diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-25 20:02:57 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-11-25 20:02:57 -0800 |
commit | 386403a115f95997c2715691226e11a7b5cffcfd (patch) | |
tree | a685df70bd3d5b295683713818ddf0752c3d75b6 /drivers/net/wireless/intel/iwlwifi/mvm | |
parent | 642356cb5f4a8c82b5ca5ebac288c327d10df236 (diff) | |
parent | 622dc5ad8052f4f0c6b7a12787696a5caa3c6a58 (diff) | |
download | talos-op-linux-386403a115f95997c2715691226e11a7b5cffcfd.tar.gz talos-op-linux-386403a115f95997c2715691226e11a7b5cffcfd.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from David Miller:
"Another merge window, another pull full of stuff:
1) Support alternative names for network devices, from Jiri Pirko.
2) Introduce per-netns netdev notifiers, also from Jiri Pirko.
3) Support MSG_PEEK in vsock/virtio, from Matias Ezequiel Vara
Larsen.
4) Allow compiling out the TLS TOE code, from Jakub Kicinski.
5) Add several new tracepoints to the kTLS code, also from Jakub.
6) Support set channels ethtool callback in ena driver, from Sameeh
Jubran.
7) New SCTP events SCTP_ADDR_ADDED, SCTP_ADDR_REMOVED,
SCTP_ADDR_MADE_PRIM, and SCTP_SEND_FAILED_EVENT. From Xin Long.
8) Add XDP support to mvneta driver, from Lorenzo Bianconi.
9) Lots of netfilter hw offload fixes, cleanups and enhancements,
from Pablo Neira Ayuso.
10) PTP support for aquantia chips, from Egor Pomozov.
11) Add UDP segmentation offload support to igb, ixgbe, and i40e. From
Josh Hunt.
12) Add smart nagle to tipc, from Jon Maloy.
13) Support L2 field rewrite by TC offloads in bnxt_en, from Venkat
Duvvuru.
14) Add a flow mask cache to OVS, from Tonghao Zhang.
15) Add XDP support to ice driver, from Maciej Fijalkowski.
16) Add AF_XDP support to ice driver, from Krzysztof Kazimierczak.
17) Support UDP GSO offload in atlantic driver, from Igor Russkikh.
18) Support it in stmmac driver too, from Jose Abreu.
19) Support TIPC encryption and auth, from Tuong Lien.
20) Introduce BPF trampolines, from Alexei Starovoitov.
21) Make page_pool API more numa friendly, from Saeed Mahameed.
22) Introduce route hints to ipv4 and ipv6, from Paolo Abeni.
23) Add UDP segmentation offload to cxgb4, Rahul Lakkireddy"
* git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1857 commits)
libbpf: Fix usage of u32 in userspace code
mm: Implement no-MMU variant of vmalloc_user_node_flags
slip: Fix use-after-free Read in slip_open
net: dsa: sja1105: fix sja1105_parse_rgmii_delays()
macvlan: schedule bc_work even if error
enetc: add support Credit Based Shaper(CBS) for hardware offload
net: phy: add helpers phy_(un)lock_mdio_bus
mdio_bus: don't use managed reset-controller
ax88179_178a: add ethtool_op_get_ts_info()
mlxsw: spectrum_router: Fix use of uninitialized adjacency index
mlxsw: spectrum_router: After underlay moves, demote conflicting tunnels
bpf: Simplify __bpf_arch_text_poke poke type handling
bpf: Introduce BPF_TRACE_x helper for the tracing tests
bpf: Add bpf_jit_blinding_enabled for !CONFIG_BPF_JIT
bpf, testing: Add various tail call test cases
bpf, x86: Emit patchable direct jump as tail call
bpf: Constant map key tracking for prog array pokes
bpf: Add poke dependency tracking for prog array maps
bpf: Add initial poke descriptor table for jit images
bpf: Move owner type, jited info into array auxiliary data
...
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
21 files changed, 1089 insertions, 500 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 86c2c587e755..43ebb2149b63 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1939,6 +1939,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) if (iwl_mvm_check_rt_status(mvm, vif)) { set_bit(STATUS_FW_ERROR, &mvm->trans->status); iwl_mvm_dump_nic_error_log(mvm); + iwl_dbg_tlv_time_point(&mvm->fwrt, + IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, false, 0); ret = 1; @@ -1955,12 +1957,39 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) } if (d0i3_first) { - ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + struct iwl_host_cmd cmd = { + .id = D0I3_END_CMD, + .flags = CMD_WANT_SKB, + }; + int len; + + ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret < 0) { IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n", ret); goto err; } + switch (mvm->cmd_ver.d0i3_resp) { + case 0: + break; + case 1: + len = iwl_rx_packet_payload_len(cmd.resp_pkt); + if (len != sizeof(u32)) { + IWL_ERR(mvm, + "Error with D0I3_END_CMD response size (%d)\n", + len); + goto err; + } + if (IWL_D0I3_RESET_REQUIRE & + le32_to_cpu(*(__le32 *)cmd.resp_pkt->data)) { + iwl_write32(mvm->trans, CSR_RESET, + CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_free_resp(&cmd); + } + break; + default: + WARN_ON(1); + } } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index ad18c2f1a806..aa659162a7c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -148,7 +148,8 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, "FLUSHING all tids queues on sta_id = %d\n", flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count; + ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFFFF, 0) + ? : count; mutex_unlock(&mvm->mutex); return ret; } @@ -377,7 +378,7 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, pos = scnprintf(buf, bufsz, "SAR geographic profile disabled\n"); } else { - value = &mvm->geo_profiles[tbl_idx - 1].values[0]; + value = &mvm->fwrt.geo_profiles[tbl_idx - 1].values[0]; pos += scnprintf(buf + pos, bufsz - pos, "Use geographic profile %d\n", tbl_idx); @@ -1174,7 +1175,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, int bin_len = count / 2; int ret = -EINVAL; size_t mpdu_cmd_hdr_size = (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_rx_mpdu_desc) : IWL_RX_DESC_SIZE_V1; @@ -1375,6 +1376,9 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (count == 0) return 0; + iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, + NULL); + iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, (count - 1), NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d9eb2b286438..dd685f7eb410 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -514,6 +514,19 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) struct iwl_phy_cfg_cmd phy_cfg_cmd; enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; + if (iwl_mvm_has_unified_ucode(mvm) && + !mvm->trans->cfg->tx_with_siso_diversity) + return 0; + + if (mvm->trans->cfg->tx_with_siso_diversity) { + /* + * TODO: currently we don't set the antenna but letting the NIC + * to decide which antenna to use. This should come from BIOS. + */ + phy_cfg_cmd.phy_cfg = + cpu_to_le32(FW_PHY_CFG_CHAIN_SAD_ENABLED); + } + /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); @@ -665,181 +678,14 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) } #ifdef CONFIG_ACPI -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; - - profile->enabled = enabled; - - for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { - if ((table[i].type != ACPI_TYPE_INTEGER) || - (table[i].integer.value > U8_MAX)) - return -EINVAL; - - profile->table[i] = table[i].integer.value; - } - - return 0; -} - -static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *table, *data; - bool enabled; - int ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - enabled = !!(wifi_pkg->package.elements[1].integer.value); - - /* position of the actual table */ - table = &wifi_pkg->package.elements[2]; - - /* The profile from WRDS is officially profile 1, but goes - * into sar_profiles[0] (because we don't have a profile 0). - */ - ret = iwl_mvm_sar_set_profile(mvm, table, &mvm->sar_profiles[0], - enabled); -out_free: - kfree(data); - return ret; -} - -static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *data; - bool enabled; - int i, n_profiles, ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if ((wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) || - (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) || - tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - enabled = !!(wifi_pkg->package.elements[1].integer.value); - n_profiles = wifi_pkg->package.elements[2].integer.value; - - /* - * Check the validity of n_profiles. The EWRD profiles start - * from index 1, so the maximum value allowed here is - * ACPI_SAR_PROFILES_NUM - 1. - */ - if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { - ret = -EINVAL; - goto out_free; - } - - for (i = 0; i < n_profiles; i++) { - /* the tables start at element 3 */ - int pos = 3; - - /* The EWRD profiles officially go from 2 to 4, but we - * save them in sar_profiles[1-3] (because we don't - * have profile 0). So in the array we start from 1. - */ - ret = iwl_mvm_sar_set_profile(mvm, - &wifi_pkg->package.elements[pos], - &mvm->sar_profiles[i + 1], - enabled); - if (ret < 0) - break; - - /* go to the next table */ - pos += ACPI_SAR_TABLE_SIZE; - } - -out_free: - kfree(data); - return ret; -} - -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *data; - int i, j, ret, tbl_rev; - int idx = 1; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - mvm->geo_rev = tbl_rev; - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { - union acpi_object *entry; - - entry = &wifi_pkg->package.elements[idx++]; - if ((entry->type != ACPI_TYPE_INTEGER) || - (entry->integer.value > U8_MAX)) { - ret = -EINVAL; - goto out_free; - } - - mvm->geo_profiles[i].values[j] = entry->integer.value; - } - } - ret = 0; -out_free: - kfree(data); - return ret; -} - int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { union { struct iwl_dev_tx_power_cmd v5; struct iwl_dev_tx_power_cmd_v4 v4; } cmd; - int i, j, idx; - int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; - int len; - BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2); - BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS != - ACPI_SAR_TABLE_SIZE); + u16 len = 0; cmd.v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS); @@ -848,174 +694,76 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) len = sizeof(cmd.v5); else if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) - len = sizeof(cmd.v4); + len = sizeof(struct iwl_dev_tx_power_cmd_v4); else len = sizeof(cmd.v4.v3); - for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { - struct iwl_mvm_sar_profile *prof; - - /* don't allow SAR to be disabled (profile 0 means disable) */ - if (profs[i] == 0) - return -EPERM; - - /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ - if (profs[i] > ACPI_SAR_PROFILE_NUM) - return -EINVAL; - - /* profiles go from 1 to 4, so decrement to access the array */ - prof = &mvm->sar_profiles[profs[i] - 1]; - - /* if the profile is disabled, do nothing */ - if (!prof->enabled) { - IWL_DEBUG_RADIO(mvm, "SAR profile %d is disabled.\n", - profs[i]); - /* if one of the profiles is disabled, we fail all */ - return -ENOENT; - } - - IWL_DEBUG_INFO(mvm, - "SAR EWRD: chain %d profile index %d\n", - i, profs[i]); - IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); - for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { - idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j; - cmd.v5.v3.per_chain_restriction[i][j] = - cpu_to_le16(prof->table[idx]); - IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", - j, prof->table[idx]); - } - } + if (iwl_sar_select_profile(&mvm->fwrt, cmd.v5.v3.per_chain_restriction, + prof_a, prof_b)) + return -ENOENT; IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); - return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } -static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm) -{ - /* - * The GEO_TX_POWER_LIMIT command is not supported on earlier - * firmware versions. Unfortunately, we don't have a TLV API - * flag to rely on, so rely on the major version which is in - * the first byte of ucode_ver. This was implemented - * initially on version 38 and then backported to 17. It was - * also backported to 29, but only for 7265D devices. The - * intention was to have it in 36 as well, but not all 8000 - * family got this feature enabled. The 8000 family is the - * only one using version 36, so skip this version entirely. - */ - return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 || - IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17 || - (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 && - ((mvm->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == - CSR_HW_REV_TYPE_7265D)); -} - int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) { - struct iwl_geo_tx_power_profiles_resp *resp; - int ret; + union geo_tx_power_profiles_cmd geo_tx_cmd; u16 len; - void *data; - struct iwl_geo_tx_power_profiles_cmd geo_cmd; - struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1; + int ret; struct iwl_host_cmd cmd; - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { - geo_cmd.ops = + if (fw_has_api(&mvm->fwrt.fw->ucode_capa, + IWL_UCODE_TLV_API_SAR_TABLE_VER)) { + geo_tx_cmd.geo_cmd.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); - len = sizeof(geo_cmd); - data = &geo_cmd; + len = sizeof(geo_tx_cmd.geo_cmd); } else { - geo_cmd_v1.ops = + geo_tx_cmd.geo_cmd_v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); - len = sizeof(geo_cmd_v1); - data = &geo_cmd_v1; + len = sizeof(geo_tx_cmd.geo_cmd_v1); } + if (!iwl_sar_geo_support(&mvm->fwrt)) + return -EOPNOTSUPP; + cmd = (struct iwl_host_cmd){ .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), .len = { len, }, .flags = CMD_WANT_SKB, - .data = { data }, + .data = { &geo_tx_cmd }, }; - if (!iwl_mvm_sar_geo_support(mvm)) - return -EOPNOTSUPP; - ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret) { IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); return ret; } - - resp = (void *)cmd.resp_pkt->data; - ret = le32_to_cpu(resp->profile_idx); - if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES)) { - ret = -EIO; - IWL_WARN(mvm, "Invalid geographic profile idx (%d)\n", ret); - } - + ret = iwl_validate_sar_geo_profile(&mvm->fwrt, &cmd); iwl_free_resp(&cmd); return ret; } static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) { - struct iwl_geo_tx_power_profiles_cmd cmd = { - .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), - }; - int ret, i, j; u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); + union geo_tx_power_profiles_cmd cmd; + u16 len; - if (!iwl_mvm_sar_geo_support(mvm)) - return 0; - - ret = iwl_mvm_sar_get_wgds_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "Geo SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return 0; - } - - IWL_DEBUG_RADIO(mvm, "Sending GEO_TX_POWER_LIMIT\n"); - - BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS * - ACPI_WGDS_TABLE_SIZE + 1 != ACPI_WGDS_WIFI_DATA_SIZE); - - BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES > IWL_NUM_GEO_PROFILES); - - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - struct iwl_per_chain_offset *chain = - (struct iwl_per_chain_offset *)&cmd.table[i]; - - for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { - u8 *value; + cmd.geo_cmd.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); - value = &mvm->geo_profiles[i].values[j * - ACPI_GEO_PER_CHAIN_SIZE]; - chain[j].max_tx_power = cpu_to_le16(value[0]); - chain[j].chain_a = value[1]; - chain[j].chain_b = value[2]; - IWL_DEBUG_RADIO(mvm, - "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, value[1], value[2], value[0]); - } - } + iwl_sar_geo_init(&mvm->fwrt, cmd.geo_cmd.table); - cmd.table_revision = cpu_to_le32(mvm->geo_rev); + cmd.geo_cmd.table_revision = cpu_to_le32(mvm->fwrt.geo_rev); - if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_SAR_TABLE_VER)) { - return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, - sizeof(struct iwl_geo_tx_power_profiles_cmd_v1), - &cmd); + if (!fw_has_api(&mvm->fwrt.fw->ucode_capa, + IWL_UCODE_TLV_API_SAR_TABLE_VER)) { + len = sizeof(struct iwl_geo_tx_power_profiles_cmd_v1); + } else { + len = sizeof(cmd.geo_cmd); } - return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, len, &cmd); } static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) @@ -1024,7 +772,7 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) int i, j, ret, tbl_rev; int idx = 2; - mvm->ppag_table.enabled = cpu_to_le32(0); + mvm->fwrt.ppag_table.enabled = cpu_to_le32(0); data = iwl_acpi_get_object(mvm->dev, ACPI_PPAG_METHOD); if (IS_ERR(data)) return PTR_ERR(data); @@ -1049,8 +797,8 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) goto out_free; } - mvm->ppag_table.enabled = cpu_to_le32(enabled->integer.value); - if (!mvm->ppag_table.enabled) { + mvm->fwrt.ppag_table.enabled = cpu_to_le32(enabled->integer.value); + if (!mvm->fwrt.ppag_table.enabled) { ret = 0; goto out_free; } @@ -1070,11 +818,11 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) (j == 0 && ent->integer.value < ACPI_PPAG_MIN_LB) || (j != 0 && ent->integer.value > ACPI_PPAG_MAX_HB) || (j != 0 && ent->integer.value < ACPI_PPAG_MIN_HB)) { - mvm->ppag_table.enabled = cpu_to_le32(0); + mvm->fwrt.ppag_table.enabled = cpu_to_le32(0); ret = -EINVAL; goto out_free; } - mvm->ppag_table.gain[i][j] = ent->integer.value; + mvm->fwrt.ppag_table.gain[i][j] = ent->integer.value; } } ret = 0; @@ -1095,20 +843,20 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); IWL_DEBUG_RADIO(mvm, "PPAG is %s\n", - mvm->ppag_table.enabled ? "enabled" : "disabled"); + mvm->fwrt.ppag_table.enabled ? "enabled" : "disabled"); for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) { for (j = 0; j < ACPI_PPAG_NUM_SUB_BANDS; j++) { IWL_DEBUG_RADIO(mvm, "PPAG table: chain[%d] band[%d]: gain = %d\n", - i, j, mvm->ppag_table.gain[i][j]); + i, j, mvm->fwrt.ppag_table.gain[i][j]); } } ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), - 0, sizeof(mvm->ppag_table), - &mvm->ppag_table); + 0, sizeof(mvm->fwrt.ppag_table), + &mvm->fwrt.ppag_table); if (ret < 0) IWL_ERR(mvm, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", ret); @@ -1131,17 +879,14 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) } #else /* CONFIG_ACPI */ -static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) -{ - return -ENOENT; -} -static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) +inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, + int prof_a, int prof_b) { return -ENOENT; } -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) +inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) { return -ENOENT; } @@ -1151,17 +896,6 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) return 0; } -int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, - int prof_b) -{ - return -ENOENT; -} - -int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) { return -ENOENT; @@ -1169,7 +903,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { - return -ENOENT; + return 0; } #endif /* CONFIG_ACPI */ @@ -1228,7 +962,7 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { int ret; - ret = iwl_mvm_sar_get_wrds_table(mvm); + ret = iwl_sar_get_wrds_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "WRDS SAR BIOS table invalid or unavailable. (%d)\n", @@ -1240,16 +974,14 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) return 1; } - ret = iwl_mvm_sar_get_ewrd_table(mvm); + ret = iwl_sar_get_ewrd_table(&mvm->fwrt); /* if EWRD is not available, we can still use WRDS, so don't fail */ if (ret < 0) IWL_DEBUG_RADIO(mvm, "EWRD SAR BIOS table invalid or unavailable. (%d)\n", ret); - /* choose profile 1 (WRDS) as default for both chains */ ret = iwl_mvm_sar_select_profile(mvm, 1, 1); - /* * If we don't have profile 0 from BIOS, just skip it. This * means that SAR Geo will not be enabled either, even if we @@ -1344,12 +1076,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ret = iwl_send_phy_db_data(mvm->phy_db); if (ret) goto error; - - ret = iwl_send_phy_cfg_cmd(mvm); - if (ret) - goto error; } + ret = iwl_send_phy_cfg_cmd(mvm); + if (ret) + goto error; + ret = iwl_mvm_send_bt_init_conf(mvm); if (ret) goto error; @@ -1480,7 +1212,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ret = iwl_mvm_sar_init(mvm); if (ret == 0) { ret = iwl_mvm_sar_geo_init(mvm); - } else if (ret > 0 && !iwl_mvm_sar_get_wgds_table(mvm)) { + } else if (ret > 0 && !iwl_sar_get_wgds_table(&mvm->fwrt)) { /* * If basic SAR is not available, we check for WGDS, * which should *not* be available either. If it is diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index d104da9170ca..72c4b2b8399d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -129,6 +129,9 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) mvm->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(mvm->hw->wiphy)); + if (!mvm->led.name) + return -ENOMEM; + mvm->led.brightness_set = iwl_led_brightness_set; mvm->led.max_brightness = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9c417dd06291..b78992e341d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -855,11 +855,10 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, struct ieee80211_vif *vif) { u8 rate; - - if (info->band == NL80211_BAND_5GHZ || vif->p2p) - rate = IWL_FIRST_OFDM_RATE; - else + if (info->band == NL80211_BAND_2GHZ && !vif->p2p) rate = IWL_FIRST_CCK_RATE; + else + rate = IWL_FIRST_OFDM_RATE; return rate; } @@ -1404,6 +1403,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, u32 rx_missed_bcon, rx_missed_bcon_since_rx; struct ieee80211_vif *vif; u32 id = le32_to_cpu(mb->mac_id); + union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; IWL_DEBUG_INFO(mvm, "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", @@ -1432,7 +1432,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, ieee80211_beacon_loss(vif); iwl_dbg_tlv_time_point(&mvm->fwrt, - IWL_FW_INI_TIME_POINT_MISSED_BEACONS, NULL); + IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), FW_DBG_TRIGGER_MISSED_BEACONS); @@ -1609,3 +1609,26 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, out_unlock: rcu_read_unlock(); } + +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_missed_vap_notif *mb = (void *)pkt->data; + struct ieee80211_vif *vif; + u32 id = le32_to_cpu(mb->mac_id); + + IWL_DEBUG_INFO(mvm, + "missed_vap notify mac_id=%u, num_beacon_intervals_elapsed=%u, profile_periodicity=%u\n", + le32_to_cpu(mb->mac_id), + mb->num_beacon_intervals_elapsed, + mb->profile_periodicity); + + rcu_read_lock(); + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + if (vif) + iwl_mvm_connection_loss(mvm, vif, "missed vap beacon"); + + rcu_read_unlock(); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d31f96c3f925..32dc9d6f0fb6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -339,14 +339,14 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) return ret; } -const static u8 he_if_types_ext_capa_sta[] = { +static const u8 he_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; -const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { +static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { { .iftype = NL80211_IFTYPE_STATION, .extended_capabilities = he_if_types_ext_capa_sta, @@ -355,6 +355,15 @@ const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { }, }; +static int +iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + *tx_ant = iwl_mvm_get_valid_tx_ant(mvm); + *rx_ant = iwl_mvm_get_valid_rx_ant(mvm); + return 0; +} + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) { struct ieee80211_hw *hw = mvm->hw; @@ -734,6 +743,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm); + hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm); + ret = ieee80211_register_hw(mvm->hw); if (ret) { iwl_mvm_leds_exit(mvm); @@ -2280,7 +2292,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, - &mvm->status)) { + &mvm->status) && + !fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { /* * If we're restarting then the firmware will * obviously have lost synchronisation with @@ -2294,6 +2308,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * * Set a large maximum delay to allow for more * than a single interface. + * + * For new firmware versions, rely on the + * firmware. This is relevant for DCM scenarios + * only anyway. */ u32 dur = (11 * vif->bss_conf.beacon_int) / 10; iwl_mvm_protect_session(mvm, vif, dur, dur, @@ -2384,8 +2402,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* * We received a beacon from the associated AP so * remove the session protection. + * A firmware with the new API will remove it automatically. */ - iwl_mvm_stop_session_protection(mvm, vif); + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_stop_session_protection(mvm, vif); iwl_mvm_sf_update(mvm, vif, false); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); @@ -3255,8 +3276,22 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, duration = req_duration; mutex_lock(&mvm->mutex); - /* Try really hard to protect the session and hear a beacon */ - iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); + /* Try really hard to protect the session and hear a beacon + * The new session protection command allows us to protect the + * session for a much longer time since the firmware will internally + * create two events: a 300TU one with a very high priority that + * won't be fragmented which should be enough for 99% of the cases, + * and another one (which we configure here to be 900TU long) which + * will have a slightly lower priority, but more importantly, can be + * fragmented so that it'll allow other activities to run. + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_schedule_session_protection(mvm, vif, 900, + min_duration); + else + iwl_mvm_protect_session(mvm, vif, duration, + min_duration, 500, false); mutex_unlock(&mvm->mutex); } @@ -3613,8 +3648,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *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, + iwl_mvm_phy_band_from_nl80211(channel->band), PHY_VHT_CHANNEL_MODE20, 0); @@ -3848,7 +3882,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter\n"); mutex_lock(&mvm->mutex); - iwl_mvm_stop_roc(mvm); + iwl_mvm_stop_roc(mvm, vif); mutex_unlock(&mvm->mutex); IWL_DEBUG_MAC80211(mvm, "leave\n"); @@ -4622,7 +4656,7 @@ static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) continue; if (drop) - iwl_mvm_flush_sta_tids(mvm, i, 0xFF, 0); + iwl_mvm_flush_sta_tids(mvm, i, 0xFFFF, 0); else iwl_mvm_wait_sta_queues_empty(mvm, iwl_mvm_sta_from_mac80211(sta)); @@ -5006,6 +5040,7 @@ 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, + .get_antenna = iwl_mvm_op_get_antenna, .start = iwl_mvm_mac_start, .reconfig_complete = iwl_mvm_mac_reconfig_complete, .stop = iwl_mvm_mac_stop, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5ca50f39a023..3ec8de00f3aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -188,6 +188,11 @@ enum iwl_power_scheme { IWL_POWER_SCHEME_LP }; +union geo_tx_power_profiles_cmd { + struct iwl_geo_tx_power_profiles_cmd geo_cmd; + struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1; +}; + #define IWL_CONN_MAX_LISTEN_INTERVAL 10 #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL @@ -774,14 +779,6 @@ enum iwl_mvm_queue_status { #define IWL_MVM_NUM_CIPHERS 10 -struct iwl_mvm_sar_profile { - bool enabled; - u8 table[ACPI_SAR_TABLE_SIZE]; -}; - -struct iwl_mvm_geo_profile { - u8 values[ACPI_GEO_TABLE_SIZE]; -}; struct iwl_mvm_txq { struct list_head list; @@ -1122,6 +1119,10 @@ struct iwl_mvm { int responses[IWL_MVM_TOF_MAX_APS]; } ftm_initiator; + struct { + u8 d0i3_resp; + } cmd_ver; + struct ieee80211_vif *nan_vif; #define IWL_MAX_BAID 32 struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID]; @@ -1140,14 +1141,6 @@ struct iwl_mvm { /* 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]; - u32 geo_rev; - struct iwl_ppag_table_cmd ppag_table; - u32 ppag_rev; -#endif }; /* Extract MVM priv from op_mode and _hw */ @@ -1405,12 +1398,19 @@ static inline bool iwl_mvm_is_scan_ext_chan_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER); } + static inline bool iwl_mvm_is_reduced_config_scan_supported(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG); } +static inline bool iwl_mvm_is_band_in_rx_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BAND_IN_RX_DATA); +} + static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, @@ -1682,6 +1682,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); /* Bindings */ @@ -2077,6 +2079,19 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct dentry *dir); #endif +static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band) +{ + switch (band) { + case NL80211_BAND_2GHZ: + return PHY_BAND_24; + case NL80211_BAND_5GHZ: + return PHY_BAND_5; + default: + WARN_ONCE(1, "Unsupported band (%u)\n", band); + return PHY_BAND_5; + } +} + /* Channel info utils */ static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) { @@ -2125,11 +2140,12 @@ iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm, struct iwl_fw_channel_info *ci, struct cfg80211_chan_def *chandef) { + enum nl80211_band band = chandef->chan->band; + 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)); + iwl_mvm_phy_band_from_nl80211(band), + 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/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3acbd5b7ab4b..1b07a8e8f069 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -263,6 +263,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, RX_HANDLER_SYNC), + RX_HANDLER_GRP(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF, + iwl_mvm_rx_session_protect_notif, RX_HANDLER_SYNC), RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, RX_HANDLER_ASYNC_LOCKED), @@ -432,6 +434,8 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), + HCMD_NAME(SESSION_PROTECTION_CMD), + HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF), }; @@ -608,6 +612,27 @@ static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .d3_debug_enable = iwl_mvm_d3_debug_enable, }; +static u8 iwl_mvm_lookup_notif_ver(struct iwl_mvm *mvm, u8 grp, u8 cmd, u8 def) +{ + const struct iwl_fw_cmd_version *entry; + unsigned int i; + + if (!mvm->fw->ucode_capa.cmd_versions || + !mvm->fw->ucode_capa.n_cmd_versions) + return def; + + entry = mvm->fw->ucode_capa.cmd_versions; + for (i = 0; i < mvm->fw->ucode_capa.n_cmd_versions; i++, entry++) { + if (entry->group == grp && entry->cmd == cmd) { + if (entry->notif_ver == IWL_FW_CMD_VER_UNKNOWN) + return def; + return entry->notif_ver; + } + } + + return def; +} + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -639,10 +664,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (!hw) return NULL; - if (cfg->max_rx_agg_size) - hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; - else - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; if (cfg->max_tx_agg_size) hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; @@ -667,7 +689,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, op_mode->ops = &iwl_mvm_ops_mq; trans->rx_mpdu_cmd_hdr_size = (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_rx_mpdu_desc) : IWL_RX_DESC_SIZE_V1; } else { @@ -722,6 +744,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork); + mvm->cmd_ver.d0i3_resp = + iwl_mvm_lookup_notif_ver(mvm, LEGACY_GROUP, D0I3_END_CMD, 0); + /* we only support version 1 */ + if (WARN_ON_ONCE(mvm->cmd_ver.d0i3_resp > 1)) + goto out_free; + /* * Populate the state variables that the transport layer needs * to know about. @@ -730,7 +758,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) rb_size_default = IWL_AMSDU_2K; else rb_size_default = IWL_AMSDU_4K; @@ -756,7 +784,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans->wide_cmd_header = true; trans_cfg.bc_table_dword = - mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_22560; + mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210; trans_cfg.command_groups = iwl_mvm_groups; trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 22136e4832ea..25d7faea1c62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -370,8 +370,6 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm, if (dtimper >= 10) return; - /* TODO: check that multicast wake lock is off */ - if (host_awake) { if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 8f50e2b121bd..e2cf9e015ef8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -341,16 +341,24 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, lq_sta = &mvmsta->lq_sta.rs_fw; if (flags & IWL_TLC_NOTIF_FLAG_RATE) { + char pretty_rate[100]; lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate); - IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n", - lq_sta->last_rate_n_flags); + rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate), + lq_sta->last_rate_n_flags); + IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate); } if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) { u16 size = le32_to_cpu(notif->amsdu_size); int i; - if (WARN_ON(sta->max_amsdu_len < size)) + /* + * In debug sta->max_amsdu_len < size + * so also check with orig_amsdu_len which holds the original + * data before debugfs changed the value + */ + if (WARN_ON(sta->max_amsdu_len < size && + mvmsta->orig_amsdu_len < size)) goto out; mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); @@ -378,7 +386,7 @@ out: rcu_read_unlock(); } -static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta) +u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta) { const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 42d525e46e80..1a990ed9c3ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1533,6 +1533,8 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i; + sta->max_amsdu_len = rs_fw_get_max_amsdu_len(sta); + /* * In case TLC offload is not active amsdu_enabled is either 0xFFFF * or 0, since there is no per-TID alg. @@ -3683,7 +3685,6 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta) IWL_DEBUG_RATE(mvm, "leave\n"); } -#ifdef CONFIG_MAC80211_DEBUGFS int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) { @@ -3739,14 +3740,15 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) } return scnprintf(buf, bufsz, - "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s\n", - type, rs_pretty_ant(ant), bw, mcs, nss, + "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s\n", + rate, type, rs_pretty_ant(ant), bw, mcs, nss, (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", (rate & RATE_MCS_BF_MSK) ? "BF " : ""); } +#ifdef CONFIG_MAC80211_DEBUGFS /** * Program the device to use fixed rate for frame transmit * This is for debugging/testing only diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 428642e66658..32104c9f8f5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -445,10 +445,6 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif -#ifdef CONFIG_MAC80211_DEBUGFS -void rs_remove_sta_debugfs(void *mvm, void *mvm_sta); -#endif - void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta); void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update); @@ -456,4 +452,6 @@ int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); + +u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta); #endif /* __rs__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 0ad8ed23a455..5ee33c8ae9d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -60,6 +60,7 @@ * (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 <asm/unaligned.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include "iwl-trans.h" @@ -357,7 +358,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); len = le16_to_cpu(rx_res->byte_count); - rx_pkt_status = le32_to_cpup((__le32 *) + rx_pkt_status = get_unaligned_le32((__le32 *) (pkt->data + sizeof(*rx_res) + len)); /* Dont use dev_alloc_skb(), we'll have enough headroom once diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 77b03b757193..ef99c49247b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -23,7 +23,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Linux Wireless <linuxwifi@intel.com> * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -1542,6 +1542,19 @@ static void iwl_mvm_decode_lsig(struct sk_buff *skb, } } +static inline u8 iwl_mvm_nl80211_band_from_rx_msdu(u8 phy_band) +{ + switch (phy_band) { + case PHY_BAND_24: + return NL80211_BAND_2GHZ; + case PHY_BAND_5: + return NL80211_BAND_5GHZ; + default: + WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band); + return NL80211_BAND_5GHZ; + } +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -1565,7 +1578,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) return; - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags); channel = desc->v3.channel; gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise); @@ -1667,7 +1680,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, u64 tsf_on_air_rise; if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) + IWL_DEVICE_FAMILY_AX210) tsf_on_air_rise = le64_to_cpu(desc->v3.tsf_on_air_rise); else tsf_on_air_rise = le64_to_cpu(desc->v1.tsf_on_air_rise); @@ -1678,8 +1691,14 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, } rx_status->device_timestamp = gp2_on_air_rise; - rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : - NL80211_BAND_2GHZ; + if (iwl_mvm_is_band_in_rx_supported(mvm)) { + u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx); + + rx_status->band = iwl_mvm_nl80211_band_from_rx_msdu(band); + } else { + 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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index fcafa22ec6ce..a046ac9fa852 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -79,9 +79,6 @@ #define IWL_SCAN_NUM_OF_FRAGS 3 #define IWL_SCAN_LAST_2_4_CHN 14 -#define IWL_SCAN_BAND_5_2 0 -#define IWL_SCAN_BAND_2_4 1 - /* adaptive dwell max budget time [TU] for full scan */ #define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 /* adaptive dwell max budget time [TU] for directed scan */ @@ -92,6 +89,10 @@ #define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 2 /* adaptive dwell default APs number in social channels (1, 6, 11) */ #define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 +/* number of scan channels */ +#define IWL_SCAN_NUM_CHANNELS 112 +/* adaptive dwell default number of APs override */ +#define IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE 10 struct iwl_mvm_scan_timing_params { u32 suspend_time; @@ -196,14 +197,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static __le32 iwl_mvm_scan_rxon_flags(enum nl80211_band band) -{ - if (band == NL80211_BAND_2GHZ) - return cpu_to_le32(PHY_BAND_24); - else - return cpu_to_le32(PHY_BAND_5); -} - static inline __le32 iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band, bool no_cck) @@ -550,6 +543,7 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, { int i, j; int index; + u32 tmp_bitmap = 0; /* * copy SSIDs from match list. @@ -569,7 +563,6 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, } /* add SSIDs from scan SSID list */ - *ssid_bitmap = 0; for (j = params->n_ssids - 1; j >= 0 && i < PROBE_OPTION_MAX; i++, j--) { @@ -581,11 +574,13 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, ssids[i].len = params->ssids[j].ssid_len; memcpy(ssids[i].ssid, params->ssids[j].ssid, ssids[i].len); - *ssid_bitmap |= BIT(i); + tmp_bitmap |= BIT(i); } else { - *ssid_bitmap |= BIT(index); + tmp_bitmap |= BIT(index); } } + if (ssid_bitmap) + *ssid_bitmap = tmp_bitmap; } static int @@ -981,10 +976,7 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->fw->ucode_capa.n_scan_channels); u32 ssid_bitmap = 0; int i; - - lockdep_assert_held(&mvm->mutex); - - memset(cmd, 0, ksize(cmd)); + u8 band; if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) return -EINVAL; @@ -1000,7 +992,8 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params, vif)); - cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band); + band = iwl_mvm_phy_band_from_nl80211(params->channels[0]->band); + cmd->flags = cpu_to_le32(band); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck); @@ -1414,21 +1407,176 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); } +static u32 iwl_mvm_scan_umac_ooc_priority(struct iwl_mvm_scan_params *params) +{ + return iwl_mvm_is_regular_scan(params) ? + IWL_SCAN_PRIORITY_EXT_6 : + IWL_SCAN_PRIORITY_EXT_2; +} + +static void +iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, + struct iwl_scan_general_params_v10 *general_params, + struct iwl_mvm_scan_params *params) +{ + struct iwl_mvm_scan_timing_params *timing, *hb_timing; + u8 active_dwell, passive_dwell; + + timing = &scan_timing[params->type]; + active_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_ACTIVE; + passive_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_PASSIVE; + + general_params->adwell_default_social_chn = + IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; + general_params->adwell_default_2g = IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; + general_params->adwell_default_5g = IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; + + /* if custom max budget was configured with debugfs */ + if (IWL_MVM_ADWELL_MAX_BUDGET) + general_params->adwell_max_budget = + cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); + else if (params->ssids && params->ssids[0].ssid_len) + general_params->adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else + general_params->adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); + + general_params->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + general_params->max_out_of_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + general_params->suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); + + hb_timing = &scan_timing[params->hb_type]; + + general_params->max_out_of_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(hb_timing->max_out_time); + general_params->suspend_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(hb_timing->suspend_time); + + general_params->active_dwell[SCAN_LB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell; + general_params->active_dwell[SCAN_HB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[SCAN_HB_LMAC_IDX] = passive_dwell; +} + +struct iwl_mvm_scan_channel_segment { + u8 start_idx; + u8 end_idx; + u8 first_channel_id; + u8 last_channel_id; + u8 channel_spacing_shift; + u8 band; +}; + +static const struct iwl_mvm_scan_channel_segment scan_channel_segments[] = { + { + .start_idx = 0, + .end_idx = 13, + .first_channel_id = 1, + .last_channel_id = 14, + .channel_spacing_shift = 0, + .band = PHY_BAND_24 + }, + { + .start_idx = 14, + .end_idx = 41, + .first_channel_id = 36, + .last_channel_id = 144, + .channel_spacing_shift = 2, + .band = PHY_BAND_5 + }, + { + .start_idx = 42, + .end_idx = 50, + .first_channel_id = 149, + .last_channel_id = 181, + .channel_spacing_shift = 2, + .band = PHY_BAND_5 + }, +}; + +static int iwl_mvm_scan_ch_and_band_to_idx(u8 channel_id, u8 band) +{ + int i, index; + + if (!channel_id) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(scan_channel_segments); i++) { + const struct iwl_mvm_scan_channel_segment *ch_segment = + &scan_channel_segments[i]; + u32 ch_offset; + + if (ch_segment->band != band || + ch_segment->first_channel_id > channel_id || + ch_segment->last_channel_id < channel_id) + continue; + + ch_offset = (channel_id - ch_segment->first_channel_id) >> + ch_segment->channel_spacing_shift; + + index = scan_channel_segments[i].start_idx + ch_offset; + if (index < IWL_SCAN_NUM_CHANNELS) + return index; + + break; + } + + return -EINVAL; +} + +static void iwl_mvm_scan_ch_add_n_aps_override(enum nl80211_iftype vif_type, + u8 ch_id, u8 band, u8 *ch_bitmap, + size_t bitmap_n_entries) +{ + int i; + static const u8 p2p_go_friendly_chs[] = { + 36, 40, 44, 48, 149, 153, 157, 161, 165, + }; + + if (vif_type != NL80211_IFTYPE_P2P_DEVICE) + return; + + for (i = 0; i < ARRAY_SIZE(p2p_go_friendly_chs); i++) { + if (p2p_go_friendly_chs[i] == ch_id) { + int ch_idx, bitmap_idx; + + ch_idx = iwl_mvm_scan_ch_and_band_to_idx(ch_id, band); + if (ch_idx < 0) + return; + + bitmap_idx = ch_idx / 8; + if (bitmap_idx >= bitmap_n_entries) + return; + + ch_idx = ch_idx % 8; + ch_bitmap[bitmap_idx] |= BIT(ch_idx); + + return; + } + } +} + static void iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, struct ieee80211_channel **channels, - int n_channels, u32 ssid_bitmap, + int n_channels, u32 flags, struct iwl_scan_channel_cfg_umac *channel_cfg) { int i; for (i = 0; i < n_channels; i++) { - channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); + channel_cfg[i].flags = cpu_to_le32(flags); channel_cfg[i].v1.channel_num = channels[i]->hw_value; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { + enum nl80211_band band = channels[i]->band; + channel_cfg[i].v2.band = - channels[i]->hw_value <= IWL_SCAN_LAST_2_4_CHN ? - IWL_SCAN_BAND_2_4 : IWL_SCAN_BAND_5_2; + iwl_mvm_phy_band_from_nl80211(band); channel_cfg[i].v2.iter_count = 1; channel_cfg[i].v2.iter_interval = 0; } else { @@ -1438,6 +1586,92 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, } } +static void +iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, + struct ieee80211_channel **channels, + struct iwl_scan_channel_params_v4 *cp, + int n_channels, u32 flags, + enum nl80211_iftype vif_type) +{ + u8 *bitmap = cp->adwell_ch_override_bitmap; + size_t bitmap_n_entries = ARRAY_SIZE(cp->adwell_ch_override_bitmap); + int i; + + for (i = 0; i < n_channels; i++) { + enum nl80211_band band = channels[i]->band; + struct iwl_scan_channel_cfg_umac *cfg = + &cp->channel_config[i]; + + cfg->flags = cpu_to_le32(flags); + cfg->v2.channel_num = channels[i]->hw_value; + cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); + cfg->v2.iter_count = 1; + cfg->v2.iter_interval = 0; + + iwl_mvm_scan_ch_add_n_aps_override(vif_type, + cfg->v2.channel_num, + cfg->v2.band, bitmap, + bitmap_n_entries); + } +} + +static u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif) +{ + u8 flags = 0; + + flags |= IWL_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; + + if (iwl_mvm_scan_use_ebs(mvm, vif)) + flags |= IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; + + /* set fragmented ebs for fragmented scan on HB channels */ + if (iwl_mvm_is_scan_fragmented(params->hb_type)) + flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG; + + return flags; +} + +static u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + int type) +{ + u16 flags = 0; + + if (params->n_ssids == 0) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; + + if (iwl_mvm_is_scan_fragmented(params->type)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1; + + if (iwl_mvm_is_scan_fragmented(params->hb_type)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2; + + if (params->pass_all) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL; + else + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH; + + if (!iwl_mvm_is_regular_scan(params)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC; + + if (params->measurement_dwell || + mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE; + + if (IWL_MVM_ADWELL_ENABLE) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; + + if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE; + + return flags; +} + static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -1481,8 +1715,7 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; - if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE && - vif->type != NL80211_IFTYPE_P2P_DEVICE) + if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL; /* @@ -1517,9 +1750,42 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, return flags; } +static int +iwl_mvm_fill_scan_sched_params(struct iwl_mvm_scan_params *params, + struct iwl_scan_umac_schedule *schedule, + __le16 *delay) +{ + int i; + if (WARN_ON(!params->n_scan_plans || + params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) + return -EINVAL; + + for (i = 0; i < params->n_scan_plans; i++) { + struct cfg80211_sched_scan_plan *scan_plan = + ¶ms->scan_plans[i]; + + schedule[i].iter_count = scan_plan->iterations; + schedule[i].interval = + cpu_to_le16(scan_plan->interval); + } + + /* + * If the number of iterations of the last scan plan is set to + * zero, it should run infinitely. However, this is not always the case. + * For example, when regular scan is requested the driver sets one scan + * plan with one iteration. + */ + if (!schedule[params->n_scan_plans - 1].iter_count) + schedule[params->n_scan_plans - 1].iter_count = 0xff; + + *delay = cpu_to_le16(params->delay); + + return 0; +} + static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_scan_params *params, - int type) + int type, int uid) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; struct iwl_scan_umac_chan_param *chan_param; @@ -1530,7 +1796,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, (struct iwl_scan_req_umac_tail_v2 *)sec_part; struct iwl_scan_req_umac_tail_v1 *tail_v1; struct iwl_ssid_ie *direct_scan; - int uid, i; + int ret = 0; u32 ssid_bitmap = 0; u8 channel_flags = 0; u16 gen_flags; @@ -1538,17 +1804,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, chan_param = iwl_mvm_get_scan_req_umac_channel(mvm); - lockdep_assert_held(&mvm->mutex); - - if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) - return -EINVAL; - - uid = iwl_mvm_scan_uid_by_status(mvm, 0); - if (uid < 0) - return uid; - - memset(cmd, 0, ksize(cmd)); - iwl_mvm_scan_umac_dwell(mvm, cmd, params); mvm->scan_uid_status[uid] = type; @@ -1591,25 +1846,10 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, chan_param->flags = channel_flags; chan_param->count = params->n_channels; - for (i = 0; i < params->n_scan_plans; i++) { - struct cfg80211_sched_scan_plan *scan_plan = - ¶ms->scan_plans[i]; - - tail_v2->schedule[i].iter_count = scan_plan->iterations; - tail_v2->schedule[i].interval = - cpu_to_le16(scan_plan->interval); - } - - /* - * If the number of iterations of the last scan plan is set to - * zero, it should run infinitely. However, this is not always the case. - * For example, when regular scan is requested the driver sets one scan - * plan with one iteration. - */ - if (!tail_v2->schedule[i - 1].iter_count) - tail_v2->schedule[i - 1].iter_count = 0xff; - - tail_v2->delay = cpu_to_le16(params->delay); + ret = iwl_mvm_fill_scan_sched_params(params, tail_v2->schedule, + &tail_v2->delay); + if (ret) + return ret; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { tail_v2->preq = params->preq; @@ -1627,6 +1867,174 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } +static void +iwl_mvm_scan_umac_fill_general_p_v10(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_general_params_v10 *gp, + u16 gen_flags) +{ + struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); + + iwl_mvm_scan_umac_dwell_v10(mvm, gp, params); + + gp->flags = cpu_to_le16(gen_flags); + + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) + gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) + gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; + + gp->scan_start_mac_id = scan_vif->id; +} + +static void +iwl_mvm_scan_umac_fill_probe_p_v3(struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v3 *pp) +{ + pp->preq = params->preq; + pp->ssid_num = params->n_ssids; + iwl_scan_build_ssids(params, pp->direct_scan, NULL); +} + +static void +iwl_mvm_scan_umac_fill_probe_p_v4(struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v4 *pp, + u32 *bitmap_ssid) +{ + pp->preq = params->preq; + iwl_scan_build_ssids(params, pp->direct_scan, bitmap_ssid); +} + +static void +iwl_mvm_scan_umac_fill_ch_p_v3(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_channel_params_v3 *cp) +{ + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); + cp->count = params->n_channels; + + iwl_mvm_umac_scan_cfg_channels(mvm, params->channels, + params->n_channels, 0, + cp->channel_config); +} + +static void +iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_channel_params_v4 *cp, + u32 channel_cfg_flags) +{ + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); + cp->count = params->n_channels; + cp->num_of_aps_override = IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE; + + iwl_mvm_umac_scan_cfg_channels_v4(mvm, params->channels, cp, + params->n_channels, + channel_cfg_flags, + vif->type); +} + +static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v11 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v11 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; + + mvm->scan_uid_status[uid] = type; + + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + cmd->uid = cpu_to_le32(uid); + + gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); + iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); + + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); + if (ret) + return ret; + + iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); + iwl_mvm_scan_umac_fill_ch_p_v3(mvm, params, vif, + &scan_p->channel_params); + + return 0; +} + +static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v12 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v12 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; + + mvm->scan_uid_status[uid] = type; + + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + cmd->uid = cpu_to_le32(uid); + + gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); + iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); + + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); + if (ret) + return ret; + + iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); + iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, + &scan_p->channel_params, 0); + + return 0; +} + +static int iwl_mvm_scan_umac_v13(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v13 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v13 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; + u32 bitmap_ssid = 0; + + mvm->scan_uid_status[uid] = type; + + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + cmd->uid = cpu_to_le32(uid); + + gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); + iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); + + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); + if (ret) + return ret; + + iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, + &bitmap_ssid); + iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, + &scan_p->channel_params, bitmap_ssid); + + return 0; +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -1729,6 +2137,64 @@ static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, } } +struct iwl_scan_umac_handler { + u8 version; + int (*handler)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, int uid); +}; + +#define IWL_SCAN_UMAC_HANDLER(_ver) { \ + .version = _ver, \ + .handler = iwl_mvm_scan_umac_v##_ver, \ +} + +static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { + /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(13), + IWL_SCAN_UMAC_HANDLER(12), + IWL_SCAN_UMAC_HANDLER(11), +}; + +static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_host_cmd *hcmd, + struct iwl_mvm_scan_params *params, + int type) +{ + int uid, i; + u8 scan_ver; + + lockdep_assert_held(&mvm->mutex); + memset(mvm->scan_cmd, 0, ksize(mvm->scan_cmd)); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { + hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; + + return iwl_mvm_scan_lmac(mvm, vif, params); + } + + uid = iwl_mvm_scan_uid_by_status(mvm, 0); + if (uid < 0) + return uid; + + hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); + + scan_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC); + + for (i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) { + const struct iwl_scan_umac_handler *ver_handler = + &iwl_scan_umac_handlers[i]; + + if (ver_handler->version != scan_ver) + continue; + + return ver_handler->handler(mvm, vif, params, type, uid); + } + + return iwl_mvm_scan_umac(mvm, vif, params, type, uid); +} + int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) @@ -1786,14 +2252,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, - IWL_MVM_SCAN_REGULAR); - } else { - hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; - ret = iwl_mvm_scan_lmac(mvm, vif, ¶ms); - } + ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, + IWL_MVM_SCAN_REGULAR); if (ret) return ret; @@ -1891,13 +2351,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, type); - } else { - hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; - ret = iwl_mvm_scan_lmac(mvm, vif, ¶ms); - } + ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type); if (ret) return ret; @@ -2048,10 +2502,31 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) 1 * HZ); } +#define IWL_SCAN_REQ_UMAC_HANDLE_SIZE(_ver) { \ + case (_ver): return sizeof(struct iwl_scan_req_umac_v##_ver); \ +} + +static int iwl_scan_req_umac_get_size(u8 scan_ver) +{ + switch (scan_ver) { + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(13); + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(11); + } + + return 0; +} + int iwl_mvm_scan_size(struct iwl_mvm *mvm) { - int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; - int tail_size; + int base_size, tail_size; + u8 scan_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC); + + base_size = iwl_scan_req_umac_get_size(scan_ver); + if (base_size) + return base_size; + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; @@ -2059,6 +2534,8 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; else if (iwl_mvm_cdb_scan_api(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; + else + base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { if (iwl_mvm_is_scan_ext_chan_supported(mvm)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b3768d5d852a..7b35f416404c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2844,13 +2844,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (normalized_ssn == tid_data->next_reclaimed) { tid_data->state = IWL_AGG_STARTING; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; } else { tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA; + ret = 0; } - ret = 0; - out: spin_unlock_bh(&mvmsta->lock); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index a06bc63fb516..51b138673ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -734,6 +734,11 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, return; } +/* + * When the firmware supports the session protection API, + * this is not needed since it'll automatically remove the + * session protection after association + beacon reception. + */ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -757,6 +762,101 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, iwl_mvm_remove_time_event(mvm, mvmvif, te_data); } +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; + struct ieee80211_vif *vif; + + rcu_read_lock(); + vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id), + true); + + if (!vif) + goto out_unlock; + + /* The vif is not a P2P_DEVICE, maintain its time_event_data */ + if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = + &mvmvif->time_event_data; + + if (!le32_to_cpu(notif->status)) { + iwl_mvm_te_check_disconnect(mvm, vif, + "Session protection failure"); + iwl_mvm_te_clear_data(mvm, te_data); + } + + if (le32_to_cpu(notif->start)) { + spin_lock_bh(&mvm->time_event_lock); + te_data->running = le32_to_cpu(notif->start); + te_data->end_jiffies = + TU_TO_EXP_TIME(te_data->duration); + spin_unlock_bh(&mvm->time_event_lock); + } else { + /* + * By now, we should have finished association + * and know the dtim period. + */ + iwl_mvm_te_check_disconnect(mvm, vif, + "No beacon heard and the session protection is over already..."); + iwl_mvm_te_clear_data(mvm, te_data); + } + + goto out_unlock; + } + + if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { + /* End TE, notify mac80211 */ + ieee80211_remain_on_channel_expired(mvm->hw); + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_roc_finished(mvm); + } else if (le32_to_cpu(notif->start)) { + set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + ieee80211_ready_on_channel(mvm->hw); /* Start TE */ + } + + out_unlock: + rcu_read_unlock(); +} + +static int +iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int duration, + enum ieee80211_roc_type type) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + + lockdep_assert_held(&mvm->mutex); + + switch (type) { + case IEEE80211_ROC_TYPE_NORMAL: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV); + break; + case IEEE80211_ROC_TYPE_MGMT_TX: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION); + break; + default: + WARN_ONCE(1, "Got an invalid ROC type\n"); + return -EINVAL; + } + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); +} + int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum ieee80211_roc_type type) { @@ -770,6 +870,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EBUSY; } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + return iwl_mvm_start_p2p_roc_session_protection(mvm, vif, + duration, + type); + time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); @@ -847,11 +953,44 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) __iwl_mvm_remove_time_event(mvm, te_data, &uid); } -void iwl_mvm_stop_roc(struct iwl_mvm *mvm) +static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif) +{ + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + int ret; + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); +} + +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif; struct iwl_mvm_time_event_data *te_data; + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + iwl_mvm_cancel_session_protection(mvm, mvmvif); + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + + iwl_mvm_roc_finished(mvm); + + return; + } + te_data = iwl_mvm_get_roc_te(mvm); if (!te_data) { IWL_WARN(mvm, "No remain on channel event\n"); @@ -916,3 +1055,51 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } + +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + if (te_data->running && + time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { + IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", + jiffies_to_msecs(te_data->end_jiffies - jiffies)); + spin_unlock_bh(&mvm->time_event_lock); + + return; + } + + iwl_mvm_te_clear_data(mvm, te_data); + te_data->duration = le32_to_cpu(cmd.duration_tu); + spin_unlock_bh(&mvm->time_event_lock); + + IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", + le32_to_cpu(cmd.duration_tu)); + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) { + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); + spin_lock_bh(&mvm->time_event_lock); + iwl_mvm_te_clear_data(mvm, te_data); + spin_unlock_bh(&mvm->time_event_lock); + } +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 1dd3d01245ea..df6832b79666 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications 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 @@ -28,6 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -178,12 +180,13 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /** * iwl_mvm_stop_roc - stop remain on channel functionality * @mvm: the mvm component + * @vif: the virtual interface for which the roc is stopped * * This function can be used to cancel an ongoing ROC session. * The function is async, it will instruct the FW to stop serving the ROC * session, but will not wait for the actual stopping of the session. */ -void iwl_mvm_stop_roc(struct iwl_mvm *mvm); +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /** * iwl_mvm_remove_time_event - general function to clean up of time event @@ -242,4 +245,20 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) return !!te_data->uid; } +/** + * iwl_mvm_schedule_session_protection - schedule a session protection + * @mvm: the mvm component + * @vif: the virtual interface for which the protection issued + * @duration: the duration of the protection + */ +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration); + +/** + * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF + */ +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); + #endif /* __time_event_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index f0c539b37ea7..b5a16f00bada 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -8,6 +8,7 @@ * Copyright(c) 2013 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 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 @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -482,26 +484,27 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = { /* budget in mWatt */ static const u32 iwl_mvm_cdev_budgets[] = { - 2000, /* cooling state 0 */ - 1800, /* cooling state 1 */ - 1600, /* cooling state 2 */ - 1400, /* cooling state 3 */ - 1200, /* cooling state 4 */ - 1000, /* cooling state 5 */ - 900, /* cooling state 6 */ - 800, /* cooling state 7 */ - 700, /* cooling state 8 */ - 650, /* cooling state 9 */ - 600, /* cooling state 10 */ - 550, /* cooling state 11 */ - 500, /* cooling state 12 */ - 450, /* cooling state 13 */ - 400, /* cooling state 14 */ - 350, /* cooling state 15 */ - 300, /* cooling state 16 */ - 250, /* cooling state 17 */ - 200, /* cooling state 18 */ - 150, /* cooling state 19 */ + 2400, /* cooling state 0 */ + 2000, /* cooling state 1 */ + 1800, /* cooling state 2 */ + 1600, /* cooling state 3 */ + 1400, /* cooling state 4 */ + 1200, /* cooling state 5 */ + 1000, /* cooling state 6 */ + 900, /* cooling state 7 */ + 800, /* cooling state 8 */ + 700, /* cooling state 9 */ + 650, /* cooling state 10 */ + 600, /* cooling state 11 */ + 550, /* cooling state 12 */ + 500, /* cooling state 13 */ + 450, /* cooling state 14 */ + 400, /* cooling state 15 */ + 350, /* cooling state 16 */ + 300, /* cooling state 17 */ + 250, /* cooling state 18 */ + 200, /* cooling state 19 */ + 150, /* cooling state 20 */ }; int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8a059da7a1fa..dc5c02fbc65a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -341,8 +341,11 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, rate_idx = rate_lowest_index( &mvm->nvm_data->bands[info->band], sta); - /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ - if (info->band == NL80211_BAND_5GHZ) + /* + * For non 2 GHZ band, remap mac80211 rate + * indices into driver indices + */ + if (info->band != NL80211_BAND_2GHZ) rate_idx += IWL_FIRST_OFDM_RATE; /* For 2.4 GHZ band, check that there is no need to remap */ @@ -547,7 +550,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, } if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) { + IWL_DEVICE_FAMILY_AX210) { struct iwl_tx_cmd_gen3 *cmd = (void *)dev_cmd->payload; cmd->offload_assist |= cpu_to_le32(offload_assist); @@ -935,7 +938,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid); + /* + * Take the min of ieee80211 station and mvm station + */ + max_amsdu_len = + min_t(unsigned int, sta->max_amsdu_len, + iwl_mvm_max_amsdu_size(mvm, sta, tid)); /* * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not @@ -2051,7 +2059,7 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) if (iwl_mvm_has_new_tx_api(mvm)) return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, - 0xff | BIT(IWL_MGMT_TID), flags); + 0xffff, flags); if (internal) return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8686107da116..6096276cb0d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -217,7 +217,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, int band_offset = 0; /* Legacy rate format, search for match in table */ - if (band == NL80211_BAND_5GHZ) + if (band != NL80211_BAND_2GHZ) band_offset = IWL_FIRST_OFDM_RATE; for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) if (fw_rate_idx_to_plcp[idx] == rate) |