diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-10 23:24:10 -0700 |
commit | 597473720f4dc69749542bfcfed4a927a43d935e (patch) | |
tree | 711bf773910fb93d1dd9120c633adc807685e0d8 /drivers/net/wireless/intel | |
parent | f0dd687815f9546860fc3ac4379d55da045942c9 (diff) | |
parent | 593fdd4fb44ef2cbf4ec53ec2c6eb60eb079bb4c (diff) |
Merge branch 'next' into for-linus
Prepare input updates for 5.3 merge window.
Diffstat (limited to 'drivers/net/wireless/intel')
112 files changed, 9205 insertions, 4456 deletions
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index d6ec44d7a391..562395517e6c 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -15,9 +15,9 @@ config IPW2100 A driver for the Intel PRO/Wireless 2100 Network Connection 802.11b wireless network adapter. - See <file:Documentation/networking/README.ipw2100> for information on - the capabilities currently enabled in this driver and for tips - for debugging issues and problems. + See <file:Documentation/networking/device_drivers/intel/ipw2100.txt> + for information on the capabilities currently enabled in this driver + and for tips for debugging issues and problems. In order to use this driver, you will need a firmware image for it. You can obtain the firmware from @@ -77,8 +77,8 @@ config IPW2200 A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network Connection adapters. - See <file:Documentation/networking/README.ipw2200> for - information on the capabilities currently enabled in this + See <file:Documentation/networking/device_drivers/intel/ipw2200.txt> + for information on the capabilities currently enabled in this driver and for tips for debugging issues and problems. In order to use this driver, you will need a firmware image for it. diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 910db46db6a1..52e5ed2d3bc2 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -5603,12 +5603,8 @@ static void shim__set_security(struct net_device *dev, if ((sec->flags & SEC_ACTIVE_KEY) && priv->ieee->sec.active_key != sec->active_key) { - if (sec->active_key <= 3) { - priv->ieee->sec.active_key = sec->active_key; - priv->ieee->sec.flags |= SEC_ACTIVE_KEY; - } else - priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; - + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; priv->status |= STATUS_SECURITY_UPDATED; } @@ -8370,7 +8366,7 @@ static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " "(detected version id of %u). " - "See Documentation/networking/README.ipw2100\n", + "See Documentation/networking/device_drivers/intel/ipw2100.txt\n", h->version); return 1; } diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index bbdca13c5a9f..fa400f92d7e2 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -10722,11 +10722,8 @@ static void shim__set_security(struct net_device *dev, } if (sec->flags & SEC_ACTIVE_KEY) { - if (sec->active_key <= 3) { - priv->ieee->sec.active_key = sec->active_key; - priv->ieee->sec.flags |= SEC_ACTIVE_KEY; - } else - priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; priv->status |= STATUS_SECURITY_UPDATED; } else priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 57e3b6cca234..271977f7fbb0 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3756,10 +3756,7 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_remove_sysfs; - err = il_dbgfs_register(il, DRV_NAME); - if (err) - IL_ERR("failed to create debugfs files. Ignoring error: %d\n", - err); + il_dbgfs_register(il, DRV_NAME); /* Start monitoring the killswitch */ queue_delayed_work(il->workqueue, &il->_3945.rfkill_poll, 2 * HZ); diff --git a/drivers/net/wireless/intel/iwlegacy/3945-rs.c b/drivers/net/wireless/intel/iwlegacy/3945-rs.c index e8983c6a2b7b..a697edd46e7f 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-rs.c @@ -781,7 +781,7 @@ il3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta, switch (scale_action) { case -1: - /* Decrese rate */ + /* Decrease rate */ if (low != RATE_INVALID) idx = low; break; diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 280cd8ae1696..94222ae464ae 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -559,7 +559,7 @@ il4965_translate_rx_status(struct il_priv *il, u32 decrypt_in) decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; break; } - /* fall through if TTAK OK */ + /* fall through - if TTAK OK */ default: if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; @@ -4988,10 +4988,7 @@ il4965_ucode_callback(const struct firmware *ucode_raw, void *context) if (err) goto out_unbind; - err = il_dbgfs_register(il, DRV_NAME); - if (err) - IL_ERR("failed to create debugfs files. Ignoring error: %d\n", - err); + il_dbgfs_register(il, DRV_NAME); err = sysfs_create_group(&il->pci_dev->dev.kobj, &il_attribute_group); if (err) { diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 6514baf799fe..a2f86cbcc740 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -2695,6 +2695,7 @@ il_set_decrypted_flag(struct il_priv *il, struct ieee80211_hdr *hdr, if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_KEY_TTAK) break; + /* fall through */ case RX_RES_STATUS_SEC_TYPE_WEP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == @@ -2704,6 +2705,7 @@ il_set_decrypted_flag(struct il_priv *il, struct ieee80211_hdr *hdr, D_RX("Packet destroyed\n"); return -1; } + /* fall through */ case RX_RES_STATUS_SEC_TYPE_CCMP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_DECRYPT_OK) { diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index dc6a74a05983..b079c64ca014 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -2974,13 +2974,11 @@ il_print_hex_dump(struct il_priv *il, int level, const void *p, u32 len) #endif /* CONFIG_IWLEGACY_DEBUG */ #ifdef CONFIG_IWLEGACY_DEBUGFS -int il_dbgfs_register(struct il_priv *il, const char *name); +void il_dbgfs_register(struct il_priv *il, const char *name); void il_dbgfs_unregister(struct il_priv *il); #else -static inline int -il_dbgfs_register(struct il_priv *il, const char *name) +static inline void il_dbgfs_register(struct il_priv *il, const char *name) { - return 0; } static inline void diff --git a/drivers/net/wireless/intel/iwlegacy/debug.c b/drivers/net/wireless/intel/iwlegacy/debug.c index d76073def677..fa211412e0ac 100644 --- a/drivers/net/wireless/intel/iwlegacy/debug.c +++ b/drivers/net/wireless/intel/iwlegacy/debug.c @@ -128,23 +128,12 @@ EXPORT_SYMBOL(il_update_stats); /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, il, \ - &il_dbgfs_##name##_ops)) \ - goto err; \ + debugfs_create_file(#name, mode, parent, il, \ + &il_dbgfs_##name##_ops); \ } while (0) #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ -} while (0) - -#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ + debugfs_create_bool(#name, 0600, parent, ptr); \ } while (0) /* file operation */ @@ -1341,27 +1330,18 @@ DEBUGFS_WRITE_FILE_OPS(wd_timeout); * Create the debugfs files and directories * */ -int +void il_dbgfs_register(struct il_priv *il, const char *name) { struct dentry *phyd = il->hw->wiphy->debugfsdir; struct dentry *dir_drv, *dir_data, *dir_rf, *dir_debug; dir_drv = debugfs_create_dir(name, phyd); - if (!dir_drv) - return -ENOMEM; - il->debugfs_dir = dir_drv; dir_data = debugfs_create_dir("data", dir_drv); - if (!dir_data) - goto err; dir_rf = debugfs_create_dir("rf", dir_drv); - if (!dir_rf) - goto err; dir_debug = debugfs_create_dir("debug", dir_drv); - if (!dir_debug) - goto err; DEBUGFS_ADD_FILE(nvm, dir_data, 0400); DEBUGFS_ADD_FILE(sram, dir_data, 0600); @@ -1399,12 +1379,6 @@ il_dbgfs_register(struct il_priv *il, const char *name) DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, &il->disable_chain_noise_cal); DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf, &il->disable_tx_power_cal); - return 0; - -err: - IL_ERR("Can't create the debugfs directory\n"); - il_dbgfs_unregister(il); - return -ENOMEM; } EXPORT_SYMBOL(il_dbgfs_register); diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index e5a2fc738ac3..83d5bceea08f 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -1,6 +1,6 @@ config IWLWIFI tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " - depends on PCI && MAC80211 && HAS_IOMEM + depends on PCI && HAS_IOMEM && CFG80211 select FW_LOADER ---help--- Select to build the driver supporting the: @@ -47,12 +47,14 @@ if IWLWIFI config IWLWIFI_LEDS bool depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI + depends on IWLMVM || IWLDVM select LEDS_TRIGGERS select MAC80211_LEDS default y config IWLDVM tristate "Intel Wireless WiFi DVM Firmware support" + depends on MAC80211 help This is the driver that supports the DVM firmware. The list of the devices that use this firmware is available here: @@ -61,6 +63,7 @@ config IWLDVM config IWLMVM tristate "Intel Wireless WiFi MVM Firmware support" select WANT_DEV_COREDUMP + depends on MAC80211 help This is the driver that supports the MVM firmware. The list of the devices that use this firmware is available here: diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 04e376cc898c..ff41987a7e35 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -11,6 +11,7 @@ iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-gen3.o iwlwifi-objs += pcie/trans-gen2.o pcie/tx-gen2.o iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o +iwlwifi-objs += iwl-dbg-tlv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c index 76b5ddb20248..1ff388b593ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c @@ -48,7 +48,7 @@ static const struct iwl_base_params iwl1000_base_params = { .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .pll_cfg = true, .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c index e7e45846dd07..a6ec7ad39dcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c @@ -57,7 +57,7 @@ #define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl2000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, @@ -71,7 +71,7 @@ static const struct iwl_base_params iwl2000_base_params = { static const struct iwl_base_params iwl2030_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, .max_ll_items = OTP_MAX_LL_ITEMS_2x00, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index da5d5f9b2573..0a87d87fbb4f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -20,7 +20,7 @@ * BSD LICENSE * * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,14 +56,13 @@ #include "iwl-config.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 41 +#define IWL_22000_UCODE_API_MAX 46 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 /* NVM versions */ #define IWL_22000_NVM_VERSION 0x0a1d -#define IWL_22000_TX_POWER_VERSION 0xffff /* meaningless */ /* Memory offsets and lengths */ #define IWL_22000_DCCM_OFFSET 0x800000 /* LMAC1 */ @@ -80,10 +79,16 @@ #define IWL_22000_HR_B_F0_FW_PRE "iwlwifi-Qu-b0-hr-b0-" #define IWL_22000_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" #define IWL_22000_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-" -#define IWL_22000_JF_B0_FW_PRE "iwlwifi-QuQnj-a0-jf-b0-" #define IWL_22000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-" #define IWL_22000_SU_Z0_FW_PRE "iwlwifi-su-z0-" #define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" +#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0-" +#define IWL_QNJ_B_JF_B_FW_PRE "iwlwifi-QuQnj-b0-jf-b0-" +#define IWL_CC_A_FW_PRE "iwlwifi-cc-a0-" +#define IWL_22000_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-" +#define IWL_22000_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0-" +#define IWL_22000_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" +#define IWL_22000_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" #define IWL_22000_HR_MODULE_FIRMWARE(api) \ IWL_22000_HR_FW_PRE __stringify(api) ".ucode" @@ -97,19 +102,29 @@ IWL_22000_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(api) \ IWL_22000_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(api) \ - IWL_22000_JF_B0_FW_PRE __stringify(api) ".ucode" #define IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(api) \ IWL_22000_HR_A0_FW_PRE __stringify(api) ".ucode" #define IWL_22000_SU_Z0_MODULE_FIRMWARE(api) \ IWL_22000_SU_Z0_FW_PRE __stringify(api) ".ucode" +#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_QUZ_A_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_22000 10 +#define IWL_QNJ_B_JF_B_MODULE_FIRMWARE(api) \ + IWL_QNJ_B_JF_B_FW_PRE __stringify(api) ".ucode" +#define IWL_CC_A_MODULE_FIRMWARE(api) \ + IWL_CC_A_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_SO_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_22000_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_SO_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_22000_SO_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_SO_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_22000_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_22000_TY_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_22000_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_22000, + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, .num_of_queues = 512, .max_tfd_queue_size = 256, .shadow_ram_support = true, @@ -121,7 +136,7 @@ static const struct iwl_base_params iwl_22000_base_params = { }; static const struct iwl_base_params iwl_22560_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_22000, + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, .num_of_queues = 512, .max_tfd_queue_size = 65536, .shadow_ram_support = true, @@ -142,7 +157,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .ucode_api_max = IWL_22000_UCODE_API_MAX, \ .ucode_api_min = IWL_22000_UCODE_API_MIN, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_22000, \ + .nvm_hw_section_num = 10, \ .non_shared_ant = ANT_B, \ .dccm_offset = IWL_22000_DCCM_OFFSET, \ .dccm_len = IWL_22000_DCCM_LEN, \ @@ -157,7 +172,6 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .mac_addr_from_csr = true, \ .ht_params = &iwl_22000_ht_params, \ .nvm_ver = IWL_22000_NVM_VERSION, \ - .nvm_calib_ver = IWL_22000_TX_POWER_VERSION, \ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ .use_tfh = true, \ .rf_id = true, \ @@ -168,6 +182,10 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .d3_debug_data_base_addr = 0x401000, \ .d3_debug_data_length = 60 * 1024 +#define IWL_DEVICE_AX200_COMMON \ + IWL_DEVICE_22000_COMMON, \ + .umac_prph_offset = 0x300000 + #define IWL_DEVICE_22500 \ IWL_DEVICE_22000_COMMON, \ .device_family = IWL_DEVICE_FAMILY_22000, \ @@ -180,6 +198,13 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .base_params = &iwl_22560_base_params, \ .csr = &iwl_csr_v2 +#define IWL_DEVICE_AX210 \ + IWL_DEVICE_AX200_COMMON, \ + .device_family = IWL_DEVICE_FAMILY_AX210, \ + .base_params = &iwl_22560_base_params, \ + .csr = &iwl_csr_v1, \ + .min_txq_size = 128 + const struct iwl_cfg iwl22000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC 22000", .fw_name_pre = IWL_22000_HR_FW_PRE, @@ -199,8 +224,8 @@ const struct iwl_cfg iwl22000_2ac_cfg_jf = { IWL_DEVICE_22500, }; -const struct iwl_cfg iwl22000_2ax_cfg_hr = { - .name = "Intel(R) Dual Band Wireless AX 22000", +const struct iwl_cfg iwl_ax101_cfg_qu_hr = { + .name = "Intel(R) Wi-Fi 6 AX101", .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -211,6 +236,57 @@ const struct iwl_cfg iwl22000_2ax_cfg_hr = { .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; +const struct iwl_cfg iwl_ax101_cfg_quz_hr = { + .name = "Intel(R) Wi-Fi 6 AX101", + .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, +}; + +const struct iwl_cfg iwl_ax200_cfg_cc = { + .name = "Intel(R) Wi-Fi 6 AX200 160MHz", + .fw_name_pre = IWL_CC_A_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, + .bisr_workaround = 1, +}; + +const struct iwl_cfg killer1650x_2ax_cfg = { + .name = "Killer(R) Wi-Fi 6 AX1650x 160MHz Wireless Network Adapter (200NGW)", + .fw_name_pre = IWL_CC_A_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, + .bisr_workaround = 1, +}; + +const struct iwl_cfg killer1650w_2ax_cfg = { + .name = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)", + .fw_name_pre = IWL_CC_A_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, + .bisr_workaround = 1, +}; + /* * All JF radio modules are part of the 9000 series, but the MAC part * looks more like 22000. That's why this device is here, but called @@ -234,6 +310,24 @@ const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0 = { IWL_DEVICE_22500, }; +const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0 = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, + IWL_DEVICE_22500, +}; + +const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0 = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL_QNJ_B_JF_B_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, +}; + const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0 = { .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, @@ -246,9 +340,9 @@ const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0 = { IWL_DEVICE_22500, }; -const struct iwl_cfg iwl22000_2ax_cfg_jf = { - .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, +const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -258,9 +352,21 @@ const struct iwl_cfg iwl22000_2ax_cfg_jf = { .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; -const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0 = { +const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE, + IWL_DEVICE_22500, + /* + * This device doesn't support receiving BlockAck with a large bitmap + * so we need to restrict the size of transmitted aggregation to the + * HT size; mac80211 would otherwise pick the HE max (256) by default. + */ + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, +}; + +const struct iwl_cfg iwl22000_2ax_cfg_jf = { .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_22000_HR_A_F0_FW_PRE, + .fw_name_pre = IWL_QU_B_JF_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -270,9 +376,9 @@ const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0 = { .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; -const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0 = { +const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0 = { .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_22000_HR_B_FW_PRE, + .fw_name_pre = IWL_22000_HR_A_F0_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -282,9 +388,9 @@ const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0 = { .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; -const struct iwl_cfg iwl22000_2ax_cfg_qnj_jf_b0 = { +const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0 = { .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_22000_JF_B0_FW_PRE, + .fw_name_pre = IWL_22000_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -319,13 +425,42 @@ const struct iwl_cfg iwl22560_2ax_cfg_su_cdb = { .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; +const struct iwl_cfg iwlax210_2ax_cfg_so_jf_a0 = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL_22000_SO_A_JF_B_FW_PRE, + IWL_DEVICE_AX210, +}; + +const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { + .name = "Intel(R) Wi-Fi 6 AX201 160MHz", + .fw_name_pre = IWL_22000_SO_A_HR_B_FW_PRE, + IWL_DEVICE_AX210, +}; + +const struct iwl_cfg iwlax210_2ax_cfg_so_gf_a0 = { + .name = "Intel(R) Wi-Fi 7 AX211 160MHz", + .fw_name_pre = IWL_22000_SO_A_GF_A_FW_PRE, + IWL_DEVICE_AX210, +}; + +const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { + .name = "Intel(R) Wi-Fi 7 AX210 160MHz", + .fw_name_pre = IWL_22000_TY_A_GF_A_FW_PRE, + IWL_DEVICE_AX210, +}; + MODULE_FIRMWARE(IWL_22000_HR_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_JF_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_A_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_B_F0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_22000_JF_B0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_22000_SU_Z0_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_SO_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_SO_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_SO_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_22000_TY_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c index 575a7022d045..3846064d51a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -136,6 +136,7 @@ const struct iwl_cfg iwl5350_agn_cfg = { .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, .internal_wimax_coex = true, + .csr = &iwl_csr_v1, }; #define IWL_DEVICE_5150 \ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index 30e62a7c9d52..fbb18d066cd0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -66,7 +66,7 @@ #define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl6000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, @@ -79,7 +79,7 @@ static const struct iwl_base_params iwl6000_base_params = { }; static const struct iwl_base_params iwl6050_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, .max_ll_items = OTP_MAX_LL_ITEMS_6x50, @@ -92,7 +92,7 @@ static const struct iwl_base_params iwl6050_base_params = { }; static const struct iwl_base_params iwl6000_g2_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE, + .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, .num_of_queues = IWLAGN_NUM_QUEUES, .max_tfd_queue_size = 256, .max_ll_items = OTP_MAX_LL_ITEMS_6x00, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index c973bfaa3414..289e3c398a12 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -80,17 +80,11 @@ /* NVM versions */ #define IWL7260_NVM_VERSION 0x0a1d -#define IWL7260_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL3160_NVM_VERSION 0x709 -#define IWL3160_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL3165_NVM_VERSION 0x709 -#define IWL3165_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL3168_NVM_VERSION 0xd01 -#define IWL3168_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL7265_NVM_VERSION 0x0a1d -#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ #define IWL7265D_NVM_VERSION 0x0c11 -#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */ /* DCCM offsets and lengths */ #define IWL7000_DCCM_OFFSET 0x800000 @@ -113,10 +107,8 @@ #define IWL7265D_FW_PRE "iwlwifi-7265D-" #define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode" -#define NVM_HW_SECTION_NUM_FAMILY_7000 0 - static const struct iwl_base_params iwl7000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_7000, + .eeprom_size = OTP_LOW_IMAGE_SIZE_16K, .num_of_queues = 31, .max_tfd_queue_size = 256, .shadow_ram_support = true, @@ -159,7 +151,7 @@ static const struct iwl_ht_params iwl7000_ht_params = { .device_family = IWL_DEVICE_FAMILY_7000, \ .base_params = &iwl7000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \ + .nvm_hw_section_num = 0, \ .non_shared_ant = ANT_A, \ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ .dccm_offset = IWL7000_DCCM_OFFSET, \ @@ -191,7 +183,6 @@ const struct iwl_cfg iwl7260_2ac_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, .dccm_len = IWL7260_DCCM_LEN, @@ -203,7 +194,6 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .high_temp = true, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, @@ -217,7 +207,6 @@ const struct iwl_cfg iwl7260_2n_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, .dccm_len = IWL7260_DCCM_LEN, @@ -229,7 +218,6 @@ const struct iwl_cfg iwl7260_n_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL7260_NVM_VERSION, - .nvm_calib_ver = IWL7260_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .lp_xtal_workaround = true, .dccm_len = IWL7260_DCCM_LEN, @@ -241,7 +229,6 @@ const struct iwl_cfg iwl3160_2ac_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .dccm_len = IWL3160_DCCM_LEN, }; @@ -252,7 +239,6 @@ const struct iwl_cfg iwl3160_2n_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .dccm_len = IWL3160_DCCM_LEN, }; @@ -263,7 +249,6 @@ const struct iwl_cfg iwl3160_n_cfg = { IWL_DEVICE_7000, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL3160_NVM_VERSION, - .nvm_calib_ver = IWL3160_TX_POWER_VERSION, .host_interrupt_operation_mode = true, .dccm_len = IWL3160_DCCM_LEN, }; @@ -291,7 +276,6 @@ const struct iwl_cfg iwl3165_2ac_cfg = { IWL_DEVICE_7005D, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL3165_NVM_VERSION, - .nvm_calib_ver = IWL3165_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -302,7 +286,6 @@ const struct iwl_cfg iwl3168_2ac_cfg = { IWL_DEVICE_3008, .ht_params = &iwl7000_ht_params, .nvm_ver = IWL3168_NVM_VERSION, - .nvm_calib_ver = IWL3168_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, .nvm_type = IWL_NVM_SDP, @@ -314,7 +297,6 @@ const struct iwl_cfg iwl7265_2ac_cfg = { IWL_DEVICE_7005, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -325,7 +307,6 @@ const struct iwl_cfg iwl7265_2n_cfg = { IWL_DEVICE_7005, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -336,7 +317,6 @@ const struct iwl_cfg iwl7265_n_cfg = { IWL_DEVICE_7005, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -347,7 +327,6 @@ const struct iwl_cfg iwl7265d_2ac_cfg = { IWL_DEVICE_7005D, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -358,7 +337,6 @@ const struct iwl_cfg iwl7265d_2n_cfg = { IWL_DEVICE_7005D, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; @@ -369,7 +347,6 @@ const struct iwl_cfg iwl7265d_n_cfg = { IWL_DEVICE_7005D, .ht_params = &iwl7265_ht_params, .nvm_ver = IWL7265D_NVM_VERSION, - .nvm_calib_ver = IWL7265_TX_POWER_VERSION, .pwr_tx_backoffs = iwl7265_pwr_tx_backoffs, .dccm_len = IWL7265_DCCM_LEN, }; diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 348c40fcddcb..d7d17c1cceea 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -75,7 +75,6 @@ /* NVM versions */ #define IWL8000_NVM_VERSION 0x0a1d -#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */ /* Memory offsets and lengths */ #define IWL8260_DCCM_OFFSET 0x800000 @@ -93,11 +92,10 @@ #define IWL8265_MODULE_FIRMWARE(api) \ IWL8265_FW_PRE __stringify(api) ".ucode" -#define NVM_HW_SECTION_NUM_FAMILY_8000 10 #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" static const struct iwl_base_params iwl8000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_8000, + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, .num_of_queues = 31, .max_tfd_queue_size = 256, .shadow_ram_support = true, @@ -139,7 +137,7 @@ static const struct iwl_tt_params iwl8000_tt_params = { .device_family = IWL_DEVICE_FAMILY_8000, \ .base_params = &iwl8000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ + .nvm_hw_section_num = 10, \ .features = NETIF_F_RXCSUM, \ .non_shared_ant = ANT_A, \ .dccm_offset = IWL8260_DCCM_OFFSET, \ @@ -177,7 +175,6 @@ const struct iwl_cfg iwl8260_2n_cfg = { IWL_DEVICE_8260, .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, }; const struct iwl_cfg iwl8260_2ac_cfg = { @@ -186,7 +183,6 @@ const struct iwl_cfg iwl8260_2ac_cfg = { IWL_DEVICE_8260, .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; @@ -196,7 +192,6 @@ const struct iwl_cfg iwl8265_2ac_cfg = { IWL_DEVICE_8265, .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .vht_mu_mimo_supported = true, }; @@ -207,7 +202,6 @@ const struct iwl_cfg iwl8275_2ac_cfg = { IWL_DEVICE_8265, .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .vht_mu_mimo_supported = true, }; @@ -218,7 +212,6 @@ const struct iwl_cfg iwl4165_2ac_cfg = { IWL_DEVICE_8000, .ht_params = &iwl8000_ht_params, .nvm_ver = IWL8000_NVM_VERSION, - .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index d55fd23cafe6..3225b64eb845 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -57,14 +57,13 @@ #include "fw/file.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 41 +#define IWL9000_UCODE_API_MAX 46 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 /* NVM versions */ #define IWL9000_NVM_VERSION 0x0a1d -#define IWL9000_TX_POWER_VERSION 0xffff /* meaningless */ /* Memory offsets and lengths */ #define IWL9000_DCCM_OFFSET 0x800000 @@ -74,26 +73,15 @@ #define IWL9000_SMEM_OFFSET 0x400000 #define IWL9000_SMEM_LEN 0x68000 -#define IWL9000A_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-" -#define IWL9000B_FW_PRE "iwlwifi-9000-pu-b0-jf-b0-" -#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-" -#define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-" -#define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" -#define IWL9000A_MODULE_FIRMWARE(api) \ - IWL9000A_FW_PRE __stringify(api) ".ucode" -#define IWL9000B_MODULE_FIRMWARE(api) \ - IWL9000B_FW_PRE __stringify(api) ".ucode" -#define IWL9000RFB_MODULE_FIRMWARE(api) \ - IWL9000RFB_FW_PRE __stringify(api) ".ucode" -#define IWL9260A_MODULE_FIRMWARE(api) \ - IWL9260A_FW_PRE __stringify(api) ".ucode" -#define IWL9260B_MODULE_FIRMWARE(api) \ - IWL9260B_FW_PRE __stringify(api) ".ucode" - -#define NVM_HW_SECTION_NUM_FAMILY_9000 10 +#define IWL9000_FW_PRE "iwlwifi-9000-pu-b0-jf-b0-" +#define IWL9260_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" +#define IWL9000_MODULE_FIRMWARE(api) \ + IWL9000_FW_PRE __stringify(api) ".ucode" +#define IWL9260_MODULE_FIRMWARE(api) \ + IWL9260_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl9000_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000, + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, .num_of_queues = 31, .max_tfd_queue_size = 256, .shadow_ram_support = true, @@ -137,7 +125,7 @@ static const struct iwl_tt_params iwl9000_tt_params = { .device_family = IWL_DEVICE_FAMILY_9000, \ .base_params = &iwl9000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_9000, \ + .nvm_hw_section_num = 10, \ .non_shared_ant = ANT_B, \ .dccm_offset = IWL9000_DCCM_OFFSET, \ .dccm_len = IWL9000_DCCM_LEN, \ @@ -157,168 +145,120 @@ static const struct iwl_tt_params iwl9000_tt_params = { .min_umac_error_event_table = 0x800000, \ .csr = &iwl_csr_v1, \ .d3_debug_data_base_addr = 0x401000, \ - .d3_debug_data_length = 92 * 1024 + .d3_debug_data_length = 92 * 1024, \ + .ht_params = &iwl9000_ht_params, \ + .nvm_ver = IWL9000_NVM_VERSION, \ + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K + const struct iwl_cfg iwl9160_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9160", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9260_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9260", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, + IWL_DEVICE_9000, +}; + +const struct iwl_cfg iwl9260_2ac_160_cfg = { + .name = "Intel(R) Wireless-AC 9260 160MHz", + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9260_killer_2ac_cfg = { .name = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW)", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9270_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9270", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9460_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9460", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9460_2ac_cfg_soc = { .name = "Intel(R) Dual Band Wireless AC 9460", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, }; const struct iwl_cfg iwl9461_2ac_cfg_soc = { - .name = "Intel(R) Dual Band Wireless AC 9461", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, - .soc_latency = 5000, + .name = "Intel(R) Dual Band Wireless AC 9461", + .fw_name_pre = IWL9000_FW_PRE, + IWL_DEVICE_9000, + .integrated = true, + .soc_latency = 5000, }; const struct iwl_cfg iwl9462_2ac_cfg_soc = { - .name = "Intel(R) Dual Band Wireless AC 9462", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, - IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, - .integrated = true, - .soc_latency = 5000, + .name = "Intel(R) Dual Band Wireless AC 9462", + .fw_name_pre = IWL9000_FW_PRE, + IWL_DEVICE_9000, + .integrated = true, + .soc_latency = 5000, }; const struct iwl_cfg iwl9560_2ac_cfg = { .name = "Intel(R) Dual Band Wireless AC 9560", - .fw_name_pre = IWL9260A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9260B_FW_PRE, + .fw_name_pre = IWL9260_FW_PRE, + IWL_DEVICE_9000, +}; + +const struct iwl_cfg iwl9560_2ac_160_cfg = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL9260_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; const struct iwl_cfg iwl9560_2ac_cfg_soc = { .name = "Intel(R) Dual Band Wireless AC 9560", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, + IWL_DEVICE_9000, + .integrated = true, + .soc_latency = 5000, +}; + +const struct iwl_cfg iwl9560_2ac_160_cfg_soc = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, }; const struct iwl_cfg iwl9560_killer_2ac_cfg_soc = { .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, }; const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc = { .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, }; const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9460", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK @@ -326,14 +266,8 @@ const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9461", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK @@ -341,14 +275,8 @@ const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = { const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9462", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK @@ -356,14 +284,17 @@ const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = { const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { .name = "Intel(R) Dual Band Wireless AC 9560", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, + IWL_DEVICE_9000, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9560_2ac_160_cfg_shared_clk = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK @@ -371,14 +302,8 @@ const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk = { .name = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK @@ -386,21 +311,12 @@ const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk = { const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk = { .name = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)", - .fw_name_pre = IWL9000A_FW_PRE, - .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, - .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + .fw_name_pre = IWL9000_FW_PRE, IWL_DEVICE_9000, - .ht_params = &iwl9000_ht_params, - .nvm_ver = IWL9000_NVM_VERSION, - .nvm_calib_ver = IWL9000_TX_POWER_VERSION, - .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, .integrated = true, .soc_latency = 5000, .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK }; -MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL9260_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile index 702d42b2d452..0486b17d7c41 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile @@ -11,4 +11,4 @@ iwldvm-objs += rxon.o devices.o iwldvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o -ccflags-y += -I$(src)/../ +ccflags-y += -I $(srctree)/$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index 431e13c6ee35..254a5ce52456 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -439,13 +439,10 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) } #ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir); +void iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir); #else -static inline int iwl_dbgfs_register(struct iwl_priv *priv, - struct dentry *dbgfs_dir) -{ - return 0; -} +static inline void iwl_dbgfs_register(struct iwl_priv *priv, + struct dentry *dbgfs_dir) { } #endif /* CONFIG_IWLWIFI_DEBUGFS */ #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 3d2e44a642de..d4b19673b06a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -3,6 +3,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -36,31 +37,8 @@ /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ - if (!debugfs_create_file(#name, mode, parent, priv, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ -} while (0) - -#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ -} while (0) - -#define DEBUGFS_ADD_X32(name, parent, ptr) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ -} while (0) - -#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \ - struct dentry *__tmp; \ - __tmp = debugfs_create_u32(#name, mode, \ - parent, ptr); \ - if (IS_ERR(__tmp) || !__tmp) \ - goto err; \ + debugfs_create_file(#name, mode, parent, priv, \ + &iwl_dbgfs_##name##_ops); \ } while (0) /* file operation */ @@ -2238,7 +2216,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; - if (sscanf(buf, "%d", &event_log_flag) != 1) + if (sscanf(buf, "%u", &event_log_flag) != 1) return -EFAULT; if (event_log_flag == 1) iwl_dump_nic_event_log(priv, true, NULL); @@ -2347,21 +2325,15 @@ DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); * Create the debugfs files and directories * */ -int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) +void iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) { struct dentry *dir_data, *dir_rf, *dir_debug; priv->debugfs_dir = dbgfs_dir; dir_data = debugfs_create_dir("data", dbgfs_dir); - if (!dir_data) - goto err; dir_rf = debugfs_create_dir("rf", dbgfs_dir); - if (!dir_rf) - goto err; dir_debug = debugfs_create_dir("debug", dbgfs_dir); - if (!dir_debug) - goto err; DEBUGFS_ADD_FILE(nvm, dir_data, 0400); DEBUGFS_ADD_FILE(sram, dir_data, 0600); @@ -2421,13 +2393,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) snprintf(buf, 100, "../../%pd2", dev_dir); - if (!debugfs_create_symlink("iwlwifi", mac80211_dir, buf)) - goto err; + debugfs_create_symlink("iwlwifi", mac80211_dir, buf); } - - return 0; - -err: - IWL_ERR(priv, "failed to create the dvm debugfs entries\n"); - return -ENOMEM; } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 49b71dbf8490..54b759cec8b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -710,24 +711,6 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) -{ - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) - return false; - return true; -} - -static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) -{ - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) - return false; - if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) - return true; - - /* disabled by default */ - return false; -} - static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) @@ -752,7 +735,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if (!iwl_enable_rx_ampdu(priv->cfg)) + if (!iwl_enable_rx_ampdu()) break; IWL_DEBUG_HT(priv, "start Rx\n"); ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn); @@ -764,7 +747,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: if (!priv->trans->ops->txq_enable) break; - if (!iwl_enable_tx_ampdu(priv->cfg)) + if (!iwl_enable_tx_ampdu()) break; IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 1088ff036e13..7c68a86ed9e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1054,7 +1054,7 @@ static void iwl_bg_restart(struct work_struct *data) ieee80211_restart_hw(priv->hw); else IWL_ERR(priv, - "Cannot request restart before registrating with mac80211\n"); + "Cannot request restart before registering with mac80211\n"); } else { WARN_ON(1); } @@ -1224,6 +1224,23 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv) return 0; } +static int iwl_nvm_check_version(struct iwl_nvm_data *data, + struct iwl_trans *trans) +{ + if (data->nvm_version >= trans->cfg->nvm_ver || + data->calib_version >= trans->cfg->nvm_calib_ver) { + IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", + data->nvm_version, data->calib_version); + return 0; + } + + IWL_ERR(trans, + "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + data->nvm_version, trans->cfg->nvm_ver, + data->calib_version, trans->cfg->nvm_calib_ver); + return -EINVAL; +} + static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, @@ -1492,13 +1509,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, if (iwlagn_mac_setup_register(priv, &fw->ucode_capa)) goto out_destroy_workqueue; - if (iwl_dbgfs_register(priv, dbgfs_dir)) - goto out_mac80211_unregister; + iwl_dbgfs_register(priv, dbgfs_dir); return op_mode; -out_mac80211_unregister: - iwlagn_mac_unregister(priv); out_destroy_workqueue: iwl_tt_exit(priv); iwl_cancel_deferred_work(priv); @@ -1864,7 +1878,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, return pos; } - if (!(iwl_have_debug_level(IWL_DL_FW_ERRORS)) && !full_log) + if (!(iwl_have_debug_level(IWL_DL_FW)) && !full_log) size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", @@ -1880,7 +1894,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, if (!*buf) return -ENOMEM; } - if (iwl_have_debug_level(IWL_DL_FW_ERRORS) || full_log) { + if (iwl_have_debug_level(IWL_DL_FW) || full_log) { /* * if uCode has wrapped back to top of log, * start at the oldest entry, @@ -1910,7 +1924,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) unsigned int reload_msec; unsigned long reload_jiffies; - if (iwl_have_debug_level(IWL_DL_FW_ERRORS)) + if (iwl_have_debug_level(IWL_DL_FW)) iwl_print_rx_config_cmd(priv, IWL_RXON_CTX_BSS); /* uCode is no longer loaded. */ @@ -1948,12 +1962,12 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { if (iwlwifi_mod_params.fw_restart) { - IWL_DEBUG_FW_ERRORS(priv, - "Restarting adapter due to uCode error.\n"); + IWL_DEBUG_FW(priv, + "Restarting adapter due to uCode error.\n"); queue_work(priv->workqueue, &priv->restart); } else - IWL_DEBUG_FW_ERRORS(priv, - "Detected FW error, but not restarting\n"); + IWL_DEBUG_FW(priv, + "Detected FW error, but not restarting\n"); } } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 6f17a5e24e82..e224b23f0ba8 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -2,6 +2,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. @@ -592,7 +593,7 @@ static int iwlagn_set_decrypted_flag(struct iwl_priv *priv, if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_KEY_TTAK) break; - + /* fall through */ case RX_RES_STATUS_SEC_TYPE_WEP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_BAD_ICV_MIC) { @@ -601,6 +602,7 @@ static int iwlagn_set_decrypted_flag(struct iwl_priv *priv, IWL_DEBUG_RX(priv, "Packet destroyed\n"); return -1; } + /* fall through */ case RX_RES_STATUS_SEC_TYPE_CCMP: if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == RX_RES_STATUS_DECRYPT_OK) { @@ -729,7 +731,7 @@ static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; break; } - /* fall through if TTAK OK */ + /* fall through */ default: if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c index 8d7aafb4d9e9..f190f7beb3a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/scan.c @@ -3,6 +3,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -418,7 +419,7 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) limit = (limits[1] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; limit /= 2; dwell_time = min(limit, dwell_time); - /* fall through to limit further */ + /* fall through */ case 1: limit = (limits[0] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; limit /= n_active; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c index 4de2727ac63e..a156dcf5b7d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -325,9 +326,9 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force) iwl_prepare_ct_kill_task(priv); tt->state = old_state; } - } else if (old_state == IWL_TI_CT_KILL && - tt->state != IWL_TI_CT_KILL) + } else if (old_state == IWL_TI_CT_KILL) { iwl_perform_ct_kill_task(priv, false); + } IWL_DEBUG_TEMP(priv, "Temperature state changed %u\n", tt->state); IWL_DEBUG_TEMP(priv, "Power Index change to %u\n", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 32d000cffe9f..405038ce98d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright (C) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -26,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright (C) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,3 +207,33 @@ out: return dflt_pwr_limit; } IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); + +int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +{ + union acpi_object *wifi_pkg, *data; + int ret; + + data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out_free; + } + + *extl_clk = wifi_pkg->package.elements[1].integer.value; + + ret = 0; + +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 7492dfb6729b..f5704e16643f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -27,7 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,6 +67,7 @@ #define ACPI_WGDS_METHOD "WGDS" #define ACPI_WRDD_METHOD "WRDD" #define ACPI_SPLC_METHOD "SPLC" +#define ACPI_ECKV_METHOD "ECKV" #define ACPI_WIFI_DOMAIN (0x07) @@ -86,6 +87,7 @@ #define ACPI_WGDS_WIFI_DATA_SIZE 19 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 +#define ACPI_ECKV_WIFI_DATA_SIZE 2 #define ACPI_WGDS_NUM_BANDS 2 #define ACPI_WGDS_TABLE_SIZE 3 @@ -109,6 +111,17 @@ int iwl_acpi_get_mcc(struct device *dev, char *mcc); u64 iwl_acpi_get_pwr_limit(struct device *dev); +/* + * iwl_acpi_get_eckv - read external clock validation from ACPI, if available + * + * @dev: the struct device + * @extl_clk: output var (2 bytes) that will get the clk indication. + * + * This function tries to read the external clock indication + * from ACPI if available. + */ +int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk); + #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method) @@ -133,5 +146,10 @@ static inline u64 iwl_acpi_get_pwr_limit(struct device *dev) return 0; } +static inline int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +{ + return -ENOENT; +} + #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h index 08d3d8a190f6..df1bd0d2450e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h @@ -96,14 +96,7 @@ enum { #define IWL_ALIVE_FLG_RFKILL BIT(0) -struct iwl_lmac_alive { - __le32 ucode_major; - __le32 ucode_minor; - u8 ver_subtype; - u8 ver_type; - u8 mac; - u8 opt; - __le32 timestamp; +struct iwl_lmac_debug_addrs { __le32 error_event_table_ptr; /* SRAM address for error log */ __le32 log_event_table_ptr; /* SRAM address for LMAC event log */ __le32 cpu_register_ptr; @@ -112,13 +105,28 @@ struct iwl_lmac_alive { __le32 scd_base_ptr; /* SRAM address for SCD */ __le32 st_fwrd_addr; /* pointer to Store and forward */ __le32 st_fwrd_size; +} __packed; /* UCODE_DEBUG_ADDRS_API_S_VER_2 */ + +struct iwl_lmac_alive { + __le32 ucode_major; + __le32 ucode_minor; + u8 ver_subtype; + u8 ver_type; + u8 mac; + u8 opt; + __le32 timestamp; + struct iwl_lmac_debug_addrs dbg_ptrs; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */ +struct iwl_umac_debug_addrs { + __le32 error_info_addr; /* SRAM address for UMAC error log */ + __le32 dbg_print_buff_addr; +} __packed; /* UMAC_DEBUG_ADDRS_API_S_VER_1 */ + struct iwl_umac_alive { __le32 umac_major; /* UMAC version: major */ __le32 umac_minor; /* UMAC version: minor */ - __le32 error_info_addr; /* SRAM address for UMAC error log */ - __le32 dbg_print_buff_addr; + struct iwl_umac_debug_addrs dbg_ptrs; } __packed; /* UMAC_ALIVE_DATA_API_S_VER_2 */ struct mvm_alive_resp_v3 { @@ -189,4 +197,24 @@ struct iwl_card_state_notif { __le32 flags; } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ +/** + * enum iwl_error_recovery_flags - flags for error recovery cmd + * @ERROR_RECOVERY_UPDATE_DB: update db from blob sent + * @ERROR_RECOVERY_END_OF_RECOVERY: end of recovery + */ +enum iwl_error_recovery_flags { + ERROR_RECOVERY_UPDATE_DB = BIT(0), + ERROR_RECOVERY_END_OF_RECOVERY = BIT(1), +}; + +/** + * struct iwl_fw_error_recovery_cmd - recovery cmd sent upon assert + * @flags: &enum iwl_error_recovery_flags + * @buf_size: db buffer size in bytes + */ +struct iwl_fw_error_recovery_cmd { + __le32 flags; + __le32 buf_size; +} __packed; /* ERROR_RECOVERY_CMD_HDR_API_S_VER_1 */ + #endif /* __iwl_fw_api_alive_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 8b4922bbe139..4d2274bcc0b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -77,7 +77,8 @@ * @DATA_PATH_GROUP: data path group, uses command IDs from * &enum iwl_data_path_subcmd_ids * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids - * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids + * @LOCATION_GROUP: location group, uses command IDs from + * &enum iwl_location_subcmd_ids * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from * &enum iwl_prot_offload_subcmd_ids * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from @@ -92,7 +93,7 @@ enum iwl_mvm_command_groups { PHY_OPS_GROUP = 0x4, DATA_PATH_GROUP = 0x5, NAN_GROUP = 0x7, - TOF_GROUP = 0x8, + LOCATION_GROUP = 0x8, PROT_OFFLOAD_GROUP = 0xb, REGULATORY_AND_NVM_GROUP = 0xc, DEBUG_GROUP = 0xf, @@ -353,16 +354,6 @@ enum iwl_legacy_cmds { PHY_DB_CMD = 0x6c, /** - * @TOF_CMD: &struct iwl_tof_config_cmd - */ - TOF_CMD = 0x10, - - /** - * @TOF_NOTIFICATION: &struct iwl_tof_gen_resp_cmd - */ - TOF_NOTIFICATION = 0x11, - - /** * @POWER_TABLE_CMD: &struct iwl_device_power_cmd */ POWER_TABLE_CMD = 0x77, @@ -415,7 +406,11 @@ enum iwl_legacy_cmds { TX_ANT_CONFIGURATION_CMD = 0x98, /** - * @STATISTICS_CMD: &struct iwl_statistics_cmd + * @STATISTICS_CMD: + * one of &struct iwl_statistics_cmd, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics */ STATISTICS_CMD = 0x9c, @@ -423,7 +418,7 @@ enum iwl_legacy_cmds { * @STATISTICS_NOTIFICATION: * one of &struct iwl_notif_statistics_v10, * &struct iwl_notif_statistics_v11, - * &struct iwl_notif_statistics_cdb + * &struct iwl_notif_statistics */ STATISTICS_NOTIFICATION = 0x9d, @@ -648,6 +643,11 @@ enum iwl_system_subcmd_ids { * @INIT_EXTENDED_CFG_CMD: &struct iwl_init_extended_cfg_cmd */ INIT_EXTENDED_CFG_CMD = 0x03, + + /** + * @FW_ERROR_RECOVERY_CMD: &struct iwl_fw_error_recovery_cmd + */ + FW_ERROR_RECOVERY_CMD = 0x7, }; #endif /* __iwl_fw_api_commands_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h index 7f645b62804e..5e88fa2e6fb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -127,17 +129,6 @@ struct iwl_phy_cfg_cmd { struct iwl_calib_ctrl calib_control; } __packed; -#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1)) -#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3)) -#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5)) -#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7)) -#define PHY_CFG_TX_CHAIN_A BIT(8) -#define PHY_CFG_TX_CHAIN_B BIT(9) -#define PHY_CFG_TX_CHAIN_C BIT(10) -#define PHY_CFG_RX_CHAIN_A BIT(12) -#define PHY_CFG_RX_CHAIN_B BIT(13) -#define PHY_CFG_RX_CHAIN_C BIT(14) - /* * enum iwl_dc2dc_config_id - flag ids * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 6fae02fa4cad..86ea0784e1a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -224,8 +224,18 @@ struct iwl_wowlan_pattern { #define IWL_WOWLAN_MAX_PATTERNS 20 +/** + * struct iwl_wowlan_patterns_cmd - WoWLAN wakeup patterns + */ struct iwl_wowlan_patterns_cmd { + /** + * @n_patterns: number of patterns + */ __le32 n_patterns; + + /** + * @patterns: the patterns, array length in @n_patterns + */ struct iwl_wowlan_pattern patterns[]; } __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index eff3249af48a..93c06e6c1ced 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -105,6 +105,17 @@ enum iwl_data_path_subcmd_ids { HE_AIR_SNIFFER_CONFIG_CMD = 0x13, /** + * @CHEST_COLLECTOR_FILTER_CONFIG_CMD: Configure the CSI + * matrix collection, uses &struct iwl_channel_estimation_cfg + */ + CHEST_COLLECTOR_FILTER_CONFIG_CMD = 0x14, + + /** + * @RX_NO_DATA_NOTIF: &struct iwl_rx_no_data + */ + RX_NO_DATA_NOTIF = 0xF5, + + /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ TLC_MNG_UPDATE_NOTIF = 0xF7, @@ -151,4 +162,53 @@ struct iwl_mu_group_mgmt_notif { __le32 user_position[4]; } __packed; /* MU_GROUP_MNG_NTFY_API_S_VER_1 */ +enum iwl_channel_estimation_flags { + IWL_CHANNEL_ESTIMATION_ENABLE = BIT(0), + IWL_CHANNEL_ESTIMATION_TIMER = BIT(1), + IWL_CHANNEL_ESTIMATION_COUNTER = BIT(2), +}; + +/** + * struct iwl_channel_estimation_cfg - channel estimation reporting config + */ +struct iwl_channel_estimation_cfg { + /** + * @flags: flags, see &enum iwl_channel_estimation_flags + */ + __le32 flags; + /** + * @timer: if enabled via flags, automatically disable after this many + * microseconds + */ + __le32 timer; + /** + * @count: if enabled via flags, automatically disable after this many + * frames with channel estimation matrix were captured + */ + __le32 count; + /** + * @rate_n_flags_mask: only try to record the channel estimation matrix + * if the rate_n_flags value for the received frame (let's call + * that rx_rnf) matches the mask/value given here like this: + * (rx_rnf & rate_n_flags_mask) == rate_n_flags_val. + */ + __le32 rate_n_flags_mask; + /** + * @rate_n_flags_val: see @rate_n_flags_mask + */ + __le32 rate_n_flags_val; + /** + * @reserved: reserved (for alignment) + */ + __le32 reserved; + /** + * @frame_types: bitmap of frame types to capture, the received frame's + * subtype|type takes 6 bits in the frame and the corresponding bit + * in this field must be set to 1 to capture channel estimation for + * that frame type. Set to all-ones to enable capturing for all + * frame types. + */ + __le64 frame_types; +} __packed; /* CHEST_COLLECTOR_FILTER_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h new file mode 100644 index 000000000000..33858787817b --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -0,0 +1,437 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2018 - 2019 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright (C) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_dbg_tlv_h__ +#define __iwl_fw_dbg_tlv_h__ + +#include <linux/bitops.h> + +/* + * struct iwl_fw_ini_header: Common Header for all debug group TLV's structures + * @tlv_version: version info + * @apply_point: &enum iwl_fw_ini_apply_point + * @data: TLV data followed + **/ +struct iwl_fw_ini_header { + __le32 tlv_version; + __le32 apply_point; + u8 data[]; +} __packed; /* FW_DEBUG_TLV_HEADER_S */ + +/** + * struct iwl_fw_ini_allocation_tlv - (IWL_FW_INI_TLV_TYPE_BUFFER_ALLOCATION) + * buffer allocation TLV - for debug + * + * @iwl_fw_ini_header: header + * @allocation_id: &enum iwl_fw_ini_allocation_id - to bind allocation and hcmd + * if needed (DBGC1/DBGC2/SDFX/...) + * @buffer_location: type of iwl_fw_ini_buffer_location + * @size: size in bytes + * @max_fragments: the maximum allowed fragmentation in the desired memory + * allocation above + * @min_frag_size: the minimum allowed fragmentation size in bytes +*/ +struct iwl_fw_ini_allocation_tlv { + struct iwl_fw_ini_header header; + __le32 allocation_id; + __le32 buffer_location; + __le32 size; + __le32 max_fragments; + __le32 min_frag_size; +} __packed; /* FW_DEBUG_TLV_BUFFER_ALLOCATION_TLV_S_VER_1 */ + +/** + * struct iwl_fw_ini_hcmd (IWL_FW_INI_TLV_TYPE_HCMD) + * Generic Host command pass through TLV + * + * @id: the debug configuration command type for instance: 0xf6 / 0xf5 / DHC + * @group: the desired cmd group + * @padding: all zeros for dword alignment + * @data: all of the relevant command (0xf6/0xf5) to be sent +*/ +struct iwl_fw_ini_hcmd { + u8 id; + u8 group; + __le16 padding; + u8 data[0]; +} __packed; /* FW_DEBUG_TLV_HCMD_DATA_S */ + +/** + * struct iwl_fw_ini_hcmd_tlv + * @header: header + * @hcmd: a variable length host-command to be sent to apply the configuration. + */ +struct iwl_fw_ini_hcmd_tlv { + struct iwl_fw_ini_header header; + struct iwl_fw_ini_hcmd hcmd; +} __packed; /* FW_DEBUG_TLV_HCMD_S_VER_1 */ + +/* + * struct iwl_fw_ini_debug_flow_tlv (IWL_FW_INI_TLV_TYPE_DEBUG_FLOW) + * + * @header: header + * @debug_flow_cfg: &enum iwl_fw_ini_debug_flow + */ +struct iwl_fw_ini_debug_flow_tlv { + struct iwl_fw_ini_header header; + __le32 debug_flow_cfg; +} __packed; /* FW_DEBUG_TLV_FLOW_TLV_S_VER_1 */ + +#define IWL_FW_INI_MAX_REGION_ID 64 +#define IWL_FW_INI_MAX_NAME 32 + +/** + * struct iwl_fw_ini_region_cfg_internal - meta data of internal memory region + * @num_of_range: the amount of ranges in the region + * @range_data_size: size of the data to read per range, in bytes. + */ +struct iwl_fw_ini_region_cfg_internal { + __le32 num_of_ranges; + __le32 range_data_size; +} __packed; /* FW_DEBUG_TLV_REGION_NIC_INTERNAL_RANGES_S */ + +/** + * struct iwl_fw_ini_region_cfg_fifos - meta data of fifos region + * @fid1: fifo id 1 - bitmap of lmac tx/rx fifos to include in the region + * @fid2: fifo id 2 - bitmap of umac rx fifos to include in the region. + * It is unused for tx. + * @num_of_registers: number of prph registers in the region, each register is + * 4 bytes size. + * @header_only: none zero value indicates that this region does not include + * fifo data and includes only the given registers. + */ +struct iwl_fw_ini_region_cfg_fifos { + __le32 fid1; + __le32 fid2; + __le32 num_of_registers; + __le32 header_only; +} __packed; /* FW_DEBUG_TLV_REGION_FIFOS_S */ + +/** + * struct iwl_fw_ini_region_cfg + * @region_id: ID of this dump configuration + * @region_type: &enum iwl_fw_ini_region_type + * @num_regions: amount of regions in the address array. + * @name_len: name length + * @name: file name to use for this region + * @internal: used in case the region uses internal memory. + * @allocation_id: For DRAM type field substitutes for allocation_id + * @fifos: used in case of fifos region. + * @offset: offset to use for each memory base address + * @start_addr: array of addresses. + */ +struct iwl_fw_ini_region_cfg { + __le32 region_id; + __le32 region_type; + __le32 name_len; + u8 name[IWL_FW_INI_MAX_NAME]; + union { + struct iwl_fw_ini_region_cfg_internal internal; + __le32 allocation_id; + struct iwl_fw_ini_region_cfg_fifos fifos; + }; + __le32 offset; + __le32 start_addr[]; +} __packed; /* FW_DEBUG_TLV_REGION_CONFIG_S */ + +/** + * struct iwl_fw_ini_region_tlv - (IWL_FW_INI_TLV_TYPE_REGION_CFG) + * DUMP sections define IDs and triggers that use those IDs TLV + * @header: header + * @num_regions: how many different region section and IDs are coming next + * @region_config: list of dump configurations + */ +struct iwl_fw_ini_region_tlv { + struct iwl_fw_ini_header header; + __le32 num_regions; + struct iwl_fw_ini_region_cfg region_config[]; +} __packed; /* FW_DEBUG_TLV_REGIONS_S_VER_1 */ + +/** + * struct iwl_fw_ini_trigger - (IWL_FW_INI_TLV_TYPE_DUMP_CFG) + * Region sections define IDs and triggers that use those IDs TLV + * + * @trigger_id: enum &iwl_fw_ini_tigger_id + * @override_trig: determines how apply trigger in case a trigger with the + * same id is already in use. Using the first 2 bytes: + * Byte 0: if 0, override trigger configuration, otherwise use the + * existing configuration. + * Byte 1: if 0, override trigger regions, otherwise append regions to + * existing trigger. + * @dump_delay: delay from trigger fire to dump, in usec + * @occurrences: max amount of times to be fired + * @ignore_consec: ignore consecutive triggers, in usec + * @force_restart: force FW restart + * @multi_dut: initiate debug dump data on several DUTs + * @trigger_data: generic data to be utilized per trigger + * @num_regions: number of dump regions defined for this trigger + * @data: region IDs + */ +struct iwl_fw_ini_trigger { + __le32 trigger_id; + __le32 override_trig; + __le32 dump_delay; + __le32 occurrences; + __le32 ignore_consec; + __le32 force_restart; + __le32 multi_dut; + __le32 trigger_data; + __le32 num_regions; + __le32 data[]; +} __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_S */ + +/** + * struct iwl_fw_ini_trigger_tlv - (IWL_FW_INI_TLV_TYPE_TRIGGERS_CFG) + * DUMP sections define IDs and triggers that use those IDs TLV + * + * @header: header + * @num_triggers: how many different triggers section and IDs are coming next + * @trigger_config: list of trigger configurations + */ +struct iwl_fw_ini_trigger_tlv { + struct iwl_fw_ini_header header; + __le32 num_triggers; + struct iwl_fw_ini_trigger trigger_config[]; +} __packed; /* FW_TLV_DEBUG_TRIGGERS_S_VER_1 */ + +/** + * enum iwl_fw_ini_trigger_id + * @IWL_FW_TRIGGER_ID_FW_ASSERT: FW assert + * @IWL_FW_TRIGGER_ID_FW_HW_ERROR: HW assert + * @IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG: TFD queue hang + * @IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER: FW debug notification + * @IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFOCATION: FW generic notification + * @IWL_FW_TRIGGER_ID_USER_TRIGGER: User trigger + * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY: peer inactivity + * @IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED: TX latency + * threshold was crossed + * @IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED: TX failed + * @IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER: Deauth initiated by host + * @IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST: stop GO request + * @IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST: start GO request + * @IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST: join P2P group request + * @IWL_FW_TRIGGER_ID_HOST_SCAN_START: scan started event + * @IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED: undefined + * @IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS: undefined + * @IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG: undefined + * @IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED: BAR frame was received + * @IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED: agg TX failed + * @IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED: EAPOL TX failed + * @IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED: suspicious TX response + * @IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT: received suspicious auth + * @IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE: roaming was completed + * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED: fast assoc failed + * @IWL_FW_TRIGGER_ID_HOST_D3_START: D3 start + * @IWL_FW_TRIGGER_ID_HOST_D3_END: D3 end + * @IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS: missed beacon events + * @IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS: P2P missed beacon events + * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES: undefined + * @IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED: undefined + * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED: authentication / association + * failed + * @IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE: scan complete event + * @IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT: scan abort complete + * @IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE: nic alive message was received + * @IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE: CSA was completed + * @IWL_FW_TRIGGER_ID_NUM: number of trigger IDs + */ +enum iwl_fw_ini_trigger_id { + IWL_FW_TRIGGER_ID_INVALID = 0, + + /* Errors triggers */ + IWL_FW_TRIGGER_ID_FW_ASSERT = 1, + IWL_FW_TRIGGER_ID_FW_HW_ERROR = 2, + IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG = 3, + + /* FW triggers */ + IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER = 4, + IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFOCATION = 5, + + /* User trigger */ + IWL_FW_TRIGGER_ID_USER_TRIGGER = 6, + + /* Host triggers */ + IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY = 7, + IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED = 8, + IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED = 9, + IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER = 10, + IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST = 11, + IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST = 12, + IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST = 13, + IWL_FW_TRIGGER_ID_HOST_SCAN_START = 14, + IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED = 15, + IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS = 16, + IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG = 17, + IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED = 18, + IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED = 19, + IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED = 20, + IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED = 21, + IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT = 22, + IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE = 23, + IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED = 24, + IWL_FW_TRIGGER_ID_HOST_D3_START = 25, + IWL_FW_TRIGGER_ID_HOST_D3_END = 26, + IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS = 27, + IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS = 28, + IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES = 29, + IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED = 30, + IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED = 31, + IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE = 32, + IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT = 33, + IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE = 34, + IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE = 35, + + IWL_FW_TRIGGER_ID_NUM, +}; /* FW_DEBUG_TLV_TRIGGER_ID_E_VER_1 */ + +/** + * enum iwl_fw_ini_apply_point + * @IWL_FW_INI_APPLY_INVALID: invalid + * @IWL_FW_INI_APPLY_EARLY: pre loading FW + * @IWL_FW_INI_APPLY_AFTER_ALIVE: first cmd from host after alive + * @IWL_FW_INI_APPLY_POST_INIT: last cmd in initialization sequence + * @IWL_FW_INI_APPLY_MISSED_BEACONS: missed beacons notification + * @IWL_FW_INI_APPLY_SCAN_COMPLETE: scan completed + * @IWL_FW_INI_APPLY_NUM: number of apply points +*/ +enum iwl_fw_ini_apply_point { + IWL_FW_INI_APPLY_INVALID, + IWL_FW_INI_APPLY_EARLY, + IWL_FW_INI_APPLY_AFTER_ALIVE, + IWL_FW_INI_APPLY_POST_INIT, + IWL_FW_INI_APPLY_MISSED_BEACONS, + IWL_FW_INI_APPLY_SCAN_COMPLETE, + IWL_FW_INI_APPLY_NUM, +}; /* FW_DEBUG_TLV_APPLY_POINT_E_VER_1 */ + +/** + * enum iwl_fw_ini_allocation_id + * @IWL_FW_INI_ALLOCATION_INVALID: invalid + * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration + * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration + * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration + * @IWL_FW_INI_ALLOCATION_ID_SDFX: for SDFX module + * @IWL_FW_INI_ALLOCATION_ID_FW_DUMP: used for crash and runtime dumps + * @IWL_FW_INI_ALLOCATION_ID_USER_DEFINED: for future user scenarios +*/ +enum iwl_fw_ini_allocation_id { + IWL_FW_INI_ALLOCATION_INVALID, + IWL_FW_INI_ALLOCATION_ID_DBGC1, + IWL_FW_INI_ALLOCATION_ID_DBGC2, + IWL_FW_INI_ALLOCATION_ID_DBGC3, + IWL_FW_INI_ALLOCATION_ID_SDFX, + IWL_FW_INI_ALLOCATION_ID_FW_DUMP, + IWL_FW_INI_ALLOCATION_ID_USER_DEFINED, +}; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ + +/** + * enum iwl_fw_ini_buffer_location + * @IWL_FW_INI_LOCATION_INVALID: invalid + * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location + * @IWL_FW_INI_LOCATION_DRAM_PATH: DRAM location + */ +enum iwl_fw_ini_buffer_location { + IWL_FW_INI_LOCATION_INVALID, + IWL_FW_INI_LOCATION_SRAM_PATH, + IWL_FW_INI_LOCATION_DRAM_PATH, +}; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ + +/** + * enum iwl_fw_ini_debug_flow + * @IWL_FW_INI_DEBUG_INVALID: invalid + * @IWL_FW_INI_DEBUG_DBTR_FLOW: undefined + * @IWL_FW_INI_DEBUG_TB2DTF_FLOW: undefined + */ +enum iwl_fw_ini_debug_flow { + IWL_FW_INI_DEBUG_INVALID, + IWL_FW_INI_DEBUG_DBTR_FLOW, + IWL_FW_INI_DEBUG_TB2DTF_FLOW, +}; /* FW_DEBUG_TLV_FLOW_E_VER_1 */ + +/** + * enum iwl_fw_ini_region_type + * @IWL_FW_INI_REGION_INVALID: invalid + * @IWL_FW_INI_REGION_DEVICE_MEMORY: device internal memory + * @IWL_FW_INI_REGION_PERIPHERY_MAC: periphery registers of MAC + * @IWL_FW_INI_REGION_PERIPHERY_PHY: periphery registers of PHY + * @IWL_FW_INI_REGION_PERIPHERY_AUX: periphery registers of AUX + * @IWL_FW_INI_REGION_DRAM_BUFFER: DRAM buffer + * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory + * @IWL_FW_INI_REGION_INTERNAL_BUFFER: undefined + * @IWL_FW_INI_REGION_TXF: TX fifos + * @IWL_FW_INI_REGION_RXF: RX fifo + * @IWL_FW_INI_REGION_PAGING: paging memory + * @IWL_FW_INI_REGION_CSR: CSR registers + * @IWL_FW_INI_REGION_NUM: number of region types + */ +enum iwl_fw_ini_region_type { + IWL_FW_INI_REGION_INVALID, + IWL_FW_INI_REGION_DEVICE_MEMORY, + IWL_FW_INI_REGION_PERIPHERY_MAC, + IWL_FW_INI_REGION_PERIPHERY_PHY, + IWL_FW_INI_REGION_PERIPHERY_AUX, + IWL_FW_INI_REGION_DRAM_BUFFER, + IWL_FW_INI_REGION_DRAM_IMR, + IWL_FW_INI_REGION_INTERNAL_BUFFER, + IWL_FW_INI_REGION_TXF, + IWL_FW_INI_REGION_RXF, + IWL_FW_INI_REGION_PAGING, + IWL_FW_INI_REGION_CSR, + IWL_FW_INI_REGION_NUM +}; /* FW_DEBUG_TLV_REGION_TYPE_E_VER_1 */ + +#endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index dc1fa377087a..988584973aba 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -335,29 +335,11 @@ struct iwl_dbg_mem_access_rsp { __le32 data[]; } __packed; /* DEBUG_(U|L)MAC_RD_WR_RSP_API_S_VER_1 */ -#define CONT_REC_COMMAND_SIZE 80 -#define ENABLE_CONT_RECORDING 0x15 -#define DISABLE_CONT_RECORDING 0x16 +#define LDBG_CFG_COMMAND_SIZE 80 #define BUFFER_ALLOCATION 0x27 #define START_DEBUG_RECORDING 0x29 #define STOP_DEBUG_RECORDING 0x2A -/* - * struct iwl_continuous_record_mode - recording mode - */ -struct iwl_continuous_record_mode { - __le16 enable_recording; -} __packed; - -/* - * struct iwl_continuous_record_cmd - enable/disable continuous recording - */ -struct iwl_continuous_record_cmd { - struct iwl_continuous_record_mode record_mode; - u8 pad[CONT_REC_COMMAND_SIZE - - sizeof(struct iwl_continuous_record_mode)]; -} __packed; - /* maximum fragments to be allocated per target of allocationId */ #define IWL_BUFFER_LOCATION_MAX_FRAGS 2 @@ -385,4 +367,17 @@ struct iwl_buffer_allocation_cmd { struct iwl_fragment_data fragments[IWL_BUFFER_LOCATION_MAX_FRAGS]; } __packed; /* BUFFER_ALLOCATION_CMD_API_S_VER_1 */ +/** + * struct iwl_ldbg_config_cmd - LDBG config command + * @type: configuration type + * @pad: reserved space for type-dependent data + */ +struct iwl_ldbg_config_cmd { + __le32 type; + union { + u8 pad[LDBG_CFG_COMMAND_SIZE - sizeof(__le32)]; + struct iwl_buffer_allocation_cmd buffer_allocation; + }; /* LDBG_CFG_BODY_API_U_VER_2 (partially) */ +} __packed; /* LDBG_CFG_CMD_API_S_VER_2 */ + #endif /* __iwl_fw_api_debug_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h new file mode 100644 index 000000000000..5dddb21c1c4d --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -0,0 +1,878 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2019 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_location_h__ +#define __iwl_fw_api_location_h__ + +/** + * enum iwl_location_subcmd_ids - location group command IDs + */ +enum iwl_location_subcmd_ids { + /** + * @TOF_RANGE_REQ_CMD: TOF ranging request, + * uses &struct iwl_tof_range_req_cmd + */ + TOF_RANGE_REQ_CMD = 0x0, + /** + * @TOF_CONFIG_CMD: TOF configuration, uses &struct iwl_tof_config_cmd + */ + TOF_CONFIG_CMD = 0x1, + /** + * @TOF_RANGE_ABORT_CMD: abort ongoing ranging, uses + * &struct iwl_tof_range_abort_cmd + */ + TOF_RANGE_ABORT_CMD = 0x2, + /** + * @TOF_RANGE_REQ_EXT_CMD: TOF extended ranging config, + * uses &struct iwl_tof_range_request_ext_cmd + */ + TOF_RANGE_REQ_EXT_CMD = 0x3, + /** + * @TOF_RESPONDER_CONFIG_CMD: FTM responder configuration, + * uses &struct iwl_tof_responder_config_cmd + */ + TOF_RESPONDER_CONFIG_CMD = 0x4, + /** + * @TOF_RESPONDER_DYN_CONFIG_CMD: FTM dynamic configuration, + * uses &struct iwl_tof_responder_dyn_config_cmd + */ + TOF_RESPONDER_DYN_CONFIG_CMD = 0x5, + /** + * @CSI_HEADER_NOTIFICATION: CSI header + */ + CSI_HEADER_NOTIFICATION = 0xFA, + /** + * @CSI_CHUNKS_NOTIFICATION: CSI chunk, + * uses &struct iwl_csi_chunk_notification + */ + CSI_CHUNKS_NOTIFICATION = 0xFB, + /** + * @TOF_LC_NOTIF: used for LCI/civic location, contains just + * the action frame + */ + TOF_LC_NOTIF = 0xFC, + /** + * @TOF_RESPONDER_STATS: FTM responder statistics notification, + * uses &struct iwl_ftm_responder_stats + */ + TOF_RESPONDER_STATS = 0xFD, + /** + * @TOF_MCSI_DEBUG_NOTIF: MCSI debug notification, uses + * &struct iwl_tof_mcsi_notif + */ + TOF_MCSI_DEBUG_NOTIF = 0xFE, + /** + * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using + * &struct iwl_tof_range_rsp_ntfy + */ + TOF_RANGE_RESPONSE_NOTIF = 0xFF, +}; + +/** + * struct iwl_tof_config_cmd - ToF configuration + * @tof_disabled: indicates if ToF is disabled (or not) + * @one_sided_disabled: indicates if one-sided is disabled (or not) + * @is_debug_mode: indiciates if debug mode is active + * @is_buf_required: indicates if channel estimation buffer is required + */ +struct iwl_tof_config_cmd { + u8 tof_disabled; + u8 one_sided_disabled; + u8 is_debug_mode; + u8 is_buf_required; +} __packed; + +/** + * enum iwl_tof_bandwidth - values for iwl_tof_range_req_ap_entry.bandwidth + * @IWL_TOF_BW_20_LEGACY: 20 MHz non-HT + * @IWL_TOF_BW_20_HT: 20 MHz HT + * @IWL_TOF_BW_40: 40 MHz + * @IWL_TOF_BW_80: 80 MHz + * @IWL_TOF_BW_160: 160 MHz + */ +enum iwl_tof_bandwidth { + IWL_TOF_BW_20_LEGACY, + IWL_TOF_BW_20_HT, + IWL_TOF_BW_40, + IWL_TOF_BW_80, + IWL_TOF_BW_160, +}; /* LOCAT_BW_TYPE_E */ + +/* + * enum iwl_tof_algo_type - Algorithym type for range measurement request + */ +enum iwl_tof_algo_type { + IWL_TOF_ALGO_TYPE_MAX_LIKE = 0, + IWL_TOF_ALGO_TYPE_LINEAR_REG = 1, + IWL_TOF_ALGO_TYPE_FFT = 2, + + /* Keep last */ + IWL_TOF_ALGO_TYPE_INVALID, +}; /* ALGO_TYPE_E */ + +/* + * enum iwl_tof_mcsi_ntfy - Enable/Disable MCSI notifications + */ +enum iwl_tof_mcsi_enable { + IWL_TOF_MCSI_DISABLED = 0, + IWL_TOF_MCSI_ENABLED = 1, +}; /* MCSI_ENABLE_E */ + +/** + * enum iwl_tof_responder_cmd_valid_field - valid fields in the responder cfg + * @IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO: channel info is valid + * @IWL_TOF_RESPONDER_CMD_VALID_TOA_OFFSET: ToA offset is valid + * @IWL_TOF_RESPONDER_CMD_VALID_COMMON_CALIB: common calibration mode is valid + * @IWL_TOF_RESPONDER_CMD_VALID_SPECIFIC_CALIB: spefici calibration mode is + * valid + * @IWL_TOF_RESPONDER_CMD_VALID_BSSID: BSSID is valid + * @IWL_TOF_RESPONDER_CMD_VALID_TX_ANT: TX antenna is valid + * @IWL_TOF_RESPONDER_CMD_VALID_ALGO_TYPE: algorithm type is valid + * @IWL_TOF_RESPONDER_CMD_VALID_NON_ASAP_SUPPORT: non-ASAP support is valid + * @IWL_TOF_RESPONDER_CMD_VALID_STATISTICS_REPORT_SUPPORT: statistics report + * support is valid + * @IWL_TOF_RESPONDER_CMD_VALID_MCSI_NOTIF_SUPPORT: MCSI notification support + * is valid + * @IWL_TOF_RESPONDER_CMD_VALID_FAST_ALGO_SUPPORT: fast algorithm support + * is valid + * @IWL_TOF_RESPONDER_CMD_VALID_RETRY_ON_ALGO_FAIL: retry on algorithm failure + * is valid + * @IWL_TOF_RESPONDER_CMD_VALID_STA_ID: station ID is valid + */ +enum iwl_tof_responder_cmd_valid_field { + IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO = BIT(0), + IWL_TOF_RESPONDER_CMD_VALID_TOA_OFFSET = BIT(1), + IWL_TOF_RESPONDER_CMD_VALID_COMMON_CALIB = BIT(2), + IWL_TOF_RESPONDER_CMD_VALID_SPECIFIC_CALIB = BIT(3), + IWL_TOF_RESPONDER_CMD_VALID_BSSID = BIT(4), + IWL_TOF_RESPONDER_CMD_VALID_TX_ANT = BIT(5), + IWL_TOF_RESPONDER_CMD_VALID_ALGO_TYPE = BIT(6), + IWL_TOF_RESPONDER_CMD_VALID_NON_ASAP_SUPPORT = BIT(7), + IWL_TOF_RESPONDER_CMD_VALID_STATISTICS_REPORT_SUPPORT = BIT(8), + IWL_TOF_RESPONDER_CMD_VALID_MCSI_NOTIF_SUPPORT = BIT(9), + IWL_TOF_RESPONDER_CMD_VALID_FAST_ALGO_SUPPORT = BIT(10), + IWL_TOF_RESPONDER_CMD_VALID_RETRY_ON_ALGO_FAIL = BIT(11), + IWL_TOF_RESPONDER_CMD_VALID_STA_ID = BIT(12), +}; + +/** + * enum iwl_tof_responder_cfg_flags - responder configuration flags + * @IWL_TOF_RESPONDER_FLAGS_NON_ASAP_SUPPORT: non-ASAP support + * @IWL_TOF_RESPONDER_FLAGS_REPORT_STATISTICS: report statistics + * @IWL_TOF_RESPONDER_FLAGS_REPORT_MCSI: report MCSI + * @IWL_TOF_RESPONDER_FLAGS_ALGO_TYPE: algorithm type + * @IWL_TOF_RESPONDER_FLAGS_TOA_OFFSET_MODE: ToA offset mode + * @IWL_TOF_RESPONDER_FLAGS_COMMON_CALIB_MODE: common calibration mode + * @IWL_TOF_RESPONDER_FLAGS_SPECIFIC_CALIB_MODE: specific calibration mode + * @IWL_TOF_RESPONDER_FLAGS_FAST_ALGO_SUPPORT: fast algorithm support + * @IWL_TOF_RESPONDER_FLAGS_RETRY_ON_ALGO_FAIL: retry on algorithm fail + * @IWL_TOF_RESPONDER_FLAGS_FTM_TX_ANT: TX antenna mask + */ +enum iwl_tof_responder_cfg_flags { + IWL_TOF_RESPONDER_FLAGS_NON_ASAP_SUPPORT = BIT(0), + IWL_TOF_RESPONDER_FLAGS_REPORT_STATISTICS = BIT(1), + IWL_TOF_RESPONDER_FLAGS_REPORT_MCSI = BIT(2), + IWL_TOF_RESPONDER_FLAGS_ALGO_TYPE = BIT(3) | BIT(4) | BIT(5), + IWL_TOF_RESPONDER_FLAGS_TOA_OFFSET_MODE = BIT(6), + IWL_TOF_RESPONDER_FLAGS_COMMON_CALIB_MODE = BIT(7), + IWL_TOF_RESPONDER_FLAGS_SPECIFIC_CALIB_MODE = BIT(8), + IWL_TOF_RESPONDER_FLAGS_FAST_ALGO_SUPPORT = BIT(9), + IWL_TOF_RESPONDER_FLAGS_RETRY_ON_ALGO_FAIL = BIT(10), + IWL_TOF_RESPONDER_FLAGS_FTM_TX_ANT = RATE_MCS_ANT_ABC_MSK, +}; + +/** + * struct iwl_tof_responder_config_cmd - ToF AP mode (for debug) + * @cmd_valid_fields: &iwl_tof_responder_cmd_valid_field + * @responder_cfg_flags: &iwl_tof_responder_cfg_flags + * @bandwidth: current AP Bandwidth: &enum iwl_tof_bandwidth + * @rate: current AP rate + * @channel_num: current AP Channel + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency, see iwl_mvm_get_ctrl_pos() + * @sta_id: index of the AP STA when in AP mode + * @reserved1: reserved + * @toa_offset: Artificial addition [pSec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @common_calib: XVT: common calibration value + * @specific_calib: XVT: specific calibration value + * @bssid: Current AP BSSID + * @reserved2: reserved + */ +struct iwl_tof_responder_config_cmd { + __le32 cmd_valid_fields; + __le32 responder_cfg_flags; + u8 bandwidth; + u8 rate; + u8 channel_num; + u8 ctrl_ch_position; + u8 sta_id; + u8 reserved1; + __le16 toa_offset; + __le16 common_calib; + __le16 specific_calib; + u8 bssid[ETH_ALEN]; + __le16 reserved2; +} __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_6 */ + +#define IWL_LCI_CIVIC_IE_MAX_SIZE 400 + +/** + * struct iwl_tof_responder_dyn_config_cmd - Dynamic responder settings + * @lci_len: The length of the 1st (LCI) part in the @lci_civic buffer + * @civic_len: The length of the 2nd (CIVIC) part in the @lci_civic buffer + * @lci_civic: The LCI/CIVIC buffer. LCI data (if exists) comes first, then, if + * needed, 0-padding such that the next part is dword-aligned, then CIVIC + * data (if exists) follows, and then 0-padding again to complete a + * 4-multiple long buffer. + */ +struct iwl_tof_responder_dyn_config_cmd { + __le32 lci_len; + __le32 civic_len; + u8 lci_civic[]; +} __packed; /* TOF_RESPONDER_DYN_CONFIG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tof_range_request_ext_cmd - extended range req for WLS + * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @reserved: reserved + * @min_delta_ftm: Minimal time between two consecutive measurements, + * in units of 100us. 0 means no preference by station + * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended + * value be sent to the AP + * @ftm_format_and_bw40M: FTM Channel Spacing/Format for 40MHz: recommended + * value to be sent to the AP + * @ftm_format_and_bw80M: FTM Channel Spacing/Format for 80MHz: recommended + * value to be sent to the AP + */ +struct iwl_tof_range_req_ext_cmd { + __le16 tsf_timer_offset_msec; + __le16 reserved; + u8 min_delta_ftm; + u8 ftm_format_and_bw20M; + u8 ftm_format_and_bw40M; + u8 ftm_format_and_bw80M; +} __packed; + +/** + * enum iwl_tof_location_query - values for query bitmap + * @IWL_TOF_LOC_LCI: query LCI + * @IWL_TOF_LOC_CIVIC: query civic + */ +enum iwl_tof_location_query { + IWL_TOF_LOC_LCI = 0x01, + IWL_TOF_LOC_CIVIC = 0x02, +}; + + /** + * struct iwl_tof_range_req_ap_entry_v2 - AP configuration parameters + * @channel_num: Current AP Channel + * @bandwidth: Current AP Bandwidth. One of iwl_tof_bandwidth. + * @tsf_delta_direction: TSF relatively to the subject AP + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency, see iwl_mvm_get_ctrl_pos(). + * @bssid: AP's BSSID + * @measure_type: Measurement type: 0 - two sided, 1 - One sided + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of the + * number of measurement iterations (min 2^0 = 1, max 2^14) + * @burst_period: Recommended value to be sent to the AP. Measurement + * periodicity In units of 100ms. ignored if num_of_bursts = 0 + * @samples_per_burst: 2-sided: the number of FTMs pairs in single Burst (1-31); + * 1-sided: how many rts/cts pairs should be used per burst. + * @retries_per_sample: Max number of retries that the LMAC should send + * in case of no replies by the AP. + * @tsf_delta: TSF Delta in units of microseconds. + * The difference between the AP TSF and the device local clock. + * @location_req: Location Request Bit[0] LCI should be sent in the FTMR; + * Bit[1] Civic should be sent in the FTMR + * @asap_mode: 0 - non asap mode, 1 - asap mode (not relevant for one sided) + * @enable_dyn_ack: Enable Dynamic ACK BW. + * 0: Initiator interact with regular AP; + * 1: Initiator interact with Responder machine: need to send the + * Initiator Acks with HT 40MHz / 80MHz, since the Responder should + * use it for its ch est measurement (this flag will be set when we + * configure the opposite machine to be Responder). + * @rssi: Last received value + * legal values: -128-0 (0x7f). above 0x0 indicating an invalid value. + * @algo_type: &enum iwl_tof_algo_type + * @notify_mcsi: &enum iwl_tof_mcsi_ntfy. + * @reserved: For alignment and future use + */ +struct iwl_tof_range_req_ap_entry_v2 { + u8 channel_num; + u8 bandwidth; + u8 tsf_delta_direction; + u8 ctrl_ch_position; + u8 bssid[ETH_ALEN]; + u8 measure_type; + u8 num_of_bursts; + __le16 burst_period; + u8 samples_per_burst; + u8 retries_per_sample; + __le32 tsf_delta; + u8 location_req; + u8 asap_mode; + u8 enable_dyn_ack; + s8 rssi; + u8 algo_type; + u8 notify_mcsi; + __le16 reserved; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_2 */ + +/** + * enum iwl_initiator_ap_flags - per responder FTM configuration flags + * @IWL_INITIATOR_AP_FLAGS_ASAP: Request for ASAP measurement. + * @IWL_INITIATOR_AP_FLAGS_LCI_REQUEST: Request for LCI information + * @IWL_INITIATOR_AP_FLAGS_CIVIC_REQUEST: Request for CIVIC information + * @IWL_INITIATOR_AP_FLAGS_DYN_ACK: Send HT/VHT ack for FTM frames. If not set, + * 20Mhz dup acks will be sent. + * @IWL_INITIATOR_AP_FLAGS_ALGO_LR: Use LR algo type for rtt calculation. + * Default algo type is ML. + * @IWL_INITIATOR_AP_FLAGS_ALGO_FFT: Use FFT algo type for rtt calculation. + * Default algo type is ML. + * @IWL_INITIATOR_AP_FLAGS_MCSI_REPORT: Send the MCSI for each FTM frame to the + * driver. + */ +enum iwl_initiator_ap_flags { + IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), + IWL_INITIATOR_AP_FLAGS_LCI_REQUEST = BIT(2), + IWL_INITIATOR_AP_FLAGS_CIVIC_REQUEST = BIT(3), + IWL_INITIATOR_AP_FLAGS_DYN_ACK = BIT(4), + IWL_INITIATOR_AP_FLAGS_ALGO_LR = BIT(5), + IWL_INITIATOR_AP_FLAGS_ALGO_FFT = BIT(6), + IWL_INITIATOR_AP_FLAGS_MCSI_REPORT = BIT(8), +}; + +/** + * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. + * @channel_num: AP Channel number + * @bandwidth: AP bandwidth. One of iwl_tof_bandwidth. + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency, see iwl_mvm_get_ctrl_pos(). + * @ftmr_max_retries: Max number of retries to send the FTMR in case of no + * reply from the AP. + * @bssid: AP's BSSID + * @burst_period: Recommended value to be sent to the AP. Measurement + * periodicity In units of 100ms. ignored if num_of_bursts_exp = 0 + * @samples_per_burst: the number of FTMs pairs in single Burst (1-31); + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of + * the number of measurement iterations (min 2^0 = 1, max 2^14) + * @reserved: For alignment and future use + * @tsf_delta: not in use + */ +struct iwl_tof_range_req_ap_entry { + __le32 initiator_ap_flags; + u8 channel_num; + u8 bandwidth; + u8 ctrl_ch_position; + u8 ftmr_max_retries; + u8 bssid[ETH_ALEN]; + __le16 burst_period; + u8 samples_per_burst; + u8 num_of_bursts; + __le16 reserved; + __le32 tsf_delta; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_3 */ + +/** + * enum iwl_tof_response_mode + * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as + * possible (not supported for this release) + * @IWL_MVM_TOF_RESPONSE_TIMEOUT: report all AP measurements as a batch upon + * timeout expiration + * @IWL_MVM_TOF_RESPONSE_COMPLETE: report all AP measurements as a batch at the + * earlier of: measurements completion / timeout + * expiration. + */ +enum iwl_tof_response_mode { + IWL_MVM_TOF_RESPONSE_ASAP, + IWL_MVM_TOF_RESPONSE_TIMEOUT, + IWL_MVM_TOF_RESPONSE_COMPLETE, +}; + +/** + * enum iwl_tof_initiator_flags + * + * @IWL_TOF_INITIATOR_FLAGS_FAST_ALGO_DISABLED: disable fast algo, meaning run + * the algo on ant A+B, instead of only one of them. + * @IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_A: open RX antenna A for FTMs RX + * @IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_B: open RX antenna B for FTMs RX + * @IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_C: open RX antenna C for FTMs RX + * @IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_A: use antenna A fo TX ACKs during FTM + * @IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_B: use antenna B fo TX ACKs during FTM + * @IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_C: use antenna C fo TX ACKs during FTM + * @IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM: use random mac address for FTM + * @IWL_TOF_INITIATOR_FLAGS_SPECIFIC_CALIB: use the specific calib value from + * the range request command + * @IWL_TOF_INITIATOR_FLAGS_COMMON_CALIB: use the common calib value from the + * ragne request command + * @IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT: support non-asap measurements + */ +enum iwl_tof_initiator_flags { + IWL_TOF_INITIATOR_FLAGS_FAST_ALGO_DISABLED = BIT(0), + IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_A = BIT(1), + IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_B = BIT(2), + IWL_TOF_INITIATOR_FLAGS_RX_CHAIN_SEL_C = BIT(3), + IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_A = BIT(4), + IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_B = BIT(5), + IWL_TOF_INITIATOR_FLAGS_TX_CHAIN_SEL_C = BIT(6), + IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM = BIT(7), + IWL_TOF_INITIATOR_FLAGS_SPECIFIC_CALIB = BIT(15), + IWL_TOF_INITIATOR_FLAGS_COMMON_CALIB = BIT(16), + IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT = BIT(20), +}; /* LOCATION_RANGE_REQ_CMD_API_S_VER_5 */ + +#define IWL_MVM_TOF_MAX_APS 5 +#define IWL_MVM_TOF_MAX_TWO_SIDED_APS 5 + +/** + * struct iwl_tof_range_req_cmd_v5 - start measurement cmd + * @initiator_flags: see flags @ iwl_tof_initiator_flags + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @initiator: 0- NW initiated, 1 - Client Initiated + * @one_sided_los_disable: '0'- run ML-Algo for both ToF/OneSided, + * '1' - run ML-Algo for ToF only + * @req_timeout: Requested timeout of the response in units of 100ms. + * This is equivalent to the session time configured to the + * LMAC in Initiator Request + * @report_policy: Supported partially for this release: For current release - + * the range report will be uploaded as a batch when ready or + * when the session is done (successfully / partially). + * one of iwl_tof_response_mode. + * @reserved0: reserved + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @macaddr_random: '0' Use default source MAC address (i.e. p2_p), + * '1' Use MAC Address randomization according to the below + * @range_req_bssid: ranging request BSSID + * @macaddr_template: MAC address template to use for non-randomized bits + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + * @ftm_rx_chains: Rx chain to open to receive Responder's FTMs (XVT) + * @ftm_tx_chains: Tx chain to send the ack to the Responder FTM (XVT) + * @common_calib: The common calib value to inject to this measurement calc + * @specific_calib: The specific calib value to inject to this measurement calc + * @ap: per-AP request data + */ +struct iwl_tof_range_req_cmd_v5 { + __le32 initiator_flags; + u8 request_id; + u8 initiator; + u8 one_sided_los_disable; + u8 req_timeout; + u8 report_policy; + u8 reserved0; + u8 num_of_ap; + u8 macaddr_random; + u8 range_req_bssid[ETH_ALEN]; + u8 macaddr_template[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + u8 ftm_rx_chains; + u8 ftm_tx_chains; + __le16 common_calib; + __le16 specific_calib; + struct iwl_tof_range_req_ap_entry_v2 ap[IWL_MVM_TOF_MAX_APS]; +} __packed; +/* LOCATION_RANGE_REQ_CMD_API_S_VER_5 */ + +/** + * struct iwl_tof_range_req_cmd - start measurement cmd + * @initiator_flags: see flags @ iwl_tof_initiator_flags + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @range_req_bssid: ranging request BSSID + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + * @macaddr_template: MAC address template to use for non-randomized bits + * @req_timeout_ms: Requested timeout of the response in units of milliseconds. + * This is the session time for completing the measurement. + * @tsf_mac_id: report the measurement start time for each ap in terms of the + * TSF of this mac id. 0xff to disable TSF reporting. + * @common_calib: The common calib value to inject to this measurement calc + * @specific_calib: The specific calib value to inject to this measurement calc + * @ap: per-AP request data, see &struct iwl_tof_range_req_ap_entry_v2. + */ +struct iwl_tof_range_req_cmd { + __le32 initiator_flags; + u8 request_id; + u8 num_of_ap; + u8 range_req_bssid[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + u8 macaddr_template[ETH_ALEN]; + __le32 req_timeout_ms; + __le32 tsf_mac_id; + __le16 common_calib; + __le16 specific_calib; + struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_7 */ + +/* + * enum iwl_tof_range_request_status - status of the sent request + * @IWL_TOF_RANGE_REQUEST_STATUS_SUCCESSFUL - FW successfully received the + * request + * @IWL_TOF_RANGE_REQUEST_STATUS_BUSY - FW is busy with a previous request, the + * sent request will not be handled + */ +enum iwl_tof_range_request_status { + IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS, + IWL_TOF_RANGE_REQUEST_STATUS_BUSY, +}; + +/** + * enum iwl_tof_entry_status + * + * @IWL_TOF_ENTRY_SUCCESS: successful measurement. + * @IWL_TOF_ENTRY_GENERAL_FAILURE: General failure. + * @IWL_TOF_ENTRY_NO_RESPONSE: Responder didn't reply to the request. + * @IWL_TOF_ENTRY_REQUEST_REJECTED: Responder rejected the request. + * @IWL_TOF_ENTRY_NOT_SCHEDULED: Time event was scheduled but not called yet. + * @IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT: Time event triggered but no + * measurement was completed. + * @IWL_TOF_ENTRY_TARGET_DIFF_CH_CANNOT_CHANGE: No range due inability to switch + * from the primary channel. + * @IWL_TOF_ENTRY_RANGE_NOT_SUPPORTED: Device doesn't support FTM. + * @IWL_TOF_ENTRY_REQUEST_ABORT_UNKNOWN_REASON: Request aborted due to unknown + * reason. + * @IWL_TOF_ENTRY_LOCATION_INVALID_T1_T4_TIME_STAMP: Failure due to invalid + * T1/T4. + * @IWL_TOF_ENTRY_11MC_PROTOCOL_FAILURE: Failure due to invalid FTM frame + * structure. + * @IWL_TOF_ENTRY_REQUEST_CANNOT_SCHED: Request cannot be scheduled. + * @IWL_TOF_ENTRY_RESPONDER_CANNOT_COLABORATE: Responder cannot serve the + * initiator for some period, period supplied in @refusal_period. + * @IWL_TOF_ENTRY_BAD_REQUEST_ARGS: Bad request arguments. + * @IWL_TOF_ENTRY_WIFI_NOT_ENABLED: Wifi not enabled. + * @IWL_TOF_ENTRY_RESPONDER_OVERRIDE_PARAMS: Responder override the original + * parameters within the current session. + */ +enum iwl_tof_entry_status { + IWL_TOF_ENTRY_SUCCESS = 0, + IWL_TOF_ENTRY_GENERAL_FAILURE = 1, + IWL_TOF_ENTRY_NO_RESPONSE = 2, + IWL_TOF_ENTRY_REQUEST_REJECTED = 3, + IWL_TOF_ENTRY_NOT_SCHEDULED = 4, + IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT = 5, + IWL_TOF_ENTRY_TARGET_DIFF_CH_CANNOT_CHANGE = 6, + IWL_TOF_ENTRY_RANGE_NOT_SUPPORTED = 7, + IWL_TOF_ENTRY_REQUEST_ABORT_UNKNOWN_REASON = 8, + IWL_TOF_ENTRY_LOCATION_INVALID_T1_T4_TIME_STAMP = 9, + IWL_TOF_ENTRY_11MC_PROTOCOL_FAILURE = 10, + IWL_TOF_ENTRY_REQUEST_CANNOT_SCHED = 11, + IWL_TOF_ENTRY_RESPONDER_CANNOT_COLABORATE = 12, + IWL_TOF_ENTRY_BAD_REQUEST_ARGS = 13, + IWL_TOF_ENTRY_WIFI_NOT_ENABLED = 14, + IWL_TOF_ENTRY_RESPONDER_OVERRIDE_PARAMS = 15, +}; /* LOCATION_RANGE_RSP_AP_ENTRY_NTFY_API_S_VER_2 */ + +/** + * struct iwl_tof_range_rsp_ap_entry_ntfy_v3 - AP parameters (response) + * @bssid: BSSID of the AP + * @measure_status: current APs measurement status, one of + * &enum iwl_tof_entry_status. + * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rtt: The Round Trip Time that took for the last measurement for + * current AP [pSec] + * @rtt_variance: The Variance of the RTT values measured for current AP + * @rtt_spread: The Difference between the maximum and the minimum RTT + * values measured for current AP in the current session [pSec] + * @rssi: RSSI as uploaded in the Channel Estimation notification + * @rssi_spread: The Difference between the maximum and the minimum RSSI values + * measured for current AP in the current session + * @reserved: reserved + * @refusal_period: refusal period in case of + * @IWL_TOF_ENTRY_RESPONDER_CANNOT_COLABORATE [sec] + * @range: Measured range [cm] + * @range_variance: Measured range variance [cm] + * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was + * uploaded by the LMAC + * @t2t3_initiator: as calculated from the algo in the initiator + * @t1t4_responder: as calculated from the algo in the responder + * @common_calib: Calib val that was used in for this AP measurement + * @specific_calib: val that was used in for this AP measurement + * @papd_calib_output: The result of the tof papd calibration that was injected + * into the algorithm. + */ +struct iwl_tof_range_rsp_ap_entry_ntfy_v3 { + u8 bssid[ETH_ALEN]; + u8 measure_status; + u8 measure_bw; + __le32 rtt; + __le32 rtt_variance; + __le32 rtt_spread; + s8 rssi; + u8 rssi_spread; + u8 reserved; + u8 refusal_period; + __le32 range; + __le32 range_variance; + __le32 timestamp; + __le32 t2t3_initiator; + __le32 t1t4_responder; + __le16 common_calib; + __le16 specific_calib; + __le32 papd_calib_output; +} __packed; /* LOCATION_RANGE_RSP_AP_ETRY_NTFY_API_S_VER_3 */ + +/** + * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) + * @bssid: BSSID of the AP + * @measure_status: current APs measurement status, one of + * &enum iwl_tof_entry_status. + * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rtt: The Round Trip Time that took for the last measurement for + * current AP [pSec] + * @rtt_variance: The Variance of the RTT values measured for current AP + * @rtt_spread: The Difference between the maximum and the minimum RTT + * values measured for current AP in the current session [pSec] + * @rssi: RSSI as uploaded in the Channel Estimation notification + * @rssi_spread: The Difference between the maximum and the minimum RSSI values + * measured for current AP in the current session + * @last_burst: 1 if no more FTM sessions are scheduled for this responder + * @refusal_period: refusal period in case of + * @IWL_TOF_ENTRY_RESPONDER_CANNOT_COLABORATE [sec] + * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was + * uploaded by the LMAC + * @start_tsf: measurement start time in TSF of the mac specified in the range + * request + * @rx_rate_n_flags: rate and flags of the last FTM frame received from this + * responder + * @tx_rate_n_flags: rate and flags of the last ack sent to this responder + * @t2t3_initiator: as calculated from the algo in the initiator + * @t1t4_responder: as calculated from the algo in the responder + * @common_calib: Calib val that was used in for this AP measurement + * @specific_calib: val that was used in for this AP measurement + * @papd_calib_output: The result of the tof papd calibration that was injected + * into the algorithm. + */ +struct iwl_tof_range_rsp_ap_entry_ntfy { + u8 bssid[ETH_ALEN]; + u8 measure_status; + u8 measure_bw; + __le32 rtt; + __le32 rtt_variance; + __le32 rtt_spread; + s8 rssi; + u8 rssi_spread; + u8 last_burst; + u8 refusal_period; + __le32 timestamp; + __le32 start_tsf; + __le32 rx_rate_n_flags; + __le32 tx_rate_n_flags; + __le32 t2t3_initiator; + __le32 t1t4_responder; + __le16 common_calib; + __le16 specific_calib; + __le32 papd_calib_output; +} __packed; /* LOCATION_RANGE_RSP_AP_ETRY_NTFY_API_S_VER_4 */ + +/** + * enum iwl_tof_response_status - tof response status + * + * @IWL_TOF_RESPONSE_SUCCESS: successful range. + * @IWL_TOF_RESPONSE_TIMEOUT: request aborted due to timeout expiration. + * partial result of ranges done so far is included in the response. + * @IWL_TOF_RESPONSE_ABORTED: Measurement aborted by command. + * @IWL_TOF_RESPONSE_FAILED: Measurement request command failed. + */ +enum iwl_tof_response_status { + IWL_TOF_RESPONSE_SUCCESS = 0, + IWL_TOF_RESPONSE_TIMEOUT = 1, + IWL_TOF_RESPONSE_ABORTED = 4, + IWL_TOF_RESPONSE_FAILED = 5, +}; /* LOCATION_RNG_RSP_STATUS */ + +/** + * struct iwl_tof_range_rsp_ntfy_v5 - ranging response notification + * @request_id: A Token ID of the corresponding Range request + * @request_status: status of current measurement session, one of + * &enum iwl_tof_response_status. + * @last_in_batch: reprot policy (when not all responses are uploaded at once) + * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @ap: per-AP data + */ +struct iwl_tof_range_rsp_ntfy_v5 { + u8 request_id; + u8 request_status; + u8 last_in_batch; + u8 num_of_aps; + struct iwl_tof_range_rsp_ap_entry_ntfy_v3 ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_RSP_NTFY_API_S_VER_5 */ + +/** + * struct iwl_tof_range_rsp_ntfy - ranging response notification + * @request_id: A Token ID of the corresponding Range request + * @num_of_aps: Number of APs results + * @last_report: 1 if no more FTM sessions are scheduled, 0 otherwise. + * @reserved: reserved + * @ap: per-AP data + */ +struct iwl_tof_range_rsp_ntfy { + u8 request_id; + u8 num_of_aps; + u8 last_report; + u8 reserved; + struct iwl_tof_range_rsp_ap_entry_ntfy ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_RSP_NTFY_API_S_VER_6 */ + +#define IWL_MVM_TOF_MCSI_BUF_SIZE (245) +/** + * struct iwl_tof_mcsi_notif - used for debug + * @token: token ID for the current session + * @role: '0' - initiator, '1' - responder + * @reserved: reserved + * @initiator_bssid: initiator machine + * @responder_bssid: responder machine + * @mcsi_buffer: debug data + */ +struct iwl_tof_mcsi_notif { + u8 token; + u8 role; + __le16 reserved; + u8 initiator_bssid[ETH_ALEN]; + u8 responder_bssid[ETH_ALEN]; + u8 mcsi_buffer[IWL_MVM_TOF_MCSI_BUF_SIZE * 4]; +} __packed; + +/** + * struct iwl_tof_range_abort_cmd + * @request_id: corresponds to a range request + * @reserved: reserved + */ +struct iwl_tof_range_abort_cmd { + u8 request_id; + u8 reserved[3]; +} __packed; + +enum ftm_responder_stats_flags { + FTM_RESP_STAT_NON_ASAP_STARTED = BIT(0), + FTM_RESP_STAT_NON_ASAP_IN_WIN = BIT(1), + FTM_RESP_STAT_NON_ASAP_OUT_WIN = BIT(2), + FTM_RESP_STAT_TRIGGER_DUP = BIT(3), + FTM_RESP_STAT_DUP = BIT(4), + FTM_RESP_STAT_DUP_IN_WIN = BIT(5), + FTM_RESP_STAT_DUP_OUT_WIN = BIT(6), + FTM_RESP_STAT_SCHED_SUCCESS = BIT(7), + FTM_RESP_STAT_ASAP_REQ = BIT(8), + FTM_RESP_STAT_NON_ASAP_REQ = BIT(9), + FTM_RESP_STAT_ASAP_RESP = BIT(10), + FTM_RESP_STAT_NON_ASAP_RESP = BIT(11), + FTM_RESP_STAT_FAIL_INITIATOR_INACTIVE = BIT(12), + FTM_RESP_STAT_FAIL_INITIATOR_OUT_WIN = BIT(13), + FTM_RESP_STAT_FAIL_INITIATOR_RETRY_LIM = BIT(14), + FTM_RESP_STAT_FAIL_NEXT_SERVED = BIT(15), + FTM_RESP_STAT_FAIL_TRIGGER_ERR = BIT(16), + FTM_RESP_STAT_FAIL_GC = BIT(17), + FTM_RESP_STAT_SUCCESS = BIT(18), + FTM_RESP_STAT_INTEL_IE = BIT(19), + FTM_RESP_STAT_INITIATOR_ACTIVE = BIT(20), + FTM_RESP_STAT_MEASUREMENTS_AVAILABLE = BIT(21), + FTM_RESP_STAT_TRIGGER_UNKNOWN = BIT(22), + FTM_RESP_STAT_PROCESS_FAIL = BIT(23), + FTM_RESP_STAT_ACK = BIT(24), + FTM_RESP_STAT_NACK = BIT(25), + FTM_RESP_STAT_INVALID_INITIATOR_ID = BIT(26), + FTM_RESP_STAT_TIMER_MIN_DELTA = BIT(27), + FTM_RESP_STAT_INITIATOR_REMOVED = BIT(28), + FTM_RESP_STAT_INITIATOR_ADDED = BIT(29), + FTM_RESP_STAT_ERR_LIST_FULL = BIT(30), + FTM_RESP_STAT_INITIATOR_SCHED_NOW = BIT(31), +}; /* RESP_IND_E */ + +/** + * struct iwl_ftm_responder_stats - FTM responder statistics + * @addr: initiator address + * @success_ftm: number of successful ftm frames + * @ftm_per_burst: num of FTM frames that were received + * @flags: &enum ftm_responder_stats_flags + * @duration: actual duration of FTM + * @allocated_duration: time that was allocated for this FTM session + * @bw: FTM request bandwidth + * @rate: FTM request rate + * @reserved: for alingment and future use + */ +struct iwl_ftm_responder_stats { + u8 addr[ETH_ALEN]; + u8 success_ftm; + u8 ftm_per_burst; + __le32 flags; + __le32 duration; + __le32 allocated_duration; + u8 bw; + u8 rate; + __le16 reserved; +} __packed; /* TOF_RESPONDER_STATISTICS_NTFY_S_VER_2 */ + +#define IWL_CSI_CHUNK_CTL_NUM_MASK 0x3 +#define IWL_CSI_CHUNK_CTL_IDX_MASK 0xc + +struct iwl_csi_chunk_notification { + __le32 token; + __le16 seq; + __le16 ctl; + __le32 size; + u8 data[]; +} __packed; /* CSI_CHUNKS_HDR_NTFY_API_S_VER_1 */ + +#endif /* __iwl_fw_api_location_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index ca49db786ed6..6b4d59daacd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -74,6 +74,10 @@ enum iwl_mac_conf_subcmd_ids { */ LOW_LATENCY_CMD = 0x3, /** + * @CHANNEL_SWITCH_TIME_EVENT_CMD: &struct iwl_chan_switch_te_cmd + */ + CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4, + /** * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif */ PROBE_RESPONSE_DATA_NOTIF = 0xFC, @@ -136,6 +140,29 @@ struct iwl_channel_switch_noa_notif { } __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ /** + * struct iwl_chan_switch_te_cmd - Channel Switch Time Event command + * + * @mac_id: MAC ID for channel switch + * @action: action to perform, one of FW_CTXT_ACTION_* + * @tsf: beacon tsf + * @cs_count: channel switch count from CSA/eCSA IE + * @cs_delayed_bcn_count: if set to N (!= 0) GO/AP can delay N beacon intervals + * at the new channel after the channel switch, otherwise (N == 0) expect + * beacon right after the channel switch. + * @cs_mode: 1 - quiet, 0 - otherwise + * @reserved: reserved for alignment purposes + */ +struct iwl_chan_switch_te_cmd { + __le32 mac_id; + __le32 action; + __le32 tsf; + u8 cs_count; + u8 cs_delayed_bcn_count; + u8 cs_mode; + u8 reserved; +} __packed; /* MAC_CHANNEL_SWITCH_TIME_EVENT_S_VER_2 */ + +/** * struct iwl_mac_low_latency_cmd - set/clear mac to 'low-latency mode' * * @mac_id: MAC ID to whom to apply the low-latency configurations diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 1dd23f846fb9..941c50477003 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -151,9 +151,9 @@ enum iwl_tsf_id { * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU - * @bi_reciprocal: 2^32 / bi + * @reserved1: reserved * @dtim_interval: dtim transmit time in TU - * @dtim_reciprocal: 2^32 / dtim_interval + * @reserved2: reserved * @mcast_qid: queue ID for multicast traffic. * NOTE: obsolete from VER2 and on * @beacon_template: beacon template ID @@ -162,9 +162,9 @@ struct iwl_mac_data_ap { __le32 beacon_time; __le64 beacon_tsf; __le32 bi; - __le32 bi_reciprocal; + __le32 reserved1; __le32 dtim_interval; - __le32 dtim_reciprocal; + __le32 reserved2; __le32 mcast_qid; __le32 beacon_template; } __packed; /* AP_MAC_DATA_API_S_VER_2 */ @@ -174,26 +174,34 @@ struct iwl_mac_data_ap { * @beacon_time: beacon transmit time in system time * @beacon_tsf: beacon transmit time in TSF * @bi: beacon interval in TU - * @bi_reciprocal: 2^32 / bi + * @reserved: reserved * @beacon_template: beacon template ID */ struct iwl_mac_data_ibss { __le32 beacon_time; __le64 beacon_tsf; __le32 bi; - __le32 bi_reciprocal; + __le32 reserved; __le32 beacon_template; } __packed; /* IBSS_MAC_DATA_API_S_VER_1 */ /** + * enum iwl_mac_data_policy - policy of the data path for this MAC + * @TWT_SUPPORTED: twt is supported + */ +enum iwl_mac_data_policy { + TWT_SUPPORTED = BIT(0), +}; + +/** * struct iwl_mac_data_sta - configuration data for station MAC context * @is_assoc: 1 for associated state, 0 otherwise * @dtim_time: DTIM arrival time in system time * @dtim_tsf: DTIM arrival time in TSF * @bi: beacon interval in TU, applicable only when associated - * @bi_reciprocal: 2^32 / bi , applicable only when associated + * @reserved1: reserved * @dtim_interval: DTIM interval in TU, applicable only when associated - * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated + * @data_policy: see &enum iwl_mac_data_policy * @listen_interval: in beacon intervals, applicable only when associated * @assoc_id: unique ID assigned by the AP during association * @assoc_beacon_arrive_time: TSF of first beacon after association @@ -203,13 +211,13 @@ struct iwl_mac_data_sta { __le32 dtim_time; __le64 dtim_tsf; __le32 bi; - __le32 bi_reciprocal; + __le32 reserved1; __le32 dtim_interval; - __le32 dtim_reciprocal; + __le32 data_policy; __le32 listen_interval; __le32 assoc_id; __le32 assoc_beacon_arrive_time; -} __packed; /* STA_MAC_DATA_API_S_VER_1 */ +} __packed; /* STA_MAC_DATA_API_S_VER_2 */ /** * struct iwl_mac_data_go - configuration data for P2P GO MAC context @@ -233,7 +241,7 @@ struct iwl_mac_data_go { struct iwl_mac_data_p2p_sta { struct iwl_mac_data_sta sta; __le32 ctwin; -} __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */ +} __packed; /* P2P_STA_MAC_DATA_API_S_VER_2 */ /** * struct iwl_mac_data_pibss - Pseudo IBSS config data @@ -378,13 +386,6 @@ struct iwl_mac_ctx_cmd { }; } __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */ -static inline u32 iwl_mvm_reciprocal(u32 v) -{ - if (!v) - return 0; - return 0xFFFFFFFF / v; -} - #define IWL_NONQOS_SEQ_GET 0x1 #define IWL_NONQOS_SEQ_SET 0x2 struct iwl_nonqos_seq_query_cmd { @@ -432,6 +433,28 @@ struct iwl_he_backoff_conf { __le16 mu_time; } __packed; /* AC_QOS_DOT11AX_API_S */ +/** + * enum iwl_he_pkt_ext_constellations - PPE constellation indices + * @IWL_HE_PKT_EXT_BPSK: BPSK + * @IWL_HE_PKT_EXT_QPSK: QPSK + * @IWL_HE_PKT_EXT_16QAM: 16-QAM + * @IWL_HE_PKT_EXT_64QAM: 64-QAM + * @IWL_HE_PKT_EXT_256QAM: 256-QAM + * @IWL_HE_PKT_EXT_1024QAM: 1024-QAM + * @IWL_HE_PKT_EXT_RESERVED: reserved value + * @IWL_HE_PKT_EXT_NONE: not defined + */ +enum iwl_he_pkt_ext_constellations { + IWL_HE_PKT_EXT_BPSK = 0, + IWL_HE_PKT_EXT_QPSK, + IWL_HE_PKT_EXT_16QAM, + IWL_HE_PKT_EXT_64QAM, + IWL_HE_PKT_EXT_256QAM, + IWL_HE_PKT_EXT_1024QAM, + IWL_HE_PKT_EXT_RESERVED, + IWL_HE_PKT_EXT_NONE, +}; + #define MAX_HE_SUPP_NSS 2 #define MAX_HE_CHANNEL_BW_INDX 4 @@ -442,7 +465,7 @@ struct iwl_he_backoff_conf { * Support for Nss x BW (or RU) matrix: * (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz) * Each entry contains 2 QAM thresholds for 8us and 16us: - * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6/7=RES + * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE * i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx: * QAM_tx < QAM_th1 --> PPE=0us * QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 45f61c6af14e..b833b80ea3d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -95,17 +97,36 @@ #define PHY_VHT_CTRL_POS_4_ABOVE (0x7) /* + * struct iwl_fw_channel_info_v1 - channel information + * * @band: PHY_BAND_* * @channel: channel number * @width: PHY_[VHT|LEGACY]_CHANNEL_* * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* */ -struct iwl_fw_channel_info { +struct iwl_fw_channel_info_v1 { u8 band; u8 channel; u8 width; u8 ctrl_pos; -} __packed; +} __packed; /* CHANNEL_CONFIG_API_S_VER_1 */ + +/* + * struct iwl_fw_channel_info - channel information + * + * @channel: channel number + * @band: PHY_BAND_* + * @width: PHY_[VHT|LEGACY]_CHANNEL_* + * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* + * @reserved: for future use and alignment + */ +struct iwl_fw_channel_info { + __le32 channel; + u8 band; + u8 width; + u8 ctrl_pos; + u8 reserved; +} __packed; /*CHANNEL_CONFIG_API_S_VER_2 */ #define PHY_RX_CHAIN_DRIVER_FORCE_POS (0) #define PHY_RX_CHAIN_DRIVER_FORCE_MSK \ @@ -134,6 +155,22 @@ struct iwl_fw_channel_info { /* TODO: complete missing documentation */ /** + * struct iwl_phy_context_cmd_tail - tail of iwl_phy_ctx_cmd for alignment with + * various channel structures. + * + * @txchain_info: ??? + * @rxchain_info: ??? + * @acquisition_data: ??? + * @dsp_cfg_flags: set to 0 + */ +struct iwl_phy_context_cmd_tail { + __le32 txchain_info; + __le32 rxchain_info; + __le32 acquisition_data; + __le32 dsp_cfg_flags; +} __packed; + +/** * struct iwl_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding @@ -142,10 +179,7 @@ struct iwl_fw_channel_info { * other value means apply new params after X usecs * @tx_param_color: ??? * @ci: channel info - * @txchain_info: ??? - * @rxchain_info: ??? - * @acquisition_data: ??? - * @dsp_cfg_flags: set to 0 + * @tail: command tail */ struct iwl_phy_context_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ @@ -155,10 +189,7 @@ struct iwl_phy_context_cmd { __le32 apply_time; __le32 tx_param_color; struct iwl_fw_channel_info ci; - __le32 txchain_info; - __le32 rxchain_info; - __le32 acquisition_data; - __le32 dsp_cfg_flags; + struct iwl_phy_context_cmd_tail tail; } __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 286a22da232d..01f003c6cff9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -200,9 +200,16 @@ struct iwl_powertable_cmd { * @DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK: * '1' Allow to save power by turning off * receiver and transmitter. '0' - does not allow. + * @DEVICE_POWER_FLAGS_ALLOW_MEM_RETENTION_MSK: + * Device Retention indication, '1' indicate retention is enabled. + * @DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK: + * 32Khz external slow clock valid indication, '1' indicate cloack is + * valid. */ enum iwl_device_power_flags { - DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), + DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), + DEVICE_POWER_FLAGS_ALLOW_MEM_RETENTION_MSK = BIT(1), + DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK = BIT(12), }; /** @@ -470,6 +477,13 @@ struct iwl_geo_tx_power_profiles_resp { * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed * for a longer period of time then this escape-timeout. Units: Beacons. * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. + * @bf_threshold_absolute_low: See below. + * @bf_threshold_absolute_high: Send Beacon to driver if Energy value calculated + * for this beacon crossed this absolute threshold. For the 'Increase' + * direction the bf_energy_absolute_low[i] is used. For the 'Decrease' + * direction the bf_energy_absolute_high[i] is used. Zero value means + * that this specific threshold is ignored for beacon filtering, and + * beacon will not be forced to be sent to driver due to this setting. */ struct iwl_beacon_filter_cmd { __le32 bf_energy_delta; @@ -483,7 +497,9 @@ struct iwl_beacon_filter_cmd { __le32 bf_escape_timer; __le32 ba_escape_timer; __le32 ba_enable_beacon_abort; -} __packed; + __le32 bf_threshold_absolute_low[2]; + __le32 bf_threshold_absolute_high[2]; +} __packed; /* BEACON_FILTER_CONFIG_API_S_VER_4 */ /* Beacon filtering and beacon abort */ #define IWL_BF_ENERGY_DELTA_DEFAULT 5 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 0537496b6eb1..6e8224ce8906 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -209,8 +209,6 @@ enum iwl_rx_phy_flags { * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors * @RX_MPDU_RES_STATUS_STA_ID_MSK: station ID mask * @RX_MDPU_RES_STATUS_STA_ID_SHIFT: station ID bit shift - * @RX_MPDU_RES_STATUS_FILTERING_MSK: filter status - * @RX_MPDU_RES_STATUS2_FILTERING_MSK: filter status 2 */ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_CRC_OK = BIT(0), @@ -238,8 +236,6 @@ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_CSUM_OK = BIT(17), RX_MDPU_RES_STATUS_STA_ID_SHIFT = 24, RX_MPDU_RES_STATUS_STA_ID_MSK = 0x1f << RX_MDPU_RES_STATUS_STA_ID_SHIFT, - RX_MPDU_RES_STATUS_FILTERING_MSK = (0xc00000), - RX_MPDU_RES_STATUS2_FILTERING_MSK = (0xc0000000), }; /* 9000 series API */ @@ -337,6 +333,8 @@ enum iwl_rx_mpdu_phy_info { IWL_RX_MPDU_PHY_AMPDU = BIT(5), IWL_RX_MPDU_PHY_AMPDU_TOGGLE = BIT(6), IWL_RX_MPDU_PHY_SHORT_PREAMBLE = BIT(7), + /* short preamble is only for CCK, for non-CCK overridden by this */ + IWL_RX_MPDU_PHY_NCCK_ADDTL_NTFY = BIT(7), IWL_RX_MPDU_PHY_TSF_OVERLOAD = BIT(8), }; @@ -345,66 +343,98 @@ enum iwl_rx_mpdu_mac_info { IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0, }; -/* - * enum iwl_rx_he_phy - HE PHY data - */ -enum iwl_rx_he_phy { - IWL_RX_HE_PHY_BEAM_CHNG = BIT(0), - IWL_RX_HE_PHY_UPLINK = BIT(1), - IWL_RX_HE_PHY_BSS_COLOR_MASK = 0xfc, - IWL_RX_HE_PHY_SPATIAL_REUSE_MASK = 0xf00, - IWL_RX_HE_PHY_SU_EXT_BW10 = BIT(12), - IWL_RX_HE_PHY_TXOP_DUR_MASK = 0xfe000, - IWL_RX_HE_PHY_LDPC_EXT_SYM = BIT(20), - IWL_RX_HE_PHY_PRE_FEC_PAD_MASK = 0x600000, - IWL_RX_HE_PHY_PE_DISAMBIG = BIT(23), - IWL_RX_HE_PHY_DOPPLER = BIT(24), +/* TSF overload low dword */ +enum iwl_rx_phy_data0 { + /* info type: HE any */ + IWL_RX_PHY_DATA0_HE_BEAM_CHNG = 0x00000001, + IWL_RX_PHY_DATA0_HE_UPLINK = 0x00000002, + IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK = 0x000000fc, + IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK = 0x00000f00, + /* 1 bit reserved */ + IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK = 0x000fe000, + IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM = 0x00100000, + IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK = 0x00600000, + IWL_RX_PHY_DATA0_HE_PE_DISAMBIG = 0x00800000, + IWL_RX_PHY_DATA0_HE_DOPPLER = 0x01000000, /* 6 bits reserved */ - IWL_RX_HE_PHY_DELIM_EOF = BIT(31), + IWL_RX_PHY_DATA0_HE_DELIM_EOF = 0x80000000, +}; + +enum iwl_rx_phy_info_type { + IWL_RX_PHY_INFO_TYPE_NONE = 0, + IWL_RX_PHY_INFO_TYPE_CCK = 1, + IWL_RX_PHY_INFO_TYPE_OFDM_LGCY = 2, + IWL_RX_PHY_INFO_TYPE_HT = 3, + IWL_RX_PHY_INFO_TYPE_VHT_SU = 4, + IWL_RX_PHY_INFO_TYPE_VHT_MU = 5, + IWL_RX_PHY_INFO_TYPE_HE_SU = 6, + IWL_RX_PHY_INFO_TYPE_HE_MU = 7, + IWL_RX_PHY_INFO_TYPE_HE_TB = 8, + IWL_RX_PHY_INFO_TYPE_HE_MU_EXT = 9, + IWL_RX_PHY_INFO_TYPE_HE_TB_EXT = 10, +}; - /* second dword - common data */ - IWL_RX_HE_PHY_HE_LTF_NUM_MASK = 0xe000000000ULL, - IWL_RX_HE_PHY_RU_ALLOC_SEC80 = BIT_ULL(32 + 8), +/* TSF overload high dword */ +enum iwl_rx_phy_data1 { + /* + * check this first - if TSF overload is set, + * see &enum iwl_rx_phy_info_type + */ + IWL_RX_PHY_DATA1_INFO_TYPE_MASK = 0xf0000000, + + /* info type: HT/VHT/HE any */ + IWL_RX_PHY_DATA1_LSIG_LEN_MASK = 0x0fff0000, + + /* info type: HE MU/MU-EXT */ + IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION = 0x00000001, + IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x0000001e, + + /* info type: HE any */ + IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK = 0x000000e0, + IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80 = 0x00000100, /* trigger encoded */ - IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL, - IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL, - IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, /* TSF low valid (first DW) */ - IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, /* TSF low/high valid (both DWs) */ - IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, /* same + SIGB-common0/1/2 valid */ - IWL_RX_HE_PHY_INFO_TYPE_TB = 0x3, /* TSF low/high valid (both DWs) */ - - /* second dword - MU data */ - IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0), - IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL, - IWL_RX_HE_PHY_MU_SIGB_MCS_MASK = 0xf000000000000ULL, - IWL_RX_HE_PHY_MU_SIGB_DCM = BIT_ULL(32 + 21), - IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL, - - /* second dword - TB data */ - IWL_RX_HE_PHY_TB_PILOT_TYPE = BIT_ULL(32 + 0), - IWL_RX_HE_PHY_TB_LOW_SS_MASK = 0xe00000000ULL + IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK = 0x0000fe00, + + /* info type: HE TB/TX-EXT */ + IWL_RX_PHY_DATA1_HE_TB_PILOT_TYPE = 0x00000001, + IWL_RX_PHY_DATA1_HE_TB_LOW_SS_MASK = 0x0000000e, }; -enum iwl_rx_he_sigb_common0 { +/* goes into Metadata DW 7 */ +enum iwl_rx_phy_data2 { + /* info type: HE MU-EXT */ /* the a1/a2/... is what the PHY/firmware calls the values */ - IWL_RX_HE_SIGB_COMMON0_CH1_RU0 = 0x000000ff, /* a1 */ - IWL_RX_HE_SIGB_COMMON0_CH1_RU2 = 0x0000ff00, /* a2 */ - IWL_RX_HE_SIGB_COMMON0_CH2_RU0 = 0x00ff0000, /* b1 */ - IWL_RX_HE_SIGB_COMMON0_CH2_RU2 = 0xff000000, /* b2 */ + IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0 = 0x000000ff, /* a1 */ + IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2 = 0x0000ff00, /* a2 */ + IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0 = 0x00ff0000, /* b1 */ + IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2 = 0xff000000, /* b2 */ + + /* info type: HE TB-EXT */ + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1 = 0x0000000f, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2 = 0x000000f0, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3 = 0x00000f00, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4 = 0x0000f000, }; -enum iwl_rx_he_sigb_common1 { - IWL_RX_HE_SIGB_COMMON1_CH1_RU1 = 0x000000ff, /* c1 */ - IWL_RX_HE_SIGB_COMMON1_CH1_RU3 = 0x0000ff00, /* c2 */ - IWL_RX_HE_SIGB_COMMON1_CH2_RU1 = 0x00ff0000, /* d1 */ - IWL_RX_HE_SIGB_COMMON1_CH2_RU3 = 0xff000000, /* d2 */ +/* goes into Metadata DW 8 */ +enum iwl_rx_phy_data3 { + /* info type: HE MU-EXT */ + IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1 = 0x000000ff, /* c1 */ + IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3 = 0x0000ff00, /* c2 */ + IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1 = 0x00ff0000, /* d1 */ + IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3 = 0xff000000, /* d2 */ }; -enum iwl_rx_he_sigb_common2 { - IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU = 0x0001, - IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU = 0x0002, - IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK = 0x0004, - IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK = 0x0008, +/* goes into Metadata DW 4 high 16 bits */ +enum iwl_rx_phy_data4 { + /* info type: HE MU-EXT */ + IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU = 0x0001, + IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU = 0x0002, + IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK = 0x0004, + IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK = 0x0008, + IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK = 0x00f0, + IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM = 0x0100, + IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK = 0x0600, }; /** @@ -419,9 +449,9 @@ struct iwl_rx_mpdu_desc_v1 { __le32 rss_hash; /** - * @sigb_common0: for HE sniffer, HE-SIG-B common part 0 + * @phy_data2: depends on info type (see @phy_data1) */ - __le32 sigb_common0; + __le32 phy_data2; }; /* DW8 - carries filter_match only when rpa_en == 1 */ @@ -432,9 +462,9 @@ struct iwl_rx_mpdu_desc_v1 { __le32 filter_match; /** - * @sigb_common1: for HE sniffer, HE-SIG-B common part 1 + * @phy_data3: depends on info type (see @phy_data1) */ - __le32 sigb_common1; + __le32 phy_data3; }; /* DW9 */ @@ -472,12 +502,19 @@ struct iwl_rx_mpdu_desc_v1 { * %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set */ __le64 tsf_on_air_rise; - /** - * @he_phy_data: - * HE PHY data, see &enum iwl_rx_he_phy, valid - * only if %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set - */ - __le64 he_phy_data; + + struct { + /** + * @phy_data0: depends on info_type, see @phy_data1 + */ + __le32 phy_data0; + /** + * @phy_data1: valid only if + * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set, + * see &enum iwl_rx_phy_data1. + */ + __le32 phy_data1; + }; }; } __packed; @@ -493,9 +530,9 @@ struct iwl_rx_mpdu_desc_v3 { __le32 filter_match; /** - * @sigb_common0: for HE sniffer, HE-SIG-B common part 0 + * @phy_data2: depends on info type (see @phy_data1) */ - __le32 sigb_common0; + __le32 phy_data2; }; /* DW8 - carries rss_hash only when rpa_en == 1 */ @@ -506,9 +543,9 @@ struct iwl_rx_mpdu_desc_v3 { __le32 rss_hash; /** - * @sigb_common1: for HE sniffer, HE-SIG-B common part 1 + * @phy_data3: depends on info type (see @phy_data1) */ - __le32 sigb_common1; + __le32 phy_data3; }; /* DW9 */ /** @@ -556,12 +593,19 @@ struct iwl_rx_mpdu_desc_v3 { * %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set */ __le64 tsf_on_air_rise; - /** - * @he_phy_data: - * HE PHY data, see &enum iwl_rx_he_phy, valid - * only if %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set - */ - __le64 he_phy_data; + + struct { + /** + * @phy_data0: depends on info_type, see @phy_data1 + */ + __le32 phy_data0; + /** + * @phy_data1: valid only if + * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set, + * see &enum iwl_rx_phy_data1. + */ + __le32 phy_data1; + }; }; /* DW16 & DW17 */ /** @@ -613,9 +657,9 @@ struct iwl_rx_mpdu_desc { __le16 l3l4_flags; /** - * @sigb_common2: for HE sniffer, HE-SIG-B common part 2 + * @phy_data4: depends on info type, see phy_data1 */ - __le16 sigb_common2; + __le16 phy_data4; }; /* DW5 */ /** @@ -651,6 +695,58 @@ struct iwl_rx_mpdu_desc { #define IWL_CD_STTS_WIFI_STATUS_POS 4 #define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0 +#define RX_NO_DATA_CHAIN_A_POS 0 +#define RX_NO_DATA_CHAIN_A_MSK (0xff << RX_NO_DATA_CHAIN_A_POS) +#define RX_NO_DATA_CHAIN_B_POS 8 +#define RX_NO_DATA_CHAIN_B_MSK (0xff << RX_NO_DATA_CHAIN_B_POS) +#define RX_NO_DATA_CHANNEL_POS 16 +#define RX_NO_DATA_CHANNEL_MSK (0xff << RX_NO_DATA_CHANNEL_POS) + +#define RX_NO_DATA_INFO_TYPE_POS 0 +#define RX_NO_DATA_INFO_TYPE_MSK (0xff << RX_NO_DATA_INFO_TYPE_POS) +#define RX_NO_DATA_INFO_TYPE_NONE 0 +#define RX_NO_DATA_INFO_TYPE_RX_ERR 1 +#define RX_NO_DATA_INFO_TYPE_NDP 2 +#define RX_NO_DATA_INFO_TYPE_MU_UNMATCHED 3 +#define RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED 4 + +#define RX_NO_DATA_INFO_ERR_POS 8 +#define RX_NO_DATA_INFO_ERR_MSK (0xff << RX_NO_DATA_INFO_ERR_POS) +#define RX_NO_DATA_INFO_ERR_NONE 0 +#define RX_NO_DATA_INFO_ERR_BAD_PLCP 1 +#define RX_NO_DATA_INFO_ERR_UNSUPPORTED_RATE 2 +#define RX_NO_DATA_INFO_ERR_NO_DELIM 3 +#define RX_NO_DATA_INFO_ERR_BAD_MAC_HDR 4 + +#define RX_NO_DATA_FRAME_TIME_POS 0 +#define RX_NO_DATA_FRAME_TIME_MSK (0xfffff << RX_NO_DATA_FRAME_TIME_POS) + +#define RX_NO_DATA_RX_VEC0_HE_NSTS_MSK 0x03800000 +#define RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK 0x38000000 + +/** + * struct iwl_rx_no_data - RX no data descriptor + * @info: 7:0 frame type, 15:8 RX error type + * @rssi: 7:0 energy chain-A, + * 15:8 chain-B, measured at FINA time (FINA_ENERGY), 16:23 channel + * @on_air_rise_time: GP2 during on air rise + * @fr_time: frame time + * @rate: rate/mcs of frame + * @phy_info: &enum iwl_rx_phy_data0 and &enum iwl_rx_phy_info_type + * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type. + * for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT + * for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT + */ +struct iwl_rx_no_data { + __le32 info; + __le32 rssi; + __le32 on_air_rise_time; + __le32 fr_time; + __le32 rate; + __le32 phy_info[2]; + __le32 rx_vec[2]; +} __packed; /* RX_NO_DATA_NTFY_API_S_VER_1 */ + /** * enum iwl_completion_desc_transfer_status - transfer status (bits 1-3) * @IWL_CD_STTS_UNUSED: unused diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 18741889ec30..890a939c463d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -434,7 +434,7 @@ struct iwl_periodic_scan_complete { /* The maximum of either of these cannot exceed 8, because we use an * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h). */ -#define IWL_MVM_MAX_UMAC_SCANS 8 +#define IWL_MVM_MAX_UMAC_SCANS 4 #define IWL_MVM_MAX_LMAC_SCANS 1 enum scan_config_flags { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index 53cb622aa9ab..318843138490 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,6 +30,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -363,14 +365,7 @@ struct mvm_statistics_general_v8 { u8 reserved[4 - (NUM_MAC_INDEX % 4)]; } __packed; /* STATISTICS_GENERAL_API_S_VER_8 */ -struct mvm_statistics_general_cdb_v9 { - struct mvm_statistics_general_common_v19 common; - __le32 beacon_counter[NUM_MAC_INDEX_CDB]; - u8 beacon_average_energy[NUM_MAC_INDEX_CDB]; - u8 reserved[4 - (NUM_MAC_INDEX_CDB % 4)]; -} __packed; /* STATISTICS_GENERAL_API_S_VER_9 */ - -struct mvm_statistics_general_cdb { +struct mvm_statistics_general { struct mvm_statistics_general_common common; __le32 beacon_counter[MAC_INDEX_AUX]; u8 beacon_average_energy[MAC_INDEX_AUX]; @@ -435,11 +430,11 @@ struct iwl_notif_statistics_v11 { struct mvm_statistics_load_v1 load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_11 */ -struct iwl_notif_statistics_cdb { +struct iwl_notif_statistics { __le32 flag; struct mvm_statistics_rx rx; struct mvm_statistics_tx tx; - struct mvm_statistics_general_cdb general; + struct mvm_statistics_general general; struct mvm_statistics_load load_stats; } __packed; /* STATISTICS_NTFY_API_S_VER_13 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h index 7c6c2462d0e8..b089285ac466 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,6 +113,17 @@ struct iwl_tdls_channel_switch_frame { } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ /** + * struct iwl_tdls_channel_switch_cmd_tail - tail of iwl_tdls_channel_switch_cmd + * + * @timing: timing related data for command + * @frame: channel-switch request/response template, depending to switch_type + */ +struct iwl_tdls_channel_switch_cmd_tail { + struct iwl_tdls_channel_switch_timing timing; + struct iwl_tdls_channel_switch_frame frame; +} __packed; + +/** * struct iwl_tdls_channel_switch_cmd - TDLS channel switch command * * The command is sent to initiate a channel switch and also in response to @@ -119,15 +132,13 @@ struct iwl_tdls_channel_switch_frame { * @switch_type: see &enum iwl_tdls_channel_switch_type * @peer_sta_id: station id of TDLS peer * @ci: channel we switch to - * @timing: timing related data for command - * @frame: channel-switch request/response template, depending to switch_type + * @tail: command tail */ struct iwl_tdls_channel_switch_cmd { u8 switch_type; __le32 peer_sta_id; struct iwl_fw_channel_info ci; - struct iwl_tdls_channel_switch_timing timing; - struct iwl_tdls_channel_switch_frame frame; + struct iwl_tdls_channel_switch_cmd_tail tail; } __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index f824bebceb06..4621ef93a2cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -318,6 +320,25 @@ struct iwl_time_event_notif { } __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */ /* + * struct iwl_hs20_roc_req_tail - tail of iwl_hs20_roc_req + * + * @node_addr: Our MAC Address + * @reserved: reserved for alignment + * @apply_time: GP2 value to start (should always be the current GP2 value) + * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max + * time by which start of the event is allowed to be postponed. + * @duration: event duration in TU To calculate event duration: + * timeEventDuration = min(duration, remainingQuota) + */ +struct iwl_hs20_roc_req_tail { + u8 node_addr[ETH_ALEN]; + __le16 reserved; + __le32 apply_time; + __le32 apply_time_max_delay; + __le32 duration; +} __packed; + +/* * Aux ROC command * * Command requests the firmware to create a time event for a certain duration @@ -336,13 +357,6 @@ struct iwl_time_event_notif { * @sta_id_and_color: station id and color, resumed during "Remain On Channel" * activity. * @channel_info: channel info - * @node_addr: Our MAC Address - * @reserved: reserved for alignment - * @apply_time: GP2 value to start (should always be the current GP2 value) - * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max - * time by which start of the event is allowed to be postponed. - * @duration: event duration in TU To calculate event duration: - * timeEventDuration = min(duration, remainingQuota) */ struct iwl_hs20_roc_req { /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ @@ -351,11 +365,7 @@ struct iwl_hs20_roc_req { __le32 event_unique_id; __le32 sta_id_and_color; struct iwl_fw_channel_info channel_info; - u8 node_addr[ETH_ALEN]; - __le16 reserved; - __le32 apply_time; - __le32 apply_time_max_delay; - __le32 duration; + struct iwl_hs20_roc_req_tail tail; } __packed; /* HOT_SPOT_CMD_API_S_VER_1 */ /* diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tof.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tof.h deleted file mode 100644 index 7328a1606146..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tof.h +++ /dev/null @@ -1,393 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#ifndef __iwl_fw_api_tof_h__ -#define __iwl_fw_api_tof_h__ - -/* ToF sub-group command IDs */ -enum iwl_mvm_tof_sub_grp_ids { - TOF_RANGE_REQ_CMD = 0x1, - TOF_CONFIG_CMD = 0x2, - TOF_RANGE_ABORT_CMD = 0x3, - TOF_RANGE_REQ_EXT_CMD = 0x4, - TOF_RESPONDER_CONFIG_CMD = 0x5, - TOF_NW_INITIATED_RES_SEND_CMD = 0x6, - TOF_NEIGHBOR_REPORT_REQ_CMD = 0x7, - TOF_NEIGHBOR_REPORT_RSP_NOTIF = 0xFC, - TOF_NW_INITIATED_REQ_RCVD_NOTIF = 0xFD, - TOF_RANGE_RESPONSE_NOTIF = 0xFE, - TOF_MCSI_DEBUG_NOTIF = 0xFB, -}; - -/** - * struct iwl_tof_config_cmd - ToF configuration - * @tof_disabled: 0 enabled, 1 - disabled - * @one_sided_disabled: 0 enabled, 1 - disabled - * @is_debug_mode: 1 debug mode, 0 - otherwise - * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise - */ -struct iwl_tof_config_cmd { - __le32 sub_grp_cmd_id; - u8 tof_disabled; - u8 one_sided_disabled; - u8 is_debug_mode; - u8 is_buf_required; -} __packed; - -/** - * struct iwl_tof_responder_config_cmd - ToF AP mode (for debug) - * @burst_period: future use: (currently hard coded in the LMAC) - * The interval between two sequential bursts. - * @min_delta_ftm: future use: (currently hard coded in the LMAC) - * The minimum delay between two sequential FTM Responses - * in the same burst. - * @burst_duration: future use: (currently hard coded in the LMAC) - * The total time for all FTMs handshake in the same burst. - * Affect the time events duration in the LMAC. - * @num_of_burst_exp: future use: (currently hard coded in the LMAC) - * The number of bursts for the current ToF request. Affect - * the number of events allocations in the current iteration. - * @get_ch_est: for xVT only, NA for driver - * @abort_responder: when set to '1' - Responder will terminate its activity - * (all other fields in the command are ignored) - * @recv_sta_req_params: 1 - Responder will ignore the other Responder's - * params and use the recomended Initiator params. - * 0 - otherwise - * @channel_num: current AP Channel - * @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz - * @rate: current AP rate - * @ctrl_ch_position: coding of the control channel position relative to - * the center frequency: - * - * 40 MHz - * 0 below center, 1 above center - * - * 80 MHz - * bits [0..1] - * * 0 the near 20MHz to the center, - * * 1 the far 20MHz to the center - * bit[2] - * as above 40MHz - * @ftm_per_burst: FTMs per Burst - * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, - * '1' - we measure over the Initial FTM Response - * @asap_mode: ASAP / Non ASAP mode for the current WLS station - * @sta_id: index of the AP STA when in AP mode - * @tsf_timer_offset_msecs: The dictated time offset (mSec) from the AP's TSF - * @toa_offset: Artificial addition [0.1nsec] for the ToA - to be used for debug - * purposes, simulating station movement by adding various values - * to this field - * @bssid: Current AP BSSID - */ -struct iwl_tof_responder_config_cmd { - __le32 sub_grp_cmd_id; - __le16 burst_period; - u8 min_delta_ftm; - u8 burst_duration; - u8 num_of_burst_exp; - u8 get_ch_est; - u8 abort_responder; - u8 recv_sta_req_params; - u8 channel_num; - u8 bandwidth; - u8 rate; - u8 ctrl_ch_position; - u8 ftm_per_burst; - u8 ftm_resp_ts_avail; - u8 asap_mode; - u8 sta_id; - __le16 tsf_timer_offset_msecs; - __le16 toa_offset; - u8 bssid[ETH_ALEN]; -} __packed; - -/** - * struct iwl_tof_range_request_ext_cmd - extended range req for WLS - * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF - * @reserved: reserved - * @min_delta_ftm: Minimal time between two consecutive measurements, - * in units of 100us. 0 means no preference by station - * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended - * value be sent to the AP - * @ftm_format_and_bw40M: FTM Channel Spacing/Format for 40MHz: recommended - * value to be sent to the AP - * @ftm_format_and_bw80M: FTM Channel Spacing/Format for 80MHz: recommended - * value to be sent to the AP - */ -struct iwl_tof_range_req_ext_cmd { - __le32 sub_grp_cmd_id; - __le16 tsf_timer_offset_msec; - __le16 reserved; - u8 min_delta_ftm; - u8 ftm_format_and_bw20M; - u8 ftm_format_and_bw40M; - u8 ftm_format_and_bw80M; -} __packed; - -#define IWL_MVM_TOF_MAX_APS 21 - -/** - * struct iwl_tof_range_req_ap_entry - AP configuration parameters - * @channel_num: Current AP Channel - * @bandwidth: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz - * @tsf_delta_direction: TSF relatively to the subject AP - * @ctrl_ch_position: Coding of the control channel position relative to the - * center frequency. - * 40MHz 0 below center, 1 above center - * 80MHz bits [0..1]: 0 the near 20MHz to the center, - * 1 the far 20MHz to the center - * bit[2] as above 40MHz - * @bssid: AP's bss id - * @measure_type: Measurement type: 0 - two sided, 1 - One sided - * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of the - * number of measurement iterations (min 2^0 = 1, max 2^14) - * @burst_period: Recommended value to be sent to the AP. Measurement - * periodicity In units of 100ms. ignored if num_of_bursts = 0 - * @samples_per_burst: 2-sided: the number of FTMs pairs in single Burst (1-31) - * 1-sided: how many rts/cts pairs should be used per burst. - * @retries_per_sample: Max number of retries that the LMAC should send - * in case of no replies by the AP. - * @tsf_delta: TSF Delta in units of microseconds. - * The difference between the AP TSF and the device local clock. - * @location_req: Location Request Bit[0] LCI should be sent in the FTMR - * Bit[1] Civic should be sent in the FTMR - * @asap_mode: 0 - non asap mode, 1 - asap mode (not relevant for one sided) - * @enable_dyn_ack: Enable Dynamic ACK BW. - * 0 Initiator interact with regular AP - * 1 Initiator interact with Responder machine: need to send the - * Initiator Acks with HT 40MHz / 80MHz, since the Responder should - * use it for its ch est measurement (this flag will be set when we - * configure the opposite machine to be Responder). - * @rssi: Last received value - * leagal values: -128-0 (0x7f). above 0x0 indicating an invalid value. - */ -struct iwl_tof_range_req_ap_entry { - u8 channel_num; - u8 bandwidth; - u8 tsf_delta_direction; - u8 ctrl_ch_position; - u8 bssid[ETH_ALEN]; - u8 measure_type; - u8 num_of_bursts; - __le16 burst_period; - u8 samples_per_burst; - u8 retries_per_sample; - __le32 tsf_delta; - u8 location_req; - u8 asap_mode; - u8 enable_dyn_ack; - s8 rssi; -} __packed; - -/** - * enum iwl_tof_response_mode - * @IWL_MVM_TOF_RESPOSE_ASAP: report each AP measurement separately as soon as - * possible (not supported for this release) - * @IWL_MVM_TOF_RESPOSE_TIMEOUT: report all AP measurements as a batch upon - * timeout expiration - * @IWL_MVM_TOF_RESPOSE_COMPLETE: report all AP measurements as a batch at the - * earlier of: measurements completion / timeout - * expiration. - */ -enum iwl_tof_response_mode { - IWL_MVM_TOF_RESPOSE_ASAP = 1, - IWL_MVM_TOF_RESPOSE_TIMEOUT, - IWL_MVM_TOF_RESPOSE_COMPLETE, -}; - -/** - * struct iwl_tof_range_req_cmd - start measurement cmd - * @request_id: A Token incremented per request. The same Token will be - * sent back in the range response - * @initiator: 0- NW initiated, 1 - Client Initiated - * @one_sided_los_disable: '0'- run ML-Algo for both ToF/OneSided, - * '1' - run ML-Algo for ToF only - * @req_timeout: Requested timeout of the response in units of 100ms. - * This is equivalent to the session time configured to the - * LMAC in Initiator Request - * @report_policy: Supported partially for this release: For current release - - * the range report will be uploaded as a batch when ready or - * when the session is done (successfully / partially). - * one of iwl_tof_response_mode. - * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) - * @macaddr_random: '0' Use default source MAC address (i.e. p2_p), - * '1' Use MAC Address randomization according to the below - * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. - * Bits set to 1 shall be randomized by the UMAC - * @ap: per-AP request data - */ -struct iwl_tof_range_req_cmd { - __le32 sub_grp_cmd_id; - u8 request_id; - u8 initiator; - u8 one_sided_los_disable; - u8 req_timeout; - u8 report_policy; - u8 los_det_disable; - u8 num_of_ap; - u8 macaddr_random; - u8 macaddr_template[ETH_ALEN]; - u8 macaddr_mask[ETH_ALEN]; - struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; -} __packed; - -/** - * struct iwl_tof_gen_resp_cmd - generic ToF response - */ -struct iwl_tof_gen_resp_cmd { - __le32 sub_grp_cmd_id; - u8 data[]; -} __packed; - -/** - * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) - * @bssid: BSSID of the AP - * @measure_status: current APs measurement status, one of - * &enum iwl_tof_entry_status. - * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz - * @rtt: The Round Trip Time that took for the last measurement for - * current AP [nSec] - * @rtt_variance: The Variance of the RTT values measured for current AP - * @rtt_spread: The Difference between the maximum and the minimum RTT - * values measured for current AP in the current session [nsec] - * @rssi: RSSI as uploaded in the Channel Estimation notification - * @rssi_spread: The Difference between the maximum and the minimum RSSI values - * measured for current AP in the current session - * @reserved: reserved - * @range: Measured range [cm] - * @range_variance: Measured range variance [cm] - * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was - * uploaded by the LMAC - */ -struct iwl_tof_range_rsp_ap_entry_ntfy { - u8 bssid[ETH_ALEN]; - u8 measure_status; - u8 measure_bw; - __le32 rtt; - __le32 rtt_variance; - __le32 rtt_spread; - s8 rssi; - u8 rssi_spread; - __le16 reserved; - __le32 range; - __le32 range_variance; - __le32 timestamp; -} __packed; - -/** - * struct iwl_tof_range_rsp_ntfy - - * @request_id: A Token ID of the corresponding Range request - * @request_status: status of current measurement session - * @last_in_batch: reprot policy (when not all responses are uploaded at once) - * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) - * @ap: per-AP data - */ -struct iwl_tof_range_rsp_ntfy { - u8 request_id; - u8 request_status; - u8 last_in_batch; - u8 num_of_aps; - struct iwl_tof_range_rsp_ap_entry_ntfy ap[IWL_MVM_TOF_MAX_APS]; -} __packed; - -#define IWL_MVM_TOF_MCSI_BUF_SIZE (245) -/** - * struct iwl_tof_mcsi_notif - used for debug - * @token: token ID for the current session - * @role: '0' - initiator, '1' - responder - * @reserved: reserved - * @initiator_bssid: initiator machine - * @responder_bssid: responder machine - * @mcsi_buffer: debug data - */ -struct iwl_tof_mcsi_notif { - u8 token; - u8 role; - __le16 reserved; - u8 initiator_bssid[ETH_ALEN]; - u8 responder_bssid[ETH_ALEN]; - u8 mcsi_buffer[IWL_MVM_TOF_MCSI_BUF_SIZE * 4]; -} __packed; - -/** - * struct iwl_tof_neighbor_report_notif - * @bssid: BSSID of the AP which sent the report - * @request_token: same token as the corresponding request - * @status: - * @report_ie_len: the length of the response frame starting from the Element ID - * @data: the IEs - */ -struct iwl_tof_neighbor_report { - u8 bssid[ETH_ALEN]; - u8 request_token; - u8 status; - __le16 report_ie_len; - u8 data[]; -} __packed; - -/** - * struct iwl_tof_range_abort_cmd - * @request_id: corresponds to a range request - * @reserved: reserved - */ -struct iwl_tof_range_abort_cmd { - __le32 sub_grp_cmd_id; - u8 request_id; - u8 reserved[3]; -} __packed; - -#endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 358bdf051e83..8511e735c374 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -847,13 +847,13 @@ struct iwl_beacon_notif { } __packed; /** - * struct iwl_extended_beacon_notif - notifies about beacon transmission + * struct iwl_extended_beacon_notif_v5 - notifies about beacon transmission * @beacon_notify_hdr: tx response command associated with the beacon * @tsf: last beacon tsf * @ibss_mgr_status: whether IBSS is manager * @gp2: last beacon time in gp2 */ -struct iwl_extended_beacon_notif { +struct iwl_extended_beacon_notif_v5 { struct iwl_mvm_tx_resp beacon_notify_hdr; __le64 tsf; __le32 ibss_mgr_status; @@ -861,6 +861,20 @@ struct iwl_extended_beacon_notif { } __packed; /* BEACON_NTFY_API_S_VER_5 */ /** + * struct iwl_extended_beacon_notif - notifies about beacon transmission + * @status: the status of the Tx response of the beacon + * @tsf: last beacon tsf + * @ibss_mgr_status: whether IBSS is manager + * @gp2: last beacon time in gp2 + */ +struct iwl_extended_beacon_notif { + __le32 status; + __le64 tsf; + __le32 ibss_mgr_status; + __le32 gp2; +} __packed; /* BEACON_NTFY_API_S_VER_6_ */ + +/** * enum iwl_dump_control - dump (flush) control flags * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty * and the TFD queues are empty. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index c16757051f16..d7380016f1c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -8,7 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -225,28 +225,25 @@ static void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt, *dump_data = iwl_fw_error_next_data(*dump_data); } -static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, - struct iwl_fw_error_dump_data **dump_data) +static void iwl_fw_dump_rxf(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data) { - struct iwl_fw_error_dump_fifo *fifo_hdr; struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; - u32 *fifo_data; - u32 fifo_len; unsigned long flags; - int i, j; - IWL_DEBUG_INFO(fwrt, "WRT FIFO dump\n"); + IWL_DEBUG_INFO(fwrt, "WRT RX FIFO dump\n"); if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) { + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF)) { /* Pull RXF1 */ iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); /* Pull RXF2 */ iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->rxfifo2_size, - RXF_DIFF_FROM_PREV, 1); + RXF_DIFF_FROM_PREV + + fwrt->trans->cfg->umac_prph_offset, 1); /* Pull LMAC2 RXF1 */ if (fwrt->smem_cfg.num_lmacs > 1) iwl_fwrt_dump_rxf(fwrt, dump_data, @@ -254,7 +251,25 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, LMAC2_PRPH_OFFSET, 2); } - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) { + iwl_trans_release_nic_access(fwrt->trans, &flags); +} + +static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data) +{ + struct iwl_fw_error_dump_fifo *fifo_hdr; + struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; + u32 *fifo_data; + u32 fifo_len; + unsigned long flags; + int i, j; + + IWL_DEBUG_INFO(fwrt, "WRT TX FIFO dump\n"); + + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) + return; + + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF)) { /* Pull TXF data from LMAC1 */ for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ @@ -279,7 +294,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, } } - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) && + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) && fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ @@ -455,6 +470,93 @@ static const struct iwl_prph_range iwl_prph_dump_addr_9000[] = { { .start = 0x00a02400, .end = 0x00a02758 }, }; +static const struct iwl_prph_range iwl_prph_dump_addr_22000[] = { + { .start = 0x00a00000, .end = 0x00a00000 }, + { .start = 0x00a0000c, .end = 0x00a00024 }, + { .start = 0x00a0002c, .end = 0x00a00034 }, + { .start = 0x00a0003c, .end = 0x00a0003c }, + { .start = 0x00a00410, .end = 0x00a00418 }, + { .start = 0x00a00420, .end = 0x00a00420 }, + { .start = 0x00a00428, .end = 0x00a00428 }, + { .start = 0x00a00430, .end = 0x00a0043c }, + { .start = 0x00a00444, .end = 0x00a00444 }, + { .start = 0x00a00840, .end = 0x00a00840 }, + { .start = 0x00a00850, .end = 0x00a00858 }, + { .start = 0x00a01004, .end = 0x00a01008 }, + { .start = 0x00a01010, .end = 0x00a01010 }, + { .start = 0x00a01018, .end = 0x00a01018 }, + { .start = 0x00a01024, .end = 0x00a01024 }, + { .start = 0x00a0102c, .end = 0x00a01034 }, + { .start = 0x00a0103c, .end = 0x00a01040 }, + { .start = 0x00a01048, .end = 0x00a01050 }, + { .start = 0x00a01058, .end = 0x00a01058 }, + { .start = 0x00a01060, .end = 0x00a01070 }, + { .start = 0x00a0108c, .end = 0x00a0108c }, + { .start = 0x00a01c20, .end = 0x00a01c28 }, + { .start = 0x00a01d10, .end = 0x00a01d10 }, + { .start = 0x00a01e28, .end = 0x00a01e2c }, + { .start = 0x00a01e60, .end = 0x00a01e60 }, + { .start = 0x00a01e80, .end = 0x00a01e80 }, + { .start = 0x00a01ea0, .end = 0x00a01ea0 }, + { .start = 0x00a02000, .end = 0x00a0201c }, + { .start = 0x00a02024, .end = 0x00a02024 }, + { .start = 0x00a02040, .end = 0x00a02048 }, + { .start = 0x00a020c0, .end = 0x00a020e0 }, + { .start = 0x00a02400, .end = 0x00a02404 }, + { .start = 0x00a0240c, .end = 0x00a02414 }, + { .start = 0x00a0241c, .end = 0x00a0243c }, + { .start = 0x00a02448, .end = 0x00a024bc }, + { .start = 0x00a024c4, .end = 0x00a024cc }, + { .start = 0x00a02508, .end = 0x00a02508 }, + { .start = 0x00a02510, .end = 0x00a02514 }, + { .start = 0x00a0251c, .end = 0x00a0251c }, + { .start = 0x00a0252c, .end = 0x00a0255c }, + { .start = 0x00a02564, .end = 0x00a025a0 }, + { .start = 0x00a025a8, .end = 0x00a025b4 }, + { .start = 0x00a025c0, .end = 0x00a025c0 }, + { .start = 0x00a025e8, .end = 0x00a025f4 }, + { .start = 0x00a02c08, .end = 0x00a02c18 }, + { .start = 0x00a02c2c, .end = 0x00a02c38 }, + { .start = 0x00a02c68, .end = 0x00a02c78 }, + { .start = 0x00a03000, .end = 0x00a03000 }, + { .start = 0x00a03010, .end = 0x00a03014 }, + { .start = 0x00a0301c, .end = 0x00a0302c }, + { .start = 0x00a03034, .end = 0x00a03038 }, + { .start = 0x00a03040, .end = 0x00a03044 }, + { .start = 0x00a03060, .end = 0x00a03068 }, + { .start = 0x00a03070, .end = 0x00a03070 }, + { .start = 0x00a0307c, .end = 0x00a03084 }, + { .start = 0x00a0308c, .end = 0x00a03090 }, + { .start = 0x00a03098, .end = 0x00a03098 }, + { .start = 0x00a030a0, .end = 0x00a030a0 }, + { .start = 0x00a030a8, .end = 0x00a030b4 }, + { .start = 0x00a030bc, .end = 0x00a030c0 }, + { .start = 0x00a030c8, .end = 0x00a030f4 }, + { .start = 0x00a03100, .end = 0x00a0312c }, + { .start = 0x00a03c00, .end = 0x00a03c5c }, + { .start = 0x00a04400, .end = 0x00a04454 }, + { .start = 0x00a04460, .end = 0x00a04474 }, + { .start = 0x00a044c0, .end = 0x00a044ec }, + { .start = 0x00a04500, .end = 0x00a04504 }, + { .start = 0x00a04510, .end = 0x00a04538 }, + { .start = 0x00a04540, .end = 0x00a04548 }, + { .start = 0x00a04560, .end = 0x00a04560 }, + { .start = 0x00a04570, .end = 0x00a0457c }, + { .start = 0x00a04590, .end = 0x00a04590 }, + { .start = 0x00a04598, .end = 0x00a04598 }, + { .start = 0x00a045c0, .end = 0x00a045f4 }, + { .start = 0x00a0c000, .end = 0x00a0c018 }, + { .start = 0x00a0c020, .end = 0x00a0c028 }, + { .start = 0x00a0c038, .end = 0x00a0c094 }, + { .start = 0x00a0c0c0, .end = 0x00a0c104 }, + { .start = 0x00a0c10c, .end = 0x00a0c118 }, + { .start = 0x00a0c150, .end = 0x00a0c174 }, + { .start = 0x00a0c17c, .end = 0x00a0c188 }, + { .start = 0x00a0c190, .end = 0x00a0c198 }, + { .start = 0x00a0c1a0, .end = 0x00a0c1a8 }, + { .start = 0x00a0c1b0, .end = 0x00a0c1b8 }, +}; + static void iwl_read_prph_block(struct iwl_trans *trans, u32 start, u32 len_bytes, __le32 *data) { @@ -464,15 +566,20 @@ static void iwl_read_prph_block(struct iwl_trans *trans, u32 start, *data++ = cpu_to_le32(iwl_read_prph_no_grab(trans, start + i)); } -static void iwl_dump_prph(struct iwl_trans *trans, - struct iwl_fw_error_dump_data **data, +static void iwl_dump_prph(struct iwl_fw_runtime *fwrt, const struct iwl_prph_range *iwl_prph_dump_addr, - u32 range_len) + u32 range_len, void *ptr) { struct iwl_fw_error_dump_prph *prph; + struct iwl_trans *trans = fwrt->trans; + struct iwl_fw_error_dump_data **data = + (struct iwl_fw_error_dump_data **)ptr; unsigned long flags; u32 i; + if (!data) + return; + IWL_DEBUG_INFO(trans, "WRT PRPH dump\n"); if (!iwl_trans_grab_nic_access(trans, &flags)) @@ -538,37 +645,49 @@ static struct scatterlist *alloc_sgtable(int size) return table; } -static int iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt) +static void iwl_fw_get_prph_len(struct iwl_fw_runtime *fwrt, + const struct iwl_prph_range *iwl_prph_dump_addr, + u32 range_len, void *ptr) { - u32 prph_len = 0; - int i; + u32 *prph_len = (u32 *)ptr; + int i, num_bytes_in_chunk; - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); - i++) { + if (!prph_len) + return; + + for (i = 0; i < range_len; i++) { /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_comm[i].end - - iwl_prph_dump_addr_comm[i].start + 4; + num_bytes_in_chunk = + iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4; - prph_len += sizeof(struct iwl_fw_error_dump_data) + + *prph_len += sizeof(struct iwl_fw_error_dump_data) + sizeof(struct iwl_fw_error_dump_prph) + num_bytes_in_chunk; } +} + +static void iwl_fw_prph_handler(struct iwl_fw_runtime *fwrt, void *ptr, + void (*handler)(struct iwl_fw_runtime *, + const struct iwl_prph_range *, + u32, void *)) +{ + u32 range_len; + + if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + /* TODO */ + } else if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000) { + range_len = ARRAY_SIZE(iwl_prph_dump_addr_22000); + handler(fwrt, iwl_prph_dump_addr_22000, range_len, ptr); + } else { + range_len = ARRAY_SIZE(iwl_prph_dump_addr_comm); + handler(fwrt, iwl_prph_dump_addr_comm, range_len, ptr); - if (fwrt->trans->cfg->mq_rx_supported) { - for (i = 0; i < - ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = - iwl_prph_dump_addr_9000[i].end - - iwl_prph_dump_addr_9000[i].start + 4; - - prph_len += sizeof(struct iwl_fw_error_dump_data) + - sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; + if (fwrt->trans->cfg->mq_rx_supported) { + range_len = ARRAY_SIZE(iwl_prph_dump_addr_9000); + handler(fwrt, iwl_prph_dump_addr_9000, range_len, ptr); } } - return prph_len; } static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, @@ -595,29 +714,45 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt, do {size_t item = item_len; len += (!!item) * const_len + item; } \ while (0) -static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt, - struct iwl_fwrt_shared_mem_cfg *mem_cfg) +static int iwl_fw_rxf_len(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_shared_mem_cfg *mem_cfg) { size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) + sizeof(struct iwl_fw_error_dump_fifo); u32 fifo_len = 0; int i; - if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF))) - goto dump_txf; + if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF)) + return 0; /* Count RXF2 size */ ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len); /* Count RXF1 sizes */ + if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC)) + mem_cfg->num_lmacs = MAX_NUM_LMAC; + for (i = 0; i < mem_cfg->num_lmacs; i++) ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len); -dump_txf: - if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF))) + return fifo_len; +} + +static int iwl_fw_txf_len(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_shared_mem_cfg *mem_cfg) +{ + size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) + + sizeof(struct iwl_fw_error_dump_fifo); + u32 fifo_len = 0; + int i; + + if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF)) goto dump_internal_txf; /* Count TXF sizes */ + if (WARN_ON(mem_cfg->num_lmacs > MAX_NUM_LMAC)) + mem_cfg->num_lmacs = MAX_NUM_LMAC; + for (i = 0; i < mem_cfg->num_lmacs; i++) { int j; @@ -627,7 +762,7 @@ dump_txf: } dump_internal_txf: - if (!((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) && + if (!(iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) && fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))) goto out; @@ -639,6 +774,35 @@ out: return fifo_len; } +static void iwl_dump_paging(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **data) +{ + int i; + + IWL_DEBUG_INFO(fwrt, "WRT paging dump\n"); + for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) { + struct iwl_fw_error_dump_paging *paging; + struct page *pages = + fwrt->fw_paging_db[i].fw_paging_block; + dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys; + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); + (*data)->len = cpu_to_le32(sizeof(*paging) + + PAGING_BLOCK_SIZE); + paging = (void *)(*data)->data; + paging->index = cpu_to_le32(i); + dma_sync_single_for_cpu(fwrt->trans->dev, addr, + PAGING_BLOCK_SIZE, + DMA_BIDIRECTIONAL); + memcpy(paging->data, page_address(pages), + PAGING_BLOCK_SIZE); + dma_sync_single_for_device(fwrt->trans->dev, addr, + PAGING_BLOCK_SIZE, + DMA_BIDIRECTIONAL); + (*data) = iwl_fw_error_next_data(*data); + } +} + static struct iwl_fw_error_dump_file * _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, struct iwl_fw_dump_ptrs *fw_error_dump) @@ -655,17 +819,14 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len; u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->dccm2_len; - bool monitor_dump_only = false; int i; - if (fwrt->dump.trig && - fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) - monitor_dump_only = true; - /* SRAM - include stack CCM if driver knows the values for it */ if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) { const struct fw_img *img; + if (fwrt->cur_fw_img >= IWL_UCODE_TYPE_MAX) + return NULL; img = &fwrt->fw->img[fwrt->cur_fw_img]; sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -676,26 +837,27 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, /* reading RXF/TXF sizes */ if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { - fifo_len = iwl_fw_fifo_len(fwrt, mem_cfg); + fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg); + fifo_len += iwl_fw_txf_len(fwrt, mem_cfg); /* Make room for PRPH registers */ - if (!fwrt->trans->cfg->gen2 && - fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH)) - prph_len += iwl_fw_get_prph_len(fwrt); + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PRPH)) + iwl_fw_prph_handler(fwrt, &prph_len, + iwl_fw_get_prph_len); if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 && - fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG)) + iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RADIO_REG)) radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ; } file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO)) file_len += sizeof(*dump_data) + sizeof(*dump_info); - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG)) file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg); - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) { size_t hdr_len = sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_mem); @@ -712,10 +874,7 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, } /* Make room for fw's virtual image pages, if it exists */ - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && - !fwrt->trans->cfg->gen2 && - fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && - fwrt->fw_paging_db[0].fw_paging_block) + if (iwl_fw_dbg_is_paging_enabled(fwrt)) file_len += fwrt->num_of_paging_blk * (sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_paging) + @@ -727,12 +886,12 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, } /* If we only want a monitor dump, reset the file length */ - if (monitor_dump_only) { + if (fwrt->dump.monitor_only) { file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 + sizeof(*dump_info) + sizeof(*dump_smem_cfg); } - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) && fwrt->dump.desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + fwrt->dump.desc->len; @@ -746,7 +905,7 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_data = (void *)dump_file->data; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) { + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO)) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_info)); dump_info = (void *)dump_data->data; @@ -763,11 +922,18 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, sizeof(dump_info->dev_human_readable) - 1); strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name, sizeof(dump_info->bus_human_readable) - 1); + dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs; + dump_info->lmac_err_id[0] = + cpu_to_le32(fwrt->dump.lmac_err_id[0]); + if (fwrt->smem_cfg.num_lmacs > 1) + dump_info->lmac_err_id[1] = + cpu_to_le32(fwrt->dump.lmac_err_id[1]); + dump_info->umac_err_id = cpu_to_le32(fwrt->dump.umac_err_id); dump_data = iwl_fw_error_next_data(dump_data); } - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) { + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG)) { /* Dump shared memory configuration */ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG); dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg)); @@ -799,12 +965,13 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, /* We only dump the FIFOs if the FW is in error state */ if (fifo_len) { - iwl_fw_dump_fifos(fwrt, &dump_data); + iwl_fw_dump_rxf(fwrt, &dump_data); + iwl_fw_dump_txf(fwrt, &dump_data); if (radio_len) iwl_read_radio_regs(fwrt, &dump_data); } - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) && + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) && fwrt->dump.desc) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_trig) + @@ -817,10 +984,10 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, } /* In case we only want monitor dump, skip to dump trasport data */ - if (monitor_dump_only) + if (fwrt->dump.monitor_only) goto out; - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) { + if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) { const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg.mem_tlv; @@ -865,44 +1032,801 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, } /* Dump fw's virtual image */ - if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) && - !fwrt->trans->cfg->gen2 && - fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && - fwrt->fw_paging_db[0].fw_paging_block) { - IWL_DEBUG_INFO(fwrt, "WRT paging dump\n"); - for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) { - struct iwl_fw_error_dump_paging *paging; - struct page *pages = - fwrt->fw_paging_db[i].fw_paging_block; - dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys; - - dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); - dump_data->len = cpu_to_le32(sizeof(*paging) + - PAGING_BLOCK_SIZE); - paging = (void *)dump_data->data; - paging->index = cpu_to_le32(i); - dma_sync_single_for_cpu(fwrt->trans->dev, addr, - PAGING_BLOCK_SIZE, - DMA_BIDIRECTIONAL); - memcpy(paging->data, page_address(pages), - PAGING_BLOCK_SIZE); - dump_data = iwl_fw_error_next_data(dump_data); + if (iwl_fw_dbg_is_paging_enabled(fwrt)) + iwl_dump_paging(fwrt, &dump_data); + + if (prph_len) + iwl_fw_prph_handler(fwrt, &dump_data, iwl_dump_prph); + +out: + dump_file->file_len = cpu_to_le32(file_len); + return dump_file; +} + +static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + __le32 *val = range->data; + u32 addr, prph_val, offset = le32_to_cpu(reg->offset); + int i; + + range->start_addr = reg->start_addr[idx]; + range->range_data_size = reg->internal.range_data_size; + for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) { + addr = le32_to_cpu(range->start_addr) + i; + prph_val = iwl_read_prph(fwrt->trans, addr + offset); + if (prph_val == 0x5a5a5a5a) + return -EBUSY; + *val++ = cpu_to_le32(prph_val); + } + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + __le32 *val = range->data; + u32 addr, offset = le32_to_cpu(reg->offset); + int i; + + range->start_addr = reg->start_addr[idx]; + range->range_data_size = reg->internal.range_data_size; + for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) { + addr = le32_to_cpu(range->start_addr) + i; + *val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, + addr + offset)); + } + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 addr = le32_to_cpu(range->start_addr); + u32 offset = le32_to_cpu(reg->offset); + + range->start_addr = reg->start_addr[idx]; + range->range_data_size = reg->internal.range_data_size; + iwl_trans_read_mem_bytes(fwrt->trans, addr + offset, range->data, + le32_to_cpu(reg->internal.range_data_size)); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int +iwl_dump_ini_paging_gen2_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 page_size = fwrt->trans->init_dram.paging[idx].size; + + range->start_addr = cpu_to_le32(idx); + range->range_data_size = cpu_to_le32(page_size); + memcpy(range->data, fwrt->trans->init_dram.paging[idx].block, + page_size); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + /* increase idx by 1 since the pages are from 1 to + * fwrt->num_of_paging_blk + 1 + */ + struct page *page = fwrt->fw_paging_db[++idx].fw_paging_block; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + dma_addr_t addr = fwrt->fw_paging_db[idx].fw_paging_phys; + u32 page_size = fwrt->fw_paging_db[idx].fw_paging_size; + + range->start_addr = cpu_to_le32(idx); + range->range_data_size = cpu_to_le32(page_size); + dma_sync_single_for_cpu(fwrt->trans->dev, addr, page_size, + DMA_BIDIRECTIONAL); + memcpy(range->data, page_address(page), page_size); + dma_sync_single_for_device(fwrt->trans->dev, addr, page_size, + DMA_BIDIRECTIONAL); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int +iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, void *range_ptr, + int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 start_addr = iwl_read_umac_prph(fwrt->trans, + MON_BUFF_BASE_ADDR_VER2); + + if (start_addr == 0x5a5a5a5a) + return -EBUSY; + + range->start_addr = cpu_to_le32(start_addr); + range->range_data_size = cpu_to_le32(fwrt->trans->fw_mon[idx].size); + + memcpy(range->data, fwrt->trans->fw_mon[idx].block, + fwrt->trans->fw_mon[idx].size); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +struct iwl_ini_txf_iter_data { + int fifo; + int lmac; + u32 fifo_size; + bool internal_txf; + bool init; +}; + +static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + struct iwl_ini_txf_iter_data *iter = fwrt->dump.fifo_iter; + struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; + int txf_num = cfg->num_txfifo_entries; + int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size); + u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid1); + + if (!iter) + return false; + + if (iter->init) { + if (le32_to_cpu(reg->offset) && + WARN_ONCE(cfg->num_lmacs == 1, + "Invalid lmac offset: 0x%x\n", + le32_to_cpu(reg->offset))) + return false; + + iter->init = false; + iter->internal_txf = false; + iter->fifo_size = 0; + iter->fifo = -1; + if (le32_to_cpu(reg->offset)) + iter->lmac = 1; + else + iter->lmac = 0; + } + + if (!iter->internal_txf) + for (iter->fifo++; iter->fifo < txf_num; iter->fifo++) { + iter->fifo_size = + cfg->lmac[iter->lmac].txfifo_size[iter->fifo]; + if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo))) + return true; } + + iter->internal_txf = true; + + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) + return false; + + for (iter->fifo++; iter->fifo < int_txf_num + txf_num; iter->fifo++) { + iter->fifo_size = + cfg->internal_txfifo_size[iter->fifo - txf_num]; + if (iter->fifo_size && (lmac_bitmap & BIT(iter->fifo))) + return true; } - if (prph_len) { - iwl_dump_prph(fwrt->trans, &dump_data, - iwl_prph_dump_addr_comm, - ARRAY_SIZE(iwl_prph_dump_addr_comm)); + return false; +} - if (fwrt->trans->cfg->mq_rx_supported) - iwl_dump_prph(fwrt->trans, &dump_data, - iwl_prph_dump_addr_9000, - ARRAY_SIZE(iwl_prph_dump_addr_9000)); +static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr; + struct iwl_ini_txf_iter_data *iter; + u32 offs = le32_to_cpu(reg->offset), addr; + u32 registers_size = + le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32); + __le32 *val = range->data; + unsigned long flags; + int i; + + if (!iwl_ini_txf_iter(fwrt, reg)) + return -EIO; + + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) + return -EBUSY; + + iter = fwrt->dump.fifo_iter; + + range->fifo_num = cpu_to_le32(iter->fifo); + range->num_of_registers = reg->fifos.num_of_registers; + range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size); + + iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo); + + /* read txf registers */ + for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { + addr = le32_to_cpu(reg->start_addr[i]) + offs; + + *val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr)); } + if (reg->fifos.header_only) { + range->range_data_size = cpu_to_le32(registers_size); + goto out; + } + + /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ + iwl_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offs, + TXF_WR_PTR + offs); + + /* Dummy-read to advance the read pointer to the head */ + iwl_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offs); + + /* Read FIFO */ + addr = TXF_READ_MODIFY_DATA + offs; + for (i = 0; i < iter->fifo_size; i += sizeof(__le32)) + *val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr)); + out: - dump_file->file_len = cpu_to_le32(file_len); + iwl_trans_release_nic_access(fwrt->trans, &flags); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +struct iwl_ini_rxf_data { + u32 fifo_num; + u32 size; + u32 offset; +}; + +static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + struct iwl_ini_rxf_data *data) +{ + u32 fid1 = le32_to_cpu(reg->fifos.fid1); + u32 fid2 = le32_to_cpu(reg->fifos.fid2); + u32 fifo_idx; + + if (!data) + return; + + memset(data, 0, sizeof(*data)); + + if (WARN_ON_ONCE((fid1 && fid2) || (!fid1 && !fid2))) + return; + + fifo_idx = ffs(fid1) - 1; + if (fid1 && !WARN_ON_ONCE((~BIT(fifo_idx) & fid1) || + fifo_idx >= MAX_NUM_LMAC)) { + data->size = fwrt->smem_cfg.lmac[fifo_idx].rxfifo1_size; + data->fifo_num = fifo_idx; + return; + } + + fifo_idx = ffs(fid2) - 1; + if (fid2 && !WARN_ON_ONCE(fifo_idx != 0)) { + data->size = fwrt->smem_cfg.rxfifo2_size; + data->offset = RXF_DIFF_FROM_PREV; + /* use bit 31 to distinguish between umac and lmac rxf while + * parsing the dump + */ + data->fifo_num = fifo_idx | IWL_RXF_UMAC_BIT; + return; + } +} + +static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_fifo_error_dump_range *range = range_ptr; + struct iwl_ini_rxf_data rxf_data; + u32 offs = le32_to_cpu(reg->offset), addr; + u32 registers_size = + le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32); + __le32 *val = range->data; + unsigned long flags; + int i; + + iwl_ini_get_rxf_data(fwrt, reg, &rxf_data); + if (!rxf_data.size) + return -EIO; + + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) + return -EBUSY; + + offs += rxf_data.offset; + + range->fifo_num = cpu_to_le32(rxf_data.fifo_num); + range->num_of_registers = reg->fifos.num_of_registers; + range->range_data_size = cpu_to_le32(rxf_data.size + registers_size); + + /* read rxf registers */ + for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { + addr = le32_to_cpu(reg->start_addr[i]) + offs; + + *val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr)); + } + + if (reg->fifos.header_only) { + range->range_data_size = cpu_to_le32(registers_size); + goto out; + } + + /* Lock fence */ + iwl_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1); + /* Set fence pointer to the same place like WR pointer */ + iwl_write_prph_no_grab(fwrt->trans, RXF_LD_WR2FENCE + offs, 0x1); + /* Set fence offset */ + iwl_write_prph_no_grab(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offs, + 0x0); + + /* Read FIFO */ + addr = RXF_FIFO_RD_FENCE_INC + offs; + for (i = 0; i < rxf_data.size; i += sizeof(__le32)) + *val++ = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, addr)); + +out: + iwl_trans_release_nic_access(fwrt->trans, &flags); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *data) +{ + struct iwl_fw_ini_error_dump *dump = data; + + return dump->ranges; +} + +static void +*iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *data) +{ + struct iwl_fw_ini_monitor_dram_dump *mon_dump = (void *)data; + u32 write_ptr, cycle_cnt; + unsigned long flags; + + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) { + IWL_ERR(fwrt, "Failed to get DRAM monitor header\n"); + return NULL; + } + write_ptr = iwl_read_umac_prph_no_grab(fwrt->trans, + MON_BUFF_WRPTR_VER2); + cycle_cnt = iwl_read_umac_prph_no_grab(fwrt->trans, + MON_BUFF_CYCLE_CNT_VER2); + iwl_trans_release_nic_access(fwrt->trans, &flags); + + mon_dump->write_ptr = cpu_to_le32(write_ptr); + mon_dump->cycle_cnt = cpu_to_le32(cycle_cnt); + + return mon_dump->ranges; +} + +static void *iwl_dump_ini_fifo_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, + void *data) +{ + struct iwl_fw_ini_fifo_error_dump *dump = data; + + return dump->ranges; +} + +static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + return le32_to_cpu(reg->internal.num_of_ranges); +} + +static u32 iwl_dump_ini_paging_gen2_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + return fwrt->trans->init_dram.paging_cnt; +} + +static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + return fwrt->num_of_paging_blk; +} + +static u32 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + return 1; +} + +static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + struct iwl_ini_txf_iter_data iter = { .init = true }; + void *fifo_iter = fwrt->dump.fifo_iter; + u32 num_of_fifos = 0; + + fwrt->dump.fifo_iter = &iter; + while (iwl_ini_txf_iter(fwrt, reg)) + num_of_fifos++; + + fwrt->dump.fifo_iter = fifo_iter; + + return num_of_fifos; +} + +static u32 iwl_dump_ini_rxf_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + /* Each Rx fifo needs a different offset and therefore, it's + * region can contain only one fifo, i.e. 1 memory range. + */ + return 1; +} + +static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + return sizeof(struct iwl_fw_ini_error_dump) + + iwl_dump_ini_mem_ranges(fwrt, reg) * + (sizeof(struct iwl_fw_ini_error_dump_range) + + le32_to_cpu(reg->internal.range_data_size)); +} + +static u32 iwl_dump_ini_paging_gen2_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + int i; + u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range); + u32 size = sizeof(struct iwl_fw_ini_error_dump); + + for (i = 0; i < iwl_dump_ini_paging_gen2_ranges(fwrt, reg); i++) + size += range_header_len + + fwrt->trans->init_dram.paging[i].size; + + return size; +} + +static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + int i; + u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range); + u32 size = sizeof(struct iwl_fw_ini_error_dump); + + for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg); i++) + size += range_header_len + fwrt->fw_paging_db[i].fw_paging_size; + + return size; +} + +static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + u32 size = sizeof(struct iwl_fw_ini_monitor_dram_dump); + + if (fwrt->trans->num_blocks) + size += fwrt->trans->fw_mon[0].size; + + return size; +} + +static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + struct iwl_ini_txf_iter_data iter = { .init = true }; + void *fifo_iter = fwrt->dump.fifo_iter; + u32 size = 0; + u32 fifo_hdr = sizeof(struct iwl_fw_ini_fifo_error_dump_range) + + le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32); + + fwrt->dump.fifo_iter = &iter; + while (iwl_ini_txf_iter(fwrt, reg)) { + size += fifo_hdr; + if (!reg->fifos.header_only) + size += iter.fifo_size; + } + + if (size) + size += sizeof(struct iwl_fw_ini_fifo_error_dump); + + fwrt->dump.fifo_iter = fifo_iter; + + return size; +} + +static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg) +{ + struct iwl_ini_rxf_data rx_data; + u32 size = sizeof(struct iwl_fw_ini_fifo_error_dump) + + sizeof(struct iwl_fw_ini_fifo_error_dump_range) + + le32_to_cpu(reg->fifos.num_of_registers) * sizeof(__le32); + + if (reg->fifos.header_only) + return size; + + iwl_ini_get_rxf_data(fwrt, reg, &rx_data); + size += rx_data.size; + + return size; +} + +/** + * struct iwl_dump_ini_mem_ops - ini memory dump operations + * @get_num_of_ranges: returns the number of memory ranges in the region. + * @get_size: returns the total size of the region. + * @fill_mem_hdr: fills region type specific headers and returns pointer to + * the first range or NULL if failed to fill headers. + * @fill_range: copies a given memory range into the dump. + * Returns the size of the range or negative error value otherwise. + */ +struct iwl_dump_ini_mem_ops { + u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg); + u32 (*get_size)(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg); + void *(*fill_mem_hdr)(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, void *data); + int (*fill_range)(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_cfg *reg, void *range, + int idx); +}; + +/** + * iwl_dump_ini_mem - copy a memory region into the dump + * @fwrt: fw runtime struct. + * @data: dump memory data. + * @reg: region to copy to the dump. + */ +static void +iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_region_type type, + struct iwl_fw_error_dump_data **data, + struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_mem_ops *ops) +{ + struct iwl_fw_ini_error_dump_header *header = (void *)(*data)->data; + void *range; + u32 num_of_ranges, i; + + if (WARN_ON(!ops || !ops->get_num_of_ranges || !ops->get_size || + !ops->fill_mem_hdr || !ops->fill_range)) + return; + + num_of_ranges = ops->get_num_of_ranges(fwrt, reg); + + (*data)->type = cpu_to_le32(type | INI_DUMP_BIT); + (*data)->len = cpu_to_le32(ops->get_size(fwrt, reg)); + + header->num_of_ranges = cpu_to_le32(num_of_ranges); + header->name_len = cpu_to_le32(min_t(int, IWL_FW_INI_MAX_NAME, + le32_to_cpu(reg->name_len))); + memcpy(header->name, reg->name, le32_to_cpu(header->name_len)); + + range = ops->fill_mem_hdr(fwrt, reg, header); + if (!range) { + IWL_ERR(fwrt, "Failed to fill region header: id=%d, type=%d\n", + le32_to_cpu(reg->region_id), type); + memset(*data, 0, le32_to_cpu((*data)->len)); + return; + } + + for (i = 0; i < num_of_ranges; i++) { + int range_size = ops->fill_range(fwrt, reg, range, i); + + if (range_size < 0) { + IWL_ERR(fwrt, "Failed to dump region: id=%d, type=%d\n", + le32_to_cpu(reg->region_id), type); + memset(*data, 0, le32_to_cpu((*data)->len)); + return; + } + range = range + range_size; + } + *data = iwl_fw_error_next_data(*data); +} + +static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_trigger *trigger) +{ + int i, size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data); + + if (!trigger || !trigger->num_regions) + return 0; + + for (i = 0; i < le32_to_cpu(trigger->num_regions); i++) { + u32 reg_id = le32_to_cpu(trigger->data[i]); + struct iwl_fw_ini_region_cfg *reg; + enum iwl_fw_ini_region_type type; + + if (WARN_ON(reg_id >= ARRAY_SIZE(fwrt->dump.active_regs))) + continue; + + reg = fwrt->dump.active_regs[reg_id]; + if (WARN(!reg, "Unassigned region %d\n", reg_id)) + continue; + + type = le32_to_cpu(reg->region_type); + switch (type) { + case IWL_FW_INI_REGION_DEVICE_MEMORY: + case IWL_FW_INI_REGION_PERIPHERY_MAC: + case IWL_FW_INI_REGION_PERIPHERY_PHY: + case IWL_FW_INI_REGION_PERIPHERY_AUX: + case IWL_FW_INI_REGION_INTERNAL_BUFFER: + case IWL_FW_INI_REGION_CSR: + size += hdr_len + iwl_dump_ini_mem_get_size(fwrt, reg); + break; + case IWL_FW_INI_REGION_TXF: + size += hdr_len + iwl_dump_ini_txf_get_size(fwrt, reg); + break; + case IWL_FW_INI_REGION_RXF: + size += hdr_len + iwl_dump_ini_rxf_get_size(fwrt, reg); + break; + case IWL_FW_INI_REGION_PAGING: { + size += hdr_len; + if (iwl_fw_dbg_is_paging_enabled(fwrt)) { + size += iwl_dump_ini_paging_get_size(fwrt, reg); + } else { + size += iwl_dump_ini_paging_gen2_get_size(fwrt, + reg); + } + break; + } + case IWL_FW_INI_REGION_DRAM_BUFFER: + if (!fwrt->trans->num_blocks) + break; + size += hdr_len + + iwl_dump_ini_mon_dram_get_size(fwrt, reg); + break; + case IWL_FW_INI_REGION_DRAM_IMR: + /* Undefined yet */ + default: + break; + } + } + return size; +} + +static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_trigger *trigger, + struct iwl_fw_error_dump_data **data) +{ + int i, num = le32_to_cpu(trigger->num_regions); + + for (i = 0; i < num; i++) { + u32 reg_id = le32_to_cpu(trigger->data[i]); + enum iwl_fw_ini_region_type type; + struct iwl_fw_ini_region_cfg *reg; + struct iwl_dump_ini_mem_ops ops; + + if (reg_id >= ARRAY_SIZE(fwrt->dump.active_regs)) + continue; + + reg = fwrt->dump.active_regs[reg_id]; + /* Don't warn, get_trigger_len already warned */ + if (!reg) + continue; + + type = le32_to_cpu(reg->region_type); + switch (type) { + case IWL_FW_INI_REGION_DEVICE_MEMORY: + case IWL_FW_INI_REGION_INTERNAL_BUFFER: + ops.get_num_of_ranges = iwl_dump_ini_mem_ranges; + ops.get_size = iwl_dump_ini_mem_get_size; + ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header; + ops.fill_range = iwl_dump_ini_dev_mem_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + case IWL_FW_INI_REGION_PERIPHERY_MAC: + case IWL_FW_INI_REGION_PERIPHERY_PHY: + case IWL_FW_INI_REGION_PERIPHERY_AUX: + ops.get_num_of_ranges = iwl_dump_ini_mem_ranges; + ops.get_size = iwl_dump_ini_mem_get_size; + ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header; + ops.fill_range = iwl_dump_ini_prph_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + case IWL_FW_INI_REGION_DRAM_BUFFER: + ops.get_num_of_ranges = iwl_dump_ini_mon_dram_ranges; + ops.get_size = iwl_dump_ini_mon_dram_get_size; + ops.fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header; + ops.fill_range = iwl_dump_ini_mon_dram_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + case IWL_FW_INI_REGION_PAGING: { + ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header; + if (iwl_fw_dbg_is_paging_enabled(fwrt)) { + ops.get_num_of_ranges = + iwl_dump_ini_paging_ranges; + ops.get_size = iwl_dump_ini_paging_get_size; + ops.fill_range = iwl_dump_ini_paging_iter; + } else { + ops.get_num_of_ranges = + iwl_dump_ini_paging_gen2_ranges; + ops.get_size = + iwl_dump_ini_paging_gen2_get_size; + ops.fill_range = iwl_dump_ini_paging_gen2_iter; + } + + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + } + case IWL_FW_INI_REGION_TXF: { + struct iwl_ini_txf_iter_data iter = { .init = true }; + void *fifo_iter = fwrt->dump.fifo_iter; + + fwrt->dump.fifo_iter = &iter; + ops.get_num_of_ranges = iwl_dump_ini_txf_ranges; + ops.get_size = iwl_dump_ini_txf_get_size; + ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header; + ops.fill_range = iwl_dump_ini_txf_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + fwrt->dump.fifo_iter = fifo_iter; + break; + } + case IWL_FW_INI_REGION_RXF: + ops.get_num_of_ranges = iwl_dump_ini_rxf_ranges; + ops.get_size = iwl_dump_ini_rxf_get_size; + ops.fill_mem_hdr = iwl_dump_ini_fifo_fill_header; + ops.fill_range = iwl_dump_ini_rxf_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + case IWL_FW_INI_REGION_CSR: + ops.get_num_of_ranges = iwl_dump_ini_mem_ranges; + ops.get_size = iwl_dump_ini_mem_get_size; + ops.fill_mem_hdr = iwl_dump_ini_mem_fill_header; + ops.fill_range = iwl_dump_ini_csr_iter; + iwl_dump_ini_mem(fwrt, type, data, reg, &ops); + break; + case IWL_FW_INI_REGION_DRAM_IMR: + /* This is undefined yet */ + default: + break; + } + } +} + +static struct iwl_fw_error_dump_file * +_iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dump_ptrs *fw_error_dump) +{ + int size, id = le32_to_cpu(fwrt->dump.desc->trig_desc.type); + struct iwl_fw_error_dump_data *dump_data; + struct iwl_fw_error_dump_file *dump_file; + struct iwl_fw_ini_trigger *trigger; + + if (id == FW_DBG_TRIGGER_FW_ASSERT) + id = IWL_FW_TRIGGER_ID_FW_ASSERT; + + if (!iwl_fw_ini_trigger_on(fwrt, id)) + return NULL; + + trigger = fwrt->dump.active_trigs[id].trig; + + size = iwl_fw_ini_get_trigger_len(fwrt, trigger); + if (!size) + return NULL; + + size += sizeof(*dump_file); + + dump_file = vzalloc(size); + if (!dump_file) + return NULL; + + fw_error_dump->fwrt_ptr = dump_file; + + dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); + dump_data = (void *)dump_file->data; + dump_file->file_len = cpu_to_le32(size); + + iwl_fw_ini_dump_trigger(fwrt, trigger, &dump_data); + return dump_file; } @@ -912,6 +1836,7 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) struct iwl_fw_error_dump_file *dump_file; struct scatterlist *sg_dump_data; u32 file_len; + u32 dump_mask = fwrt->fw->dbg.dump_mask; IWL_DEBUG_INFO(fwrt, "WRT dump start\n"); @@ -925,14 +1850,23 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) if (!fw_error_dump) goto out; - dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump); + if (fwrt->trans->ini_valid) + dump_file = _iwl_fw_error_ini_dump(fwrt, fw_error_dump); + else + dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump); + if (!dump_file) { kfree(fw_error_dump); goto out; } - fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans, - fwrt->dump.trig); + if (!fwrt->trans->ini_valid && fwrt->dump.monitor_only) + dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR; + + if (!fwrt->trans->ini_valid) + fw_error_dump->trans_ptr = + iwl_trans_dump_data(fwrt->trans, dump_mask); + file_len = le32_to_cpu(dump_file->file_len); fw_error_dump->fwrt_len = file_len; if (fw_error_dump->trans_ptr) { @@ -973,52 +1907,12 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = { }; IWL_EXPORT_SYMBOL(iwl_dump_desc_assert); -void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt) -{ - struct iwl_fw_dump_desc *iwl_dump_desc_no_alive = - kmalloc(sizeof(*iwl_dump_desc_no_alive), GFP_KERNEL); - - if (!iwl_dump_desc_no_alive) - return; - - iwl_dump_desc_no_alive->trig_desc.type = - cpu_to_le32(FW_DBG_TRIGGER_NO_ALIVE); - iwl_dump_desc_no_alive->len = 0; - - if (WARN_ON(fwrt->dump.desc)) - iwl_fw_free_dump_desc(fwrt); - - IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", - FW_DBG_TRIGGER_NO_ALIVE); - - fwrt->dump.desc = iwl_dump_desc_no_alive; - iwl_fw_error_dump(fwrt); - clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status); -} -IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump); - int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, - const struct iwl_fw_dump_desc *desc, void *trigger, + const struct iwl_fw_dump_desc *desc, + bool monitor_only, unsigned int delay) { - /* - * If the loading of the FW completed successfully, the next step is to - * get the SMEM config data. Thus, if fwrt->smem_cfg.num_lmacs is non - * zero, the FW was already loaded successully. If the state is "NO_FW" - * in such a case - exit, since FW may be dead. Otherwise, we - * can try to collect the data, since FW might just not be fully - * loaded (no "ALIVE" yet), and the debug data is accessible. - * - * Corner case: got the FW alive but crashed before getting the SMEM - * config. In such a case, due to HW access problems, we might - * collect garbage. - */ - if (fwrt->trans->state == IWL_TRANS_NO_FW && - fwrt->smem_cfg.num_lmacs) - return -EIO; - - if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status) || - test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &fwrt->status)) + if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status)) return -EBUSY; if (WARN_ON(fwrt->dump.desc)) @@ -1028,21 +1922,45 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, le32_to_cpu(desc->trig_desc.type)); fwrt->dump.desc = desc; - fwrt->dump.trig = trigger; + fwrt->dump.monitor_only = monitor_only; - schedule_delayed_work(&fwrt->dump.wk, delay); + schedule_delayed_work(&fwrt->dump.wk, usecs_to_jiffies(delay)); return 0; } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc); -int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, - struct iwl_fw_dbg_trigger_tlv *trigger) +int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig_type) +{ + int ret; + struct iwl_fw_dump_desc *iwl_dump_error_desc = + kmalloc(sizeof(*iwl_dump_error_desc), GFP_KERNEL); + + if (!iwl_dump_error_desc) + return -ENOMEM; + + iwl_dump_error_desc->trig_desc.type = cpu_to_le32(trig_type); + iwl_dump_error_desc->len = 0; + + ret = iwl_fw_dbg_collect_desc(fwrt, iwl_dump_error_desc, false, 0); + if (ret) + kfree(iwl_dump_error_desc); + else + iwl_trans_sync_nmi(fwrt->trans); + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_error_collect); + +int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig, + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_fw_dump_desc *desc; unsigned int delay = 0; + bool monitor_only = false; if (trigger) { u16 occurrences = le16_to_cpu(trigger->occurrences) - 1; @@ -1058,7 +1976,10 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, } trigger->occurrences = cpu_to_le16(occurrences); - delay = le16_to_cpu(trigger->trig_dis_ms); + monitor_only = trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY; + + /* convert msec to usec */ + delay = le32_to_cpu(trigger->stop_delay) * USEC_PER_MSEC; } desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); @@ -1070,7 +1991,50 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_fw_dbg_collect_desc(fwrt, desc, trigger, delay); + return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay); +} +IWL_EXPORT_SYMBOL(_iwl_fw_dbg_collect); + +int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, + u32 id, const char *str, size_t len) +{ + struct iwl_fw_dump_desc *desc; + struct iwl_fw_ini_active_triggers *active; + u32 occur, delay; + + if (!fwrt->trans->ini_valid) + return _iwl_fw_dbg_collect(fwrt, id, str, len, NULL); + + if (id == FW_DBG_TRIGGER_USER) + id = IWL_FW_TRIGGER_ID_USER_TRIGGER; + + active = &fwrt->dump.active_trigs[id]; + + if (WARN_ON(!active->active)) + return -EINVAL; + + delay = le32_to_cpu(active->trig->dump_delay); + occur = le32_to_cpu(active->trig->occurrences); + if (!occur) + return 0; + + if (le32_to_cpu(active->trig->force_restart)) { + IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", id); + iwl_force_nmi(fwrt->trans); + return 0; + } + + desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); + if (!desc) + return -ENOMEM; + + active->trig->occurrences = cpu_to_le32(--occur); + + desc->len = len; + desc->trig_desc.type = cpu_to_le32(id); + memcpy(desc->trig_desc.data, str, len); + + return iwl_fw_dbg_collect_desc(fwrt, desc, true, delay); } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); @@ -1081,6 +2045,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, int ret, len = 0; char buf[64]; + if (fwrt->trans->ini_valid) + return 0; + if (fmt) { va_list ap; @@ -1097,8 +2064,8 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, len = strlen(buf) + 1; } - ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len, - trigger); + ret = _iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len, + trigger); if (ret) return ret; @@ -1224,3 +2191,304 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt) cfg->d3_debug_data_length); } IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data); + +static void +iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt, u32 size) +{ + struct iwl_trans *trans = fwrt->trans; + void *virtual_addr = NULL; + dma_addr_t phys_addr; + + if (WARN_ON_ONCE(trans->num_blocks == ARRAY_SIZE(trans->fw_mon))) + return; + + virtual_addr = + dma_alloc_coherent(fwrt->trans->dev, size, &phys_addr, + GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO | + __GFP_COMP); + + /* TODO: alloc fragments if needed */ + if (!virtual_addr) + IWL_ERR(fwrt, "Failed to allocate debug memory\n"); + + trans->fw_mon[trans->num_blocks].block = virtual_addr; + trans->fw_mon[trans->num_blocks].physical = phys_addr; + trans->fw_mon[trans->num_blocks].size = size; + trans->num_blocks++; + + IWL_DEBUG_FW(trans, "Allocated debug block of size %d\n", size); +} + +static void iwl_fw_dbg_buffer_apply(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_allocation_data *alloc, + enum iwl_fw_ini_apply_point pnt) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_ldbg_config_cmd ldbg_cmd = { + .type = cpu_to_le32(BUFFER_ALLOCATION), + }; + struct iwl_buffer_allocation_cmd *cmd = &ldbg_cmd.buffer_allocation; + struct iwl_host_cmd hcmd = { + .id = LDBG_CONFIG_CMD, + .flags = CMD_ASYNC, + .data[0] = &ldbg_cmd, + .len[0] = sizeof(ldbg_cmd), + }; + int block_idx = trans->num_blocks; + u32 buf_location = le32_to_cpu(alloc->tlv.buffer_location); + + if (buf_location == IWL_FW_INI_LOCATION_SRAM_PATH) { + if (!WARN(pnt != IWL_FW_INI_APPLY_EARLY, + "Invalid apply point %d for SMEM buffer allocation", + pnt)) + /* set sram monitor by enabling bit 7 */ + iwl_set_bit(fwrt->trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM); + return; + } + + if (buf_location != IWL_FW_INI_LOCATION_DRAM_PATH) + return; + + if (!alloc->is_alloc) { + iwl_fw_dbg_buffer_allocation(fwrt, + le32_to_cpu(alloc->tlv.size)); + if (block_idx == trans->num_blocks) + return; + alloc->is_alloc = 1; + } + + /* First block is assigned via registers / context info */ + if (trans->num_blocks == 1) + return; + + cmd->num_frags = cpu_to_le32(1); + cmd->fragments[0].address = + cpu_to_le64(trans->fw_mon[block_idx].physical); + cmd->fragments[0].size = alloc->tlv.size; + cmd->allocation_id = alloc->tlv.allocation_id; + cmd->buffer_location = alloc->tlv.buffer_location; + + iwl_trans_send_cmd(trans, &hcmd); +} + +static void iwl_fw_dbg_send_hcmd(struct iwl_fw_runtime *fwrt, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_hcmd_tlv *hcmd_tlv = (void *)&tlv->data[0]; + struct iwl_fw_ini_hcmd *data = &hcmd_tlv->hcmd; + u16 len = le32_to_cpu(tlv->length) - sizeof(*hcmd_tlv); + + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(data->group, data->id), + .len = { len, }, + .data = { data->data, }, + }; + + iwl_trans_send_cmd(fwrt->trans, &hcmd); +} + +static void iwl_fw_dbg_update_regions(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_region_tlv *tlv, + bool ext, enum iwl_fw_ini_apply_point pnt) +{ + void *iter = (void *)tlv->region_config; + int i, size = le32_to_cpu(tlv->num_regions); + + for (i = 0; i < size; i++) { + struct iwl_fw_ini_region_cfg *reg = iter, **active; + int id = le32_to_cpu(reg->region_id); + u32 type = le32_to_cpu(reg->region_type); + + if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_regs), + "Invalid region id %d for apply point %d\n", id, pnt)) + break; + + active = &fwrt->dump.active_regs[id]; + + if (*active) + IWL_WARN(fwrt->trans, "region TLV %d override\n", id); + + IWL_DEBUG_FW(fwrt, + "%s: apply point %d, activating region ID %d\n", + __func__, pnt, id); + + *active = reg; + + if (type == IWL_FW_INI_REGION_TXF || + type == IWL_FW_INI_REGION_RXF) + iter += le32_to_cpu(reg->fifos.num_of_registers) * + sizeof(__le32); + else if (type != IWL_FW_INI_REGION_DRAM_BUFFER) + iter += le32_to_cpu(reg->internal.num_of_ranges) * + sizeof(__le32); + + iter += sizeof(*reg); + } +} + +static int iwl_fw_dbg_trig_realloc(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_active_triggers *active, + u32 id, int size) +{ + void *ptr; + + if (size <= active->size) + return 0; + + ptr = krealloc(active->trig, size, GFP_KERNEL); + if (!ptr) { + IWL_ERR(fwrt, "Failed to allocate memory for trigger %d\n", id); + return -ENOMEM; + } + active->trig = ptr; + active->size = size; + + return 0; +} + +static void iwl_fw_dbg_update_triggers(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_trigger_tlv *tlv, + bool ext, + enum iwl_fw_ini_apply_point apply_point) +{ + int i, size = le32_to_cpu(tlv->num_triggers); + void *iter = (void *)tlv->trigger_config; + + for (i = 0; i < size; i++) { + struct iwl_fw_ini_trigger *trig = iter; + struct iwl_fw_ini_active_triggers *active; + int id = le32_to_cpu(trig->trigger_id); + u32 trig_regs_size = le32_to_cpu(trig->num_regions) * + sizeof(__le32); + + if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_trigs))) + break; + + active = &fwrt->dump.active_trigs[id]; + + if (!active->active) { + size_t trig_size = sizeof(*trig) + trig_regs_size; + + if (iwl_fw_dbg_trig_realloc(fwrt, active, id, + trig_size)) + goto next; + + memcpy(active->trig, trig, trig_size); + + } else { + u32 conf_override = + !(le32_to_cpu(trig->override_trig) & 0xff); + u32 region_override = + !(le32_to_cpu(trig->override_trig) & 0xff00); + u32 offset = 0; + u32 active_regs = + le32_to_cpu(active->trig->num_regions); + u32 new_regs = le32_to_cpu(trig->num_regions); + int mem_to_add = trig_regs_size; + + if (region_override) { + mem_to_add -= active_regs * sizeof(__le32); + } else { + offset += active_regs; + new_regs += active_regs; + } + + if (iwl_fw_dbg_trig_realloc(fwrt, active, id, + active->size + mem_to_add)) + goto next; + + if (conf_override) + memcpy(active->trig, trig, sizeof(*trig)); + + memcpy(active->trig->data + offset, trig->data, + trig_regs_size); + active->trig->num_regions = cpu_to_le32(new_regs); + } + + /* Since zero means infinity - just set to -1 */ + if (!le32_to_cpu(active->trig->occurrences)) + active->trig->occurrences = cpu_to_le32(-1); + + active->active = true; +next: + iter += sizeof(*trig) + trig_regs_size; + + } +} + +static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, + struct iwl_apply_point_data *data, + enum iwl_fw_ini_apply_point pnt, + bool ext) +{ + void *iter = data->data; + + while (iter && iter < data->data + data->size) { + struct iwl_ucode_tlv *tlv = iter; + void *ini_tlv = (void *)tlv->data; + u32 type = le32_to_cpu(tlv->type); + + switch (type) { + case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: { + struct iwl_fw_ini_allocation_data *buf_alloc = ini_tlv; + + iwl_fw_dbg_buffer_apply(fwrt, ini_tlv, pnt); + iter += sizeof(buf_alloc->is_alloc); + break; + } + case IWL_UCODE_TLV_TYPE_HCMD: + if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) { + IWL_ERR(fwrt, + "Invalid apply point %x for host command\n", + pnt); + goto next; + } + iwl_fw_dbg_send_hcmd(fwrt, tlv); + break; + case IWL_UCODE_TLV_TYPE_REGIONS: + iwl_fw_dbg_update_regions(fwrt, ini_tlv, ext, pnt); + break; + case IWL_UCODE_TLV_TYPE_TRIGGERS: + iwl_fw_dbg_update_triggers(fwrt, ini_tlv, ext, pnt); + break; + case IWL_UCODE_TLV_TYPE_DEBUG_FLOW: + break; + default: + WARN_ONCE(1, "Invalid TLV %x for apply point\n", type); + break; + } +next: + iter += sizeof(*tlv) + le32_to_cpu(tlv->length); + } +} + +void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_apply_point apply_point) +{ + void *data = &fwrt->trans->apply_points[apply_point]; + int i; + + if (apply_point == IWL_FW_INI_APPLY_EARLY) { + for (i = 0; i < IWL_FW_INI_MAX_REGION_ID; i++) + fwrt->dump.active_regs[i] = NULL; + + /* disable the triggers, used in recovery flow */ + for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++) + fwrt->dump.active_trigs[i].active = false; + } + + _iwl_fw_dbg_apply_point(fwrt, data, apply_point, false); + + data = &fwrt->trans->apply_points_ext[apply_point]; + _iwl_fw_dbg_apply_point(fwrt, data, apply_point, true); +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point); + +void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt) +{ + iwl_fw_dbg_collect_sync(fwrt); + + iwl_trans_stop_device(fwrt->trans); +} +IWL_EXPORT_SYMBOL(iwl_fwrt_stop_device); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 6f8d3256f7b0..a199056234d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -8,7 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,6 +72,7 @@ #include "file.h" #include "error-dump.h" #include "api/commands.h" +#include "api/dbg-tlv.h" /** * struct iwl_fw_dump_desc - describes the dump @@ -101,17 +102,24 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) if (fwrt->dump.desc != &iwl_dump_desc_assert) kfree(fwrt->dump.desc); fwrt->dump.desc = NULL; - fwrt->dump.trig = NULL; + fwrt->dump.lmac_err_id[0] = 0; + if (fwrt->smem_cfg.num_lmacs > 1) + fwrt->dump.lmac_err_id[1] = 0; + fwrt->dump.umac_err_id = 0; } void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, const struct iwl_fw_dump_desc *desc, - void *trigger, unsigned int delay); + bool monitor_only, unsigned int delay); +int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig_type); +int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig, + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, - struct iwl_fw_dbg_trigger_tlv *trigger); + u32 id, const char *str, size_t len); int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) __printf(3, 4); @@ -154,9 +162,9 @@ iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt, } static inline bool -iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_ms) +iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_usec) { - unsigned long wind_jiff = msecs_to_jiffies(dis_ms); + unsigned long wind_jiff = usecs_to_jiffies(dis_usec); /* If this is the first event checked, jump to update start ts */ if (fwrt->dump.non_collect_ts_start[id] && @@ -173,11 +181,12 @@ iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt, struct wireless_dev *wdev, struct iwl_fw_dbg_trigger_tlv *trig) { + u32 usec = le16_to_cpu(trig->trig_dis_ms) * USEC_PER_MSEC; + if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev)) return false; - if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id), - le16_to_cpu(trig->trig_dis_ms))) { + if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id), usec)) { IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n", trig->id); return false; @@ -193,6 +202,9 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt, { struct iwl_fw_dbg_trigger_tlv *trig; + if (fwrt->trans->ini_valid) + return NULL; + if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id)) return NULL; @@ -210,6 +222,30 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt, _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \ }) +static inline bool +iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_trigger_id id) +{ + struct iwl_fw_ini_trigger *trig; + u32 usec; + + + + if (!fwrt->trans->ini_valid || id >= IWL_FW_TRIGGER_ID_NUM || + !fwrt->dump.active_trigs[id].active) + return false; + + trig = fwrt->dump.active_trigs[id].trig; + usec = le32_to_cpu(trig->ignore_consec); + + if (iwl_fw_dbg_no_trig_window(fwrt, id, usec)) { + IWL_WARN(fwrt, "Trigger %d fired in no-collect window\n", id); + return false; + } + + return true; +} + static inline void _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, struct wireless_dev *wdev, @@ -229,20 +265,20 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, iwl_fw_dbg_get_trigger((fwrt)->fw,\ (trig))) -static int iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start) +static inline int +iwl_fw_dbg_start_stop_hcmd(struct iwl_fw_runtime *fwrt, bool start) { - struct iwl_continuous_record_cmd cont_rec = {}; + struct iwl_ldbg_config_cmd cmd = { + .type = start ? cpu_to_le32(START_DEBUG_RECORDING) : + cpu_to_le32(STOP_DEBUG_RECORDING), + }; struct iwl_host_cmd hcmd = { .id = LDBG_CONFIG_CMD, .flags = CMD_ASYNC, - .data[0] = &cont_rec, - .len[0] = sizeof(cont_rec), + .data[0] = &cmd, + .len[0] = sizeof(cmd), }; - cont_rec.record_mode.enable_recording = start ? - cpu_to_le16(START_DEBUG_RECORDING) : - cpu_to_le16(STOP_DEBUG_RECORDING); - return iwl_trans_send_cmd(fwrt->trans, &hcmd); } @@ -256,13 +292,16 @@ _iwl_fw_dbg_stop_recording(struct iwl_trans *trans, } if (params) { - params->in_sample = iwl_read_prph(trans, DBGC_IN_SAMPLE); - params->out_ctrl = iwl_read_prph(trans, DBGC_OUT_CTRL); + params->in_sample = iwl_read_umac_prph(trans, DBGC_IN_SAMPLE); + params->out_ctrl = iwl_read_umac_prph(trans, DBGC_OUT_CTRL); } - iwl_write_prph(trans, DBGC_IN_SAMPLE, 0); + iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0); udelay(100); - iwl_write_prph(trans, DBGC_OUT_CTRL, 0); + iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0); +#ifdef CONFIG_IWLWIFI_DEBUGFS + trans->dbg_rec_on = false; +#endif } static inline void @@ -287,12 +326,20 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans, iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); } else { - iwl_write_prph(trans, DBGC_IN_SAMPLE, params->in_sample); + iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample); udelay(100); - iwl_write_prph(trans, DBGC_OUT_CTRL, params->out_ctrl); + iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl); } } +#ifdef CONFIG_IWLWIFI_DEBUGFS +static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt) +{ + if (fwrt->fw->dbg.dest_tlv && fwrt->cur_fw_img == IWL_UCODE_REGULAR) + fwrt->trans->dbg_rec_on = true; +} +#endif + static inline void iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_params *params) @@ -301,6 +348,9 @@ iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt, _iwl_fw_dbg_restart_recording(fwrt->trans, params); else iwl_fw_dbg_start_stop_hcmd(fwrt, true); +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_fw_set_dbg_rec_on(fwrt); +#endif } static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt) @@ -310,12 +360,28 @@ static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt) void iwl_fw_error_dump_wk(struct work_struct *work); +static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type) +{ + return (fwrt->fw->dbg.dump_mask & BIT(type) || fwrt->trans->ini_valid); +} + static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt) { return fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_D3_DEBUG) && - fwrt->trans->cfg->d3_debug_data_length && - fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); + fwrt->trans->cfg->d3_debug_data_length && fwrt->ops && + fwrt->ops->d3_debug_enable && + fwrt->ops->d3_debug_enable(fwrt->ops_ctx) && + iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA); +} + +static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt) +{ + return iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PAGING) && + !fwrt->trans->cfg->gen2 && + fwrt->cur_fw_img < IWL_UCODE_TYPE_MAX && + fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && + fwrt->fw_paging_db[0].fw_paging_block; } void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt); @@ -366,6 +432,33 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} #endif /* CONFIG_IWLWIFI_DEBUGFS */ -void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt); void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt); +void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_apply_point apply_point); + +void iwl_fwrt_stop_device(struct iwl_fw_runtime *fwrt); + +static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans, + u32 lmac_error_event_table) +{ + if (!(trans->error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_LMAC1) || + WARN_ON(trans->lmac_error_event_table[0] != + lmac_error_event_table)) + trans->lmac_error_event_table[0] = lmac_error_event_table; +} + +static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans, + u32 umac_error_event_table) +{ + if (!(trans->error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_UMAC) || + WARN_ON(trans->umac_error_event_table != + umac_error_event_table)) + trans->umac_error_event_table = umac_error_event_table; +} + +/* This bit is used to differentiate the legacy dump from the ini dump */ +#define INI_DUMP_BIT BIT(31) + #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 3e120dd47305..c1aa4360736b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -173,9 +173,8 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime) #define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \ - if (!debugfs_create_file(alias, mode, parent, fwrt, \ - &iwl_dbgfs_##name##_ops)) \ - goto err; \ + debugfs_create_file(alias, mode, parent, fwrt, \ + &iwl_dbgfs_##name##_ops); \ } while (0) #define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \ FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) @@ -321,14 +320,10 @@ out: FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512); -int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, +void iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) { INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk); FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200); FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200); - return 0; -err: - IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n"); - return -ENOMEM; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index 88255035e8ef..fde40ff88451 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -63,14 +63,11 @@ #include "runtime.h" #ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, +void iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir); #else -static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, - struct dentry *dbgfs_dir) -{ - return 0; -} +static inline void iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, + struct dentry *dbgfs_dir) { } #endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 6fede174c664..9b5077bd46c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -8,7 +8,7 @@ * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -180,6 +180,8 @@ enum iwl_fw_error_dump_family { IWL_FW_ERROR_DUMP_FAMILY_8 = 8, }; +#define MAX_NUM_LMAC 2 + /** * struct iwl_fw_error_dump_info - info on the device / firmware * @device_family: the family of the device (7 / 8) @@ -187,6 +189,11 @@ enum iwl_fw_error_dump_family { * @fw_human_readable: human readable FW version * @dev_human_readable: name of the device * @bus_human_readable: name of the bus used + * @num_of_lmacs: the number of lmacs + * @lmac_err_id: the lmac 0/1 error_id/rt_status that triggered the latest dump + * if the dump collection was not initiated by an assert, the value is 0 + * @umac_err_id: the umac error_id/rt_status that triggered the latest dump + * if the dump collection was not initiated by an assert, the value is 0 */ struct iwl_fw_error_dump_info { __le32 device_family; @@ -194,6 +201,9 @@ struct iwl_fw_error_dump_info { u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ]; u8 dev_human_readable[64]; u8 bus_human_readable[8]; + u8 num_of_lmacs; + __le32 umac_err_id; + __le32 lmac_err_id[MAX_NUM_LMAC]; } __packed; /** @@ -249,6 +259,7 @@ struct iwl_fw_error_dump_prph { enum iwl_fw_error_dump_mem_type { IWL_FW_ERROR_DUMP_MEM_SRAM, IWL_FW_ERROR_DUMP_MEM_SMEM, + IWL_FW_ERROR_DUMP_MEM_NAMED_MEM = 10, }; /** @@ -264,6 +275,68 @@ struct iwl_fw_error_dump_mem { }; /** + * struct iwl_fw_ini_error_dump_range - range of memory + * @start_addr: the start address of this range + * @range_data_size: the size of this range, in bytes + * @data: the actual memory + */ +struct iwl_fw_ini_error_dump_range { + __le32 start_addr; + __le32 range_data_size; + __le32 data[]; +} __packed; + +/** + * struct iwl_fw_ini_error_dump_header - ini region dump header + * @num_of_ranges: number of ranges in this region + * @name_len: number of bytes allocated to the name string of this region + * @name: name of the region + */ +struct iwl_fw_ini_error_dump_header { + __le32 num_of_ranges; + __le32 name_len; + u8 name[IWL_FW_INI_MAX_NAME]; +}; + +/** + * struct iwl_fw_ini_error_dump - ini region dump + * @header: the header of this region + * @ranges: the memory ranges of this region + */ +struct iwl_fw_ini_error_dump { + struct iwl_fw_ini_error_dump_header header; + struct iwl_fw_ini_error_dump_range ranges[]; +} __packed; + +/* This bit is used to differentiate between lmac and umac rxf */ +#define IWL_RXF_UMAC_BIT BIT(31) + +/** + * struct iwl_fw_ini_fifo_error_dump_range - ini fifo range dump + * @fifo_num: the fifo num. In case of rxf and umac rxf, set BIT(31) to + * distinguish between lmac and umac + * @num_of_registers: num of registers to dump, dword size each + * @range_data_size: the size of the registers and fifo data + * @data: fifo data + */ +struct iwl_fw_ini_fifo_error_dump_range { + __le32 fifo_num; + __le32 num_of_registers; + __le32 range_data_size; + __le32 data[]; +} __packed; + +/** + * struct iwl_fw_ini_fifo_error_dump - ini fifo region dump + * @header: the header of this region + * @ranges: the memory ranges of this region + */ +struct iwl_fw_ini_fifo_error_dump { + struct iwl_fw_ini_error_dump_header header; + struct iwl_fw_ini_fifo_error_dump_range ranges[]; +} __packed; + +/** * struct iwl_fw_error_dump_rb - content of an Receive Buffer * @index: the index of the Receive Buffer in the Rx queue * @rxq: the RB's Rx queue @@ -278,6 +351,20 @@ struct iwl_fw_error_dump_rb { }; /** + * struct iwl_fw_ini_monitor_dram_dump - ini dram monitor dump + * @header - header of the region + * @write_ptr - write pointer position in the dram + * @cycle_cnt - cycles count + * @ranges - the memory ranges of this this region + */ +struct iwl_fw_ini_monitor_dram_dump { + struct iwl_fw_ini_error_dump_header header; + __le32 write_ptr; + __le32 cycle_cnt; + struct iwl_fw_ini_error_dump_range ranges[]; +} __packed; + +/** * struct iwl_fw_error_dump_paging - content of the UMAC's image page * block on DRAM * @index: the index of the page block @@ -328,7 +415,9 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TDLS: trigger log collection upon TDLS related events. * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when * the firmware sends a tx reply. - * @FW_DBG_TRIGGER_NO_ALIVE: trigger log collection if alive flow fails + * @FW_DBG_TRIGGER_ALIVE_TIMEOUT: trigger log collection if alive flow timeouts + * @FW_DBG_TRIGGER_DRIVER: trigger log collection upon a flow failure + * in the driver. */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, @@ -346,7 +435,8 @@ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_TX_LATENCY, FW_DBG_TRIGGER_TDLS, FW_DBG_TRIGGER_TX_STATUS, - FW_DBG_TRIGGER_NO_ALIVE, + FW_DBG_TRIGGER_ALIVE_TIMEOUT, + FW_DBG_TRIGGER_DRIVER, /* must be last */ FW_DBG_TRIGGER_MAX, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 6005a41c53d1..e06407dc088b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -9,6 +9,7 @@ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +33,7 @@ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -91,6 +93,8 @@ struct iwl_ucode_header { } u; }; +#define IWL_UCODE_INI_TLV_GROUP 0x1000000 + /* * new TLV uCode file layout * @@ -141,6 +145,17 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, IWL_UCODE_TLV_FW_MEM_SEG = 51, IWL_UCODE_TLV_IML = 52, + IWL_UCODE_TLV_UMAC_DEBUG_ADDRS = 54, + IWL_UCODE_TLV_LMAC_DEBUG_ADDRS = 55, + IWL_UCODE_TLV_FW_RECOVERY_INFO = 57, + + IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_INI_TLV_GROUP + 0x1, + IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION, + IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_INI_TLV_GROUP + 0x2, + IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_INI_TLV_GROUP + 0x3, + IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_INI_TLV_GROUP + 0x4, + IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_INI_TLV_GROUP + 0x5, + IWL_UCODE_TLV_DEBUG_MAX = IWL_UCODE_TLV_TYPE_DEBUG_FLOW, /* TLVs 0x1000-0x2000 are for internal driver usage */ IWL_UCODE_TLV_FW_DBG_DUMP_LST = 0x1000, @@ -256,6 +271,12 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_FRAG_EBS: This ucode supports fragmented EBS * @IWL_UCODE_TLV_API_REDUCE_TX_POWER: This ucode supports v5 of * the REDUCE_TX_POWER_CMD. + * @IWL_UCODE_TLV_API_SHORT_BEACON_NOTIF: This ucode supports the short + * version of the beacon notification. + * @IWL_UCODE_TLV_API_BEACON_FILTER_V4: This ucode supports v4 of + * BEACON_FILTER_CONFIG_API_S_VER_4. + * @IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ: This ucode supports v7 of + * LOCATION_RANGE_REQ_CMD_API_S and v6 of LOCATION_RANGE_RESP_NTFY_API_S. * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -280,6 +301,9 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42, IWL_UCODE_TLV_API_FRAG_EBS = (__force iwl_ucode_tlv_api_t)44, IWL_UCODE_TLV_API_REDUCE_TX_POWER = (__force iwl_ucode_tlv_api_t)45, + IWL_UCODE_TLV_API_SHORT_BEACON_NOTIF = (__force iwl_ucode_tlv_api_t)46, + IWL_UCODE_TLV_API_BEACON_FILTER_V4 = (__force iwl_ucode_tlv_api_t)47, + IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ = (__force iwl_ucode_tlv_api_t)49, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ @@ -296,7 +320,6 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer - * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report @@ -327,6 +350,9 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm * @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related * @IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2: firmware implements Coex Schema 2 + * IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD: firmware supports CSA command + * @IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS: firmware supports ultra high band + * (6 GHz). * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT @@ -350,19 +376,24 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger * command size (command version 4) that supports toggling ACK TX * power reduction. - * @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload * @IWL_UCODE_TLV_CAPA_D3_DEBUG: supports debug recording during D3 * @IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT: MCC response support 11ax * capability. + * @IWL_UCODE_TLV_CAPA_CSI_REPORTING: firmware is capable of being configured + * to report the CSI information with (certain) RX frames + * @IWL_UCODE_TLV_CAPA_FTM_CALIBRATED: has FTM calibrated and thus supports both + * initiator and responder + * + * @IWL_UCODE_TLV_CAPA_MLME_OFFLOAD: supports MLME offload * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ enum iwl_ucode_tlv_capa { + /* set 0 */ IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1, IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2, IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3, - IWL_UCODE_TLV_CAPA_TOF_SUPPORT = (__force iwl_ucode_tlv_capa_t)5, IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6, IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8, IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9, @@ -380,6 +411,8 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, + + /* set 1 */ IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40, @@ -387,6 +420,11 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_TLC_OFFLOAD = (__force iwl_ucode_tlv_capa_t)43, IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA = (__force iwl_ucode_tlv_capa_t)44, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2 = (__force iwl_ucode_tlv_capa_t)45, + IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD = (__force iwl_ucode_tlv_capa_t)46, + IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS = (__force iwl_ucode_tlv_capa_t)48, + IWL_UCODE_TLV_CAPA_FTM_CALIBRATED = (__force iwl_ucode_tlv_capa_t)47, + + /* set 2 */ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65, IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67, @@ -405,6 +443,9 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D3_DEBUG = (__force iwl_ucode_tlv_capa_t)87, IWL_UCODE_TLV_CAPA_LED_CMD_SUPPORT = (__force iwl_ucode_tlv_capa_t)88, IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT = (__force iwl_ucode_tlv_capa_t)89, + IWL_UCODE_TLV_CAPA_CSI_REPORTING = (__force iwl_ucode_tlv_capa_t)90, + + /* set 3 */ IWL_UCODE_TLV_CAPA_MLME_OFFLOAD = (__force iwl_ucode_tlv_capa_t)96, NUM_IWL_UCODE_TLV_CAPA diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 54dbbd998abf..f4c5a4d73206 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -65,6 +65,8 @@ #define __iwl_fw_img_h__ #include <linux/types.h> +#include "api/dbg-tlv.h" + #include "file.h" #include "error-dump.h" @@ -103,6 +105,8 @@ struct iwl_ucode_capabilities { u32 n_scan_channels; u32 standard_phy_calibration_size; u32 flags; + u32 error_log_addr; + u32 error_log_size; unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)]; unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)]; }; @@ -221,6 +225,27 @@ struct iwl_fw_dbg { }; /** + * @tlv: the buffer allocation tlv + * @is_alloc: indicates if the buffer was already allocated + */ +struct iwl_fw_ini_allocation_data { + struct iwl_fw_ini_allocation_tlv tlv; + u32 is_alloc; +} __packed; + +/** + * struct iwl_fw_ini_active_triggers + * @active: is this trigger active + * @size: allocated memory size of the trigger + * @trig: trigger + */ +struct iwl_fw_ini_active_triggers { + bool active; + size_t size; + struct iwl_fw_ini_trigger *trig; +}; + +/** * struct iwl_fw - variables associated with the firmware * * @ucode_ver: ucode version from the ucode file diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index 2efac307909e..12310e3d2fc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -26,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 2b8b50a77990..a5fe1a8ca426 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -27,7 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,6 +64,7 @@ #include "iwl-trans.h" #include "img.h" #include "fw/api/debug.h" +#include "fw/api/dbg-tlv.h" #include "fw/api/paging.h" #include "iwl-eeprom-parse.h" @@ -72,6 +73,7 @@ struct iwl_fw_runtime_ops { void (*dump_end)(void *ctx); bool (*fw_running)(void *ctx); int (*send_hcmd)(void *ctx, struct iwl_host_cmd *host_cmd); + bool (*d3_debug_enable)(void *ctx); }; #define MAX_NUM_LMAC 2 @@ -89,7 +91,6 @@ struct iwl_fwrt_shared_mem_cfg { enum iwl_fw_runtime_status { IWL_FWRT_STATUS_DUMPING = 0, - IWL_FWRT_STATUS_WAIT_ALIVE, }; /** @@ -131,14 +132,19 @@ struct iwl_fw_runtime { /* debug */ struct { const struct iwl_fw_dump_desc *desc; - const struct iwl_fw_dbg_trigger_tlv *trig; + bool monitor_only; struct delayed_work wk; u8 conf; /* ts of the beginning of a non-collect fw dbg data period */ - unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1]; + unsigned long non_collect_ts_start[IWL_FW_TRIGGER_ID_NUM]; u32 *d3_debug_data; + struct iwl_fw_ini_region_cfg *active_regs[IWL_FW_INI_MAX_REGION_ID]; + struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM]; + u32 lmac_err_id[MAX_NUM_LMAC]; + u32 umac_err_id; + void *fifo_iter; } dump; #ifdef CONFIG_IWLWIFI_DEBUGFS struct { @@ -156,8 +162,20 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, static inline void iwl_fw_runtime_free(struct iwl_fw_runtime *fwrt) { + int i; + kfree(fwrt->dump.d3_debug_data); fwrt->dump.d3_debug_data = NULL; + + for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++) { + struct iwl_fw_ini_active_triggers *active = + &fwrt->dump.active_trigs[i]; + + active->active = false; + active->size = 0; + kfree(active->trig); + active->trig = NULL; + } } void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 5eb906a0d0d2..93070848280a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -7,7 +7,7 @@ * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright (C) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright (C) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,6 +89,7 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_9000, IWL_DEVICE_FAMILY_22000, IWL_DEVICE_FAMILY_22560, + IWL_DEVICE_FAMILY_AX210, }; /* @@ -265,11 +266,9 @@ struct iwl_tt_params { #define EEPROM_REGULATORY_BAND_NO_HT40 0 /* lower blocks contain EEPROM image and calibration data */ -#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */ -#define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (16 * 512 * sizeof(u16)) /* 16 KB */ -#define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16)) /* 32 KB */ -#define OTP_LOW_IMAGE_SIZE_FAMILY_9000 OTP_LOW_IMAGE_SIZE_FAMILY_8000 -#define OTP_LOW_IMAGE_SIZE_FAMILY_22000 OTP_LOW_IMAGE_SIZE_FAMILY_9000 +#define OTP_LOW_IMAGE_SIZE_2K (2 * 512 * sizeof(u16)) /* 2 KB */ +#define OTP_LOW_IMAGE_SIZE_16K (16 * 512 * sizeof(u16)) /* 16 KB */ +#define OTP_LOW_IMAGE_SIZE_32K (32 * 512 * sizeof(u16)) /* 32 KB */ struct iwl_eeprom_params { const u8 regulatory_bands[7]; @@ -337,10 +336,6 @@ struct iwl_csr_params { * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The * filename is constructed as fw_name_pre<api>.ucode. - * @fw_name_pre_b_or_c_step: same as @fw_name_pre, only for b or c steps - * (if supported) - * @fw_name_pre_rf_next_step: same as @fw_name_pre_b_or_c_step, only for rf - * next step. Supported only in integrated solutions. * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @max_inst_size: The maximal length of the fw inst section (only DVM) @@ -385,6 +380,9 @@ struct iwl_csr_params { * @nvm_type: see &enum iwl_nvm_type * @d3_debug_data_base_addr: base address where D3 debug data is stored * @d3_debug_data_length: length of the D3 debug data + * @bisr_workaround: BISR hardware workaround (for 22260 series devices) + * @min_txq_size: minimum number of slots required in a TX queue + * @umac_prph_offset: offset to add to UMAC periphery address * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -394,8 +392,6 @@ struct iwl_cfg { /* params specific to an individual device within a device family */ const char *name; const char *fw_name_pre; - const char *fw_name_pre_b_or_c_step; - const char *fw_name_pre_rf_next_step; /* params not likely to change within a device family */ const struct iwl_base_params *base_params; /* params likely to change within a device family */ @@ -436,7 +432,8 @@ struct iwl_cfg { use_tfh:1, gen2:1, cdb:1, - dbgc_supported:1; + dbgc_supported:1, + bisr_workaround:1; u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; @@ -451,37 +448,12 @@ struct iwl_cfg { u32 extra_phy_cfg_flags; u32 d3_debug_data_base_addr; u32 d3_debug_data_length; + u32 min_txq_size; + u32 umac_prph_offset; }; -static const struct iwl_csr_params iwl_csr_v1 = { - .flag_mac_clock_ready = 0, - .flag_val_mac_access_en = 0, - .flag_init_done = 2, - .flag_mac_access_req = 3, - .flag_sw_reset = 7, - .flag_master_dis = 8, - .flag_stop_master = 9, - .addr_sw_reset = (CSR_BASE + 0x020), - .mac_addr0_otp = 0x380, - .mac_addr1_otp = 0x384, - .mac_addr0_strap = 0x388, - .mac_addr1_strap = 0x38C -}; - -static const struct iwl_csr_params iwl_csr_v2 = { - .flag_init_done = 6, - .flag_mac_clock_ready = 20, - .flag_val_mac_access_en = 20, - .flag_mac_access_req = 21, - .flag_master_dis = 28, - .flag_stop_master = 29, - .flag_sw_reset = 31, - .addr_sw_reset = (CSR_BASE + 0x024), - .mac_addr0_otp = 0x30, - .mac_addr1_otp = 0x34, - .mac_addr0_strap = 0x38, - .mac_addr1_strap = 0x3C -}; +extern const struct iwl_csr_params iwl_csr_v1; +extern const struct iwl_csr_params iwl_csr_v2; /* * This list declares the config structures for all devices. @@ -553,38 +525,54 @@ extern const struct iwl_cfg iwl8275_2ac_cfg; extern const struct iwl_cfg iwl4165_2ac_cfg; extern const struct iwl_cfg iwl9160_2ac_cfg; extern const struct iwl_cfg iwl9260_2ac_cfg; +extern const struct iwl_cfg iwl9260_2ac_160_cfg; extern const struct iwl_cfg iwl9260_killer_2ac_cfg; extern const struct iwl_cfg iwl9270_2ac_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg; +extern const struct iwl_cfg iwl9560_2ac_160_cfg; extern const struct iwl_cfg iwl9460_2ac_cfg_soc; extern const struct iwl_cfg iwl9461_2ac_cfg_soc; extern const struct iwl_cfg iwl9462_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; +extern const struct iwl_cfg iwl9560_2ac_160_cfg_soc; extern const struct iwl_cfg iwl9560_killer_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_soc; extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_2ac_160_cfg_shared_clk; extern const struct iwl_cfg iwl9560_killer_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl9560_killer_s_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl22000_2ac_cfg_hr; extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwl22000_2ac_cfg_jf; +extern const struct iwl_cfg iwl_ax101_cfg_qu_hr; +extern const struct iwl_cfg iwl_ax101_cfg_quz_hr; extern const struct iwl_cfg iwl22000_2ax_cfg_hr; +extern const struct iwl_cfg iwl_ax200_cfg_cc; +extern const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0; +extern const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0; +extern const struct iwl_cfg killer1650x_2ax_cfg; +extern const struct iwl_cfg killer1650w_2ax_cfg; extern const struct iwl_cfg iwl9461_2ac_cfg_qu_b0_jf_b0; extern const struct iwl_cfg iwl9462_2ac_cfg_qu_b0_jf_b0; extern const struct iwl_cfg iwl9560_2ac_cfg_qu_b0_jf_b0; +extern const struct iwl_cfg iwl9560_2ac_160_cfg_qu_b0_jf_b0; extern const struct iwl_cfg killer1550i_2ac_cfg_qu_b0_jf_b0; extern const struct iwl_cfg killer1550s_2ac_cfg_qu_b0_jf_b0; extern const struct iwl_cfg iwl22000_2ax_cfg_jf; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0_f0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0_f0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0; -extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_jf_b0; +extern const struct iwl_cfg iwl9560_2ac_cfg_qnj_jf_b0; extern const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_a0; extern const struct iwl_cfg iwl22560_2ax_cfg_su_cdb; +extern const struct iwl_cfg iwlax210_2ax_cfg_so_jf_a0; +extern const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0; +extern const struct iwl_cfg iwlax210_2ax_cfg_so_gf_a0; +extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0; #endif /* CPTCFG_IWLMVM || CPTCFG_IWLFMAC */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index caa5806acd81..e539bc94eff7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -180,6 +180,7 @@ /* Bits for CSR_HW_IF_CONFIG_REG */ #define CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH (0x00000003) #define CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP (0x0000000C) +#define CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM (0x00000080) #define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x000000C0) #define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) #define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) @@ -325,12 +326,17 @@ enum { #define CSR_HW_REV_TYPE_7265D (0x0000210) #define CSR_HW_REV_TYPE_NONE (0x00001F0) #define CSR_HW_REV_TYPE_QNJ (0x0000360) +#define CSR_HW_REV_TYPE_QNJ_B0 (0x0000364) +#define CSR_HW_REV_TYPE_QUZ (0x0000354) #define CSR_HW_REV_TYPE_HR_CDB (0x0000340) +#define CSR_HW_REV_TYPE_SO (0x0000370) +#define CSR_HW_REV_TYPE_TY (0x0000420) /* RF_ID value */ #define CSR_HW_RF_ID_TYPE_JF (0x00105100) #define CSR_HW_RF_ID_TYPE_HR (0x0010A000) #define CSR_HW_RF_ID_TYPE_HRCDB (0x00109F00) +#define CSR_HW_RF_ID_TYPE_GF (0x0010D000) /* HW_RF CHIP ID */ #define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF) @@ -592,6 +598,7 @@ enum msix_hw_int_causes { MSIX_HW_INT_CAUSES_REG_ALIVE = BIT(0), MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1), MSIX_HW_INT_CAUSES_REG_IPC = BIT(1), + MSIX_HW_INT_CAUSES_REG_IML = BIT(2), MSIX_HW_INT_CAUSES_REG_SW_ERR_V2 = BIT(5), MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6), MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c new file mode 100644 index 000000000000..c7070760a10a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -0,0 +1,251 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright (C) 2018 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include <linux/firmware.h> +#include "iwl-trans.h" +#include "iwl-dbg-tlv.h" + +void iwl_fw_dbg_copy_tlv(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, + bool ext) +{ + struct iwl_apply_point_data *data; + struct iwl_fw_ini_header *header = (void *)&tlv->data[0]; + u32 apply_point = le32_to_cpu(header->apply_point); + + int copy_size = le32_to_cpu(tlv->length) + sizeof(*tlv); + int offset_size = copy_size; + + if (WARN_ONCE(apply_point >= IWL_FW_INI_APPLY_NUM, + "Invalid apply point id %d\n", apply_point)) + return; + + if (ext) + data = &trans->apply_points_ext[apply_point]; + else + data = &trans->apply_points[apply_point]; + + /* add room for is_alloc field in &iwl_fw_ini_allocation_data struct */ + if (le32_to_cpu(tlv->type) == IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) { + struct iwl_fw_ini_allocation_data *buf_alloc = + (void *)tlv->data; + + offset_size += sizeof(buf_alloc->is_alloc); + } + + /* + * Make sure we still have room to copy this TLV. Offset points to the + * location the last copy ended. + */ + if (WARN_ONCE(data->offset + offset_size > data->size, + "Not enough memory for apply point %d\n", + apply_point)) + return; + + memcpy(data->data + data->offset, (void *)tlv, copy_size); + data->offset += offset_size; +} + +void iwl_alloc_dbg_tlv(struct iwl_trans *trans, size_t len, const u8 *data, + bool ext) +{ + struct iwl_ucode_tlv *tlv; + u32 size[IWL_FW_INI_APPLY_NUM] = {0}; + int i; + + while (len >= sizeof(*tlv)) { + u32 tlv_len, tlv_type, apply; + struct iwl_fw_ini_header *hdr; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) + return; + + len -= ALIGN(tlv_len, 4); + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + + if (tlv_type < IWL_UCODE_TLV_DEBUG_BASE || + tlv_type > IWL_UCODE_TLV_DEBUG_MAX) + continue; + + hdr = (void *)&tlv->data[0]; + apply = le32_to_cpu(hdr->apply_point); + + IWL_DEBUG_FW(trans, "Read TLV %x, apply point %d\n", + le32_to_cpu(tlv->type), apply); + + if (WARN_ON(apply >= IWL_FW_INI_APPLY_NUM)) + continue; + + /* add room for is_alloc field in &iwl_fw_ini_allocation_data + * struct + */ + if (tlv_type == IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) { + struct iwl_fw_ini_allocation_data *buf_alloc = + (void *)tlv->data; + + size[apply] += sizeof(buf_alloc->is_alloc); + } + + size[apply] += sizeof(*tlv) + tlv_len; + } + + for (i = 0; i < ARRAY_SIZE(size); i++) { + void *mem; + + if (!size[i]) + continue; + + mem = kzalloc(size[i], GFP_KERNEL); + + if (!mem) { + IWL_ERR(trans, "No memory for apply point %d\n", i); + return; + } + + if (ext) { + trans->apply_points_ext[i].data = mem; + trans->apply_points_ext[i].size = size[i]; + } else { + trans->apply_points[i].data = mem; + trans->apply_points[i].size = size[i]; + } + + trans->ini_valid = true; + } +} + +void iwl_fw_dbg_free(struct iwl_trans *trans) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(trans->apply_points); i++) { + kfree(trans->apply_points[i].data); + trans->apply_points[i].size = 0; + trans->apply_points[i].offset = 0; + + kfree(trans->apply_points_ext[i].data); + trans->apply_points_ext[i].size = 0; + trans->apply_points_ext[i].offset = 0; + } +} + +static int iwl_parse_fw_dbg_tlv(struct iwl_trans *trans, const u8 *data, + size_t len) +{ + struct iwl_ucode_tlv *tlv; + enum iwl_ucode_tlv_type tlv_type; + u32 tlv_len; + + while (len >= sizeof(*tlv)) { + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) { + IWL_ERR(trans, "invalid TLV len: %zd/%u\n", + len, tlv_len); + return -EINVAL; + } + len -= ALIGN(tlv_len, 4); + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + + switch (tlv_type) { + case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: + case IWL_UCODE_TLV_TYPE_HCMD: + case IWL_UCODE_TLV_TYPE_REGIONS: + case IWL_UCODE_TLV_TYPE_TRIGGERS: + case IWL_UCODE_TLV_TYPE_DEBUG_FLOW: + iwl_fw_dbg_copy_tlv(trans, tlv, true); + break; + default: + WARN_ONCE(1, "Invalid TLV %x\n", tlv_type); + break; + } + } + + return 0; +} + +void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans) +{ + const struct firmware *fw; + int res; + + if (trans->external_ini_loaded || !iwlwifi_mod_params.enable_ini) + return; + + res = request_firmware(&fw, "iwl-dbg-tlv.ini", dev); + if (res) + return; + + iwl_alloc_dbg_tlv(trans, fw->size, fw->data, true); + iwl_parse_fw_dbg_tlv(trans, fw->data, fw->size); + + trans->external_ini_loaded = true; + release_firmware(fw); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 8138d0606c52..222cd789e07a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -16,16 +16,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. + * * The full GNU General Public License is included in this distribution * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE * - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,35 +58,30 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifndef __tof_h__ -#define __tof_h__ +#ifndef __iwl_dbg_tlv_h__ +#define __iwl_dbg_tlv_h__ -#include "fw/api/tof.h" +#include <linux/device.h> +#include <linux/types.h> -struct iwl_mvm_tof_data { - struct iwl_tof_config_cmd tof_cfg; - struct iwl_tof_range_req_cmd range_req; - struct iwl_tof_range_req_ext_cmd range_req_ext; -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct iwl_tof_responder_config_cmd responder_cfg; -#endif - struct iwl_tof_range_rsp_ntfy range_resp; - u8 last_abort_id; - u16 active_range_request; +/** + * struct iwl_apply_point_data + * @data: start address of this apply point data + * @size total size of the data + * @offset: current offset of the copied data + */ +struct iwl_apply_point_data { + void *data; + int size; + int offset; }; -void iwl_mvm_tof_init(struct iwl_mvm *mvm); -void iwl_mvm_tof_clean(struct iwl_mvm *mvm); -int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm); -int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id); -int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); -void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb); -int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); -#endif -#endif /* __tof_h__ */ +struct iwl_trans; +void iwl_load_fw_dbg_tlv(struct device *dev, struct iwl_trans *trans); +void iwl_fw_dbg_free(struct iwl_trans *trans); +void iwl_fw_dbg_copy_tlv(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, + bool ext); +void iwl_alloc_dbg_tlv(struct iwl_trans *trans, size_t len, const u8 *data, + bool ext); + +#endif /* __iwl_dbg_tlv_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h index a2af68a0d34b..655ff5694560 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-debug.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Intel Corporation * * Portions of this file are derived from the ipw3945 project. * @@ -159,7 +160,7 @@ do { \ /* 0x000F0000 - 0x00010000 */ #define IWL_DL_FW 0x00010000 #define IWL_DL_RF_KILL 0x00020000 -#define IWL_DL_FW_ERRORS 0x00040000 +#define IWL_DL_TPT 0x00040000 /* 0x00F00000 - 0x00100000 */ #define IWL_DL_RATE 0x00100000 #define IWL_DL_CALIB 0x00200000 @@ -193,7 +194,6 @@ do { \ #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) #define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a) -#define IWL_DEBUG_FW_ERRORS(p, f, a...) IWL_DEBUG(p, IWL_DL_FW_ERRORS, f, ## a) #define IWL_DEBUG_DROP(p, f, a...) IWL_DEBUG(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_DROP_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) @@ -215,6 +215,7 @@ do { \ #define IWL_DEBUG_DEV_RADIO(p, f, a...) IWL_DEBUG_DEV(p, IWL_DL_RADIO, f, ## a) #define IWL_DEBUG_POWER(p, f, a...) IWL_DEBUG(p, IWL_DL_POWER, f, ## a) #define IWL_DEBUG_11H(p, f, a...) IWL_DEBUG(p, IWL_DL_11H, f, ## a) +#define IWL_DEBUG_TPT(p, f, a...) IWL_DEBUG(p, IWL_DL_TPT, f, ## a) #define IWL_DEBUG_RPM(p, f, a...) IWL_DEBUG(p, IWL_DL_RPM, f, ## a) #define IWL_DEBUG_LAR(p, f, a...) IWL_DEBUG(p, IWL_DL_LAR, f, ## a) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ba41d23b4211..689a65b11cc3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,8 +74,10 @@ #include "iwl-op-mode.h" #include "iwl-agn-hw.h" #include "fw/img.h" +#include "iwl-dbg-tlv.h" #include "iwl-config.h" #include "iwl-modparams.h" +#include "fw/api/alive.h" /****************************************************************************** * @@ -209,18 +213,15 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) { const struct iwl_cfg *cfg = drv->trans->cfg; char tag[8]; - const char *fw_pre_name; if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && - (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP || - CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_C_STEP)) - fw_pre_name = cfg->fw_name_pre_b_or_c_step; - else if (drv->trans->cfg->integrated && - CSR_HW_RFID_STEP(drv->trans->hw_rf_id) == SILICON_B_STEP && - cfg->fw_name_pre_rf_next_step) - fw_pre_name = cfg->fw_name_pre_rf_next_step; - else - fw_pre_name = cfg->fw_name_pre; + (CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_B_STEP && + CSR_HW_REV_STEP(drv->trans->hw_rev) != SILICON_C_STEP)) { + IWL_ERR(drv, + "Only HW steps B and C are currently supported (0x%0x)\n", + drv->trans->hw_rev); + return -EINVAL; + } if (first) { drv->fw_index = cfg->ucode_api_max; @@ -234,15 +235,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (cfg->ucode_api_min == cfg->ucode_api_max) { - IWL_ERR(drv, "%s%d is required\n", fw_pre_name, + IWL_ERR(drv, "%s%d is required\n", cfg->fw_name_pre, cfg->ucode_api_max); } else { IWL_ERR(drv, "minimum version required: %s%d\n", - fw_pre_name, - cfg->ucode_api_min); + cfg->fw_name_pre, cfg->ucode_api_min); IWL_ERR(drv, "maximum version supported: %s%d\n", - fw_pre_name, - cfg->ucode_api_max); + cfg->fw_name_pre, cfg->ucode_api_max); } IWL_ERR(drv, @@ -251,7 +250,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) } snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%s.ucode", - fw_pre_name, tag); + cfg->fw_name_pre, tag); IWL_DEBUG_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); @@ -592,6 +591,8 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, return 0; } +#define FW_ADDR_CACHE_CONTROL 0xC0000000 + static int iwl_parse_tlv_firmware(struct iwl_drv *drv, const struct firmware *ucode_raw, struct iwl_firmware_pieces *pieces, @@ -645,6 +646,9 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, len -= sizeof(*ucode); + if (iwlwifi_mod_params.enable_ini) + iwl_alloc_dbg_tlv(drv->trans, len, data, false); + while (len >= sizeof(*tlv)) { len -= sizeof(*tlv); tlv = (void *)data; @@ -1086,6 +1090,60 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -ENOMEM; break; } + case IWL_UCODE_TLV_FW_RECOVERY_INFO: { + struct { + __le32 buf_addr; + __le32 buf_size; + } *recov_info = (void *)tlv_data; + + if (tlv_len != sizeof(*recov_info)) + goto invalid_tlv_len; + capa->error_log_addr = + le32_to_cpu(recov_info->buf_addr); + capa->error_log_size = + le32_to_cpu(recov_info->buf_size); + } + break; + case IWL_UCODE_TLV_UMAC_DEBUG_ADDRS: { + struct iwl_umac_debug_addrs *dbg_ptrs = + (void *)tlv_data; + + if (tlv_len != sizeof(*dbg_ptrs)) + goto invalid_tlv_len; + if (drv->trans->cfg->device_family < + IWL_DEVICE_FAMILY_22000) + break; + drv->trans->umac_error_event_table = + le32_to_cpu(dbg_ptrs->error_info_addr) & + ~FW_ADDR_CACHE_CONTROL; + drv->trans->error_event_table_tlv_status |= + IWL_ERROR_EVENT_TABLE_UMAC; + break; + } + case IWL_UCODE_TLV_LMAC_DEBUG_ADDRS: { + struct iwl_lmac_debug_addrs *dbg_ptrs = + (void *)tlv_data; + + if (tlv_len != sizeof(*dbg_ptrs)) + goto invalid_tlv_len; + if (drv->trans->cfg->device_family < + IWL_DEVICE_FAMILY_22000) + break; + drv->trans->lmac_error_event_table[0] = + le32_to_cpu(dbg_ptrs->error_event_table_ptr) & + ~FW_ADDR_CACHE_CONTROL; + drv->trans->error_event_table_tlv_status |= + IWL_ERROR_EVENT_TABLE_LMAC1; + break; + } + case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: + case IWL_UCODE_TLV_TYPE_HCMD: + case IWL_UCODE_TLV_TYPE_REGIONS: + case IWL_UCODE_TLV_TYPE_TRIGGERS: + case IWL_UCODE_TLV_TYPE_DEBUG_FLOW: + if (iwlwifi_mod_params.enable_ini) + iwl_fw_dbg_copy_tlv(drv->trans, tlv, false); + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -1195,11 +1253,6 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) #ifdef CONFIG_IWLWIFI_DEBUGFS drv->dbgfs_op_mode = debugfs_create_dir(op->name, drv->dbgfs_drv); - if (!drv->dbgfs_op_mode) { - IWL_ERR(drv, - "failed to create opmode debugfs directory\n"); - return op_mode; - } dbgfs_dir = drv->dbgfs_op_mode; #endif @@ -1255,8 +1308,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) fw->ucode_capa.standard_phy_calibration_size = IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE; fw->ucode_capa.n_scan_channels = IWL_DEFAULT_SCAN_CHANNELS; - /* dump all fw memory areas by default except d3 debug data */ - fw->dbg.dump_mask = 0xfffdffff; + /* dump all fw memory areas by default */ + fw->dbg.dump_mask = 0xffffffff; pieces = kzalloc(sizeof(*pieces), GFP_KERNEL); if (!pieces) @@ -1562,20 +1615,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), iwl_dbgfs_root); - if (!drv->dbgfs_drv) { - IWL_ERR(drv, "failed to create debugfs directory\n"); - ret = -ENOMEM; - goto err_free_drv; - } - /* Create transport layer debugfs dir */ drv->trans->dbgfs_dir = debugfs_create_dir("trans", drv->dbgfs_drv); - - if (!drv->trans->dbgfs_dir) { - IWL_ERR(drv, "failed to create transport debugfs directory\n"); - ret = -ENOMEM; - goto err_free_dbgfs; - } #endif ret = iwl_request_firmware(drv, true); @@ -1588,9 +1629,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) err_fw: #ifdef CONFIG_IWLWIFI_DEBUGFS -err_free_dbgfs: debugfs_remove_recursive(drv->dbgfs_drv); -err_free_drv: + iwl_fw_dbg_free(drv->trans); #endif kfree(drv); err: @@ -1616,9 +1656,13 @@ void iwl_drv_stop(struct iwl_drv *drv) mutex_unlock(&iwlwifi_opmode_table_mtx); #ifdef CONFIG_IWLWIFI_DEBUGFS + drv->trans->ops->debugfs_cleanup(drv->trans); + debugfs_remove_recursive(drv->dbgfs_drv); #endif + iwl_fw_dbg_free(drv->trans); + kfree(drv); } @@ -1696,9 +1740,6 @@ static int __init iwl_drv_init(void) #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the root of iwlwifi debugfs subsystem. */ iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL); - - if (!iwl_dbgfs_root) - return -EFAULT; #endif return iwl_pci_register_driver(); @@ -1749,6 +1790,10 @@ MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)"); module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, uint, 0644); MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3)"); +module_param_named(enable_ini, iwlwifi_mod_params.enable_ini, + bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_ini, + "Enable debug INI TLV FW debug infrastructure (default: 0"); /* * set bt_coex_active to true, uCode will do kill/defer diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c index 4e3422a1c7bb..04338c3a6205 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -850,8 +850,7 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, if (WARN_ON(!cfg || !cfg->eeprom_params)) return NULL; - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, + data = kzalloc(struct_size(data, channels, IWL_NUM_CHANNELS), GFP_KERNEL); if (!data) return NULL; @@ -927,22 +926,3 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, return NULL; } IWL_EXPORT_SYMBOL(iwl_parse_eeprom_data); - -/* helper functions */ -int iwl_nvm_check_version(struct iwl_nvm_data *data, - struct iwl_trans *trans) -{ - if (data->nvm_version >= trans->cfg->nvm_ver || - data->calib_version >= trans->cfg->nvm_calib_ver) { - IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n", - data->nvm_version, data->calib_version); - return 0; - } - - IWL_ERR(trans, - "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - data->nvm_version, trans->cfg->nvm_ver, - data->calib_version, trans->cfg->nvm_calib_ver); - return -EINVAL; -} -IWL_EXPORT_SYMBOL(iwl_nvm_check_version); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h index d910bda087f7..2375d300a7cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.h @@ -7,6 +7,7 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -117,9 +119,6 @@ struct iwl_nvm_data * iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg, const u8 *eeprom, size_t eeprom_size); -int iwl_nvm_check_version(struct iwl_nvm_data *data, - struct iwl_trans *trans); - int iwl_init_sband_channels(struct iwl_nvm_data *data, struct ieee80211_supported_band *sband, int n_channels, enum nl80211_band band); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c index a6db6a814257..82e87192119e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-read.c @@ -193,34 +193,25 @@ static int iwl_init_otp_access(struct iwl_trans *trans) { int ret; - /* Enable 40MHz radio clock */ - iwl_write32(trans, CSR_GP_CNTRL, - iwl_read32(trans, CSR_GP_CNTRL) | - BIT(trans->cfg->csr->flag_init_done)); - - /* wait for clock to be ready */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (ret < 0) { - IWL_ERR(trans, "Time out access OTP\n"); - } else { - iwl_set_bits_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - udelay(5); - iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); - - /* - * CSR auto clock gate disable bit - - * this is only applicable for HW with OTP shadow RAM - */ - if (trans->cfg->base_params->shadow_ram_support) - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); - } - return ret; + ret = iwl_finish_nic_init(trans); + if (ret) + return ret; + + iwl_set_bits_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + udelay(5); + iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); + + /* + * CSR auto clock gate disable bit - + * this is only applicable for HW with OTP shadow RAM + */ + if (trans->cfg->base_params->shadow_ram_support) + iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + + return 0; } static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 4f10914f6048..a704e25af810 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -1,9 +1,13 @@ /****************************************************************************** * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * - * Portions of this file are derived from the ipw3945 project. + * Copyright(C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -15,12 +19,45 @@ * more details. * * The full GNU General Public License is included in this distribution in the - * file called LICENSE. + * file called COPYING. * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * + * BSD LICENSE + * + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright (C) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * *****************************************************************************/ #include <linux/delay.h> #include <linux/device.h> @@ -33,6 +70,36 @@ #include "iwl-prph.h" #include "iwl-fh.h" +const struct iwl_csr_params iwl_csr_v1 = { + .flag_mac_clock_ready = 0, + .flag_val_mac_access_en = 0, + .flag_init_done = 2, + .flag_mac_access_req = 3, + .flag_sw_reset = 7, + .flag_master_dis = 8, + .flag_stop_master = 9, + .addr_sw_reset = CSR_BASE + 0x020, + .mac_addr0_otp = 0x380, + .mac_addr1_otp = 0x384, + .mac_addr0_strap = 0x388, + .mac_addr1_strap = 0x38C +}; + +const struct iwl_csr_params iwl_csr_v2 = { + .flag_init_done = 6, + .flag_mac_clock_ready = 20, + .flag_val_mac_access_en = 20, + .flag_mac_access_req = 21, + .flag_master_dis = 28, + .flag_stop_master = 29, + .flag_sw_reset = 31, + .addr_sw_reset = CSR_BASE + 0x024, + .mac_addr0_otp = 0x30, + .mac_addr1_otp = 0x34, + .mac_addr0_strap = 0x38, + .mac_addr1_strap = 0x3C +}; + void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) { trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); @@ -240,9 +307,12 @@ void iwl_force_nmi(struct iwl_trans *trans) if (trans->cfg->device_family < IWL_DEVICE_FAMILY_9000) iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); + else if (trans->cfg->device_family < IWL_DEVICE_FAMILY_AX210) + iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, + UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER_MSK); else - iwl_write_prph(trans, UREG_NIC_SET_NMI_DRIVER, - UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER_MSK); + iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_NMI_BIT); } IWL_EXPORT_SYMBOL(iwl_force_nmi); @@ -421,3 +491,43 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) return 0; } + +int iwl_finish_nic_init(struct iwl_trans *trans) +{ + int err; + + if (trans->cfg->bisr_workaround) { + /* ensure the TOP FSM isn't still in previous reset */ + mdelay(2); + } + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + iwl_set_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_init_done)); + + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + udelay(2); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + err = iwl_poll_bit(trans, CSR_GP_CNTRL, + BIT(trans->cfg->csr->flag_mac_clock_ready), + BIT(trans->cfg->csr->flag_mac_clock_ready), + 25000); + if (err < 0) + IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); + + if (trans->cfg->bisr_workaround) { + /* ensure BISR shift has finished */ + udelay(200); + } + + return err < 0 ? err : 0; +} +IWL_EXPORT_SYMBOL(iwl_finish_nic_init); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index 38085850a2d3..920e2146ea3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -1,8 +1,11 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. * - * Portions of this file are derived from the ipw3945 project. + * GPL LICENSE SUMMARY + * + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -14,14 +17,44 @@ * more details. * * The full GNU General Public License is included in this distribution in the - * file called LICENSE. + * file called COPYING. * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * + * BSD LICENSE + * + * Copyright (C) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * *****************************************************************************/ - #ifndef __iwl_io_h__ #define __iwl_io_h__ @@ -66,7 +99,48 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); void iwl_force_nmi(struct iwl_trans *trans); +int iwl_finish_nic_init(struct iwl_trans *trans); + /* Error handling */ int iwl_dump_fh(struct iwl_trans *trans, char **buf); +/* + * UMAC periphery address space changed from 0xA00000 to 0xD00000 starting from + * device family AX200. So peripheries used in families above and below AX200 + * should go through iwl_..._umac_..._prph. + */ +static inline u32 iwl_umac_prph(struct iwl_trans *trans, u32 ofs) +{ + return ofs + trans->cfg->umac_prph_offset; +} + +static inline u32 iwl_read_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs) +{ + return iwl_read_prph_no_grab(trans, ofs + trans->cfg->umac_prph_offset); +} + +static inline u32 iwl_read_umac_prph(struct iwl_trans *trans, u32 ofs) +{ + return iwl_read_prph(trans, ofs + trans->cfg->umac_prph_offset); +} + +static inline void iwl_write_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs, + u32 val) +{ + iwl_write_prph_no_grab(trans, ofs + trans->cfg->umac_prph_offset, val); +} + +static inline void iwl_write_umac_prph(struct iwl_trans *trans, u32 ofs, + u32 val) +{ + iwl_write_prph(trans, ofs + trans->cfg->umac_prph_offset, val); +} + +static inline int iwl_poll_umac_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + return iwl_poll_prph_bit(trans, addr + trans->cfg->umac_prph_offset, + bits, mask, timeout); +} + #endif diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index 6fc8dac4aab7..0cae2ef9b9df 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -122,6 +122,7 @@ enum iwl_uapsd_disable { * @fw_monitor: allow to use firmware monitor * @disable_11ac: disable VHT capabilities, default = false. * @remove_when_gone: remove an inaccessible device from the PCIe bus. + * @enable_ini: enable new FW debug infratructure (INI TLVs) */ struct iwl_mod_params { int swcrypto; @@ -148,6 +149,25 @@ struct iwl_mod_params { */ bool disable_11ax; bool remove_when_gone; + bool enable_ini; }; +static inline bool iwl_enable_rx_ampdu(void) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) + return false; + return true; +} + +static inline bool iwl_enable_tx_ampdu(void) +{ + if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) + return false; + if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) + return true; + + /* enabled by default */ + return true; +} + #endif /* #__iwl_modparams_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 96e101d79662..87d6de7efdd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -8,7 +8,7 @@ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -463,103 +463,173 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, } vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; + + vht_cap->vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } -static struct ieee80211_sband_iftype_data iwl_he_capa = { - .types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP), - .he_cap = { - .has_he = true, - .he_cap_elem = { - .mac_cap_info[0] = - IEEE80211_HE_MAC_CAP0_HTC_HE | - IEEE80211_HE_MAC_CAP0_TWT_REQ, - .mac_cap_info[1] = - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, - .mac_cap_info[2] = - IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | - IEEE80211_HE_MAC_CAP2_MU_CASCADING | - IEEE80211_HE_MAC_CAP2_ACK_EN, - .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, - .mac_cap_info[4] = - IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | - IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, - .mac_cap_info[5] = - IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | - IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | - IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, - .phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, - .phy_cap_info[1] = - IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | - IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS, - .phy_cap_info[2] = - IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | - IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | - IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO, - .phy_cap_info[3] = - IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK | - IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | - IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK | - IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, - .phy_cap_info[4] = - IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, - .phy_cap_info[5] = - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | - IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK, - .phy_cap_info[6] = - IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | - IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | - IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | - IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | - IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | - IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO | - IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, - .phy_cap_info[7] = - IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1, - .phy_cap_info[8] = - IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_DCM_MAX_BW_160_OR_80P80_MHZ, - .phy_cap_info[9] = - IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB, +static struct ieee80211_sband_iftype_data iwl_he_capa[] = { + { + .types_mask = BIT(NL80211_IFTYPE_STATION), + .he_cap = { + .has_he = true, + .he_cap_elem = { + .mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE | + IEEE80211_HE_MAC_CAP0_TWT_REQ, + .mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, + .mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP | + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | + IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | + IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS | + IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, + .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + .phy_cap_info[3] = + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, + .phy_cap_info[4] = + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, + .phy_cap_info[5] = + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, + .phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP7_MAX_NC_1, + .phy_cap_info[8] = + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, + }, + /* + * Set default Tx/Rx HE MCS NSS Support field. + * Indicate support for up to 2 spatial streams and all + * MCS, without any special cases + */ + .he_mcs_nss_supp = { + .rx_mcs_80 = cpu_to_le16(0xfffa), + .tx_mcs_80 = cpu_to_le16(0xfffa), + .rx_mcs_160 = cpu_to_le16(0xfffa), + .tx_mcs_160 = cpu_to_le16(0xfffa), + .rx_mcs_80p80 = cpu_to_le16(0xffff), + .tx_mcs_80p80 = cpu_to_le16(0xffff), + }, + /* + * Set default PPE thresholds, with PPET16 set to 0, + * PPET8 set to 7 + */ + .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, }, - /* - * Set default Tx/Rx HE MCS NSS Support field. Indicate support - * for up to 2 spatial streams and all MCS, without any special - * cases - */ - .he_mcs_nss_supp = { - .rx_mcs_80 = cpu_to_le16(0xfffa), - .tx_mcs_80 = cpu_to_le16(0xfffa), - .rx_mcs_160 = cpu_to_le16(0xfffa), - .tx_mcs_160 = cpu_to_le16(0xfffa), - .rx_mcs_80p80 = cpu_to_le16(0xffff), - .tx_mcs_80p80 = cpu_to_le16(0xffff), + }, + { + .types_mask = BIT(NL80211_IFTYPE_AP), + .he_cap = { + .has_he = true, + .he_cap_elem = { + .mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE, + .mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, + .mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_BSR | + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, + .phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, + .phy_cap_info[3] = + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, + .phy_cap_info[4] = + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, + .phy_cap_info[5] = + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, + .phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP7_MAX_NC_1, + .phy_cap_info[8] = + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, + }, + /* + * Set default Tx/Rx HE MCS NSS Support field. + * Indicate support for up to 2 spatial streams and all + * MCS, without any special cases + */ + .he_mcs_nss_supp = { + .rx_mcs_80 = cpu_to_le16(0xfffa), + .tx_mcs_80 = cpu_to_le16(0xfffa), + .rx_mcs_160 = cpu_to_le16(0xfffa), + .tx_mcs_160 = cpu_to_le16(0xfffa), + .rx_mcs_80p80 = cpu_to_le16(0xffff), + .tx_mcs_80p80 = cpu_to_le16(0xffff), + }, + /* + * Set default PPE thresholds, with PPET16 set to 0, + * PPET8 set to 7 + */ + .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, }, - /* - * Set default PPE thresholds, with PPET16 set to 0, PPET8 set - * to 7 - */ - .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, }, }; @@ -568,20 +638,24 @@ static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband, { if (sband->band == NL80211_BAND_2GHZ || sband->band == NL80211_BAND_5GHZ) - sband->iftype_data = &iwl_he_capa; + sband->iftype_data = iwl_he_capa; else return; - sband->n_iftype_data = 1; + sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa); /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ if ((tx_chains & rx_chains) != ANT_AB) { - iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &= - ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; - iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &= - ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; - iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[7] &= - ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; + int i; + + for (i = 0; i < sband->n_iftype_data; i++) { + iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[1] &= + ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; + iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[2] &= + ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; + iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[7] &= + ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; + } } } @@ -859,15 +933,13 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const __le16 *ch_section; if (cfg->nvm_type != IWL_NVM_EXT) - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * - IWL_NVM_NUM_CHANNELS, - GFP_KERNEL); + data = kzalloc(struct_size(data, channels, + IWL_NVM_NUM_CHANNELS), + GFP_KERNEL); else - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * - IWL_NVM_NUM_CHANNELS_EXT, - GFP_KERNEL); + data = kzalloc(struct_size(data, channels, + IWL_NVM_NUM_CHANNELS_EXT), + GFP_KERNEL); if (!data) return NULL; @@ -1015,12 +1087,12 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int max_num_ch = cfg->nvm_type == IWL_NVM_EXT ? IWL_NVM_NUM_CHANNELS_EXT : IWL_NVM_NUM_CHANNELS; - if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) - return ERR_PTR(-EINVAL); - if (WARN_ON(num_of_ch > max_num_ch)) num_of_ch = max_num_ch; + if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) + return ERR_PTR(-EINVAL); + IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", num_of_ch); @@ -1108,14 +1180,12 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, regd_to_copy = sizeof(struct ieee80211_regdomain) + valid_rules * sizeof(struct ieee80211_reg_rule); - copy_rd = kzalloc(regd_to_copy, GFP_KERNEL); + copy_rd = kmemdup(regd, regd_to_copy, GFP_KERNEL); if (!copy_rd) { copy_rd = ERR_PTR(-ENOMEM); goto out; } - memcpy(copy_rd, regd, regd_to_copy); - out: kfree(regdb_ptrs); kfree(regd); @@ -1356,9 +1426,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, if (empty_otp) IWL_INFO(trans, "OTP is empty\n"); - nvm = kzalloc(sizeof(*nvm) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, - GFP_KERNEL); + nvm = kzalloc(struct_size(nvm, channels, IWL_NUM_CHANNELS), GFP_KERNEL); if (!nvm) { ret = -ENOMEM; goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 0f51c7bea8d0..1af9f9e1ecd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -8,6 +8,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH + * Copyright (C) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -356,10 +358,16 @@ /* FW monitor */ #define MON_BUFF_SAMPLE_CTL (0xa03c00) -#define MON_BUFF_BASE_ADDR (0xa03c3c) +#define MON_BUFF_BASE_ADDR (0xa03c1c) #define MON_BUFF_END_ADDR (0xa03c40) #define MON_BUFF_WRPTR (0xa03c44) #define MON_BUFF_CYCLE_CNT (0xa03c48) +/* FW monitor family 8000 and on */ +#define MON_BUFF_BASE_ADDR_VER2 (0xa03c1c) +#define MON_BUFF_END_ADDR_VER2 (0xa03c20) +#define MON_BUFF_WRPTR_VER2 (0xa03c24) +#define MON_BUFF_CYCLE_CNT_VER2 (0xa03c28) +#define MON_BUFF_SHIFT_VER2 (0x8) #define MON_DMARB_RD_CTL_ADDR (0xa03c60) #define MON_DMARB_RD_DATA_ADDR (0xa03c5c) @@ -394,6 +402,7 @@ enum aux_misc_master1_en { #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define RSA_ENABLE 0xA24B08 #define PREG_AUX_BUS_WPROT_0 0xA04CC0 +#define PREG_PRPH_WPROT_0 0xA04CE0 #define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_2_STATUS 0xA01E34 #define UMAG_SB_CPU_1_STATUS 0xA038C0 @@ -420,4 +429,11 @@ enum { #define UREG_CHICK (0xA05C00) #define UREG_CHICK_MSI_ENABLE BIT(24) #define UREG_CHICK_MSIX_ENABLE BIT(25) + +#define HPM_DEBUG 0xA03440 +#define PERSISTENCE_BIT BIT(12) +#define PREG_WFPM_ACCESS BIT(12) + +#define UREG_DOORBELL_TO_ISR6 0xA05C04 +#define UREG_DOORBELL_TO_ISR6_NMI_BIT BIT(0) #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 26b3c73051ca..d8690acee40c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,6 +75,8 @@ #include "iwl-op-mode.h" #include "fw/api/cmdhdr.h" #include "fw/api/txq.h" +#include "fw/api/dbg-tlv.h" +#include "iwl-dbg-tlv.h" /** * DOC: Transport layer - what is it ? @@ -228,6 +232,12 @@ enum iwl_hcmd_dataflag { IWL_HCMD_DFL_DUP = BIT(1), }; +enum iwl_error_event_table_status { + IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0), + IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1), + IWL_ERROR_EVENT_TABLE_UMAC = BIT(2), +}; + /** * struct iwl_host_cmd - Host command to the uCode * @@ -534,6 +544,8 @@ struct iwl_trans_rxq_dma_data { * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last * TX'ed commands and similar. The buffer will be vfree'd by the caller. * Note that the transport must fill in the proper file headers. + * @debugfs_cleanup: used in the driver unload flow to make a proper cleanup + * of the trans debugfs */ struct iwl_trans_ops { @@ -602,8 +614,9 @@ struct iwl_trans_ops { void (*resume)(struct iwl_trans *trans); struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, - const struct iwl_fw_dbg_trigger_tlv - *trigger); + u32 dump_mask); + void (*debugfs_cleanup)(struct iwl_trans *trans); + void (*sync_nmi)(struct iwl_trans *trans); }; /** @@ -679,7 +692,9 @@ enum iwl_plat_pm_mode { * enter/exit (in msecs). */ #define IWL_TRANS_IDLE_TIMEOUT 2000 -#define IWL_MAX_DEBUG_ALLOCATIONS 1 + +/* Max time to wait for nmi interrupt */ +#define IWL_TRANS_NMI_TIMEOUT (HZ / 4) /** * struct iwl_dram_data @@ -694,6 +709,20 @@ struct iwl_dram_data { }; /** + * struct iwl_self_init_dram - dram data used by self init process + * @fw: lmac and umac dram data + * @fw_cnt: total number of items in array + * @paging: paging dram data + * @paging_cnt: total number of items in array + */ +struct iwl_self_init_dram { + struct iwl_dram_data *fw; + int fw_cnt; + struct iwl_dram_data *paging; + int paging_cnt; +}; + +/** * struct iwl_trans - transport common data * * @ops - pointer to iwl_trans_ops @@ -734,6 +763,11 @@ struct iwl_dram_data { * @runtime_pm_mode: the runtime power management mode in use. This * mode is set during the initialization phase and is not * supposed to change during runtime. + * @dbg_rec_on: true iff there is a fw debug recording currently active + * @lmac_error_event_table: addrs of lmacs error tables + * @umac_error_event_table: addr of umac error table + * @error_event_table_tlv_status: bitmap that indicates what error table + * pointers was recevied via TLV. use enum &iwl_error_event_table_status */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -774,17 +808,28 @@ struct iwl_trans { struct lockdep_map sync_cmd_lockdep_map; #endif + struct iwl_apply_point_data apply_points[IWL_FW_INI_APPLY_NUM]; + struct iwl_apply_point_data apply_points_ext[IWL_FW_INI_APPLY_NUM]; + + bool external_ini_loaded; + bool ini_valid; + const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv; const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX]; struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; - u32 dbg_dump_mask; u8 dbg_n_dest_reg; int num_blocks; - struct iwl_dram_data fw_mon[IWL_MAX_DEBUG_ALLOCATIONS]; + struct iwl_dram_data fw_mon[IWL_FW_INI_APPLY_NUM]; + struct iwl_self_init_dram init_dram; enum iwl_plat_pm_mode system_pm_mode; enum iwl_plat_pm_mode runtime_pm_mode; bool suspending; + bool dbg_rec_on; + + u32 lmac_error_event_table[2]; + u32 umac_error_event_table; + unsigned int error_event_table_tlv_status; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ @@ -897,12 +942,11 @@ static inline void iwl_trans_resume(struct iwl_trans *trans) } static inline struct iwl_trans_dump_data * -iwl_trans_dump_data(struct iwl_trans *trans, - const struct iwl_fw_dbg_trigger_tlv *trigger) +iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask) { if (!trans->ops->dump_data) return NULL; - return trans->ops->dump_data(trans, trigger); + return trans->ops->dump_data(trans, dump_mask); } static inline struct iwl_device_cmd * @@ -1195,6 +1239,12 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans) iwl_op_mode_nic_error(trans->op_mode); } +static inline void iwl_trans_sync_nmi(struct iwl_trans *trans) +{ + if (trans->ops->sync_nmi) + trans->ops->sync_nmi(trans); +} + /***************************************************** * transport helper functions *****************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 9ffd21918b5a..dd268c4bd371 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -5,9 +5,9 @@ iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o iwlmvm-y += scan.o time-event.o rs.o rs-fw.o iwlmvm-y += power.o coex.o iwlmvm-y += tt.o offloading.o tdls.o +iwlmvm-y += ftm-responder.o ftm-initiator.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o -iwlmvm-y += tof.o iwlmvm-$(CONFIG_PM) += d3.o -ccflags-y += -I$(src)/../ +ccflags-y += -I $(srctree)/$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 730e37744dc0..3d2abbc5c76c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -241,7 +241,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_bt_coex_reduced_txp_update_cmd cmd = {}; struct iwl_mvm_sta *mvmsta; u32 value; - int ret; mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) @@ -262,10 +261,8 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, cmd.reduced_txp = cpu_to_le32(value); mvmsta->bt_reduced_txpower = enable; - ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC, - sizeof(cmd), &cmd); - - return ret; + return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, + CMD_ASYNC, sizeof(cmd), &cmd); } struct iwl_bt_iterator_data { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index d96ada3c06fc..dff14f1ec55f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -8,6 +8,7 @@ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,6 +65,7 @@ #define __MVM_CONSTANTS_H #include <linux/ieee80211.h> +#include "fw-api.h" #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 @@ -114,6 +117,7 @@ #define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */ #define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */ #define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM +#define IWL_MVM_NON_TRANSMITTING_AP 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 @@ -145,5 +149,8 @@ #define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ #define IWL_MVM_RS_TPC_TX_POWER_STEP 3 #define IWL_MVM_ENABLE_EBS 1 +#define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE +#define IWL_MVM_FTM_INITIATOR_DYNACK true +#define IWL_MVM_D3_DEBUG false #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 843f3b41b72e..808bc6f363d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1811,8 +1811,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, n_matches = 0; } - net_detect = kzalloc(sizeof(*net_detect) + - (n_matches * sizeof(net_detect->matches[0])), + net_detect = kzalloc(struct_size(net_detect, matches, n_matches), GFP_KERNEL); if (!net_detect || !n_matches) goto out_report_nd; @@ -1827,8 +1826,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; j++) n_channels += hweight8(fw_match->matching_channels[j]); - match = kzalloc(sizeof(*match) + - (n_channels * sizeof(*match->channels)), + match = kzalloc(struct_size(match, channels, n_channels), GFP_KERNEL); if (!match) goto out_report_nd; @@ -1901,7 +1899,7 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - u32 base = mvm->error_event_table[0]; + u32 base = mvm->trans->lmac_error_event_table[0]; struct error_table_start { /* cf. struct iwl_error_event_table */ u32 valid; @@ -1956,7 +1954,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) set_bit(STATUS_FW_ERROR, &mvm->trans->status); iwl_mvm_dump_nic_error_log(mvm); iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, - NULL, 0); + false, 0); ret = 1; goto err; } @@ -2127,7 +2125,6 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) file->private_data = inode->i_private; - ieee80211_stop_queues(mvm->hw); synchronize_net(); mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; @@ -2142,10 +2139,9 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) rtnl_unlock(); if (err > 0) err = -EINVAL; - if (err) { - ieee80211_wake_queues(mvm->hw); + if (err) return err; - } + mvm->d3_test_active = true; mvm->keep_vif = NULL; return 0; @@ -2225,8 +2221,6 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); - ieee80211_wake_queues(mvm->hw); - return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 1aa6c7e93088..6925527d8457 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -60,7 +60,6 @@ * *****************************************************************************/ #include "mvm.h" -#include "fw/api/tof.h" #include "debugfs.h" static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, @@ -523,753 +522,30 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif, - char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 value; - int ret = -EINVAL; - char *data; - - mutex_lock(&mvm->mutex); - - data = iwl_dbgfs_is_match("tof_disabled=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.tof_cfg.tof_disabled = value; - goto out; - } - - data = iwl_dbgfs_is_match("one_sided_disabled=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.tof_cfg.one_sided_disabled = value; - goto out; - } - - data = iwl_dbgfs_is_match("is_debug_mode=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.tof_cfg.is_debug_mode = value; - goto out; - } - - data = iwl_dbgfs_is_match("is_buf=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.tof_cfg.is_buf_required = value; - goto out; - } - - data = iwl_dbgfs_is_match("send_tof_cfg=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) { - ret = iwl_mvm_tof_config_cmd(mvm); - goto out; - } - } - -out: - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_tof_enable_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - struct iwl_tof_config_cmd *cmd; - - cmd = &mvm->tof_data.tof_cfg; - - mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n", - cmd->tof_disabled); - pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n", - cmd->one_sided_disabled); - pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n", - cmd->is_debug_mode); - pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n", - cmd->is_buf_required); - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif, - char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 value; - int ret = 0; - char *data; - - mutex_lock(&mvm->mutex); - - data = iwl_dbgfs_is_match("burst_period=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (!ret) - mvm->tof_data.responder_cfg.burst_period = - cpu_to_le16(value); - goto out; - } - - data = iwl_dbgfs_is_match("min_delta_ftm=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.min_delta_ftm = value; - goto out; - } - - data = iwl_dbgfs_is_match("burst_duration=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.burst_duration = value; - goto out; - } - - data = iwl_dbgfs_is_match("num_of_burst_exp=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.num_of_burst_exp = value; - goto out; - } - - data = iwl_dbgfs_is_match("abort_responder=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.abort_responder = value; - goto out; - } - - data = iwl_dbgfs_is_match("get_ch_est=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.get_ch_est = value; - goto out; - } - - data = iwl_dbgfs_is_match("recv_sta_req_params=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.recv_sta_req_params = value; - goto out; - } - - data = iwl_dbgfs_is_match("channel_num=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.channel_num = value; - goto out; - } - - data = iwl_dbgfs_is_match("bandwidth=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.bandwidth = value; - goto out; - } - - data = iwl_dbgfs_is_match("rate=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.rate = value; - goto out; - } - - data = iwl_dbgfs_is_match("bssid=", buf); - if (data) { - u8 *mac = mvm->tof_data.responder_cfg.bssid; - - if (!mac_pton(data, mac)) { - ret = -EINVAL; - goto out; - } - } - - data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.tsf_timer_offset_msecs = - cpu_to_le16(value); - goto out; - } - - data = iwl_dbgfs_is_match("toa_offset=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.toa_offset = - cpu_to_le16(value); - goto out; - } - - data = iwl_dbgfs_is_match("center_freq=", buf); - if (data) { - struct iwl_tof_responder_config_cmd *cmd = - &mvm->tof_data.responder_cfg; - - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) { - enum nl80211_band band = (cmd->channel_num <= 14) ? - NL80211_BAND_2GHZ : - NL80211_BAND_5GHZ; - struct ieee80211_channel chn = { - .band = band, - .center_freq = ieee80211_channel_to_frequency( - cmd->channel_num, band), - }; - struct cfg80211_chan_def chandef = { - .chan = &chn, - .center_freq1 = - ieee80211_channel_to_frequency(value, - band), - }; - - cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef); - } - goto out; - } - - data = iwl_dbgfs_is_match("ftm_per_burst=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.ftm_per_burst = value; - goto out; - } - - data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; - goto out; - } - - data = iwl_dbgfs_is_match("asap_mode=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.responder_cfg.asap_mode = value; - goto out; - } - - data = iwl_dbgfs_is_match("send_responder_cfg=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) { - ret = iwl_mvm_tof_responder_cmd(mvm, vif); - goto out; - } - } - -out: - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - struct iwl_tof_responder_config_cmd *cmd; - - cmd = &mvm->tof_data.responder_cfg; - - mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", - le16_to_cpu(cmd->burst_period)); - pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", - cmd->burst_duration); - pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", - cmd->bandwidth); - pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", - cmd->channel_num); - pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", - cmd->ctrl_ch_position); - pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", - cmd->bssid); - pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", - cmd->min_delta_ftm); - pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", - cmd->num_of_burst_exp); - pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); - pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", - cmd->abort_responder); - pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", - cmd->get_ch_est); - pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", - cmd->recv_sta_req_params); - pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", - cmd->ftm_per_burst); - pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", - cmd->ftm_resp_ts_avail); - pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", - cmd->asap_mode); - pos += scnprintf(buf + pos, bufsz - pos, - "tsf_timer_offset_msecs = %d\n", - le16_to_cpu(cmd->tsf_timer_offset_msecs)); - pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", - le16_to_cpu(cmd->toa_offset)); - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 value; - int ret = 0; - char *data; - - mutex_lock(&mvm->mutex); - - data = iwl_dbgfs_is_match("request_id=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.request_id = value; - goto out; - } - - data = iwl_dbgfs_is_match("initiator=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.initiator = value; - goto out; - } - - data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.one_sided_los_disable = value; - goto out; - } - - data = iwl_dbgfs_is_match("req_timeout=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.req_timeout = value; - goto out; - } - - data = iwl_dbgfs_is_match("report_policy=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.report_policy = value; - goto out; - } - - data = iwl_dbgfs_is_match("macaddr_random=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.macaddr_random = value; - goto out; - } - - data = iwl_dbgfs_is_match("num_of_ap=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req.num_of_ap = value; - goto out; - } - - data = iwl_dbgfs_is_match("macaddr_template=", buf); - if (data) { - u8 mac[ETH_ALEN]; - - if (!mac_pton(data, mac)) { - ret = -EINVAL; - goto out; - } - memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); - goto out; - } - - data = iwl_dbgfs_is_match("macaddr_mask=", buf); - if (data) { - u8 mac[ETH_ALEN]; - - if (!mac_pton(data, mac)) { - ret = -EINVAL; - goto out; - } - memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); - goto out; - } - - data = iwl_dbgfs_is_match("ap=", buf); - if (data) { - struct iwl_tof_range_req_ap_entry ap = {}; - int size = sizeof(struct iwl_tof_range_req_ap_entry); - u16 burst_period; - u8 *mac = ap.bssid; - unsigned int i; - - if (sscanf(data, "%u %hhd %hhd %hhd" - "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" - "%hhd %hhd %hd" - "%hhd %hhd %d" - "%hhx %hhd %hhd %hhd", - &i, &ap.channel_num, &ap.bandwidth, - &ap.ctrl_ch_position, - mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, - &ap.measure_type, &ap.num_of_bursts, - &burst_period, - &ap.samples_per_burst, &ap.retries_per_sample, - &ap.tsf_delta, &ap.location_req, &ap.asap_mode, - &ap.enable_dyn_ack, &ap.rssi) != 20) { - ret = -EINVAL; - goto out; - } - if (i >= IWL_MVM_TOF_MAX_APS) { - IWL_ERR(mvm, "Invalid AP index %d\n", i); - ret = -EINVAL; - goto out; - } - - ap.burst_period = cpu_to_le16(burst_period); - - memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); - goto out; - } - - data = iwl_dbgfs_is_match("send_range_request=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) - ret = iwl_mvm_tof_range_request_cmd(mvm, vif); - goto out; - } - - ret = -EINVAL; -out: - mutex_unlock(&mvm->mutex); - return ret ?: count; -} - -static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - char buf[512]; - int pos = 0; - const size_t bufsz = sizeof(buf); - struct iwl_tof_range_req_cmd *cmd; - int i; - - cmd = &mvm->tof_data.range_req; - - mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", - cmd->request_id); - pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", - cmd->initiator); - pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", - cmd->one_sided_los_disable); - pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", - cmd->req_timeout); - pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", - cmd->report_policy); - pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", - cmd->macaddr_random); - pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", - cmd->macaddr_template); - pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", - cmd->macaddr_mask); - pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", - cmd->num_of_ap); - for (i = 0; i < cmd->num_of_ap; i++) { - struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; - - pos += scnprintf(buf + pos, bufsz - pos, - "ap %.2d: channel_num=%hhd bw=%hhd" - " control=%hhd bssid=%pM type=%hhd" - " num_of_bursts=%hhd burst_period=%hd ftm=%hhd" - " retries=%hhd tsf_delta=%d" - " tsf_delta_direction=%hhd location_req=0x%hhx " - " asap=%hhd enable=%hhd rssi=%hhd\n", - i, ap->channel_num, ap->bandwidth, - ap->ctrl_ch_position, ap->bssid, - ap->measure_type, ap->num_of_bursts, - ap->burst_period, ap->samples_per_burst, - ap->retries_per_sample, ap->tsf_delta, - ap->tsf_delta_direction, - ap->location_req, ap->asap_mode, - ap->enable_dyn_ack, ap->rssi); - } - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif, - char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 value; - int ret = 0; - char *data; - - mutex_lock(&mvm->mutex); - - data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req_ext.tsf_timer_offset_msec = - cpu_to_le16(value); - goto out; - } - - data = iwl_dbgfs_is_match("min_delta_ftm=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req_ext.min_delta_ftm = value; - goto out; - } - - data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req_ext.ftm_format_and_bw20M = - value; - goto out; - } - - data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req_ext.ftm_format_and_bw40M = - value; - goto out; - } - - data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.range_req_ext.ftm_format_and_bw80M = - value; - goto out; - } - - data = iwl_dbgfs_is_match("send_range_req_ext=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) - ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); - goto out; - } - - ret = -EINVAL; -out: - mutex_unlock(&mvm->mutex); - return ret ?: count; -} - -static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - struct iwl_tof_range_req_ext_cmd *cmd; - - cmd = &mvm->tof_data.range_req_ext; - - mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, - "tsf_timer_offset_msec = %hd\n", - cmd->tsf_timer_offset_msec); - pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n", - cmd->min_delta_ftm); - pos += scnprintf(buf + pos, bufsz - pos, - "ftm_format_and_bw20M = %hhd\n", - cmd->ftm_format_and_bw20M); - pos += scnprintf(buf + pos, bufsz - pos, - "ftm_format_and_bw40M = %hhd\n", - cmd->ftm_format_and_bw40M); - pos += scnprintf(buf + pos, bufsz - pos, - "ftm_format_and_bw80M = %hhd\n", - cmd->ftm_format_and_bw80M); - - mutex_unlock(&mvm->mutex); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif, - char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 value; - int abort_id, ret = 0; - char *data; - - mutex_lock(&mvm->mutex); - - data = iwl_dbgfs_is_match("abort_id=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0) - mvm->tof_data.last_abort_id = value; - goto out; - } - - data = iwl_dbgfs_is_match("send_range_abort=", buf); - if (data) { - ret = kstrtou32(data, 10, &value); - if (ret == 0 && value) { - abort_id = mvm->tof_data.last_abort_id; - ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); - goto out; - } - } - -out: - mutex_unlock(&mvm->mutex); - return ret ?: count; -} - -static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - char buf[32]; - int pos = 0; - const size_t bufsz = sizeof(buf); - int last_abort_id; - - mutex_lock(&mvm->mutex); - last_abort_id = mvm->tof_data.last_abort_id; - mutex_unlock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", - last_abort_id); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, + size_t count, loff_t *ppos) { - struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; - char *buf; - int pos = 0; - const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; - struct iwl_tof_range_rsp_ntfy *cmd; - int i, ret; + u8 value; + int ret; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; + ret = kstrtou8(buf, 0, &value); + if (ret) + return ret; + if (value > 1) + return -EINVAL; mutex_lock(&mvm->mutex); - cmd = &mvm->tof_data.range_resp; - - pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", - cmd->request_id); - pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", - cmd->request_status); - pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", - cmd->last_in_batch); - pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", - cmd->num_of_aps); - for (i = 0; i < cmd->num_of_aps; i++) { - struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; - - pos += scnprintf(buf + pos, bufsz - pos, - "ap %.2d: bssid=%pM status=%hhd bw=%hhd" - " rtt=%d rtt_var=%d rtt_spread=%d" - " rssi=%hhd rssi_spread=%hhd" - " range=%d range_var=%d" - " time_stamp=%d\n", - i, ap->bssid, ap->measure_status, - ap->measure_bw, - ap->rtt, ap->rtt_variance, ap->rtt_spread, - ap->rssi, ap->rssi_spread, ap->range, - ap->range_variance, ap->timestamp); - } + iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS); mutex_unlock(&mvm->mutex); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; + return count; } -static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, - size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, + size_t count, loff_t *ppos) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; @@ -1279,13 +555,24 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, ret = kstrtou8(buf, 0, &value); if (ret) return ret; - if (value > 1) + + if (value > NUM_LOW_LATENCY_FORCE) return -EINVAL; mutex_lock(&mvm->mutex); - iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS); + if (value == LOW_LATENCY_FORCE_UNSET) { + iwl_mvm_update_low_latency(mvm, vif, false, + LOW_LATENCY_DEBUGFS_FORCE); + iwl_mvm_update_low_latency(mvm, vif, false, + LOW_LATENCY_DEBUGFS_FORCE_ENABLE); + } else { + iwl_mvm_update_low_latency(mvm, vif, + value == LOW_LATENCY_FORCE_ON, + LOW_LATENCY_DEBUGFS_FORCE); + iwl_mvm_update_low_latency(mvm, vif, true, + LOW_LATENCY_DEBUGFS_FORCE_ENABLE); + } mutex_unlock(&mvm->mutex); - return count; } @@ -1295,14 +582,25 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, { struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - char buf[30] = {}; + char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n" + "dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n"; + + /* + * all values in format are boolean so the size of format is enough + * for holding the result string + */ + char buf[sizeof(format) + 1] = {}; int len; - len = scnprintf(buf, sizeof(buf) - 1, - "traffic=%d\ndbgfs=%d\nvcmd=%d\n", + len = scnprintf(buf, sizeof(buf) - 1, format, !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC), !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS), - !!(mvmvif->low_latency & LOW_LATENCY_VCMD)); + !!(mvmvif->low_latency & LOW_LATENCY_VCMD), + !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE), + !!(mvmvif->low_latency & + LOW_LATENCY_DEBUGFS_FORCE_ENABLE), + !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE), + !!(mvmvif->low_latency_actual)); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1440,15 +738,6 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static const char * const chanwidths[] = { - [NL80211_CHAN_WIDTH_20_NOHT] = "noht", - [NL80211_CHAN_WIDTH_20] = "ht20", - [NL80211_CHAN_WIDTH_40] = "ht40", - [NL80211_CHAN_WIDTH_80] = "vht80", - [NL80211_CHAN_WIDTH_80P80] = "vht80p80", - [NL80211_CHAN_WIDTH_160] = "vht160", -}; - #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -1464,14 +753,9 @@ MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); -MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); @@ -1490,8 +774,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); - - if (!mvmvif->dbgfs_dir) { + if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) { IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n", dbgfs_dir); return; @@ -1505,6 +788,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400); MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400); MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600); @@ -1514,24 +798,6 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif == mvm->bf_allowed_vif) MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && - !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { - if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) - MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, - mvmvif->dbgfs_dir, 0600); - - MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, - 0600); - MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, - 0600); - MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, - 0600); - MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, - 0600); - MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, - 0400); - } - /* * Create symlink for convenience pointing to interface specific * debugfs entries for the driver. For example, under diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 3b6b3d8fb961..776b24f54200 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,6 +69,7 @@ #include "sta.h" #include "iwl-io.h" #include "debugfs.h" +#include "iwl-modparams.h" #include "fw/error-dump.h" static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, @@ -1187,64 +1188,128 @@ out: return ret ?: count; } -static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) +static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len) { - struct iwl_mvm *mvm = file->private_data; - int conf; - char buf[8]; - const size_t bufsz = sizeof(buf); - int pos = 0; + struct ieee80211_vif *vif; + struct iwl_mvm_vif *mvmvif; + struct sk_buff *beacon; + struct ieee80211_tx_info *info; + struct iwl_mac_beacon_cmd beacon_cmd = {}; + u8 rate; + u16 flags; + int i; + + len /= 2; + + /* Element len should be represented by u8 */ + if (len >= U8_MAX) + return -EINVAL; + + if (!iwl_mvm_firmware_running(mvm)) + return -EIO; + + if (!iwl_mvm_has_new_tx_api(mvm) && + !fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE)) + return -EINVAL; + + rcu_read_lock(); + + for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, true); + if (!vif) + continue; + + if (vif->type == NL80211_IFTYPE_AP) + break; + } + + if (i == NUM_MAC_INDEX_DRIVER || !vif) + goto out_err; + + mvm->hw->extra_beacon_tailroom = len; + + beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL); + if (!beacon) + goto out_err; + + if (len && hex2bin(skb_put_zero(beacon, len), bin, len)) { + dev_kfree_skb(beacon); + goto out_err; + } + + mvm->beacon_inject_active = true; + + mvmvif = iwl_mvm_vif_from_mac80211(vif); + info = IEEE80211_SKB_CB(beacon); + rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); + flags = iwl_mvm_mac80211_idx_to_hwrate(rate); + + if (rate == IWL_FIRST_CCK_RATE) + flags |= IWL_MAC_BEACON_CCK; + + beacon_cmd.flags = cpu_to_le16(flags); + beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); + beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + + iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx, + &beacon_cmd.tim_size, + beacon->data, beacon->len); mutex_lock(&mvm->mutex); - conf = mvm->fwrt.dump.conf; + iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, + sizeof(beacon_cmd)); mutex_unlock(&mvm->mutex); - pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + dev_kfree_skb(beacon); - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); + rcu_read_unlock(); + return 0; + +out_err: + rcu_read_unlock(); + return -EINVAL; } -/* - * Enable / Disable continuous recording. - * Cause the FW to start continuous recording, by sending the relevant hcmd. - * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING. - * Disable: for 0 as input, DISABLE_CONT_RECORDING. - */ -static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) +static ssize_t iwl_dbgfs_inject_beacon_ie_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) { - struct iwl_trans *trans = mvm->trans; - const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv; - struct iwl_continuous_record_cmd cont_rec = {}; - int ret, rec_mode; + int ret = _iwl_dbgfs_inject_beacon_ie(mvm, buf, count); - if (!iwl_mvm_firmware_running(mvm)) - return -EIO; - - if (!dest) - return -EOPNOTSUPP; + mvm->hw->extra_beacon_tailroom = 0; + return ret ?: count; +} - if (dest->monitor_mode != SMEM_MODE || - trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) - return -EOPNOTSUPP; +static ssize_t iwl_dbgfs_inject_beacon_ie_restore_write(struct iwl_mvm *mvm, + char *buf, + size_t count, + loff_t *ppos) +{ + int ret = _iwl_dbgfs_inject_beacon_ie(mvm, NULL, 0); - ret = kstrtoint(buf, 0, &rec_mode); - if (ret) - return ret; + mvm->hw->extra_beacon_tailroom = 0; + mvm->beacon_inject_active = false; + return ret ?: count; +} - cont_rec.record_mode.enable_recording = rec_mode ? - cpu_to_le16(ENABLE_CONT_RECORDING) : - cpu_to_le16(DISABLE_CONT_RECORDING); +static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + int conf; + char buf[8]; + const size_t bufsz = sizeof(buf); + int pos = 0; mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0, - sizeof(cont_rec), &cont_rec); + conf = mvm->fwrt.dump.conf; mutex_unlock(&mvm->mutex); - return ret ?: count; + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, @@ -1284,7 +1349,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, return 0; iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, - (count - 1), NULL); + (count - 1)); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); @@ -1722,11 +1787,36 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +struct iwl_mvm_sniffer_apply { + struct iwl_mvm *mvm; + u8 *bssid; + u16 aid; +}; + +static bool iwl_mvm_sniffer_apply(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt, void *data) +{ + struct iwl_mvm_sniffer_apply *apply = data; + + apply->mvm->cur_aid = cpu_to_le16(apply->aid); + memcpy(apply->mvm->cur_bssid, apply->bssid, + sizeof(apply->mvm->cur_bssid)); + + return true; +} + static ssize_t iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { + struct iwl_notification_wait wait; struct iwl_he_monitor_cmd he_mon_cmd = {}; + struct iwl_mvm_sniffer_apply apply = { + .mvm = mvm, + }; + u16 wait_cmds[] = { + iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD, DATA_PATH_GROUP, 0), + }; u32 aid; int ret; @@ -1742,16 +1832,54 @@ iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf, he_mon_cmd.aid = cpu_to_le16(aid); + apply.aid = aid; + apply.bssid = (void *)he_mon_cmd.bssid; + mutex_lock(&mvm->mutex); + + /* + * Use the notification waiter to get our function triggered + * in sequence with other RX. This ensures that frames we get + * on the RX queue _before_ the new configuration is applied + * still have mvm->cur_aid pointing to the old AID, and that + * frames on the RX queue _after_ the firmware processed the + * new configuration (and sent the response, synchronously) + * get mvm->cur_aid correctly set to the new AID. + */ + iwl_init_notification_wait(&mvm->notif_wait, &wait, + wait_cmds, ARRAY_SIZE(wait_cmds), + iwl_mvm_sniffer_apply, &apply); + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD, DATA_PATH_GROUP, 0), 0, sizeof(he_mon_cmd), &he_mon_cmd); + + /* no need to really wait, we already did anyway */ + iwl_remove_notification(&mvm->notif_wait, &wait); + mutex_unlock(&mvm->mutex); return ret ?: count; } static ssize_t +iwl_dbgfs_he_sniffer_params_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm *mvm = file->private_data; + u8 buf[32]; + int len; + + len = scnprintf(buf, sizeof(buf), + "%d %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", + le16_to_cpu(mvm->cur_aid), mvm->cur_bssid[0], + mvm->cur_bssid[1], mvm->cur_bssid[2], mvm->cur_bssid[3], + mvm->cur_bssid[4], mvm->cur_bssid[5]); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1800,11 +1928,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64); -MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8); MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512); +MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512); +MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512); MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids); @@ -1820,7 +1949,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); #endif -MVM_DEBUGFS_WRITE_FILE_OPS(he_sniffer_params, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32); static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2004,13 +2133,14 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200); #ifdef CONFIG_ACPI MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400); #endif - MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0600); if (!debugfs_create_bool("enable_scan_iteration_notif", 0600, @@ -2071,6 +2201,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) if (!debugfs_create_blob("nvm_phy_sku", 0400, mvm->debugfs_dir, &mvm->nvm_phy_sku_blob)) goto err; + if (!debugfs_create_blob("nvm_reg", S_IRUSR, + mvm->debugfs_dir, &mvm->nvm_reg_blob)) + goto err; debugfs_create_file("mem", 0600, dbgfs_dir, mvm, &iwl_dbgfs_mem_ops); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c new file mode 100644 index 000000000000..94132cfd1f56 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -0,0 +1,652 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2019 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include <linux/etherdevice.h> +#include <linux/math64.h> +#include <net/cfg80211.h> +#include "mvm.h" +#include "iwl-io.h" +#include "iwl-prph.h" +#include "constants.h" + +struct iwl_mvm_loc_entry { + struct list_head list; + u8 addr[ETH_ALEN]; + u8 lci_len, civic_len; + u8 buf[]; +}; + +static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm) +{ + struct iwl_mvm_loc_entry *e, *t; + + mvm->ftm_initiator.req = NULL; + mvm->ftm_initiator.req_wdev = NULL; + memset(mvm->ftm_initiator.responses, 0, + sizeof(mvm->ftm_initiator.responses)); + list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) { + list_del(&e->list); + kfree(e); + } +} + +void iwl_mvm_ftm_restart(struct iwl_mvm *mvm) +{ + struct cfg80211_pmsr_result result = { + .status = NL80211_PMSR_STATUS_FAILURE, + .final = 1, + .host_time = ktime_get_boot_ns(), + .type = NL80211_PMSR_TYPE_FTM, + }; + int i; + + lockdep_assert_held(&mvm->mutex); + + if (!mvm->ftm_initiator.req) + return; + + for (i = 0; i < mvm->ftm_initiator.req->n_peers; i++) { + memcpy(result.addr, mvm->ftm_initiator.req->peers[i].addr, + ETH_ALEN); + result.ftm.burst_index = mvm->ftm_initiator.responses[i]; + + cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, + mvm->ftm_initiator.req, + &result, GFP_KERNEL); + } + + cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev, + mvm->ftm_initiator.req, GFP_KERNEL); + iwl_mvm_ftm_reset(mvm); +} + +static int +iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s) +{ + switch (s) { + case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS: + return 0; + case IWL_TOF_RANGE_REQUEST_STATUS_BUSY: + return -EBUSY; + default: + WARN_ON_ONCE(1); + return -EIO; + } +} + +static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_tof_range_req_cmd_v5 *cmd, + struct cfg80211_pmsr_request *req) +{ + int i; + + cmd->request_id = req->cookie; + cmd->num_of_ap = req->n_peers; + + /* use maximum for "no timeout" or bigger than what we can do */ + if (!req->timeout || req->timeout > 255 * 100) + cmd->req_timeout = 255; + else + cmd->req_timeout = DIV_ROUND_UP(req->timeout, 100); + + /* + * We treat it always as random, since if not we'll + * have filled our local address there instead. + */ + cmd->macaddr_random = 1; + memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) + cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; + + if (vif->bss_conf.assoc) + memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); + else + eth_broadcast_addr(cmd->range_req_bssid); +} + +static void iwl_mvm_ftm_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_tof_range_req_cmd *cmd, + struct cfg80211_pmsr_request *req) +{ + int i; + + cmd->initiator_flags = + cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM | + IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT); + cmd->request_id = req->cookie; + cmd->num_of_ap = req->n_peers; + + /* + * Use a large value for "no timeout". Don't use the maximum value + * because of fw limitations. + */ + if (req->timeout) + cmd->req_timeout_ms = cpu_to_le32(req->timeout); + else + cmd->req_timeout_ms = cpu_to_le32(0xfffff); + + memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) + cmd->macaddr_mask[i] = ~req->mac_addr_mask[i]; + + if (vif->bss_conf.assoc) + memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN); + else + eth_broadcast_addr(cmd->range_req_bssid); + + /* TODO: fill in tsf_mac_id if needed */ + cmd->tsf_mac_id = cpu_to_le32(0xff); +} + +static int iwl_mvm_ftm_target_chandef(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + u8 *channel, u8 *bandwidth, + u8 *ctrl_ch_position) +{ + u32 freq = peer->chandef.chan->center_freq; + + *channel = ieee80211_frequency_to_channel(freq); + + switch (peer->chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + *bandwidth = IWL_TOF_BW_20_LEGACY; + break; + case NL80211_CHAN_WIDTH_20: + *bandwidth = IWL_TOF_BW_20_HT; + break; + case NL80211_CHAN_WIDTH_40: + *bandwidth = IWL_TOF_BW_40; + break; + case NL80211_CHAN_WIDTH_80: + *bandwidth = IWL_TOF_BW_80; + break; + default: + IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n", + peer->chandef.width); + return -EINVAL; + } + + *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ? + iwl_mvm_get_ctrl_pos(&peer->chandef) : 0; + + return 0; +} + +static int +iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v2 *target) +{ + int ret; + + ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num, + &target->bandwidth, + &target->ctrl_ch_position); + if (ret) + return ret; + + memcpy(target->bssid, peer->addr, ETH_ALEN); + target->burst_period = + cpu_to_le16(peer->ftm.burst_period); + target->samples_per_burst = peer->ftm.ftms_per_burst; + target->num_of_bursts = peer->ftm.num_bursts_exp; + target->measure_type = 0; /* regular two-sided FTM */ + target->retries_per_sample = peer->ftm.ftmr_retries; + target->asap_mode = peer->ftm.asap; + target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK; + + if (peer->ftm.request_lci) + target->location_req |= IWL_TOF_LOC_LCI; + if (peer->ftm.request_civicloc) + target->location_req |= IWL_TOF_LOC_CIVIC; + + target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO; + + return 0; +} + +#define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \ + cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag)) + +static int iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry *target) +{ + int ret; + + ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num, + &target->bandwidth, + &target->ctrl_ch_position); + if (ret) + return ret; + + memcpy(target->bssid, peer->addr, ETH_ALEN); + target->burst_period = + cpu_to_le16(peer->ftm.burst_period); + target->samples_per_burst = peer->ftm.ftms_per_burst; + target->num_of_bursts = peer->ftm.num_bursts_exp; + target->ftmr_max_retries = peer->ftm.ftmr_retries; + target->initiator_ap_flags = cpu_to_le32(0); + + if (peer->ftm.asap) + FTM_PUT_FLAG(ASAP); + + if (peer->ftm.request_lci) + FTM_PUT_FLAG(LCI_REQUEST); + + if (peer->ftm.request_civicloc) + FTM_PUT_FLAG(CIVIC_REQUEST); + + if (IWL_MVM_FTM_INITIATOR_DYNACK) + FTM_PUT_FLAG(DYN_ACK); + + if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG) + FTM_PUT_FLAG(ALGO_LR); + else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT) + FTM_PUT_FLAG(ALGO_FFT); + + return 0; +} + +int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_req_cmd_v5 cmd_v5; + struct iwl_tof_range_req_cmd cmd; + bool new_api = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); + u8 num_of_ap; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), + .dataflags[0] = IWL_HCMD_DFL_DUP, + }; + u32 status = 0; + int err, i; + + lockdep_assert_held(&mvm->mutex); + + if (mvm->ftm_initiator.req) + return -EBUSY; + + if (new_api) { + iwl_mvm_ftm_cmd(mvm, vif, &cmd, req); + hcmd.data[0] = &cmd; + hcmd.len[0] = sizeof(cmd); + num_of_ap = cmd.num_of_ap; + } else { + iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req); + hcmd.data[0] = &cmd_v5; + hcmd.len[0] = sizeof(cmd_v5); + num_of_ap = cmd_v5.num_of_ap; + } + + for (i = 0; i < num_of_ap; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + + if (new_api) + err = iwl_mvm_ftm_put_target(mvm, peer, &cmd.ap[i]); + else + err = iwl_mvm_ftm_put_target_v2(mvm, peer, + &cmd_v5.ap[i]); + + if (err) + return err; + } + + err = iwl_mvm_send_cmd_status(mvm, &hcmd, &status); + if (!err && status) { + IWL_ERR(mvm, "FTM range request command failure, status: %u\n", + status); + err = iwl_ftm_range_request_status_to_err(status); + } + + if (!err) { + mvm->ftm_initiator.req = req; + mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif); + } + + return err; +} + +void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_abort_cmd cmd = { + .request_id = req->cookie, + }; + + lockdep_assert_held(&mvm->mutex); + + if (req != mvm->ftm_initiator.req) + return; + + if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD, + LOCATION_GROUP, 0), + 0, sizeof(cmd), &cmd)) + IWL_ERR(mvm, "failed to abort FTM process\n"); +} + +static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req, + const u8 *addr) +{ + int i; + + for (i = 0; i < req->n_peers; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + + if (ether_addr_equal_unaligned(peer->addr, addr)) + return i; + } + + return -ENOENT; +} + +static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) +{ + u32 gp2_ts = le32_to_cpu(fw_gp2_ts); + u32 curr_gp2, diff; + u64 now_from_boot_ns; + + iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); + + if (curr_gp2 >= gp2_ts) + diff = curr_gp2 - gp2_ts; + else + diff = curr_gp2 + (U32_MAX - gp2_ts + 1); + + return now_from_boot_ns - (u64)diff * 1000; +} + +static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm, + struct cfg80211_pmsr_result *res) +{ + struct iwl_mvm_loc_entry *entry; + + list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) { + if (!ether_addr_equal_unaligned(res->addr, entry->addr)) + continue; + + if (entry->lci_len) { + res->ftm.lci_len = entry->lci_len; + res->ftm.lci = entry->buf; + } + + if (entry->civic_len) { + res->ftm.civicloc_len = entry->civic_len; + res->ftm.civicloc = entry->buf + entry->lci_len; + } + + /* we found the entry we needed */ + break; + } +} + +static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id, + u8 num_of_aps) +{ + lockdep_assert_held(&mvm->mutex); + + if (request_id != (u8)mvm->ftm_initiator.req->cookie) { + IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n", + request_id, (u8)mvm->ftm_initiator.req->cookie); + return -EINVAL; + } + + if (num_of_aps > mvm->ftm_initiator.req->n_peers) { + IWL_ERR(mvm, "FTM range response invalid\n"); + return -EINVAL; + } + + return 0; +} + +static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index, + struct cfg80211_pmsr_result *res) +{ + s64 rtt_avg = div_s64(res->ftm.rtt_avg * 100, 6666); + + IWL_DEBUG_INFO(mvm, "entry %d\n", index); + IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status); + IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr); + IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time); + IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index); + IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes); + IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg); + IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread); + IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg); + IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance); + IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread); + IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg); +} + +void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data; + struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data; + int i; + bool new_api = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ); + u8 num_of_aps, last_in_batch; + + lockdep_assert_held(&mvm->mutex); + + if (!mvm->ftm_initiator.req) { + IWL_ERR(mvm, "Got FTM response but have no request?\n"); + return; + } + + if (new_api) { + if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id, + fw_resp->num_of_aps)) + return; + + num_of_aps = fw_resp->num_of_aps; + last_in_batch = fw_resp->last_report; + } else { + if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id, + fw_resp_v5->num_of_aps)) + return; + + num_of_aps = fw_resp_v5->num_of_aps; + last_in_batch = fw_resp_v5->last_in_batch; + } + + IWL_DEBUG_INFO(mvm, "Range response received\n"); + IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n", + mvm->ftm_initiator.req->cookie, num_of_aps); + + for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) { + struct cfg80211_pmsr_result result = {}; + struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap; + int peer_idx; + + if (new_api) { + fw_ap = &fw_resp->ap[i]; + result.final = fw_resp->ap[i].last_burst; + } else { + /* the first part is the same for old and new APIs */ + fw_ap = (void *)&fw_resp_v5->ap[i]; + /* + * FIXME: the firmware needs to report this, we don't + * even know the number of bursts the responder picked + * (if we asked it to) + */ + result.final = 0; + } + + peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req, + fw_ap->bssid); + if (peer_idx < 0) { + IWL_WARN(mvm, + "Unknown address (%pM, target #%d) in FTM response\n", + fw_ap->bssid, i); + continue; + } + + switch (fw_ap->measure_status) { + case IWL_TOF_ENTRY_SUCCESS: + result.status = NL80211_PMSR_STATUS_SUCCESS; + break; + case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT: + result.status = NL80211_PMSR_STATUS_TIMEOUT; + break; + case IWL_TOF_ENTRY_NO_RESPONSE: + result.status = NL80211_PMSR_STATUS_FAILURE; + result.ftm.failure_reason = + NL80211_PMSR_FTM_FAILURE_NO_RESPONSE; + break; + case IWL_TOF_ENTRY_REQUEST_REJECTED: + result.status = NL80211_PMSR_STATUS_FAILURE; + result.ftm.failure_reason = + NL80211_PMSR_FTM_FAILURE_PEER_BUSY; + result.ftm.busy_retry_time = fw_ap->refusal_period; + break; + default: + result.status = NL80211_PMSR_STATUS_FAILURE; + result.ftm.failure_reason = + NL80211_PMSR_FTM_FAILURE_UNSPECIFIED; + break; + } + memcpy(result.addr, fw_ap->bssid, ETH_ALEN); + result.host_time = iwl_mvm_ftm_get_host_time(mvm, + fw_ap->timestamp); + result.type = NL80211_PMSR_TYPE_FTM; + result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx]; + mvm->ftm_initiator.responses[peer_idx]++; + result.ftm.rssi_avg = fw_ap->rssi; + result.ftm.rssi_avg_valid = 1; + result.ftm.rssi_spread = fw_ap->rssi_spread; + result.ftm.rssi_spread_valid = 1; + result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt); + result.ftm.rtt_avg_valid = 1; + result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance); + result.ftm.rtt_variance_valid = 1; + result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread); + result.ftm.rtt_spread_valid = 1; + + iwl_mvm_ftm_get_lci_civic(mvm, &result); + + cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, + mvm->ftm_initiator.req, + &result, GFP_KERNEL); + + iwl_mvm_debug_range_resp(mvm, i, &result); + } + + if (last_in_batch) { + cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev, + mvm->ftm_initiator.req, + GFP_KERNEL); + iwl_mvm_ftm_reset(mvm); + } +} + +void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + const struct ieee80211_mgmt *mgmt = (void *)pkt->data; + size_t len = iwl_rx_packet_payload_len(pkt); + struct iwl_mvm_loc_entry *entry; + const u8 *ies, *lci, *civic, *msr_ie; + size_t ies_len, lci_len = 0, civic_len = 0; + size_t baselen = IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.ftm); + static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI; + static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC; + + if (len <= baselen) + return; + + lockdep_assert_held(&mvm->mutex); + + ies = mgmt->u.action.u.ftm.variable; + ies_len = len - baselen; + + msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, + &rprt_type_lci, 1, 4); + if (msr_ie) { + lci = msr_ie + 2; + lci_len = msr_ie[1]; + } + + msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len, + &rprt_type_civic, 1, 4); + if (msr_ie) { + civic = msr_ie + 2; + civic_len = msr_ie[1]; + } + + entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL); + if (!entry) + return; + + memcpy(entry->addr, mgmt->bssid, ETH_ALEN); + + entry->lci_len = lci_len; + if (lci_len) + memcpy(entry->buf, lci, lci_len); + + entry->civic_len = civic_len; + if (civic_len) + memcpy(entry->buf + lci_len, civic, civic_len); + + list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c new file mode 100644 index 000000000000..1513b8b4062f --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -0,0 +1,244 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include <net/cfg80211.h> +#include <linux/etherdevice.h> +#include "mvm.h" +#include "constants.h" + +static int +iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_tof_responder_config_cmd cmd = { + .channel_num = chandef->chan->hw_value, + .cmd_valid_fields = + cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | + IWL_TOF_RESPONDER_CMD_VALID_BSSID | + IWL_TOF_RESPONDER_CMD_VALID_STA_ID), + .sta_id = mvmvif->bcast_sta.sta_id, + }; + + lockdep_assert_held(&mvm->mutex); + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + cmd.bandwidth = IWL_TOF_BW_20_LEGACY; + break; + case NL80211_CHAN_WIDTH_20: + cmd.bandwidth = IWL_TOF_BW_20_HT; + break; + case NL80211_CHAN_WIDTH_40: + cmd.bandwidth = IWL_TOF_BW_40; + cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); + break; + case NL80211_CHAN_WIDTH_80: + cmd.bandwidth = IWL_TOF_BW_80; + cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); + break; + default: + WARN_ON(1); + return -EINVAL; + } + + memcpy(cmd.bssid, vif->addr, ETH_ALEN); + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD, + LOCATION_GROUP, 0), + 0, sizeof(cmd), &cmd); +} + +static int +iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_ftm_responder_params *params) +{ + struct iwl_tof_responder_dyn_config_cmd cmd = { + .lci_len = cpu_to_le32(params->lci_len + 2), + .civic_len = cpu_to_le32(params->civicloc_len + 2), + }; + u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0}; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD, + LOCATION_GROUP, 0), + .data[0] = &cmd, + .len[0] = sizeof(cmd), + .data[1] = &data, + /* .len[1] set later */ + /* may not be able to DMA from stack */ + .dataflags[1] = IWL_HCMD_DFL_DUP, + }; + u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4); + u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4); + u8 *pos = data; + + lockdep_assert_held(&mvm->mutex); + + if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) { + IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n", + params->lci_len, params->civicloc_len); + return -ENOBUFS; + } + + pos[0] = WLAN_EID_MEASURE_REPORT; + pos[1] = params->lci_len; + memcpy(pos + 2, params->lci, params->lci_len); + + pos += aligned_lci_len; + pos[0] = WLAN_EID_MEASURE_REPORT; + pos[1] = params->civicloc_len; + memcpy(pos + 2, params->civicloc, params->civicloc_len); + + hcmd.len[1] = aligned_lci_len + aligned_civicloc_len; + + return iwl_mvm_send_cmd(mvm, &hcmd); +} + +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_ftm_responder_params *params; + struct ieee80211_chanctx_conf ctx, *pctx; + u16 *phy_ctxt_id; + struct iwl_mvm_phy_ctxt *phy_ctxt; + int ret; + + params = vif->bss_conf.ftmr_params; + + lockdep_assert_held(&mvm->mutex); + + if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) + return -EINVAL; + + if (vif->p2p || vif->type != NL80211_IFTYPE_AP || + !mvmvif->ap_ibss_active) { + IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); + return -EIO; + } + + rcu_read_lock(); + pctx = rcu_dereference(vif->chanctx_conf); + /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care + * about changes in the ctx after releasing the lock because the driver + * is still protected by the mutex. */ + ctx = *pctx; + phy_ctxt_id = (u16 *)pctx->drv_priv; + rcu_read_unlock(); + + phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, + ctx.rx_chains_static, + ctx.rx_chains_dynamic); + if (ret) + return ret; + + ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); + if (ret) + return ret; + + if (params) + ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params); + + return ret; +} + +void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + if (!vif->bss_conf.ftm_responder) + return; + + iwl_mvm_ftm_start_responder(mvm, vif); +} + +void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_ftm_responder_stats *resp = (void *)pkt->data; + struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats; + u32 flags = le32_to_cpu(resp->flags); + + if (resp->success_ftm == resp->ftm_per_burst) + stats->success_num++; + else if (resp->success_ftm >= 2) + stats->partial_num++; + else + stats->failed_num++; + + if ((flags & FTM_RESP_STAT_ASAP_REQ) && + (flags & FTM_RESP_STAT_ASAP_RESP)) + stats->asap_num++; + + if (flags & FTM_RESP_STAT_NON_ASAP_RESP) + stats->non_asap_num++; + + stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC; + + if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN) + stats->unknown_triggers_num++; + + if (flags & FTM_RESP_STAT_DUP) + stats->reschedule_requests_num++; + + if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN) + stats->out_of_window_triggers_num++; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index 143c7fcaea41..e3eb812e0248 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,7 +91,7 @@ #include "fw/api/sf.h" #include "fw/api/sta.h" #include "fw/api/stats.h" -#include "fw/api/tof.h" +#include "fw/api/location.h" #include "fw/api/tx.h" #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 1689bead1b4f..ab68b5d53ec9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,12 +105,12 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) int i; struct iwl_rss_config_cmd cmd = { .flags = cpu_to_le32(IWL_RSS_ENABLE), - .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | - IWL_RSS_HASH_TYPE_IPV4_UDP | - IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | - IWL_RSS_HASH_TYPE_IPV6_TCP | - IWL_RSS_HASH_TYPE_IPV6_UDP | - IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, + .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | + BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), }; if (mvm->trans->num_rx_queues == 1) @@ -127,13 +127,17 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) static int iwl_configure_rxq(struct iwl_mvm *mvm) { - int i, num_queues, size; + int i, num_queues, size, ret; struct iwl_rfh_queue_config *cmd; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DATA_PATH_GROUP, RFH_QUEUE_CONFIG_CMD), + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, + }; /* Do not configure default queue, it is configured via context info */ num_queues = mvm->trans->num_rx_queues - 1; - size = sizeof(*cmd) + num_queues * sizeof(struct iwl_rfh_queue_data); + size = struct_size(cmd, data, num_queues); cmd = kzalloc(size, GFP_KERNEL); if (!cmd) @@ -154,10 +158,14 @@ static int iwl_configure_rxq(struct iwl_mvm *mvm) cmd->data[i].fr_bd_wid = cpu_to_le32(data.fr_bd_wid); } - return iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(DATA_PATH_GROUP, - RFH_QUEUE_CONFIG_CMD), - 0, size, cmd); + hcmd.data[0] = cmd; + hcmd.len[0] = size; + + ret = iwl_mvm_send_cmd(mvm, &hcmd); + + kfree(cmd); + + return ret; } static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) @@ -210,7 +218,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_lmac_alive *lmac1; struct iwl_lmac_alive *lmac2 = NULL; u16 status; - u32 umac_error_event_table; + u32 lmac_error_event_table, umac_error_event_table; if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) { palive = (void *)pkt->data; @@ -225,30 +233,35 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, status = le16_to_cpu(palive3->status); } - mvm->error_event_table[0] = le32_to_cpu(lmac1->error_event_table_ptr); + lmac_error_event_table = + le32_to_cpu(lmac1->dbg_ptrs.error_event_table_ptr); + iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table); + if (lmac2) - mvm->error_event_table[1] = - le32_to_cpu(lmac2->error_event_table_ptr); - mvm->log_event_table = le32_to_cpu(lmac1->log_event_table_ptr); + mvm->trans->lmac_error_event_table[1] = + le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr); - umac_error_event_table = le32_to_cpu(umac->error_info_addr); + umac_error_event_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr); if (!umac_error_event_table) { mvm->support_umac_log = false; } else if (umac_error_event_table >= mvm->trans->cfg->min_umac_error_event_table) { mvm->support_umac_log = true; - mvm->umac_error_event_table = umac_error_event_table; } else { IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", - mvm->umac_error_event_table, + umac_error_event_table, (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ? "Init" : "RT"); mvm->support_umac_log = false; } - alive_data->scd_base_addr = le32_to_cpu(lmac1->scd_base_ptr); + if (mvm->support_umac_log) + iwl_fw_umac_set_alive_err_table(mvm->trans, + umac_error_event_table); + + alive_data->scd_base_addr = le32_to_cpu(lmac1->dbg_ptrs.scd_base_ptr); alive_data->valid = status == IWL_ALIVE_STATUS_OK; IWL_DEBUG_FW(mvm, @@ -293,13 +306,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type) { struct iwl_notification_wait alive_wait; - struct iwl_mvm_alive_data alive_data; + struct iwl_mvm_alive_data alive_data = {}; const struct fw_img *fw; - int ret, i; + int ret; enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; - set_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status); if (ucode_type == IWL_UCODE_REGULAR && iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && !(fw_has_capa(&mvm->fw->ucode_capa, @@ -332,11 +344,16 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, if (ret) { struct iwl_trans *trans = mvm->trans; + if (ret == -ETIMEDOUT) + iwl_fw_dbg_error_collect(&mvm->fwrt, + FW_DBG_TRIGGER_ALIVE_TIMEOUT); + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS), - iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS)); + iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), + iwl_read_umac_prph(trans, + UMAG_SB_CPU_2_STATUS)); else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", @@ -373,11 +390,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap = BIT(IWL_MAX_TID_COUNT + 2); - for (i = 0; i < IEEE80211_MAX_QUEUES; i++) - atomic_set(&mvm->mac80211_queue_stop_count[i], 0); - set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); - clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status); +#ifdef CONFIG_IWLWIFI_DEBUGFS + iwl_fw_set_dbg_rec_on(&mvm->fwrt); +#endif return 0; } @@ -403,12 +419,15 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) iwl_wait_init_complete, NULL); + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY); + /* Will also start the device */ ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); goto error; } + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE); /* Send init config command to mark that we are sending NVM access * commands @@ -543,7 +562,9 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) if (mvm->nvm_file_name) iwl_mvm_load_nvm_to_nic(mvm); - WARN_ON(iwl_nvm_check_version(mvm->nvm_data, mvm->trans)); + WARN_ONCE(mvm->nvm_data->nvm_version < mvm->trans->cfg->nvm_ver, + "Too old NVM version (0x%0x, required = 0x%0x)", + mvm->nvm_data->nvm_version, mvm->trans->cfg->nvm_ver); /* * abort after reading the nvm in case RF Kill is on, we will complete @@ -625,10 +646,10 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) } #ifdef CONFIG_ACPI -static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, - union acpi_object *table, - struct iwl_mvm_sar_profile *profile, - bool enabled) +static inline int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, + union acpi_object *table, + struct iwl_mvm_sar_profile *profile, + bool enabled) { int i; @@ -959,6 +980,57 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) } #endif /* CONFIG_ACPI */ +void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) +{ + u32 error_log_size = mvm->fw->ucode_capa.error_log_size; + int ret; + u32 resp; + + struct iwl_fw_error_recovery_cmd recovery_cmd = { + .flags = cpu_to_le32(flags), + .buf_size = 0, + }; + struct iwl_host_cmd host_cmd = { + .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD), + .flags = CMD_WANT_SKB, + .data = {&recovery_cmd, }, + .len = {sizeof(recovery_cmd), }, + }; + + /* no error log was defined in TLV */ + if (!error_log_size) + return; + + if (flags & ERROR_RECOVERY_UPDATE_DB) { + /* no buf was allocated while HW reset */ + if (!mvm->error_recovery_buf) + return; + + host_cmd.data[1] = mvm->error_recovery_buf; + host_cmd.len[1] = error_log_size; + host_cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; + recovery_cmd.buf_size = cpu_to_le32(error_log_size); + } + + ret = iwl_mvm_send_cmd(mvm, &host_cmd); + kfree(mvm->error_recovery_buf); + mvm->error_recovery_buf = NULL; + + if (ret) { + IWL_ERR(mvm, "Failed to send recovery cmd %d\n", ret); + return; + } + + /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */ + if (flags & ERROR_RECOVERY_UPDATE_DB) { + resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); + if (resp) + IWL_ERR(mvm, + "Failed to send recovery cmd blob was invalid %d\n", + resp); + } +} + static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { int ret; @@ -1023,10 +1095,14 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) if (ret) return ret; + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY); + ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); if (ret) return ret; + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE); + return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img); } @@ -1045,6 +1121,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ret = iwl_mvm_load_rt_fw(mvm); if (ret) { IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); + if (ret != -ERFKILL) + iwl_fw_dbg_error_collect(&mvm->fwrt, + FW_DBG_TRIGGER_DRIVER); goto error; } @@ -1054,11 +1133,13 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); - mvm->fwrt.dump.conf = FW_DBG_INVALID; - /* if we have a destination, assume EARLY START */ - if (mvm->fw->dbg.dest_tlv) - mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; - iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); + if (!mvm->trans->ini_valid) { + mvm->fwrt.dump.conf = FW_DBG_INVALID; + /* if we have a destination, assume EARLY START */ + if (mvm->fw->dbg.dest_tlv) + mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; + iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); + } ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) @@ -1188,6 +1269,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) + iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); + + if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) + IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); + ret = iwl_mvm_sar_init(mvm); if (ret == 0) { ret = iwl_mvm_sar_geo_init(mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index 9bb1de1cad64..4348bb00e761 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -113,6 +115,7 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) switch (mode) { case IWL_LED_BLINK: IWL_ERR(mvm, "Blink led mode not supported, used default\n"); + /* fall through */ case IWL_LED_DEFAULT: case IWL_LED_RF_STATE: mode = IWL_LED_RF_STATE; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 6486cfb33f40..6a70dece447d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -97,11 +97,6 @@ struct iwl_mvm_mac_iface_iterator_data { bool found_vif; }; -struct iwl_mvm_hw_queues_iface_iterator_data { - struct ieee80211_vif *exclude_vif; - unsigned long used_hw_queues; -}; - static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -208,61 +203,6 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, data->preferred_tsf = NUM_TSF_IDS; } -/* - * Get the mask of the queues used by the vif - */ -u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif) -{ - u32 qmask = 0, ac; - - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) - return BIT(IWL_MVM_OFFCHANNEL_QUEUE); - - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - qmask |= BIT(vif->hw_queue[ac]); - } - - if (vif->type == NL80211_IFTYPE_AP || - vif->type == NL80211_IFTYPE_ADHOC) - qmask |= BIT(vif->cab_queue); - - return qmask; -} - -static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; - - /* exclude the given vif */ - if (vif == data->exclude_vif) - return; - - data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); -} - -unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, - struct ieee80211_vif *exclude_vif) -{ - struct iwl_mvm_hw_queues_iface_iterator_data data = { - .exclude_vif = exclude_vif, - .used_hw_queues = - BIT(IWL_MVM_OFFCHANNEL_QUEUE) | - BIT(mvm->aux_queue) | - BIT(IWL_MVM_DQA_GCAST_QUEUE), - }; - - lockdep_assert_held(&mvm->mutex); - - /* mark all VIF used hw queues */ - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - iwl_mvm_iface_hw_queues_iter, &data); - - return data.used_hw_queues; -} - static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { @@ -360,8 +300,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, iwl_mvm_mac_iface_iterator, &data); - used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif); - /* * In the case we're getting here during resume, it's similar to * firmware restart, and with RESUME_ALL the iterator will find @@ -416,9 +354,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * the ones here - no real limit */ queue_limit = IEEE80211_MAX_QUEUES; - BUILD_BUG_ON(IEEE80211_MAX_QUEUES > - BITS_PER_BYTE * - sizeof(mvm->hw_queue_to_mac80211[0])); /* * Find available queues, and allocate them to the ACs. When in @@ -446,9 +381,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * queue value (when queue is enabled). */ mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; - vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; - } else { - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; } mvmvif->bcast_sta.sta_id = IWL_MVM_INVALID_STA; @@ -462,8 +394,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) exit_fail: memset(mvmvif, 0, sizeof(struct iwl_mvm_vif)); - memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue)); - vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; return ret; } @@ -767,13 +697,8 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); - ctxt_sta->bi_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); ctxt_sta->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * vif->bss_conf.dtim_period); - ctxt_sta->dtim_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period)); ctxt_sta->listen_interval = cpu_to_le32(mvm->hw->conf.listen_interval); ctxt_sta->assoc_id = cpu_to_le32(vif->bss_conf.aid); @@ -781,9 +706,12 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); - if (vif->bss_conf.assoc && vif->bss_conf.he_support && - !iwlwifi_mod_params.disable_11ax) + if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); + if (vif->bss_conf.twt_requester) + ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED); + } + return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); } @@ -832,8 +760,6 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, /* cmd.ibss.beacon_time/cmd.ibss.beacon_tsf are curently ignored */ cmd.ibss.bi = cpu_to_le32(vif->bss_conf.beacon_int); - cmd.ibss.bi_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); /* TODO: Assumes that the beacon id == mac context id */ cmd.ibss.beacon_template = cpu_to_le32(mvmvif->id); @@ -866,8 +792,6 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); - cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT); - /* Override the filter flags to accept only probe requests */ cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST); @@ -887,9 +811,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); } -static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, - __le32 *tim_index, __le32 *tim_size, - u8 *beacon, u32 frame_size) +void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, + __le32 *tim_index, __le32 *tim_size, + u8 *beacon, u32 frame_size) { u32 tim_idx; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon; @@ -929,8 +853,8 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size) return ie - beacon; } -static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, - struct ieee80211_vif *vif) +u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, + struct ieee80211_vif *vif) { u8 rate; @@ -965,11 +889,8 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, tx->tx_flags = cpu_to_le32(tx_flags); if (!fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) { - mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), - mvm->mgmt_last_antenna_idx); - } + IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) + iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); tx->rate_n_flags = cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << @@ -983,9 +904,9 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, } -static int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm, - struct sk_buff *beacon, - void *data, int len) +int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm, + struct sk_buff *beacon, + void *data, int len) { struct iwl_host_cmd cmd = { .id = BEACON_TEMPLATE_CMD, @@ -1088,13 +1009,16 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, sizeof(beacon_cmd)); } -static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct sk_buff *beacon) +int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon) { if (WARN_ON(!beacon)) return -EINVAL; + if (IWL_MVM_NON_TRANSMITTING_AP) + return 0; + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) return iwl_mvm_mac_ctxt_send_beacon_v6(mvm, vif, beacon); @@ -1120,6 +1044,11 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, if (!beacon) return -ENOMEM; +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvm->beacon_inject_active) + return -EBUSY; +#endif + ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon); dev_kfree_skb(beacon); return ret; @@ -1182,18 +1111,16 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, IWL_DEBUG_HC(mvm, "No need to receive beacons\n"); } + if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) + cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); + ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int); - ctxt_ap->bi_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); ctxt_ap->dtim_interval = cpu_to_le32(vif->bss_conf.beacon_int * vif->bss_conf.dtim_period); - ctxt_ap->dtim_reciprocal = - cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int * - vif->bss_conf.dtim_period)); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) - ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue); + ctxt_ap->mcast_qid = cpu_to_le32(mvmvif->cab_queue); /* * Only set the beacon time when the MAC is being added, when we @@ -1410,7 +1337,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; - struct iwl_mvm_tx_resp *beacon_notify_hdr; + struct iwl_extended_beacon_notif_v5 *beacon_v5 = (void *)pkt->data; struct ieee80211_vif *csa_vif; struct ieee80211_vif *tx_blocked_vif; struct agg_tx_status *agg_status; @@ -1418,18 +1345,29 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - beacon_notify_hdr = &beacon->beacon_notify_hdr; mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); - mvm->ibss_manager = beacon->ibss_mgr_status != 0; - agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); - status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; - IWL_DEBUG_RX(mvm, - "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", - status, beacon_notify_hdr->failure_frame, - le64_to_cpu(beacon->tsf), - mvm->ap_last_beacon_gp2, - le32_to_cpu(beacon_notify_hdr->initial_rate)); + if (!iwl_mvm_is_short_beacon_notif_supported(mvm)) { + struct iwl_mvm_tx_resp *beacon_notify_hdr = + &beacon_v5->beacon_notify_hdr; + + mvm->ibss_manager = beacon_v5->ibss_mgr_status != 0; + agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr); + status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK; + IWL_DEBUG_RX(mvm, + "beacon status %#x retries:%d tsf:0x%016llX gp2:0x%X rate:%d\n", + status, beacon_notify_hdr->failure_frame, + le64_to_cpu(beacon->tsf), + mvm->ap_last_beacon_gp2, + le32_to_cpu(beacon_notify_hdr->initial_rate)); + } else { + mvm->ibss_manager = beacon->ibss_mgr_status != 0; + status = le32_to_cpu(beacon->status) & TX_STATUS_MSK; + IWL_DEBUG_RX(mvm, + "beacon status %#x tsf:0x%016llX gp2:0x%X\n", + status, le64_to_cpu(beacon->tsf), + mvm->ap_last_beacon_gp2); + } csa_vif = rcu_dereference_protected(mvm->csa_vif, lockdep_is_held(&mvm->mutex)); @@ -1462,35 +1400,48 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, } } -static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { - struct iwl_missed_beacons_notif *missed_beacons = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_missed_beacons_notif *mb = (void *)pkt->data; struct iwl_fw_dbg_trigger_missed_bcon *bcon_trig; struct iwl_fw_dbg_trigger_tlv *trigger; u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx; u32 rx_missed_bcon, rx_missed_bcon_since_rx; + struct ieee80211_vif *vif; + u32 id = le32_to_cpu(mb->mac_id); - if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id)) - return; + IWL_DEBUG_INFO(mvm, + "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", + le32_to_cpu(mb->mac_id), + le32_to_cpu(mb->consec_missed_beacons), + le32_to_cpu(mb->consec_missed_beacons_since_last_rx), + le32_to_cpu(mb->num_recvd_beacons), + le32_to_cpu(mb->num_expected_beacons)); - rx_missed_bcon = le32_to_cpu(missed_beacons->consec_missed_beacons); + rcu_read_lock(); + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + if (!vif) + goto out; + + rx_missed_bcon = le32_to_cpu(mb->consec_missed_beacons); rx_missed_bcon_since_rx = - le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx); + le32_to_cpu(mb->consec_missed_beacons_since_last_rx); /* * TODO: the threshold should be adjusted based on latency conditions, * and/or in case of a CS flow on one of the other AP vifs. */ - if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) > - IWL_MVM_MISSED_BEACONS_THRESHOLD) + if (rx_missed_bcon > IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG) + iwl_mvm_connection_loss(mvm, vif, "missed beacons"); + else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) ieee80211_beacon_loss(vif); trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), FW_DBG_TRIGGER_MISSED_BEACONS); if (!trigger) - return; + goto out; bcon_trig = (void *)trigger->data; stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon); @@ -1502,26 +1453,11 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx || rx_missed_bcon >= stop_trig_missed_bcon) iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL); -} - -void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_missed_beacons_notif *mb = (void *)pkt->data; - IWL_DEBUG_INFO(mvm, - "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", - le32_to_cpu(mb->mac_id), - le32_to_cpu(mb->consec_missed_beacons), - le32_to_cpu(mb->consec_missed_beacons_since_last_rx), - le32_to_cpu(mb->num_recvd_beacons), - le32_to_cpu(mb->num_expected_beacons)); + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_MISSED_BEACONS); - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_beacon_loss_iterator, - mb); +out: + rcu_read_unlock(); } void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, @@ -1563,16 +1499,29 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm, ieee80211_rx_napi(mvm->hw, NULL, skb, NULL); } -static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac, - struct ieee80211_vif *vif) +void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { - struct iwl_probe_resp_data_notif *notif = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_probe_resp_data_notif *notif = (void *)pkt->data; struct iwl_probe_resp_data *old_data, *new_data; + int len = iwl_rx_packet_payload_len(pkt); + u32 id = le32_to_cpu(notif->mac_id); + struct ieee80211_vif *vif; + struct iwl_mvm_vif *mvmvif; + + if (WARN_ON_ONCE(len < sizeof(*notif))) + return; + + IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n", + notif->noa_active, notif->csa_counter); - if (mvmvif->id != (u16)le32_to_cpu(notif->mac_id)) + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); + if (!vif) return; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); if (!new_data) return; @@ -1603,66 +1552,63 @@ static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac, ieee80211_csa_set_counter(vif, notif->csa_counter); } -void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_probe_resp_data_notif *notif = (void *)pkt->data; - int len = iwl_rx_packet_payload_len(pkt); - - if (WARN_ON_ONCE(len < sizeof(*notif))) - return; - - IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n", - notif->noa_active, notif->csa_counter); - - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_ACTIVE, - iwl_mvm_probe_resp_data_iter, - notif); -} - void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data; - struct ieee80211_vif *csa_vif; + struct ieee80211_vif *csa_vif, *vif; struct iwl_mvm_vif *mvmvif; int len = iwl_rx_packet_payload_len(pkt); - u32 id_n_color; + u32 id_n_color, csa_id, mac_id; if (WARN_ON_ONCE(len < sizeof(*notif))) return; - rcu_read_lock(); - - csa_vif = rcu_dereference(mvm->csa_vif); - if (WARN_ON(!csa_vif || !csa_vif->csa_active)) - goto out_unlock; - id_n_color = le32_to_cpu(notif->id_and_color); + mac_id = id_n_color & FW_CTXT_ID_MSK; + + if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER)) + return; - mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); - if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color, - "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", - FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color)) - goto out_unlock; + rcu_read_lock(); + vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]); - IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n"); + switch (vif->type) { + case NL80211_IFTYPE_AP: + csa_vif = rcu_dereference(mvm->csa_vif); + if (WARN_ON(!csa_vif || !csa_vif->csa_active || + csa_vif != vif)) + goto out_unlock; - schedule_delayed_work(&mvm->cs_tx_unblock_dwork, - msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * - csa_vif->bss_conf.beacon_int)); + mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); + csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); + if (WARN(csa_id != id_n_color, + "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", + csa_id, id_n_color)) + goto out_unlock; - ieee80211_csa_finish(csa_vif); + IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n"); - rcu_read_unlock(); + schedule_delayed_work(&mvm->cs_tx_unblock_dwork, + msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT * + csa_vif->bss_conf.beacon_int)); - RCU_INIT_POINTER(mvm->csa_vif, NULL); + ieee80211_csa_finish(csa_vif); - return; + rcu_read_unlock(); + RCU_INIT_POINTER(mvm->csa_vif, NULL); + return; + case NL80211_IFTYPE_STATION: + iwl_mvm_csa_client_absent(mvm, vif); + ieee80211_chswitch_done(vif, true); + break; + default: + /* should never happen */ + WARN_ON_ONCE(1); + break; + } out_unlock: rcu_read_unlock(); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 00f831d88366..6a3b11dd2edf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -184,6 +184,29 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = { }; #endif +static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = { + .max_peers = IWL_MVM_TOF_MAX_APS, + .report_ap_tsf = 1, + .randomize_mac_addr = 1, + + .ftm = { + .supported = 1, + .asap = 1, + .non_asap = 1, + .request_lci = 1, + .request_civicloc = 1, + .max_bursts_exponent = -1, /* all supported */ + .max_ftms_per_burst = 0, /* no limits */ + .bandwidths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), + .preambles = BIT(NL80211_PREAMBLE_LEGACY) | + BIT(NL80211_PREAMBLE_HT) | + BIT(NL80211_PREAMBLE_VHT), + }, +}; + void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) { if (!iwl_mvm_is_d0i3_supported(mvm)) @@ -395,6 +418,21 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) return ret; } +const static u8 he_if_types_ext_capa_sta[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, + [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, +}; + +const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { + { + .iftype = NL80211_IFTYPE_STATION, + .extended_capabilities = he_if_types_ext_capa_sta, + .extended_capabilities_mask = he_if_types_ext_capa_sta, + .extended_capabilities_len = sizeof(he_if_types_ext_capa_sta), + }, +}; + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) { struct ieee80211_hw *hw = mvm->hw; @@ -405,12 +443,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, }; +#ifdef CONFIG_PM_SLEEP + bool unified = fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); +#endif /* Tell mac80211 our characteristics */ ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, SPECTRUM_MGMT); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(hw, QUEUE_CONTROL); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); @@ -423,6 +464,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP); + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + ieee80211_hw_set(hw, BUFF_MMPDU_TXQ); + ieee80211_hw_set(hw, STA_MMPDU_TXQ); + ieee80211_hw_set(hw, TX_AMSDU); + ieee80211_hw_set(hw, TX_FRAG_LIST); if (iwl_mvm_has_tlc_offload(mvm)) { ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); @@ -468,6 +514,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES; hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; + hw->max_tx_fragments = mvm->trans->max_skb_frags; BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6); memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers)); @@ -524,6 +571,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->n_cipher_suites++; } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FTM_CALIBRATED)) { + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); + hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa; + } + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); hw->wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | @@ -533,6 +587,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->sta_data_size = sizeof(struct iwl_mvm_sta); hw->vif_data_size = sizeof(struct iwl_mvm_vif); hw->chanctx_data_size = sizeof(u16); + hw->txq_data_size = sizeof(struct iwl_mvm_txq); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | @@ -672,6 +727,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); } + if (mvm->nvm_data->sku_cap_11ax_enable && + !iwlwifi_mod_params.disable_11ax) { + hw->wiphy->iftype_ext_capab = he_iftypes_ext_capa; + hw->wiphy->num_iftype_ext_capab = + ARRAY_SIZE(he_iftypes_ext_capa); + } + mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; #ifdef CONFIG_PM_SLEEP @@ -681,7 +743,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->wowlan = &mvm->wowlan; } - if (mvm->fw->img[IWL_UCODE_WOWLAN].num_sec && + if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) && mvm->trans->ops->d3_suspend && mvm->trans->ops->d3_resume && device_can_wakeup(mvm->trans->dev)) { @@ -734,15 +796,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->netdev_features |= IWL_TX_CSUM_NETIF_FLAGS; } - ret = ieee80211_register_hw(mvm->hw); - if (ret) - iwl_mvm_leds_exit(mvm); - mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; - if (mvm->cfg->vht_mu_mimo_supported) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + ret = ieee80211_register_hw(mvm->hw); + if (ret) { + iwl_mvm_leds_exit(mvm); + } + return ret; } @@ -775,7 +837,6 @@ static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm, goto out; __skb_queue_tail(&mvm->d0i3_tx, skb); - ieee80211_stop_queues(mvm->hw); /* trigger wakeup */ iwl_mvm_ref(mvm, IWL_MVM_REF_TX); @@ -795,13 +856,15 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, struct ieee80211_sta *sta = control->sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; + bool offchannel = IEEE80211_SKB_CB(skb)->flags & + IEEE80211_TX_CTL_TX_OFFCHAN; if (iwl_mvm_is_radio_killed(mvm)) { IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); goto drop; } - if (info->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && + if (offchannel && !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; @@ -813,6 +876,21 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) sta = NULL; + /* If there is no sta, and it's not offchannel - send through AP */ + if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION && + !offchannel) { + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(info->control.vif); + u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id); + + if (ap_sta_id < IWL_MVM_STATION_COUNT) { + /* mac80211 holds rcu read lock */ + sta = rcu_dereference(mvm->fw_id_to_mac_id[ap_sta_id]); + if (IS_ERR_OR_NULL(sta)) + goto drop; + } + } + if (sta) { if (iwl_mvm_defer_tx(mvm, sta, skb)) return; @@ -828,22 +906,101 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, ieee80211_free_txskb(hw, skb); } -static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg) +void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG) - return false; - return true; + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq); + struct sk_buff *skb = NULL; + + /* + * No need for threads to be pending here, they can leave the first + * taker all the work. + * + * mvmtxq->tx_request logic: + * + * If 0, no one is currently TXing, set to 1 to indicate current thread + * will now start TX and other threads should quit. + * + * If 1, another thread is currently TXing, set to 2 to indicate to + * that thread that there was another request. Since that request may + * have raced with the check whether the queue is empty, the TXing + * thread should check the queue's status one more time before leaving. + * This check is done in order to not leave any TX hanging in the queue + * until the next TX invocation (which may not even happen). + * + * If 2, another thread is currently TXing, and it will already double + * check the queue, so do nothing. + */ + if (atomic_fetch_add_unless(&mvmtxq->tx_request, 1, 2)) + return; + + rcu_read_lock(); + do { + while (likely(!mvmtxq->stopped && + (mvm->trans->system_pm_mode == + IWL_PLAT_PM_MODE_DISABLED))) { + skb = ieee80211_tx_dequeue(hw, txq); + + if (!skb) { + if (txq->sta) + IWL_DEBUG_TX(mvm, + "TXQ of sta %pM tid %d is now empty\n", + txq->sta->addr, + txq->tid); + break; + } + + if (!txq->sta) + iwl_mvm_tx_skb_non_sta(mvm, skb); + else + iwl_mvm_tx_skb(mvm, skb, txq->sta); + } + } while (atomic_dec_return(&mvmtxq->tx_request)); + rcu_read_unlock(); } -static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) +static void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) { - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) - return false; - if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG) - return true; + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq); - /* enabled by default */ - return true; + /* + * Please note that racing is handled very carefully here: + * mvmtxq->txq_id is updated during allocation, and mvmtxq->list is + * deleted afterwards. + * This means that if: + * mvmtxq->txq_id != INVALID_QUEUE && list_empty(&mvmtxq->list): + * queue is allocated and we can TX. + * mvmtxq->txq_id != INVALID_QUEUE && !list_empty(&mvmtxq->list): + * a race, should defer the frame. + * mvmtxq->txq_id == INVALID_QUEUE && list_empty(&mvmtxq->list): + * need to allocate the queue and defer the frame. + * mvmtxq->txq_id == INVALID_QUEUE && !list_empty(&mvmtxq->list): + * queue is already scheduled for allocation, no need to allocate, + * should defer the frame. + */ + + /* If the queue is allocated TX and return. */ + if (!txq->sta || mvmtxq->txq_id != IWL_MVM_INVALID_QUEUE) { + /* + * Check that list is empty to avoid a race where txq_id is + * already updated, but the queue allocation work wasn't + * finished + */ + if (unlikely(txq->sta && !list_empty(&mvmtxq->list))) + return; + + iwl_mvm_mac_itxq_xmit(hw, txq); + return; + } + + /* The list is being deleted only after the queue is fully allocated. */ + if (!list_empty(&mvmtxq->list)) + return; + + list_add_tail(&mvmtxq->list, &mvm->add_stream_txqs); + schedule_work(&mvm->add_stream_wk); } #define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \ @@ -958,7 +1115,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); cancel_delayed_work(&mvmvif->uapsd_nonagg_detected_wk); } - if (!iwl_enable_rx_ampdu(mvm->cfg)) { + if (!iwl_enable_rx_ampdu()) { ret = -EINVAL; break; } @@ -970,7 +1127,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, timeout); break; case IEEE80211_AMPDU_TX_START: - if (!iwl_enable_tx_ampdu(mvm->cfg)) { + if (!iwl_enable_tx_ampdu()) { ret = -EINVAL; break; } @@ -1050,6 +1207,8 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_stop_device(mvm); + mvm->cur_aid = 0; + mvm->scan_status = 0; mvm->ps_disabled = false; mvm->calibrating = false; @@ -1058,6 +1217,8 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_cleanup_roc_te(mvm); ieee80211_remain_on_channel_expired(mvm->hw); + iwl_mvm_ftm_restart(mvm); + /* * cleanup all interfaces, even inactive ones, as some might have * gone down during the HW restart @@ -1069,7 +1230,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames)); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -1113,6 +1273,8 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) } ret = iwl_mvm_up(mvm); + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_POST_INIT); + if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { /* Something went wrong - we need to finish some cleanup * that normally iwl_mvm_mac_restart_complete() below @@ -1170,6 +1332,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) /* allow transport/FW low power modes */ iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); + iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_END_OF_RECOVERY); + /* * If we have TDLS peers, remove them. We don't know the last seqno/PN * of packets the FW sent out, so we must reconnect. @@ -1373,6 +1537,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_unlock; + rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); + /* Counting number of interfaces is needed for legacy PM */ if (vif->type != NL80211_IFTYPE_P2P_DEVICE) mvm->vif_count++; @@ -1531,6 +1697,9 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI); } + if (vif->bss_conf.ftm_responder) + memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats)); + iwl_mvm_vif_dbgfs_clean(mvm, vif); /* @@ -1564,6 +1733,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, iwl_mvm_power_update_mac(mvm); iwl_mvm_mac_ctxt_remove(mvm, vif); + RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL); + if (vif->type == NL80211_IFTYPE_MONITOR) mvm->monitor_on = false; @@ -2005,7 +2176,13 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, if (sta->he_cap.he_cap_elem.mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BQR_SUPP); - /* If PPE Thresholds exist, parse them into a FW-familiar format */ + /* + * Initialize the PPE thresholds to "None" (7), as described in Table + * 9-262ac of 80211.ax/D3.0. + */ + memset(&sta_ctxt_cmd.pkt_ext, 7, sizeof(sta_ctxt_cmd.pkt_ext)); + + /* If PPE Thresholds exist, parse them into a FW-familiar format. */ if (sta->he_cap.he_cap_elem.phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { u8 nss = (sta->he_cap.ppe_thres[0] & @@ -2052,6 +2229,46 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, } flags |= STA_CTXT_HE_PACKET_EXT; + } else if ((sta->he_cap.he_cap_elem.phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) != + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED) { + int low_th = -1; + int high_th = -1; + + /* Take the PPE thresholds from the nominal padding info */ + switch (sta->he_cap.he_cap_elem.phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) { + case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US: + low_th = IWL_HE_PKT_EXT_NONE; + high_th = IWL_HE_PKT_EXT_NONE; + break; + case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US: + low_th = IWL_HE_PKT_EXT_BPSK; + high_th = IWL_HE_PKT_EXT_NONE; + break; + case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US: + low_th = IWL_HE_PKT_EXT_NONE; + high_th = IWL_HE_PKT_EXT_BPSK; + break; + } + + /* Set the PPE thresholds accordingly */ + if (low_th >= 0 && high_th >= 0) { + u8 ***pkt_ext_qam = + (void *)sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th; + + for (i = 0; i < MAX_HE_SUPP_NSS; i++) { + u8 bw; + + for (bw = 0; bw < MAX_HE_CHANNEL_BW_INDX; + bw++) { + pkt_ext_qam[i][bw][0] = low_th; + pkt_ext_qam[i][bw][1] = high_th; + } + } + + flags |= STA_CTXT_HE_PACKET_EXT; + } } rcu_read_unlock(); @@ -2122,6 +2339,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); } + /* Update MU EDCA params */ + if (changes & BSS_CHANGED_QOS && mvmvif->associated && + bss_conf->assoc && vif->bss_conf.he_support && + !iwlwifi_mod_params.disable_11ax) + iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id); + /* * If we're not associated yet, take the (new) BSSID before associating * so the firmware knows. If we're already associated, then use the old @@ -2187,7 +2410,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * If update fails - SF might be running in associated * mode while disassociated - which is forbidden. */ - WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false), + ret = iwl_mvm_sf_update(mvm, vif, false); + WARN_ONCE(ret && + !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status), "Failed to update SF upon disassociation\n"); /* @@ -2383,6 +2609,12 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, /* must be set before quota calculations */ mvmvif->ap_ibss_active = true; + if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) { + iwl_mvm_vif_set_low_latency(mvmvif, true, + LOW_LATENCY_VIF_TYPE); + iwl_mvm_send_low_latency_cmd(mvm, true, mvmvif->id); + } + /* power updated needs to be done before quotas */ iwl_mvm_power_update_mac(mvm); @@ -2402,6 +2634,8 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); + iwl_mvm_ftm_restart_responder(mvm, vif); + goto out_unlock; out_quota_failed: @@ -2445,6 +2679,12 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, mvmvif->ap_ibss_active = false; mvm->ap_last_beacon_gp2 = 0; + if (vif->type == NL80211_IFTYPE_AP && !vif->p2p) { + iwl_mvm_vif_set_low_latency(mvmvif, false, + LOW_LATENCY_VIF_TYPE); + iwl_mvm_send_low_latency_cmd(mvm, false, mvmvif->id); + } + iwl_mvm_bt_coex_vif_change(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_AP_IBSS); @@ -2474,9 +2714,6 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_remove(mvm, vif); - kfree(mvmvif->ap_wep_key); - mvmvif->ap_wep_key = NULL; - mutex_unlock(&mvm->mutex); } @@ -2507,6 +2744,15 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, bss_conf->txpower); iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); } + + if (changes & BSS_CHANGED_FTM_RESPONDER) { + int ret = iwl_mvm_ftm_start_responder(mvm, vif); + + if (ret) + IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", + ret); + } + } static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, @@ -2636,7 +2882,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, return; spin_lock_bh(&mvmsta->lock); - for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { + for (tid = 0; tid < ARRAY_SIZE(mvmsta->tid_data); tid++) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE) @@ -2825,32 +3071,6 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm, peer_addr, action); } -static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta) -{ - struct iwl_mvm_tid_data *tid_data; - struct sk_buff *skb; - int i; - - spin_lock_bh(&mvm_sta->lock); - for (i = 0; i <= IWL_MAX_TID_COUNT; i++) { - tid_data = &mvm_sta->tid_data[i]; - - while ((skb = __skb_dequeue(&tid_data->deferred_tx_frames))) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - /* - * The first deferred frame should've stopped the MAC - * queues, so we should never get a second deferred - * frame for the RA/TID. - */ - iwl_mvm_start_mac_queues(mvm, BIT(info->hw_queue)); - ieee80211_free_txskb(mvm->hw, skb); - } - } - spin_unlock_bh(&mvm_sta->lock); -} - static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2884,7 +3104,6 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, */ if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) { - iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta); flush_work(&mvm->add_stream_wk); /* @@ -2931,6 +3150,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr, NL80211_TDLS_SETUP); } + + sta->max_rc_amsdu_len = 1; } else if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_AUTH) { /* @@ -2943,8 +3164,15 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { if (vif->type == NL80211_IFTYPE_AP) { + vif->bss_conf.he_support = sta->he_cap.has_he; mvmvif->ap_assoc_sta_count++; iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + if (vif->bss_conf.he_support && + !iwlwifi_mod_params.disable_11ax) + iwl_mvm_cfg_he_sta(mvm, vif, mvm_sta->sta_id); + } else if (vif->type == NL80211_IFTYPE_STATION) { + vif->bss_conf.he_support = sta->he_cap.has_he; + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); } iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, @@ -2952,6 +3180,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, ret = iwl_mvm_update_sta(mvm, vif, sta); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { + ret = 0; /* we don't support TDLS during DCM */ if (iwl_mvm_phy_ctx_count(mvm) > 1) @@ -2966,18 +3195,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, true); - - /* if wep is used, need to set the key for the station now */ - if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key) - ret = iwl_mvm_set_sta_key(mvm, vif, sta, - mvmvif->ap_wep_key, - STA_KEY_IDX_INVALID); - else - ret = 0; } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { /* disable beacon filtering */ - WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, 0)); + ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + WARN_ON(ret && + !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status)); ret = 0; } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) { @@ -2997,6 +3221,11 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr, NL80211_TDLS_DISABLE_LINK); } + + if (unlikely(ret && + test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status))) + ret = 0; } else { ret = -EIO; } @@ -3029,6 +3258,13 @@ static void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 changed) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (changed & (IEEE80211_RC_BW_CHANGED | + IEEE80211_RC_SUPP_RATES_CHANGED | + IEEE80211_RC_NSS_CHANGED)) + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, + true); if (vif->type == NL80211_IFTYPE_STATION && changed & IEEE80211_RC_NSS_CHANGED) @@ -3179,20 +3415,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - if (vif->type == NL80211_IFTYPE_AP) { - struct iwl_mvm_vif *mvmvif = - iwl_mvm_vif_from_mac80211(vif); - - mvmvif->ap_wep_key = kmemdup(key, - sizeof(*key) + key->keylen, - GFP_KERNEL); - if (!mvmvif->ap_wep_key) - return -ENOMEM; - } - - if (vif->type != NL80211_IFTYPE_STATION) - return 0; - break; + if (vif->type == NL80211_IFTYPE_STATION) + break; + if (iwl_mvm_has_new_tx_api(mvm)) + return -EOPNOTSUPP; + /* support HW crypto on TX */ + return 0; default: /* currently FW supports only one optional cipher scheme */ if (hw->n_cipher_schemes && @@ -3280,12 +3508,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset); if (ret) { IWL_WARN(mvm, "set key failed\n"); + key->hw_key_idx = STA_KEY_IDX_INVALID; /* * can't add key for RX, but we don't need it - * in the device for TX so still return 0 + * in the device for TX so still return 0, + * unless we have new TX API where we cannot + * put key material into the TX_CMD */ - key->hw_key_idx = STA_KEY_IDX_INVALID; - ret = 0; + if (iwl_mvm_has_new_tx_api(mvm)) + ret = -EOPNOTSUPP; + else + ret = 0; } break; @@ -3355,7 +3588,7 @@ static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait, resp = (void *)pkt->data; IWL_DEBUG_TE(mvm, - "Aux ROC: Recieved response from ucode: status=%d uid=%d\n", + "Aux ROC: Received response from ucode: status=%d uid=%d\n", resp->status, resp->event_unique_id); te_data->uid = le32_to_cpu(resp->event_unique_id); @@ -3392,14 +3625,20 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, .id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)), .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id), - /* Set the channel info data */ - .channel_info.band = (channel->band == NL80211_BAND_2GHZ) ? - PHY_BAND_24 : PHY_BAND_5, - .channel_info.channel = channel->hw_value, - .channel_info.width = PHY_VHT_CHANNEL_MODE20, - /* Set the time and duration */ - .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)), - }; + }; + struct iwl_hs20_roc_req_tail *tail = iwl_mvm_chan_info_cmd_tail(mvm, + &aux_roc_req.channel_info); + u16 len = sizeof(aux_roc_req) - iwl_mvm_chan_info_padding(mvm); + + /* Set the channel info data */ + iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value, + (channel->band == NL80211_BAND_2GHZ) ? + PHY_BAND_24 : PHY_BAND_5, + PHY_VHT_CHANNEL_MODE20, + 0); + + /* Set the time and duration */ + tail->apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)); delay = AUX_ROC_MIN_DELAY; req_dur = MSEC_TO_TU(duration); @@ -3424,15 +3663,15 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, } } - aux_roc_req.duration = cpu_to_le32(req_dur); - aux_roc_req.apply_time_max_delay = cpu_to_le32(delay); + tail->duration = cpu_to_le32(req_dur); + tail->apply_time_max_delay = cpu_to_le32(delay); IWL_DEBUG_TE(mvm, "ROC: Requesting to remain on channel %u for %ums (requested = %ums, max_delay = %ums, dtim_interval = %ums)\n", channel->hw_value, req_dur, duration, delay, dtim_interval); /* Set the node address */ - memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN); + memcpy(tail->node_addr, vif->addr, ETH_ALEN); lockdep_assert_held(&mvm->mutex); @@ -3463,7 +3702,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, ARRAY_SIZE(time_event_response), iwl_mvm_rx_aux_roc, te_data); - res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req), + res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, len, &aux_roc_req); if (res) { @@ -3634,11 +3873,43 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) return 0; } +struct iwl_mvm_ftm_responder_iter_data { + bool responder; + struct ieee80211_chanctx_conf *ctx; +}; + +static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_ftm_responder_iter_data *data = _data; + + if (rcu_access_pointer(vif->chanctx_conf) == data->ctx && + vif->type == NL80211_IFTYPE_AP && vif->bss_conf.ftmr_params) + data->responder = true; +} + +static bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm, + struct ieee80211_chanctx_conf *ctx) +{ + struct iwl_mvm_ftm_responder_iter_data data = { + .responder = false, + .ctx = ctx, + }; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_ftm_responder_chanctx_iter, + &data); + return data.responder; +} + static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, struct ieee80211_chanctx_conf *ctx) { u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt; + bool responder = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx); + struct cfg80211_chan_def *def = responder ? &ctx->def : &ctx->min_def; int ret; lockdep_assert_held(&mvm->mutex); @@ -3651,7 +3922,7 @@ static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm, goto out; } - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, ctx->rx_chains_static, ctx->rx_chains_dynamic); if (ret) { @@ -3706,6 +3977,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; + bool responder = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx); + struct cfg80211_chan_def *def = responder ? &ctx->def : &ctx->min_def; if (WARN_ONCE((phy_ctxt->ref > 1) && (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | @@ -3720,17 +3993,17 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, /* we are only changing the min_width, may be a noop */ if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) { - if (phy_ctxt->width == ctx->min_def.width) + if (phy_ctxt->width == def->width) goto out_unlock; /* we are just toggling between 20_NOHT and 20 */ if (phy_ctxt->width <= NL80211_CHAN_WIDTH_20 && - ctx->min_def.width <= NL80211_CHAN_WIDTH_20) + def->width <= NL80211_CHAN_WIDTH_20) goto out_unlock; } iwl_mvm_bt_coex_vif_change(mvm); - iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def, + iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def, ctx->rx_chains_static, ctx->rx_chains_dynamic); @@ -3759,6 +4032,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, mvmvif->ap_ibss_active = true; break; } + /* fall through */ case NL80211_IFTYPE_ADHOC: /* * The AP binding flow is handled as part of the start_ap flow @@ -3811,25 +4085,30 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, } if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) { - u32 duration = 3 * vif->bss_conf.beacon_int; + mvmvif->csa_bcn_pending = true; - /* iwl_mvm_protect_session() reads directly from the - * device (the system time), so make sure it is - * available. - */ - ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA); - if (ret) - goto out_remove_binding; + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) { + u32 duration = 3 * vif->bss_conf.beacon_int; - /* Protect the session to make sure we hear the first - * beacon on the new channel. - */ - mvmvif->csa_bcn_pending = true; - iwl_mvm_protect_session(mvm, vif, duration, duration, - vif->bss_conf.beacon_int / 2, - true); - iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); + /* iwl_mvm_protect_session() reads directly from the + * device (the system time), so make sure it is + * available. + */ + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA); + if (ret) + goto out_remove_binding; + + /* Protect the session to make sure we hear the first + * beacon on the new channel. + */ + iwl_mvm_protect_session(mvm, vif, duration, duration, + vif->bss_conf.beacon_int / 2, + true); + + iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); + } iwl_mvm_update_quotas(mvm, false, NULL); } @@ -3899,7 +4178,9 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, disabled_vif = vif; - iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) + iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); break; default: break; @@ -4150,6 +4431,27 @@ static void iwl_mvm_channel_switch(struct ieee80211_hw *hw, "dummy channel switch op\n"); } +static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_chan_switch_te_cmd cmd = { + .mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .tsf = cpu_to_le32(chsw->timestamp), + .cs_count = chsw->count, + }; + + lockdep_assert_held(&mvm->mutex); + + return iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(MAC_CONF_GROUP, + CHANNEL_SWITCH_TIME_EVENT_CMD), + 0, sizeof(cmd), &cmd); +} + static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw) @@ -4217,14 +4519,19 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, if (chsw->block_tx) iwl_mvm_csa_client_absent(mvm, vif); - iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int, - apply_time); if (mvmvif->bf_data.bf_enabled) { ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); if (ret) goto out_unlock; } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) + iwl_mvm_schedule_client_csa(mvm, vif, chsw); + else + iwl_mvm_schedule_csa_period(mvm, vif, + vif->bss_conf.beacon_int, + apply_time); break; default: break; @@ -4617,8 +4924,89 @@ static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw) mutex_unlock(&mvm->mutex); } +static int +iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_ftm_responder_stats *stats) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (vif->p2p || vif->type != NL80211_IFTYPE_AP || + !mvmvif->ap_ibss_active || !vif->bss_conf.ftm_responder) + return -EINVAL; + + mutex_lock(&mvm->mutex); + *stats = mvm->ftm_resp_stats; + mutex_unlock(&mvm->mutex); + + stats->filled = BIT(NL80211_FTM_STATS_SUCCESS_NUM) | + BIT(NL80211_FTM_STATS_PARTIAL_NUM) | + BIT(NL80211_FTM_STATS_FAILED_NUM) | + BIT(NL80211_FTM_STATS_ASAP_NUM) | + BIT(NL80211_FTM_STATS_NON_ASAP_NUM) | + BIT(NL80211_FTM_STATS_TOTAL_DURATION_MSEC) | + BIT(NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM) | + BIT(NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM) | + BIT(NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM); + + return 0; +} + +static int iwl_mvm_start_pmsr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_ftm_start(mvm, vif, request); + mutex_unlock(&mvm->mutex); + + return ret; +} + +static void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + mutex_lock(&mvm->mutex); + iwl_mvm_ftm_abort(mvm, request); + mutex_unlock(&mvm->mutex); +} + +static bool iwl_mvm_can_hw_csum(struct sk_buff *skb) +{ + u8 protocol = ip_hdr(skb)->protocol; + + if (!IS_ENABLED(CONFIG_INET)) + return false; + + return protocol == IPPROTO_TCP || protocol == IPPROTO_UDP; +} + +static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw, + struct sk_buff *head, + struct sk_buff *skb) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + /* For now don't aggregate IPv6 in AMSDU */ + if (skb->protocol != htons(ETH_P_IP)) + return false; + + if (!iwl_mvm_is_csum_supported(mvm)) + return true; + + return iwl_mvm_can_hw_csum(skb) == iwl_mvm_can_hw_csum(head); +} + const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, + .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, .ampdu_action = iwl_mvm_mac_ampdu_action, .start = iwl_mvm_mac_start, .reconfig_complete = iwl_mvm_mac_reconfig_complete, @@ -4692,6 +5080,11 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { #endif .get_survey = iwl_mvm_mac_get_survey, .sta_statistics = iwl_mvm_mac_sta_statistics, + .get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats, + .start_pmsr = iwl_mvm_start_pmsr, + .abort_pmsr = iwl_mvm_abort_pmsr, + + .can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate, #ifdef CONFIG_IWLWIFI_DEBUGFS .sta_add_debugfs = iwl_mvm_sta_add_debugfs, #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7ba5bc2ed1c4..a50dc53df086 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -83,7 +83,6 @@ #include "sta.h" #include "fw-api.h" #include "constants.h" -#include "tof.h" #include "fw/runtime.h" #include "fw/dbg.h" #include "fw/acpi.h" @@ -95,6 +94,8 @@ /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 +#define IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG 16 + /* A TimeUnit is 1024 microsecond */ #define MSEC_TO_TU(_msec) (_msec*1000/1024) @@ -299,15 +300,38 @@ enum iwl_bt_force_ant_mode { }; /** + * struct iwl_mvm_low_latency_force - low latency force mode set by debugfs + * @LOW_LATENCY_FORCE_UNSET: unset force mode + * @LOW_LATENCY_FORCE_ON: for low latency on + * @LOW_LATENCY_FORCE_OFF: for low latency off + * @NUM_LOW_LATENCY_FORCE: max num of modes + */ +enum iwl_mvm_low_latency_force { + LOW_LATENCY_FORCE_UNSET, + LOW_LATENCY_FORCE_ON, + LOW_LATENCY_FORCE_OFF, + NUM_LOW_LATENCY_FORCE +}; + +/** * struct iwl_mvm_low_latency_cause - low latency set causes * @LOW_LATENCY_TRAFFIC: indicates low latency traffic was detected * @LOW_LATENCY_DEBUGFS: low latency mode set from debugfs * @LOW_LATENCY_VCMD: low latency mode set from vendor command +* @LOW_LATENCY_VIF_TYPE: low latency mode set because of vif type (ap) +* @LOW_LATENCY_DEBUGFS_FORCE_ENABLE: indicate that force mode is enabled +* the actual set/unset is done with LOW_LATENCY_DEBUGFS_FORCE +* @LOW_LATENCY_DEBUGFS_FORCE: low latency force mode from debugfs +* set this with LOW_LATENCY_DEBUGFS_FORCE_ENABLE flag +* in low_latency. */ enum iwl_mvm_low_latency_cause { LOW_LATENCY_TRAFFIC = BIT(0), LOW_LATENCY_DEBUGFS = BIT(1), LOW_LATENCY_VCMD = BIT(2), + LOW_LATENCY_VIF_TYPE = BIT(3), + LOW_LATENCY_DEBUGFS_FORCE_ENABLE = BIT(4), + LOW_LATENCY_DEBUGFS_FORCE = BIT(5), }; /** @@ -358,8 +382,10 @@ struct iwl_probe_resp_data { * @pm_enabled - Indicate if MAC power management is allowed * @monitor_active: indicates that monitor context is configured, and that the * interface should get quota etc. - * @low_latency: indicates low latency is set, see - * enum &iwl_mvm_low_latency_cause for causes. + * @low_latency: bit flags for low latency + * see enum &iwl_mvm_low_latency_cause for causes. + * @low_latency_actual: boolean, indicates low latency is set, + * as a result from low_latency bit flags and takes force into account. * @ps_disabled: indicates that this interface requires PS to be disabled * @queue_params: QoS params for this MAC * @bcast_sta: station used for broadcast packets. Used by the following @@ -391,7 +417,8 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; - u8 low_latency; + u8 low_latency: 6; + u8 low_latency_actual: 1; bool ps_disabled; struct iwl_mvm_vif_bf_data bf_data; @@ -471,7 +498,6 @@ struct iwl_mvm_vif { netdev_features_t features; struct iwl_probe_resp_data __rcu *probe_resp_data; - struct ieee80211_key_conf *ap_wep_key; }; static inline struct iwl_mvm_vif * @@ -776,6 +802,39 @@ struct iwl_mvm_geo_profile { u8 values[ACPI_GEO_TABLE_SIZE]; }; +struct iwl_mvm_txq { + struct list_head list; + u16 txq_id; + atomic_t tx_request; + bool stopped; +}; + +static inline struct iwl_mvm_txq * +iwl_mvm_txq_from_mac80211(struct ieee80211_txq *txq) +{ + return (void *)txq->drv_priv; +} + +static inline struct iwl_mvm_txq * +iwl_mvm_txq_from_tid(struct ieee80211_sta *sta, u8 tid) +{ + if (tid == IWL_MAX_TID_COUNT) + tid = IEEE80211_NUM_TIDS; + + return (void *)sta->txq[tid]->drv_priv; +} + +/** + * struct iwl_mvm_tvqm_txq_info - maps TVQM hw queue to tid + * + * @sta_id: sta id + * @txq_tid: txq tid + */ +struct iwl_mvm_tvqm_txq_info { + u8 sta_id; + u8 txq_tid; +}; + struct iwl_mvm_dqa_txq_info { u8 ra_sta_id; /* The RA this queue is mapped to, if exists */ bool reserved; /* Is this the TXQ reserved for a STA */ @@ -819,9 +878,6 @@ struct iwl_mvm { bool hw_registered; bool calibrating; - u32 error_event_table[2]; - u32 log_event_table; - u32 umac_error_event_table; bool support_umac_log; u32 ampdu_ref; @@ -841,14 +897,13 @@ struct iwl_mvm { u64 on_time_scan; } radio_stats, accu_radio_stats; - u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES]; - - struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES]; - spinlock_t queue_info_lock; /* For syncing queue mgmt operations */ + struct list_head add_stream_txqs; + union { + struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES]; + struct iwl_mvm_tvqm_txq_info tvqm_info[IWL_MAX_TVQM_QUEUES]; + }; struct work_struct add_stream_wk; /* To add streams to queues */ - atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; - const char *nvm_file_name; struct iwl_nvm_data *nvm_data; /* NVM sections */ @@ -862,7 +917,6 @@ struct iwl_mvm { /* data related to data path */ struct iwl_rx_phy_info last_phy_info; struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; - unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; u8 rx_ba_sessions; /* configured by mac80211 */ @@ -923,6 +977,7 @@ struct iwl_mvm { u32 dbgfs_prph_reg_addr; bool disable_power_off; bool disable_power_off_d3; + bool beacon_inject_active; bool scan_iter_notif_enabled; @@ -931,6 +986,7 @@ struct iwl_mvm { struct debugfs_blob_wrapper nvm_calib_blob; struct debugfs_blob_wrapper nvm_prod_blob; struct debugfs_blob_wrapper nvm_phy_sku_blob; + struct debugfs_blob_wrapper nvm_reg_blob; struct iwl_mvm_frame_stats drv_rx_stats; spinlock_t drv_stats_lock; @@ -954,9 +1010,11 @@ struct iwl_mvm { u8 refs[IWL_MVM_REF_COUNT]; u8 vif_count; + struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER]; /* -1 for always, 0 for never, >0 for that many times */ s8 fw_restart; + u8 *error_recovery_buf; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -1046,6 +1104,8 @@ struct iwl_mvm { /* Indicate if device power save is allowed */ u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */ + /* Indicate if 32Khz external clock is valid */ + u32 ext_clock_valid; unsigned int max_amsdu_len; /* used for debugfs only */ struct ieee80211_vif __rcu *csa_vif; @@ -1089,7 +1149,14 @@ struct iwl_mvm { u32 ciphers[IWL_MVM_NUM_CIPHERS]; struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; - struct iwl_mvm_tof_data tof_data; + + struct cfg80211_ftm_responder_stats ftm_resp_stats; + struct { + struct cfg80211_pmsr_request *req; + struct wireless_dev *req_wdev; + struct list_head loc_list; + int responses[IWL_MVM_TOF_MAX_APS]; + } ftm_initiator; struct ieee80211_vif *nan_vif; #define IWL_MAX_BAID 32 @@ -1105,6 +1172,11 @@ struct iwl_mvm { /* does a monitor vif exist (only one can exist hence bool) */ bool monitor_on; + + /* sniffer data to include in radiotap */ + __le16 cur_aid; + u8 cur_bssid[ETH_ALEN]; + #ifdef CONFIG_ACPI struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES]; @@ -1148,8 +1220,6 @@ enum iwl_mvm_status { enum iwl_mvm_init_status { IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0), IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1), - IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2), - IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3), }; static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) @@ -1206,6 +1276,19 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) return iwl_mvm_sta_from_mac80211(sta); } +static inline struct ieee80211_vif * +iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu) +{ + if (WARN_ON(vif_id >= ARRAY_SIZE(mvm->vif_id_to_mac))) + return NULL; + + if (rcu) + return rcu_dereference(mvm->vif_id_to_mac[vif_id]); + + return rcu_dereference_protected(mvm->vif_id_to_mac[vif_id], + lockdep_is_held(&mvm->mutex)); +} + static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) { return !iwlwifi_mod_params.d0i3_disable && @@ -1236,6 +1319,12 @@ static inline bool iwl_mvm_is_frag_ebs_supported(struct iwl_mvm *mvm) return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAG_EBS); } +static inline bool iwl_mvm_is_short_beacon_notif_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SHORT_BEACON_NOTIF); +} + static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) { /* For now we only use this mode to differentiate between @@ -1469,6 +1558,11 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc); +void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); +unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + unsigned int tid); + #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_mvm_get_tx_fail_reason(u32 status); #else @@ -1521,6 +1615,11 @@ static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm) mvm->fw->valid_rx_ant; } +static inline void iwl_mvm_toggle_tx_ant(struct iwl_mvm *mvm, u8 *ant) +{ + *ant = iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), *ant); +} + static inline u32 iwl_mvm_get_phy_config(struct iwl_mvm *mvm) { u32 phy_config = ~(FW_PHY_CFG_TX_CHAIN | @@ -1550,6 +1649,8 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); +void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, @@ -1559,6 +1660,7 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags); void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); @@ -1591,9 +1693,19 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off, const u8 *bssid_override); int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon); +int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm, + struct sk_buff *beacon, + void *data, int len); +u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, + struct ieee80211_vif *vif); +void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm, + __le32 *tim_index, __le32 *tim_size, + u8 *beacon, u32 frame_size); void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, @@ -1607,8 +1719,6 @@ void iwl_mvm_window_status_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, - struct ieee80211_vif *exclude_vif); void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, @@ -1846,6 +1956,8 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* get SystemLowLatencyMode - only needed for beacon threshold? */ bool iwl_mvm_low_latency(struct iwl_mvm *mvm); bool iwl_mvm_low_latency_band(struct iwl_mvm *mvm, enum nl80211_band band); +void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm, bool low_latency, + u16 mac_id); /* get VMACLowLatencyMode */ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) @@ -1860,17 +1972,43 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) * binding, so this has no real impact. For now, just return * the current desired low-latency state. */ - return mvmvif->low_latency; + return mvmvif->low_latency_actual; } static inline void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set, enum iwl_mvm_low_latency_cause cause) { + u8 new_state; + if (set) mvmvif->low_latency |= cause; else mvmvif->low_latency &= ~cause; + + /* + * if LOW_LATENCY_DEBUGFS_FORCE_ENABLE is enabled no changes are + * allowed to actual mode. + */ + if (mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE_ENABLE && + cause != LOW_LATENCY_DEBUGFS_FORCE_ENABLE) + return; + + if (cause == LOW_LATENCY_DEBUGFS_FORCE_ENABLE && set) + /* + * We enter force state + */ + new_state = !!(mvmvif->low_latency & + LOW_LATENCY_DEBUGFS_FORCE); + else + /* + * Check if any other one set low latency + */ + new_state = !!(mvmvif->low_latency & + ~(LOW_LATENCY_DEBUGFS_FORCE_ENABLE | + LOW_LATENCY_DEBUGFS_FORCE)); + + mvmvif->low_latency_actual = new_state; } /* Return a bitmask with all the hw supported queues, except for the @@ -1885,21 +2023,24 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { lockdep_assert_held(&mvm->mutex); - /* calling this function without using dump_start/end since at this - * point we already hold the op mode mutex + /* If IWL_MVM_STATUS_HW_RESTART_REQUESTED bit is set then we received + * an assert. Since we failed to bring the interface up, mac80211 + * will not attempt to reconfig the device, + * which handles the dump collection in assert flow, + * so trigger dump collection here. */ - iwl_fw_dbg_collect_sync(&mvm->fwrt); + if (test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status)) + iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, + false, 0); + iwl_fw_cancel_timestamp(&mvm->fwrt); - iwl_free_fw_paging(&mvm->fwrt); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); + iwl_fwrt_stop_device(&mvm->fwrt); + iwl_free_fw_paging(&mvm->fwrt); iwl_fw_dump_conf_clear(&mvm->fwrt); - iwl_trans_stop_device(mvm->trans); } -/* Stop/start all mac queues in a given bitmap */ -void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq); -void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq); - /* Re-configure the SCD for a queue that has already been configured */ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn); @@ -1939,6 +2080,23 @@ void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm); int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); +/* FTM responder */ +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); + +/* FTM initiator */ +void iwl_mvm_ftm_restart(struct iwl_mvm *mvm); +void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *request); +void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req); + /* TDLS */ /* @@ -2005,4 +2163,59 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct dentry *dir); #endif +/* Channel info utils */ +static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) +{ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS); +} + +static inline void *iwl_mvm_chan_info_cmd_tail(struct iwl_mvm *mvm, + struct iwl_fw_channel_info *ci) +{ + return (u8 *)ci + (iwl_mvm_has_ultra_hb_channel(mvm) ? + sizeof(struct iwl_fw_channel_info) : + sizeof(struct iwl_fw_channel_info_v1)); +} + +static inline size_t iwl_mvm_chan_info_padding(struct iwl_mvm *mvm) +{ + return iwl_mvm_has_ultra_hb_channel(mvm) ? 0 : + sizeof(struct iwl_fw_channel_info) - + sizeof(struct iwl_fw_channel_info_v1); +} + +static inline void iwl_mvm_set_chan_info(struct iwl_mvm *mvm, + struct iwl_fw_channel_info *ci, + u32 chan, u8 band, u8 width, + u8 ctrl_pos) +{ + if (iwl_mvm_has_ultra_hb_channel(mvm)) { + ci->channel = cpu_to_le32(chan); + ci->band = band; + ci->width = width; + ci->ctrl_pos = ctrl_pos; + } else { + struct iwl_fw_channel_info_v1 *ci_v1 = + (struct iwl_fw_channel_info_v1 *)ci; + + ci_v1->channel = chan; + ci_v1->band = band; + ci_v1->width = width; + ci_v1->ctrl_pos = ctrl_pos; + } +} + +static inline void +iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm, + struct iwl_fw_channel_info *ci, + struct cfg80211_chan_def *chandef) +{ + iwl_mvm_set_chan_info(mvm, ci, chandef->chan->hw_value, + (chandef->chan->band == NL80211_BAND_2GHZ ? + PHY_BAND_24 : PHY_BAND_5), + iwl_mvm_get_channel_width(chandef), + iwl_mvm_get_ctrl_pos(chandef)); +} + #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 6fc5cc1f2b5b..7bdbd010ae6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -179,7 +179,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM access command failed with status %d (device: %s)\n", ret, mvm->cfg->name); - ret = -EIO; + ret = -ENODATA; } goto exit; } @@ -380,8 +380,12 @@ int iwl_nvm_init(struct iwl_mvm *mvm) /* we override the constness for initial read */ ret = iwl_nvm_read_section(mvm, section, nvm_buffer, size_read); - if (ret < 0) + if (ret == -ENODATA) { + ret = 0; continue; + } + if (ret < 0) + break; size_read += ret; temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); if (!temp) { @@ -412,6 +416,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm) mvm->nvm_phy_sku_blob.data = temp; mvm->nvm_phy_sku_blob.size = ret; break; + case NVM_SECTION_TYPE_REGULATORY_SDP: + case NVM_SECTION_TYPE_REGULATORY: + mvm->nvm_reg_blob.data = temp; + mvm->nvm_reg_blob.size = ret; + break; default: if (section == mvm->cfg->nvm_hw_section_num) { mvm->nvm_hw_blob.data = temp; @@ -454,7 +463,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n", mvm->nvm_data->nvm_version); - return 0; + return ret < 0 ? ret : 0; } struct iwl_mcc_update_resp * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index af3fba10abc1..13681b03c10e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -82,7 +82,6 @@ #include "fw/api/scan.h" #include "time-event.h" #include "fw-api.h" -#include "fw/api/scan.h" #include "fw/acpi.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" @@ -301,8 +300,14 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, RX_HANDLER_SYNC), - RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, - RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER_GRP(LOCATION_GROUP, TOF_RESPONDER_STATS, + iwl_mvm_ftm_responder_stats, RX_HANDLER_ASYNC_LOCKED), + + RX_HANDLER_GRP(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, + iwl_mvm_ftm_range_resp, RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER_GRP(LOCATION_GROUP, TOF_LC_NOTIF, + iwl_mvm_ftm_lc_notif, RX_HANDLER_ASYNC_LOCKED), + RX_HANDLER_GRP(DEBUG_GROUP, MFU_ASSERT_DUMP_NTF, iwl_mvm_mfu_assert_dump_notif, RX_HANDLER_SYNC), RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF, @@ -329,8 +334,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_REQ_UMAC), HCMD_NAME(SCAN_ABORT_UMAC), HCMD_NAME(SCAN_COMPLETE_UMAC), - HCMD_NAME(TOF_CMD), - HCMD_NAME(TOF_NOTIFICATION), HCMD_NAME(BA_WINDOW_STATUS_NOTIFICATION_ID), HCMD_NAME(ADD_STA_KEY), HCMD_NAME(ADD_STA), @@ -419,12 +422,14 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { static const struct iwl_hcmd_names iwl_mvm_system_names[] = { HCMD_NAME(SHARED_MEM_CFG_CMD), HCMD_NAME(INIT_EXTENDED_CFG_CMD), + HCMD_NAME(FW_ERROR_RECOVERY_CMD), }; /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { + HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF), }; @@ -449,6 +454,8 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD), HCMD_NAME(STA_HE_CTXT_CMD), HCMD_NAME(RFH_QUEUE_CONFIG_CMD), + HCMD_NAME(TLC_MNG_CONFIG_CMD), + HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), @@ -464,6 +471,22 @@ static const struct iwl_hcmd_names iwl_mvm_debug_names[] = { /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ +static const struct iwl_hcmd_names iwl_mvm_location_names[] = { + HCMD_NAME(TOF_RANGE_REQ_CMD), + HCMD_NAME(TOF_CONFIG_CMD), + HCMD_NAME(TOF_RANGE_ABORT_CMD), + HCMD_NAME(TOF_RANGE_REQ_EXT_CMD), + HCMD_NAME(TOF_RESPONDER_CONFIG_CMD), + HCMD_NAME(TOF_RESPONDER_DYN_CONFIG_CMD), + HCMD_NAME(TOF_LC_NOTIF), + HCMD_NAME(TOF_RESPONDER_STATS), + HCMD_NAME(TOF_MCSI_DEBUG_NOTIF), + HCMD_NAME(TOF_RANGE_RESPONSE_NOTIF), +}; + +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = { HCMD_NAME(STORED_BEACON_NTF), }; @@ -483,6 +506,7 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { [MAC_CONF_GROUP] = HCMD_ARR(iwl_mvm_mac_conf_names), [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names), [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names), + [LOCATION_GROUP] = HCMD_ARR(iwl_mvm_location_names), [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names), [REGULATORY_AND_NVM_GROUP] = HCMD_ARR(iwl_mvm_regulatory_and_nvm_names), @@ -577,11 +601,17 @@ static int iwl_mvm_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd) return ret; } +static bool iwl_mvm_d3_debug_enable(void *ctx) +{ + return IWL_MVM_D3_DEBUG; +} + static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .dump_start = iwl_mvm_fwrt_dump_start, .dump_end = iwl_mvm_fwrt_dump_end, .fw_running = iwl_mvm_fwrt_fw_running, .send_hcmd = iwl_mvm_fwrt_send_hcmd, + .d3_debug_enable = iwl_mvm_d3_debug_enable, }; static struct iwl_op_mode * @@ -676,7 +706,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_LIST_HEAD(&mvm->aux_roc_te_list); INIT_LIST_HEAD(&mvm->async_handlers_list); spin_lock_init(&mvm->time_event_lock); - spin_lock_init(&mvm->queue_info_lock); + INIT_LIST_HEAD(&mvm->ftm_initiator.loc_list); INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); @@ -686,6 +716,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); + INIT_LIST_HEAD(&mvm->add_stream_txqs); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); @@ -737,6 +768,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.rx_buf_size = rb_size_default; } + BUILD_BUG_ON(sizeof(struct iwl_ldbg_config_cmd) != + LDBG_CFG_COMMAND_SIZE); + trans->wide_cmd_header = true; trans_cfg.bc_table_dword = mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560; @@ -770,7 +804,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, memcpy(trans->dbg_conf_tlv, mvm->fw->dbg.conf_tlv, sizeof(trans->dbg_conf_tlv)); trans->dbg_trigger_tlv = mvm->fw->dbg.trigger_tlv; - trans->dbg_dump_mask = mvm->fw->dbg.dump_mask; trans->iml = mvm->fw->iml; trans->iml_len = mvm->fw->iml_len; @@ -801,8 +834,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mutex_lock(&mvm->mutex); iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE); err = iwl_run_init_mvm_ucode(mvm, true); - if (test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status)) - iwl_fw_alive_error_dump(&mvm->fwrt); + if (err && err != -ERFKILL) + iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER); if (!iwlmvm_mod_params.init_dbg || !err) iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); @@ -844,7 +877,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (iwl_mvm_is_d0i3_supported(mvm)) iwl_trans_unref(mvm->trans); - iwl_mvm_tof_init(mvm); + iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); return op_mode; @@ -886,15 +919,15 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) iwl_mvm_thermal_exit(mvm); - if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) { - ieee80211_unregister_hw(mvm->hw); - mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE; - } + ieee80211_unregister_hw(mvm->hw); kfree(mvm->scan_cmd); kfree(mvm->mcast_filter_cmd); mvm->mcast_filter_cmd = NULL; + kfree(mvm->error_recovery_buf); + mvm->error_recovery_buf = NULL; + #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) kfree(mvm->d3_resume_sram); #endif @@ -909,8 +942,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) cancel_delayed_work_sync(&mvm->tcm.work); - iwl_mvm_tof_clean(mvm); - iwl_fw_runtime_free(&mvm->fwrt); mutex_destroy(&mvm->mutex); mutex_destroy(&mvm->d0i3_suspend_mutex); @@ -1073,28 +1104,12 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, iwl_mvm_rx_queue_notif(mvm, rxb, 0); else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)) iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); + else if (cmd == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF)) + iwl_mvm_rx_monitor_ndp(mvm, napi, rxb, 0); else iwl_mvm_rx_common(mvm, rxb, pkt); } -void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq) -{ - int q; - - if (WARN_ON_ONCE(!mq)) - return; - - for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { - if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) { - IWL_DEBUG_TX_QUEUES(mvm, - "mac80211 %d already stopped\n", q); - continue; - } - - ieee80211_stop_queue(mvm->hw, q); - } -} - static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, const struct iwl_device_cmd *cmd) { @@ -1107,46 +1122,81 @@ static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode, iwl_trans_block_txq_ptrs(mvm->trans, false); } -static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) +static int iwl_mvm_is_static_queue(struct iwl_mvm *mvm, int queue) { - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - unsigned long mq; - - spin_lock_bh(&mvm->queue_info_lock); - mq = mvm->hw_queue_to_mac80211[hw_queue]; - spin_unlock_bh(&mvm->queue_info_lock); - - iwl_mvm_stop_mac_queues(mvm, mq); + return queue == mvm->aux_queue || queue == mvm->probe_queue || + queue == mvm->p2p_dev_queue || queue == mvm->snif_queue; } -void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq) +static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode, + int hw_queue, bool start) { - int q; + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + struct ieee80211_sta *sta; + struct ieee80211_txq *txq; + struct iwl_mvm_txq *mvmtxq; + int i; + unsigned long tid_bitmap; + struct iwl_mvm_sta *mvmsta; + u8 sta_id; - if (WARN_ON_ONCE(!mq)) + sta_id = iwl_mvm_has_new_tx_api(mvm) ? + mvm->tvqm_info[hw_queue].sta_id : + mvm->queue_info[hw_queue].ra_sta_id; + + if (WARN_ON_ONCE(sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) return; - for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) { - if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) { - IWL_DEBUG_TX_QUEUES(mvm, - "mac80211 %d still stopped\n", q); - continue; - } + rcu_read_lock(); + + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (IS_ERR_OR_NULL(sta)) + goto out; + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + if (iwl_mvm_is_static_queue(mvm, hw_queue)) { + if (!start) + ieee80211_stop_queues(mvm->hw); + else if (mvmsta->sta_state != IEEE80211_STA_NOTEXIST) + ieee80211_wake_queues(mvm->hw); + + goto out; + } + + if (iwl_mvm_has_new_tx_api(mvm)) { + int tid = mvm->tvqm_info[hw_queue].txq_tid; + + tid_bitmap = BIT(tid); + } else { + tid_bitmap = mvm->queue_info[hw_queue].tid_bitmap; + } + + for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + int tid = i; + + if (tid == IWL_MAX_TID_COUNT) + tid = IEEE80211_NUM_TIDS; + + txq = sta->txq[tid]; + mvmtxq = iwl_mvm_txq_from_mac80211(txq); + mvmtxq->stopped = !start; - ieee80211_wake_queue(mvm->hw, q); + if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) + iwl_mvm_mac_itxq_xmit(mvm->hw, txq); } + +out: + rcu_read_unlock(); } -static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) +static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) { - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - unsigned long mq; - - spin_lock_bh(&mvm->queue_info_lock); - mq = mvm->hw_queue_to_mac80211[hw_queue]; - spin_unlock_bh(&mvm->queue_info_lock); + iwl_mvm_queue_state_change(op_mode, hw_queue, false); +} - iwl_mvm_start_mac_queues(mvm, mq); +static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue) +{ + iwl_mvm_queue_state_change(op_mode, hw_queue, true); } static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm) @@ -1242,7 +1292,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) */ if (!mvm->fw_restart && fw_error) { iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, - NULL, 0); + false, 0); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; @@ -1267,12 +1317,29 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); + } else if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, + &mvm->status)) { + IWL_ERR(mvm, "HW restart already requested, but not started\n"); } else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && mvm->hw_registered && !test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); + if (mvm->fw->ucode_capa.error_log_size) { + u32 src_size = mvm->fw->ucode_capa.error_log_size; + u32 src_addr = mvm->fw->ucode_capa.error_log_addr; + u8 *recover_buf = kzalloc(src_size, GFP_ATOMIC); + + if (recover_buf) { + mvm->error_recovery_buf = recover_buf; + iwl_trans_read_mem_bytes(mvm->trans, + src_addr, + recover_buf, + src_size); + } + } + if (fw_error && mvm->fw_restart > 0) mvm->fw_restart--; set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 7f5434b34d0d..86e40bae57e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -109,6 +109,7 @@ u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef) return PHY_VHT_CTRL_POS_4_ABOVE; default: WARN(1, "Invalid channel definition"); + /* fall through */ case 0: /* * The FW is expected to check the control channel position only @@ -143,14 +144,11 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, u8 chains_static, u8 chains_dynamic) { u8 active_cnt, idle_cnt; + struct iwl_phy_context_cmd_tail *tail = + iwl_mvm_chan_info_cmd_tail(mvm, &cmd->ci); /* Set the channel info data */ - cmd->ci.band = (chandef->chan->band == NL80211_BAND_2GHZ ? - PHY_BAND_24 : PHY_BAND_5); - - cmd->ci.channel = chandef->chan->hw_value; - cmd->ci.width = iwl_mvm_get_channel_width(chandef); - cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); + iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); /* Set rx the chains */ idle_cnt = chains_static; @@ -168,17 +166,17 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, active_cnt = 2; } - cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << + tail->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); - cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); - cmd->rxchain_info |= cpu_to_le32(active_cnt << + tail->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); + tail->rxchain_info |= cpu_to_le32(active_cnt << PHY_RX_CHAIN_MIMO_CNT_POS); #ifdef CONFIG_IWLWIFI_DEBUGFS if (unlikely(mvm->dbgfs_rx_phyinfo)) - cmd->rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo); + tail->rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo); #endif - cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); + tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); } /* @@ -195,6 +193,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, { struct iwl_phy_context_cmd cmd; int ret; + u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm); /* Set the command header fields */ iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time); @@ -203,9 +202,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, chains_static, chains_dynamic); - ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, - sizeof(struct iwl_phy_context_cmd), - &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, len, &cmd); if (ret) IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 5a0a28fd762d..36f5fa1ee793 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -79,6 +81,8 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, struct iwl_beacon_filter_cmd *cmd, u32 flags) { + u16 len; + IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", le32_to_cpu(cmd->ba_enable_beacon_abort)); IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", @@ -101,9 +105,23 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, le32_to_cpu(cmd->bf_temp_fast_filter)); IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", le32_to_cpu(cmd->bf_temp_slow_filter)); + IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_low is: %d, %d\n", + le32_to_cpu(cmd->bf_threshold_absolute_low[0]), + le32_to_cpu(cmd->bf_threshold_absolute_low[1])); + + IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_high is: %d, %d\n", + le32_to_cpu(cmd->bf_threshold_absolute_high[0]), + le32_to_cpu(cmd->bf_threshold_absolute_high[1])); + + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BEACON_FILTER_V4)) + len = sizeof(struct iwl_beacon_filter_cmd); + else + len = offsetof(struct iwl_beacon_filter_cmd, + bf_threshold_absolute_low); return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, - sizeof(struct iwl_beacon_filter_cmd), cmd); + len, cmd); } static @@ -526,6 +544,9 @@ int iwl_mvm_power_update_device(struct iwl_mvm *mvm) cmd.flags &= cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif + if (mvm->ext_clock_valid) + cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK); + IWL_DEBUG_POWER(mvm, "Sending device power command with flags = 0x%X\n", cmd.flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 7a98e1a1dc40..a28283ff7295 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -98,8 +98,12 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta) { struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; u8 supp = 0; + if (he_cap && he_cap->has_he) + return 0; + if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) supp |= BIT(IWL_TLC_MNG_CH_WIDTH_20MHZ); if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) @@ -145,14 +149,9 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm, if (he_cap && he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[3] & - IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK)) { + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK)) flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK; - if (he_cap->he_cap_elem.phy_cap_info[3] & - IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2) - flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK; - } - return flags; } @@ -316,12 +315,26 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) { u16 size = le32_to_cpu(notif->amsdu_size); + int i; if (WARN_ON(sta->max_amsdu_len < size)) goto out; mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); mvmsta->max_amsdu_len = size; + sta->max_rc_amsdu_len = mvmsta->max_amsdu_len; + + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + if (mvmsta->amsdu_enabled & BIT(i)) + sta->max_tid_amsdu_len[i] = + iwl_mvm_max_amsdu_size(mvm, sta, i); + else + /* + * Not so elegant, but this will effectively + * prevent AMSDU on this TID + */ + sta->max_tid_amsdu_len[i] = 1; + } IWL_DEBUG_RATE(mvm, "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 089972280daa..e231a44d2423 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -3,7 +3,7 @@ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -1643,8 +1643,26 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta) { + struct ieee80211_sta_vht_cap *sta_vht_cap = &sta->vht_cap; + struct ieee80211_vht_cap vht_cap = { + .vht_cap_info = cpu_to_le32(sta_vht_cap->cap), + .supp_mcs = sta_vht_cap->vht_mcs, + }; + switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_160: + /* + * Don't use 160 MHz if VHT extended NSS support + * says we cannot use 2 streams, we don't want to + * deal with this. + * We only check MCS 0 - they will support that if + * we got here at all and we don't care which MCS, + * we want to determine a more global state. + */ + if (ieee80211_get_vht_max_nss(&vht_cap, + IEEE80211_VHT_CHANWIDTH_160MHZ, + 0, true) < sta->rx_nss) + return RATE_MCS_CHAN_WIDTH_80; return RATE_MCS_CHAN_WIDTH_160; case IEEE80211_STA_RX_BW_80: return RATE_MCS_CHAN_WIDTH_80; @@ -1744,6 +1762,7 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum rs_action scale_action) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + int i; /* * In case TLC offload is not active amsdu_enabled is either 0xFFFF @@ -1756,7 +1775,25 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, else mvmsta->amsdu_enabled = 0xFFFF; - mvmsta->max_amsdu_len = sta->max_amsdu_len; + if (mvmsta->vif->bss_conf.he_support && + !iwlwifi_mod_params.disable_11ax) + mvmsta->max_amsdu_len = sta->max_amsdu_len; + else + mvmsta->max_amsdu_len = min_t(int, sta->max_amsdu_len, 8500); + + sta->max_rc_amsdu_len = mvmsta->max_amsdu_len; + + for (i = 0; i < IWL_MAX_TID_COUNT; i++) { + if (mvmsta->amsdu_enabled) + sta->max_tid_amsdu_len[i] = + iwl_mvm_max_amsdu_size(mvm, sta, i); + else + /* + * Not so elegant, but this will effectively + * prevent AMSDU on this TID + */ + sta->max_tid_amsdu_len[i] = 1; + } } /* @@ -1777,7 +1814,7 @@ static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm, struct iwl_scale_tbl_info *tbl, enum rs_action scale_action) { - if (sta->bandwidth != IEEE80211_STA_RX_BW_80) + if (rs_bw_from_sta_bw(sta) != RATE_MCS_CHAN_WIDTH_80) return false; if (!is_vht_siso(&tbl->rate)) @@ -3332,12 +3369,12 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm, /* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI * column the rate table should look like this: * - * rate[0] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI - * rate[1] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI - * rate[2] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI - * rate[3] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI - * rate[4] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI - * rate[5] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI + * rate[0] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI + * rate[1] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI + * rate[2] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI + * rate[3] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI + * rate[4] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI + * rate[5] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI * rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI * rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI * rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI @@ -4108,6 +4145,7 @@ static const struct rate_control_ops rs_mvm_ops_drv = { .add_sta_debugfs = rs_drv_add_sta_debugfs, .remove_sta_debugfs = rs_remove_sta_debugfs, #endif + .capa = RATE_CTRL_CAPA_VHT_EXT_NSS_BW, }; void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index ef624833cf1b..fbd3014e8b82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -222,7 +222,7 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, !(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK)) return 0; *crypt_len = IEEE80211_TKIP_IV_LEN; - /* fall through if TTAK OK */ + /* fall through */ case RX_MPDU_RES_STATUS_SEC_WEP_ENC: if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK)) @@ -593,31 +593,28 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, int hyst = vif->bss_conf.cqm_rssi_hyst; u16 id = le32_to_cpu(data->mac_id); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u16 vif_id = mvmvif->id; /* This doesn't need the MAC ID check since it's not taking the * data copied into the "data" struct, but rather the data from * the notification directly. */ - if (data->general) { - u16 vif_id = mvmvif->id; - - if (iwl_mvm_is_cdb_supported(mvm)) { - struct mvm_statistics_general_cdb *general = - data->general; - - mvmvif->beacon_stats.num_beacons = - le32_to_cpu(general->beacon_counter[vif_id]); - mvmvif->beacon_stats.avg_signal = - -general->beacon_average_energy[vif_id]; - } else { - struct mvm_statistics_general_v8 *general = - data->general; - - mvmvif->beacon_stats.num_beacons = - le32_to_cpu(general->beacon_counter[vif_id]); - mvmvif->beacon_stats.avg_signal = - -general->beacon_average_energy[vif_id]; - } + if (iwl_mvm_has_new_rx_stats_api(mvm)) { + struct mvm_statistics_general *general = + data->general; + + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(general->beacon_counter[vif_id]); + mvmvif->beacon_stats.avg_signal = + -general->beacon_average_energy[vif_id]; + } else { + struct mvm_statistics_general_v8 *general = + data->general; + + mvmvif->beacon_stats.num_beacons = + le32_to_cpu(general->beacon_counter[vif_id]); + mvmvif->beacon_stats.avg_signal = + -general->beacon_average_energy[vif_id]; } if (mvmvif->id != id) @@ -726,7 +723,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, else expected_size = sizeof(struct iwl_notif_statistics_v10); } else { - expected_size = sizeof(struct iwl_notif_statistics_cdb); + expected_size = sizeof(struct iwl_notif_statistics); } if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) != expected_size, @@ -756,7 +753,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, flags = stats->flag; } else { - struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + struct iwl_notif_statistics *stats = (void *)&pkt->data; data.mac_id = stats->rx.general.mac_id; data.beacon_filter_average_energy = @@ -795,7 +792,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, bytes = (void *)&v11->load_stats.byte_count; air_time = (void *)&v11->load_stats.air_time; } else { - struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data; + struct iwl_notif_statistics *stats = (void *)&pkt->data; energy = (void *)&stats->load_stats.avg_energy; bytes = (void *)&stats->load_stats.byte_count; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 26ac9402568d..b516fd1867ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -66,11 +66,37 @@ #include "mvm.h" #include "fw-api.h" +static void *iwl_mvm_skb_get_hdr(struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u8 *data = skb->data; + + /* Alignment concerns */ + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4); + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4); + BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) % 4); + BUILD_BUG_ON(sizeof(struct ieee80211_vendor_radiotap) % 4); + + if (rx_status->flag & RX_FLAG_RADIOTAP_HE) + data += sizeof(struct ieee80211_radiotap_he); + if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU) + data += sizeof(struct ieee80211_radiotap_he_mu); + if (rx_status->flag & RX_FLAG_RADIOTAP_LSIG) + data += sizeof(struct ieee80211_radiotap_lsig); + if (rx_status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { + struct ieee80211_vendor_radiotap *radiotap = (void *)data; + + data += sizeof(*radiotap) + radiotap->len + radiotap->pad; + } + + return data; +} + static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, int queue, struct ieee80211_sta *sta) { struct iwl_mvm_sta *mvmsta; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb); struct iwl_mvm_key_pn *ptk_pn; int res; @@ -143,9 +169,9 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, } /* iwl_mvm_create_skb Adds the rxb to a new skb */ -static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, - u16 len, u8 crypt_len, - struct iwl_rx_cmd_buffer *rxb) +static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; @@ -178,6 +204,20 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, * present before copying packet data. */ hdrlen += crypt_len; + + if (WARN_ONCE(headlen < hdrlen, + "invalid packet lengths (hdrlen=%d, len=%d, crypt_len=%d)\n", + hdrlen, len, crypt_len)) { + /* + * We warn and trace because we want to be able to see + * it in trace-cmd as well. + */ + IWL_DEBUG_RX(mvm, + "invalid packet lengths (hdrlen=%d, len=%d, crypt_len=%d)\n", + hdrlen, len, crypt_len); + return -EINVAL; + } + skb_put_data(skb, hdr, hdrlen); skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); @@ -190,28 +230,54 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } + + return 0; +} + +static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_vendor_radiotap *radiotap; + const int size = sizeof(*radiotap) + sizeof(__le16); + + if (!mvm->cur_aid) + return; + + /* ensure alignment */ + BUILD_BUG_ON((size + 2) % 4); + + radiotap = skb_put(skb, size + 2); + radiotap->align = 1; + /* Intel OUI */ + radiotap->oui[0] = 0xf6; + radiotap->oui[1] = 0x54; + radiotap->oui[2] = 0x25; + /* radiotap sniffer config sub-namespace */ + radiotap->subns = 1; + radiotap->present = 0x1; + radiotap->len = size - sizeof(*radiotap); + radiotap->pad = 2; + + /* fill the data now */ + memcpy(radiotap->data, &mvm->cur_aid, sizeof(mvm->cur_aid)); + /* and clear the padding */ + memset(radiotap->data + sizeof(__le16), 0, radiotap->pad); + + rx_status->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA; } /* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb, int queue, - struct ieee80211_sta *sta) + struct ieee80211_sta *sta, + bool csi) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - - if (iwl_mvm_check_pn(mvm, skb, queue, sta)) { + if (iwl_mvm_check_pn(mvm, skb, queue, sta)) kfree_skb(skb); - } else { - unsigned int radiotap_len = 0; - - if (rx_status->flag & RX_FLAG_RADIOTAP_HE) - radiotap_len += sizeof(struct ieee80211_radiotap_he); - if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU) - radiotap_len += sizeof(struct ieee80211_radiotap_he_mu); - __skb_push(skb, radiotap_len); + else ieee80211_rx_napi(mvm->hw, sta, skb, napi); - } } static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, @@ -288,7 +354,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, stats->flag |= RX_FLAG_MMIC_ERROR; *crypt_len = IEEE80211_TKIP_IV_LEN; - /* fall through if TTAK OK */ + /* fall through */ case IWL_RX_MPDU_STATUS_SEC_WEP: if (!(status & IWL_RX_MPDU_STATUS_ICV_OK)) return -1; @@ -472,7 +538,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, while ((skb = __skb_dequeue(skb_list))) { iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, reorder_buf->queue, - sta); + sta, false); reorder_buf->num_stored--; } } @@ -641,7 +707,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_rx_mpdu_desc *desc) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_baid_data *baid_data; struct iwl_mvm_reorder_buffer *buffer; @@ -665,6 +731,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * This also covers the case of receiving a Block Ack Request * outside a BA session; we'll pass it to mac80211 and that * then sends a delBA action frame. + * This also covers pure monitor mode, in which case we won't + * have any BA sessions. */ if (baid == IWL_RX_REORDER_DATA_INVALID_BAID) return false; @@ -863,68 +931,66 @@ static void iwl_mvm_flip_address(u8 *addr) ether_addr_copy(addr, mac_addr); } -static void iwl_mvm_decode_he_sigb(struct iwl_mvm *mvm, - struct iwl_rx_mpdu_desc *desc, - u32 rate_n_flags, - struct ieee80211_radiotap_he_mu *he_mu) -{ - u32 sigb0, sigb1; - u16 sigb2; +struct iwl_mvm_rx_phy_data { + enum iwl_rx_phy_info_type info_type; + __le32 d0, d1, d2, d3; + __le16 d4; +}; - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { - sigb0 = le32_to_cpu(desc->v3.sigb_common0); - sigb1 = le32_to_cpu(desc->v3.sigb_common1); - } else { - sigb0 = le32_to_cpu(desc->v1.sigb_common0); - sigb1 = le32_to_cpu(desc->v1.sigb_common1); - } - - sigb2 = le16_to_cpu(desc->sigb_common2); +static void iwl_mvm_decode_he_mu_ext(struct iwl_mvm *mvm, + struct iwl_mvm_rx_phy_data *phy_data, + u32 rate_n_flags, + struct ieee80211_radiotap_he_mu *he_mu) +{ + u32 phy_data2 = le32_to_cpu(phy_data->d2); + u32 phy_data3 = le32_to_cpu(phy_data->d3); + u16 phy_data4 = le16_to_cpu(phy_data->d4); - if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK, sigb2)) { + if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK, phy_data4)) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN); he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU, - sigb2), + le16_encode_bits(FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU, + phy_data4), IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU); - he_mu->ru_ch1[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU0, - sigb0); - he_mu->ru_ch1[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU1, - sigb1); - he_mu->ru_ch1[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH1_RU2, - sigb0); - he_mu->ru_ch1[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH1_RU3, - sigb1); + he_mu->ru_ch1[0] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0, + phy_data2); + he_mu->ru_ch1[1] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1, + phy_data3); + he_mu->ru_ch1[2] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2, + phy_data2); + he_mu->ru_ch1[3] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3, + phy_data3); } - if (FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK, sigb2) && + if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK, phy_data4) && (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) { he_mu->flags1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN); he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU, - sigb2), + le16_encode_bits(FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU, + phy_data4), IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU); - he_mu->ru_ch2[0] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU0, - sigb0); - he_mu->ru_ch2[1] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU1, - sigb1); - he_mu->ru_ch2[2] = FIELD_GET(IWL_RX_HE_SIGB_COMMON0_CH2_RU2, - sigb0); - he_mu->ru_ch2[3] = FIELD_GET(IWL_RX_HE_SIGB_COMMON1_CH2_RU3, - sigb1); + he_mu->ru_ch2[0] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0, + phy_data2); + he_mu->ru_ch2[1] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1, + phy_data3); + he_mu->ru_ch2[2] = FIELD_GET(IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2, + phy_data2); + he_mu->ru_ch2[3] = FIELD_GET(IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3, + phy_data3); } } static void -iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags, +iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data, + u32 rate_n_flags, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, struct ieee80211_rx_status *rx_status) @@ -937,7 +1003,8 @@ iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags, * happen though as management frames where we need * the TSF/timers are not be transmitted in HE-MU. */ - u8 ru = FIELD_GET(IWL_RX_HE_PHY_RU_ALLOC_MASK, he_phy_data); + u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK); + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; u8 offs = 0; rx_status->bw = RATE_INFO_BW_HE_RU; @@ -976,126 +1043,160 @@ iwl_mvm_decode_he_phy_ru_alloc(u64 he_phy_data, u32 rate_n_flags, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN | IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN); - if (he_phy_data & IWL_RX_HE_PHY_RU_ALLOC_SEC80) + if (phy_data->d1 & cpu_to_le32(IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80)) he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC); - if (he_mu) { #define CHECK_BW(bw) \ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS); \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \ RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS) - CHECK_BW(20); - CHECK_BW(40); - CHECK_BW(80); - CHECK_BW(160); + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); + + if (he_mu) he_mu->flags2 |= le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, rate_n_flags), IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW); - } + else if (he_type == RATE_MCS_HE_TYPE_TRIG) + he->data6 |= + cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) | + le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK, + rate_n_flags), + IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW); } static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, - struct iwl_rx_mpdu_desc *desc, + struct iwl_mvm_rx_phy_data *phy_data, struct ieee80211_radiotap_he *he, struct ieee80211_radiotap_he_mu *he_mu, struct ieee80211_rx_status *rx_status, - u64 he_phy_data, u32 rate_n_flags, - int queue) + u32 rate_n_flags, int queue) { - u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; - bool sigb_data; - u16 d1known = IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN; - u16 d2known = IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | - IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN; - - he->data1 |= cpu_to_le16(d1known); - he->data2 |= cpu_to_le16(d2known); - he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BSS_COLOR_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); - he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_UPLINK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_UL_DL); - he->data3 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_LDPC_EXT_SYM, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); - he->data4 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_SPATIAL_REUSE_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); - he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PRE_FEC_PAD_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); - he->data5 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_PE_DISAMBIG, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); - he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_TXOP_DUR_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA6_TXOP); - he->data6 |= le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_DOPPLER, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); - - switch (he_type) { - case RATE_MCS_HE_TYPE_MU: + switch (phy_data->info_type) { + case IWL_RX_PHY_INFO_TYPE_NONE: + case IWL_RX_PHY_INFO_TYPE_CCK: + case IWL_RX_PHY_INFO_TYPE_OFDM_LGCY: + case IWL_RX_PHY_INFO_TYPE_HT: + case IWL_RX_PHY_INFO_TYPE_VHT_SU: + case IWL_RX_PHY_INFO_TYPE_VHT_MU: + return; + case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN); + he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1), + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1); + he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2), + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2); + he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3), + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3); + he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2, + IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4), + IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4); + /* fall through */ + case IWL_RX_PHY_INFO_TYPE_HE_SU: + case IWL_RX_PHY_INFO_TYPE_HE_MU: + case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: + case IWL_RX_PHY_INFO_TYPE_HE_TB: + /* HE common */ + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN); + he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN | + IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); + he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK), + IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR); + if (phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB && + phy_data->info_type != IWL_RX_PHY_INFO_TYPE_HE_TB_EXT) { + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN); + he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_UPLINK), + IEEE80211_RADIOTAP_HE_DATA3_UL_DL); + } + he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM), + IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG); + he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK), + IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD); + he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_PE_DISAMBIG), + IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG); + he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d1, + IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK), + IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); + he->data6 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK), + IEEE80211_RADIOTAP_HE_DATA6_TXOP); + he->data6 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_DOPPLER), + IEEE80211_RADIOTAP_HE_DATA6_DOPPLER); + break; + } + + switch (phy_data->info_type) { + case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: + case IWL_RX_PHY_INFO_TYPE_HE_MU: + case IWL_RX_PHY_INFO_TYPE_HE_SU: + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN); + he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK), + IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE); + break; + default: + /* nothing here */ + break; + } + + switch (phy_data->info_type) { + case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_DCM, - he_phy_data), + le16_encode_bits(le16_get_bits(phy_data->d4, + IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM), IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); he_mu->flags1 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_MCS_MASK, - he_phy_data), + le16_encode_bits(le16_get_bits(phy_data->d4, + IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK), IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); + le16_encode_bits(le16_get_bits(phy_data->d4, + IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); + iwl_mvm_decode_he_mu_ext(mvm, phy_data, rate_n_flags, he_mu); + /* fall through */ + case IWL_RX_PHY_INFO_TYPE_HE_MU: he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_SIGB_COMPRESSION, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); + le16_encode_bits(le32_get_bits(phy_data->d1, + IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); he_mu->flags2 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW); - - sigb_data = FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, - he_phy_data) == - IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO; - if (sigb_data) - iwl_mvm_decode_he_sigb(mvm, desc, rate_n_flags, he_mu); + le16_encode_bits(le32_get_bits(phy_data->d1, + IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION), + IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); /* fall through */ - case RATE_MCS_HE_TYPE_TRIG: - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - he->data5 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_HE_LTF_NUM_MASK, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); - break; - case RATE_MCS_HE_TYPE_SU: - case RATE_MCS_HE_TYPE_EXT_SU: - he->data1 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); - he->data3 |= - le16_encode_bits(FIELD_GET(IWL_RX_HE_PHY_BEAM_CHNG, - he_phy_data), - IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); - break; - } - - switch (FIELD_GET(IWL_RX_HE_PHY_INFO_TYPE_MASK, he_phy_data)) { - case IWL_RX_HE_PHY_INFO_TYPE_MU: - case IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO: - case IWL_RX_HE_PHY_INFO_TYPE_TB: - iwl_mvm_decode_he_phy_ru_alloc(he_phy_data, rate_n_flags, + case IWL_RX_PHY_INFO_TYPE_HE_TB: + case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: + iwl_mvm_decode_he_phy_ru_alloc(phy_data, rate_n_flags, he, he_mu, rx_status); break; + case IWL_RX_PHY_INFO_TYPE_HE_SU: + he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN); + he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0, + IWL_RX_PHY_DATA0_HE_BEAM_CHNG), + IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE); + break; default: /* nothing */ break; @@ -1103,13 +1204,10 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm, } static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_rx_mpdu_desc *desc, + struct iwl_mvm_rx_phy_data *phy_data, u32 rate_n_flags, u16 phy_info, int queue) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - /* this is invalid e.g. because puncture type doesn't allow 0b11 */ -#define HE_PHY_DATA_INVAL ((u64)-1) - u64 he_phy_data = HE_PHY_DATA_INVAL; struct ieee80211_radiotap_he *he = NULL; struct ieee80211_radiotap_he_mu *he_mu = NULL; u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; @@ -1130,55 +1228,37 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN | IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN), }; - unsigned int radiotap_len = 0; he = skb_put_data(skb, &known, sizeof(known)); - radiotap_len += sizeof(known); rx_status->flag |= RX_FLAG_RADIOTAP_HE; - if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) { - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) - he_phy_data = le64_to_cpu(desc->v3.he_phy_data); - else - he_phy_data = le64_to_cpu(desc->v1.he_phy_data); - - if (he_type == RATE_MCS_HE_TYPE_MU) { - he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); - radiotap_len += sizeof(mu_known); - rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; - } + if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU || + phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) { + he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known)); + rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU; } - /* temporarily hide the radiotap data */ - __skb_pull(skb, radiotap_len); - - if (he_phy_data != HE_PHY_DATA_INVAL && - he_type == RATE_MCS_HE_TYPE_SU) { - /* report the AMPDU-EOF bit on single frames */ - if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { - rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, he_phy_data)) - rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; - } + /* report the AMPDU-EOF bit on single frames */ + if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + rx_status->flag |= RX_FLAG_AMPDU_DETAILS; + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } - if (he_phy_data != HE_PHY_DATA_INVAL) - iwl_mvm_decode_he_phy_data(mvm, desc, he, he_mu, rx_status, - he_phy_data, rate_n_flags, queue); + if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) + iwl_mvm_decode_he_phy_data(mvm, phy_data, he, he_mu, rx_status, + rate_n_flags, queue); /* update aggregation data for monitor sake on default queue */ - if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { + if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && + (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; /* toggle is switched whenever new aggregation starts */ - if (toggle_bit != mvm->ampdu_toggle && - he_phy_data != HE_PHY_DATA_INVAL && - (he_type == RATE_MCS_HE_TYPE_MU || - he_type == RATE_MCS_HE_TYPE_SU)) { + if (toggle_bit != mvm->ampdu_toggle) { rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; - if (FIELD_GET(IWL_RX_HE_PHY_DELIM_EOF, - he_phy_data)) + if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF)) rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } } @@ -1261,43 +1341,34 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb, break; } - he->data5 |= le16_encode_bits(ltf, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - - if (he_type == RATE_MCS_HE_TYPE_SU || - he_type == RATE_MCS_HE_TYPE_EXT_SU) { - u16 val; - - /* LTF syms correspond to streams */ - he->data2 |= - cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN); - switch (rx_status->nss) { - case 1: - val = 0; - break; - case 2: - val = 1; - break; - case 3: - case 4: - val = 2; - break; - case 5: - case 6: - val = 3; - break; - case 7: - case 8: - val = 4; - break; - default: - WARN_ONCE(1, "invalid nss: %d\n", - rx_status->nss); - val = 0; - } + he->data5 |= le16_encode_bits(ltf, + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); +} - he->data5 |= - le16_encode_bits(val, - IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS); +static void iwl_mvm_decode_lsig(struct sk_buff *skb, + struct iwl_mvm_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_radiotap_lsig *lsig; + + switch (phy_data->info_type) { + case IWL_RX_PHY_INFO_TYPE_HT: + case IWL_RX_PHY_INFO_TYPE_VHT_SU: + case IWL_RX_PHY_INFO_TYPE_VHT_MU: + case IWL_RX_PHY_INFO_TYPE_HE_TB_EXT: + case IWL_RX_PHY_INFO_TYPE_HE_SU: + case IWL_RX_PHY_INFO_TYPE_HE_MU: + case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT: + case IWL_RX_PHY_INFO_TYPE_HE_TB: + lsig = skb_put(skb, sizeof(*lsig)); + lsig->data1 = cpu_to_le16(IEEE80211_RADIOTAP_LSIG_DATA1_LENGTH_KNOWN); + lsig->data2 = le16_encode_bits(le32_get_bits(phy_data->d1, + IWL_RX_PHY_DATA1_LSIG_LEN_MASK), + IEEE80211_RADIOTAP_LSIG_DATA2_LENGTH); + rx_status->flag |= RX_FLAG_RADIOTAP_LSIG; + break; + default: + break; } } @@ -1315,6 +1386,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb; u8 crypt_len = 0, channel, energy_a, energy_b; size_t desc_size; + struct iwl_mvm_rx_phy_data phy_data = { + .d4 = desc->phy_data4, + .info_type = IWL_RX_PHY_INFO_TYPE_NONE, + }; + bool csi = false; if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) return; @@ -1326,6 +1402,11 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, energy_a = desc->v3.energy_a; energy_b = desc->v3.energy_b; desc_size = sizeof(*desc); + + phy_data.d0 = desc->v3.phy_data0; + phy_data.d1 = desc->v3.phy_data1; + phy_data.d2 = desc->v3.phy_data2; + phy_data.d3 = desc->v3.phy_data3; } else { rate_n_flags = le32_to_cpu(desc->v1.rate_n_flags); channel = desc->v1.channel; @@ -1333,8 +1414,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, energy_a = desc->v1.energy_a; energy_b = desc->v1.energy_b; desc_size = IWL_RX_DESC_SIZE_V1; + + phy_data.d0 = desc->v1.phy_data0; + phy_data.d1 = desc->v1.phy_data1; + phy_data.d2 = desc->v1.phy_data2; + phy_data.d3 = desc->v1.phy_data3; } + if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) + phy_data.info_type = + le32_get_bits(phy_data.d1, + IWL_RX_PHY_DATA1_INFO_TYPE_MASK); + hdr = (void *)(pkt->data + desc_size); /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. @@ -1373,7 +1464,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, } if (rate_n_flags & RATE_MCS_HE_MSK) - iwl_mvm_rx_he(mvm, skb, desc, rate_n_flags, phy_info, queue); + iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags, + phy_info, queue); + + iwl_mvm_decode_lsig(skb, &phy_data); rx_status = IEEE80211_SKB_RXCB(skb); @@ -1395,7 +1489,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; } /* set the preamble flag if appropriate */ - if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) + if (rate_n_flags & RATE_MCS_CCK_MSK && + phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) { @@ -1422,22 +1517,25 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, /* update aggregation data for monitor sake on default queue */ if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) { bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; - u64 he_phy_data; - - if (mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) - he_phy_data = le64_to_cpu(desc->v3.he_phy_data); - else - he_phy_data = le64_to_cpu(desc->v1.he_phy_data); rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->ampdu_reference = mvm->ampdu_ref; - /* toggle is switched whenever new aggregation starts */ + /* + * Toggle is switched whenever new aggregation starts. Make + * sure ampdu_reference is never 0 so we can later use it to + * see if the frame was really part of an A-MPDU or not. + */ if (toggle_bit != mvm->ampdu_toggle) { mvm->ampdu_ref++; + if (mvm->ampdu_ref == 0) + mvm->ampdu_ref++; mvm->ampdu_toggle = toggle_bit; } + rx_status->ampdu_reference = mvm->ampdu_ref; } + if (unlikely(mvm->monitor_on)) + iwl_mvm_add_rtap_sniffer_config(mvm, skb); + rcu_read_lock(); if (desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { @@ -1589,13 +1687,150 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->boottime_ns = ktime_get_boot_ns(); } - iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb); + if (iwl_mvm_create_skb(mvm, skb, hdr, len, crypt_len, rxb)) { + kfree_skb(skb); + goto out; + } + if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc)) - iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta); + iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, + sta, csi); out: rcu_read_unlock(); } +void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue) +{ + struct ieee80211_rx_status *rx_status; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_rx_no_data *desc = (void *)pkt->data; + u32 rate_n_flags = le32_to_cpu(desc->rate); + u32 gp2_on_air_rise = le32_to_cpu(desc->on_air_rise_time); + u32 rssi = le32_to_cpu(desc->rssi); + u32 info_type = le32_to_cpu(desc->info) & RX_NO_DATA_INFO_TYPE_MSK; + u16 phy_info = IWL_RX_MPDU_PHY_TSF_OVERLOAD; + struct ieee80211_sta *sta = NULL; + struct sk_buff *skb; + u8 channel, energy_a, energy_b; + struct iwl_mvm_rx_phy_data phy_data = { + .d0 = desc->phy_info[0], + .info_type = IWL_RX_PHY_INFO_TYPE_NONE, + }; + + if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) + return; + + /* Currently only NDP type is supported */ + if (info_type != RX_NO_DATA_INFO_TYPE_NDP) + return; + + energy_a = (rssi & RX_NO_DATA_CHAIN_A_MSK) >> RX_NO_DATA_CHAIN_A_POS; + energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS; + channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS; + + phy_data.info_type = + le32_get_bits(desc->phy_info[1], + IWL_RX_PHY_DATA1_INFO_TYPE_MASK); + + /* Dont use dev_alloc_skb(), we'll have enough headroom once + * ieee80211_hdr pulled. + */ + skb = alloc_skb(128, GFP_ATOMIC); + if (!skb) { + IWL_ERR(mvm, "alloc_skb failed\n"); + return; + } + + rx_status = IEEE80211_SKB_RXCB(skb); + + /* 0-length PSDU */ + rx_status->flag |= RX_FLAG_NO_PSDU; + /* currently this is the only type for which we get this notif */ + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; + + /* This may be overridden by iwl_mvm_rx_he() to HE_RU */ + switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { + case RATE_MCS_CHAN_WIDTH_20: + break; + case RATE_MCS_CHAN_WIDTH_40: + rx_status->bw = RATE_INFO_BW_40; + break; + case RATE_MCS_CHAN_WIDTH_80: + rx_status->bw = RATE_INFO_BW_80; + break; + case RATE_MCS_CHAN_WIDTH_160: + rx_status->bw = RATE_INFO_BW_160; + break; + } + + if (rate_n_flags & RATE_MCS_HE_MSK) + iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags, + phy_info, queue); + + iwl_mvm_decode_lsig(skb, &phy_data); + + rx_status->device_timestamp = gp2_on_air_rise; + rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : + NL80211_BAND_2GHZ; + rx_status->freq = ieee80211_channel_to_frequency(channel, + rx_status->band); + iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a, + energy_b); + + rcu_read_lock(); + + if (!(rate_n_flags & RATE_MCS_CCK_MSK) && + rate_n_flags & RATE_MCS_SGI_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + if (rate_n_flags & RATE_HT_MCS_GF_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_HT_GF; + if (rate_n_flags & RATE_MCS_LDPC_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_LDPC; + if (rate_n_flags & RATE_MCS_HT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> + RATE_MCS_STBC_POS; + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK; + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + } else if (rate_n_flags & RATE_MCS_VHT_MSK) { + u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> + RATE_MCS_STBC_POS; + rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK; + rx_status->encoding = RX_ENC_VHT; + rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT; + if (rate_n_flags & RATE_MCS_BF_MSK) + rx_status->enc_flags |= RX_ENC_FLAG_BF; + /* + * take the nss from the rx_vec since the rate_n_flags has + * only 2 bits for the nss which gives a max of 4 ss but + * there may be up to 8 spatial streams + */ + rx_status->nss = + le32_get_bits(desc->rx_vec[0], + RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1; + } else if (rate_n_flags & RATE_MCS_HE_MSK) { + rx_status->nss = + le32_get_bits(desc->rx_vec[0], + RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1; + } else { + int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags, + rx_status->band); + + if (WARN(rate < 0 || rate > 0xFF, + "Invalid rate flags 0x%x, band %d,\n", + rate_n_flags, rx_status->band)) { + kfree_skb(skb); + goto out; + } + rx_status->rate_idx = rate; + } + + ieee80211_rx_napi(mvm->hw, sta, skb, napi); +out: + rcu_read_unlock(); +} void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index cfb784fea77b..78694bc38e76 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,9 +205,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band, { u32 tx_ant; - mvm->scan_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), - mvm->scan_last_antenna_idx); + iwl_mvm_toggle_tx_ant(mvm, &mvm->scan_last_antenna_idx); tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS; if (band == NL80211_BAND_2GHZ && !no_cck) @@ -1582,6 +1580,11 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type) * scheduled scan before starting a normal scan. */ + /* FW supports only a single periodic scan */ + if ((type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) && + mvm->scan_status & (IWL_MVM_SCAN_SCHED | IWL_MVM_SCAN_NETDETECT)) + return -EBUSY; + if (iwl_mvm_num_scans(mvm) < mvm->max_scans) return 0; @@ -1618,10 +1621,10 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type) if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK) return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); - - /* fall through, something is wrong if no scan was - * running but we ran out of scans. + /* Something is wrong if no scan was running but we + * ran out of scans. */ + /* fall through */ default: WARN_ON(1); break; @@ -1895,6 +1898,8 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = false; mvm->scan_uid_status[uid] = 0; + + iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_SCAN_COMPLETE); } void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, @@ -1976,9 +1981,8 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) return ret; } - ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); - - return ret; + return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, + 1 * HZ); } int iwl_mvm_scan_size(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index d1d76bb9a750..9da0dae78510 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -7,6 +7,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,7 +66,7 @@ struct iwl_mvm_active_iface_iterator_data { struct ieee80211_vif *ignore_vif; u8 sta_vif_ap_sta_id; enum iwl_sf_state sta_vif_state; - int num_active_macs; + u32 num_active_macs; }; /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 1887d2b9f185..98d123dd7177 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -314,14 +314,11 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, struct iwl_mvm_sta *mvmsta; u32 status; u8 sta_id; - int ret; if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; - spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; - spin_unlock_bh(&mvm->queue_info_lock); rcu_read_lock(); @@ -351,105 +348,66 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, /* Notify FW of queue removal from the STA queues */ status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, - iwl_mvm_add_sta_cmd_size(mvm), - &cmd, &status); - - return ret; + return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), + &cmd, &status); } -static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, - int mac80211_queue, u8 tid, u8 flags) +static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int queue, u8 tid, u8 flags) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; - bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; int ret; - if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) - return -EINVAL; - if (iwl_mvm_has_new_tx_api(mvm)) { - spin_lock_bh(&mvm->queue_info_lock); - - if (remove_mac_queue) - mvm->hw_queue_to_mac80211[queue] &= - ~BIT(mac80211_queue); - - spin_unlock_bh(&mvm->queue_info_lock); - iwl_trans_txq_free(mvm->trans, queue); return 0; } - spin_lock_bh(&mvm->queue_info_lock); - - if (WARN_ON(mvm->queue_info[queue].tid_bitmap == 0)) { - spin_unlock_bh(&mvm->queue_info_lock); + if (WARN_ON(mvm->queue_info[queue].tid_bitmap == 0)) return 0; - } mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); - /* - * If there is another TID with the same AC - don't remove the MAC queue - * from the mapping - */ - if (tid < IWL_MAX_TID_COUNT) { - unsigned long tid_bitmap = - mvm->queue_info[queue].tid_bitmap; - int ac = tid_to_mac80211_ac[tid]; - int i; - - for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) { - if (tid_to_mac80211_ac[i] == ac) - remove_mac_queue = false; - } - } - - if (remove_mac_queue) - mvm->hw_queue_to_mac80211[queue] &= - ~BIT(mac80211_queue); - cmd.action = mvm->queue_info[queue].tid_bitmap ? SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE; if (cmd.action == SCD_CFG_DISABLE_QUEUE) mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE; IWL_DEBUG_TX_QUEUES(mvm, - "Disabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", + "Disabling TXQ #%d tids=0x%x\n", queue, - mvm->queue_info[queue].tid_bitmap, - mvm->hw_queue_to_mac80211[queue]); + mvm->queue_info[queue].tid_bitmap); /* If the queue is still enabled - nothing left to do in this func */ - if (cmd.action == SCD_CFG_ENABLE_QUEUE) { - spin_unlock_bh(&mvm->queue_info_lock); + if (cmd.action == SCD_CFG_ENABLE_QUEUE) return 0; - } cmd.sta_id = mvm->queue_info[queue].ra_sta_id; cmd.tid = mvm->queue_info[queue].txq_tid; /* Make sure queue info is correct even though we overwrite it */ - WARN(mvm->queue_info[queue].tid_bitmap || - mvm->hw_queue_to_mac80211[queue], - "TXQ #%d info out-of-sync - mac map=0x%x, tids=0x%x\n", - queue, mvm->hw_queue_to_mac80211[queue], - mvm->queue_info[queue].tid_bitmap); + WARN(mvm->queue_info[queue].tid_bitmap, + "TXQ #%d info out-of-sync - tids=0x%x\n", + queue, mvm->queue_info[queue].tid_bitmap); /* If we are here - the queue is freed and we can zero out these vals */ mvm->queue_info[queue].tid_bitmap = 0; - mvm->hw_queue_to_mac80211[queue] = 0; + + if (sta) { + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_tid(sta, tid); + + mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; + } /* Regardless if this is a reserved TXQ for a STA - mark it as false */ mvm->queue_info[queue].reserved = false; - spin_unlock_bh(&mvm->queue_info_lock); - iwl_trans_txq_disable(mvm->trans, queue, false); ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, sizeof(struct iwl_scd_txq_cfg_cmd), &cmd); @@ -474,10 +432,8 @@ static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue) if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; - spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; - spin_unlock_bh(&mvm->queue_info_lock); sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); @@ -516,10 +472,8 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; - spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; - spin_unlock_bh(&mvm->queue_info_lock); rcu_read_lock(); @@ -535,9 +489,14 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) spin_lock_bh(&mvmsta->lock); /* Unmap MAC queues and TIDs from this queue */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_tid(sta, tid); + if (mvmsta->tid_data[tid].state == IWL_AGG_ON) disable_agg_tids |= BIT(tid); mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; + + mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; } mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */ @@ -545,14 +504,25 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue) rcu_read_unlock(); + /* + * The TX path may have been using this TXQ_ID from the tid_data, + * so make sure it's no longer running so that we can safely reuse + * this TXQ later. We've set all the TIDs to IWL_MVM_INVALID_QUEUE + * above, but nothing guarantees we've stopped using them. Thus, + * without this, we could get to iwl_mvm_disable_txq() and remove + * the queue while still sending frames to it. + */ + synchronize_net(); + return disable_agg_tids; } static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, + struct ieee80211_sta *old_sta, u8 new_sta_id) { struct iwl_mvm_sta *mvmsta; - u8 txq_curr_ac, sta_id, tid; + u8 sta_id, tid; unsigned long disable_agg_tids = 0; bool same_sta; int ret; @@ -562,11 +532,8 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; - spin_lock_bh(&mvm->queue_info_lock); - txq_curr_ac = mvm->queue_info[queue].mac80211_ac; sta_id = mvm->queue_info[queue].ra_sta_id; tid = mvm->queue_info[queue].txq_tid; - spin_unlock_bh(&mvm->queue_info_lock); same_sta = sta_id == new_sta_id; @@ -580,9 +547,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue, iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids, false); - ret = iwl_mvm_disable_txq(mvm, queue, - mvmsta->vif->hw_queue[txq_curr_ac], - tid, 0); + ret = iwl_mvm_disable_txq(mvm, old_sta, queue, tid, 0); if (ret) { IWL_ERR(mvm, "Failed to free inactive queue %d (ret=%d)\n", @@ -610,7 +575,6 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, * by the inactivity checker. */ lockdep_assert_held(&mvm->mutex); - lockdep_assert_held(&mvm->queue_info_lock); if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; @@ -673,16 +637,15 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm, * in such a case, otherwise - if no redirection required - it does nothing, * unless the %force param is true. */ -static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, - int ac, int ssn, unsigned int wdg_timeout, - bool force) +static int iwl_mvm_redirect_queue(struct iwl_mvm *mvm, int queue, int tid, + int ac, int ssn, unsigned int wdg_timeout, + bool force, struct iwl_mvm_txq *txq) { struct iwl_scd_txq_cfg_cmd cmd = { .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; bool shared_queue; - unsigned long mq; int ret; if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) @@ -696,10 +659,7 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, * value 3 and VO with value 0, so to check if ac X is lower than ac Y * we need to check if the numerical value of X is LARGER than of Y. */ - spin_lock_bh(&mvm->queue_info_lock); if (ac <= mvm->queue_info[queue].mac80211_ac && !force) { - spin_unlock_bh(&mvm->queue_info_lock); - IWL_DEBUG_TX_QUEUES(mvm, "No redirection needed on TXQ #%d\n", queue); @@ -709,15 +669,14 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, cmd.sta_id = mvm->queue_info[queue].ra_sta_id; cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac]; cmd.tid = mvm->queue_info[queue].txq_tid; - mq = mvm->hw_queue_to_mac80211[queue]; shared_queue = hweight16(mvm->queue_info[queue].tid_bitmap) > 1; - spin_unlock_bh(&mvm->queue_info_lock); IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n", queue, iwl_mvm_ac_to_tx_fifo[ac]); - /* Stop MAC queues and wait for this queue to empty */ - iwl_mvm_stop_mac_queues(mvm, mq); + /* Stop the queue and wait for it to empty */ + txq->stopped = true; + ret = iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(queue)); if (ret) { IWL_ERR(mvm, "Error draining queue %d before reconfig\n", @@ -737,9 +696,7 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); /* Update the TID "owner" of the queue */ - spin_lock_bh(&mvm->queue_info_lock); mvm->queue_info[queue].txq_tid = tid; - spin_unlock_bh(&mvm->queue_info_lock); /* TODO: Work-around SCD bug when moving back by multiples of 0x40 */ @@ -748,9 +705,7 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, cmd.sta_id, tid, IWL_FRAME_LIMIT, ssn); /* Update AC marking of the queue */ - spin_lock_bh(&mvm->queue_info_lock); mvm->queue_info[queue].mac80211_ac = ac; - spin_unlock_bh(&mvm->queue_info_lock); /* * Mark queue as shared in transport if shared @@ -762,8 +717,8 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid, iwl_trans_txq_set_shared_mode(mvm->trans, queue, true); out: - /* Continue using the MAC queues */ - iwl_mvm_start_mac_queues(mvm, mq); + /* Continue using the queue */ + txq->stopped = false; return ret; } @@ -773,7 +728,7 @@ static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, { int i; - lockdep_assert_held(&mvm->queue_info_lock); + lockdep_assert_held(&mvm->mutex); /* This should not be hit with new TX path */ if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) @@ -788,14 +743,15 @@ static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, return -ENOSPC; } -static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, +static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, u8 sta_id, u8 tid, unsigned int timeout) { int queue, size = IWL_DEFAULT_QUEUE_SIZE; if (tid == IWL_MAX_TID_COUNT) { tid = IWL_MGMT_TID; - size = IWL_MGMT_QUEUE_SIZE; + size = max_t(u32, IWL_MGMT_QUEUE_SIZE, + mvm->trans->cfg->min_txq_size); } queue = iwl_trans_txq_alloc(mvm->trans, cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE), @@ -811,10 +767,7 @@ static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", queue, sta_id, tid); - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); - IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d (mac80211 map:0x%x)\n", - queue, mvm->hw_queue_to_mac80211[queue]); + IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d\n", queue); return queue; } @@ -824,9 +777,10 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, int tid) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_tid(sta, tid); unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); - u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; lockdep_assert_held(&mvm->mutex); @@ -834,11 +788,14 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, IWL_DEBUG_TX_QUEUES(mvm, "Allocating queue for sta %d on tid %d\n", mvmsta->sta_id, tid); - queue = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, mvmsta->sta_id, tid, - wdg_timeout); + queue = iwl_mvm_tvqm_enable_txq(mvm, mvmsta->sta_id, tid, wdg_timeout); if (queue < 0) return queue; + mvmtxq->txq_id = queue; + mvm->tvqm_info[queue].txq_tid = tid; + mvm->tvqm_info[queue].sta_id = mvmsta->sta_id; + IWL_DEBUG_TX_QUEUES(mvm, "Allocated queue is %d\n", queue); spin_lock_bh(&mvmsta->lock); @@ -848,16 +805,14 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm, return 0; } -static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, - int mac80211_queue, u8 sta_id, u8 tid) +static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + int queue, u8 sta_id, u8 tid) { bool enable_queue = true; - spin_lock_bh(&mvm->queue_info_lock); - /* Make sure this TID isn't already enabled */ if (mvm->queue_info[queue].tid_bitmap & BIT(tid)) { - spin_unlock_bh(&mvm->queue_info_lock); IWL_ERR(mvm, "Trying to enable TXQ %d with existing TID %d\n", queue, tid); return false; @@ -867,14 +822,6 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, if (mvm->queue_info[queue].tid_bitmap) enable_queue = false; - if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) { - WARN(mac80211_queue >= - BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]), - "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n", - mac80211_queue, queue, sta_id, tid); - mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue); - } - mvm->queue_info[queue].tid_bitmap |= BIT(tid); mvm->queue_info[queue].ra_sta_id = sta_id; @@ -888,18 +835,22 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue, mvm->queue_info[queue].txq_tid = tid; } - IWL_DEBUG_TX_QUEUES(mvm, - "Enabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n", - queue, mvm->queue_info[queue].tid_bitmap, - mvm->hw_queue_to_mac80211[queue]); + if (sta) { + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_tid(sta, tid); - spin_unlock_bh(&mvm->queue_info_lock); + mvmtxq->txq_id = queue; + } + + IWL_DEBUG_TX_QUEUES(mvm, + "Enabling TXQ #%d tids=0x%x\n", + queue, mvm->queue_info[queue].tid_bitmap); return enable_queue; } -static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, - int mac80211_queue, u16 ssn, +static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, + int queue, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg, unsigned int wdg_timeout) { @@ -919,8 +870,7 @@ static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, return false; /* Send the enabling command if we need to */ - if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue, - cfg->sta_id, cfg->tid)) + if (!iwl_mvm_update_txq_mapping(mvm, sta, queue, cfg->sta_id, cfg->tid)) return false; inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, @@ -949,9 +899,7 @@ static void iwl_mvm_change_queue_tid(struct iwl_mvm *mvm, int queue) if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return; - spin_lock_bh(&mvm->queue_info_lock); tid_bitmap = mvm->queue_info[queue].tid_bitmap; - spin_unlock_bh(&mvm->queue_info_lock); if (WARN(!tid_bitmap, "TXQ %d has no tids assigned to it\n", queue)) return; @@ -968,9 +916,7 @@ static void iwl_mvm_change_queue_tid(struct iwl_mvm *mvm, int queue) return; } - spin_lock_bh(&mvm->queue_info_lock); mvm->queue_info[queue].txq_tid = tid; - spin_unlock_bh(&mvm->queue_info_lock); IWL_DEBUG_TX_QUEUES(mvm, "Changed TXQ %d ownership to tid %d\n", queue, tid); } @@ -992,10 +938,8 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) lockdep_assert_held(&mvm->mutex); - spin_lock_bh(&mvm->queue_info_lock); sta_id = mvm->queue_info[queue].ra_sta_id; tid_bitmap = mvm->queue_info[queue].tid_bitmap; - spin_unlock_bh(&mvm->queue_info_lock); /* Find TID for queue, and make sure it is the only one on the queue */ tid = find_first_bit(&tid_bitmap, IWL_MAX_TID_COUNT + 1); @@ -1019,9 +963,10 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number); - ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, - tid_to_mac80211_ac[tid], ssn, - wdg_timeout, true); + ret = iwl_mvm_redirect_queue(mvm, queue, tid, + tid_to_mac80211_ac[tid], ssn, + wdg_timeout, true, + iwl_mvm_txq_from_tid(sta, tid)); if (ret) { IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue); return; @@ -1052,9 +997,7 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue) } } - spin_lock_bh(&mvm->queue_info_lock); mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; - spin_unlock_bh(&mvm->queue_info_lock); } /* @@ -1073,7 +1016,7 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, int tid; lockdep_assert_held(&mvmsta->lock); - lockdep_assert_held(&mvm->queue_info_lock); + lockdep_assert_held(&mvm->mutex); if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return false; @@ -1100,11 +1043,9 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, * Remove the ones that did. */ for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]; u16 tid_bitmap; mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; - mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue); mvm->queue_info[queue].tid_bitmap &= ~BIT(tid); tid_bitmap = mvm->queue_info[queue].tid_bitmap; @@ -1137,10 +1078,6 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, * sure all TIDs have existing corresponding mac queues enabled */ tid_bitmap = mvm->queue_info[queue].tid_bitmap; - for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) { - mvm->hw_queue_to_mac80211[queue] |= - BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]); - } /* If the queue is marked as shared - "unshare" it */ if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 && @@ -1168,14 +1105,13 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) unsigned long unshare_queues = 0; unsigned long changetid_queues = 0; int i, ret, free_queue = -ENOSPC; + struct ieee80211_sta *queue_owner = NULL; lockdep_assert_held(&mvm->mutex); if (iwl_mvm_has_new_tx_api(mvm)) return -ENOSPC; - spin_lock_bh(&mvm->queue_info_lock); - rcu_read_lock(); /* we skip the CMD queue below by starting at 1 */ @@ -1230,24 +1166,19 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) mvmsta = iwl_mvm_sta_from_mac80211(sta); - /* this isn't so nice, but works OK due to the way we loop */ - spin_unlock(&mvm->queue_info_lock); - - /* and we need this locking order */ - spin_lock(&mvmsta->lock); - spin_lock(&mvm->queue_info_lock); + spin_lock_bh(&mvmsta->lock); ret = iwl_mvm_remove_inactive_tids(mvm, mvmsta, i, inactive_tid_bitmap, &unshare_queues, &changetid_queues); - if (ret >= 0 && free_queue < 0) + if (ret >= 0 && free_queue < 0) { + queue_owner = sta; free_queue = ret; + } /* only unlock sta lock - we still need the queue info lock */ - spin_unlock(&mvmsta->lock); + spin_unlock_bh(&mvmsta->lock); } - rcu_read_unlock(); - spin_unlock_bh(&mvm->queue_info_lock); /* Reconfigure queues requiring reconfiguation */ for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES) @@ -1256,18 +1187,21 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) iwl_mvm_change_queue_tid(mvm, i); if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { - ret = iwl_mvm_free_inactive_queue(mvm, free_queue, + ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner, alloc_for_sta); - if (ret) + if (ret) { + rcu_read_unlock(); return ret; + } } + rcu_read_unlock(); + return free_queue; } static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, u8 ac, int tid, - struct ieee80211_hdr *hdr) + struct ieee80211_sta *sta, u8 ac, int tid) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_trans_txq_scd_cfg cfg = { @@ -1278,7 +1212,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, }; unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false); - u8 mac_queue = mvmsta->vif->hw_queue[ac]; int queue = -1; unsigned long disable_agg_tids = 0; enum iwl_mvm_agg_state queue_state; @@ -1294,16 +1227,10 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, spin_lock_bh(&mvmsta->lock); tfd_queue_mask = mvmsta->tfd_queue_msk; + ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number); spin_unlock_bh(&mvmsta->lock); - spin_lock_bh(&mvm->queue_info_lock); - - /* - * Non-QoS, QoS NDP and MGMT frames should go to a MGMT queue, if one - * exists - */ - if (!ieee80211_is_data_qos(hdr->frame_control) || - ieee80211_is_qos_nullfunc(hdr->frame_control)) { + if (tid == IWL_MAX_TID_COUNT) { queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, IWL_MVM_DQA_MIN_MGMT_QUEUE, IWL_MVM_DQA_MAX_MGMT_QUEUE); @@ -1327,12 +1254,8 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); if (queue < 0) { - spin_unlock_bh(&mvm->queue_info_lock); - /* try harder - perhaps kill an inactive queue */ queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id); - - spin_lock_bh(&mvm->queue_info_lock); } /* No free queue - we'll have to share */ @@ -1353,8 +1276,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, if (queue > 0 && !shared_queue) mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; - spin_unlock_bh(&mvm->queue_info_lock); - /* This shouldn't happen - out of queues */ if (WARN_ON(queue <= 0)) { IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n", @@ -1388,13 +1309,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, } } - ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue, - ssn, &cfg, wdg_timeout); - if (inc_ssn) { - ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; - le16_add_cpu(&hdr->seq_ctrl, 0x10); - } + inc_ssn = iwl_mvm_enable_txq(mvm, sta, queue, ssn, &cfg, wdg_timeout); /* * Mark queue as shared in transport if shared @@ -1411,8 +1326,10 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, * this ra/tid in our Tx path since we stop the Qdisc when we * need to allocate a new TFD queue. */ - if (inc_ssn) + if (inc_ssn) { mvmsta->tid_data[tid].seq_number += 0x10; + ssn = (ssn + 1) & IEEE80211_SCTL_SEQ; + } mvmsta->tid_data[tid].txq_id = queue; mvmsta->tfd_queue_msk |= BIT(queue); queue_state = mvmsta->tid_data[tid].state; @@ -1434,8 +1351,9 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, } } else { /* Redirect queue, if needed */ - ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn, - wdg_timeout, false); + ret = iwl_mvm_redirect_queue(mvm, queue, tid, ac, ssn, + wdg_timeout, false, + iwl_mvm_txq_from_tid(sta, tid)); if (ret) goto out_err; } @@ -1443,7 +1361,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, return 0; out_err: - iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0); + iwl_mvm_disable_txq(mvm, sta, queue, tid, 0); return ret; } @@ -1456,87 +1374,34 @@ static inline u8 iwl_mvm_tid_to_ac_queue(int tid) return tid_to_mac80211_ac[tid]; } -static void iwl_mvm_tx_deferred_stream(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, int tid) -{ - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - struct sk_buff *skb; - struct ieee80211_hdr *hdr; - struct sk_buff_head deferred_tx; - u8 mac_queue; - bool no_queue = false; /* Marks if there is a problem with the queue */ - u8 ac; - - lockdep_assert_held(&mvm->mutex); - - skb = skb_peek(&tid_data->deferred_tx_frames); - if (!skb) - return; - hdr = (void *)skb->data; - - ac = iwl_mvm_tid_to_ac_queue(tid); - mac_queue = IEEE80211_SKB_CB(skb)->hw_queue; - - if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE && - iwl_mvm_sta_alloc_queue(mvm, sta, ac, tid, hdr)) { - IWL_ERR(mvm, - "Can't alloc TXQ for sta %d tid %d - dropping frame\n", - mvmsta->sta_id, tid); - - /* - * Mark queue as problematic so later the deferred traffic is - * freed, as we can do nothing with it - */ - no_queue = true; - } - - __skb_queue_head_init(&deferred_tx); - - /* Disable bottom-halves when entering TX path */ - local_bh_disable(); - spin_lock(&mvmsta->lock); - skb_queue_splice_init(&tid_data->deferred_tx_frames, &deferred_tx); - mvmsta->deferred_traffic_tid_map &= ~BIT(tid); - spin_unlock(&mvmsta->lock); - - while ((skb = __skb_dequeue(&deferred_tx))) - if (no_queue || iwl_mvm_tx_skb(mvm, skb, sta)) - ieee80211_free_txskb(mvm->hw, skb); - local_bh_enable(); - - /* Wake queue */ - iwl_mvm_start_mac_queues(mvm, BIT(mac_queue)); -} - void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, add_stream_wk); - struct ieee80211_sta *sta; - struct iwl_mvm_sta *mvmsta; - unsigned long deferred_tid_traffic; - int sta_id, tid; mutex_lock(&mvm->mutex); iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); - /* Go over all stations with deferred traffic */ - for_each_set_bit(sta_id, mvm->sta_deferred_frames, - IWL_MVM_STATION_COUNT) { - clear_bit(sta_id, mvm->sta_deferred_frames); - sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - if (IS_ERR_OR_NULL(sta)) - continue; + while (!list_empty(&mvm->add_stream_txqs)) { + struct iwl_mvm_txq *mvmtxq; + struct ieee80211_txq *txq; + u8 tid; - mvmsta = iwl_mvm_sta_from_mac80211(sta); - deferred_tid_traffic = mvmsta->deferred_traffic_tid_map; + mvmtxq = list_first_entry(&mvm->add_stream_txqs, + struct iwl_mvm_txq, list); + + txq = container_of((void *)mvmtxq, struct ieee80211_txq, + drv_priv); + tid = txq->tid; + if (tid == IEEE80211_NUM_TIDS) + tid = IWL_MAX_TID_COUNT; - for_each_set_bit(tid, &deferred_tid_traffic, - IWL_MAX_TID_COUNT + 1) - iwl_mvm_tx_deferred_stream(mvm, sta, tid); + iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid); + list_del_init(&mvmtxq->list); + local_bh_disable(); + iwl_mvm_mac_itxq_xmit(mvm->hw, txq); + local_bh_enable(); } mutex_unlock(&mvm->mutex); @@ -1556,8 +1421,6 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, /* run the general cleanup/unsharing of queues */ iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); - spin_lock_bh(&mvm->queue_info_lock); - /* Make sure we have free resources for this STA */ if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls && !mvm->queue_info[IWL_MVM_DQA_BSS_CLIENT_QUEUE].tid_bitmap && @@ -1569,19 +1432,15 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); if (queue < 0) { - spin_unlock_bh(&mvm->queue_info_lock); /* try again - this time kick out a queue if needed */ queue = iwl_mvm_inactivity_check(mvm, mvmsta->sta_id); if (queue < 0) { IWL_ERR(mvm, "No available queues for new station\n"); return -ENOSPC; } - spin_lock_bh(&mvm->queue_info_lock); } mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED; - spin_unlock_bh(&mvm->queue_info_lock); - mvmsta->reserved_queue = queue; IWL_DEBUG_TX_QUEUES(mvm, "Reserving data queue #%d for sta_id %d\n", @@ -1598,10 +1457,11 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, * Note that re-enabling aggregations isn't done in this function. */ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta) + struct ieee80211_sta *sta) { - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false); + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + unsigned int wdg = + iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false); int i; struct iwl_trans_txq_scd_cfg cfg = { .sta_id = mvm_sta->sta_id, @@ -1617,23 +1477,18 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i]; int txq_id = tid_data->txq_id; int ac; - u8 mac_queue; if (txq_id == IWL_MVM_INVALID_QUEUE) continue; - skb_queue_head_init(&tid_data->deferred_tx_frames); - ac = tid_to_mac80211_ac[i]; - mac_queue = mvm_sta->vif->hw_queue[ac]; if (iwl_mvm_has_new_tx_api(mvm)) { IWL_DEBUG_TX_QUEUES(mvm, "Re-mapping sta %d tid %d\n", mvm_sta->sta_id, i); - txq_id = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, - mvm_sta->sta_id, - i, wdg_timeout); + txq_id = iwl_mvm_tvqm_enable_txq(mvm, mvm_sta->sta_id, + i, wdg); tid_data->txq_id = txq_id; /* @@ -1656,8 +1511,7 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, "Re-mapping sta %d tid %d to queue %d\n", mvm_sta->sta_id, i, txq_id); - iwl_mvm_enable_txq(mvm, txq_id, mac_queue, seq, &cfg, - wdg_timeout); + iwl_mvm_enable_txq(mvm, sta, txq_id, seq, &cfg, wdg); mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; } } @@ -1747,7 +1601,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (ret) goto err; - iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta); + iwl_mvm_realloc_queues_after_restart(mvm, sta); sta_update = true; sta_flags = iwl_mvm_has_new_tx_api(mvm) ? 0 : STA_MODIFY_QUEUES; goto update_fw; @@ -1780,9 +1634,17 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, * frames until the queue is allocated */ mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; - skb_queue_head_init(&mvm_sta->tid_data[i].deferred_tx_frames); } - mvm_sta->deferred_traffic_tid_map = 0; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_mac80211(sta->txq[i]); + + mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; + INIT_LIST_HEAD(&mvmtxq->list); + atomic_set(&mvmtxq->tx_request, 0); + } + mvm_sta->agg_tids = 0; if (iwl_mvm_has_new_rx_api(mvm) && @@ -1822,6 +1684,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_tlc_offload(mvm)) iwl_mvm_rs_add_sta(mvm, mvm_sta); + iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); + update_fw: ret = iwl_mvm_sta_send_to_fw(mvm, sta, sta_update, sta_flags); if (ret) @@ -1915,9 +1779,9 @@ static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id) static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_sta *mvm_sta) + struct ieee80211_sta *sta) { - int ac; + struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); int i; lockdep_assert_held(&mvm->mutex); @@ -1926,11 +1790,17 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE) continue; - ac = iwl_mvm_tid_to_ac_queue(i); - iwl_mvm_disable_txq(mvm, mvm_sta->tid_data[i].txq_id, - vif->hw_queue[ac], i, 0); + iwl_mvm_disable_txq(mvm, sta, mvm_sta->tid_data[i].txq_id, i, + 0); mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE; } + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + struct iwl_mvm_txq *mvmtxq = + iwl_mvm_txq_from_mac80211(sta->txq[i]); + + mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; + } } int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, @@ -1992,7 +1862,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); - iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); + iwl_mvm_disable_sta_queues(mvm, vif, sta); /* If there is a TXQ still marked as reserved - free it */ if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { @@ -2004,18 +1874,14 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, * is still marked as IWL_MVM_QUEUE_RESERVED, and * should be manually marked as free again */ - spin_lock_bh(&mvm->queue_info_lock); status = &mvm->queue_info[reserved_txq].status; if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && (*status != IWL_MVM_QUEUE_FREE), "sta_id %d reserved txq %d status %d", - sta_id, reserved_txq, *status)) { - spin_unlock_bh(&mvm->queue_info_lock); + sta_id, reserved_txq, *status)) return -EINVAL; - } *status = IWL_MVM_QUEUE_FREE; - spin_unlock_bh(&mvm->queue_info_lock); } if (vif->type == NL80211_IFTYPE_STATION && @@ -2102,7 +1968,7 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 *queue, if (iwl_mvm_has_new_tx_api(mvm)) { int tvqm_queue = - iwl_mvm_tvqm_enable_txq(mvm, *queue, sta_id, + iwl_mvm_tvqm_enable_txq(mvm, sta_id, IWL_MAX_TID_COUNT, wdg_timeout); *queue = tvqm_queue; @@ -2115,7 +1981,7 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 *queue, .frame_limit = IWL_FRAME_LIMIT, }; - iwl_mvm_enable_txq(mvm, *queue, *queue, 0, &cfg, wdg_timeout); + iwl_mvm_enable_txq(mvm, NULL, *queue, 0, &cfg, wdg_timeout); } } @@ -2193,8 +2059,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - iwl_mvm_disable_txq(mvm, mvm->snif_queue, mvm->snif_queue, - IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0); ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id); if (ret) IWL_WARN(mvm, "Failed sending remove station\n"); @@ -2253,8 +2118,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) bsta->tfd_queue_msk |= BIT(queue); - iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0, - &cfg, wdg_timeout); + iwl_mvm_enable_txq(mvm, NULL, queue, 0, &cfg, wdg_timeout); } if (vif->type == NL80211_IFTYPE_ADHOC) @@ -2273,8 +2137,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * to firmware so enable queue here - after the station was added */ if (iwl_mvm_has_new_tx_api(mvm)) { - queue = iwl_mvm_tvqm_enable_txq(mvm, vif->hw_queue[0], - bsta->sta_id, + queue = iwl_mvm_tvqm_enable_txq(mvm, bsta->sta_id, IWL_MAX_TID_COUNT, wdg_timeout); @@ -2312,7 +2175,7 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, return; } - iwl_mvm_disable_txq(mvm, queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0); + iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0); if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2435,10 +2298,8 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * Note that this is done here as we want to avoid making DQA * changes in mac80211 layer. */ - if (vif->type == NL80211_IFTYPE_ADHOC) { - vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; - mvmvif->cab_queue = vif->cab_queue; - } + if (vif->type == NL80211_IFTYPE_ADHOC) + mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; /* * While in previous FWs we had to exclude cab queue from TFD queue @@ -2446,9 +2307,9 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) */ if (!iwl_mvm_has_new_tx_api(mvm) && fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) { - iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, - &cfg, timeout); - msta->tfd_queue_msk |= BIT(vif->cab_queue); + iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg, + timeout); + msta->tfd_queue_msk |= BIT(mvmvif->cab_queue); } ret = iwl_mvm_add_int_sta_common(mvm, msta, maddr, mvmvif->id, mvmvif->color); @@ -2465,30 +2326,69 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * tfd_queue_mask. */ if (iwl_mvm_has_new_tx_api(mvm)) { - int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue, - msta->sta_id, + int queue = iwl_mvm_tvqm_enable_txq(mvm, msta->sta_id, 0, timeout); mvmvif->cab_queue = queue; } else if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) - iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0, - &cfg, timeout); + iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg, + timeout); - if (mvmvif->ap_wep_key) { - u8 key_offset = iwl_mvm_set_fw_key_idx(mvm); + return 0; +} - if (key_offset == STA_KEY_IDX_INVALID) - return -ENOSPC; +static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, + struct ieee80211_key_conf *keyconf, + bool mcast) +{ + union { + struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1; + struct iwl_mvm_add_sta_key_cmd cmd; + } u = {}; + bool new_api = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_TKIP_MIC_KEYS); + __le16 key_flags; + int ret, size; + u32 status; - ret = iwl_mvm_send_sta_key(mvm, mvmvif->mcast_sta.sta_id, - mvmvif->ap_wep_key, 1, 0, NULL, 0, - key_offset, 0); - if (ret) - return ret; + /* This is a valid situation for GTK removal */ + if (sta_id == IWL_MVM_INVALID_STA) + return 0; + + key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & + STA_KEY_FLG_KEYID_MSK); + key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); + key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); + + if (mcast) + key_flags |= cpu_to_le16(STA_KEY_MULTICAST); + + /* + * The fields assigned here are in the same location at the start + * of the command, so we can do this union trick. + */ + u.cmd.common.key_flags = key_flags; + u.cmd.common.key_offset = keyconf->hw_key_idx; + u.cmd.common.sta_id = sta_id; + + size = new_api ? sizeof(u.cmd) : sizeof(u.cmd_v1); + + status = ADD_STA_SUCCESS; + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, &u.cmd, + &status); + + switch (status) { + case ADD_STA_SUCCESS: + IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); + break; + default: + ret = -EIO; + IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); + break; } - return 0; + return ret; } /* @@ -2504,8 +2404,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); - iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, - 0, 0); + iwl_mvm_disable_txq(mvm, NULL, mvmvif->cab_queue, 0, 0); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id); if (ret) @@ -2839,7 +2738,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; u16 normalized_ssn; - int txq_id; + u16 txq_id; int ret; if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) @@ -2873,8 +2772,6 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EIO; } - spin_lock(&mvm->queue_info_lock); - /* * Note the possible cases: * 1. An enabled TXQ - TXQ needs to become agg'ed @@ -2883,28 +2780,33 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ txq_id = mvmsta->tid_data[tid].txq_id; if (txq_id == IWL_MVM_INVALID_QUEUE) { - txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - IWL_MVM_DQA_MIN_DATA_QUEUE, - IWL_MVM_DQA_MAX_DATA_QUEUE); - if (txq_id < 0) { - ret = txq_id; + ret = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, + IWL_MVM_DQA_MAX_DATA_QUEUE); + if (ret < 0) { IWL_ERR(mvm, "Failed to allocate agg queue\n"); - goto release_locks; + goto out; } + txq_id = ret; + /* TXQ hasn't yet been enabled, so mark it only as reserved */ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED; + } else if (WARN_ON(txq_id >= IWL_MAX_HW_QUEUES)) { + ret = -ENXIO; + IWL_ERR(mvm, "tid_id %d out of range (0, %d)!\n", + tid, IWL_MAX_HW_QUEUES - 1); + goto out; + } else if (unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED)) { ret = -ENXIO; IWL_DEBUG_TX_QUEUES(mvm, "Can't start tid %d agg on shared queue!\n", tid); - goto release_locks; + goto out; } - spin_unlock(&mvm->queue_info_lock); - IWL_DEBUG_TX_QUEUES(mvm, "AGG for tid %d will be on queue #%d\n", tid, txq_id); @@ -2935,10 +2837,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } ret = 0; - goto out; -release_locks: - spin_unlock(&mvm->queue_info_lock); out: spin_unlock_bh(&mvmsta->lock); @@ -3007,9 +2906,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cfg.fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; - spin_lock_bh(&mvm->queue_info_lock); queue_status = mvm->queue_info[queue].status; - spin_unlock_bh(&mvm->queue_info_lock); /* Maybe there is no need to even alloc a queue... */ if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY) @@ -3043,8 +2940,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } if (alloc_queue) - iwl_mvm_enable_txq(mvm, queue, - vif->hw_queue[tid_to_mac80211_ac[tid]], ssn, + iwl_mvm_enable_txq(mvm, sta, queue, ssn, &cfg, wdg_timeout); /* Send ADD_STA command to enable aggs only if the queue isn't shared */ @@ -3055,9 +2951,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } /* No need to mark as reserved */ - spin_lock_bh(&mvm->queue_info_lock); mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY; - spin_unlock_bh(&mvm->queue_info_lock); out: /* @@ -3083,10 +2977,11 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, { u16 txq_id = tid_data->txq_id; + lockdep_assert_held(&mvm->mutex); + if (iwl_mvm_has_new_tx_api(mvm)) return; - spin_lock_bh(&mvm->queue_info_lock); /* * The TXQ is marked as reserved only if no traffic came through yet * This means no traffic has been sent on this TID (agg'd or not), so @@ -3098,8 +2993,6 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE; tid_data->txq_id = IWL_MVM_INVALID_QUEUE; } - - spin_unlock_bh(&mvm->queue_info_lock); } int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -3544,59 +3437,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm, return ret; } -static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, - struct ieee80211_key_conf *keyconf, - bool mcast) -{ - union { - struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1; - struct iwl_mvm_add_sta_key_cmd cmd; - } u = {}; - bool new_api = fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_TKIP_MIC_KEYS); - __le16 key_flags; - int ret, size; - u32 status; - - /* This is a valid situation for GTK removal */ - if (sta_id == IWL_MVM_INVALID_STA) - return 0; - - key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & - STA_KEY_FLG_KEYID_MSK); - key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); - key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); - - if (mcast) - key_flags |= cpu_to_le16(STA_KEY_MULTICAST); - - /* - * The fields assigned here are in the same location at the start - * of the command, so we can do this union trick. - */ - u.cmd.common.key_flags = key_flags; - u.cmd.common.key_offset = keyconf->hw_key_idx; - u.cmd.common.sta_id = sta_id; - - size = new_api ? sizeof(u.cmd) : sizeof(u.cmd_v1); - - status = ADD_STA_SUCCESS; - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, &u.cmd, - &status); - - switch (status) { - case ADD_STA_SUCCESS: - IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n"); - break; - default: - ret = -EIO; - IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n"); - break; - } - - return ret; -} - int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index de1a0a2d8723..b4d4071b865d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -297,7 +297,6 @@ enum iwl_mvm_agg_state { /** * struct iwl_mvm_tid_data - holds the states for each RA / TID - * @deferred_tx_frames: deferred TX frames for this RA/TID * @seq_number: the next WiFi sequence number to use * @next_reclaimed: the WiFi sequence number of the next packet to be acked. * This is basically (last acked packet++). @@ -318,7 +317,6 @@ enum iwl_mvm_agg_state { * tpt_meas_start */ struct iwl_mvm_tid_data { - struct sk_buff_head deferred_tx_frames; u16 seq_number; u16 next_reclaimed; /* The rest is Tx AGG related */ @@ -397,6 +395,9 @@ struct iwl_mvm_rxq_dup_data { * @ptk_pn: per-queue PTK PN data structures * @dup_data: per queue duplicate packet detection data * @deferred_traffic_tid_map: indication bitmap of deferred traffic per-TID + * @tx_ant: the index of the antenna to use for data tx to this station. Only + * used during connection establishment (e.g. for the 4 way handshake + * exchange). * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -424,8 +425,6 @@ struct iwl_mvm_sta { struct iwl_mvm_key_pn __rcu *ptk_pn[4]; struct iwl_mvm_rxq_dup_data *dup_data; - u16 deferred_traffic_tid_map; - u8 reserved_queue; /* Temporary, until the new TLC will control the Tx protection */ @@ -439,6 +438,7 @@ struct iwl_mvm_sta { u8 agg_tids; u8 sleep_tx_count; u8 avg_energy; + u8 tx_ant; }; u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index e02f4eb20359..859aa5a4e6b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -399,6 +399,9 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, struct ieee80211_tx_info *info; struct ieee80211_hdr *hdr; struct iwl_tdls_channel_switch_cmd cmd = {0}; + struct iwl_tdls_channel_switch_cmd_tail *tail = + iwl_mvm_chan_info_cmd_tail(mvm, &cmd.ci); + u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm); int ret; lockdep_assert_held(&mvm->mutex); @@ -414,9 +417,9 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, } cmd.switch_type = type; - cmd.timing.frame_timestamp = cpu_to_le32(timestamp); - cmd.timing.switch_time = cpu_to_le32(switch_time); - cmd.timing.switch_timeout = cpu_to_le32(switch_timeout); + tail->timing.frame_timestamp = cpu_to_le32(timestamp); + tail->timing.switch_time = cpu_to_le32(switch_time); + tail->timing.switch_timeout = cpu_to_le32(switch_timeout); rcu_read_lock(); sta = ieee80211_find_sta(vif, peer); @@ -448,21 +451,16 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, } } - if (chandef) { - cmd.ci.band = (chandef->chan->band == NL80211_BAND_2GHZ ? - PHY_BAND_24 : PHY_BAND_5); - cmd.ci.channel = chandef->chan->hw_value; - cmd.ci.width = iwl_mvm_get_channel_width(chandef); - cmd.ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef); - } + if (chandef) + iwl_mvm_set_chan_info_chandef(mvm, &cmd.ci, chandef); /* keep quota calculation simple for now - 50% of DTIM for TDLS */ - cmd.timing.max_offchan_duration = + tail->timing.max_offchan_duration = cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int) / 2); /* Switch time is the first element in the switch-timing IE. */ - cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); + tail->frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); info = IEEE80211_SKB_CB(skb); hdr = (void *)skb->data; @@ -472,20 +470,19 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, ret = -EINVAL; goto out; } - iwl_mvm_set_tx_cmd_ccmp(info, &cmd.frame.tx_cmd); + iwl_mvm_set_tx_cmd_ccmp(info, &tail->frame.tx_cmd); } - iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info, + iwl_mvm_set_tx_cmd(mvm, skb, &tail->frame.tx_cmd, info, mvmsta->sta_id); - iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta, + iwl_mvm_set_tx_cmd_rate(mvm, &tail->frame.tx_cmd, info, sta, hdr->frame_control); rcu_read_unlock(); - memcpy(cmd.frame.data, skb->data, skb->len); + memcpy(tail->frame.data, skb->data, skb->len); - ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, - sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, len, &cmd); if (ret) { IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n", ret); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index e1a6f4e22253..9693fa4cdc39 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -85,7 +85,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, { lockdep_assert_held(&mvm->time_event_lock); - if (!te_data->vif) + if (!te_data || !te_data->vif) return; list_del(&te_data->list); @@ -334,6 +334,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, switch (te_data->vif->type) { case NL80211_IFTYPE_P2P_DEVICE: ieee80211_remain_on_channel_expired(mvm->hw); + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); iwl_mvm_roc_finished(mvm); break; case NL80211_IFTYPE_STATION: @@ -686,6 +687,8 @@ static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data) { struct iwl_hs20_roc_req aux_cmd = {}; + u16 len = sizeof(aux_cmd) - iwl_mvm_chan_info_padding(mvm); + u32 uid; int ret; @@ -699,7 +702,7 @@ static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm, IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n", le32_to_cpu(aux_cmd.event_unique_id)); ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, - sizeof(aux_cmd), &aux_cmd); + len, &aux_cmd); if (WARN_ON(ret)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c deleted file mode 100644 index 01e0a999063b..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ /dev/null @@ -1,305 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2015 Intel Deutschland GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * The full GNU General Public License is included in this distribution - * in the file called COPYING. - * - * Contact Information: - * Intel Linux Wireless <linuxwifi@intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2015 Intel Deutschland GmbH - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -#include "mvm.h" -#include "fw/api/tof.h" - -#define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256 - -void iwl_mvm_tof_init(struct iwl_mvm *mvm) -{ - struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return; - - memset(tof_data, 0, sizeof(*tof_data)); - - tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (IWL_MVM_TOF_IS_RESPONDER) { - tof_data->responder_cfg.sub_grp_cmd_id = - cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); - tof_data->responder_cfg.sta_id = IWL_MVM_INVALID_STA; - } -#endif - - tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); - tof_data->range_req.req_timeout = 1; - tof_data->range_req.initiator = 1; - tof_data->range_req.report_policy = 3; - - tof_data->range_req_ext.sub_grp_cmd_id = - cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); - - mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; -} - -void iwl_mvm_tof_clean(struct iwl_mvm *mvm) -{ - struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; - - if (!fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_TOF_SUPPORT) || - !(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE)) - return; - - memset(tof_data, 0, sizeof(*tof_data)); - mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE; -} - -static void iwl_tof_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - bool *enabled = _data; - - /* non bss vif exists */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) - *enabled = false; -} - -int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) -{ - struct iwl_tof_config_cmd *cmd = &mvm->tof_data.tof_cfg; - bool enabled; - - lockdep_assert_held(&mvm->mutex); - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return -EINVAL; - - ieee80211_iterate_active_interfaces_atomic(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_tof_iterator, &enabled); - if (!enabled) { - IWL_DEBUG_INFO(mvm, "ToF is not supported (non bss vif)\n"); - return -EINVAL; - } - - mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, - IWL_ALWAYS_LONG_GROUP, 0), - 0, sizeof(*cmd), cmd); -} - -int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) -{ - struct iwl_tof_range_abort_cmd cmd = { - .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), - .request_id = id, - }; - - lockdep_assert_held(&mvm->mutex); - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return -EINVAL; - - if (id != mvm->tof_data.active_range_request) { - IWL_ERR(mvm, "Invalid range request id %d (active %d)\n", - id, mvm->tof_data.active_range_request); - return -EINVAL; - } - - /* after abort is sent there's no active request anymore */ - mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, - IWL_ALWAYS_LONG_GROUP, 0), - 0, sizeof(cmd), &cmd); -} - -#ifdef CONFIG_IWLWIFI_DEBUGFS -int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_tof_responder_config_cmd *cmd = &mvm->tof_data.responder_cfg; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - lockdep_assert_held(&mvm->mutex); - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return -EINVAL; - - if (vif->p2p || vif->type != NL80211_IFTYPE_AP || - !mvmvif->ap_ibss_active) { - IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); - return -EIO; - } - - cmd->sta_id = mvmvif->bcast_sta.sta_id; - memcpy(cmd->bssid, vif->addr, ETH_ALEN); - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, - IWL_ALWAYS_LONG_GROUP, 0), - 0, sizeof(*cmd), cmd); -} -#endif - -int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_host_cmd cmd = { - .id = iwl_cmd_id(TOF_CMD, IWL_ALWAYS_LONG_GROUP, 0), - .len = { sizeof(mvm->tof_data.range_req), }, - /* no copy because of the command size */ - .dataflags = { IWL_HCMD_DFL_NOCOPY, }, - }; - - lockdep_assert_held(&mvm->mutex); - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return -EINVAL; - - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { - IWL_ERR(mvm, "Cannot send range request, not STA mode\n"); - return -EIO; - } - - /* nesting of range requests is not supported in FW */ - if (mvm->tof_data.active_range_request != - IWL_MVM_TOF_RANGE_REQ_MAX_ID) { - IWL_ERR(mvm, "Cannot send range req, already active req %d\n", - mvm->tof_data.active_range_request); - return -EIO; - } - - mvm->tof_data.active_range_request = mvm->tof_data.range_req.request_id; - - cmd.data[0] = &mvm->tof_data.range_req; - return iwl_mvm_send_cmd(mvm, &cmd); -} - -int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - lockdep_assert_held(&mvm->mutex); - - if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) - return -EINVAL; - - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { - IWL_ERR(mvm, "Cannot send ext range req, not in STA mode\n"); - return -EIO; - } - - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, - IWL_ALWAYS_LONG_GROUP, 0), - 0, sizeof(mvm->tof_data.range_req_ext), - &mvm->tof_data.range_req_ext); -} - -static int iwl_mvm_tof_range_resp(struct iwl_mvm *mvm, void *data) -{ - struct iwl_tof_range_rsp_ntfy *resp = (void *)data; - - if (resp->request_id != mvm->tof_data.active_range_request) { - IWL_ERR(mvm, "Request id mismatch, got %d, active %d\n", - resp->request_id, mvm->tof_data.active_range_request); - return -EIO; - } - - memcpy(&mvm->tof_data.range_resp, resp, - sizeof(struct iwl_tof_range_rsp_ntfy)); - mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - - return 0; -} - -static int iwl_mvm_tof_mcsi_notif(struct iwl_mvm *mvm, void *data) -{ - struct iwl_tof_mcsi_notif *resp = (struct iwl_tof_mcsi_notif *)data; - - IWL_DEBUG_INFO(mvm, "MCSI notification, token %d\n", resp->token); - return 0; -} - -static int iwl_mvm_tof_nb_report_notif(struct iwl_mvm *mvm, void *data) -{ - struct iwl_tof_neighbor_report *report = - (struct iwl_tof_neighbor_report *)data; - - IWL_DEBUG_INFO(mvm, "NB report, bssid %pM, token %d, status 0x%x\n", - report->bssid, report->request_token, report->status); - return 0; -} - -void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_tof_gen_resp_cmd *resp = (void *)pkt->data; - - lockdep_assert_held(&mvm->mutex); - - switch (le32_to_cpu(resp->sub_grp_cmd_id)) { - case TOF_RANGE_RESPONSE_NOTIF: - iwl_mvm_tof_range_resp(mvm, resp->data); - break; - case TOF_MCSI_DEBUG_NOTIF: - iwl_mvm_tof_mcsi_notif(mvm, resp->data); - break; - case TOF_NEIGHBOR_REPORT_RSP_NOTIF: - iwl_mvm_tof_nb_report_notif(mvm, resp->data); - break; - default: - IWL_ERR(mvm, "Unknown sub-group command 0x%x\n", - resp->sub_grp_cmd_id); - break; - } -} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ec57682efe54..0c2aabc842f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -209,7 +209,9 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, u16 offload_assist = 0; u8 ac; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) || + (ieee80211_is_probe_resp(fc) && + !is_multicast_ether_addr(hdr->addr1))) tx_flags |= TX_CMD_FLG_ACK; else tx_flags &= ~TX_CMD_FLG_ACK; @@ -278,7 +280,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, } if (ieee80211_is_data(fc) && len > mvm->rts_threshold && - !is_multicast_ether_addr(ieee80211_get_DA(hdr))) + !is_multicast_ether_addr(hdr->addr1)) tx_flags |= TX_CMD_FLG_PROT_REQUIRE; if (fw_has_capa(&mvm->fw->ucode_capa, @@ -302,13 +304,30 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, offload_assist)); } +static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc) +{ + if (info->band == NL80211_BAND_2GHZ && + !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) + return mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS; + + if (sta && ieee80211_is_data(fc)) { + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + return BIT(mvmsta->tx_ant) << RATE_MCS_ANT_POS; + } + + return BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; +} + static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, struct ieee80211_sta *sta) { int rate_idx; u8 rate_plcp; - u32 rate_flags; + u32 rate_flags = 0; /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS, @@ -332,13 +351,6 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, /* Get PLCP rate for tx_cmd->rate_n_flags */ rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); - if (info->band == NL80211_BAND_2GHZ && - !iwl_mvm_bt_coex_is_shared_ant_avail(mvm)) - rate_flags = mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS; - else - rate_flags = - BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; - /* Set CCK flag as needed */ if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) rate_flags |= RATE_MCS_CCK_MSK; @@ -346,6 +358,14 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, return (u32)rate_plcp | rate_flags; } +static u32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc) +{ + return iwl_mvm_get_tx_rate(mvm, info, sta) | + iwl_mvm_get_tx_ant(mvm, info, sta, fc); +} + /* * Sets the fields in the Tx cmd that are rate related */ @@ -373,20 +393,21 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, */ if (ieee80211_is_data(fc) && sta) { - tx_cmd->initial_rate_index = 0; - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); - return; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + + if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { + tx_cmd->initial_rate_index = 0; + tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); + return; + } } else if (ieee80211_is_back_req(fc)) { tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR); } - mvm->mgmt_last_antenna_idx = - iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm), - mvm->mgmt_last_antenna_idx); - /* Set the rate in the TX cmd */ - tx_cmd->rate_n_flags = cpu_to_le32(iwl_mvm_get_tx_rate(mvm, info, sta)); + tx_cmd->rate_n_flags = + cpu_to_le32(iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc)); } static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, @@ -491,6 +512,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, u16 offload_assist = 0; u32 rate_n_flags = 0; u16 flags = 0; + struct iwl_mvm_sta *mvmsta = sta ? + iwl_mvm_sta_from_mac80211(sta) : NULL; if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); @@ -510,10 +533,17 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, if (!info->control.hw_key) flags |= IWL_TX_FLAGS_ENCRYPT_DIS; - /* For data packets rate info comes from the fw */ - if (!(ieee80211_is_data(hdr->frame_control) && sta)) { + /* + * For data packets rate info comes from the fw. Only + * set rate/antenna during connection establishment or in case + * no station is given. + */ + if (!sta || !ieee80211_is_data(hdr->frame_control) || + mvmsta->sta_state < IEEE80211_STA_AUTHORIZED) { flags |= IWL_TX_FLAGS_CMD_RATE; - rate_n_flags = iwl_mvm_get_tx_rate(mvm, info, sta); + rate_n_flags = + iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, + hdr->frame_control); } if (mvm->trans->cfg->device_family >= @@ -575,11 +605,12 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb, } static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, __le16 fc) + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr) { - struct iwl_mvm_vif *mvmvif; - - mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(info->control.vif); + __le16 fc = hdr->frame_control; switch (info->control.vif->type) { case NL80211_IFTYPE_AP: @@ -598,7 +629,9 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, (!ieee80211_is_bufferable_mmpdu(fc) || ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc))) return mvm->probe_queue; - if (info->hw_queue == info->control.vif->cab_queue) + + if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) && + is_multicast_ether_addr(hdr->addr1)) return mvmvif->cab_queue; WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC, @@ -607,8 +640,6 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, case NL80211_IFTYPE_P2P_DEVICE: if (ieee80211_is_mgmt(fc)) return mvm->p2p_dev_queue; - if (info->hw_queue == info->control.vif->cab_queue) - return mvmvif->cab_queue; WARN_ON_ONCE(1); return mvm->p2p_dev_queue; @@ -681,45 +712,23 @@ out: int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info info; struct iwl_device_cmd *dev_cmd; u8 sta_id; int hdrlen = ieee80211_hdrlen(hdr->frame_control); __le16 fc = hdr->frame_control; - int queue; + bool offchannel = IEEE80211_SKB_CB(skb)->flags & + IEEE80211_TX_CTL_TX_OFFCHAN; + int queue = -1; - /* IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used - * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel - * queue. STATION (HS2.0) uses the auxiliary context of the FW, - * and hence needs to be sent on the aux queue - */ - if (skb_info->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && - skb_info->control.vif->type == NL80211_IFTYPE_STATION) - skb_info->hw_queue = mvm->aux_queue; + if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc)) + return -1; memcpy(&info, skb->cb, sizeof(info)); if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU)) return -1; - if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && - (!info.control.vif || - info.hw_queue != info.control.vif->cab_queue))) - return -1; - - queue = info.hw_queue; - - /* - * If the interface on which the frame is sent is the P2P_DEVICE - * or an AP/GO interface use the broadcast station associated - * with it; otherwise if the interface is a managed interface - * use the AP station associated with it for multicast traffic - * (this is not possible for unicast packets as a TLDS discovery - * response are sent without a station entry); otherwise use the - * AUX station. - */ - sta_id = mvm->aux_sta.sta_id; if (info.control.vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info.control.vif); @@ -732,22 +741,30 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) else sta_id = mvmvif->mcast_sta.sta_id; - queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, - hdr->frame_control); - if (queue < 0) - return -1; - } else if (info.control.vif->type == NL80211_IFTYPE_STATION && - is_multicast_ether_addr(hdr->addr1)) { - u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id); - - if (ap_sta_id != IWL_MVM_INVALID_STA) - sta_id = ap_sta_id; + queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr); } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->snif_queue; sta_id = mvm->snif_sta.sta_id; + } else if (info.control.vif->type == NL80211_IFTYPE_STATION && + offchannel) { + /* + * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets + * that can be used in 2 different types of vifs, P2P & + * STATION. + * P2P uses the offchannel queue. + * STATION (HS2.0) uses the auxiliary context of the FW, + * and hence needs to be sent on the aux queue. + */ + sta_id = mvm->aux_sta.sta_id; + queue = mvm->aux_queue; } } + if (queue < 0) { + IWL_ERR(mvm, "No queue was found. Dropping TX\n"); + return -1; + } + if (unlikely(ieee80211_is_probe_resp(fc))) iwl_mvm_probe_resp_set_noa(mvm, skb); @@ -768,6 +785,35 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) return 0; } +unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, unsigned int tid) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band; + u8 ac = tid_to_mac80211_ac[tid]; + unsigned int txf; + int lmac = IWL_LMAC_24G_INDEX; + + if (iwl_mvm_is_cdb_supported(mvm) && + band == NL80211_BAND_5GHZ) + lmac = IWL_LMAC_5G_INDEX; + + /* For HE redirect to trigger based fifos */ + if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm))) + ac += 4; + + txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac); + + /* + * Don't send an AMSDU that will be longer than the TXF. + * Add a security margin of 256 for the TX command + headers. + * We also want to have the start of the next packet inside the + * fifo to be able to send bursts. + */ + return min_t(unsigned int, mvmsta->max_amsdu_len, + mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); +} + #ifdef CONFIG_INET static int @@ -837,36 +883,6 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, return 0; } -static unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, - struct ieee80211_sta *sta, - unsigned int tid) -{ - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band; - u8 ac = tid_to_mac80211_ac[tid]; - unsigned int txf; - int lmac = IWL_LMAC_24G_INDEX; - - if (iwl_mvm_is_cdb_supported(mvm) && - band == NL80211_BAND_5GHZ) - lmac = IWL_LMAC_5G_INDEX; - - /* For HE redirect to trigger based fifos */ - if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm))) - ac += 4; - - txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac); - - /* - * Don't send an AMSDU that will be longer than the TXF. - * Add a security margin of 256 for the TX command + headers. - * We also want to have the start of the next packet inside the - * fifo to be able to send bursts. - */ - return min_t(unsigned int, mvmsta->max_amsdu_len, - mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); -} - static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, @@ -989,34 +1005,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, } #endif -static void iwl_mvm_tx_add_stream(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvm_sta, u8 tid, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u8 mac_queue = info->hw_queue; - struct sk_buff_head *deferred_tx_frames; - - lockdep_assert_held(&mvm_sta->lock); - - mvm_sta->deferred_traffic_tid_map |= BIT(tid); - set_bit(mvm_sta->sta_id, mvm->sta_deferred_frames); - - deferred_tx_frames = &mvm_sta->tid_data[tid].deferred_tx_frames; - - skb_queue_tail(deferred_tx_frames, skb); - - /* - * The first deferred frame should've stopped the MAC queues, so we - * should never get a second deferred frame for the RA/TID. - * In case of GSO the first packet may have been split, so don't warn. - */ - if (skb_queue_len(deferred_tx_frames) == 1) { - iwl_mvm_stop_mac_queues(mvm, BIT(mac_queue)); - schedule_work(&mvm->add_stream_wk); - } -} - /* Check if there are any timed-out TIDs on a given shared TXQ */ static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id) { @@ -1041,7 +1029,12 @@ static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm, int airtime) { int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; - struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + struct iwl_mvm_tcm_mac *mdata; + + if (mac >= NUM_MAC_INDEX_DRIVER) + return; + + mdata = &mvm->tcm.data[mac]; if (mvm->tcm.paused) return; @@ -1052,14 +1045,21 @@ static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm, mdata->tx.airtime += airtime; } -static void iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm, - struct iwl_mvm_sta *mvmsta, int tid) +static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, int tid) { u32 ac = tid_to_mac80211_ac[tid]; int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; - struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac]; + struct iwl_mvm_tcm_mac *mdata; + + if (mac >= NUM_MAC_INDEX_DRIVER) + return -EINVAL; + + mdata = &mvm->tcm.data[mac]; mdata->tx.pkts[ac]++; + + return 0; } /* @@ -1075,7 +1075,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, __le16 fc; u16 seq_number = 0; u8 tid = IWL_MAX_TID_COUNT; - u16 txq_id = info->hw_queue; + u16 txq_id; bool is_ampdu = false; int hdrlen; @@ -1083,6 +1083,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, fc = hdr->frame_control; hdrlen = ieee80211_hdrlen(fc); + if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc)) + return -1; + if (WARN_ON_ONCE(!mvmsta)) return -1; @@ -1112,12 +1115,14 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, */ if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { tid = ieee80211_get_tid(hdr); - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + if (WARN_ONCE(tid >= IWL_MAX_TID_COUNT, "Invalid TID %d", tid)) goto drop_unlock_sta; is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; - if (WARN_ON_ONCE(is_ampdu && - mvmsta->tid_data[tid].state != IWL_AGG_ON)) + if (WARN_ONCE(is_ampdu && + mvmsta->tid_data[tid].state != IWL_AGG_ON, + "Invalid internal agg state %d for TID %d", + mvmsta->tid_data[tid].state, tid)) goto drop_unlock_sta; seq_number = mvmsta->tid_data[tid].seq_number; @@ -1139,14 +1144,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); - /* Check if TXQ needs to be allocated or re-activated */ - if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE)) { - iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); - - /* - * The frame is now deferred, and the worker scheduled - * will re-allocate it, so we can free it for now. - */ + if (WARN_ONCE(txq_id == IWL_MVM_INVALID_QUEUE, "Invalid TXQ id")) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); spin_unlock(&mvmsta->lock); return 0; @@ -1160,11 +1158,11 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, * If we have timed-out TIDs - schedule the worker that will * reconfig the queues and update them * - * Note that the mvm->queue_info_lock isn't being taken here in - * order to not serialize the TX flow. This isn't dangerous - * because scheduling mvm->add_stream_wk can't ruin the state, - * and if we DON'T schedule it due to some race condition then - * next TX we get here we will. + * Note that the no lock is taken here in order to not serialize + * the TX flow. This isn't dangerous because scheduling + * mvm->add_stream_wk can't ruin the state, and if we DON'T + * schedule it due to some race condition then next TX we get + * here we will. */ if (unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED && @@ -1186,7 +1184,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, spin_unlock(&mvmsta->lock); - iwl_mvm_tx_pkt_queued(mvm, mvmsta, tid == IWL_MAX_TID_COUNT ? 0 : tid); + if (iwl_mvm_tx_pkt_queued(mvm, mvmsta, + tid == IWL_MAX_TID_COUNT ? 0 : tid)) + goto drop; return 0; @@ -1194,6 +1194,7 @@ drop_unlock_sta: iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); spin_unlock(&mvmsta->lock); drop: + IWL_DEBUG_TX(mvm, "TX to [%d|%d] dropped\n", mvmsta->sta_id, tid); return -1; } @@ -1451,7 +1452,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, iwl_mvm_get_agg_status(mvm, tx_resp); u32 status = le16_to_cpu(agg_status->status); u16 ssn = iwl_mvm_get_scd_ssn(mvm, tx_resp); - struct iwl_mvm_sta *mvmsta; struct sk_buff_head skbs; u8 skb_freed = 0; u8 lq_color; @@ -1501,6 +1501,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, break; } + if ((status & TX_STATUS_MSK) != TX_STATUS_SUCCESS && + ieee80211_is_mgmt(hdr->frame_control)) + iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); + /* * If we are freeing multiple frames, mark all the frames * but the first one as acked, since they were acknowledged @@ -1595,11 +1599,15 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, goto out; if (!IS_ERR(sta)) { - mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); iwl_mvm_tx_airtime(mvm, mvmsta, le16_to_cpu(tx_resp->wireless_media_time)); + if ((status & TX_STATUS_MSK) != TX_STATUS_SUCCESS && + mvmsta->sta_state < IEEE80211_STA_AUTHORIZED) + iwl_mvm_toggle_tx_ant(mvm, &mvmsta->tx_ant); + if (sta->wme && tid != IWL_MGMT_TID) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; @@ -1654,10 +1662,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, mvmsta->next_status_eosp = false; ieee80211_sta_eosp(sta); } - } else { - mvmsta = NULL; } - out: rcu_read_unlock(); } @@ -1800,8 +1805,6 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid, return; } - spin_lock_bh(&mvmsta->lock); - __skb_queue_head_init(&reclaimed_skbs); /* @@ -1811,6 +1814,8 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid, */ iwl_trans_reclaim(mvm->trans, txq, index, &reclaimed_skbs); + spin_lock_bh(&mvmsta->lock); + tid_data->next_reclaimed = index; iwl_mvm_check_ratid_empty(mvm, sta, tid); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 818e1180bbdd..4649327abb45 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -248,7 +248,7 @@ void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n", le16_to_cpu(err_resp->bad_cmd_seq_num), le32_to_cpu(err_resp->error_service)); - IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n", + IWL_ERR(mvm, "FW Error notification: timestamp 0x%016llX\n", le64_to_cpu(err_resp->timestamp)); } @@ -285,6 +285,7 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) return last_idx; } +#define FW_SYSASSERT_CPU_MASK 0xf0000000 static const struct { const char *name; u8 num; @@ -293,6 +294,7 @@ static const struct { { "SYSASSERT", 0x35 }, { "UCODE_VERSION_MISMATCH", 0x37 }, { "BAD_COMMAND", 0x38 }, + { "BAD_COMMAND", 0x39 }, { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, { "FATAL_ERROR", 0x3D }, { "NMI_TRM_HW_ERR", 0x46 }, @@ -301,6 +303,9 @@ static const struct { { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, { "NMI_INTERRUPT_HOST", 0x66 }, + { "NMI_INTERRUPT_LMAC_FATAL", 0x70 }, + { "NMI_INTERRUPT_UMAC_FATAL", 0x71 }, + { "NMI_INTERRUPT_OTHER_LMAC_FATAL", 0x73 }, { "NMI_INTERRUPT_ACTION_PT", 0x7C }, { "NMI_INTERRUPT_UNKNOWN", 0x84 }, { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, @@ -312,7 +317,7 @@ static const char *desc_lookup(u32 num) int i; for (i = 0; i < ARRAY_SIZE(advanced_lookup) - 1; i++) - if (advanced_lookup[i].num == num) + if (advanced_lookup[i].num == (num & ~FW_SYSASSERT_CPU_MASK)) return advanced_lookup[i].name; /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */ @@ -452,12 +457,17 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) { struct iwl_trans *trans = mvm->trans; struct iwl_umac_error_event_table table; + u32 base = mvm->trans->umac_error_event_table; - if (!mvm->support_umac_log) + if (!mvm->support_umac_log && + !(mvm->trans->error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_UMAC)) return; - iwl_trans_read_mem_bytes(trans, mvm->umac_error_event_table, &table, - sizeof(table)); + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (table.valid) + mvm->fwrt.dump.umac_err_id = table.error_id; if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); @@ -482,11 +492,11 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); } -static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) +static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num) { struct iwl_trans *trans = mvm->trans; struct iwl_error_event_table table; - u32 val; + u32 val, base = mvm->trans->lmac_error_event_table[lmac_num]; if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) { if (!base) @@ -515,27 +525,16 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) /* reset the device */ iwl_trans_sw_reset(trans); - /* set INIT_DONE flag */ - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - - /* and wait for clock stabilization */ - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) - udelay(2); - - err = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (err < 0) { - IWL_DEBUG_INFO(trans, - "Failed to reset the card for the dump\n"); + err = iwl_finish_nic_init(trans); + if (err) return; - } } iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + if (table.valid) + mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id; + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", @@ -591,10 +590,10 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) return; } - iwl_mvm_dump_lmac_error_log(mvm, mvm->error_event_table[0]); + iwl_mvm_dump_lmac_error_log(mvm, 0); - if (mvm->error_event_table[1]) - iwl_mvm_dump_lmac_error_log(mvm, mvm->error_event_table[1]); + if (mvm->trans->lmac_error_event_table[1]) + iwl_mvm_dump_lmac_error_log(mvm, 1); iwl_mvm_dump_umac_error_log(mvm); } @@ -618,13 +617,9 @@ int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) return -EINVAL; - spin_lock_bh(&mvm->queue_info_lock); if (WARN(mvm->queue_info[queue].tid_bitmap == 0, - "Trying to reconfig unallocated queue %d\n", queue)) { - spin_unlock_bh(&mvm->queue_info_lock); + "Trying to reconfig unallocated queue %d\n", queue)) return -ENXIO; - } - spin_unlock_bh(&mvm->queue_info_lock); IWL_DEBUG_TX_QUEUES(mvm, "Reconfig SCD for TXQ #%d\n", queue); @@ -768,6 +763,29 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) return result; } +void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm, + bool low_latency, u16 mac_id) +{ + struct iwl_mac_low_latency_cmd cmd = { + .mac_id = cpu_to_le32(mac_id) + }; + + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) + return; + + if (low_latency) { + /* currently we don't care about the direction */ + cmd.low_latency_rx = 1; + cmd.low_latency_tx = 1; + } + + if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(LOW_LATENCY_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd)) + IWL_ERR(mvm, "Failed to send low latency command\n"); +} + int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool low_latency, enum iwl_mvm_low_latency_cause cause) @@ -786,24 +804,7 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (low_latency == prev) return 0; - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) { - struct iwl_mac_low_latency_cmd cmd = { - .mac_id = cpu_to_le32(mvmvif->id) - }; - - if (low_latency) { - /* currently we don't care about the direction */ - cmd.low_latency_rx = 1; - cmd.low_latency_tx = 1; - } - res = iwl_mvm_send_cmd_pdu(mvm, - iwl_cmd_id(LOW_LATENCY_CMD, - MAC_CONF_GROUP, 0), - 0, sizeof(cmd), &cmd); - if (res) - IWL_ERR(mvm, "Failed to send low latency command\n"); - } + iwl_mvm_send_low_latency_cmd(mvm, low_latency, mvmvif->id); res = iwl_mvm_update_quotas(mvm, false, NULL); if (res) @@ -1124,19 +1125,14 @@ static void iwl_mvm_tcm_uapsd_nonagg_detected_wk(struct work_struct *wk) "AP isn't using AMPDU with uAPSD enabled"); } -static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - int *mac_id = data; if (vif->type != NL80211_IFTYPE_STATION) return; - if (mvmvif->id != *mac_id) - return; - if (!vif->bss_conf.assoc) return; @@ -1146,10 +1142,10 @@ static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac, !mvmvif->queue_params[IEEE80211_AC_BK].uapsd) return; - if (mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected) + if (mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected) return; - mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected = true; + mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected = true; IWL_INFO(mvm, "detected AP should do aggregation but isn't, likely due to U-APSD\n"); schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk, 15 * HZ); @@ -1162,6 +1158,7 @@ static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm, u64 bytes = mvm->tcm.data[mac].uapsd_nonagg_detect.rx_bytes; u64 tpt; unsigned long rate; + struct ieee80211_vif *vif; rate = ewma_rate_read(&mvm->tcm.data[mac].uapsd_nonagg_detect.rate); @@ -1190,9 +1187,11 @@ static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm, return; } - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_uapsd_agg_disconnect_iter, &mac); + rcu_read_lock(); + vif = rcu_dereference(mvm->vif_id_to_mac[mac]); + if (vif) + iwl_mvm_uapsd_agg_disconnect(mvm, vif); + rcu_read_unlock(); } static void iwl_mvm_tcm_iterator(void *_data, u8 *mac, @@ -1372,6 +1371,7 @@ void iwl_mvm_pause_tcm(struct iwl_mvm *mvm, bool with_cancel) void iwl_mvm_resume_tcm(struct iwl_mvm *mvm) { int mac; + bool low_latency = false; spin_lock_bh(&mvm->tcm.lock); mvm->tcm.ts = jiffies; @@ -1383,10 +1383,23 @@ void iwl_mvm_resume_tcm(struct iwl_mvm *mvm) memset(&mdata->tx.pkts, 0, sizeof(mdata->tx.pkts)); memset(&mdata->rx.airtime, 0, sizeof(mdata->rx.airtime)); memset(&mdata->tx.airtime, 0, sizeof(mdata->tx.airtime)); + + if (mvm->tcm.result.low_latency[mac]) + low_latency = true; } /* The TCM data needs to be reset before "paused" flag changes */ smp_mb(); mvm->tcm.paused = false; + + /* + * if the current load is not low or low latency is active, force + * re-evaluation to cover the case of no traffic. + */ + if (mvm->tcm.result.global_load > IWL_MVM_TRAFFIC_LOW) + schedule_delayed_work(&mvm->tcm.work, MVM_TCM_PERIOD); + else if (low_latency) + schedule_delayed_work(&mvm->tcm.work, MVM_LL_PERIOD); + spin_unlock_bh(&mvm->tcm.lock); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 05ed4fb88e0c..1e36459948db 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,7 +18,7 @@ * * BSD LICENSE * - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +66,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, void *iml_img; u32 control_flags = 0; int ret; + int cmdq_size = max_t(u32, TFD_CMD_SLOTS, trans->cfg->min_txq_size); /* Allocate prph scratch */ prph_scratch = dma_alloc_coherent(trans->dev, sizeof(*prph_scratch), @@ -94,11 +95,14 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, cpu_to_le64(trans_pcie->rxq->bd_dma); /* Configure debug, for integration */ - iwl_pcie_alloc_fw_monitor(trans, 0); - prph_sc_ctrl->hwm_cfg.hwm_base_addr = - cpu_to_le64(trans->fw_mon[0].physical); - prph_sc_ctrl->hwm_cfg.hwm_size = - cpu_to_le32(trans->fw_mon[0].size); + if (!trans->ini_valid) + iwl_pcie_alloc_fw_monitor(trans, 0); + if (trans->num_blocks) { + prph_sc_ctrl->hwm_cfg.hwm_base_addr = + cpu_to_le64(trans->fw_mon[0].physical); + prph_sc_ctrl->hwm_cfg.hwm_size = + cpu_to_le32(trans->fw_mon[0].size); + } /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram); @@ -148,7 +152,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, ctxt_info_gen3->mcr_base_addr = cpu_to_le64(trans_pcie->rxq->used_bd_dma); ctxt_info_gen3->mtr_size = - cpu_to_le16(TFD_QUEUE_CB_SIZE(TFD_CMD_SLOTS)); + cpu_to_le16(TFD_QUEUE_CB_SIZE(cmdq_size)); ctxt_info_gen3->mcr_size = cpu_to_le16(RX_QUEUE_CB_SIZE(MQ_RX_TABLE_SIZE)); @@ -172,8 +176,13 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, iwl_write64(trans, CSR_IML_DATA_ADDR, trans_pcie->iml_dma_addr); iwl_write32(trans, CSR_IML_SIZE_ADDR, trans->iml_len); - iwl_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL, CSR_AUTO_FUNC_BOOT_ENA); - iwl_set_bit(trans, CSR_GP_CNTRL, CSR_AUTO_FUNC_INIT); + + iwl_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL, + CSR_AUTO_FUNC_BOOT_ENA); + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); + else + iwl_set_bit(trans, CSR_GP_CNTRL, CSR_AUTO_FUNC_INIT); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 6f45a0303ddd..9274e317cc77 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -59,8 +59,7 @@ void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + struct iwl_self_init_dram *dram = &trans->init_dram; int i; if (!dram->paging) { @@ -83,8 +82,7 @@ int iwl_pcie_init_fw_sec(struct iwl_trans *trans, const struct fw_img *fw, struct iwl_context_info_dram *ctxt_dram) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + struct iwl_self_init_dram *dram = &trans->init_dram; int i, ret, lmac_cnt, umac_cnt, paging_cnt; if (WARN(dram->paging, @@ -227,7 +225,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, iwl_enable_interrupts(trans); /* Configure debug, if exists */ - if (trans->dbg_dest_tlv) + if (iwl_pcie_dbg_on(trans)) iwl_pcie_apply_destination(trans); /* kick FW self load */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 9e015212c2c0..9f1af8da9dc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -8,7 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016-2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -513,13 +513,70 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)}, /* 9000 Series */ - {IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x02F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0040, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0044, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0244, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x02F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0040, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0044, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0244, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x06F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x001C, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x003C, iwl9560_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0060, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0064, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x00A0, iwl9460_2ac_cfg)}, @@ -543,24 +600,28 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4018, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x401C, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x8014, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x8010, iwl9260_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_160_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0214, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x271C, 0x0214, iwl9260_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2720, 0x0034, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2720, 0x0038, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2720, 0x003C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0034, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0038, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x003C, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0044, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x2720, 0x0060, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -569,6 +630,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x0234, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2720, 0x0238, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2720, 0x023C, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x0244, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x2720, 0x0260, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)}, @@ -578,17 +640,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2720, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2720, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_160_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -606,17 +668,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x30DC, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_160_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_160_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_160_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_shared_clk)}, @@ -634,18 +696,19 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x31DC, 0x1551, iwl9560_killer_s_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x1552, iwl9560_killer_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_160_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_160_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_160_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_160_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)}, - {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0044, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, @@ -654,24 +717,25 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x0244, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x1551, killer1550s_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x1552, killer1550i_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_160_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_qu_b0_jf_b0)}, {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_qu_b0_jf_b0)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -689,17 +753,18 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x3DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0044, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -708,6 +773,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0244, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)}, @@ -717,19 +783,19 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x43F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x003C, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0060, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -755,18 +821,19 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0044, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -775,6 +842,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0244, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)}, @@ -784,17 +852,17 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA0F0, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x003C, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0060, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x00A0, iwl9462_2ac_cfg_soc)}, @@ -812,41 +880,99 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1551, iwl9560_killer_s_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x1552, iwl9560_killer_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_160_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_160_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x40A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x0030, iwl9560_2ac_cfg_qnj_jf_b0)}, /* 22000 Series */ - {IWL_PCI_DEVICE(0x2720, 0x0000, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x2720, 0x0040, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x2720, 0x0078, iwl22000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x007C, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x0310, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x02F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x02F0, 0x4070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x007C, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x0310, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x06F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x06F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x06F0, 0x4070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0000, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0040, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x2720, 0x0070, iwl22000_2ac_cfg_hr_cdb)}, - {IWL_PCI_DEVICE(0x2720, 0x0030, iwl22000_2ac_cfg_hr_cdb)}, - {IWL_PCI_DEVICE(0x2720, 0x1080, iwl22000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x007C, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x2720, 0x0090, iwl22000_2ac_cfg_hr_cdb)}, {IWL_PCI_DEVICE(0x2720, 0x0310, iwl22000_2ac_cfg_hr_cdb)}, - {IWL_PCI_DEVICE(0x34F0, 0x0040, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x34F0, 0x0070, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x34F0, 0x0078, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x34F0, 0x0310, iwl22000_2ac_cfg_jf)}, + {IWL_PCI_DEVICE(0x2720, 0x0A10, iwl22000_2ac_cfg_hr_cdb)}, + {IWL_PCI_DEVICE(0x2720, 0x1080, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x2720, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x2720, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x2720, 0x4070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0040, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x007C, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x0310, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x34F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x34F0, 0x4070, iwl_ax101_cfg_qu_hr)}, {IWL_PCI_DEVICE(0x40C0, 0x0000, iwl22560_2ax_cfg_su_cdb)}, {IWL_PCI_DEVICE(0x40C0, 0x0010, iwl22560_2ax_cfg_su_cdb)}, {IWL_PCI_DEVICE(0x40c0, 0x0090, iwl22560_2ax_cfg_su_cdb)}, {IWL_PCI_DEVICE(0x40C0, 0x0310, iwl22560_2ax_cfg_su_cdb)}, {IWL_PCI_DEVICE(0x40C0, 0x0A10, iwl22560_2ax_cfg_su_cdb)}, - {IWL_PCI_DEVICE(0x43F0, 0x0040, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x43F0, 0x0070, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0x43F0, 0x0078, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0000, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0040, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0070, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0078, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x00B0, iwl22000_2ax_cfg_hr)}, - {IWL_PCI_DEVICE(0xA0F0, 0x0A10, iwl22000_2ax_cfg_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x0040, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x0070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x007C, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0x43F0, 0x4070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0000, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0040, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0070, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0074, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0078, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x007C, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00B0, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0A10, iwl_ax101_cfg_qu_hr)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4070, iwl_ax101_cfg_qu_hr)}, + + {IWL_PCI_DEVICE(0x2723, 0x0080, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x0084, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x0088, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x008C, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x1653, killer1650w_2ax_cfg)}, + {IWL_PCI_DEVICE(0x2723, 0x1654, killer1650x_2ax_cfg)}, + {IWL_PCI_DEVICE(0x2723, 0x2080, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x4080, iwl_ax200_cfg_cc)}, + {IWL_PCI_DEVICE(0x2723, 0x4088, iwl_ax200_cfg_cc)}, + + {IWL_PCI_DEVICE(0x1a56, 0x1653, killer1650w_2ax_cfg)}, + {IWL_PCI_DEVICE(0x1a56, 0x1654, killer1650x_2ax_cfg)}, + + {IWL_PCI_DEVICE(0x2725, 0x0090, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x7A70, 0x0090, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x7A70, 0x0310, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x2725, 0x0020, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x2725, 0x0310, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x2725, 0x0A10, iwlax210_2ax_cfg_so_hr_a0)}, + {IWL_PCI_DEVICE(0x2725, 0x00B0, iwlax210_2ax_cfg_so_hr_a0)}, #endif /* CONFIG_IWLMVM */ @@ -899,7 +1025,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rf_id_chp == jf_chp_id) { if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QNJ) - cfg = &iwl22000_2ax_cfg_qnj_jf_b0; + cfg = &iwl9560_2ac_cfg_qnj_jf_b0; else cfg = &iwl22000_2ac_cfg_jf; } else if (rf_id_chp == hr_chp_id) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index f9c4c64dee66..59213164f35e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -1,12 +1,14 @@ /****************************************************************************** * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -18,12 +20,46 @@ * more details. * * The full GNU General Public License is included in this distribution in the - * file called LICENSE. + * file called COPYING. * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * + * BSD LICENSE + * + * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * *****************************************************************************/ #ifndef __iwl_trans_int_pcie_h__ #define __iwl_trans_int_pcie_h__ @@ -364,6 +400,8 @@ struct iwl_txq { u32 id; int low_mark; int high_mark; + + bool overflow_tx; }; static inline dma_addr_t @@ -378,6 +416,23 @@ struct iwl_tso_hdr_page { u8 *pos; }; +#ifdef CONFIG_IWLWIFI_DEBUGFS +/** + * enum iwl_fw_mon_dbgfs_state - the different states of the monitor_data + * debugfs file + * + * @IWL_FW_MON_DBGFS_STATE_CLOSED: the file is closed. + * @IWL_FW_MON_DBGFS_STATE_OPEN: the file is open. + * @IWL_FW_MON_DBGFS_STATE_DISABLED: the file is disabled, once this state is + * set the file can no longer be used. + */ +enum iwl_fw_mon_dbgfs_state { + IWL_FW_MON_DBGFS_STATE_CLOSED, + IWL_FW_MON_DBGFS_STATE_OPEN, + IWL_FW_MON_DBGFS_STATE_DISABLED, +}; +#endif + /** * enum iwl_shared_irq_flags - level of sharing for irq * @IWL_SHARED_IRQ_NON_RX: interrupt vector serves non rx causes. @@ -401,18 +456,24 @@ enum iwl_image_response_code { }; /** - * struct iwl_self_init_dram - dram data used by self init process - * @fw: lmac and umac dram data - * @fw_cnt: total number of items in array - * @paging: paging dram data - * @paging_cnt: total number of items in array + * struct cont_rec: continuous recording data structure + * @prev_wr_ptr: the last address that was read in monitor_data + * debugfs file + * @prev_wrap_cnt: the wrap count that was used during the last read in + * monitor_data debugfs file + * @state: the state of monitor_data debugfs file as described + * in &iwl_fw_mon_dbgfs_state enum + * @mutex: locked while reading from monitor_data debugfs file */ -struct iwl_self_init_dram { - struct iwl_dram_data *fw; - int fw_cnt; - struct iwl_dram_data *paging; - int paging_cnt; +#ifdef CONFIG_IWLWIFI_DEBUGFS +struct cont_rec { + u32 prev_wr_ptr; + u32 prev_wrap_cnt; + u8 state; + /* Used to sync monitor_data debugfs file with driver unload flow */ + struct mutex mutex; }; +#endif /** * struct iwl_trans_pcie - PCIe transport specific data @@ -451,6 +512,9 @@ struct iwl_self_init_dram { * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight +#ifdef CONFIG_IWLWIFI_DEBUGFS + * @fw_mon_data: fw continuous recording data +#endif * @msix_entries: array of MSI-X entries * @msix_enabled: true if managed to enable MSI-X * @shared_vec_mask: the type of causes the shared vector handles @@ -462,6 +526,8 @@ struct iwl_self_init_dram { * @fh_mask: current unmasked fh causes * @hw_mask: current unmasked hw causes * @in_rescan: true if we have triggered a device rescan + * @base_rb_stts: base virtual address of receive buffer status for all queues + * @base_rb_stts_dma: base physical address of receive buffer status */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -478,7 +544,6 @@ struct iwl_trans_pcie { dma_addr_t prph_info_dma_addr; dma_addr_t prph_scratch_dma_addr; dma_addr_t iml_dma_addr; - struct iwl_self_init_dram init_dram; struct iwl_trans *trans; struct net_device napi_dev; @@ -538,6 +603,10 @@ struct iwl_trans_pcie { bool cmd_hold_nic_awake; bool ref_cmd_in_flight; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct cont_rec fw_mon_data; +#endif + struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; bool msix_enabled; u8 shared_vec_mask; @@ -550,6 +619,9 @@ struct iwl_trans_pcie { cpumask_t affinity_mask[IWL_MAX_RX_HW_QUEUES]; u16 tx_cmd_queue_size; bool in_rescan; + + void *base_rb_stts; + dma_addr_t base_rb_stts_dma; }; static inline struct iwl_trans_pcie * @@ -733,8 +805,7 @@ static inline int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans *trans, static inline void iwl_pcie_ctxt_info_free_fw_img(struct iwl_trans *trans) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_self_init_dram *dram = &trans_pcie->init_dram; + struct iwl_self_init_dram *dram = &trans->init_dram; int i; if (!dram->fw) { @@ -965,8 +1036,14 @@ static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); } +static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans) +{ + return (trans->dbg_dest_tlv || trans->ini_valid); +} + void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state); void iwl_trans_pcie_dump_regs(struct iwl_trans *trans); +void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans); @@ -980,8 +1057,6 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans); int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans); -void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable); - void iwl_pcie_rx_allocator_work(struct work_struct *data); /* common functions that are used by gen2 transport */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index e965cc588850..8d4f0628622b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1,12 +1,14 @@ /****************************************************************************** * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -18,12 +20,46 @@ * more details. * * The full GNU General Public License is included in this distribution in the - * file called LICENSE. + * file called COPYING. * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * + * BSD LICENSE + * + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * *****************************************************************************/ #include <linux/sched.h> #include <linux/wait.h> @@ -166,9 +202,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans) { if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { /* TODO: remove this for 22560 once fw does it */ - iwl_write_prph(trans, RFH_RXF_DMA_CFG_GEN3, 0); - return iwl_poll_prph_bit(trans, RFH_GEN_STATUS_GEN3, - RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); + iwl_write_umac_prph(trans, RFH_RXF_DMA_CFG_GEN3, 0); + return iwl_poll_umac_prph_bit(trans, RFH_GEN_STATUS_GEN3, + RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); } else if (trans->cfg->mq_rx_supported) { iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0); return iwl_poll_prph_bit(trans, RFH_GEN_STATUS, @@ -211,7 +247,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, } rxq->write_actual = round_down(rxq->write, 8); - if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_22560) iwl_write32(trans, HBUS_TARG_WRPTR, (rxq->write_actual | ((FIRST_RX_QUEUE + rxq->id) << 16))); @@ -256,6 +292,9 @@ static void iwl_pcie_restock_bd(struct iwl_trans *trans, bd[rxq->write] = cpu_to_le64(rxb->page_dma | rxb->vid); } + + IWL_DEBUG_RX(trans, "Assigned virtual RB ID %u to queue %d index %d\n", + (u32)rxb->vid, rxq->id, rxq->write); } /* @@ -499,9 +538,9 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; struct list_head local_empty; - int pending = atomic_xchg(&rba->req_pending, 0); + int pending = atomic_read(&rba->req_pending); - IWL_DEBUG_RX(trans, "Pending allocation requests = %d\n", pending); + IWL_DEBUG_TPT(trans, "Pending allocation requests = %d\n", pending); /* If we were scheduled - there is at least one request */ spin_lock(&rba->lock); @@ -554,12 +593,15 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) i++; } + atomic_dec(&rba->req_pending); pending--; + if (!pending) { - pending = atomic_xchg(&rba->req_pending, 0); - IWL_DEBUG_RX(trans, - "Pending allocation requests = %d\n", - pending); + pending = atomic_read(&rba->req_pending); + if (pending) + IWL_DEBUG_TPT(trans, + "Got more pending allocation requests = %d\n", + pending); } spin_lock(&rba->lock); @@ -570,12 +612,15 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) spin_unlock(&rba->lock); atomic_inc(&rba->req_ready); + } spin_lock(&rba->lock); /* return unused rbds to the allocator empty list */ list_splice_tail(&local_empty, &rba->rbd_empty); spin_unlock(&rba->lock); + + IWL_DEBUG_TPT(trans, "%s, exit.\n", __func__); } /* @@ -657,11 +702,6 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, rxq->bd_dma = 0; rxq->bd = NULL; - if (rxq->rb_stts) - dma_free_coherent(trans->dev, - use_rx_td ? sizeof(__le16) : - sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); rxq->rb_stts_dma = 0; rxq->rb_stts = NULL; @@ -698,6 +738,8 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, int free_size; bool use_rx_td = (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560); + size_t rb_stts_size = use_rx_td ? sizeof(__le16) : + sizeof(struct iwl_rb_status); spin_lock_init(&rxq->lock); if (trans->cfg->mq_rx_supported) @@ -711,47 +753,36 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, * Allocate the circular buffer of Read Buffer Descriptors * (RBDs) */ - rxq->bd = dma_zalloc_coherent(dev, - free_size * rxq->queue_size, - &rxq->bd_dma, GFP_KERNEL); + rxq->bd = dma_alloc_coherent(dev, free_size * rxq->queue_size, + &rxq->bd_dma, GFP_KERNEL); if (!rxq->bd) goto err; if (trans->cfg->mq_rx_supported) { - rxq->used_bd = dma_zalloc_coherent(dev, - (use_rx_td ? - sizeof(*rxq->cd) : - sizeof(__le32)) * - rxq->queue_size, - &rxq->used_bd_dma, - GFP_KERNEL); + rxq->used_bd = dma_alloc_coherent(dev, + (use_rx_td ? sizeof(*rxq->cd) : sizeof(__le32)) * rxq->queue_size, + &rxq->used_bd_dma, + GFP_KERNEL); if (!rxq->used_bd) goto err; } - /* Allocate the driver's pointer to receive buffer status */ - rxq->rb_stts = dma_zalloc_coherent(dev, use_rx_td ? - sizeof(__le16) : - sizeof(struct iwl_rb_status), - &rxq->rb_stts_dma, - GFP_KERNEL); - if (!rxq->rb_stts) - goto err; + rxq->rb_stts = trans_pcie->base_rb_stts + rxq->id * rb_stts_size; + rxq->rb_stts_dma = + trans_pcie->base_rb_stts_dma + rxq->id * rb_stts_size; if (!use_rx_td) return 0; /* Allocate the driver's pointer to TR tail */ - rxq->tr_tail = dma_zalloc_coherent(dev, sizeof(__le16), - &rxq->tr_tail_dma, - GFP_KERNEL); + rxq->tr_tail = dma_alloc_coherent(dev, sizeof(__le16), + &rxq->tr_tail_dma, GFP_KERNEL); if (!rxq->tr_tail) goto err; /* Allocate the driver's pointer to CR tail */ - rxq->cr_tail = dma_zalloc_coherent(dev, sizeof(__le16), - &rxq->cr_tail_dma, - GFP_KERNEL); + rxq->cr_tail = dma_alloc_coherent(dev, sizeof(__le16), + &rxq->cr_tail_dma, GFP_KERNEL); if (!rxq->cr_tail) goto err; /* @@ -768,7 +799,6 @@ err: iwl_pcie_free_rxq_dma(trans, rxq); } - kfree(trans_pcie->rxq); return -ENOMEM; } @@ -778,6 +808,9 @@ int iwl_pcie_rx_alloc(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, ret; + size_t rb_stts_size = trans->cfg->device_family >= + IWL_DEVICE_FAMILY_22560 ? + sizeof(__le16) : sizeof(struct iwl_rb_status); if (WARN_ON(trans_pcie->rxq)) return -EINVAL; @@ -785,18 +818,46 @@ int iwl_pcie_rx_alloc(struct iwl_trans *trans) trans_pcie->rxq = kcalloc(trans->num_rx_queues, sizeof(struct iwl_rxq), GFP_KERNEL); if (!trans_pcie->rxq) - return -EINVAL; + return -ENOMEM; spin_lock_init(&rba->lock); + /* + * Allocate the driver's pointer to receive buffer status. + * Allocate for all queues continuously (HW requirement). + */ + trans_pcie->base_rb_stts = + dma_alloc_coherent(trans->dev, + rb_stts_size * trans->num_rx_queues, + &trans_pcie->base_rb_stts_dma, + GFP_KERNEL); + if (!trans_pcie->base_rb_stts) { + ret = -ENOMEM; + goto err; + } + for (i = 0; i < trans->num_rx_queues; i++) { struct iwl_rxq *rxq = &trans_pcie->rxq[i]; + rxq->id = i; ret = iwl_pcie_alloc_rxq_dma(trans, rxq); if (ret) - return ret; + goto err; } return 0; + +err: + if (trans_pcie->base_rb_stts) { + dma_free_coherent(trans->dev, + rb_stts_size * trans->num_rx_queues, + trans_pcie->base_rb_stts, + trans_pcie->base_rb_stts_dma); + trans_pcie->base_rb_stts = NULL; + trans_pcie->base_rb_stts_dma = 0; + } + kfree(trans_pcie->rxq); + + return ret; } static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) @@ -868,30 +929,6 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); } -void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable) -{ - if (trans->cfg->device_family != IWL_DEVICE_FAMILY_9000) - return; - - if (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP) - return; - - if (!trans->cfg->integrated) - return; - - /* - * Turn on the chicken-bits that cause MAC wakeup for RX-related - * values. - * This costs some power, but needed for W/A 9000 integrated A-step - * bug where shadow registers are not in the retention list and their - * value is lost when NIC powers down - */ - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, - CSR_MAC_SHADOW_REG_CTRL_RX_WAKE); - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2, - CSR_MAC_SHADOW_REG_CTL2_RX_WAKE); -} - static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -979,8 +1016,6 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) /* Set interrupt coalescing timer to default (2048 usecs) */ iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); - - iwl_pcie_enable_rx_wake(trans, true); } void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) @@ -1031,8 +1066,6 @@ int _iwl_pcie_rx_init(struct iwl_trans *trans) for (i = 0; i < trans->num_rx_queues; i++) { struct iwl_rxq *rxq = &trans_pcie->rxq[i]; - rxq->id = i; - spin_lock(&rxq->lock); /* * Set read write pointer to reflect that we have processed @@ -1119,6 +1152,9 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; int i; + size_t rb_stts_size = trans->cfg->device_family >= + IWL_DEVICE_FAMILY_22560 ? + sizeof(__le16) : sizeof(struct iwl_rb_status); /* * if rxq is NULL, it means that nothing has been allocated, @@ -1133,6 +1169,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) iwl_pcie_free_rbs_pool(trans); + if (trans_pcie->base_rb_stts) { + dma_free_coherent(trans->dev, + rb_stts_size * trans->num_rx_queues, + trans_pcie->base_rb_stts, + trans_pcie->base_rb_stts_dma); + trans_pcie->base_rb_stts = NULL; + trans_pcie->base_rb_stts_dma = 0; + } + for (i = 0; i < trans->num_rx_queues; i++) { struct iwl_rxq *rxq = &trans_pcie->rxq[i]; @@ -1368,6 +1413,8 @@ static struct iwl_rx_mem_buffer *iwl_pcie_get_rxb(struct iwl_trans *trans, if (rxb->invalid) goto out_err; + IWL_DEBUG_RX(trans, "Got virtual RB ID %u\n", (u32)rxb->vid); + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) rxb->size = le32_to_cpu(rxq->cd[i].size) & IWL_RX_CD_SIZE; @@ -1417,13 +1464,17 @@ restart: !emergency)) { iwl_pcie_rx_move_to_allocator(rxq, rba); emergency = true; + IWL_DEBUG_TPT(trans, + "RX path is in emergency. Pending allocations %d\n", + rb_pending_alloc); } + IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i); + rxb = iwl_pcie_get_rxb(trans, rxq, i); if (!rxb) goto out; - IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i); iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency, i); i = (i + 1) & (rxq->queue_size - 1); @@ -1445,8 +1496,12 @@ restart: count++; if (count == 8) { count = 0; - if (rb_pending_alloc < rxq->queue_size / 3) + if (rb_pending_alloc < rxq->queue_size / 3) { + IWL_DEBUG_TPT(trans, + "RX path exited emergency. Pending allocations %d\n", + rb_pending_alloc); emergency = false; + } rxq->read = i; spin_unlock(&rxq->lock); @@ -1947,9 +2002,8 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->ict_tbl = - dma_zalloc_coherent(trans->dev, ICT_SIZE, - &trans_pcie->ict_tbl_dma, - GFP_KERNEL); + dma_alloc_coherent(trans->dev, ICT_SIZE, + &trans_pcie->ict_tbl_dma, GFP_KERNEL); if (!trans_pcie->ict_tbl) return -ENOMEM; @@ -2113,7 +2167,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) } } - if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560 && + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_22560 && inta_hw & MSIX_HW_INT_CAUSES_REG_IPC) { /* Reflect IML transfer status */ int res = iwl_read32(trans, CSR_IML_RESP_ADDR); @@ -2132,6 +2186,17 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) isr_stats->wakeup++; } + if (inta_hw & MSIX_HW_INT_CAUSES_REG_IML) { + /* Reflect IML transfer status */ + int res = iwl_read32(trans, CSR_IML_RESP_ADDR); + + IWL_DEBUG_ISR(trans, "IML transfer status: %d\n", res); + if (res == IWL_IMAGE_RESP_FAIL) { + isr_stats->sw++; + iwl_pcie_irq_handle_error(trans); + } + } + /* Chip got too hot and stopped itself */ if (inta_hw & MSIX_HW_INT_CAUSES_REG_CT_KILL) { IWL_ERR(trans, "Microcode CT kill error detected.\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 77f3610e5ca9..9c203ca75de9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -92,26 +92,9 @@ int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) iwl_pcie_apm_config(trans); - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (ret < 0) { - IWL_DEBUG_INFO(trans, "Failed to init the card\n"); + ret = iwl_finish_nic_init(trans); + if (ret) return ret; - } set_bit(STATUS_DEVICE_ENABLED, &trans->status); @@ -188,7 +171,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) } iwl_pcie_ctxt_info_free_paging(trans); - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_22560) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) iwl_pcie_ctxt_info_gen3_free(trans); else iwl_pcie_ctxt_info_free(trans); @@ -251,6 +234,7 @@ void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int queue_size = max_t(u32, TFD_CMD_SLOTS, trans->cfg->min_txq_size); /* TODO: most of the logic can be removed in A0 - but not in Z0 */ spin_lock(&trans_pcie->irq_lock); @@ -264,7 +248,7 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) return -ENOMEM; /* Allocate or reset and init all Tx and Command queues */ - if (iwl_pcie_gen2_tx_init(trans, trans_pcie->cmd_queue, TFD_CMD_SLOTS)) + if (iwl_pcie_gen2_tx_init(trans, trans_pcie->cmd_queue, queue_size)) return -ENOMEM; /* enable shadow regs in HW */ @@ -349,7 +333,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, goto out; } - if (trans->cfg->device_family == IWL_DEVICE_FAMILY_22560) + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) ret = iwl_pcie_ctxt_info_gen3_init(trans, fw); else ret = iwl_pcie_ctxt_info_init(trans, fw); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 5bafb3f46eb8..c4375b868901 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -8,7 +8,7 @@ * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,6 +71,7 @@ #include <linux/vmalloc.h> #include <linux/pm_runtime.h> #include <linux/module.h> +#include <linux/wait.h> #include "iwl-drv.h" #include "iwl-trans.h" @@ -363,26 +364,9 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) if (trans->cfg->base_params->pll_cfg) iwl_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() - * and accesses to uCode SRAM. - */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (ret < 0) { - IWL_ERR(trans, "Failed to init the card\n"); + ret = iwl_finish_nic_init(trans); + if (ret) return ret; - } if (trans->cfg->host_interrupt_operation_mode) { /* @@ -452,23 +436,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) iwl_trans_pcie_sw_reset(trans); - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - - /* - * Wait for clock stabilization; once stabilized, access to - * device-internal resources is possible. - */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (WARN_ON(ret < 0)) { - IWL_ERR(trans, "Access time out - failed to enable LP XTAL\n"); + ret = iwl_finish_nic_init(trans); + if (WARN_ON(ret)) { /* Release XTAL ON request */ __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_XTAL_ON); @@ -923,6 +892,20 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv; int i; + if (trans->ini_valid) { + if (!trans->num_blocks) + return; + + iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, + trans->fw_mon[0].physical >> + MON_BUFF_SHIFT_VER2); + iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, + (trans->fw_mon[0].physical + + trans->fw_mon[0].size - 256) >> + MON_BUFF_SHIFT_VER2); + return; + } + IWL_INFO(trans, "Applying debug destination %s\n", get_fw_dbg_mode_string(dest->monitor_mode)); @@ -1025,7 +1008,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, (trans->fw_mon[0].physical + trans->fw_mon[0].size) >> 4); } - } else if (trans->dbg_dest_tlv) { + } else if (iwl_pcie_dbg_on(trans)) { iwl_pcie_apply_destination(trans); } @@ -1046,7 +1029,7 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, IWL_DEBUG_FW(trans, "working with %s CPU\n", image->is_dual_cpus ? "Dual" : "Single"); - if (trans->dbg_dest_tlv) + if (iwl_pcie_dbg_on(trans)) iwl_pcie_apply_destination(trans); IWL_DEBUG_POWER(trans, "Original WFPM value = 0x%08X\n", @@ -1111,6 +1094,7 @@ static struct iwl_causes_list causes_list[] = { {MSIX_FH_INT_CAUSES_FH_ERR, CSR_MSIX_FH_INT_MASK_AD, 0x5}, {MSIX_HW_INT_CAUSES_REG_ALIVE, CSR_MSIX_HW_INT_MASK_AD, 0x10}, {MSIX_HW_INT_CAUSES_REG_WAKEUP, CSR_MSIX_HW_INT_MASK_AD, 0x11}, + {MSIX_HW_INT_CAUSES_REG_IML, CSR_MSIX_HW_INT_MASK_AD, 0x12}, {MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16}, {MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17}, {MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18}, @@ -1143,7 +1127,7 @@ static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int val = trans_pcie->def_irq | MSIX_NON_AUTO_CLEAR_CAUSE; int i, arr_size = - (trans->cfg->device_family < IWL_DEVICE_FAMILY_22560) ? + (trans->cfg->device_family != IWL_DEVICE_FAMILY_22560) ? ARRAY_SIZE(causes_list) : ARRAY_SIZE(causes_list_v2); /* @@ -1153,7 +1137,7 @@ static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans) */ for (i = 0; i < arr_size; i++) { struct iwl_causes_list *causes = - (trans->cfg->device_family < IWL_DEVICE_FAMILY_22560) ? + (trans->cfg->device_family != IWL_DEVICE_FAMILY_22560) ? causes_list : causes_list_v2; iwl_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val); @@ -1199,8 +1183,8 @@ void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) if (!trans_pcie->msix_enabled) { if (trans->cfg->mq_rx_supported && test_bit(STATUS_DEVICE_ENABLED, &trans->status)) - iwl_write_prph(trans, UREG_CHICK, - UREG_CHICK_MSI_ENABLE); + iwl_write_umac_prph(trans, UREG_CHICK, + UREG_CHICK_MSI_ENABLE); return; } /* @@ -1209,7 +1193,7 @@ void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) * prph. */ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) - iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); + iwl_write_umac_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); /* * Each cause from the causes list above and the RX causes is @@ -1515,8 +1499,6 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, iwl_clear_bit(trans, CSR_GP_CNTRL, BIT(trans->cfg->csr->flag_init_done)); - iwl_pcie_enable_rx_wake(trans, false); - if (reset) { /* * reset TX queues -- some of their registers reset during S3 @@ -1543,24 +1525,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } - iwl_pcie_enable_rx_wake(trans, true); - iwl_set_bit(trans, CSR_GP_CNTRL, BIT(trans->cfg->csr->flag_mac_access_req)); - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) - udelay(2); - - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (ret < 0) { - IWL_ERR(trans, "Failed to resume the device (mac ready)\n"); + ret = iwl_finish_nic_init(trans); + if (ret) return ret; - } /* * Reconfigure IVAR table in case of MSIX or reset ict table in @@ -1591,7 +1561,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, } IWL_DEBUG_POWER(trans, "WFPM value upon resume = 0x%08X\n", - iwl_read_prph(trans, WFPM_GP2)); + iwl_read_umac_prph(trans, WFPM_GP2)); val = iwl_read32(trans, CSR_RESET); if (val & CSR_RESET_REG_FLAG_NEVO_RESET) @@ -1729,6 +1699,7 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 hpm; int err; lockdep_assert_held(&trans_pcie->mutex); @@ -1739,6 +1710,20 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) return err; } + hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG); + if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) { + int wfpm_val = iwl_read_umac_prph_no_grab(trans, + PREG_PRPH_WPROT_0); + + if (wfpm_val & PREG_WFPM_ACCESS) { + IWL_ERR(trans, + "Error, can not clear persistence bit\n"); + return -EPERM; + } + iwl_write_umac_prph_no_grab(trans, HPM_DEBUG, + hpm & ~PERSISTENCE_BIT); + } + iwl_trans_pcie_sw_reset(trans); err = iwl_pcie_apm_init(trans); @@ -1941,7 +1926,7 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk) struct iwl_trans_pcie_removal *removal = container_of(wk, struct iwl_trans_pcie_removal, work); struct pci_dev *pdev = removal->pdev; - char *prop[] = {"EVENT=INACCESSIBLE", NULL}; + static char *prop[] = {"EVENT=INACCESSIBLE", NULL}; dev_err(&pdev->dev, "Device gone - attempting removal\n"); kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop); @@ -2258,6 +2243,7 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq; unsigned long now = jiffies; + bool overflow_tx; u8 wr_ptr; /* Make sure the NIC is still alive in the bus */ @@ -2269,18 +2255,37 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx); txq = trans_pcie->txq[txq_idx]; + + spin_lock_bh(&txq->lock); + overflow_tx = txq->overflow_tx || + !skb_queue_empty(&txq->overflow_q); + spin_unlock_bh(&txq->lock); + wr_ptr = READ_ONCE(txq->write_ptr); - while (txq->read_ptr != READ_ONCE(txq->write_ptr) && + while ((txq->read_ptr != READ_ONCE(txq->write_ptr) || + overflow_tx) && !time_after(jiffies, now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { u8 write_ptr = READ_ONCE(txq->write_ptr); - if (WARN_ONCE(wr_ptr != write_ptr, + /* + * If write pointer moved during the wait, warn only + * if the TX came from op mode. In case TX came from + * trans layer (overflow TX) don't warn. + */ + if (WARN_ONCE(wr_ptr != write_ptr && !overflow_tx, "WR pointer moved while flushing %d -> %d\n", wr_ptr, write_ptr)) return -ETIMEDOUT; + wr_ptr = write_ptr; + usleep_range(1000, 2000); + + spin_lock_bh(&txq->lock); + overflow_tx = txq->overflow_tx || + !skb_queue_empty(&txq->overflow_q); + spin_unlock_bh(&txq->lock); } if (txq->read_ptr != txq->write_ptr) { @@ -2697,6 +2702,137 @@ static ssize_t iwl_dbgfs_rfkill_write(struct file *file, return count; } +static int iwl_dbgfs_monitor_data_open(struct inode *inode, + struct file *file) +{ + struct iwl_trans *trans = inode->i_private; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans->dbg_dest_tlv || + trans->dbg_dest_tlv->monitor_mode != EXTERNAL_MODE) { + IWL_ERR(trans, "Debug destination is not set to DRAM\n"); + return -ENOENT; + } + + if (trans_pcie->fw_mon_data.state != IWL_FW_MON_DBGFS_STATE_CLOSED) + return -EBUSY; + + trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_OPEN; + return simple_open(inode, file); +} + +static int iwl_dbgfs_monitor_data_release(struct inode *inode, + struct file *file) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(inode->i_private); + + if (trans_pcie->fw_mon_data.state == IWL_FW_MON_DBGFS_STATE_OPEN) + trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_CLOSED; + return 0; +} + +static bool iwl_write_to_user_buf(char __user *user_buf, ssize_t count, + void *buf, ssize_t *size, + ssize_t *bytes_copied) +{ + int buf_size_left = count - *bytes_copied; + + buf_size_left = buf_size_left - (buf_size_left % sizeof(u32)); + if (*size > buf_size_left) + *size = buf_size_left; + + *size -= copy_to_user(user_buf, buf, *size); + *bytes_copied += *size; + + if (buf_size_left == *size) + return true; + return false; +} + +static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + void *cpu_addr = (void *)trans->fw_mon[0].block, *curr_buf; + struct cont_rec *data = &trans_pcie->fw_mon_data; + u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt; + ssize_t size, bytes_copied = 0; + bool b_full; + + if (trans->dbg_dest_tlv) { + write_ptr_addr = + le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); + wrap_cnt_addr = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); + } else { + write_ptr_addr = MON_BUFF_WRPTR; + wrap_cnt_addr = MON_BUFF_CYCLE_CNT; + } + + if (unlikely(!trans->dbg_rec_on)) + return 0; + + mutex_lock(&data->mutex); + if (data->state == + IWL_FW_MON_DBGFS_STATE_DISABLED) { + mutex_unlock(&data->mutex); + return 0; + } + + /* write_ptr position in bytes rather then DW */ + write_ptr = iwl_read_prph(trans, write_ptr_addr) * sizeof(u32); + wrap_cnt = iwl_read_prph(trans, wrap_cnt_addr); + + if (data->prev_wrap_cnt == wrap_cnt) { + size = write_ptr - data->prev_wr_ptr; + curr_buf = cpu_addr + data->prev_wr_ptr; + b_full = iwl_write_to_user_buf(user_buf, count, + curr_buf, &size, + &bytes_copied); + data->prev_wr_ptr += size; + + } else if (data->prev_wrap_cnt == wrap_cnt - 1 && + write_ptr < data->prev_wr_ptr) { + size = trans->fw_mon[0].size - data->prev_wr_ptr; + curr_buf = cpu_addr + data->prev_wr_ptr; + b_full = iwl_write_to_user_buf(user_buf, count, + curr_buf, &size, + &bytes_copied); + data->prev_wr_ptr += size; + + if (!b_full) { + size = write_ptr; + b_full = iwl_write_to_user_buf(user_buf, count, + cpu_addr, &size, + &bytes_copied); + data->prev_wr_ptr = size; + data->prev_wrap_cnt++; + } + } else { + if (data->prev_wrap_cnt == wrap_cnt - 1 && + write_ptr > data->prev_wr_ptr) + IWL_WARN(trans, + "write pointer passed previous write pointer, start copying from the beginning\n"); + else if (!unlikely(data->prev_wrap_cnt == 0 && + data->prev_wr_ptr == 0)) + IWL_WARN(trans, + "monitor data is out of sync, start copying from the beginning\n"); + + size = write_ptr; + b_full = iwl_write_to_user_buf(user_buf, count, + cpu_addr, &size, + &bytes_copied); + data->prev_wr_ptr = size; + data->prev_wrap_cnt = wrap_cnt; + } + + mutex_unlock(&data->mutex); + + return bytes_copied; +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); @@ -2704,6 +2840,12 @@ DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(rfkill); +static const struct file_operations iwl_dbgfs_monitor_data_ops = { + .read = iwl_dbgfs_monitor_data_read, + .open = iwl_dbgfs_monitor_data_open, + .release = iwl_dbgfs_monitor_data_release, +}; + /* Create the debugfs files and directories */ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { @@ -2715,12 +2857,23 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(csr, dir, 0200); DEBUGFS_ADD_FILE(fh_reg, dir, 0400); DEBUGFS_ADD_FILE(rfkill, dir, 0600); + DEBUGFS_ADD_FILE(monitor_data, dir, 0400); return 0; err: IWL_ERR(trans, "failed to create the trans debugfs entry\n"); return -ENOMEM; } + +static void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct cont_rec *data = &trans_pcie->fw_mon_data; + + mutex_lock(&data->mutex); + data->state = IWL_FW_MON_DBGFS_STATE_DISABLED; + mutex_unlock(&data->mutex); +} #endif /*CONFIG_IWLWIFI_DEBUGFS */ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_trans *trans, void *tfd) @@ -2818,7 +2971,8 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, i += sizeof(u32)) *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); else - for (i = FH_MEM_LOWER_BOUND_GEN2; i < FH_MEM_UPPER_BOUND_GEN2; + for (i = iwl_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2); + i < iwl_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2); i += sizeof(u32)) *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, i)); @@ -2843,17 +2997,45 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans, if (!iwl_trans_grab_nic_access(trans, &flags)) return 0; - iwl_write_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1); + iwl_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1); for (i = 0; i < buf_size_in_dwords; i++) - buffer[i] = iwl_read_prph_no_grab(trans, - MON_DMARB_RD_DATA_ADDR); - iwl_write_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x0); + buffer[i] = iwl_read_umac_prph_no_grab(trans, + MON_DMARB_RD_DATA_ADDR); + iwl_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x0); iwl_trans_release_nic_access(trans, &flags); return monitor_len; } +static void +iwl_trans_pcie_dump_pointers(struct iwl_trans *trans, + struct iwl_fw_error_dump_fw_mon *fw_mon_data) +{ + u32 base, write_ptr, wrap_cnt; + + /* If there was a dest TLV - use the values from there */ + if (trans->ini_valid) { + base = iwl_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2); + write_ptr = iwl_umac_prph(trans, MON_BUFF_WRPTR_VER2); + wrap_cnt = iwl_umac_prph(trans, MON_BUFF_CYCLE_CNT_VER2); + } else if (trans->dbg_dest_tlv) { + write_ptr = le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); + wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); + base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); + } else { + base = MON_BUFF_BASE_ADDR; + write_ptr = MON_BUFF_WRPTR; + wrap_cnt = MON_BUFF_CYCLE_CNT; + } + fw_mon_data->fw_mon_wr_ptr = + cpu_to_le32(iwl_read_prph(trans, write_ptr)); + fw_mon_data->fw_mon_cycle_cnt = + cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); + fw_mon_data->fw_mon_base_ptr = + cpu_to_le32(iwl_read_prph(trans, base)); +} + static u32 iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, struct iwl_fw_error_dump_data **data, @@ -2863,30 +3045,14 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, if ((trans->num_blocks && trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || - trans->dbg_dest_tlv) { + (trans->dbg_dest_tlv && !trans->ini_valid) || + (trans->ini_valid && trans->num_blocks)) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; - u32 base, write_ptr, wrap_cnt; - - /* If there was a dest TLV - use the values from there */ - if (trans->dbg_dest_tlv) { - write_ptr = - le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); - wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); - base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); - } else { - base = MON_BUFF_BASE_ADDR; - write_ptr = MON_BUFF_WRPTR; - wrap_cnt = MON_BUFF_CYCLE_CNT; - } (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); fw_mon_data = (void *)(*data)->data; - fw_mon_data->fw_mon_wr_ptr = - cpu_to_le32(iwl_read_prph(trans, write_ptr)); - fw_mon_data->fw_mon_cycle_cnt = - cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); - fw_mon_data->fw_mon_base_ptr = - cpu_to_le32(iwl_read_prph(trans, base)); + + iwl_trans_pcie_dump_pointers(trans, fw_mon_data); len += sizeof(**data) + sizeof(*fw_mon_data); if (trans->num_blocks) { @@ -2896,6 +3062,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, monitor_len = trans->fw_mon[0].size; } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { + u32 base = le32_to_cpu(fw_mon_data->fw_mon_base_ptr); /* * Update pointers to reflect actual values after * shifting @@ -2930,7 +3097,7 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, return len; } -static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, int *len) +static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len) { if (trans->num_blocks) { *len += sizeof(struct iwl_fw_error_dump_data) + @@ -2978,19 +3145,21 @@ static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, int *len) static struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans, - const struct iwl_fw_dbg_trigger_tlv *trigger) + u32 dump_mask) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_fw_error_dump_data *data; struct iwl_txq *cmdq = trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_fw_error_dump_txcmd *txcmd; struct iwl_trans_dump_data *dump_data; - u32 len, num_rbs = 0; - u32 monitor_len; + u32 len, num_rbs = 0, monitor_len = 0; int i, ptr; bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && !trans->cfg->mq_rx_supported && - trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); + dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); + + if (!dump_mask) + return NULL; /* transport dump header */ len = sizeof(*dump_data); @@ -3000,34 +3169,19 @@ static struct iwl_trans_dump_data cmdq->n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); /* FW monitor */ - monitor_len = iwl_trans_get_fw_monitor_len(trans, &len); - - if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) { - if (!(trans->dbg_dump_mask & - BIT(IWL_FW_ERROR_DUMP_FW_MONITOR))) - return NULL; - - dump_data = vzalloc(len); - if (!dump_data) - return NULL; - - data = (void *)dump_data->data; - len = iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); - dump_data->len = len; - - return dump_data; - } + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_FW_MONITOR)) + monitor_len = iwl_trans_get_fw_monitor_len(trans, &len); /* CSR registers */ - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_CSR)) + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_CSR)) len += sizeof(*data) + IWL_CSR_TO_DUMP; /* FH registers */ - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_FH_REGS)) { + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_FH_REGS)) { if (trans->cfg->gen2) len += sizeof(*data) + - (FH_MEM_UPPER_BOUND_GEN2 - - FH_MEM_LOWER_BOUND_GEN2); + (iwl_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2) - + iwl_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2)); else len += sizeof(*data) + (FH_MEM_UPPER_BOUND - @@ -3048,12 +3202,11 @@ static struct iwl_trans_dump_data } /* Paged memory for gen2 HW */ - if (trans->cfg->gen2 && - trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING)) - for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) + if (trans->cfg->gen2 && dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING)) + for (i = 0; i < trans->init_dram.paging_cnt; i++) len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_paging) + - trans_pcie->init_dram.paging[i].size; + trans->init_dram.paging[i].size; dump_data = vzalloc(len); if (!dump_data) @@ -3062,7 +3215,7 @@ static struct iwl_trans_dump_data len = 0; data = (void *)dump_data->data; - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD)) { + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_TXCMD)) { u16 tfd_size = trans_pcie->tfd_size; data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD); @@ -3096,36 +3249,31 @@ static struct iwl_trans_dump_data data = iwl_fw_error_next_data(data); } - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_CSR)) + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_CSR)) len += iwl_trans_pcie_dump_csr(trans, &data); - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_FH_REGS)) + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_FH_REGS)) len += iwl_trans_pcie_fh_regs_dump(trans, &data); if (dump_rbs) len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); /* Paged memory for gen2 HW */ - if (trans->cfg->gen2 && - trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING)) { - for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) { + if (trans->cfg->gen2 && dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING)) { + for (i = 0; i < trans->init_dram.paging_cnt; i++) { struct iwl_fw_error_dump_paging *paging; - dma_addr_t addr = - trans_pcie->init_dram.paging[i].physical; - u32 page_len = trans_pcie->init_dram.paging[i].size; + u32 page_len = trans->init_dram.paging[i].size; data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); data->len = cpu_to_le32(sizeof(*paging) + page_len); paging = (void *)data->data; paging->index = cpu_to_le32(i); - dma_sync_single_for_cpu(trans->dev, addr, page_len, - DMA_BIDIRECTIONAL); memcpy(paging->data, - trans_pcie->init_dram.paging[i].block, page_len); + trans->init_dram.paging[i].block, page_len); data = iwl_fw_error_next_data(data); len += sizeof(*data) + sizeof(*paging) + page_len; } } - if (trans->dbg_dump_mask & BIT(IWL_FW_ERROR_DUMP_FW_MONITOR)) + if (dump_mask & BIT(IWL_FW_ERROR_DUMP_FW_MONITOR)) len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); dump_data->len = len; @@ -3170,7 +3318,8 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) .unref = iwl_trans_pcie_unref, \ .dump_data = iwl_trans_pcie_dump_data, \ .d3_suspend = iwl_trans_pcie_d3_suspend, \ - .d3_resume = iwl_trans_pcie_d3_resume + .d3_resume = iwl_trans_pcie_d3_resume, \ + .sync_nmi = iwl_trans_pcie_sync_nmi #ifdef CONFIG_PM_SLEEP #define IWL_TRANS_PM_OPS \ @@ -3202,6 +3351,9 @@ static const struct iwl_trans_ops trans_ops_pcie = { .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, +#ifdef CONFIG_IWLWIFI_DEBUGFS + .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, +#endif }; static const struct iwl_trans_ops trans_ops_pcie_gen2 = { @@ -3221,6 +3373,9 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_free = iwl_trans_pcie_dyn_txq_free, .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, +#ifdef CONFIG_IWLWIFI_DEBUGFS + .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, +#endif }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, @@ -3350,25 +3505,18 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, * in-order to recognize C step driver should read chip version * id located at the AUX bus MISC address space. */ - iwl_set_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_init_done)); - udelay(2); - - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - BIT(trans->cfg->csr->flag_mac_clock_ready), - BIT(trans->cfg->csr->flag_mac_clock_ready), - 25000); - if (ret < 0) { - IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n"); + ret = iwl_finish_nic_init(trans); + if (ret) goto out_no_pci; - } if (iwl_trans_grab_nic_access(trans, &flags)) { u32 hw_step; - hw_step = iwl_read_prph_no_grab(trans, WFPM_CTRL_REG); + hw_step = iwl_read_umac_prph_no_grab(trans, + WFPM_CTRL_REG); hw_step |= ENABLE_WFPM; - iwl_write_prph_no_grab(trans, WFPM_CTRL_REG, hw_step); + iwl_write_umac_prph_no_grab(trans, WFPM_CTRL_REG, + hw_step); hw_step = iwl_read_prph_no_grab(trans, AUX_MISC_REG); hw_step = (hw_step >> HW_STEP_LOCATION_BITS) & 0xF; if (hw_step == 0x3) @@ -3378,22 +3526,47 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } - /* - * 9000-series integrated A-step has a problem with suspend/resume - * and sometimes even causes the whole platform to get stuck. This - * workaround makes the hardware not go into the problematic state. - */ - if (trans->cfg->integrated && - trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 && - CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP) - iwl_set_bit(trans, CSR_HOST_CHICKEN, - CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME); + IWL_DEBUG_INFO(trans, "HW REV: 0x%0x\n", trans->hw_rev); #if IS_ENABLED(CONFIG_IWLMVM) trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID); - if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR)) { + if (cfg == &iwlax210_2ax_cfg_so_hr_a0) { + if (trans->hw_rev == CSR_HW_REV_TYPE_TY) { + trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0; + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF)) { + trans->cfg = &iwlax210_2ax_cfg_so_jf_a0; + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF)) { + trans->cfg = &iwlax210_2ax_cfg_so_gf_a0; + } + } else if (cfg == &iwl_ax101_cfg_qu_hr) { + if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && + trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) { + trans->cfg = &iwl22000_2ax_cfg_qnj_hr_b0; + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR)) { + trans->cfg = &iwl_ax101_cfg_qu_hr; + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF)) { + trans->cfg = &iwl22000_2ax_cfg_jf; + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HRCDB)) { + IWL_ERR(trans, "RF ID HRCDB is not supported\n"); + ret = -EINVAL; + goto out_no_pci; + } else { + IWL_ERR(trans, "Unrecognized RF ID 0x%08x\n", + CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id)); + ret = -EINVAL; + goto out_no_pci; + } + } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(trans->hw_rf_id) == + CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && + (trans->cfg != &iwl_ax200_cfg_cc || + trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0)) { u32 hw_status; hw_status = iwl_read_prph(trans, UMAG_GEN_HW_STATUS); @@ -3454,6 +3627,11 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, trans->runtime_pm_mode = IWL_PLAT_PM_MODE_DISABLED; #endif /* CONFIG_IWLWIFI_PCIE_RTPM */ +#ifdef CONFIG_IWLWIFI_DEBUGFS + trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_CLOSED; + mutex_init(&trans_pcie->fw_mon_data.mutex); +#endif + return trans; out_free_ict: @@ -3463,3 +3641,35 @@ out_no_pci: iwl_trans_free(trans); return ERR_PTR(ret); } + +void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; + u32 inta_addr, sw_err_bit; + + if (trans_pcie->msix_enabled) { + inta_addr = CSR_MSIX_HW_INT_CAUSES_AD; + sw_err_bit = MSIX_HW_INT_CAUSES_REG_SW_ERR; + } else { + inta_addr = CSR_INT; + sw_err_bit = CSR_INT_BIT_SW_ERR; + } + + iwl_disable_interrupts(trans); + iwl_force_nmi(trans); + while (time_after(timeout, jiffies)) { + u32 inta_hw = iwl_read32(trans, inta_addr); + + /* Error detected by uCode */ + if (inta_hw & sw_err_bit) { + /* Clear causes register */ + iwl_write32(trans, inta_addr, inta_hw & sw_err_bit); + break; + } + + mdelay(1); + } + iwl_enable_interrupts(trans); + iwl_trans_fw_error(trans); +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index e880f69eac26..38d110338987 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -20,7 +20,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -214,7 +214,11 @@ static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int idx = iwl_pcie_gen2_get_num_tbs(trans, tfd); - struct iwl_tfh_tb *tb = &tfd->tbs[idx]; + struct iwl_tfh_tb *tb; + + if (WARN_ON(idx >= IWL_TFH_NUM_TBS)) + return -EINVAL; + tb = &tfd->tbs[idx]; /* Each TFD can point to a maximum max_tbs Tx buffers */ if (le16_to_cpu(tfd->num_tbs) >= trans_pcie->max_tbs) { @@ -238,7 +242,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, { #ifdef CONFIG_INET struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload; + struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; @@ -408,7 +412,7 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx_amsdu(struct iwl_trans *trans, goto out_err; /* building the A-MSDU might have changed this data, memcpy it now */ - memcpy(&txq->first_tb_bufs[idx], &dev_cmd->hdr, IWL_FIRST_TB_SIZE); + memcpy(&txq->first_tb_bufs[idx], dev_cmd, IWL_FIRST_TB_SIZE); return tfd; out_err: @@ -469,7 +473,7 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, tb_phys = iwl_pcie_get_first_tb_dma(txq, idx); /* The first TB points to bi-directional DMA data */ - memcpy(&txq->first_tb_bufs[idx], &dev_cmd->hdr, IWL_FIRST_TB_SIZE); + memcpy(&txq->first_tb_bufs[idx], dev_cmd, IWL_FIRST_TB_SIZE); iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE); @@ -583,18 +587,6 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_lock(&txq->lock); - if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { - struct iwl_tx_cmd_gen3 *tx_cmd_gen3 = - (void *)dev_cmd->payload; - - cmd_len = le16_to_cpu(tx_cmd_gen3->len); - } else { - struct iwl_tx_cmd_gen2 *tx_cmd_gen2 = - (void *)dev_cmd->payload; - - cmd_len = le16_to_cpu(tx_cmd_gen2->len); - } - if (iwl_queue_space(trans, txq) < txq->high_mark) { iwl_stop_queue(trans, txq); @@ -632,6 +624,18 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, return -1; } + if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + struct iwl_tx_cmd_gen3 *tx_cmd_gen3 = + (void *)dev_cmd->payload; + + cmd_len = le16_to_cpu(tx_cmd_gen3->len); + } else { + struct iwl_tx_cmd_gen2 *tx_cmd_gen2 = + (void *)dev_cmd->payload; + + cmd_len = le16_to_cpu(tx_cmd_gen2->len); + } + /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_gen2_update_byte_tbl(trans_pcie, txq, cmd_len, iwl_pcie_gen2_get_num_tbs(trans, tfd)); @@ -834,14 +838,14 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, /* start the TFD with the minimum copy bytes */ tb0_size = min_t(int, copy_size, IWL_FIRST_TB_SIZE); - memcpy(&txq->first_tb_bufs[idx], &out_cmd->hdr, tb0_size); + memcpy(&txq->first_tb_bufs[idx], out_cmd, tb0_size); iwl_pcie_gen2_set_tb(trans, tfd, iwl_pcie_get_first_tb_dma(txq, idx), tb0_size); /* map first command fragment, if any remains */ if (copy_size > tb0_size) { phys_addr = dma_map_single(trans->dev, - ((u8 *)&out_cmd->hdr) + tb0_size, + (u8 *)out_cmd + tb0_size, copy_size - tb0_size, DMA_TO_DEVICE); if (dma_mapping_error(trans->dev, phys_addr)) { @@ -961,9 +965,7 @@ static int iwl_pcie_gen2_send_hcmd_sync(struct iwl_trans *trans, cmd_str); ret = -ETIMEDOUT; - iwl_force_nmi(trans); - iwl_trans_fw_error(trans); - + iwl_trans_pcie_sync_nmi(trans); goto cancel; } @@ -1228,8 +1230,7 @@ int iwl_trans_pcie_txq_alloc_response(struct iwl_trans *trans, /* Place first TFD at index corresponding to start sequence number */ txq->read_ptr = wr_ptr; txq->write_ptr = wr_ptr; - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (txq->write_ptr) | (qid << 16)); + IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid); iwl_free_resp(hcmd); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 87b7225fe289..7be73e2c4681 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1,12 +1,14 @@ /****************************************************************************** * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -18,12 +20,46 @@ * more details. * * The full GNU General Public License is included in this distribution in the - * file called LICENSE. + * file called COPYING. * * Contact Information: * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * + * BSD LICENSE + * + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * *****************************************************************************/ #include <linux/etherdevice.h> #include <linux/ieee80211.h> @@ -959,7 +995,11 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) txq_id++) { bool cmd_queue = (txq_id == trans_pcie->cmd_queue); - slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + if (cmd_queue) + slots_num = max_t(u32, TFD_CMD_SLOTS, + trans->cfg->min_txq_size); + else + slots_num = TFD_TX_CMD_SLOTS; trans_pcie->txq[txq_id] = &trans_pcie->txq_memory[txq_id]; ret = iwl_pcie_txq_alloc(trans, trans_pcie->txq[txq_id], slots_num, cmd_queue); @@ -1008,7 +1048,11 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) txq_id++) { bool cmd_queue = (txq_id == trans_pcie->cmd_queue); - slots_num = cmd_queue ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + if (cmd_queue) + slots_num = max_t(u32, TFD_CMD_SLOTS, + trans->cfg->min_txq_size); + else + slots_num = TFD_TX_CMD_SLOTS; ret = iwl_pcie_txq_init(trans, trans_pcie->txq[txq_id], slots_num, cmd_queue); if (ret) { @@ -1138,6 +1182,15 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, skb_queue_splice_init(&txq->overflow_q, &overflow_skbs); /* + * We are going to transmit from the overflow queue. + * Remember this state so that wait_for_txq_empty will know we + * are adding more packets to the TFD queue. It cannot rely on + * the state of &txq->overflow_q, as we just emptied it, but + * haven't TXed the content yet. + */ + txq->overflow_tx = true; + + /* * This is tricky: we are in reclaim path which is non * re-entrant, so noone will try to take the access the * txq data from that path. We stopped tx, so we can't @@ -1160,10 +1213,12 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, */ iwl_trans_tx(trans, skb, dev_cmd_ptr, txq_id); } - spin_lock_bh(&txq->lock); if (iwl_queue_space(trans, txq) > txq->low_mark) iwl_wake_queue(trans, txq); + + spin_lock_bh(&txq->lock); + txq->overflow_tx = false; } if (txq->read_ptr == txq->write_ptr) { @@ -1245,11 +1300,11 @@ void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) if (idx >= trans->cfg->base_params->max_tfd_queue_size || (!iwl_queue_used(txq, idx))) { - IWL_ERR(trans, - "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", - __func__, txq_id, idx, - trans->cfg->base_params->max_tfd_queue_size, - txq->write_ptr, txq->read_ptr); + WARN_ONCE(test_bit(txq_id, trans_pcie->queue_used), + "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n", + __func__, txq_id, idx, + trans->cfg->base_params->max_tfd_queue_size, + txq->write_ptr, txq->read_ptr); return; } @@ -1905,9 +1960,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, iwl_get_cmd_string(trans, cmd->id)); ret = -ETIMEDOUT; - iwl_force_nmi(trans); - iwl_trans_fw_error(trans); - + iwl_trans_pcie_sync_nmi(trans); goto cancel; } @@ -2437,8 +2490,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, } /* building the A-MSDU might have changed this data, so memcpy it now */ - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, - IWL_FIRST_TB_SIZE); + memcpy(&txq->first_tb_bufs[txq->write_ptr], dev_cmd, IWL_FIRST_TB_SIZE); tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr); /* Set up entry for this TFD in Tx byte-count array */ |