From 382d8296c5b5664a4f16653f71d3fbf64263afb3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 24 Apr 2020 18:48:07 +0300 Subject: iwlwifi: fw api: fix PHY data 2/3 position In AX210 devices, the PHY data wasn't actually reported, but now that it's going to be reported it turns out that the position is supposed to be the other way around, fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182643.06de959301f5.I544c353a8a811f107bd66d168e37920237ecf071@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 88bc7733065f..b8b36a4f9eb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 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 @@ -535,9 +533,9 @@ struct iwl_rx_mpdu_desc_v3 { __le32 filter_match; /** - * @phy_data2: depends on info type (see @phy_data1) + * @phy_data3: depends on info type (see @phy_data1) */ - __le32 phy_data2; + __le32 phy_data3; }; /* DW8 - carries rss_hash only when rpa_en == 1 */ @@ -548,9 +546,9 @@ struct iwl_rx_mpdu_desc_v3 { __le32 rss_hash; /** - * @phy_data3: depends on info type (see @phy_data1) + * @phy_data2: depends on info type (see @phy_data1) */ - __le32 phy_data3; + __le32 phy_data2; }; /* DW9 */ /** -- cgit From ebfa7f8ae155c9a0bb2e4038d6b5d8b14881c424 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 18:48:08 +0300 Subject: iwlwifi: yoyo: add support for parsing SHARED_MEM_ALLOC version 4 The new version adds the information for RX2C FIFO addresses. Use the new addresses to parse the FIFO info when dumping. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182643.97cc25d96b53.I65fd0400d80f505bd6d7eed442f12db24b25bbe3@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/debug.h | 14 ++++++----- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 29 ++++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 5 ++-- drivers/net/wireless/intel/iwlwifi/fw/smem.c | 14 +++++++---- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 11 ++++----- 5 files changed, 52 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h index 98e957ecbeed..94b1a1268476 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * 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 + * Copyright(c) 2007 - 2014, 2018 - 2020 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,10 +27,9 @@ * * BSD LICENSE * - * 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 + * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -218,6 +216,8 @@ struct iwl_shared_mem_lmac_cfg { * @page_buff_size: size of %page_buff_addr * @lmac_num: number of LMACs (1 or 2) * @lmac_smem: per - LMAC smem data + * @rxfifo2_control_addr: start addr of RXF2C + * @rxfifo2_control_size: size of RXF2C */ struct iwl_shared_mem_cfg { __le32 shared_mem_addr; @@ -229,8 +229,10 @@ struct iwl_shared_mem_cfg { __le32 page_buff_addr; __le32 page_buff_size; __le32 lmac_num; - struct iwl_shared_mem_lmac_cfg lmac_smem[2]; -} __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ + struct iwl_shared_mem_lmac_cfg lmac_smem[3]; + __le32 rxfifo2_control_addr; + __le32 rxfifo2_control_size; +} __packed; /* SHARED_MEM_ALLOC_API_S_VER_4 */ /** * struct iwl_mfuart_load_notif - mfuart image version & status diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 39c8332be3ac..914f0eb07d52 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1386,13 +1386,36 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, } 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; + if (fid2 && !WARN_ON_ONCE(~BIT(fifo_idx) & fid2)) { + u8 max_idx; + + if (iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, + SHARED_MEM_CFG_CMD, 0) <= 3) + max_idx = 0; + else + max_idx = 1; + + if (WARN_ONCE(fifo_idx > max_idx, + "invalid umac fifo idx %d", fifo_idx)) + return; + /* use bit 31 to distinguish between umac and lmac rxf while * parsing the dump */ data->fifo_num = fifo_idx | IWL_RXF_UMAC_BIT; + + switch (fifo_idx) { + case 0: + data->size = fwrt->smem_cfg.rxfifo2_size; + data->offset = iwl_umac_prph(fwrt->trans, + RXF_DIFF_FROM_PREV); + break; + case 1: + data->size = fwrt->smem_cfg.rxfifo2_control_size; + data->offset = iwl_umac_prph(fwrt->trans, + RXF2C_DIFF_FROM_PREV); + break; + } return; } } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 9906d9b9bdd5..9629ef94b214 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-2019 Intel Corporation + * Copyright (C) 2018-2020 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-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,6 +86,7 @@ struct iwl_fwrt_shared_mem_cfg { u32 rxfifo1_size; } lmac[MAX_NUM_LMAC]; u32 rxfifo2_size; + u32 rxfifo2_control_size; u32 internal_txfifo_addr; u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c index 409b2dd854ac..700fdab14209 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * 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 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 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,10 +27,9 @@ * * BSD LICENSE * - * 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 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,6 +69,8 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data; int i, lmac; int lmac_num = le32_to_cpu(mem_cfg->lmac_num); + u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, + SHARED_MEM_CFG_CMD, 0); if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) return; @@ -80,6 +80,12 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, ARRAY_SIZE(mem_cfg->lmac_smem[0].txfifo_size); fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); + if (api_ver >= 4 && + !WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg))) { + fwrt->smem_cfg.rxfifo2_control_size = + le32_to_cpu(mem_cfg->rxfifo2_control_size); + } + for (lmac = 0; lmac < lmac_num; lmac++) { struct iwl_shared_mem_lmac_cfg *lmac_cfg = &mem_cfg->lmac_smem[lmac]; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 1136d9784f9d..8e254c0eda13 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018 - 2019 Intel Corporation + * Copyright(c) 2005 - 2014, 2018 - 2020 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,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018 - 2019 Intel Corporation + * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -326,6 +324,7 @@ #define RXF_SIZE_BYTE_CND_POS (7) #define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS) #define RXF_DIFF_FROM_PREV (0x200) +#define RXF2C_DIFF_FROM_PREV (0x4e00) #define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10) #define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c) -- cgit From cc9b6012d34b8cb130d4269a79032b75a84bf46e Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 18:48:09 +0300 Subject: iwlwifi: yoyo: use hweight_long instead of bit manipulating Also we can only have one fid1 or fid2 set so no need to check if the fid2 is set in case fid1 wasn't set. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.34e74106bad3.Ic3a9f0a35fed47b02ebcd27c2dc2b50cb1e56bdf@changeid --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 914f0eb07d52..37c8b6cc2ec7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1367,28 +1367,30 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; u32 fid1 = le32_to_cpu(reg->fifos.fid[0]); u32 fid2 = le32_to_cpu(reg->fifos.fid[1]); - u32 fifo_idx; + u8 fifo_idx; if (!data) return; + /* make sure only one bit is set in only one fid */ + if (WARN_ONCE(hweight_long(fid1) + hweight_long(fid2) != 1, + "fid1=%x, fid2=%x\n", fid1, fid2)) + return; + memset(data, 0, sizeof(*data)); - if (WARN_ON_ONCE((fid1 && fid2) || (!fid1 && !fid2))) - return; + if (fid1) { + fifo_idx = ffs(fid1) - 1; + if (WARN_ONCE(fifo_idx >= MAX_NUM_LMAC, "fifo_idx=%d\n", + fifo_idx)) + 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(~BIT(fifo_idx) & fid2)) { + } else { u8 max_idx; + fifo_idx = ffs(fid2) - 1; if (iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, SHARED_MEM_CFG_CMD, 0) <= 3) max_idx = 0; @@ -1416,7 +1418,6 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, RXF2C_DIFF_FROM_PREV); break; } - return; } } -- cgit From f25c418dcad93755cf48537d60a46070112be72c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 24 Apr 2020 18:48:10 +0300 Subject: iwlwifi: remove antenna_coupling module parameter This module parameter should not be mangled by users. This relates to a very old driver and I doubt people can really check the antenna coupling in a way that would make the BT Coexistence work better with a real value. Drop it. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.6e566897ce0a.I8395a50c1c39522e542366064bff33a33009ce7b@changeid --- drivers/net/wireless/intel/iwlwifi/dvm/dev.h | 3 +-- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 9 +-------- drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 11 +---------- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 11 ++--------- drivers/net/wireless/intel/iwlwifi/iwl-modparams.h | 8 ++------ 5 files changed, 7 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 8d8380026180..4bd792c06ff6 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** * - * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2020 Intel Corporation. All rights reserved. * * Contact Information: * Intel Linux Wireless @@ -810,7 +810,6 @@ struct iwl_priv { u8 bt_traffic_load, last_bt_traffic_load; bool bt_ch_announce; bool bt_full_concurrent; - bool bt_ant_couple_ok; __le32 kill_ack_mask; __le32 kill_cts_mask; __le16 bt_valid; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 598ee7315558..99822744122f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright (C) 2018 - 2019 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -1370,12 +1369,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); - /* is antenna coupling more than 35dB ? */ - priv->bt_ant_couple_ok = - (iwlwifi_mod_params.antenna_coupling > - IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? - true : false; - /* bt channel inhibition enabled*/ priv->bt_ch_announce = true; IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n", diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index dac809df7f1d..4fa4eab2d7f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -2,6 +2,7 @@ /****************************************************************************** * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2019 - 2020 Intel Corporation * * Contact Information: * Intel Linux Wireless @@ -846,16 +847,6 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_scale_tbl_info *tbl; bool full_concurrent = priv->bt_full_concurrent; - if (priv->bt_ant_couple_ok) { - /* - * Is there a need to switch between - * full concurrency and 3-wire? - */ - if (priv->bt_ci_compliance) - full_concurrent = true; - else - full_concurrent = false; - } if ((priv->bt_traffic_load != priv->last_bt_traffic_load) || (priv->bt_full_concurrent != full_concurrent)) { priv->bt_full_concurrent = full_concurrent; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index a483d389d9c2..f3148e70f85c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014, 2018 - 2020 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014, 2018 - 2020 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 @@ -1824,11 +1822,6 @@ MODULE_PARM_DESC(amsdu_size, module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, 0444); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); -module_param_named(antenna_coupling, iwlwifi_mod_params.antenna_coupling, - int, 0444); -MODULE_PARM_DESC(antenna_coupling, - "specify antenna coupling in dB (default: 0 dB)"); - module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, 0444); MODULE_PARM_DESC(nvm_file, "NVM file name"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h index b094cc1e9be0..e8ce3a300857 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-modparams.h @@ -5,8 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2007 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * * 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,8 +25,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -111,7 +109,6 @@ enum iwl_uapsd_disable { * @power_save: enable power save, default = false * @power_level: power level, default = 1 * @debug_level: levels are IWL_DL_* - * @antenna_coupling: antenna coupling in dB, default = 0 * @nvm_file: specifies a external NVM file * @uapsd_disable: disable U-APSD, see &enum iwl_uapsd_disable, default = * IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT @@ -131,7 +128,6 @@ struct iwl_mod_params { #ifdef CONFIG_IWLWIFI_DEBUG u32 debug_level; #endif - int antenna_coupling; char *nvm_file; u32 uapsd_disable; bool disable_11ac; -- cgit From 0c9e025e797e02c35449b3ad08d3317e5fc7d7b8 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 18:48:11 +0300 Subject: iwlwifi: yoyo: don't access TLV before verifying len If we access the TLV memory with shorter len than the struct we access garbage data that was not given by the user. On the way rewrite the checker in a cleaner way. Signed-off-by: Mordechay Goodstein Fixes: a9248de42464 ("iwlwifi: dbg_ini: add TLV allocation new API support") Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.54418c829390.I15d6b462a0e69a280b6c6cfbcb6bcb05bb5f79ee@changeid --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 5 ++- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 44 +++++++++++----------- 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index b9d7ed93311c..74ac65bd545a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright (C) 2018 - 2019 Intel Corporation + * Copyright (C) 2018 - 2020 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 @@ -25,7 +25,7 @@ * * BSD LICENSE * - * Copyright (C) 2018 - 2019 Intel Corporation + * Copyright (C) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -304,6 +304,7 @@ enum iwl_fw_ini_buffer_location { IWL_FW_INI_LOCATION_SRAM_PATH, IWL_FW_INI_LOCATION_DRAM_PATH, IWL_FW_INI_LOCATION_NPK_PATH, + IWL_FW_INI_LOCATION_NUM, }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 9eb8fbfaa2a2..7987a288917b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -165,38 +165,36 @@ static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv) { struct iwl_fw_ini_allocation_tlv *alloc = (void *)tlv->data; - u32 buf_location = le32_to_cpu(alloc->buf_location); - u32 alloc_id = le32_to_cpu(alloc->alloc_id); + u32 buf_location; + u32 alloc_id; - if (le32_to_cpu(tlv->length) != sizeof(*alloc) || - (buf_location != IWL_FW_INI_LOCATION_SRAM_PATH && - buf_location != IWL_FW_INI_LOCATION_DRAM_PATH && - buf_location != IWL_FW_INI_LOCATION_NPK_PATH)) { - IWL_ERR(trans, - "WRT: Invalid allocation TLV\n"); + if (le32_to_cpu(tlv->length) != sizeof(*alloc)) return -EINVAL; - } - if ((buf_location == IWL_FW_INI_LOCATION_SRAM_PATH || - buf_location == IWL_FW_INI_LOCATION_NPK_PATH) && - alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) { - IWL_ERR(trans, - "WRT: Allocation TLV for SMEM/NPK path must have id %u (current: %u)\n", - IWL_FW_INI_ALLOCATION_ID_DBGC1, alloc_id); - return -EINVAL; - } + buf_location = le32_to_cpu(alloc->buf_location); + alloc_id = le32_to_cpu(alloc->alloc_id); + + if (buf_location == IWL_FW_INI_LOCATION_INVALID || + buf_location >= IWL_FW_INI_LOCATION_NUM) + goto err; if (alloc_id == IWL_FW_INI_ALLOCATION_INVALID || - alloc_id >= IWL_FW_INI_ALLOCATION_NUM) { - IWL_ERR(trans, - "WRT: Invalid allocation id %u for allocation TLV\n", - alloc_id); - return -EINVAL; - } + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + goto err; + + if ((buf_location == IWL_FW_INI_LOCATION_SRAM_PATH || + buf_location == IWL_FW_INI_LOCATION_NPK_PATH) && + alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) + goto err; trans->dbg.fw_mon_cfg[alloc_id] = *alloc; return 0; +err: + IWL_ERR(trans, + "WRT: Invalid allocation id %u and/or location id %u for allocation TLV\n", + alloc_id, buf_location); + return -EINVAL; } static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, -- cgit From f092e4e35b34fba55f2ad5b8d34d342755afa49a Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Fri, 24 Apr 2020 18:48:12 +0300 Subject: iwlwifi: mvm: add support for range request command version 9 This version adds support for per responder calibrations. Currently the driver will use a single value for all responders and bandwidths. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.5ce74a87009c.I9079332b21eef490bbdbf8d7d66e35d7d0c7882b@changeid --- .../net/wireless/intel/iwlwifi/fw/api/location.h | 110 +++++++++++++++++++-- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 67 ++++++++++--- 2 files changed, 155 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 0214e553d5ae..7ffad19d80fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -6,8 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2018 - 2020 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,8 +27,7 @@ * BSD LICENSE * * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 Intel Corporation - * Copyright (C) 2019 Intel Corporation + * Copyright (C) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -147,6 +145,7 @@ struct iwl_tof_config_cmd { * @IWL_TOF_BW_40: 40 MHz * @IWL_TOF_BW_80: 80 MHz * @IWL_TOF_BW_160: 160 MHz + * @IWL_TOF_BW_NUM: number of tof bandwidths */ enum iwl_tof_bandwidth { IWL_TOF_BW_20_LEGACY, @@ -154,6 +153,7 @@ enum iwl_tof_bandwidth { IWL_TOF_BW_40, IWL_TOF_BW_80, IWL_TOF_BW_160, + IWL_TOF_BW_NUM, }; /* LOCAT_BW_TYPE_E */ /* @@ -430,6 +430,9 @@ struct iwl_tof_range_req_ap_entry_v2 { * @IWL_INITIATOR_AP_FLAGS_NON_TB: Use non trigger based flow * @IWL_INITIATOR_AP_FLAGS_TB: Use trigger based flow * @IWL_INITIATOR_AP_FLAGS_SECURED: request secured measurement + * @IWL_INITIATOR_AP_FLAGS_LMR_FEEDBACK: Send LMR feedback + * @IWL_INITIATOR_AP_FLAGS_USE_CALIB: Use calibration values from the request + * instead of fw internal values. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -442,6 +445,8 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_NON_TB = BIT(9), IWL_INITIATOR_AP_FLAGS_TB = BIT(10), IWL_INITIATOR_AP_FLAGS_SECURED = BIT(11), + IWL_INITIATOR_AP_FLAGS_LMR_FEEDBACK = BIT(12), + IWL_INITIATOR_AP_FLAGS_USE_CALIB = BIT(13), }; /** @@ -508,7 +513,7 @@ enum iwl_location_bw { #define LOCATION_BW_POS 4 /** - * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * struct iwl_tof_range_req_ap_entry_v4 - AP configuration parameters * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. * @channel_num: AP Channel number * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. @@ -527,7 +532,7 @@ enum iwl_location_bw { * @hltk: HLTK to be used for secured 11az measurement * @tk: TK to be used for secured 11az measurement */ -struct iwl_tof_range_req_ap_entry { +struct iwl_tof_range_req_ap_entry_v4 { __le32 initiator_ap_flags; u8 channel_num; u8 format_bw; @@ -542,6 +547,65 @@ struct iwl_tof_range_req_ap_entry { u8 tk[TK_11AZ_LEN]; } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_4 */ +/** + * enum iwl_location_cipher - location cipher selection + * @IWL_LOCATION_CIPHER_CCMP_128: CCMP 128 + * @IWL_LOCATION_CIPHER_CCMP_256: CCMP 256 + * @IWL_LOCATION_CIPHER_GCMP_128: GCMP 128 + * @IWL_LOCATION_CIPHER_GCMP_256: GCMP 256 + */ +enum iwl_location_cipher { + IWL_LOCATION_CIPHER_CCMP_128, + IWL_LOCATION_CIPHER_CCMP_256, + IWL_LOCATION_CIPHER_GCMP_128, + IWL_LOCATION_CIPHER_GCMP_256, +}; + +/** + * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. + * @channel_num: AP Channel number + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @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 + * @cipher: pairwise cipher suite for secured measurement. + * &enum iwl_location_cipher. + * @hltk: HLTK to be used for secured 11az measurement + * @tk: TK to be used for secured 11az measurement + * @calib: An array of calibration values per FTM rx bandwidth. + * If &IWL_INITIATOR_AP_FLAGS_USE_CALIB is set, the fw will use the + * calibration value that corresponds to the rx bandwidth of the FTM + * frame. + * @reserved2: For alignment and future use. + */ +struct iwl_tof_range_req_ap_entry { + __le32 initiator_ap_flags; + u8 channel_num; + u8 format_bw; + u8 ctrl_ch_position; + u8 ftmr_max_retries; + u8 bssid[ETH_ALEN]; + __le16 burst_period; + u8 samples_per_burst; + u8 num_of_bursts; + u8 reserved; + u8 cipher; + u8 hltk[HLTK_11AZ_LEN]; + u8 tk[TK_11AZ_LEN]; + __le16 calib[IWL_TOF_BW_NUM]; + __le16 reserved2; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_5 */ + /** * enum iwl_tof_response_mode * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as @@ -676,7 +740,7 @@ struct iwl_tof_range_req_cmd_v7 { } __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_7 */ /** - * struct iwl_tof_range_req_cmd - start measurement cmd + * struct iwl_tof_range_req_cmd_v8 - 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 @@ -693,7 +757,7 @@ struct iwl_tof_range_req_cmd_v7 { * @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 { +struct iwl_tof_range_req_cmd_v8 { __le32 initiator_flags; u8 request_id; u8 num_of_ap; @@ -704,9 +768,37 @@ struct iwl_tof_range_req_cmd { __le32 tsf_mac_id; __le16 common_calib; __le16 specific_calib; - struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; + struct iwl_tof_range_req_ap_entry_v4 ap[IWL_MVM_TOF_MAX_APS]; } __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_8 */ +/** + * 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. + * @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; + struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_9 */ + /* * enum iwl_tof_range_request_status - status of the sent request * @IWL_TOF_RANGE_REQUEST_STATUS_SUCCESSFUL - FW successfully received the diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index cdb87139100d..aaa7dd1788b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -164,9 +164,10 @@ static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 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) +static void iwl_mvm_ftm_cmd_common(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_tof_range_req_cmd *cmd, + struct cfg80211_pmsr_request *req) { int i; @@ -210,6 +211,13 @@ static void iwl_mvm_ftm_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->tsf_mac_id = cpu_to_le32(0xff); } +static void iwl_mvm_ftm_cmd_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_tof_range_req_cmd_v8 *cmd, + struct cfg80211_pmsr_request *req) +{ + iwl_mvm_ftm_cmd_common(mvm, vif, (void *)cmd, req); +} + static int iwl_mvm_ftm_target_chandef_v1(struct iwl_mvm *mvm, struct cfg80211_pmsr_request_peer *peer, @@ -382,9 +390,10 @@ iwl_mvm_ftm_put_target_v3(struct iwl_mvm *mvm, return 0; } -static int iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm, - struct cfg80211_pmsr_request_peer *peer, - struct iwl_tof_range_req_ap_entry *target) +static int +iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v4 *target) { int ret; @@ -394,7 +403,7 @@ static int iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm, if (ret) return ret; - iwl_mvm_ftm_put_target_common(mvm, peer, target); + iwl_mvm_ftm_put_target_common(mvm, peer, (void *)target); return 0; } @@ -456,7 +465,7 @@ static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Versions 7 and 8 has the same structure except from the responders * list, so iwl_mvm_ftm_cmd() can be used for version 7 too. */ - iwl_mvm_ftm_cmd(mvm, vif, (void *)&cmd_v7, req); + iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd_v7, req); for (i = 0; i < cmd_v7.num_of_ap; i++) { struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; @@ -471,6 +480,32 @@ static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_req_cmd_v8 cmd; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0), + .dataflags[0] = IWL_HCMD_DFL_DUP, + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + u8 i; + int err; + + iwl_mvm_ftm_cmd_v8(mvm, vif, (void *)&cmd, req); + + for (i = 0; i < cmd.num_of_ap; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + + err = iwl_mvm_ftm_put_target(mvm, peer, &cmd.ap[i]); + if (err) + return err; + } + + return iwl_mvm_ftm_send_cmd(mvm, &hcmd); +} + +static int iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd cmd; struct iwl_host_cmd hcmd = { @@ -482,12 +517,12 @@ static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 i; int err; - iwl_mvm_ftm_cmd(mvm, vif, &cmd, req); + iwl_mvm_ftm_cmd_common(mvm, vif, &cmd, req); for (i = 0; i < cmd.num_of_ap; i++) { struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; - err = iwl_mvm_ftm_put_target_v4(mvm, peer, &cmd.ap[i]); + err = iwl_mvm_ftm_put_target(mvm, peer, (void *)&cmd.ap[i]); if (err) return err; } @@ -511,11 +546,17 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP, TOF_RANGE_REQ_CMD); - if (cmd_ver == 8) + switch (cmd_ver) { + case 9: + err = iwl_mvm_ftm_start_v9(mvm, vif, req); + break; + case 8: err = iwl_mvm_ftm_start_v8(mvm, vif, req); - else + break; + default: err = iwl_mvm_ftm_start_v7(mvm, vif, req); - + break; + } } else { err = iwl_mvm_ftm_start_v5(mvm, vif, req); } -- cgit From f4bfdc5e571ef5107112a7f1daa6a9c572e4a798 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 24 Apr 2020 18:48:13 +0300 Subject: iwlwifi: mvm: stop supporting swcrypto and bt_coex_active module parameters Leave them active for iwldvm. We do not test this configuration and there is no reason nowadays to allow this. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.674a325b008b.Ifc925ca84500fb76c7b6f926a24a34ca777b4192@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 7 ++-- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 31 +++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 42 ++++++++++------------- 3 files changed, 33 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 3d2abbc5c76c..5ae22cd7ecdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014, 2018 - 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * @@ -216,8 +216,7 @@ int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm) goto send_cmd; } - mode = iwlwifi_mod_params.bt_coex_active ? BT_COEX_NW : BT_COEX_DISABLE; - bt_cmd.mode = cpu_to_le32(mode); + bt_cmd.mode = cpu_to_le32(BT_COEX_NW); if (IWL_MVM_BT_COEX_SYNC2SCO) bt_cmd.enabled_modules |= diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 222775714859..89096bcb053e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -80,9 +78,6 @@ void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (iwlwifi_mod_params.swcrypto) - return; - mutex_lock(&mvm->mutex); memcpy(mvmvif->rekey_data.kek, data->kek, NL80211_KEK_LEN); @@ -843,18 +838,16 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - if (!iwlwifi_mod_params.swcrypto) { - /* - * This needs to be unlocked due to lock ordering - * constraints. Since we're in the suspend path - * that isn't really a problem though. - */ - mutex_unlock(&mvm->mutex); - ret = iwl_mvm_wowlan_config_key_params(mvm, vif, CMD_ASYNC); - mutex_lock(&mvm->mutex); - if (ret) - return ret; - } + /* + * This needs to be unlocked due to lock ordering + * constraints. Since we're in the suspend path + * that isn't really a problem though. + */ + mutex_unlock(&mvm->mutex); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif, CMD_ASYNC); + mutex_lock(&mvm->mutex); + if (ret) + return ret; ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, sizeof(*wowlan_config_cmd), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 853ba7b8bf3f..ee3d2ff432f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -475,23 +475,23 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->n_cipher_suites++; } - /* Enable 11w if software crypto is not enabled (as the - * firmware will interpret some mgmt packets, so enabling it - * with software crypto isn't safe). - */ - if (!iwlwifi_mod_params.swcrypto) { - ieee80211_hw_set(hw, MFP_CAPABLE); + if (iwlwifi_mod_params.swcrypto) + IWL_ERR(mvm, + "iwlmvm doesn't allow to disable HW crypto, check swcrypto module parameter\n"); + if (!iwlwifi_mod_params.bt_coex_active) + IWL_ERR(mvm, + "iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n"); + + ieee80211_hw_set(hw, MFP_CAPABLE); + mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC; + hw->wiphy->n_cipher_suites++; + if (iwl_mvm_has_new_rx_api(mvm)) { mvm->ciphers[hw->wiphy->n_cipher_suites] = - WLAN_CIPHER_SUITE_AES_CMAC; + WLAN_CIPHER_SUITE_BIP_GMAC_128; + hw->wiphy->n_cipher_suites++; + mvm->ciphers[hw->wiphy->n_cipher_suites] = + WLAN_CIPHER_SUITE_BIP_GMAC_256; hw->wiphy->n_cipher_suites++; - if (iwl_mvm_has_new_rx_api(mvm)) { - mvm->ciphers[hw->wiphy->n_cipher_suites] = - WLAN_CIPHER_SUITE_BIP_GMAC_128; - hw->wiphy->n_cipher_suites++; - mvm->ciphers[hw->wiphy->n_cipher_suites] = - WLAN_CIPHER_SUITE_BIP_GMAC_256; - hw->wiphy->n_cipher_suites++; - } } /* currently FW API supports only one optional cipher scheme */ @@ -697,10 +697,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) WIPHY_WOWLAN_EAP_IDENTITY_REQ | WIPHY_WOWLAN_RFKILL_RELEASE | WIPHY_WOWLAN_NET_DETECT; - if (!iwlwifi_mod_params.swcrypto) - mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | - WIPHY_WOWLAN_GTK_REKEY_FAILURE | - WIPHY_WOWLAN_4WAY_HANDSHAKE; + mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_4WAY_HANDSHAKE; mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS; mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN; @@ -3366,11 +3365,6 @@ static int __iwl_mvm_mac_set_key(struct ieee80211_hw *hw, int ret, i; u8 key_offset; - if (iwlwifi_mod_params.swcrypto) { - IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n"); - return -EOPNOTSUPP; - } - switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: if (!mvm->trans->trans_cfg->gen2) { -- cgit From 9617040ecab4810363ccab81aac1de3725675c9b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 24 Apr 2020 18:48:14 +0300 Subject: iwlwifi: mvm: remove iwlmvm's tfd_q_hang_detect module parameter This should be controlled by the firmware debugging mechanism and not by a module parameter. This has always been true. Remove it and assume it is set. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.b6e4982e62ae.I7f7352f79c40ada2f221bd4b41449a40821e833f@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 ++------ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 11 ++--------- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 16 ++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 9 +++------ 4 files changed, 13 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 9e2a0858108c..e2f7f6ec711e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -134,12 +132,10 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; * We will register to mac80211 to have testmode working. The NIC must not * be up'ed after the INIT fw asserted. This is useful to be able to use * proprietary tools over testmode to debug the INIT fw. - * @tfd_q_hang_detect: enabled the detection of hung transmit queues * @power_scheme: one of enum iwl_power_scheme */ struct iwl_mvm_mod_params { bool init_dbg; - bool tfd_q_hang_detect; int power_scheme; }; extern struct iwl_mvm_mod_params iwlmvm_mod_params; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index d0afc806706d..bde1b9b5face 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 @@ -94,7 +92,6 @@ static const struct iwl_op_mode_ops iwl_mvm_ops_mq; struct iwl_mvm_mod_params iwlmvm_mod_params = { .power_scheme = IWL_POWER_SCHEME_BPS, - .tfd_q_hang_detect = true /* rest of fields are 0 by default */ }; @@ -104,10 +101,6 @@ MODULE_PARM_DESC(init_dbg, module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, 0444); MODULE_PARM_DESC(power_scheme, "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); -module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect, - bool, 0444); -MODULE_PARM_DESC(tfd_q_hang_detect, - "TFD queues hang detection (default: true"); /* * module init and exit functions diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 56ae72debb96..ca5dcd7643e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2015, 2018 - 2020 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 @@ -28,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2015, 2018 - 2020 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 @@ -1965,9 +1963,8 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue, u8 sta_id, u8 fifo) { - unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? - mvm->trans->trans_cfg->base_params->wd_timeout : - IWL_WATCHDOG_DISABLED; + unsigned int wdg_timeout = + mvm->trans->trans_cfg->base_params->wd_timeout; struct iwl_trans_txq_scd_cfg cfg = { .fifo = fifo, .sta_id = sta_id, @@ -1983,9 +1980,8 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue, static int iwl_mvm_enable_aux_snif_queue_tvqm(struct iwl_mvm *mvm, u8 sta_id) { - unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? - mvm->trans->trans_cfg->base_params->wd_timeout : - IWL_WATCHDOG_DISABLED; + unsigned int wdg_timeout = + mvm->trans->trans_cfg->base_params->wd_timeout; WARN_ON(!iwl_mvm_has_new_tx_api(mvm)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 6096276cb0d0..ee8f152e7606 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 * * 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,10 +27,9 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014, 2018 - 2020 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 * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -952,8 +950,7 @@ unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF) && vif && vif->type == NL80211_IFTYPE_AP) return IWL_WATCHDOG_DISABLED; - return iwlmvm_mod_params.tfd_q_hang_detect ? - default_timeout : IWL_WATCHDOG_DISABLED; + return default_timeout; } trigger = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TXQ_TIMERS); -- cgit From a65a5824298b06049dbaceb8a9bd19709dc9507c Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 18:48:15 +0300 Subject: iwlwifi: avoid debug max amsdu config overwriting itself If we set amsdu_len one after another the second one overwrites the orig_amsdu_len so allow only moving from debug to non debug state. Also the TLC update check was wrong: it was checking that also the orig is smaller then the new updated size, which is not the case in debug amsdu mode. Signed-off-by: Mordechay Goodstein Fixes: af2984e9e625 ("iwlwifi: mvm: add a debugfs entry to set a fixed size AMSDU for all TX packets") Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.e565446a4fce.I9729d8c520d8b8bb4de9a5cdc62e01eb85168aac@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 11 +++++++---- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 3beef8d077b8..8fae7e707374 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * 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 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 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,10 +27,9 @@ * * BSD LICENSE * - * 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 - 2019 Intel Corporation + * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -481,6 +479,11 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta, if (kstrtou16(buf, 0, &amsdu_len)) return -EINVAL; + /* only change from debug set <-> debug unset */ + if ((amsdu_len && mvmsta->orig_amsdu_len) || + (!!amsdu_len && mvmsta->orig_amsdu_len)) + return -EBUSY; + if (amsdu_len) { mvmsta->orig_amsdu_len = sta->max_amsdu_len; sta->max_amsdu_len = amsdu_len; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 15d11fb72aca..6f4d241d47e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -369,14 +369,15 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, u16 size = le32_to_cpu(notif->amsdu_size); int i; - /* - * 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)) + if (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 + */ + WARN_ON(mvmsta->orig_amsdu_len < size); goto out; + } mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); mvmsta->max_amsdu_len = size; -- cgit From 73f23d91cfa32c087b7289f2516efa186b2e982c Mon Sep 17 00:00:00 2001 From: Shaul Triebitz Date: Fri, 24 Apr 2020 18:48:16 +0300 Subject: iwlwifi: mvm: set properly station flags in STA_HE_CTXT_CMD For ACK_ENABLED and 32BIT_BA_BITMAP flags check the station capabilities rather than bss_conf.ack_enabled and bss_conf.multi_sta_back_32bit. These fields are stations capabilities and should not be in bss_conf. Also note that the bss_conf flags are set in station mode only. In the next patch I will remove ack_enabled and multi_sta_back_32bit from the bss_conf structure. Signed-off-by: Shaul Triebitz Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.bc7230b74f93.I144f73cd6a797a7060429981fee62572861bc76b@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ee3d2ff432f7..10df77ab1a77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2179,6 +2179,15 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, flags |= STA_CTXT_HE_PACKET_EXT; } } + + if (sta->he_cap.he_cap_elem.mac_cap_info[2] & + IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP) + flags |= STA_CTXT_HE_32BIT_BA_BITMAP; + + if (sta->he_cap.he_cap_elem.mac_cap_info[2] & + IEEE80211_HE_MAC_CAP2_ACK_EN) + flags |= STA_CTXT_HE_ACK_ENABLED; + rcu_read_unlock(); /* Mark MU EDCA as enabled, unless none detected on some AC */ @@ -2203,11 +2212,6 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, cpu_to_le16(mu_edca->mu_edca_timer); } - if (vif->bss_conf.multi_sta_back_32bit) - flags |= STA_CTXT_HE_32BIT_BA_BITMAP; - - if (vif->bss_conf.ack_enabled) - flags |= STA_CTXT_HE_ACK_ENABLED; if (vif->bss_conf.uora_exists) { flags |= STA_CTXT_HE_TRIG_RND_ALLOC; -- cgit From 89cb1ddee1a9f26ee2c1a60e768dfd0e8e705b0a Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 18:48:17 +0300 Subject: iwlwifi: yoyo: add D3 resume timepoint This timepoint is used for getting a clean log (if needed) after resume without any commands/interrupts from the driver to the FW. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.7cd450812977.Ibc9ddd6eae6af5ce499ac1e4f6c01853577d1e83@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 89096bcb053e..2a94545d737f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1986,6 +1986,9 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) goto err; } + iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_END, + NULL); + ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image); if (ret) goto err; -- cgit From 45baf306b0a14bba59c1529add2ba7f8df48082e Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 18:48:18 +0300 Subject: iwlwifi: bump FW API to 55 for AX devices Start supporting API version 55 for AX devices. We skipped 54 because it won't be published. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424182644.5b4628e18203.I626d3b19d84214a83cd92dc4ddf291903b0983aa@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 2f741f5e3a7d..2fbe0aa3e548 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-2019 Intel Corporation + * Copyright (C) 2018-2020 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-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,7 +57,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 53 +#define IWL_22000_UCODE_API_MAX 55 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 -- cgit From 2abe24f9e15b2ccce471dd1996debdae6c84e64b Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Fri, 24 Apr 2020 19:46:57 +0300 Subject: iwlwifi: dbg: set debug descriptor to NULL outside of iwl_fw_free_dump_desc To avoid static analysis warning and to make the flow more readable, set the debug descriptor to NULL outside iwl_fw_free_dump_desc and only in the required places. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.5d5c50750a52.I17e33fc268c2097b7c42877f86cef2aa163b913a@changeid --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 37c8b6cc2ec7..4df10f3d99d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2198,12 +2198,11 @@ static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, } static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt, - const struct iwl_fw_dump_desc **desc) + const struct iwl_fw_dump_desc *desc) { - if (desc && *desc != &iwl_dump_desc_assert) - kfree(*desc); + if (desc && desc != &iwl_dump_desc_assert) + kfree(desc); - *desc = NULL; fwrt->dump.lmac_err_id[0] = 0; if (fwrt->smem_cfg.num_lmacs > 1) fwrt->dump.lmac_err_id[1] = 0; @@ -2315,7 +2314,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, unsigned long idx; if (iwl_trans_dbg_ini_valid(fwrt->trans)) { - iwl_fw_free_dump_desc(fwrt, &desc); + iwl_fw_free_dump_desc(fwrt, desc); return 0; } @@ -2336,7 +2335,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, wk_data = &fwrt->dump.wks[idx]; if (WARN_ON(wk_data->dump_data.desc)) - iwl_fw_free_dump_desc(fwrt, &wk_data->dump_data.desc); + iwl_fw_free_dump_desc(fwrt, wk_data->dump_data.desc); wk_data->dump_data.desc = desc; wk_data->dump_data.monitor_only = monitor_only; @@ -2593,10 +2592,12 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, false); out: - if (iwl_trans_dbg_ini_valid(fwrt->trans)) + if (iwl_trans_dbg_ini_valid(fwrt->trans)) { iwl_fw_error_dump_data_free(dump_data); - else - iwl_fw_free_dump_desc(fwrt, &dump_data->desc); + } else { + iwl_fw_free_dump_desc(fwrt, dump_data->desc); + dump_data->desc = NULL; + } clear_bit(wk_idx, &fwrt->dump.active_wks); } -- cgit From 71e9378bcfd2e9dd96c2bfbef23f3562946d30b3 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:46:58 +0300 Subject: iwlwifi: mvm: initialize iwl_dev_tx_power_cmd to zero If the REDUCE_TX_POWER_CMD version is v4 or v5, we are not initializing some values before sending to the FW, which causes SAR not to work properly. Solve this by initializing the struct in the declaration. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.0dc957a264ff.I43cfd72d539c1287ccaaa454e95c673dac38214f@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 164fc9e98c86..60246a8eed50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -787,13 +787,12 @@ 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; - + } cmd = { + .v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), + }; int ret; u16 len = 0; - cmd.v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS); - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_REDUCE_TX_POWER)) len = sizeof(cmd.v5); -- cgit From 0960237d2fa39eae376580690c2d6bc6bd0a1d07 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 19:46:59 +0300 Subject: iwlwifi: yoyo: remove magic number The for loop is iterating over active regions so iterate only over the len of the active regions buffer size. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.e10482b9eed7.I15da7bb25d9b9e3eef1c1b117dc585e703ce756a@changeid --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 4df10f3d99d2..04de7688884d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2119,7 +2119,11 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, u32 size = 0; u64 regions_mask = le64_to_cpu(trigger->regions_mask); - for (i = 0; i < 64; i++) { + BUILD_BUG_ON(sizeof(trigger->regions_mask) != sizeof(regions_mask)); + BUILD_BUG_ON((sizeof(trigger->regions_mask) * BITS_PER_BYTE) < + ARRAY_SIZE(fwrt->trans->dbg.active_regions)); + + for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.active_regions); i++) { u32 reg_type; struct iwl_fw_ini_region_tlv *reg; -- cgit From a8eb340f2ea48280eb2b7dc5a0e6cfff4928f5a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 24 Apr 2020 19:47:00 +0300 Subject: iwlwifi: move iwl_set_soc_latency to iwl-drv to be used by other op_modes All the op_mode need to send this command as well. Instead of duplicating the code from mvm, put the code in a common place. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.7f30f977f9bf.I060b51d0d66d09b9d1ee512e7de8f2d695a52152@changeid --- drivers/net/wireless/intel/iwlwifi/fw/init.c | 55 ++++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 46 +-------------------- 3 files changed, 55 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index ba00d162ce72..b373606e1241 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2019 Intel Corporation + * Copyright(c) 2019 - 2020 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) 2019 Intel Corporation + * Copyright(c) 2019 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,6 +62,9 @@ #include "dbg.h" #include "debugfs.h" +#include "fw/api/soc.h" +#include "fw/api/commands.h" + void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, const struct iwl_fw *fw, const struct iwl_fw_runtime_ops *ops, void *ops_ctx, @@ -95,3 +98,51 @@ void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt) iwl_fw_resume_timestamp(fwrt); } IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume); + +/* set device type and latency */ +int iwl_set_soc_latency(struct iwl_fw_runtime *fwrt) +{ + struct iwl_soc_configuration_cmd cmd = {}; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(SOC_CONFIGURATION_CMD, SYSTEM_GROUP, 0), + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + int ret; + + /* + * In VER_1 of this command, the discrete value is considered + * an integer; In VER_2, it's a bitmask. Since we have only 2 + * values in VER_1, this is backwards-compatible with VER_2, + * as long as we don't set any other bits. + */ + if (!fwrt->trans->trans_cfg->integrated) + cmd.flags = cpu_to_le32(SOC_CONFIG_CMD_FLAGS_DISCRETE); + + BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_NONE != + SOC_FLAGS_LTR_APPLY_DELAY_NONE); + BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_200US != + SOC_FLAGS_LTR_APPLY_DELAY_200); + BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_2500US != + SOC_FLAGS_LTR_APPLY_DELAY_2500); + BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_1820US != + SOC_FLAGS_LTR_APPLY_DELAY_1820); + + if (fwrt->trans->trans_cfg->ltr_delay != IWL_CFG_TRANS_LTR_DELAY_NONE && + !WARN_ON(!fwrt->trans->trans_cfg->integrated)) + cmd.flags |= le32_encode_bits(fwrt->trans->trans_cfg->ltr_delay, + SOC_FLAGS_LTR_APPLY_DELAY_MASK); + + if (iwl_fw_lookup_cmd_ver(fwrt->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC) >= 2 && + fwrt->trans->trans_cfg->low_latency_xtal) + cmd.flags |= cpu_to_le32(SOC_CONFIG_CMD_FLAGS_LOW_LATENCY); + + cmd.latency = cpu_to_le32(fwrt->trans->trans_cfg->xtal_latency); + + ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); + if (ret) + IWL_ERR(fwrt, "Failed to set soc latency: %d\n", ret); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_set_soc_latency); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 9629ef94b214..b5e5e32b6152 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -242,5 +242,6 @@ int iwl_init_paging(struct iwl_fw_runtime *fwrt, enum iwl_ucode_type type); void iwl_free_fw_paging(struct iwl_fw_runtime *fwrt); void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt); +int iwl_set_soc_latency(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_runtime_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 60246a8eed50..5e8d3f8c3d86 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -87,50 +87,6 @@ struct iwl_mvm_alive_data { u32 scd_base_addr; }; -/* set device type and latency */ -static int iwl_set_soc_latency(struct iwl_mvm *mvm) -{ - struct iwl_soc_configuration_cmd cmd = {}; - int ret; - - /* - * In VER_1 of this command, the discrete value is considered - * an integer; In VER_2, it's a bitmask. Since we have only 2 - * values in VER_1, this is backwards-compatible with VER_2, - * as long as we don't set any other bits. - */ - if (!mvm->trans->trans_cfg->integrated) - cmd.flags = cpu_to_le32(SOC_CONFIG_CMD_FLAGS_DISCRETE); - - BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_NONE != - SOC_FLAGS_LTR_APPLY_DELAY_NONE); - BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_200US != - SOC_FLAGS_LTR_APPLY_DELAY_200); - BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_2500US != - SOC_FLAGS_LTR_APPLY_DELAY_2500); - BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_1820US != - SOC_FLAGS_LTR_APPLY_DELAY_1820); - - if (mvm->trans->trans_cfg->ltr_delay != IWL_CFG_TRANS_LTR_DELAY_NONE && - !WARN_ON(!mvm->trans->trans_cfg->integrated)) - cmd.flags |= le32_encode_bits(mvm->trans->trans_cfg->ltr_delay, - SOC_FLAGS_LTR_APPLY_DELAY_MASK); - - if (iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, - SCAN_REQ_UMAC) >= 2 && - mvm->trans->trans_cfg->low_latency_xtal) - cmd.flags |= cpu_to_le32(SOC_CONFIG_CMD_FLAGS_LOW_LATENCY); - - cmd.latency = cpu_to_le32(mvm->trans->trans_cfg->xtal_latency); - - ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SOC_CONFIGURATION_CMD, - SYSTEM_GROUP, 0), 0, - sizeof(cmd), &cmd); - if (ret) - IWL_ERR(mvm, "Failed to set soc latency: %d\n", ret); - return ret; -} - static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) { struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { @@ -1237,7 +1193,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) { - ret = iwl_set_soc_latency(mvm); + ret = iwl_set_soc_latency(&mvm->fwrt); if (ret) goto error; } -- cgit From 37dee1f18eefd727a2f186ea16c6d76c802d8541 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:01 +0300 Subject: iwlwifi: mvm: add IML/ROM information to the assertion dumps Dump the IML/ROM error code and data, which are read from some registers, when printing an assertion dump. This makes it easier to debug IML/ROM errors. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.a522161a7372.I2a65ee35a5e0242f8a0e106f126356dff81ef59d@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index ee8f152e7606..be57b8391850 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -586,6 +586,23 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num) IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); } +static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm) +{ + struct iwl_trans *trans = mvm->trans; + u32 error; + + error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); + + IWL_ERR(trans, "IML/ROM dump:\n"); + + if (error & 0xFFFF0000) + IWL_ERR(trans, "IML/ROM SYSASSERT:\n"); + + IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error); + IWL_ERR(mvm, "0x%08X | IML/ROM data1\n", + iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS)); +} + void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) { if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { @@ -601,6 +618,9 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) iwl_mvm_dump_umac_error_log(mvm); + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + iwl_mvm_dump_iml_error_log(mvm); + iwl_fw_error_print_fseq_regs(&mvm->fwrt); } -- cgit From 53abad420b7e106232fdc93208e438570f4aa908 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:02 +0300 Subject: iwlwifi: pcie: remove outdated comment about PCI RTPM reference This comment was only related to the PCI RTPM implementation, which has been removed a while ago, and is not meaningless. Remove it. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.f362e4560a3b.I8d858c6c9a6c98b45d2195dfe28dabe0286c8a83@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 2083eb4f2f15..5c216fa6505c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * 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 + * Copyright(c) 2007 - 2014, 2018 - 2020 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,11 +27,10 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2005 - 2014, 2018 - 2020 Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1162,12 +1160,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* register transport layer debugfs here */ iwl_trans_pcie_dbgfs_register(iwl_trans); - /* The PCI device starts with a reference taken and we are - * supposed to release it here. But to simplify the - * interaction with the opmode, we don't do it now, but let - * the opmode release it when it's ready. - */ - return 0; out_free_trans: -- cgit From ebe7b061e9293968181bbe60a3e261681358c50f Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:03 +0300 Subject: iwlwifi: pcie: remove mangling for iwl_ax101_cfg_qu_hr All devices that use iwl_ax101_cfg_qu_hr are recognized via the device info table, so the cfg will never be iwl_ax101_cfg_qu_hr. Remove the code that converts this into QuZ and Qu-C, since it's not needed anymore. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.30b6b4aae1c1.If5e583835c9f7f2771a50ba1b2f33bb85f25b383@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 5c216fa6505c..4146526b1278 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1062,29 +1062,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF4)) { iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0; } - } else if (cfg == &iwl_ax101_cfg_qu_hr) { - if ((CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && - iwl_trans->hw_rev == CSR_HW_REV_TYPE_QNJ_B0) || - (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR1))) { - iwl_trans->cfg = &iwl22000_2ax_cfg_qnj_hr_b0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR) && - iwl_trans->hw_rev == CSR_HW_REV_TYPE_QUZ) { - iwl_trans->cfg = &iwl_ax101_cfg_quz_hr; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR)) { - iwl_trans->cfg = &iwl_ax101_cfg_qu_hr; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HRCDB)) { - IWL_ERR(iwl_trans, "RF ID HRCDB is not supported\n"); - return -EINVAL; - } else { - IWL_ERR(iwl_trans, "Unrecognized RF ID 0x%08x\n", - CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id)); - return -EINVAL; - } } /* -- cgit From d5727b60a18edb2e762a95fbf445b1ce3ff41e25 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:04 +0300 Subject: iwlwifi: pcie: convert QnJ with Hr to the device table Convert all the occurrences of QnJ with Hr into a single entry in the PCI device table. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.21283ca79d82.I57a493c679a56fff11417afdaec76617711ff6a9@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 14 +++++++------- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 24 +++++------------------- 3 files changed, 14 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 2fbe0aa3e548..c88394849c86 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -77,7 +77,7 @@ #define IWL_22000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" #define IWL_22000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" #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_QNJ_B_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-" #define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0-" #define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" #define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0-" @@ -99,8 +99,8 @@ IWL_22000_JF_FW_PRE __stringify(api) ".ucode" #define IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(api) \ 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_QNJ_B_HR_B_MODULE_FIRMWARE(api) \ + IWL_QNJ_B_HR_B_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_QUZ_A_JF_B_MODULE_FIRMWARE(api) \ @@ -343,6 +343,7 @@ const struct iwl_cfg_trans_params iwl_ax200_trans_cfg = { }; const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; +const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; @@ -520,9 +521,8 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwl22000_2ax_cfg_qnj_hr_b0 = { - .name = "Intel(R) Dual Band Wireless AX 22000", - .fw_name_pre = IWL_22000_HR_B_FW_PRE, +const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg = { + .fw_name_pre = IWL_QNJ_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -609,7 +609,7 @@ const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { 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_B_QNJ_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_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)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 3a9a33851793..91ec41e0d427 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -535,6 +535,7 @@ extern const char iwl9260_killer_1550_name[]; extern const char iwl9560_killer_1550i_name[]; extern const char iwl9560_killer_1550s_name[]; extern const char iwl_ax200_name[]; +extern const char iwl_ax201_name[]; extern const char iwl_ax200_killer_1650w_name[]; extern const char iwl_ax200_killer_1650x_name[]; @@ -625,8 +626,7 @@ extern const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0; extern const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0; extern const struct iwl_cfg killer1650x_2ax_cfg; extern const struct iwl_cfg killer1650w_2ax_cfg; -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 iwl_qnj_b0_hr_b0_cfg; 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 iwlax211_2ax_cfg_so_gf_a0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 4146526b1278..d5f437ac3c43 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -590,7 +590,10 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x2723, 0x1654, iwl_ax200_cfg_cc, iwl_ax200_killer_1650x_name), IWL_DEV_INFO(0x2723, IWL_CFG_ANY, iwl_ax200_cfg_cc, iwl_ax200_name), -/* Qu with Hr */ + /* QnJ with Hr */ + IWL_DEV_INFO(0x2720, IWL_CFG_ANY, iwl_qnj_b0_hr_b0_cfg, iwl_ax201_name), + + /* Qu with Hr */ IWL_DEV_INFO(0x43F0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), @@ -675,23 +678,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x4DF0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x2720, 0x0000, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0040, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0044, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0070, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0074, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0078, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x007C, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0244, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0310, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x0A10, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x1080, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x1651, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x1652, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x2074, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x4070, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - IWL_DEV_INFO(0x2720, 0x4244, iwl22000_2ax_cfg_qnj_hr_b0, NULL), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, @@ -789,7 +775,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_NO_160, IWL_CFG_CORES_BT, iwl9260_2ac_cfg, iwl9260_name), - /* Qu with Jf */ +/* Qu with Jf */ /* Qu B step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, -- cgit From e34aa5abfcf56502b79a4fdbe5fd9e94f70aa279 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:05 +0300 Subject: iwlwifi: pcie: remove occurrences of 22000 in the FW name defines We don't use the number 22000 for our devices anymore, so remove all occurrences of it in the FW name macros. While at it, add IWL_QU_B_HR_B to the list of firmwares used by the driver, which was missing. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.93cc41bdbb4d.Ib7599901888a2d050f851bd878a875f593f2e8e5@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 72 ++++++++++++-------------- 1 file changed, 32 insertions(+), 40 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index c88394849c86..b9d13e38f12b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -73,10 +73,7 @@ #define IWL_22000_SMEM_OFFSET 0x400000 #define IWL_22000_SMEM_LEN 0xD0000 -#define IWL_22000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" -#define IWL_22000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" -#define IWL_22000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" -#define IWL_22000_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" +#define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" #define IWL_QNJ_B_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-" #define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0-" #define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" @@ -85,20 +82,16 @@ #define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-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_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" +#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-" +#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0-" +#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" +#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" +#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" #define IWL_SNJ_A_GF4_A_FW_PRE "iwlwifi-SoSnj-a0-gf4-a0-" #define IWL_SNJ_A_GF_A_FW_PRE "iwlwifi-SoSnj-a0-gf-a0-" -#define IWL_22000_HR_MODULE_FIRMWARE(api) \ - IWL_22000_HR_FW_PRE __stringify(api) ".ucode" -#define IWL_22000_JF_MODULE_FIRMWARE(api) \ - IWL_22000_JF_FW_PRE __stringify(api) ".ucode" -#define IWL_22000_QU_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_22000_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ + IWL_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QNJ_B_HR_B_MODULE_FIRMWARE(api) \ IWL_QNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ @@ -113,14 +106,14 @@ 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" +#define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SO_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_TY_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" #define IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(api) \ IWL_SNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" #define IWL_SNJ_A_GF_A_MODULE_FIRMWARE(api) \ @@ -352,7 +345,7 @@ const char iwl_ax200_killer_1650x_name[] = 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, + .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -366,7 +359,7 @@ const struct iwl_cfg iwl_ax101_cfg_qu_hr = { const struct iwl_cfg iwl_ax201_cfg_qu_hr = { .name = "Intel(R) Wi-Fi 6 AX201 160MHz", - .fw_name_pre = IWL_22000_QU_B_HR_B_FW_PRE, + .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -471,7 +464,7 @@ const struct iwl_cfg iwl_ax200_cfg_cc = { 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, + .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -484,7 +477,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { 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, + .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* * This device doesn't support receiving BlockAck with a large bitmap @@ -535,21 +528,21 @@ const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg = { 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, + .fw_name_pre = IWL_SO_A_JF_B_FW_PRE, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_NON_HE, }; const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_22000_SO_A_HR_B_FW_PRE, + .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { .name = "Intel(R) Wi-Fi 6 AX211 160MHz", - .fw_name_pre = IWL_22000_SO_A_GF_A_FW_PRE, + .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, @@ -557,7 +550,7 @@ const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long = { .name = "Intel(R) Wi-Fi 6 AX211 160MHz", - .fw_name_pre = IWL_22000_SO_A_GF_A_FW_PRE, + .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, @@ -567,7 +560,7 @@ const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long = { const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_22000_TY_A_GF_A_FW_PRE, + .fw_name_pre = IWL_TY_A_GF_A_FW_PRE, .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, @@ -575,7 +568,7 @@ const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = { .name = "Intel(R) Wi-Fi 6 AX411 160MHz", - .fw_name_pre = IWL_22000_SO_A_GF4_A_FW_PRE, + .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, @@ -583,7 +576,7 @@ const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = { const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { .name = "Intel(R) Wi-Fi 6 AX411 160MHz", - .fw_name_pre = IWL_22000_SO_A_GF4_A_FW_PRE, + .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, @@ -607,8 +600,7 @@ const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; -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_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); @@ -616,9 +608,9 @@ MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QUZ_A_JF_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)); +MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_TY_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -- cgit From 3f910a25839b13436bf0a22186f1698b23eafb91 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Apr 2020 19:47:06 +0300 Subject: iwlwifi: pcie: convert all AX101 devices to the device tables Convert all Qu/Hr1 devices to the new device tables, by modifying the corresponding structures, adding a new name and generalizing the device recognition. Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.ec0e04102d2c.Ia36f2c7bbf06cb6436424d40d6adb2376f2962ee@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 10 ++--- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 11 ++++-- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 52 ++++++++++++------------- 3 files changed, 37 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index b9d13e38f12b..1fcc346ba425 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -337,14 +337,14 @@ const struct iwl_cfg_trans_params iwl_ax200_trans_cfg = { const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; +const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; const char iwl_ax200_killer_1650x_name[] = "Killer(R) Wi-Fi 6 AX1650x 160MHz Wireless Network Adapter (200NGW)"; -const struct iwl_cfg iwl_ax101_cfg_qu_hr = { - .name = "Intel(R) Wi-Fi 6 AX101", +const struct iwl_cfg iwl_qu_b0_hr1_b0 = { .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -370,8 +370,7 @@ const struct iwl_cfg iwl_ax201_cfg_qu_hr = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0 = { - .name = "Intel(R) Wi-Fi 6 AX101", +const struct iwl_cfg iwl_qu_c0_hr1_b0 = { .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -397,8 +396,7 @@ const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0 = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwl_ax101_cfg_quz_hr = { - .name = "Intel(R) Wi-Fi 6 AX101", +const struct iwl_cfg iwl_quz_a0_hr1_b0 = { .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, IWL_DEVICE_22500, /* diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 91ec41e0d427..244899f3f3bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -477,12 +477,16 @@ struct iwl_cfg { #define IWL_CFG_RF_TYPE_TH1 0x108 #define IWL_CFG_RF_TYPE_JF2 0x105 #define IWL_CFG_RF_TYPE_JF1 0x108 +#define IWL_CFG_RF_TYPE_HR2 0x10A +#define IWL_CFG_RF_TYPE_HR1 0x10C #define IWL_CFG_RF_ID_TH 0x1 #define IWL_CFG_RF_ID_TH1 0x1 #define IWL_CFG_RF_ID_JF 0x3 #define IWL_CFG_RF_ID_JF1 0x6 #define IWL_CFG_RF_ID_JF1_DIV 0xA +#define IWL_CFG_RF_ID_HR 0x7 +#define IWL_CFG_RF_ID_HR1 0x4 #define IWL_CFG_NO_160 0x0 #define IWL_CFG_160 0x1 @@ -536,6 +540,7 @@ extern const char iwl9560_killer_1550i_name[]; extern const char iwl9560_killer_1550s_name[]; extern const char iwl_ax200_name[]; extern const char iwl_ax201_name[]; +extern const char iwl_ax101_name[]; extern const char iwl_ax200_killer_1650w_name[]; extern const char iwl_ax200_killer_1650x_name[]; @@ -610,9 +615,9 @@ extern const struct iwl_cfg iwl9560_qu_c0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_quz_a0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_qnj_b0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; -extern const struct iwl_cfg iwl_ax101_cfg_qu_hr; -extern const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0; -extern const struct iwl_cfg iwl_ax101_cfg_quz_hr; +extern const struct iwl_cfg iwl_qu_b0_hr1_b0; +extern const struct iwl_cfg iwl_qu_c0_hr1_b0; +extern const struct iwl_cfg iwl_quz_a0_hr1_b0; extern const struct iwl_cfg iwl_ax200_cfg_cc; extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d5f437ac3c43..f179cd08b418 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -594,89 +594,68 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x2720, IWL_CFG_ANY, iwl_qnj_b0_hr_b0_cfg, iwl_ax201_name), /* Qu with Hr */ - IWL_DEV_INFO(0x43F0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x43F0, 0x0244, iwl_ax101_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x43F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), - IWL_DEV_INFO(0x43F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x43F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x43F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x43F0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), - IWL_DEV_INFO(0xA0F0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0xA0F0, 0x0244, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x0A10, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0xA0F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0xA0F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0xA0F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0xA0F0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0078, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x007C, iwl_ax201_cfg_quz_hr, NULL), - IWL_DEV_INFO(0x02F0, 0x0244, iwl_ax101_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x0310, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x1651, iwl_ax1650s_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x1652, iwl_ax1650i_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x2074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x02F0, 0x4070, iwl_ax201_cfg_quz_hr, NULL), - IWL_DEV_INFO(0x02F0, 0x4244, iwl_ax101_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0070, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0078, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x007C, iwl_ax201_cfg_quz_hr, NULL), - IWL_DEV_INFO(0x06F0, 0x0244, iwl_ax101_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x0310, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x1651, iwl_ax1650s_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x1652, iwl_ax1650i_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x2074, iwl_ax201_cfg_quz_hr, NULL), IWL_DEV_INFO(0x06F0, 0x4070, iwl_ax201_cfg_quz_hr, NULL), - IWL_DEV_INFO(0x06F0, 0x4244, iwl_ax101_cfg_quz_hr, NULL), - IWL_DEV_INFO(0x34F0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x34F0, 0x0244, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x34F0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x34F0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x34F0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x34F0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x3DF0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x3DF0, 0x0244, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x3DF0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x3DF0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x3DF0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x3DF0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x4DF0, 0x0044, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0070, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0078, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x007C, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x4DF0, 0x0244, iwl_ax101_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x0310, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x1651, killer1650s_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x4DF0, 0x1652, killer1650i_2ax_cfg_qu_b0_hr_b0, NULL), IWL_DEV_INFO(0x4DF0, 0x2074, iwl_ax201_cfg_qu_hr, NULL), IWL_DEV_INFO(0x4DF0, 0x4070, iwl_ax201_cfg_qu_hr, NULL), - IWL_DEV_INFO(0x4DF0, 0x4244, iwl_ax101_cfg_qu_hr, NULL), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, @@ -951,6 +930,29 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_NO_160, IWL_CFG_CORES_BT, iwl9560_qnj_b0_jf_b0_cfg, iwl9560_killer_1550i_name), + +/* Qu with Hr */ + /* Qu B step */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, + IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, + iwl_qu_b0_hr1_b0, iwl_ax101_name), + + /* Qu C step */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, + IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, + iwl_qu_c0_hr1_b0, iwl_ax101_name), + + /* QuZ */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, + iwl_quz_a0_hr1_b0, iwl_ax101_name), + #endif /* CONFIG_IWLMVM */ }; @@ -1057,9 +1059,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * rest must be removed once we convert Qu with Hr as well. */ if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QU_C0) { - if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr) - iwl_trans->cfg = &iwl_ax101_cfg_qu_c0_hr_b0; - else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr) + if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr) iwl_trans->cfg = &iwl_ax201_cfg_qu_c0_hr_b0; else if (iwl_trans->cfg == &killer1650s_2ax_cfg_qu_b0_hr_b0) iwl_trans->cfg = &killer1650s_2ax_cfg_qu_c0_hr_b0; @@ -1069,9 +1069,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* same thing for QuZ... */ if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QUZ) { - if (iwl_trans->cfg == &iwl_ax101_cfg_qu_hr) - iwl_trans->cfg = &iwl_ax101_cfg_quz_hr; - else if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr) + if (iwl_trans->cfg == &iwl_ax201_cfg_qu_hr) iwl_trans->cfg = &iwl_ax201_cfg_quz_hr; } -- cgit From 36dfe9ac6e8b8fc2e25733d003a867a40db791da Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 24 Apr 2020 19:47:07 +0300 Subject: iwlwifi: dump api version in yaml format Used for debugging what FW API we are using to understand misalignment with API changes. The output looks like this as a yaml format fw_api_ver: 0x0001: name: MVM_ALIVE cmd_ver: 99 notif_ver: 4 0x0108: name: PHY_CONTEXT_CMD cmd_ver: 2 notif_ver: 0 ... Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200424194456.18bf540ab8e0.I6217488f1740f0e6accd0cecd09dfd46bad88426@changeid --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 104 +++++++++++++++++++++++- 1 file changed, 100 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 89f74116569d..6e72c27f527b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -5,10 +5,9 @@ * * GPL LICENSE SUMMARY * - * 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) 2012 - 2014, 2018 - 2020 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,10 +27,9 @@ * * BSD LICENSE * - * 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) 2012 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,6 +62,7 @@ #include "api/commands.h" #include "debugfs.h" #include "dbg.h" +#include #define FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype) \ struct dbgfs_##name##_data { \ @@ -329,11 +328,108 @@ static ssize_t iwl_dbgfs_fw_dbg_domain_read(struct iwl_fw_runtime *fwrt, FWRT_DEBUGFS_READ_FILE_OPS(fw_dbg_domain, 20); +struct iwl_dbgfs_fw_info_priv { + struct iwl_fw_runtime *fwrt; +}; + +struct iwl_dbgfs_fw_info_state { + loff_t pos; +}; + +static void *iwl_dbgfs_fw_info_seq_next(struct seq_file *seq, + void *v, loff_t *pos) +{ + struct iwl_dbgfs_fw_info_state *state = v; + struct iwl_dbgfs_fw_info_priv *priv = seq->private; + const struct iwl_fw *fw = priv->fwrt->fw; + + *pos = ++state->pos; + if (*pos >= fw->ucode_capa.n_cmd_versions) + return NULL; + + return state; +} + +static void iwl_dbgfs_fw_info_seq_stop(struct seq_file *seq, + void *v) +{ + kfree(v); +} + +static void *iwl_dbgfs_fw_info_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct iwl_dbgfs_fw_info_priv *priv = seq->private; + const struct iwl_fw *fw = priv->fwrt->fw; + struct iwl_dbgfs_fw_info_state *state; + + if (*pos >= fw->ucode_capa.n_cmd_versions) + return NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + state->pos = *pos; + return state; +}; + +static int iwl_dbgfs_fw_info_seq_show(struct seq_file *seq, void *v) +{ + struct iwl_dbgfs_fw_info_state *state = v; + struct iwl_dbgfs_fw_info_priv *priv = seq->private; + const struct iwl_fw *fw = priv->fwrt->fw; + const struct iwl_fw_cmd_version *ver; + u32 cmd_id; + + if (!state->pos) + seq_puts(seq, "fw_api_ver:\n"); + + ver = &fw->ucode_capa.cmd_versions[state->pos]; + + cmd_id = iwl_cmd_id(ver->cmd, ver->group, 0); + + seq_printf(seq, " 0x%04x:\n", cmd_id); + seq_printf(seq, " name: %s\n", + iwl_get_cmd_string(priv->fwrt->trans, cmd_id)); + seq_printf(seq, " cmd_ver: %d\n", ver->cmd_ver); + seq_printf(seq, " notif_ver: %d\n", ver->notif_ver); + return 0; +} + +static const struct seq_operations iwl_dbgfs_info_seq_ops = { + .start = iwl_dbgfs_fw_info_seq_start, + .next = iwl_dbgfs_fw_info_seq_next, + .stop = iwl_dbgfs_fw_info_seq_stop, + .show = iwl_dbgfs_fw_info_seq_show, +}; + +static int iwl_dbgfs_fw_info_open(struct inode *inode, struct file *filp) +{ + struct iwl_dbgfs_fw_info_priv *priv; + + priv = __seq_open_private(filp, &iwl_dbgfs_info_seq_ops, + sizeof(*priv)); + + if (!priv) + return -ENOMEM; + + priv->fwrt = inode->i_private; + return 0; +} + +static const struct file_operations iwl_dbgfs_fw_info_ops = { + .owner = THIS_MODULE, + .open = iwl_dbgfs_fw_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + 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(fw_info, dbgfs_dir, 0200); FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200); FWRT_DEBUGFS_ADD_FILE(fw_dbg_domain, dbgfs_dir, 0400); } -- cgit From 752d95a2bf6fe207d612fc1febd621df714f5dde Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:49 +0300 Subject: iwlwifi: pcie: allocate much smaller byte-count table The hardware needs a byte-count table with the size of each frame on the queue to build A-MPDUs, but: * newer generation no longer have the duplicated space at the end, they can deal with the wrap properly - and we don't even fill the dup anyway * we have a maximum queue size of 512 right now and don't use the theoretical hardware maximum of 65536. Together, this reduces the byte count table DMA allocation from 64KiB (65536*2 + 64*2 rounded up) to 1 KiB (though that might be rounded up to a full 4 KiB page by the allocator, not sure it can share the allocations.) Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.c263b787b5ab.I059507a9760b1ce1d45d84dcaa91629a5cfb58e0@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 7 +++---- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 24 +++++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index bf673ce5f183..a8e988281eaf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -7,7 +7,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 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) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -646,8 +646,7 @@ struct iwl_rb_status { #define TFD_QUEUE_CB_SIZE(x) (ilog2(x) - 3) #define TFD_QUEUE_SIZE_BC_DUP (64) #define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) -#define TFD_QUEUE_BC_SIZE_GEN3 (TFD_QUEUE_SIZE_MAX_GEN3 + \ - TFD_QUEUE_SIZE_BC_DUP) +#define TFD_QUEUE_BC_SIZE_GEN3 512 #define IWL_TX_DMA_MASK DMA_BIT_MASK(36) #define IWL_NUM_OF_TBS 20 #define IWL_TFH_NUM_TBS 25 diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 53747ac945b8..84df12ff131a 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 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 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 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1272,17 +1272,25 @@ int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, struct iwl_txq **intxq, int size, unsigned int timeout) { + size_t bc_tbl_size, bc_tbl_entries; + struct iwl_txq *txq; int ret; - struct iwl_txq *txq; + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + bc_tbl_size = sizeof(struct iwl_gen3_bc_tbl); + bc_tbl_entries = bc_tbl_size / sizeof(u16); + } else { + bc_tbl_size = sizeof(struct iwlagn_scd_bc_tbl); + bc_tbl_entries = bc_tbl_size / sizeof(u16); + } + + if (WARN_ON(size > bc_tbl_entries)) + return -EINVAL; + txq = kzalloc(sizeof(*txq), GFP_KERNEL); if (!txq) return -ENOMEM; - ret = iwl_pcie_alloc_dma_ptr(trans, &txq->bc_tbl, - (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_AX210) ? - sizeof(struct iwl_gen3_bc_tbl) : - sizeof(struct iwlagn_scd_bc_tbl)); + ret = iwl_pcie_alloc_dma_ptr(trans, &txq->bc_tbl, bc_tbl_size); if (ret) { IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); kfree(txq); -- cgit From 92f78d4b15a40f6b055be73bbecc2e79b10638f0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:50 +0300 Subject: iwlwifi: mvm: attempt to allocate smaller queues We currently attempt to allocate queues that are 512 entries long, but that requires 32 KiB memory, which may not be available, at least not contiguously. If we fail to allocate, attempt to use a smaller queue all the way down to 16 entries (which fit into a single page). Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.c8548d7cc08a.I5059c410e628726cbce98d6311b690c632d00f97@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ca5dcd7643e0..b36aef1d61b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -749,16 +749,23 @@ static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, 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), - sta_id, tid, SCD_QUEUE_CFG, size, timeout); - if (queue < 0) { - IWL_DEBUG_TX_QUEUES(mvm, - "Failed allocating TXQ for sta %d tid %d, ret: %d\n", - sta_id, tid, queue); + do { + __le16 enable = cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE); + + queue = iwl_trans_txq_alloc(mvm->trans, enable, + sta_id, tid, SCD_QUEUE_CFG, + size, timeout); + + if (queue < 0) + IWL_DEBUG_TX_QUEUES(mvm, + "Failed allocating TXQ of size %d for sta %d tid %d, ret: %d\n", + size, sta_id, tid, queue); + size /= 2; + } while (queue < 0 && size >= 16); + + if (queue < 0) return queue; - } IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n", queue, sta_id, tid); -- cgit From 281277b206f03f8e66e6d5c151d75ac9c15e066d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:51 +0300 Subject: iwlwifi: dbg: mark a variable __maybe_unused If CONFIG_IWLWIFI_DEBUGFS is not set, the variable is assigned but not checked, resulting in a compiler warning. Suppress it, we need the variable for the debugfs-enabled case. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.485f886f5a6c.I8a91c560c26cced33b15d8419caebb53a9abcc2d@changeid --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 04de7688884d..2a271aad8106 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2760,7 +2760,7 @@ void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_params *params, bool stop) { - int ret = 0; + int ret __maybe_unused = 0; if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) return; -- cgit From a8e82c36081e574c0c7bdc1b407a697465777069 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:52 +0300 Subject: iwlwifi: pcie: remove some dead code We can never get into this code with a gen2/3 device, and therefore don't need to allocate the byte count tables in a single contiguous DMA region. Just WARN and bail out if something is misconfigured. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.a748d33252ef.If2f5810016efb40b041f93fe8c6b4c251542e2f1@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 4582d418ba4d..9ff78bca460b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -8,7 +8,7 @@ * 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 + * Copyright(c) 2018 - 2020 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) 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 + * Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -954,10 +954,10 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u16 bc_tbls_size = trans->trans_cfg->base_params->num_of_queues; - bc_tbls_size *= (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_AX210) ? - sizeof(struct iwl_gen3_bc_tbl) : - sizeof(struct iwlagn_scd_bc_tbl); + if (WARN_ON(trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)) + return -EINVAL; + + bc_tbls_size *= sizeof(struct iwlagn_scd_bc_tbl); /*It is not allowed to alloc twice, so warn when this happens. * We cannot rely on the previous allocation, so free and fail */ -- cgit From c239feec5038585d8ba622ecc97322e0e2f3398c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:53 +0300 Subject: iwlwifi: pcie: gen2: use DMA pool for byte-count tables Since the recent patch in this area, we no longer allocate 64k for a single queue, but only 1k, which still means a full page. Use a DMA pool to reduce this further, since we will have a lot of queues in a typical system that can share pages. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.6e84c79aea30.Ie9a417132812d110ec1cc87852f101477c01cfcb@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 1 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 19 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 11 ++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index abe649af689c..43f81204c152 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -556,6 +556,7 @@ struct iwl_trans_pcie { u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; struct iwl_dma_ptr kw; + struct dma_pool *bc_pool; struct iwl_txq *txq_memory; struct iwl_txq *txq[IWL_MAX_TVQM_QUEUES]; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index a0daae058c1c..8ccfc7cc7348 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3672,6 +3672,25 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, init_waitqueue_head(&trans_pcie->sx_waitq); + /* + * For gen2 devices, we use a single allocation for each byte-count + * table, but they're pretty small (1k) so use a DMA pool that we + * allocate here. + */ + if (cfg_trans->gen2) { + size_t bc_tbl_size; + + if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_AX210) + bc_tbl_size = sizeof(struct iwl_gen3_bc_tbl); + else + bc_tbl_size = sizeof(struct iwlagn_scd_bc_tbl); + + trans_pcie->bc_pool = dmam_pool_create("iwlwifi:bc", &pdev->dev, + bc_tbl_size, 256, 0); + if (!trans_pcie->bc_pool) + goto out_no_pci; + } + if (trans_pcie->msix_enabled) { ret = iwl_pcie_init_msix_handler(pdev, trans_pcie); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 84df12ff131a..bb55563bba68 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1224,7 +1224,9 @@ void iwl_pcie_gen2_txq_free_memory(struct iwl_trans *trans, } kfree(txq->entries); - iwl_pcie_free_dma_ptr(trans, &txq->bc_tbl); + if (txq->bc_tbl.addr) + dma_pool_free(trans_pcie->bc_pool, txq->bc_tbl.addr, + txq->bc_tbl.dma); kfree(txq); } @@ -1272,6 +1274,7 @@ int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, struct iwl_txq **intxq, int size, unsigned int timeout) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); size_t bc_tbl_size, bc_tbl_entries; struct iwl_txq *txq; int ret; @@ -1290,8 +1293,10 @@ int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, txq = kzalloc(sizeof(*txq), GFP_KERNEL); if (!txq) return -ENOMEM; - ret = iwl_pcie_alloc_dma_ptr(trans, &txq->bc_tbl, bc_tbl_size); - if (ret) { + + txq->bc_tbl.addr = dma_pool_alloc(trans_pcie->bc_pool, GFP_KERNEL, + &txq->bc_tbl.dma); + if (!txq->bc_tbl.addr) { IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); kfree(txq); return -ENOMEM; -- cgit From 3da1a4e3287094887397c083d1549b2d067fa1ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:54 +0300 Subject: iwlwifi: use longer queues for 256-BA When we have 256 block-ack support, we may need to be very fast to provide a lot of frames to the hardware to transmit, but that cannot be guaranteed. Use a longer queue size to have more time, and the next possible queue size is 1024 since it must be a power of two. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.851866c7e4c4.I13fa678929431f1694fd202c1da40aa476ab70fe@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 1fcc346ba425..1daa653bcb99 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -211,7 +211,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .trans.base_params = &iwl_ax210_base_params, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ - .min_256_ba_txq_size = 512, \ + .min_256_ba_txq_size = 1024, \ .mon_dram_regs = { \ .write_ptr = { \ .addr = DBGC_CUR_DBGBUF_STATUS, \ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index a8e988281eaf..e77d8d13cb51 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -646,7 +646,7 @@ struct iwl_rb_status { #define TFD_QUEUE_CB_SIZE(x) (ilog2(x) - 3) #define TFD_QUEUE_SIZE_BC_DUP (64) #define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) -#define TFD_QUEUE_BC_SIZE_GEN3 512 +#define TFD_QUEUE_BC_SIZE_GEN3 1024 #define IWL_TX_DMA_MASK DMA_BIT_MASK(36) #define IWL_NUM_OF_TBS 20 #define IWL_TFH_NUM_TBS 25 -- cgit From e88e2cd0b80f2dfa18f72cfb7a3b8ab3d8d59894 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sat, 25 Apr 2020 13:04:55 +0300 Subject: iwlwifi: tx: enable A-MSDU in low latency mode Tests have shown that we can meet low latency KPIs with A-MSDU enabled so enable it to achieve max TPT. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.e469ce6501e4.Ibdecebca830bdfbf5220693dd1f5367f7736242d@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index a8d0d17f79fd..2f6484e0d726 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 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 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 - 2019 Intel Corporation + * Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -920,11 +920,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * No need to lock amsdu_in_ampdu_allowed since it can't be modified * during an BA session. */ - if (info->flags & IEEE80211_TX_CTL_AMPDU && - !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) - return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - - if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(mvmsta->vif)) || + if ((info->flags & IEEE80211_TX_CTL_AMPDU && + !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) || !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); -- cgit From 3d1d87ab1a3a40c5fea3dde11d4532c4efd11093 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:56 +0300 Subject: iwlwifi: mvm: don't transmit on unallocated queue We can currently end up transmitting on an unallocated queue, if the allocation fails. Stop doing that, by simply not transmitting. We don't have any better strategy here, unfortunately, but the previous commits make that much less likely. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.dcf1801f25ef.I6d71e13ea042765800f2ee41401b8eb282527c34@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b36aef1d61b0..44d4720b7629 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1400,7 +1400,17 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) if (tid == IEEE80211_NUM_TIDS) tid = IWL_MAX_TID_COUNT; - iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid); + /* + * We can't really do much here, but if this fails we can't + * transmit anyway - so just don't transmit the frame etc. + * and let them back up ... we've tried our best to allocate + * a queue in the function itself. + */ + if (iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid)) { + list_del_init(&mvmtxq->list); + continue; + } + list_del_init(&mvmtxq->list); local_bh_disable(); iwl_mvm_mac_itxq_xmit(mvm->hw, txq); -- cgit From e9a7f025e72c919d7d05318acf887541266933b9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:57 +0300 Subject: iwlwifi: remove outdated copyright print/module statement Remove the outdated copyright, don't print it, and update the module author to actually be Intel, not Intel's copyright. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.dc86a4e9451a.Ice2e21b6427a4b57f953dba9ceb5b8b96b251a8c@changeid --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 3 +-- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 7 +++---- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 99822744122f..b882705ff66d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -52,7 +52,7 @@ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); /* Please keep this array *SORTED* by hex value. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index f3148e70f85c..04f14bfdd091 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -85,7 +85,7 @@ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1774,7 +1774,6 @@ static int __init iwl_drv_init(void) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); pr_info(DRV_DESCRIPTION "\n"); - pr_info(DRV_COPYRIGHT "\n"); #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the root of iwlwifi debugfs subsystem. */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 2be30af7bdc3..8938a6467996 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014, 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014, 2020 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * All rights reserved. * @@ -63,8 +63,7 @@ /* for all modules */ #define DRV_NAME "iwlwifi" -#define DRV_COPYRIGHT "Copyright(c) 2003- 2015 Intel Corporation" -#define DRV_AUTHOR "" +#define DRV_AUTHOR "Intel Corporation " /* radio config bits (actual values from NVM definition) */ #define NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index bde1b9b5face..d095ff847be9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -84,7 +84,7 @@ #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); +MODULE_AUTHOR(DRV_AUTHOR); MODULE_LICENSE("GPL"); static const struct iwl_op_mode_ops iwl_mvm_ops; -- cgit From b1c860f6ec73d993f0427e8d0d70c8f3d6625e6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 25 Apr 2020 13:04:58 +0300 Subject: iwlwifi: pcie: skip fragmented receive buffers We don't really expect fragmented RBs, and don't seem to be seeing them in practice since that would've caused a crash. Nevertheless, we should be expecting the hardware to send them. Parse the flag indicating a fragmented buffer, but then discard it and any fragments thereof, at least for now. We need to do more work in the higher layers to properly deal with this, since we may not get "normal" firmware notifications that are fragmented, only RX, and then we need to put it back together and add the necessary API to report a chain of things to the higher layers, this doesn't fit into the struct iwl_rx_cmd_buffer today. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.e78a59f70b1d.Ica656a98a4e4220d73edc97600edd680cbc97241@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 ++- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 32 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 43f81204c152..b76c0396335a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -189,6 +189,8 @@ struct iwl_rx_completion_desc { * @rb_stts_dma: bus address of receive buffer status * @lock: * @queue: actual rx queue. Not used for multi-rx queue. + * @next_rb_is_fragment: indicates that the previous RB that we handled set + * the fragmented flag, so the next one is still another fragment * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ @@ -214,7 +216,7 @@ struct iwl_rxq { u32 queue_size; struct list_head rx_free; struct list_head rx_used; - bool need_update; + bool need_update, next_rb_is_fragment; void *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 8c29071cb415..72d1cf27e6a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1427,7 +1427,8 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, } static struct iwl_rx_mem_buffer *iwl_pcie_get_rxb(struct iwl_trans *trans, - struct iwl_rxq *rxq, int i) + struct iwl_rxq *rxq, int i, + bool *join) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rx_mem_buffer *rxb; @@ -1441,10 +1442,12 @@ static struct iwl_rx_mem_buffer *iwl_pcie_get_rxb(struct iwl_trans *trans, return rxb; } - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { vid = le16_to_cpu(rxq->cd[i].rbid); - else + *join = rxq->cd[i].flags & IWL_RX_CD_FLAGS_FRAGMENTED; + } else { vid = le32_to_cpu(rxq->bd_32[i]) & 0x0FFF; /* 12-bit VID */ + } if (!vid || vid > RX_POOL_SIZE(trans_pcie->num_rx_bufs)) goto out_err; @@ -1502,6 +1505,7 @@ restart: u32 rb_pending_alloc = atomic_read(&trans_pcie->rba.req_pending) * RX_CLAIM_REQ_ALLOC; + bool join = false; if (unlikely(rb_pending_alloc >= rxq->queue_size / 2 && !emergency)) { @@ -1514,11 +1518,29 @@ restart: IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i); - rxb = iwl_pcie_get_rxb(trans, rxq, i); + rxb = iwl_pcie_get_rxb(trans, rxq, i, &join); if (!rxb) goto out; - iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency, i); + if (unlikely(join || rxq->next_rb_is_fragment)) { + rxq->next_rb_is_fragment = join; + /* + * We can only get a multi-RB in the following cases: + * - firmware issue, sending a too big notification + * - sniffer mode with a large A-MSDU + * - large MTU frames (>2k) + * since the multi-RB functionality is limited to newer + * hardware that cannot put multiple entries into a + * single RB. + * + * Right now, the higher layers aren't set up to deal + * with that, so discard all of these. + */ + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else { + iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency, i); + } i = (i + 1) & (rxq->queue_size - 1); -- cgit From d3d2674cc6ff10e89bfbace7b943c09fb9052cca Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sat, 25 Apr 2020 13:04:59 +0300 Subject: iwlwifi: dbg_ini: differentiate ax210 hw with same hw type There are several "flavors" of HW that have the same HW type, but can be told apart after reading a certain perph register. This is easy to do in runtime, but more complicated to do when looking at the logs offline. To make it easier to tell apart these "flavors" when looking at the dumped dbg info, add these bits to the HW type, allowing simple differentiation. Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/iwlwifi.20200425130140.330ea11d17ae.Ie59b25430a308090b15112ac6deedf4fbf487ff1@changeid --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 22 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 13 +++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 2a271aad8106..4d3687cc83a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1958,6 +1958,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_dump_cfg_name *cfg_name; u32 size = sizeof(*tlv) + sizeof(*dump); u32 num_of_cfg_names = 0; + u32 hw_type; list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { size += sizeof(*cfg_name); @@ -1986,7 +1987,26 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, dump->ver_subtype = cpu_to_le32(fwrt->dump.fw_ver.subtype); dump->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); - dump->hw_type = cpu_to_le32(CSR_HW_REV_TYPE(fwrt->trans->hw_rev)); + + /* + * Several HWs all have type == 0x42, so we'll override this value + * according to the detected HW + */ + hw_type = CSR_HW_REV_TYPE(fwrt->trans->hw_rev); + if (hw_type == IWL_AX210_HW_TYPE) { + u32 prph_val = iwl_read_prph(fwrt->trans, WFPM_OTP_CFG1_ADDR); + u32 is_jacket = !!(prph_val & WFPM_OTP_CFG1_IS_JACKET_BIT); + u32 is_cdb = !!(prph_val & WFPM_OTP_CFG1_IS_CDB_BIT); + u32 masked_bits = is_jacket | (is_cdb << 1); + + /* + * The HW type depends on certain bits in this case, so add + * these bits to the HW type. We won't have collisions since we + * add these bits after the highest possible bit in the mask. + */ + hw_type |= masked_bits << IWL_AX210_HW_TYPE_ADDITION_SHIFT; + } + dump->hw_type = cpu_to_le32(hw_type); dump->rf_id_flavor = cpu_to_le32(CSR_HW_RFID_FLAVOR(fwrt->trans->hw_rf_id)); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index f008e1bbfdf4..72bfc64580ab 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 - 2019 Intel Corporation + * Copyright (C) 2018 - 2020 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 - 2019 Intel Corporation + * Copyright (C) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -394,6 +394,15 @@ struct iwl_fw_ini_dump_cfg_name { u8 cfg_name[IWL_FW_INI_MAX_CFG_NAME]; } __packed; +/* AX210's HW type */ +#define IWL_AX210_HW_TYPE 0x42 +/* How many bits to roll when adding to the HW type of AX210 HW */ +#define IWL_AX210_HW_TYPE_ADDITION_SHIFT 12 +/* This prph is used to tell apart HW_TYPE == 0x42 NICs */ +#define WFPM_OTP_CFG1_ADDR 0xd03098 +#define WFPM_OTP_CFG1_IS_JACKET_BIT BIT(4) +#define WFPM_OTP_CFG1_IS_CDB_BIT BIT(5) + /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version * @time_point: time point that caused the dump collection -- cgit From 92072e5fb099136fc3ea8d7a44352c1d4230b8df Mon Sep 17 00:00:00 2001 From: Saravanan Shanmugham Date: Tue, 5 May 2020 01:51:26 -0500 Subject: brcmfmac: map 802.1d priority to precedence level based on AP WMM params In WLAN, priority among various access categories of traffic is always set by the AP using WMM parameters and this may not always follow the standard 802.1d priority. In this change, priority is adjusted based on the AP WMM params received as part of the Assoc Response and the same is later used to map the priority of all incoming traffic. In a specific scenario where EDCA parameters are configured to be same for all ACs, use the default FW priority definition to avoid queuing packets of all ACs to the same priority queue. This change fixes the following 802.11 certification tests: * 11n - 5.2.31 ACM Bit Conformance test * 11n - 5.2.32 AC Parameter Modification test * 11ac - 5.2.33 TXOP Limit test Signed-off-by: Saravanan Shanmugham Signed-off-by: Justin Li Signed-off-by: Madhan Mohan R Signed-off-by: Chi-hsien Lin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1588661487-21884-2-git-send-email-chi-hsien.lin@cypress.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 152 +++++++++++++++++++++ .../broadcom/brcm80211/brcmfmac/cfg80211.h | 24 ++++ .../wireless/broadcom/brcm80211/brcmfmac/common.h | 4 + .../broadcom/brcm80211/brcmfmac/fwsignal.c | 26 +--- .../broadcom/brcm80211/brcmfmac/fwsignal.h | 23 ++++ .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 17 +-- 6 files changed, 213 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index f2f84af923a9..537e5ae35ca0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -23,6 +23,7 @@ #include "p2p.h" #include "btcoex.h" #include "pno.h" +#include "fwsignal.h" #include "cfg80211.h" #include "feature.h" #include "fwil.h" @@ -5586,12 +5587,151 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) conn_info->resp_ie_len = 0; } +u8 brcmf_map_prio_to_prec(void *config, u8 prio) +{ + struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config; + + if (!cfg) + return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? + (prio ^ 2) : prio; + + /* For those AC(s) with ACM flag set to 1, convert its 4-level priority + * to an 8-level precedence which is the same as BE's + */ + if (prio > PRIO_8021D_EE && + cfg->ac_priority[prio] == cfg->ac_priority[PRIO_8021D_BE]) + return cfg->ac_priority[prio] * 2; + + /* Conversion of 4-level priority to 8-level precedence */ + if (prio == PRIO_8021D_BE || prio == PRIO_8021D_BK || + prio == PRIO_8021D_CL || prio == PRIO_8021D_VO) + return cfg->ac_priority[prio] * 2; + else + return cfg->ac_priority[prio] * 2 + 1; +} + +u8 brcmf_map_prio_to_aci(void *config, u8 prio) +{ + /* Prio here refers to the 802.1d priority in range of 0 to 7. + * ACI here refers to the WLAN AC Index in range of 0 to 3. + * This function will return ACI corresponding to input prio. + */ + struct brcmf_cfg80211_info *cfg = (struct brcmf_cfg80211_info *)config; + + if (cfg) + return cfg->ac_priority[prio]; + + return prio; +} + +static void brcmf_init_wmm_prio(u8 *priority) +{ + /* Initialize AC priority array to default + * 802.1d priority as per following table: + * 802.1d prio 0,3 maps to BE + * 802.1d prio 1,2 maps to BK + * 802.1d prio 4,5 maps to VI + * 802.1d prio 6,7 maps to VO + */ + priority[0] = BRCMF_FWS_FIFO_AC_BE; + priority[3] = BRCMF_FWS_FIFO_AC_BE; + priority[1] = BRCMF_FWS_FIFO_AC_BK; + priority[2] = BRCMF_FWS_FIFO_AC_BK; + priority[4] = BRCMF_FWS_FIFO_AC_VI; + priority[5] = BRCMF_FWS_FIFO_AC_VI; + priority[6] = BRCMF_FWS_FIFO_AC_VO; + priority[7] = BRCMF_FWS_FIFO_AC_VO; +} + +static void brcmf_wifi_prioritize_acparams(const + struct brcmf_cfg80211_edcf_acparam *acp, u8 *priority) +{ + u8 aci; + u8 aifsn; + u8 ecwmin; + u8 ecwmax; + u8 acm; + u8 ranking_basis[EDCF_AC_COUNT]; + u8 aci_prio[EDCF_AC_COUNT]; /* AC_BE, AC_BK, AC_VI, AC_VO */ + u8 index; + + for (aci = 0; aci < EDCF_AC_COUNT; aci++, acp++) { + aifsn = acp->ACI & EDCF_AIFSN_MASK; + acm = (acp->ACI & EDCF_ACM_MASK) ? 1 : 0; + ecwmin = acp->ECW & EDCF_ECWMIN_MASK; + ecwmax = (acp->ECW & EDCF_ECWMAX_MASK) >> EDCF_ECWMAX_SHIFT; + brcmf_dbg(CONN, "ACI %d aifsn %d acm %d ecwmin %d ecwmax %d\n", + aci, aifsn, acm, ecwmin, ecwmax); + /* Default AC_VO will be the lowest ranking value */ + ranking_basis[aci] = aifsn + ecwmin + ecwmax; + /* Initialise priority starting at 0 (AC_BE) */ + aci_prio[aci] = 0; + + /* If ACM is set, STA can't use this AC as per 802.11. + * Change the ranking to BE + */ + if (aci != AC_BE && aci != AC_BK && acm == 1) + ranking_basis[aci] = ranking_basis[AC_BE]; + } + + /* Ranking method which works for AC priority + * swapping when values for cwmin, cwmax and aifsn are varied + * Compare each aci_prio against each other aci_prio + */ + for (aci = 0; aci < EDCF_AC_COUNT; aci++) { + for (index = 0; index < EDCF_AC_COUNT; index++) { + if (index != aci) { + /* Smaller ranking value has higher priority, + * so increment priority for each ACI which has + * a higher ranking value + */ + if (ranking_basis[aci] < ranking_basis[index]) + aci_prio[aci]++; + } + } + } + + /* By now, aci_prio[] will be in range of 0 to 3. + * Use ACI prio to get the new priority value for + * each 802.1d traffic type, in this range. + */ + if (!(aci_prio[AC_BE] == aci_prio[AC_BK] && + aci_prio[AC_BK] == aci_prio[AC_VI] && + aci_prio[AC_VI] == aci_prio[AC_VO])) { + /* 802.1d 0,3 maps to BE */ + priority[0] = aci_prio[AC_BE]; + priority[3] = aci_prio[AC_BE]; + + /* 802.1d 1,2 maps to BK */ + priority[1] = aci_prio[AC_BK]; + priority[2] = aci_prio[AC_BK]; + + /* 802.1d 4,5 maps to VO */ + priority[4] = aci_prio[AC_VI]; + priority[5] = aci_prio[AC_VI]; + + /* 802.1d 6,7 maps to VO */ + priority[6] = aci_prio[AC_VO]; + priority[7] = aci_prio[AC_VO]; + } else { + /* Initialize to default priority */ + brcmf_init_wmm_prio(priority); + } + + brcmf_dbg(CONN, "Adj prio BE 0->%d, BK 1->%d, BK 2->%d, BE 3->%d\n", + priority[0], priority[1], priority[2], priority[3]); + + brcmf_dbg(CONN, "Adj prio VI 4->%d, VI 5->%d, VO 6->%d, VO 7->%d\n", + priority[4], priority[5], priority[6], priority[7]); +} + static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) { struct brcmf_pub *drvr = cfg->pub; struct brcmf_cfg80211_assoc_ielen_le *assoc_info; struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); + struct brcmf_cfg80211_edcf_acparam edcf_acparam_info[EDCF_AC_COUNT]; u32 req_len; u32 resp_len; s32 err = 0; @@ -5640,6 +5780,17 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, GFP_KERNEL); if (!conn_info->resp_ie) conn_info->resp_ie_len = 0; + + err = brcmf_fil_iovar_data_get(ifp, "wme_ac_sta", + edcf_acparam_info, + sizeof(edcf_acparam_info)); + if (err) { + brcmf_err("could not get wme_ac_sta (%d)\n", err); + return err; + } + + brcmf_wifi_prioritize_acparams(edcf_acparam_info, + cfg->ac_priority); } else { conn_info->resp_ie_len = 0; conn_info->resp_ie = NULL; @@ -6056,6 +6207,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) mutex_init(&cfg->usr_sync); brcmf_init_escan(cfg); brcmf_init_conf(cfg->conf); + brcmf_init_wmm_prio(cfg->ac_priority); init_completion(&cfg->vif_disabled); return err; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 3ca8c07d6370..333fdf394f95 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -23,6 +23,23 @@ #define WL_ROAM_TRIGGER_LEVEL -75 #define WL_ROAM_DELTA 20 +/* WME Access Category Indices (ACIs) */ +#define AC_BE 0 /* Best Effort */ +#define AC_BK 1 /* Background */ +#define AC_VI 2 /* Video */ +#define AC_VO 3 /* Voice */ +#define EDCF_AC_COUNT 4 +#define MAX_8021D_PRIO 8 + +#define EDCF_ACI_MASK 0x60 +#define EDCF_ACI_SHIFT 5 +#define EDCF_ACM_MASK 0x10 +#define EDCF_ECWMIN_MASK 0x0f +#define EDCF_ECWMAX_SHIFT 4 +#define EDCF_AIFSN_MASK 0x0f +#define EDCF_AIFSN_MAX 15 +#define EDCF_ECWMAX_MASK 0xf0 + /* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be * problematic on some systems and should be avoided. */ @@ -209,6 +226,12 @@ struct brcmf_cfg80211_assoc_ielen_le { __le32 resp_len; }; +struct brcmf_cfg80211_edcf_acparam { + u8 ACI; + u8 ECW; + u16 TXOP; /* stored in network order (ls octet first) */ +}; + /* dongle escan state */ enum wl_escan_state { WL_ESCAN_STATE_IDLE, @@ -327,6 +350,7 @@ struct brcmf_cfg80211_info { struct brcmf_assoclist_le assoclist; struct brcmf_cfg80211_wowl wowl; struct brcmf_pno_info *pno; + u8 ac_priority[MAX_8021D_PRIO]; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 144cf4570bc3..8b5f49997c8b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -72,4 +72,8 @@ static inline void brcmf_dmi_probe(struct brcmf_mp_device *settings, u32 chip, u32 chiprev) {} #endif +u8 brcmf_map_prio_to_prec(void *cfg, u8 prio); + +u8 brcmf_map_prio_to_aci(void *cfg, u8 prio); + #endif /* BRCMFMAC_COMMON_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 2b7837887c0b..09701262330d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -311,28 +311,6 @@ struct brcmf_skbuff_cb { /* How long to defer borrowing in jiffies */ #define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10) -/** - * enum brcmf_fws_fifo - fifo indices used by dongle firmware. - * - * @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background. - * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic. - * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic. - * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic. - * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic. - * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only). - * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only). - * @BRCMF_FWS_FIFO_COUNT: number of fifos. - */ -enum brcmf_fws_fifo { - BRCMF_FWS_FIFO_FIRST, - BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST, - BRCMF_FWS_FIFO_AC_BE, - BRCMF_FWS_FIFO_AC_VI, - BRCMF_FWS_FIFO_AC_VO, - BRCMF_FWS_FIFO_BCMC, - BRCMF_FWS_FIFO_ATIM, - BRCMF_FWS_FIFO_COUNT -}; /** * enum brcmf_fws_txstatus - txstatus flag values. @@ -2130,8 +2108,10 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) skcb->if_flags = 0; skcb->state = BRCMF_FWS_SKBSTATE_NEW; brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx); + + /* mapping from 802.1d priority to firmware fifo index */ if (!multicast) - fifo = brcmf_fws_prio2fifo[skb->priority]; + fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority); brcmf_fws_lock(fws); if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index b486d578ec96..b16a9d1c0508 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -6,6 +6,29 @@ #ifndef FWSIGNAL_H_ #define FWSIGNAL_H_ +/** + * enum brcmf_fws_fifo - fifo indices used by dongle firmware. + * + * @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background. + * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic. + * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic. + * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic. + * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic. + * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only). + * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only). + * @BRCMF_FWS_FIFO_COUNT: number of fifos. + */ +enum brcmf_fws_fifo { + BRCMF_FWS_FIFO_FIRST, + BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST, + BRCMF_FWS_FIFO_AC_BE, + BRCMF_FWS_FIFO_AC_VI, + BRCMF_FWS_FIFO_AC_VO, + BRCMF_FWS_FIFO_BCMC, + BRCMF_FWS_FIFO_ATIM, + BRCMF_FWS_FIFO_COUNT +}; + struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); void brcmf_fws_detach(struct brcmf_fws_info *fws); void brcmf_fws_debugfs_create(struct brcmf_pub *drvr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 3a08252f1a53..ce6f15284277 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -315,15 +315,6 @@ struct rte_console { #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US) #define BRCMF_SDIO_MAX_ACCESS_ERRORS 5 -/* - * Conversion of 802.1D priority to precedence level - */ -static uint prio2prec(u32 prio) -{ - return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? - (prio^2) : prio; -} - #ifdef DEBUG /* Device console log buffer state */ struct brcmf_console { @@ -2774,7 +2765,13 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt) skb_push(pkt, bus->tx_hdrlen); /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ - prec = prio2prec((pkt->priority & PRIOMASK)); + /* In WLAN, priority is always set by the AP using WMM parameters + * and this need not always follow the standard 802.1d priority. + * Based on AP WMM config, map from 802.1d priority to corresponding + * precedence level. + */ + prec = brcmf_map_prio_to_prec(bus_if->drvr->config, + (pkt->priority & PRIOMASK)); /* Check for existing queue, current flow-control, pending event, or pending clock */ -- cgit From f5da2a370f2f3885dff6d2d6815be75e60580784 Mon Sep 17 00:00:00 2001 From: Pramod Prakash Date: Tue, 5 May 2020 01:51:27 -0500 Subject: brcmfmac: fix 802.1d priority to ac mapping for pcie dongles 802.1d defines 0,3 for BE and 1,2 for BK. In pcie dongles, 0 & 3 are mapped to 0 and 1,2 are mapped to 1. This change corrects this mapping, so that BE & BK are given access precedence accordingly by pcie dongles. Signed-off-by: Pramod Prakash Signed-off-by: Chi-hsien Lin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1588661487-21884-3-git-send-email-chi-hsien.lin@cypress.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c index 8e9d067bdfed..096f6b969dd8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c @@ -26,10 +26,10 @@ #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) static const u8 brcmf_flowring_prio2fifo[] = { - 1, - 0, 0, 1, + 1, + 0, 2, 2, 3, -- cgit From b46f1546a708588700eb5adad0e69e944a7a000d Mon Sep 17 00:00:00 2001 From: Jia-Shyr Chuang Date: Wed, 6 May 2020 08:03:19 -0500 Subject: brcmfmac: set security after reiniting interface Host driver parses and sets security params into FW passed by supplicant. This has to be done after reiniting interface in the firmware. Signed-off-by: Jia-Shyr Chuang Signed-off-by: Chi-Hsien Lin Signed-off-by: Wright Feng Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1588770201-54361-2-git-send-email-wright.feng@cypress.com --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 90 ++++++++++++++-------- 1 file changed, 58 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 537e5ae35ca0..181f4df79866 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -4613,6 +4613,48 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, return err; } +static s32 +brcmf_parse_configure_security(struct brcmf_if *ifp, + struct cfg80211_ap_settings *settings, + enum nl80211_iftype dev_role) +{ + const struct brcmf_tlv *rsn_ie; + const struct brcmf_vs_tlv *wpa_ie; + s32 err = 0; + + /* find the RSN_IE */ + rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, + settings->beacon.tail_len, WLAN_EID_RSN); + + /* find the WPA_IE */ + wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, + settings->beacon.tail_len); + + if (wpa_ie || rsn_ie) { + brcmf_dbg(TRACE, "WPA(2) IE is found\n"); + if (wpa_ie) { + /* WPA IE */ + err = brcmf_configure_wpaie(ifp, wpa_ie, false); + if (err < 0) + return err; + } else { + struct brcmf_vs_tlv *tmp_ie; + + tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; + + /* RSN IE */ + err = brcmf_configure_wpaie(ifp, tmp_ie, true); + if (err < 0) + return err; + } + } else { + brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); + brcmf_configure_opensecurity(ifp); + } + + return err; +} + static s32 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *settings) @@ -4625,8 +4667,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, const struct brcmf_tlv *country_ie; struct brcmf_ssid_le ssid_le; s32 err = -EPERM; - const struct brcmf_tlv *rsn_ie; - const struct brcmf_vs_tlv *wpa_ie; struct brcmf_join_params join_params; enum nl80211_iftype dev_role; struct brcmf_fil_bss_enable_le bss_enable; @@ -4680,36 +4720,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, brcmf_configure_arp_nd_offload(ifp, false); } - /* find the RSN_IE */ - rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, - settings->beacon.tail_len, WLAN_EID_RSN); - - /* find the WPA_IE */ - wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail, - settings->beacon.tail_len); - - if ((wpa_ie != NULL || rsn_ie != NULL)) { - brcmf_dbg(TRACE, "WPA(2) IE is found\n"); - if (wpa_ie != NULL) { - /* WPA IE */ - err = brcmf_configure_wpaie(ifp, wpa_ie, false); - if (err < 0) - goto exit; - } else { - struct brcmf_vs_tlv *tmp_ie; - - tmp_ie = (struct brcmf_vs_tlv *)rsn_ie; - - /* RSN IE */ - err = brcmf_configure_wpaie(ifp, tmp_ie, true); - if (err < 0) - goto exit; - } - } else { - brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); - brcmf_configure_opensecurity(ifp); - } - /* Parameters shared by all radio interfaces */ if (!mbss) { if ((supports_11d) && (is_11d != ifp->vif->is_11d)) { @@ -4791,6 +4801,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "BRCMF_C_UP error (%d)\n", err); goto exit; } + + err = brcmf_parse_configure_security(ifp, settings, + NL80211_IFTYPE_AP); + if (err < 0) { + bphy_err(drvr, "brcmf_parse_configure_security error\n"); + goto exit; + } + /* On DOWN the firmware removes the WEP keys, reconfigure * them if they were set. */ @@ -4823,6 +4841,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, chanspec, err); goto exit; } + + err = brcmf_parse_configure_security(ifp, settings, + NL80211_IFTYPE_P2P_GO); + if (err < 0) { + brcmf_err("brcmf_parse_configure_security error\n"); + goto exit; + } + err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, sizeof(ssid_le)); if (err < 0) { -- cgit From 30fb1b2729099a3506222bbeff09a7ed6bca6fb0 Mon Sep 17 00:00:00 2001 From: Ryohei Kondo Date: Wed, 6 May 2020 08:03:20 -0500 Subject: brcmfmac: use actframe_abort to cancel ongoing action frame The driver sends an action frame down and waits for dwell time to be completed or aborted before sending out the next action frame. Driver issues "scan abort" to cancel the current time slot, but this doesn't have any effect because, we are not using scan engine for sending action frame. Fix is to use "actframe_abort" to cancels the current action frame. Signed-off-by: Ryohei Kondo Signed-off-by: Chi-Hsien Lin Signed-off-by: Wright Feng Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1588770201-54361-3-git-send-email-wright.feng@cypress.com --- .../net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 34 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index e32c24a2670d..cd5801e32488 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1267,6 +1267,30 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, return true; } +/** + * brcmf_p2p_abort_action_frame() - abort action frame. + * + * @cfg: common configuration struct. + * + */ +static s32 brcmf_p2p_abort_action_frame(struct brcmf_cfg80211_info *cfg) +{ + struct brcmf_p2p_info *p2p = &cfg->p2p; + struct brcmf_cfg80211_vif *vif; + s32 err; + s32 int_val = 1; + + brcmf_dbg(TRACE, "Enter\n"); + + vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; + err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe_abort", &int_val, + sizeof(s32)); + if (err) + brcmf_err(" aborting action frame has failed (%d)\n", err); + + return err; +} + /** * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete. * @@ -1278,6 +1302,7 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) { struct brcmf_p2p_info *p2p = &cfg->p2p; struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; + s32 err; if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || @@ -1286,8 +1311,13 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) /* if channel is not zero, "actfame" uses off channel scan. * So abort scan for off channel completion. */ - if (p2p->af_sent_channel) - brcmf_notify_escan_complete(cfg, ifp, true, true); + if (p2p->af_sent_channel) { + /* abort actframe using actframe_abort or abort scan */ + err = brcmf_p2p_abort_action_frame(cfg); + if (err) + brcmf_notify_escan_complete(cfg, ifp, true, + true); + } } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, &p2p->status)) { brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); -- cgit From 78db077db638b6b7679ebbadda7b19eef65a6720 Mon Sep 17 00:00:00 2001 From: Soontak Lee Date: Wed, 6 May 2020 08:03:21 -0500 Subject: brcmfmac: Use seq/seq_len and set iv_initialize when plumbing of rxiv in (GTK) keys When plumbing rxiv for (GTK) keys, current code does not use seq/seq_len when present nor set iv_initialized for iovar wsec_key. This could result in missing broadcast traffic after GTK rekey. The fix is setting iv_initialized and using seq/seq_len for iovar wsec_key. Signed-off-by: Soontak Lee Signed-off-by: Chi-Hsien Lin Signed-off-by: Wright Feng Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1588770201-54361-4-git-send-email-wright.feng@cypress.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 181f4df79866..579b9306f533 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2469,6 +2469,17 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (!ext_key) key->flags = BRCMF_PRIMARY_KEY; + if (params->seq && params->seq_len == 6) { + /* rx iv */ + u8 *ivptr; + + ivptr = (u8 *)params->seq; + key->rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key->rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key->iv_initialized = true; + } + switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: key->algo = CRYPTO_ALGO_WEP1; -- cgit From 7294ee6f564281bc805496648ec56fce203d8ee4 Mon Sep 17 00:00:00 2001 From: Chen Zhou Date: Fri, 8 May 2020 09:32:49 +0800 Subject: brcmfmac: make non-global functions static Fix sparse warning: drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c:2206:5: warning: symbol 'brcmf_p2p_get_conn_idx' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Chen Zhou Reviewed-by: Wright Feng Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200508013249.95196-1-chenzhou10@huawei.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index cd5801e32488..b0a41cf06c99 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2233,7 +2233,7 @@ fail: return ERR_PTR(err); } -int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg) +static int brcmf_p2p_get_conn_idx(struct brcmf_cfg80211_info *cfg) { int i; struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); -- cgit From 78a6fb42f67c567f80338a9eaec0090678dbd58e Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Fri, 8 May 2020 15:43:51 +0800 Subject: brcmfmac: remove Comparison to bool in brcmf_p2p_send_action_frame() Fix the following coccicheck warning: drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c:1785:5-8: WARNING: Comparison to bool Signed-off-by: Jason Yan Reviewed-by: Chi-hsien Lin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200508074351.19193-1-yanaijie@huawei.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index b0a41cf06c99..d2795dc17c46 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1866,7 +1866,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, dwell_overflow = brcmf_p2p_check_dwell_overflow(requested_dwell, dwell_jiffies); } - if (ack == false) { + if (!ack) { bphy_err(drvr, "Failed to send Action Frame(retry %d)\n", tx_retry); clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); -- cgit From f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 5 May 2020 18:52:05 -0500 Subject: rndis_wlan: Remove logically dead code caps_buf is always of size sizeof(*caps) because sizeof(caps->auth_encr_pair) * 16 is always zero. Notice that when using zero-length arrays, sizeof evaluates to zero[1]. So, the code introduced by commit 0308383f9591 ("rndis_wlan: get max_num_pmkids from device") is logically dead, hence is never executed and can be removed. As a consequence, the rest of the related code can be refactored a bit. Notice that this code has been out there since March 2010. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200505235205.GA18539@embeddedor Link: https://lore.kernel.org/r/20200507110741.37757-1-yanaijie@huawei.com --- drivers/net/wireless/rndis_wlan.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c8f8fe5497a8..78a4325bfe1b 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -312,17 +312,11 @@ struct ndis_80211_assoc_info { __le32 offset_resp_ies; } __packed; -struct ndis_80211_auth_encr_pair { - __le32 auth_mode; - __le32 encr_mode; -} __packed; - struct ndis_80211_capability { __le32 length; __le32 version; __le32 num_pmkids; __le32 num_auth_encr_pair; - struct ndis_80211_auth_encr_pair auth_encr_pair[0]; } __packed; struct ndis_80211_bssid_info { @@ -3109,8 +3103,7 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) __le32 num_items; __le32 items[8]; } networks_supported; - struct ndis_80211_capability *caps; - u8 caps_buf[sizeof(*caps) + sizeof(caps->auth_encr_pair) * 16]; + struct ndis_80211_capability caps; int len, retval, i, n; struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); @@ -3140,19 +3133,18 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy) } /* get device 802.11 capabilities, number of PMKIDs */ - caps = (struct ndis_80211_capability *)caps_buf; - len = sizeof(caps_buf); + len = sizeof(caps); retval = rndis_query_oid(usbdev, RNDIS_OID_802_11_CAPABILITY, - caps, &len); + &caps, &len); if (retval >= 0) { netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, " "ver %d, pmkids %d, auth-encr-pairs %d\n", - le32_to_cpu(caps->length), - le32_to_cpu(caps->version), - le32_to_cpu(caps->num_pmkids), - le32_to_cpu(caps->num_auth_encr_pair)); - wiphy->max_num_pmkids = le32_to_cpu(caps->num_pmkids); + le32_to_cpu(caps.length), + le32_to_cpu(caps.version), + le32_to_cpu(caps.num_pmkids), + le32_to_cpu(caps.num_auth_encr_pair)); + wiphy->max_num_pmkids = le32_to_cpu(caps.num_pmkids); } else wiphy->max_num_pmkids = 0; -- cgit From e0e05f20c200c41b34294078bbc29d67bfd607ea Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 13:54:51 -0500 Subject: ipw2x00: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507185451.GA14603@embeddedor --- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 2 +- drivers/net/wireless/intel/ipw2x00/ipw2200.h | 10 +++++----- drivers/net/wireless/intel/ipw2x00/libipw.h | 28 ++++++++++++++-------------- 3 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index e9e686ad57b1..661e63bfc892 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3386,7 +3386,7 @@ struct ipw_fw { __le32 boot_size; __le32 ucode_size; __le32 fw_size; - u8 data[0]; + u8 data[]; }; static int ipw_get_fw(struct ipw_priv *priv, diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index 4346520545c4..09fa7f19050f 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -448,7 +448,7 @@ struct tfd_command { u8 index; u8 length; __le16 reserved; - u8 payload[0]; + u8 payload[]; } __packed; struct tfd_data { @@ -675,7 +675,7 @@ struct ipw_rx_frame { // is identical) u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen __le16 length; - u8 data[0]; + u8 data[]; } __packed; struct ipw_rx_header { @@ -1002,7 +1002,7 @@ struct ipw_cmd { /* XXX */ * Incoming parameters listed 1-st, followed by outcoming params. * nParams=(len+3)/4+status_len */ - u32 param[0]; + u32 param[]; } __packed; #define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */ @@ -1108,7 +1108,7 @@ struct ipw_fw_error { /* XXX */ u32 log_len; struct ipw_error_elem *elem; struct ipw_event *log; - u8 payload[0]; + u8 payload[]; } __packed; #ifdef CONFIG_IPW2200_PROMISCUOUS @@ -1153,7 +1153,7 @@ struct ipw_rt_hdr { s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ s8 rt_dbmnoise; u8 rt_antenna; /* antenna number */ - u8 payload[0]; /* payload... */ + u8 payload[]; /* payload... */ } __packed; #endif diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h index e4a6ab4e8391..e87538a8b88b 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw.h +++ b/drivers/net/wireless/intel/ipw2x00/libipw.h @@ -334,7 +334,7 @@ struct libipw_hdr_1addr { __le16 frame_ctl; __le16 duration_id; u8 addr1[ETH_ALEN]; - u8 payload[0]; + u8 payload[]; } __packed; struct libipw_hdr_2addr { @@ -342,7 +342,7 @@ struct libipw_hdr_2addr { __le16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; - u8 payload[0]; + u8 payload[]; } __packed; struct libipw_hdr_3addr { @@ -352,7 +352,7 @@ struct libipw_hdr_3addr { u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; __le16 seq_ctl; - u8 payload[0]; + u8 payload[]; } __packed; struct libipw_hdr_4addr { @@ -363,7 +363,7 @@ struct libipw_hdr_4addr { u8 addr3[ETH_ALEN]; __le16 seq_ctl; u8 addr4[ETH_ALEN]; - u8 payload[0]; + u8 payload[]; } __packed; struct libipw_hdr_3addrqos { @@ -380,7 +380,7 @@ struct libipw_hdr_3addrqos { struct libipw_info_element { u8 id; u8 len; - u8 data[0]; + u8 data[]; } __packed; /* @@ -406,7 +406,7 @@ struct libipw_auth { __le16 transaction; __le16 status; /* challenge */ - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; struct libipw_channel_switch { @@ -442,7 +442,7 @@ struct libipw_disassoc { struct libipw_probe_request { struct libipw_hdr_3addr header; /* SSID, supported rates */ - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; struct libipw_probe_response { @@ -452,7 +452,7 @@ struct libipw_probe_response { __le16 capability; /* SSID, supported rates, FH params, DS params, * CF params, IBSS params, TIM (if beacon), RSN */ - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; /* Alias beacon for probe_response */ @@ -463,7 +463,7 @@ struct libipw_assoc_request { __le16 capability; __le16 listen_interval; /* SSID, supported rates, RSN */ - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; struct libipw_reassoc_request { @@ -471,7 +471,7 @@ struct libipw_reassoc_request { __le16 capability; __le16 listen_interval; u8 current_ap[ETH_ALEN]; - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; struct libipw_assoc_response { @@ -480,7 +480,7 @@ struct libipw_assoc_response { __le16 status; __le16 aid; /* supported rates */ - struct libipw_info_element info_element[0]; + struct libipw_info_element info_element[]; } __packed; struct libipw_txb { @@ -490,7 +490,7 @@ struct libipw_txb { u8 reserved; u16 frag_size; u16 payload_size; - struct sk_buff *fragments[0]; + struct sk_buff *fragments[]; }; /* SWEEP TABLE ENTRIES NUMBER */ @@ -594,7 +594,7 @@ struct libipw_ibss_dfs { struct libipw_info_element ie; u8 owner[ETH_ALEN]; u8 recovery_interval; - struct libipw_channel_map channel_map[0]; + struct libipw_channel_map channel_map[]; }; struct libipw_csa { @@ -830,7 +830,7 @@ struct libipw_device { /* This must be the last item so that it points to the data * allocated beyond this structure by alloc_libipw */ - u8 priv[0]; + u8 priv[]; }; #define IEEE_A (1<<0) -- cgit From 8863b1212aab2c738be9526f90389bc0fc18f90f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 13:55:29 -0500 Subject: iwlegacy: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507185529.GA14639@embeddedor --- drivers/net/wireless/intel/iwlegacy/commands.h | 22 +++++++++++----------- drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlegacy/commands.h b/drivers/net/wireless/intel/iwlegacy/commands.h index dd744135c956..89c6671b32bc 100644 --- a/drivers/net/wireless/intel/iwlegacy/commands.h +++ b/drivers/net/wireless/intel/iwlegacy/commands.h @@ -203,7 +203,7 @@ struct il_cmd_header { __le16 sequence; /* command or response/notification data follows immediately */ - u8 data[0]; + u8 data[]; } __packed; /** @@ -1112,7 +1112,7 @@ struct il_wep_cmd { u8 global_key_type; u8 flags; u8 reserved; - struct il_wep_key key[0]; + struct il_wep_key key[]; } __packed; #define WEP_KEY_WEP_TYPE 1 @@ -1166,7 +1166,7 @@ struct il3945_rx_frame_stats { u8 agc; __le16 sig_avg; __le16 noise_diff; - u8 payload[0]; + u8 payload[]; } __packed; struct il3945_rx_frame_hdr { @@ -1175,7 +1175,7 @@ struct il3945_rx_frame_hdr { u8 reserved1; u8 rate; __le16 len; - u8 payload[0]; + u8 payload[]; } __packed; struct il3945_rx_frame_end { @@ -1211,7 +1211,7 @@ struct il4965_rx_non_cfg_phy { __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */ __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */ u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ - u8 pad[0]; + u8 pad[]; } __packed; /* @@ -1409,7 +1409,7 @@ struct il3945_tx_cmd { * length is 26 or 30 bytes, followed by payload data */ u8 payload[0]; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* @@ -1511,7 +1511,7 @@ struct il_tx_cmd { * length is 26 or 30 bytes, followed by payload data */ u8 payload[0]; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* TX command response is sent after *3945* transmission attempts. @@ -2520,7 +2520,7 @@ struct il3945_scan_cmd { * for one scan to complete (i.e. receive N_SCAN_COMPLETE) * before requesting another scan. */ - u8 data[0]; + u8 data[]; } __packed; struct il_scan_cmd { @@ -2564,7 +2564,7 @@ struct il_scan_cmd { * for one scan to complete (i.e. receive N_SCAN_COMPLETE) * before requesting another scan. */ - u8 data[0]; + u8 data[]; } __packed; /* Can abort will notify by complete notification with abort status. */ @@ -2664,7 +2664,7 @@ struct il3945_tx_beacon_cmd { __le16 tim_idx; u8 tim_size; u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ + struct ieee80211_hdr frame[]; /* beacon frame */ } __packed; struct il_tx_beacon_cmd { @@ -2672,7 +2672,7 @@ struct il_tx_beacon_cmd { __le16 tim_idx; u8 tim_size; u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ + struct ieee80211_hdr frame[]; /* beacon frame */ } __packed; /****************************************************************************** diff --git a/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h index a3b490501a70..1e8ab704dbfb 100644 --- a/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h +++ b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h @@ -53,7 +53,7 @@ struct ieee80211_measurement_params { struct ieee80211_info_element { u8 id; u8 len; - u8 data[0]; + u8 data[]; } __packed; struct ieee80211_measurement_request { @@ -61,7 +61,7 @@ struct ieee80211_measurement_request { u8 token; u8 mode; u8 type; - struct ieee80211_measurement_params params[0]; + struct ieee80211_measurement_params params[]; } __packed; struct ieee80211_measurement_report { -- cgit From 174812346c30321158046d879912c85d638cd1b7 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 13:59:14 -0500 Subject: mwl8k: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507185914.GA15124@embeddedor --- drivers/net/wireless/marvell/mwl8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 47fb4b3ea004..97f23f93f6e7 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -2668,7 +2668,7 @@ struct mwl8k_cmd_mac_multicast_adr { struct mwl8k_cmd_pkt header; __le16 action; __le16 numaddr; - __u8 addr[0][ETH_ALEN]; + __u8 addr[][ETH_ALEN]; }; #define MWL8K_ENABLE_RX_DIRECTED 0x0001 -- cgit From 8d7d7a93d5265468a0019f11d0bcd2e005ce9ebd Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 14:02:10 -0500 Subject: prism54: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507190210.GA15375@embeddedor --- drivers/net/wireless/intersil/prism54/isl_oid.h | 8 ++++---- drivers/net/wireless/intersil/prism54/islpci_mgt.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intersil/prism54/isl_oid.h b/drivers/net/wireless/intersil/prism54/isl_oid.h index 5441c1f9f2fc..1afc2ccf94ca 100644 --- a/drivers/net/wireless/intersil/prism54/isl_oid.h +++ b/drivers/net/wireless/intersil/prism54/isl_oid.h @@ -37,7 +37,7 @@ struct obj_mlmeex { u16 state; u16 code; u16 size; - u8 data[0]; + u8 data[]; } __packed; struct obj_buffer { @@ -68,12 +68,12 @@ struct obj_bss { struct obj_bsslist { u32 nr; - struct obj_bss bsslist[0]; + struct obj_bss bsslist[]; } __packed; struct obj_frequencies { u16 nr; - u16 mhz[0]; + u16 mhz[]; } __packed; struct obj_attachment { @@ -81,7 +81,7 @@ struct obj_attachment { char reserved; short id; short size; - char data[0]; + char data[]; } __packed; /* diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.h b/drivers/net/wireless/intersil/prism54/islpci_mgt.h index d6bbbac46b4a..1f87d0aea60c 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.h +++ b/drivers/net/wireless/intersil/prism54/islpci_mgt.h @@ -99,7 +99,7 @@ struct islpci_mgmtframe { pimfor_header_t *header; /* payload header, points into buf */ void *data; /* payload ex header, points into buf */ struct work_struct ws; /* argument for schedule_work() */ - char buf[0]; /* fragment buffer */ + char buf[]; /* fragment buffer */ }; int -- cgit From 55bb8a2b01a3f1531a5154457ec1c7041f5c6f9e Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 14:19:26 -0500 Subject: qtnfmac: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Sergey Matyukevich Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507191926.GA15970@embeddedor --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 2 +- drivers/net/wireless/quantenna/qtnfmac/qlink.h | 54 +++++++++++++------------- 2 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 87d048df09d1..3334c45aac13 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -69,7 +69,7 @@ struct qtnf_bus { struct notifier_block netdev_nb; u8 hw_id[ETH_ALEN]; /* bus private data */ - char bus_priv[0] __aligned(sizeof(void *)); + char bus_priv[] __aligned(sizeof(void *)); }; static inline bool qtnf_fw_is_up(struct qtnf_bus *bus) diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 4d22a54c034f..2dda4c5d7427 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -362,7 +362,7 @@ struct qlink_cmd { struct qlink_cmd_init_fw { struct qlink_cmd chdr; __le32 qlink_proto_ver; - u8 var_info[0]; + u8 var_info[]; } __packed; /** @@ -434,7 +434,7 @@ struct qlink_cmd_frame_tx { __le32 cookie; __le16 freq; __le16 flags; - u8 frame_data[0]; + u8 frame_data[]; } __packed; /** @@ -466,7 +466,7 @@ struct qlink_cmd_add_key { __le32 cipher; __le16 vlanid; u8 rsvd[2]; - u8 key_data[0]; + u8 key_data[]; } __packed; /** @@ -578,7 +578,7 @@ struct qlink_cmd_connect { u8 mfp; u8 pbss; u8 rsvd[2]; - u8 payload[0]; + u8 payload[]; } __packed; /** @@ -592,7 +592,7 @@ struct qlink_cmd_external_auth { struct qlink_cmd chdr; u8 peer[ETH_ALEN]; __le16 status; - u8 payload[0]; + u8 payload[]; } __packed; /** @@ -698,7 +698,7 @@ struct qlink_cmd_reg_notify { u8 dfs_region; u8 slave_radar; u8 dfs_offload; - u8 info[0]; + u8 info[]; } __packed; /** @@ -773,7 +773,7 @@ struct qlink_cmd_start_ap { struct qlink_sr_params sr_params; u8 twt_responder; u8 rsvd[3]; - u8 info[0]; + u8 info[]; } __packed; /** @@ -807,7 +807,7 @@ struct qlink_mac_address { struct qlink_acl_data { __le32 policy; __le32 num_entries; - struct qlink_mac_address mac_addrs[0]; + struct qlink_mac_address mac_addrs[]; } __packed; /** @@ -882,7 +882,7 @@ enum qlink_wowlan_trigger { struct qlink_cmd_wowlan_set { struct qlink_cmd chdr; __le32 triggers; - u8 data[0]; + u8 data[]; } __packed; enum qlink_ndev_event_type { @@ -958,7 +958,7 @@ struct qlink_cmd_scan { u8 bssid[ETH_ALEN]; u8 scan_width; u8 rsvd[3]; - u8 var_info[0]; + u8 var_info[]; } __packed; /** @@ -972,7 +972,7 @@ struct qlink_cmd_update_owe { struct qlink_cmd chdr; u8 peer[ETH_ALEN]; __le16 status; - u8 ies[0]; + u8 ies[]; } __packed; /* QLINK Command Responses messages related definitions @@ -1106,7 +1106,7 @@ struct qlink_resp_get_mac_info { u8 n_reg_rules; u8 dfs_region; u8 rsvd[3]; - u8 var_info[0]; + u8 var_info[]; } __packed; /** @@ -1131,7 +1131,7 @@ struct qlink_resp_get_hw_info { u8 mac_bitmap; u8 total_tx_chain; u8 total_rx_chain; - u8 info[0]; + u8 info[]; } __packed; /** @@ -1167,7 +1167,7 @@ struct qlink_resp_get_sta_info { struct qlink_resp rhdr; u8 sta_addr[ETH_ALEN]; u8 rsvd[2]; - u8 info[0]; + u8 info[]; } __packed; /** @@ -1184,7 +1184,7 @@ struct qlink_resp_band_info_get { u8 num_chans; u8 num_bitrates; u8 rsvd[1]; - u8 info[0]; + u8 info[]; } __packed; /** @@ -1196,7 +1196,7 @@ struct qlink_resp_band_info_get { struct qlink_resp_get_chan_stats { struct qlink_resp rhdr; __le32 chan_freq; - u8 info[0]; + u8 info[]; } __packed; /** @@ -1270,7 +1270,7 @@ struct qlink_event_sta_assoc { struct qlink_event ehdr; u8 sta_addr[ETH_ALEN]; __le16 frame_control; - u8 ies[0]; + u8 ies[]; } __packed; /** @@ -1297,7 +1297,7 @@ struct qlink_event_bss_join { struct qlink_chandef chan; u8 bssid[ETH_ALEN]; __le16 status; - u8 ies[0]; + u8 ies[]; } __packed; /** @@ -1339,7 +1339,7 @@ struct qlink_event_rxmgmt { __le32 flags; s8 sig_dbm; u8 rsvd[3]; - u8 frame_data[0]; + u8 frame_data[]; } __packed; /** @@ -1367,7 +1367,7 @@ struct qlink_event_scan_result { u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 bssid[ETH_ALEN]; u8 rsvd[2]; - u8 payload[0]; + u8 payload[]; } __packed; /** @@ -1456,7 +1456,7 @@ struct qlink_event_update_owe { struct qlink_event ehdr; u8 peer[ETH_ALEN]; u8 rsvd[2]; - u8 ies[0]; + u8 ies[]; } __packed; /* QLINK TLVs (Type-Length Values) definitions @@ -1512,7 +1512,7 @@ enum qlink_tlv_id { struct qlink_tlv_hdr { __le16 type; __le16 len; - u8 val[0]; + u8 val[]; } __packed; struct qlink_iface_limit { @@ -1524,7 +1524,7 @@ struct qlink_iface_limit_record { __le16 max_interfaces; u8 num_different_channels; u8 n_limits; - struct qlink_iface_limit limits[0]; + struct qlink_iface_limit limits[]; } __packed; #define QLINK_RSSI_OFFSET 120 @@ -1647,7 +1647,7 @@ struct qlink_tlv_ie_set { u8 type; u8 flags; u8 rsvd[2]; - u8 ie_data[0]; + u8 ie_data[]; } __packed; /** @@ -1660,7 +1660,7 @@ struct qlink_tlv_ext_ie { struct qlink_tlv_hdr hdr; u8 eid_ext; u8 rsvd[3]; - u8 ie_data[0]; + u8 ie_data[]; } __packed; #define IEEE80211_HE_PPE_THRES_MAX_LEN 25 @@ -1681,7 +1681,7 @@ struct qlink_tlv_iftype_data { struct qlink_tlv_hdr hdr; u8 n_iftype_data; u8 rsvd[3]; - struct qlink_sband_iftype_data iftype_data[0]; + struct qlink_sband_iftype_data iftype_data[]; } __packed; /** @@ -1867,7 +1867,7 @@ struct qlink_random_mac_addr { struct qlink_wowlan_capab_data { __le16 version; __le16 len; - u8 data[0]; + u8 data[]; } __packed; /** -- cgit From bd7db3021aa7a31f7d5122af1a863e66c75f88f5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 7 May 2020 14:26:47 -0500 Subject: rndis_wlan: Replace zero-length array with flexible-array The current codebase makes use of the zero-length array language extension to the C90 standard, but the preferred mechanism to declare variable-length types such as these ones is a flexible array member[1][2], introduced in C99: struct foo { int stuff; struct boo array[]; }; By making use of the mechanism above, we will get a compiler warning in case the flexible array does not occur last in the structure, which will help us prevent some kind of undefined behavior bugs from being inadvertently introduced[3] to the codebase from now on. Also, notice that, dynamic memory allocations won't be affected by this change: "Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero."[1] sizeof(flexible-array-member) triggers a warning because flexible array members have incomplete type[1]. There are some instances of code in which the sizeof operator is being incorrectly/erroneously applied to zero-length arrays and the result is zero. Such instances may be hiding some bugs. So, this work (flexible-array member conversions) will also help to get completely rid of those sorts of issues. This issue was found with the help of Coccinelle. [1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html [2] https://github.com/KSPP/linux/issues/21 [3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200507192647.GA16710@embeddedor --- drivers/net/wireless/rndis_wlan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 78a4325bfe1b..8852a1832951 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -201,7 +201,7 @@ struct ndis_80211_pmkid_candidate { struct ndis_80211_pmkid_cand_list { __le32 version; __le32 num_candidates; - struct ndis_80211_pmkid_candidate candidate_list[0]; + struct ndis_80211_pmkid_candidate candidate_list[]; } __packed; struct ndis_80211_status_indication { @@ -246,12 +246,12 @@ struct ndis_80211_bssid_ex { __le32 net_infra; u8 rates[NDIS_802_11_LENGTH_RATES_EX]; __le32 ie_length; - u8 ies[0]; + u8 ies[]; } __packed; struct ndis_80211_bssid_list_ex { __le32 num_items; - struct ndis_80211_bssid_ex bssid[0]; + struct ndis_80211_bssid_ex bssid[]; } __packed; struct ndis_80211_fixed_ies { @@ -327,7 +327,7 @@ struct ndis_80211_bssid_info { struct ndis_80211_pmkid { __le32 length; __le32 bssid_info_count; - struct ndis_80211_bssid_info bssid_info[0]; + struct ndis_80211_bssid_info bssid_info[]; } __packed; /* -- cgit From 5bb4e125815aa769a7d2ab7dc203593925bba0ba Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 8 May 2020 21:51:39 +0200 Subject: ipw2x00: Fix comment for CLOCK_BOOTTIME constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct name of constant is CLOCK_BOOTTIME and not CLOCK_BOOTIME. Signed-off-by: Pali Rohár Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200508195139.20078-1-pali@kernel.org --- drivers/net/wireless/intel/ipw2x00/ipw2200.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index 09fa7f19050f..e1ec1c96dcd8 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -1329,7 +1329,7 @@ struct ipw_priv { s8 tx_power; - /* Track time in suspend using CLOCK_BOOTIME */ + /* Track time in suspend using CLOCK_BOOTTIME */ time64_t suspend_at; time64_t suspend_time; -- cgit From fd6c2dfa49b762ffe773a835ba62fa692df4c1b0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 16 Feb 2020 16:08:58 +0100 Subject: mt76: mt76x02: fix handling MCU timeouts during hw restart If a MCU timeout occurs before a hw restart completes, another hw restart is scheduled, and the station state gets corrupted. To speed up dealing with that, do not issue any MCU commands after the first timeout, and defer handling timeouts until the reset has completed. Also ignore errors in MCU commands during start/config to avoid making user space fail on this condition. If it happens, another restart is scheduled quickly, and that usually recovers the hardware properly. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 19 ++++++------------- 7 files changed, 31 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8e4759bc8f59..6d60187e88ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -275,6 +275,7 @@ enum { MT76_STATE_RUNNING, MT76_STATE_MCU_RUNNING, MT76_SCANNING, + MT76_RESTART, MT76_RESET, MT76_MCU_RESET, MT76_REMOVED, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 0b520ae08d01..57091d41eb85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -29,6 +29,7 @@ static void mt76x0e_stop_hw(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mt76.mac_work); + clear_bit(MT76_RESTART, &dev->mphy.state); if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, 0, 1000)) @@ -83,6 +84,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .set_coverage_class = mt76x02_set_coverage_class, .set_rts_threshold = mt76x02_set_rts_threshold, .get_antenna = mt76_get_antenna, + .reconfig_complete = mt76x02_reconfig_complete, }; static int mt76x0e_register_device(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 23040c193ca5..94dd142cb3d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -187,6 +187,8 @@ void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u32 changed); +void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type); struct beacon_bc_data { struct mt76x02_dev *dev; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 5664749ad6c1..8247611d9b18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -20,6 +20,9 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int ret; u8 seq; + if (mt76_is_mmio(&dev->mt76) && dev->mcu_timeout) + return -EIO; + skb = mt76x02_mcu_msg_alloc(data, len); if (!skb) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 7dcc5d342e9f..7e389dbccfeb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -520,6 +520,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) } if (restart) { + set_bit(MT76_RESTART, &dev->mphy.state); mt76x02_mcu_function_select(dev, Q_SELECT, 1); ieee80211_restart_hw(dev->mt76.hw); } else { @@ -528,8 +529,23 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) } } +void mt76x02_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) +{ + struct mt76x02_dev *dev = hw->priv; + + if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) + return; + + clear_bit(MT76_RESTART, &dev->mphy.state); +} +EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); + static void mt76x02_check_tx_hang(struct mt76x02_dev *dev) { + if (test_bit(MT76_RESTART, &dev->mphy.state)) + return; + if (mt76x02_tx_hang(dev)) { if (++dev->tx_hang_check >= MT_TX_HANG_TH) goto restart; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index c69579e5f647..f27774f57438 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -256,6 +256,7 @@ void mt76x2_stop_hardware(struct mt76x02_dev *dev) cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mt76.mac_work); cancel_delayed_work_sync(&dev->wdt_work); + clear_bit(MT76_RESTART, &dev->mphy.state); mt76x02_mcu_set_radio_state(dev, false); mt76x2_mac_stop(dev, false); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 105e5b99b3f9..a74599f7f729 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -10,12 +10,9 @@ static int mt76x2_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; - int ret; mt76x02_mac_start(dev); - ret = mt76x2_phy_start(dev); - if (ret) - return ret; + mt76x2_phy_start(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, MT_MAC_WORK_INTERVAL); @@ -35,11 +32,9 @@ mt76x2_stop(struct ieee80211_hw *hw) mt76x2_stop_hardware(dev); } -static int +static void mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { - int ret; - cancel_delayed_work_sync(&dev->cal_work); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); tasklet_disable(&dev->dfs_pd.dfs_tasklet); @@ -50,7 +45,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76_set_channel(&dev->mphy); mt76x2_mac_stop(dev, true); - ret = mt76x2_phy_set_channel(dev, chandef); + mt76x2_phy_set_channel(dev, chandef); mt76x02_mac_cc_reset(dev); mt76x02_dfs_init_params(dev); @@ -64,15 +59,12 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) tasklet_enable(&dev->mt76.pre_tbtt_tasklet); mt76_txq_schedule_all(&dev->mphy); - - return ret; } static int mt76x2_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x02_dev *dev = hw->priv; - int ret = 0; mutex_lock(&dev->mt76.mutex); @@ -101,11 +93,11 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ieee80211_stop_queues(hw); - ret = mt76x2_set_channel(dev, &hw->conf.chandef); + mt76x2_set_channel(dev, &hw->conf.chandef); ieee80211_wake_queues(hw); } - return ret; + return 0; } static void @@ -162,5 +154,6 @@ const struct ieee80211_ops mt76x2_ops = { .set_antenna = mt76x2_set_antenna, .get_antenna = mt76_get_antenna, .set_rts_threshold = mt76x02_set_rts_threshold, + .reconfig_complete = mt76x02_reconfig_complete, }; -- cgit From b2934279c3e9719145ff4090d4ab951e340df17e Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 18 Mar 2020 16:07:48 -0700 Subject: mt76: mt76x02u: Add support for newer versions of the XBox One wifi adapter The current version has a new USB ID and reports as an 0x7632 device. Adding the IDs results in it working out of the box. Signed-off-by: Matthew Garrett Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 94dd142cb3d7..6ea210bd3f07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -218,6 +218,7 @@ static inline bool is_mt76x0(struct mt76x02_dev *dev) static inline bool is_mt76x2(struct mt76x02_dev *dev) { return mt76_chip(&dev->mt76) == 0x7612 || + mt76_chip(&dev->mt76) == 0x7632 || mt76_chip(&dev->mt76) == 0x7662 || mt76_chip(&dev->mt76) == 0x7602; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index eafa283ca699..6376734282b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -18,6 +18,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ + { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ { }, }; -- cgit From 3efdfbe0b5b5e08d7b699f5d3138c1801ffb3714 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 21 Mar 2020 16:14:42 +0100 Subject: mt76: mt76x2u: introduce Mercury UD13 support Introduce Mercury UD13 dual-band dongle support to mt76x2u driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 6376734282b7..3a4e41724af1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -16,6 +16,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ + { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ -- cgit From 663e69b141cd1e31039a9bebdaeb3aab0fe9c661 Mon Sep 17 00:00:00 2001 From: Pawel Dembicki Date: Wed, 25 Mar 2020 06:55:23 +0100 Subject: mt76: mt76x0: pci: add mt7610 PCI ID Add mt7610 PCI id found on D-Link DWR-960 to pci_device_id table. Run-tested on D-Link DWR-960 with no-name half-size mPCIE card with mt7610e. Signed-off-by: Pawel Dembicki Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 57091d41eb85..f7ec3400e368 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -218,6 +218,7 @@ mt76x0e_remove(struct pci_dev *pdev) } static const struct pci_device_id mt76x0e_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7610) }, { PCI_DEVICE(0x14c3, 0x7630) }, { PCI_DEVICE(0x14c3, 0x7650) }, { }, -- cgit From f8de2bf26ce9e6611cbded70e6e9c78a5b4fd107 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 31 Mar 2020 14:51:35 +0800 Subject: mt76: mt7615: modify mt7615_ampdu_stat_read for each phy This is a preliminary patch to add more Tx counters. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index b4d0795154e3..9fd40d723201 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -120,12 +120,17 @@ mt7615_reset_test_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(fops_reset_test, NULL, mt7615_reset_test_set, "%lld\n"); -static int -mt7615_ampdu_stat_read(struct seq_file *file, void *data) +static void +mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy, + struct seq_file *file) { struct mt7615_dev *dev = file->private; + bool ext_phy = phy != &dev->phy; int bound[7], i, range; + if (!phy) + return; + range = mt76_rr(dev, MT_AGG_ASRCR0); for (i = 0; i < 4; i++) bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; @@ -133,6 +138,8 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data) for (i = 0; i < 3; i++) bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1; + seq_printf(file, "\nPhy %d\n", ext_phy); + seq_printf(file, "Length: %8d | ", bound[0]); for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) seq_printf(file, "%3d -%3d | ", @@ -141,6 +148,15 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data) for (i = 0; i < ARRAY_SIZE(bound); i++) seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); seq_puts(file, "\n"); +} + +static int +mt7615_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7615_dev *dev = file->private; + + mt7615_ampdu_stat_read_phy(&dev->phy, file); + mt7615_ampdu_stat_read_phy(mt7615_ext_phy(dev), file); return 0; } -- cgit From b473fdbb745612e6ed50a176825ded1c5ba42c3f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 31 Mar 2020 14:51:36 +0800 Subject: mt76: mt7615: enable aggr_stats for both phy Use bottom half of aggr_stats for second phy. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 21 +++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 3 ++- 3 files changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 9fd40d723201..980e7e3cf37e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -145,8 +145,10 @@ mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy, seq_printf(file, "%3d -%3d | ", bound[i], bound[i + 1]); seq_puts(file, "\nCount: "); + + range = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < ARRAY_SIZE(bound); i++) - seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + range]); seq_puts(file, "\n"); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index a27a6d164009..8572973cc4c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -82,8 +82,10 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) { int i; - for (i = 0; i < 4; i++) - mt76_rr(dev, MT_TX_AGG_CNT(i)); + for (i = 0; i < 4; i++) { + mt76_rr(dev, MT_TX_AGG_CNT(0, i)); + mt76_rr(dev, MT_TX_AGG_CNT(1, i)); + } memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); dev->mt76.phy.survey_time = ktime_get_boottime(); @@ -1751,13 +1753,14 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) struct mt7615_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; bool ext_phy = phy != &dev->phy; - int i; + int i, aggr; memset(mib, 0, sizeof(*mib)); mib->fcs_err_cnt = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), MT_MIB_SDR3_FCS_ERR_MASK); + aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < 4; i++) { u32 data, val, val2; @@ -1772,6 +1775,11 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val2); mib->rts_retries_cnt = data; } + + val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); + + dev->mt76.aggr_stats[aggr++] += val & 0xffff; + dev->mt76.aggr_stats[aggr++] += val >> 16; } } @@ -1779,7 +1787,6 @@ void mt7615_mac_work(struct work_struct *work) { struct mt7615_dev *dev; struct mt7615_phy *ext_phy; - int i, idx; dev = (struct mt7615_dev *)container_of(work, struct mt76_dev, mac_work.work); @@ -1799,12 +1806,6 @@ void mt7615_mac_work(struct work_struct *work) dev->mac_work_count = 0; } - for (i = 0, idx = 0; i < 4; i++) { - u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); - - dev->mt76.aggr_stats[idx++] += val & 0xffff; - dev->mt76.aggr_stats[idx++] += val >> 16; - } mutex_unlock(&dev->mt76.mutex); mt76_tx_status_check(&dev->mt76, NULL, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 1e0d95b917e1..d91041613df8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -406,7 +406,8 @@ enum mt7615_reg_base { ((n) << 4)) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) -#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(0xa8 + ((_band) << 9) + \ + ((n) << 2)) #define MT_DMA_SHDL(ofs) (dev->reg_map[MT_DMA_SHDL_BASE] + (ofs)) -- cgit From b7825ca0a29e1e679af1b0c6187c0d09a76c8554 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 31 Mar 2020 14:51:37 +0800 Subject: mt76: mt7615: cleanup mib related defines and structs Simplify mib macros and use proper type for related counters. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 16 +++++++-------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 23 ++++++++++------------ 3 files changed, 22 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 8572973cc4c8..f30dc015e88e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1535,8 +1535,8 @@ void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable) mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(1), MT_WF_PHY_PD_BLK(1)); if (is_mt7622(&dev->mt76)) { - mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7 << 8); - mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7); + mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8); + mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7); } } else { mt76_clear(dev, MT_WF_PHY_MIN_PRI_PWR(0), @@ -1762,18 +1762,18 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < 4; i++) { - u32 data, val, val2; + u32 val, val2; val = mt76_get_field(dev, MT_MIB_MB_SDR1(ext_phy, i), MT_MIB_ACK_FAIL_COUNT_MASK); if (val > mib->ack_fail_cnt) mib->ack_fail_cnt = val; - val2 = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); - data = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val2); - if (data > mib->rts_retries_cnt) { - mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val2); - mib->rts_retries_cnt = data; + val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); + val2 = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); + if (val2 > mib->rts_retries_cnt) { + mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); + mib->rts_retries_cnt = val2; } val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 676ca622c35a..000070769217 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -113,10 +113,10 @@ struct mt7615_vif { }; struct mib_stats { - u32 ack_fail_cnt; - u32 fcs_err_cnt; - u32 rts_cnt; - u32 rts_retries_cnt; + u16 ack_fail_cnt; + u16 fcs_err_cnt; + u16 rts_cnt; + u16 rts_retries_cnt; }; struct mt7615_phy { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index d91041613df8..58aaa57fb451 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -379,35 +379,32 @@ enum mt7615_reg_base { #define MT_LPON_UTTR1 MT_LPON(0x01c) #define MT_WF_MIB_BASE (dev->reg_map[MT_MIB_BASE]) -#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs)) +#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE + (ofs) + (_band) * 0x200) -#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c) +#define MT_MIB_M0_MISC_CR(_band) MT_WF_MIB(_band, 0x00c) -#define MT_MIB_SDR3(n) MT_WF_MIB(0x014 + ((n) << 9)) +#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) -#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9)) +#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) #define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) -#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9)) +#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) #define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) -#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9)) +#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9)) +#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) #define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) -#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(0x100 + ((_band) << 9) + \ - ((n) << 4)) +#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) -#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(0x104 + ((_band) << 9) + \ - ((n) << 4)) +#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4)) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) -#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(0xa8 + ((_band) << 9) + \ - ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa8 + ((n) << 2)) #define MT_DMA_SHDL(ofs) (dev->reg_map[MT_DMA_SHDL_BASE] + (ofs)) -- cgit From aef16345ba8db6455c816fdbe584e140dde84d32 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 31 Mar 2020 14:51:38 +0800 Subject: mt76: mt7615: add more useful Tx mib counters Add ba_miss_cnt and ampdu_per in mib_stats. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 20 +++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 7 +++++++ 4 files changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 980e7e3cf37e..641bfada5756 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -150,6 +150,10 @@ mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy, for (i = 0; i < ARRAY_SIZE(bound); i++) seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + range]); seq_puts(file, "\n"); + + seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); + seq_printf(file, "PER: %ld.%1ld%%\n", + phy->mib.aggr_per / 10, phy->mib.aggr_per % 10); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f30dc015e88e..5451c0b8c9f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1754,20 +1754,30 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) struct mib_stats *mib = &phy->mib; bool ext_phy = phy != &dev->phy; int i, aggr; + u32 val, val2; memset(mib, 0, sizeof(*mib)); mib->fcs_err_cnt = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), MT_MIB_SDR3_FCS_ERR_MASK); + val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy), + MT_MIB_AMPDU_MPDU_COUNT); + val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy), + MT_MIB_AMPDU_ACK_COUNT); + mib->aggr_per = 1000 * (val - val2) / val; + aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < 4; i++) { - u32 val, val2; + val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i)); + + val2 = FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); + if (val2 > mib->ack_fail_cnt) + mib->ack_fail_cnt = val2; - val = mt76_get_field(dev, MT_MIB_MB_SDR1(ext_phy, i), - MT_MIB_ACK_FAIL_COUNT_MASK); - if (val > mib->ack_fail_cnt) - mib->ack_fail_cnt = val; + val2 = FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); + if (val2 > mib->ba_miss_cnt) + mib->ba_miss_cnt = val2; val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); val2 = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 000070769217..052031d25f38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -117,6 +117,8 @@ struct mib_stats { u16 fcs_err_cnt; u16 rts_cnt; u16 rts_retries_cnt; + u16 ba_miss_cnt; + unsigned long aggr_per; }; struct mt7615_phy { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 58aaa57fb451..29c56b0723cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -389,6 +389,12 @@ enum mt7615_reg_base { #define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) #define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x040) +#define MT_MIB_AMPDU_MPDU_COUNT GENMASK(23, 0) + +#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x044) +#define MT_MIB_AMPDU_ACK_COUNT GENMASK(23, 0) + #define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) #define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) @@ -402,6 +408,7 @@ enum mt7615_reg_base { #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4)) +#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa8 + ((n) << 2)) -- cgit From 886a862d3677ac0d3b57d19ffcf5b2d48b9c5267 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:31 +0200 Subject: mt76: mt7663: fix mt7615_mac_cca_stats_reset routine Fix PHYMUX_5 register definition for mt7663 in mt7615_mac_cca_stats_reset routine Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 8 +++++++- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5451c0b8c9f2..778b47912475 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1576,8 +1576,14 @@ void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; - u32 reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); + u32 reg; + if (is_mt7663(&dev->mt76)) + reg = MT7663_WF_PHY_R0_PHYMUX_5; + else + reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); + + /* reset PD and MDRDY counters */ mt76_clear(dev, reg, GENMASK(22, 20)); mt76_set(dev, reg, BIT(22) | BIT(20)); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 29c56b0723cd..a255a6199680 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -151,6 +151,7 @@ enum mt7615_reg_base { #define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9) #define MT_WF_PHY_R0_PHYMUX_5(_phy) MT_WF_PHY(0x0614 + ((_phy) << 9)) +#define MT7663_WF_PHY_R0_PHYMUX_5 MT_WF_PHY(0x0414) #define MT_WF_PHY_R0_PHYCTRL_STS0(_phy) MT_WF_PHY(0x020c + ((_phy) << 9)) #define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16) -- cgit From b61e45eb891fd8fb0704fc05aaae3be53e7687ae Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:32 +0200 Subject: mt76: mt7663: enable nf estimation Enable Noise floor estimation for mt7663 driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 16 +++++++++++----- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 778b47912475..e6d312dd81c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1558,10 +1558,12 @@ out: void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) { - u32 rxtd; + u32 rxtd, reg; if (is_mt7663(&dev->mt76)) - return; + reg = MT7663_WF_PHY_R0_PHYMUX_5; + else + reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); if (ext_phy) rxtd = MT_WF_PHY_RXTD2(10); @@ -1569,7 +1571,7 @@ void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) rxtd = MT_WF_PHY_RXTD(12); mt76_set(dev, rxtd, BIT(18) | BIT(29)); - mt76_set(dev, MT_WF_PHY_R0_PHYMUX_5(ext_phy), 0x5 << 12); + mt76_set(dev, reg, 0x5 << 12); } void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy) @@ -1693,10 +1695,14 @@ static u8 mt7615_phy_get_nf(struct mt7615_dev *dev, int idx) { static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; - u32 reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20); - u32 val, sum = 0, n = 0; + u32 reg, val, sum = 0, n = 0; int i; + if (is_mt7663(&dev->mt76)) + reg = MT7663_WF_PHY_RXTD(20); + else + reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20); + for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { val = mt76_rr(dev, reg); sum += val * nf_power[i]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index a255a6199680..481e4d941e72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -170,6 +170,8 @@ enum mt7615_reg_base { #define MT_WF_PHY_RXTD_BASE MT_WF_PHY(0x2200) #define MT_WF_PHY_RXTD(_n) (MT_WF_PHY_RXTD_BASE + ((_n) << 2)) +#define MT7663_WF_PHY_RXTD(_n) (MT_WF_PHY(0x25b0) + ((_n) << 2)) + #define MT_WF_PHY_RXTD_CCK_PD(_phy) MT_WF_PHY((_phy) ? 0x2314 : 0x2310) #define MT_WF_PHY_PD_CCK_MASK(_phy) (_phy) ? GENMASK(31, 24) : \ GENMASK(8, 1) -- cgit From 594034b788673a42a0fad785b8a72c523568721f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:33 +0200 Subject: mt76: mt7615: make scs configurable per phy Make scs configurable per phy since most of the chipsets do not support dbdc Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 8 ++++-- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 4 ++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 29 ++++++++-------------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 5 ++-- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 641bfada5756..777c7f9bd760 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -20,11 +20,15 @@ static int mt7615_scs_set(void *data, u64 val) { struct mt7615_dev *dev = data; + struct mt7615_phy *ext_phy; if (!mt7615_wait_for_mcu_init(dev)) return 0; - mt7615_mac_set_scs(dev, val); + mt7615_mac_set_scs(&dev->phy, val); + ext_phy = mt7615_ext_phy(dev); + if (ext_phy) + mt7615_mac_set_scs(ext_phy, val); return 0; } @@ -34,7 +38,7 @@ mt7615_scs_get(void *data, u64 *val) { struct mt7615_dev *dev = data; - *val = dev->scs_en; + *val = dev->phy.scs_en; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 03b1e56534d6..8b7d8118d9ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -90,7 +90,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev) MT_TMAC_CTCR0_INS_DDLMT_EN); mt7615_mcu_set_rts_thresh(&dev->phy, 0x92b); - mt7615_mac_set_scs(dev, true); + mt7615_mac_set_scs(&dev->phy, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, MT_AGG_SCR_NLNAV_MID_PTEC_DIS); @@ -411,6 +411,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1; mt7615_init_wiphy(mphy->hw); + mt7615_mac_set_scs(phy, true); + /* * Make the secondary PHY MAC address local without overlapping with * the usual MAC address allocation scheme on multiple virtual interfaces diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e6d312dd81c2..6b013e8dadd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1517,40 +1517,33 @@ mt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) phy->last_cca_adj = jiffies; } -void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable) +void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) { - struct mt7615_phy *ext_phy; + struct mt7615_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; mutex_lock(&dev->mt76.mutex); - if (dev->scs_en == enable) + if (phy->scs_en == enable) goto out; if (is_mt7663(&dev->mt76)) goto out; if (enable) { - mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(0), - MT_WF_PHY_PD_BLK(0)); - mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(1), - MT_WF_PHY_PD_BLK(1)); + mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), + MT_WF_PHY_PD_BLK(ext_phy)); if (is_mt7622(&dev->mt76)) { mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8); mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7); } } else { - mt76_clear(dev, MT_WF_PHY_MIN_PRI_PWR(0), - MT_WF_PHY_PD_BLK(0)); - mt76_clear(dev, MT_WF_PHY_MIN_PRI_PWR(1), - MT_WF_PHY_PD_BLK(1)); + mt76_clear(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), + MT_WF_PHY_PD_BLK(ext_phy)); } - mt7615_mac_set_default_sensitivity(&dev->phy); - ext_phy = mt7615_ext_phy(dev); - if (ext_phy) - mt7615_mac_set_default_sensitivity(ext_phy); - - dev->scs_en = enable; + mt7615_mac_set_default_sensitivity(phy); + phy->scs_en = enable; out: mutex_unlock(&dev->mt76.mutex); @@ -1663,7 +1656,7 @@ mt7615_mac_scs_check(struct mt7615_phy *phy) u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm; bool ext_phy = phy != &dev->phy; - if (!dev->scs_en) + if (!phy->scs_en) return; val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 052031d25f38..e531c416f85d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -130,6 +130,8 @@ struct mt7615_phy { u16 noise; + bool scs_en; + unsigned long last_cca_adj; int false_cca_ofdm, false_cca_cck; s8 ofdm_sensitivity; @@ -211,7 +213,6 @@ struct mt7615_dev { u32 hw_pattern; u8 mac_work_count; - bool scs_en; bool fw_debug; spinlock_t token_lock; @@ -369,7 +370,7 @@ void mt7615_update_channel(struct mt76_dev *mdev); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); -void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); +void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, -- cgit From 02c655919c431fc72171b3016dead174a4bf4f8e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:34 +0200 Subject: mt76: mt7663: disable RDD commands Disable dfs RDD mcu commands for mt7663 driver since they are not currently supported by the 7663 firmware Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 6b013e8dadd7..e88914685807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2047,6 +2047,9 @@ int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy) bool ext_phy = phy != &dev->phy; int err; + if (is_mt7663(&dev->mt76)) + return 0; + if (dev->mt76.region == NL80211_DFS_UNSET) { phy->dfs_state = -1; if (phy->rdd_state) -- cgit From 938d76bb3a29591e18da9aa8d8c8fc6a4454e2b7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:35 +0200 Subject: mt76: mt7615: add ethool support to mt7663 driver Report n9 firmware version using ethtool Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 610cfa918c7b..32e3e4219076 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1914,8 +1914,14 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) } ret = mt7615_mcu_start_firmware(dev, override_addr, flag); - if (ret) + if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); + goto out; + } + + snprintf(dev->mt76.hw->wiphy->fw_version, + sizeof(dev->mt76.hw->wiphy->fw_version), + "%.10s-%.15s", hdr->fw_ver, hdr->build_date); out: release_firmware(fw); -- cgit From bf18fcdc9a4ba0861743cb7c8c8a6349ad0114f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:36 +0200 Subject: mt76: mt7615: introduce mt7615_mcu_set_channel_domain mcu command Introduce mt7615_mcu_set_channel_domain routines in order to instruct the mcu about supported band/channels. This is a preliminary patch to add hw scan support to mt7663e driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 72 +++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 9 ++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 6 ++ 4 files changed, 85 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 6586176c29af..20f6e31a017d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -50,6 +50,7 @@ static int mt7615_start(struct ieee80211_hw *hw) mt7615_mac_enable_nf(dev, 1); } + mt7615_mcu_set_channel_domain(phy); mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 32e3e4219076..9ce08be2f7c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -135,14 +135,21 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, mcu_txd->pkt_type = MCU_PKT_ID; mcu_txd->seq = seq; - if (cmd & MCU_FW_PREFIX) { + switch (cmd & ~MCU_CMD_MASK) { + case MCU_FW_PREFIX: mcu_txd->set_query = MCU_Q_NA; mcu_txd->cid = mcu_cmd; - } else { + break; + case MCU_CE_PREFIX: + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->cid = mcu_cmd; + break; + default: mcu_txd->cid = MCU_CMD_EXT_CID; mcu_txd->set_query = MCU_Q_SET; mcu_txd->ext_cid = cmd; mcu_txd->ext_cid_ack = 1; + break; } } @@ -2421,3 +2428,64 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req, sizeof(req), true); } + +int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) +{ + struct mt76_phy *mphy = phy->mt76; + struct mt7615_dev *dev = phy->dev; + struct mt7615_mcu_channel_domain { + __le32 country_code; /* regulatory_request.alpha2 */ + u8 bw_2g; /* BW_20_40M 0 + * BW_20M 1 + * BW_20_40_80M 2 + * BW_20_40_80_160M 3 + * BW_20_40_80_8080M 4 + */ + u8 bw_5g; + __le16 pad; + u8 n_2ch; + u8 n_5ch; + __le16 pad2; + } __packed hdr = { + .bw_2g = 0, + .bw_5g = 3, + .n_2ch = mphy->sband_2g.sband.n_channels, + .n_5ch = mphy->sband_5g.sband.n_channels, + }; + struct mt7615_mcu_chan { + __le16 hw_value; + __le16 pad; + __le32 flags; + } __packed; + int i, n_channels = hdr.n_2ch + hdr.n_5ch; + int len = sizeof(hdr) + n_channels * sizeof(struct mt7615_mcu_chan); + struct sk_buff *skb; + + if (!mt7615_firmware_offload(dev)) + return 0; + + skb = mt7615_mcu_msg_alloc(NULL, len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + + for (i = 0; i < n_channels; i++) { + struct ieee80211_channel *chan; + struct mt7615_mcu_chan channel; + + if (i < hdr.n_2ch) + chan = &mphy->sband_2g.sband.channels[i]; + else + chan = &mphy->sband_5g.sband.channels[i - hdr.n_2ch]; + + channel.hw_value = cpu_to_le16(chan->hw_value); + channel.flags = cpu_to_le32(chan->flags); + channel.pad = 0; + + skb_put_data(skb, &channel, sizeof(channel)); + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_CMD_SET_CHAN_DOMAIN, false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index d1f7391472fc..c03541328ad7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -232,7 +232,9 @@ enum { #define MCU_FW_PREFIX BIT(31) #define MCU_UNI_PREFIX BIT(30) -#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX) +#define MCU_CE_PREFIX BIT(29) +#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ + MCU_CE_PREFIX) enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, @@ -275,6 +277,11 @@ enum { MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, }; +/* offload mcu commands */ +enum { + MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, +}; + #define MCU_CMD_ACK BIT(0) #define MCU_CMD_UNI BIT(1) #define MCU_CMD_QUERY BIT(2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index e531c416f85d..c61dc2f54c52 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -366,6 +366,11 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) +{ + return dev->fw_ver > MT7615_FIRMWARE_V2; +} + void mt7615_update_channel(struct mt76_dev *mdev); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); @@ -395,6 +400,7 @@ int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq); +int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy); int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, -- cgit From daf250f89f4c5261997b76abc13323be0dc0205e Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 2 Apr 2020 15:06:37 +0200 Subject: mt76: mt7663: keep Rx filters as the default Keep Rx filters default value if the firmware supports offload and low power features. Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 8b7d8118d9ab..96b37f6ebf1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -22,7 +22,7 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) { - u32 val, mask, set; + u32 val; if (!chain) val = MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN; @@ -62,15 +62,19 @@ mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1)); - mask = MT_DMA_RCFR0_MCU_RX_MGMT | - MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR | - MT_DMA_RCFR0_MCU_RX_CTL_BAR | - MT_DMA_RCFR0_MCU_RX_BYPASS | - MT_DMA_RCFR0_RX_DROPPED_UCAST | - MT_DMA_RCFR0_RX_DROPPED_MCAST; - set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) | - FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); - mt76_rmw(dev, MT_DMA_RCFR0(chain), mask, set); + if (!mt7615_firmware_offload(dev)) { + u32 mask, set; + + mask = MT_DMA_RCFR0_MCU_RX_MGMT | + MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR | + MT_DMA_RCFR0_MCU_RX_CTL_BAR | + MT_DMA_RCFR0_MCU_RX_BYPASS | + MT_DMA_RCFR0_RX_DROPPED_UCAST | + MT_DMA_RCFR0_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) | + FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); + mt76_rmw(dev, MT_DMA_RCFR0(chain), mask, set); + } } static void mt7615_mac_init(struct mt7615_dev *dev) -- cgit From fcdfc29e58ee3b4db894f356fb6b12a6546f57bd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:38 +0200 Subject: mt76: mt7615: introduce hw scan support Introduce hw scan support to mt7663e driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 8 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 19 +++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 34 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 125 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 90 +++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 11 ++ 7 files changed, 285 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 6d60187e88ed..09f407cb1c48 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -275,6 +275,7 @@ enum { MT76_STATE_RUNNING, MT76_STATE_MCU_RUNNING, MT76_SCANNING, + MT76_HW_SCANNING, MT76_RESTART, MT76_RESET, MT76_MCU_RESET, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 96b37f6ebf1e..04bcc1a2aa8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -349,8 +349,13 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->reg_notifier = mt7615_regd_notifier; + wiphy->max_scan_ie_len = MT7615_SCAN_IE_LEN; + wiphy->max_scan_ssids = 4; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); if (is_mt7615(&phy->dev->mt76)) @@ -403,6 +408,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) if (phy) return 0; + INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); + mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); if (!mphy) @@ -459,6 +466,7 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); + INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e88914685807..d2319fb2f006 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -166,6 +166,20 @@ void mt7615_mac_set_timing(struct mt7615_phy *phy) } +static void +mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, + struct mt76_rx_status *status, u8 chfreq) +{ + if (!test_bit(MT76_HW_SCANNING, &mphy->state)) { + status->freq = mphy->chandef.chan->center_freq; + status->band = mphy->chandef.chan->band; + return; + } + + status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + status->freq = ieee80211_channel_to_frequency(chfreq, status->band); +} + int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -284,11 +298,10 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->ext_phy = true; } - if (chfreq != phy->chfreq) + if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq) return -EINVAL; - status->freq = mphy->chandef.chan->center_freq; - status->band = mphy->chandef.chan->band; + mt7615_get_status_freq_info(dev, mphy, status, chfreq); if (status->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 20f6e31a017d..6a7d802c69a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -77,6 +77,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + cancel_delayed_work_sync(&phy->scan_work); if (phy != &dev->phy) { mt7615_mcu_set_pm(dev, 1, 1); @@ -702,6 +703,37 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) return 0; } +void mt7615_scan_work(struct work_struct *work) +{ + struct cfg80211_scan_info info = { + .aborted = false, + }; + struct mt7615_phy *phy; + + phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, + scan_work.work); + + clear_bit(MT76_HW_SCANNING, &phy->mt76->state); + ieee80211_scan_completed(phy->mt76->hw, &info); +} + +static int +mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct mt76_phy *mphy = hw->priv; + + return mt7615_mcu_hw_scan(mphy->priv, vif, req); +} + +static void +mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_phy *mphy = hw->priv; + + mt7615_mcu_cancel_hw_scan(mphy->priv, vif); +} + const struct ieee80211_ops mt7615_ops = { .tx = mt7615_tx, .start = mt7615_start, @@ -731,6 +763,8 @@ const struct ieee80211_ops mt7615_ops = { .get_antenna = mt76_get_antenna, .set_antenna = mt7615_set_antenna, .set_coverage_class = mt7615_set_coverage_class, + .hw_scan = mt7615_hw_scan, + .cancel_hw_scan = mt7615_cancel_hw_scan, }; static int __init mt7615_init(void) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 9ce08be2f7c7..0db81ca9c730 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -317,6 +317,26 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) } } +static void +mt7615_mcu_scan_done_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; + struct mt7615_hw_scan_done *event; + struct mt7615_phy *phy; + struct mt76_phy *mphy; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7615_hw_scan_done *)skb->data; + if (event->seq_num & BIT(7) && dev->mt76.phy2) + mphy = dev->mt76.phy2; + else + mphy = &dev->mt76.phy; + + phy = (struct mt7615_phy *)mphy->priv; + ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, + MT7615_HW_SCAN_TIMEOUT); +} + static void mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) { @@ -326,6 +346,9 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7615_mcu_rx_ext_event(dev, skb); break; + case MCU_EVENT_SCAN_DONE: + mt7615_mcu_scan_done_event(dev, skb); + break; default: break; } @@ -340,6 +363,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + rxd->eid == MCU_EVENT_SCAN_DONE || !rxd->seq) mt7615_mcu_rx_unsolicited_event(dev, skb); else @@ -2489,3 +2513,104 @@ int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) return __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SET_CHAN_DOMAIN, false); } + +#define MT7615_SCAN_CHANNEL_TIME 120 +int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct cfg80211_scan_request *sreq = &scan_req->req; + int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); + struct ieee80211_channel **scan_list = sreq->channels; + int err, i, duration = MT7615_SCAN_CHANNEL_TIME; + struct mt7615_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + struct mt7615_mcu_scan_channel *chan; + struct mt7615_hw_scan_req *req; + struct sk_buff *skb; + + /* fall-back to sw-scan */ + if (!mt7615_firmware_offload(dev)) + return 1; + + skb = mt7615_mcu_msg_alloc(NULL, sizeof(*req)); + if (!skb) + return -ENOMEM; + + set_bit(MT76_HW_SCANNING, &phy->mt76->state); + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + req = (struct mt7615_hw_scan_req *)skb_put(skb, sizeof(*req)); + + req->seq_num = mvif->scan_seq_num | ext_phy << 7; + req->bss_idx = mvif->idx; + req->scan_type = 1; + req->ssid_type = 1; + req->probe_req_num = 2; + req->version = 1; + req->channel_type = 4; + + for (i = 0; i < sreq->n_ssids; i++) { + req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); + memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, + sreq->ssids[i].ssid_len); + } + + req->timeout_value = cpu_to_le16(sreq->n_channels * duration); + req->channel_min_dwell_time = cpu_to_le16(duration); + req->channel_dwell_time = cpu_to_le16(duration); + + req->channels_num = min_t(u8, sreq->n_channels, 32); + req->ext_channels_num = min_t(u8, ext_channels_num, 32); + for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { + if (i >= 32) + chan = &req->ext_channels[i - 32]; + else + chan = &req->channels[i]; + + chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + chan->channel_num = scan_list[i]->hw_value; + } + + if (sreq->ie_len > 0) { + memcpy(req->ies, sreq->ie, sreq->ie_len); + req->ies_len = cpu_to_le16(sreq->ie_len); + } + + memcpy(req->bssid, sreq->bssid, ETH_ALEN); + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(req->random_mac, sreq->mac_addr, + sreq->mac_addr_mask); + req->scan_func = 1; + } + + err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN, + false); + if (err < 0) + clear_bit(MT76_HW_SCANNING, &phy->mt76->state); + + return err; +} + +int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, + struct ieee80211_vif *vif) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = phy->dev; + struct cfg80211_scan_info info = { + .aborted = true, + }; + struct { + u8 seq_num; + u8 is_ext_channel; + u8 rsv[2]; + } __packed req = { + .seq_num = mvif->scan_seq_num, + }; + + ieee80211_scan_completed(phy->mt76->hw, &info); + clear_bit(MT76_HW_SCANNING, &phy->mt76->state); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, + sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index c03541328ad7..0ce709d2158f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -81,6 +81,7 @@ enum { MCU_EVENT_GENERIC = 0x01, MCU_EVENT_ACCESS_REG = 0x02, MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_CH_PRIVILEGE = 0x18, MCU_EVENT_EXT = 0xed, MCU_EVENT_RESTART_DL = 0xef, @@ -277,9 +278,98 @@ enum { MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, }; +struct mt7615_mcu_scan_ssid { + __le32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +} __packed; + +struct mt7615_mcu_scan_channel { + u8 band; /* 1: 2.4GHz + * 2: 5.0GHz + * Others: Reserved + */ + u8 channel_num; +} __packed; + +struct mt7615_hw_scan_req { + u8 seq_num; + u8 bss_idx; + u8 scan_type; /* 0: PASSIVE SCAN + * 1: ACTIVE SCAN + */ + u8 ssid_type; /* BIT(0) wildcard SSID + * BIT(1) P2P wildcard SSID + * BIT(2) specified SSID + */ + u8 ssids_num; + u8 probe_req_num; /* Number of probe request for each SSID */ + u8 scan_func; /* BIT(0) Enable random MAC scan + * BIT(1) Disable DBDC scan type 1~3. + * BIT(2) Use DBDC scan type 3 (dedicated one RF to scan). + */ + u8 version; /* 0: Not support fields after ies. + * 1: Support fields after ies. + */ + struct mt7615_mcu_scan_ssid ssids[4]; + __le16 probe_delay_time; + __le16 channel_dwell_time; /* channel Dwell interval */ + __le16 timeout_value; + u8 channel_type; /* 0: Full channels + * 1: Only 2.4GHz channels + * 2: Only 5GHz channels + * 3: P2P social channel only (channel #1, #6 and #11) + * 4: Specified channels + * Others: Reserved + */ + u8 channels_num; /* valid when channel_type is 4 */ + /* valid when channels_num is set */ + struct mt7615_mcu_scan_channel channels[32]; + __le16 ies_len; + u8 ies[MT7615_SCAN_IE_LEN]; + /* following fields are valid if version > 0 */ + u8 ext_channels_num; + u8 ext_ssids_num; + __le16 channel_min_dwell_time; + struct mt7615_mcu_scan_channel ext_channels[32]; + struct mt7615_mcu_scan_ssid ext_ssids[6]; + u8 bssid[ETH_ALEN]; + u8 random_mac[ETH_ALEN]; /* valid when BIT(1) in scan_func is set. */ + u8 pad[64]; +} __packed; + +#define SCAN_DONE_EVENT_MAX_CHANNEL_NUM 64 +struct mt7615_hw_scan_done { + u8 seq_num; + u8 sparse_channel_num; + struct mt7615_mcu_scan_channel sparse_channel; + u8 complete_channel_num; + u8 current_state; + u8 version; + u8 pad; + __le32 beacon_scan_num; + u8 pno_enabled; + u8 pad2[3]; + u8 sparse_channel_valid_num; + u8 pad3[3]; + u8 channel_num[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + /* idle format for channel_idle_time + * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) + * 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) + * 2: dwell time (16us) + */ + __le16 channel_idle_time[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + /* beacon and probe response count */ + u8 beacon_probe_num[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + u8 mdrdy_count[SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; + __le32 beacon_2g_num; + __le32 beacon_5g_num; +} __packed; + /* offload mcu commands */ enum { + MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, + MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, }; #define MCU_CMD_ACK BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index c61dc2f54c52..c2faa9ef654d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -18,6 +18,7 @@ MT7615_MAX_INTERFACES) #define MT7615_WATCHDOG_TIME (HZ / 10) +#define MT7615_HW_SCAN_TIMEOUT (HZ / 10) #define MT7615_RESET_TIMEOUT (30 * HZ) #define MT7615_RATE_RETRY 2 @@ -57,6 +58,8 @@ #define MT7615_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7615_SCAN_IE_LEN 600 + struct mt7615_vif; struct mt7615_sta; struct mt7615_dfs_pulse; @@ -108,6 +111,7 @@ struct mt7615_vif { u8 omac_idx; u8 band_idx; u8 wmm_idx; + u8 scan_seq_num; struct mt7615_sta sta; }; @@ -150,6 +154,8 @@ struct mt7615_phy { u32 ampdu_ref; struct mib_stats mib; + + struct delayed_work scan_work; }; #define mt7615_mcu_add_tx_ba(dev, ...) (dev)->mcu_ops->add_tx_ba((dev), __VA_ARGS__) @@ -371,6 +377,7 @@ static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) return dev->fw_ver > MT7615_FIRMWARE_V2; } +void mt7615_scan_work(struct work_struct *work); void mt7615_update_channel(struct mt76_dev *mdev); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); @@ -401,6 +408,10 @@ void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq); int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy); +int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req); +int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, + struct ieee80211_vif *vif); int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, -- cgit From 20305f98177432b48892d8add9cf6b05577b5d5d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:39 +0200 Subject: mt76: mt7615: introduce scheduled scan support Introduce scheduled scan support for mt7663e devices Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 7 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 55 ++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 110 +++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 35 +++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 10 ++ 7 files changed, 207 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 09f407cb1c48..ca7475a95356 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -276,6 +276,7 @@ enum { MT76_STATE_MCU_RUNNING, MT76_SCANNING, MT76_HW_SCANNING, + MT76_HW_SCHED_SCANNING, MT76_RESTART, MT76_RESET, MT76_MCU_RESET, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 04bcc1a2aa8f..f4775945e3d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -349,7 +349,12 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->reg_notifier = mt7615_regd_notifier; + wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL; + wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_scan_ie_len = MT7615_SCAN_IE_LEN; + wiphy->max_sched_scan_ssids = MT7615_MAX_SCHED_SCAN_SSID; + wiphy->max_match_sets = MT7615_MAX_SCAN_MATCH; + wiphy->max_sched_scan_reqs = 1; wiphy->max_scan_ssids = 4; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); @@ -409,6 +414,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) return 0; INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); + skb_queue_head_init(&phy->scan_event_list); mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); @@ -467,6 +473,7 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->mt76.phy.priv = &dev->phy; INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); + skb_queue_head_init(&dev->phy.scan_event_list); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d2319fb2f006..c9534fab2911 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -170,7 +170,8 @@ static void mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, struct mt76_rx_status *status, u8 chfreq) { - if (!test_bit(MT76_HW_SCANNING, &mphy->state)) { + if (!test_bit(MT76_HW_SCANNING, &mphy->state) && + !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) { status->freq = mphy->chandef.chan->center_freq; status->band = mphy->chandef.chan->band; return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 6a7d802c69a6..2c2d763b667c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -705,16 +705,36 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) void mt7615_scan_work(struct work_struct *work) { - struct cfg80211_scan_info info = { - .aborted = false, - }; struct mt7615_phy *phy; phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, scan_work.work); - clear_bit(MT76_HW_SCANNING, &phy->mt76->state); - ieee80211_scan_completed(phy->mt76->hw, &info); + while (true) { + struct mt7615_mcu_rxd *rxd; + struct sk_buff *skb; + + spin_lock_bh(&phy->dev->mt76.lock); + skb = __skb_dequeue(&phy->scan_event_list); + spin_unlock_bh(&phy->dev->mt76.lock); + + if (!skb) + break; + + rxd = (struct mt7615_mcu_rxd *)skb->data; + if (rxd->eid == MCU_EVENT_SCAN_DONE) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + clear_bit(MT76_HW_SCANNING, &phy->mt76->state); + ieee80211_scan_completed(phy->mt76->hw, &info); + } else { + clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); + ieee80211_sched_scan_results(phy->mt76->hw); + } + dev_kfree_skb(skb); + } } static int @@ -734,6 +754,29 @@ mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7615_mcu_cancel_hw_scan(mphy->priv, vif); } +static int +mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct mt76_phy *mphy = hw->priv; + int err; + + err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req); + if (err < 0) + return err; + + return mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); +} + +static int +mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_phy *mphy = hw->priv; + + return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); +} + const struct ieee80211_ops mt7615_ops = { .tx = mt7615_tx, .start = mt7615_start, @@ -765,6 +808,8 @@ const struct ieee80211_ops mt7615_ops = { .set_coverage_class = mt7615_set_coverage_class, .hw_scan = mt7615_hw_scan, .cancel_hw_scan = mt7615_cancel_hw_scan, + .sched_scan_start = mt7615_start_sched_scan, + .sched_scan_stop = mt7615_stop_sched_scan, }; static int __init mt7615_init(void) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 0db81ca9c730..193808cca905 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -318,21 +318,23 @@ mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) } static void -mt7615_mcu_scan_done_event(struct mt7615_dev *dev, struct sk_buff *skb) +mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) { - struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; - struct mt7615_hw_scan_done *event; + u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd); struct mt7615_phy *phy; struct mt76_phy *mphy; - skb_pull(skb, sizeof(*rxd)); - event = (struct mt7615_hw_scan_done *)skb->data; - if (event->seq_num & BIT(7) && dev->mt76.phy2) + if (*seq_num & BIT(7) && dev->mt76.phy2) mphy = dev->mt76.phy2; else mphy = &dev->mt76.phy; phy = (struct mt7615_phy *)mphy->priv; + + spin_lock_bh(&dev->mt76.lock); + __skb_queue_tail(&phy->scan_event_list, skb); + spin_unlock_bh(&dev->mt76.lock); + ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, MT7615_HW_SCAN_TIMEOUT); } @@ -346,9 +348,10 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7615_mcu_rx_ext_event(dev, skb); break; + case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: - mt7615_mcu_scan_done_event(dev, skb); - break; + mt7615_mcu_scan_event(dev, skb); + return; default: break; } @@ -363,6 +366,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_SCAN_DONE || !rxd->seq) mt7615_mcu_rx_unsolicited_event(dev, skb); @@ -2614,3 +2618,93 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, sizeof(req), false); } + +int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct ieee80211_channel **scan_list = sreq->channels; + struct mt7615_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + struct mt7615_mcu_scan_channel *chan; + struct mt7615_sched_scan_req *req; + struct cfg80211_match_set *match; + struct cfg80211_ssid *ssid; + struct sk_buff *skb; + int i; + + if (!mt7615_firmware_offload(dev)) + return -ENOTSUPP; + + skb = mt7615_mcu_msg_alloc(NULL, sizeof(*req) + sreq->ie_len); + if (!skb) + return -ENOMEM; + + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + req = (struct mt7615_sched_scan_req *)skb_put(skb, sizeof(*req)); + req->version = 1; + req->seq_num = mvif->scan_seq_num | ext_phy << 7; + req->scan_func = !!(sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR); + + req->ssids_num = sreq->n_ssids; + for (i = 0; i < req->ssids_num; i++) { + ssid = &sreq->ssids[i]; + memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); + req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); + } + + req->match_num = sreq->n_match_sets; + for (i = 0; i < req->match_num; i++) { + match = &sreq->match_sets[i]; + memcpy(req->match[i].ssid, match->ssid.ssid, + match->ssid.ssid_len); + req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); + req->match[i].ssid_len = match->ssid.ssid_len; + } + + req->channel_type = 4; + req->channels_num = min_t(u8, sreq->n_channels, 64); + for (i = 0; i < req->channels_num; i++) { + chan = &req->channels[i]; + chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; + chan->channel_num = scan_list[i]->hw_value; + } + + req->intervals_num = sreq->n_scan_plans; + for (i = 0; i < req->intervals_num; i++) + req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); + + if (sreq->ie_len > 0) { + req->ie_len = cpu_to_le16(sreq->ie_len); + memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_CMD_SCHED_SCAN_REQ, false); +} + +int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, + struct ieee80211_vif *vif, + bool enable) +{ + struct mt7615_dev *dev = phy->dev; + struct { + u8 active; /* 0: enabled 1: disabled */ + u8 rsv[3]; + } __packed req = { + .active = !enable, + }; + + if (!mt7615_firmware_offload(dev)) + return -ENOTSUPP; + + if (enable) + set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); + else + clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, + &req, sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 0ce709d2158f..7e55da2b6573 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -83,6 +83,7 @@ enum { MCU_EVENT_MT_PATCH_SEM = 0x04, MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_CH_PRIVILEGE = 0x18, + MCU_EVENT_SCHED_SCAN_DONE = 0x23, MCU_EVENT_EXT = 0xed, MCU_EVENT_RESTART_DL = 0xef, }; @@ -291,6 +292,13 @@ struct mt7615_mcu_scan_channel { u8 channel_num; } __packed; +struct mt7615_mcu_scan_match { + __le32 rssi_th; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + u8 rsv[3]; +} __packed; + struct mt7615_hw_scan_req { u8 seq_num; u8 bss_idx; @@ -365,11 +373,38 @@ struct mt7615_hw_scan_done { __le32 beacon_5g_num; } __packed; +struct mt7615_sched_scan_req { + u8 version; + u8 seq_num; + u8 stop_on_match; + u8 ssids_num; + u8 match_num; + u8 pad; + __le16 ie_len; + struct mt7615_mcu_scan_ssid ssids[MT7615_MAX_SCHED_SCAN_SSID]; + struct mt7615_mcu_scan_match match[MT7615_MAX_SCAN_MATCH]; + u8 channel_type; + u8 channels_num; + u8 intervals_num; + u8 scan_func; + struct mt7615_mcu_scan_channel channels[64]; + __le16 intervals[MT7615_MAX_SCHED_SCAN_INTERVAL]; + u8 pad2[64]; +} __packed; + +struct nt7615_sched_scan_done { + u8 seq_num; + u8 status; /* 0: ssid found */ + __le16 pad; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, + MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, + MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, }; #define MCU_CMD_ACK BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index c2faa9ef654d..9206157e255c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -59,6 +59,9 @@ #define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT7615_SCAN_IE_LEN 600 +#define MT7615_MAX_SCHED_SCAN_INTERVAL 10 +#define MT7615_MAX_SCHED_SCAN_SSID 10 +#define MT7615_MAX_SCAN_MATCH 16 struct mt7615_vif; struct mt7615_sta; @@ -155,6 +158,7 @@ struct mt7615_phy { struct mib_stats mib; + struct sk_buff_head scan_event_list; struct delayed_work scan_work; }; @@ -412,6 +416,12 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif); +int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq); +int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, + struct ieee80211_vif *vif, + bool enable); int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, -- cgit From bb366c5b88be7b96ba4ec09c9de3ca649c89c9d8 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 2 Apr 2020 15:06:40 +0200 Subject: mt76: mt7615: introduce BSS absence event Introduce BSS absence event that is reported when the fw is leaving or entering current operational channel. Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 8 ++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 193808cca905..5385d16e435d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -339,6 +339,26 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) MT7615_HW_SCAN_TIMEOUT); } +static void +mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_mcu_bss_event *event; + struct mt76_phy *mphy; + + event = (struct mt7615_mcu_bss_event *)(skb->data + + sizeof(struct mt7615_mcu_rxd)); + + if (event->bss_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + else + mphy = &dev->mt76.phy; + + if (event->is_absent) + ieee80211_stop_queues(mphy->hw); + else + ieee80211_wake_queues(mphy->hw); +} + static void mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) { @@ -352,6 +372,9 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) case MCU_EVENT_SCAN_DONE: mt7615_mcu_scan_event(dev, skb); return; + case MCU_EVENT_BSS_ABSENCE: + mt7615_mcu_bss_event(dev, skb); + break; default: break; } @@ -367,6 +390,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || + rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || !rxd->seq) mt7615_mcu_rx_unsolicited_event(dev, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 7e55da2b6573..e6a927fd209f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -82,6 +82,7 @@ enum { MCU_EVENT_ACCESS_REG = 0x02, MCU_EVENT_MT_PATCH_SEM = 0x04, MCU_EVENT_SCAN_DONE = 0x0d, + MCU_EVENT_BSS_ABSENCE = 0x11, MCU_EVENT_CH_PRIVILEGE = 0x18, MCU_EVENT_SCHED_SCAN_DONE = 0x23, MCU_EVENT_EXT = 0xed, @@ -398,6 +399,13 @@ struct nt7615_sched_scan_done { __le16 pad; } __packed; +struct mt7615_mcu_bss_event { + u8 bss_idx; + u8 is_absent; + u8 free_quota; + u8 pad; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, -- cgit From 5d3a4a4b57aa557d9d48bf2133fbd99f3bf1f354 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 15:06:41 +0200 Subject: mt76: mt7615: introduce rlm tlv in bss_info mcu command Introduce rlm tlv header in bss_info mcu command in order to inform the mcu about operating channel. Rlm header is necessary only if the mcu is running low power functionalities (e.g offloaded scan) Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 111 ++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- 4 files changed, 104 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 2c2d763b667c..c91f0896b09f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -410,15 +410,15 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, u32 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); mutex_lock(&dev->mt76.mutex); if (changed & BSS_CHANGED_ASSOC) - mt7615_mcu_add_bss_info(dev, vif, info->assoc); + mt7615_mcu_add_bss_info(phy, vif, info->assoc); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; - struct mt7615_phy *phy = mt7615_hw_phy(hw); if (slottime != phy->slottime) { phy->slottime = slottime; @@ -427,7 +427,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - mt7615_mcu_add_bss_info(dev, vif, info->enable_beacon); + mt7615_mcu_add_bss_info(phy, vif, info->enable_beacon); mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 5385d16e435d..9bb65de0cc64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -967,10 +967,11 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } static int -mt7615_mcu_add_bss(struct mt7615_dev *dev, struct ieee80211_vif *vif, +mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = phy->dev; struct sk_buff *skb; skb = mt7615_mcu_alloc_sta_req(mvif, NULL); @@ -1244,12 +1245,15 @@ mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) } static int -mt7615_mcu_uni_add_bss(struct mt7615_dev *dev, +mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; + struct mt7615_dev *dev = phy->dev; struct { - struct req_hdr { + struct { u8 bss_idx; u8 pad[3]; } __packed hdr; @@ -1267,12 +1271,18 @@ mt7615_mcu_uni_add_bss(struct mt7615_dev *dev, __le16 bmc_tx_wlan_idx; __le16 bcn_interval; u8 dtim_period; - u8 phymode; + u8 phymode; /* bit(0): A + * bit(1): B + * bit(2): G + * bit(3): GN + * bit(4): AN + * bit(5): AC + */ __le16 sta_idx; u8 nonht_basic_phy; u8 pad[3]; } __packed basic; - } req = { + } basic_req = { .hdr = { .bss_idx = mvif->idx, }, @@ -1285,17 +1295,53 @@ mt7615_mcu_uni_add_bss(struct mt7615_dev *dev, .band_idx = mvif->band_idx, .wmm_idx = mvif->wmm_idx, .active = enable, + .phymode = 0x38, + }, + }; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct rlm_tlv { + __le16 tag; + __le16 len; + u8 control_channel; + u8 center_chan; + u8 center_chan2; + u8 bw; + u8 tx_streams; + u8 rx_streams; + u8 short_st; + u8 ht_op_info; + u8 sco; + u8 pad[3]; + } __packed rlm; + } __packed rlm_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .rlm = { + .tag = cpu_to_le16(UNI_BSS_INFO_RLM), + .len = cpu_to_le16(sizeof(struct rlm_tlv)), + .control_channel = chandef->chan->hw_value, + .center_chan = ieee80211_frequency_to_channel(freq1), + .center_chan2 = ieee80211_frequency_to_channel(freq2), + .tx_streams = hweight8(phy->mt76->antenna_mask), + .rx_streams = phy->chainmask, + .short_st = true, }, }; u8 idx, tx_wlan_idx = 0; + int err; idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; - req.basic.hw_bss_idx = idx; + basic_req.basic.hw_bss_idx = idx; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: - req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); tx_wlan_idx = mvif->sta.wcid.idx; break; case NL80211_IFTYPE_STATION: @@ -1314,20 +1360,59 @@ mt7615_mcu_uni_add_bss(struct mt7615_dev *dev, tx_wlan_idx = msta->wcid.idx; rcu_read_unlock(); } - req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); break; default: WARN_ON(1); break; } - memcpy(req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); - req.basic.bmc_tx_wlan_idx = cpu_to_le16(tx_wlan_idx); - req.basic.sta_idx = cpu_to_le16(tx_wlan_idx); - req.basic.conn_state = !enable; + memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); + basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(tx_wlan_idx); + basic_req.basic.sta_idx = cpu_to_le16(tx_wlan_idx); + basic_req.basic.conn_state = !enable; + + err = __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, + &basic_req, sizeof(basic_req), true); + if (err < 0) + return err; + + if (!mt7615_firmware_offload(dev)) + return 0; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + rlm_req.rlm.bw = CMD_CBW_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + rlm_req.rlm.bw = CMD_CBW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + rlm_req.rlm.bw = CMD_CBW_8080MHZ; + break; + case NL80211_CHAN_WIDTH_160: + rlm_req.rlm.bw = CMD_CBW_160MHZ; + break; + case NL80211_CHAN_WIDTH_5: + rlm_req.rlm.bw = CMD_CBW_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + rlm_req.rlm.bw = CMD_CBW_10MHZ; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + default: + rlm_req.rlm.bw = CMD_CBW_20MHZ; + break; + } + + if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) + rlm_req.rlm.sco = 1; /* SCA */ + else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) + rlm_req.rlm.sco = 3; /* SCB */ return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, - &req, sizeof(req), true); + &rlm_req, sizeof(rlm_req), true); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index e6a927fd209f..43c13a47cea2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -423,6 +423,7 @@ enum { enum { UNI_BSS_INFO_BASIC = 0, + UNI_BSS_INFO_RLM = 2, UNI_BSS_INFO_BCN_CONTENT = 7, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 9206157e255c..a0ddb35b5e26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -166,7 +166,7 @@ struct mt7615_phy { #define mt7615_mcu_add_rx_ba(dev, ...) (dev)->mcu_ops->add_rx_ba((dev), __VA_ARGS__) #define mt7615_mcu_sta_add(dev, ...) (dev)->mcu_ops->sta_add((dev), __VA_ARGS__) #define mt7615_mcu_add_dev_info(dev, ...) (dev)->mcu_ops->add_dev_info((dev), __VA_ARGS__) -#define mt7615_mcu_add_bss_info(dev, ...) (dev)->mcu_ops->add_bss_info((dev), __VA_ARGS__) +#define mt7615_mcu_add_bss_info(phy, ...) (phy->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__) #define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__) #define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__) struct mt7615_mcu_ops { @@ -181,7 +181,7 @@ struct mt7615_mcu_ops { struct ieee80211_sta *sta, bool enable); int (*add_dev_info)(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); - int (*add_bss_info)(struct mt7615_dev *dev, struct ieee80211_vif *vif, + int (*add_bss_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable); int (*add_beacon_offload)(struct mt7615_dev *dev, struct ieee80211_hw *hw, -- cgit From 34cdf1a618eb071a62362eb79428835167630531 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 2 Apr 2020 15:06:42 +0200 Subject: mt76: mt7615: remove unnecessary register operations Remove mt76_wr(dev, MT_CSR(0x010), 0x8208) that would cause MT_PCIE_IRQ_ENABLE to be disabled; MT_PCIE_IRQ_ENABLE should always keep on enabled when the driver is running. 0x44064 is a not existing address Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index f4775945e3d7..be0f3a77e22f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -117,8 +117,6 @@ static void mt7615_mac_init(struct mt7615_dev *dev) FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) | MT_DMA_DCR0_RX_VEC_DROP); if (is_mt7663(&dev->mt76)) { - mt76_wr(dev, MT_CSR(0x010), 0x8208); - mt76_wr(dev, 0x44064, 0x2000000); mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02); mt76_wr(dev, MT_WF_AGG(0x164), 0x70708040); } else { -- cgit From bb31a80eb2b36cccf5d72b616381aff650ac3961 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:48 +0200 Subject: mt76: add headroom and tailroom to mt76_mcu_ops data structure Introduce headroom and tailroom to mt76_mcu_ops data structure in order to unify the routine used for mcu message allocation. This is a preliminary patch to add mt7663u support Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mcu.c | 9 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 7 ++- drivers/net/wireless/mediatek/mt76/mt7603/mcu.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7603/mcu.h | 7 --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 63 ++++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 7 --- drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h | 6 --- .../net/wireless/mediatek/mt76/mt76x02_usb_mcu.c | 4 +- 9 files changed, 51 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 4048f446e3ee..ade61a5334c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -6,10 +6,11 @@ #include "mt76.h" struct sk_buff * -mt76_mcu_msg_alloc(const void *data, int head_len, - int data_len, int tail_len) +mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, + int data_len) { - int length = head_len + data_len + tail_len; + const struct mt76_mcu_ops *ops = dev->mcu_ops; + int length = ops->headroom + data_len + ops->tailroom; struct sk_buff *skb; skb = alloc_skb(length, GFP_KERNEL); @@ -17,7 +18,7 @@ mt76_mcu_msg_alloc(const void *data, int head_len, return NULL; memset(skb->head, 0, length); - skb_reserve(skb, head_len); + skb_reserve(skb, ops->headroom); if (data && data_len) skb_put_data(skb, data, data_len); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ca7475a95356..e31d98a4f88f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -137,6 +137,9 @@ struct mt76_sw_queue { }; struct mt76_mcu_ops { + u32 headroom; + u32 tailroom; + int (*mcu_send_msg)(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp); int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, @@ -914,8 +917,8 @@ int mt76u_resume_rx(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); struct sk_buff * -mt76_mcu_msg_alloc(const void *data, int head_len, - int data_len, int tail_len); +mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, + int data_len); void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb); struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, unsigned long expires); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c index 77985d81c447..a47a3a644ecc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c @@ -62,7 +62,7 @@ mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, struct sk_buff *skb; int ret, seq; - skb = mt7603_mcu_msg_alloc(data, len); + skb = mt76_mcu_msg_alloc(mdev, data, len); if (!skb) return -ENOMEM; @@ -265,6 +265,7 @@ out: int mt7603_mcu_init(struct mt7603_dev *dev) { static const struct mt76_mcu_ops mt7603_mcu_ops = { + .headroom = sizeof(struct mt7603_mcu_txd), .mcu_send_msg = mt7603_mcu_msg_send, .mcu_restart = mt7603_mcu_restart, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.h index 1bba369d5c8a..30df8a3fd11a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.h @@ -100,11 +100,4 @@ enum { MCU_EXT_EVENT_BCN_UPDATE = 0x31, }; -static inline struct sk_buff * -mt7603_mcu_msg_alloc(const void *data, int len) -{ - return mt76_mcu_msg_alloc(data, sizeof(struct mt7603_mcu_txd), - len, 0); -} - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 9bb65de0cc64..12759158e69a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -244,7 +244,7 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, { struct sk_buff *skb; - skb = mt7615_mcu_msg_alloc(data, len); + skb = mt76_mcu_msg_alloc(mdev, data, len); if (!skb) return -ENOMEM; @@ -552,7 +552,8 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) } static struct sk_buff * -mt7615_mcu_alloc_sta_req(struct mt7615_vif *mvif, struct mt7615_sta *msta) +mt7615_mcu_alloc_sta_req(struct mt7615_dev *dev, struct mt7615_vif *mvif, + struct mt7615_sta *msta) { struct sta_req_hdr hdr = { .bss_idx = mvif->idx, @@ -562,7 +563,7 @@ mt7615_mcu_alloc_sta_req(struct mt7615_vif *mvif, struct mt7615_sta *msta) }; struct sk_buff *skb; - skb = mt7615_mcu_msg_alloc(NULL, MT7615_STA_UPDATE_MAX_SIZE); + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, MT7615_STA_UPDATE_MAX_SIZE); if (!skb) return ERR_PTR(-ENOMEM); @@ -572,8 +573,8 @@ mt7615_mcu_alloc_sta_req(struct mt7615_vif *mvif, struct mt7615_sta *msta) } static struct wtbl_req_hdr * -mt7615_mcu_alloc_wtbl_req(struct mt7615_sta *msta, int cmd, - void *sta_wtbl, struct sk_buff **skb) +mt7615_mcu_alloc_wtbl_req(struct mt7615_dev *dev, struct mt7615_sta *msta, + int cmd, void *sta_wtbl, struct sk_buff **skb) { struct tlv *sta_hdr = sta_wtbl; struct wtbl_req_hdr hdr = { @@ -583,7 +584,8 @@ mt7615_mcu_alloc_wtbl_req(struct mt7615_sta *msta, int cmd, struct sk_buff *nskb = *skb; if (!nskb) { - nskb = mt7615_mcu_msg_alloc(NULL, MT7615_WTBL_UPDATE_BA_SIZE); + nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + MT7615_WTBL_UPDATE_BA_SIZE); if (!nskb) return ERR_PTR(-ENOMEM); @@ -974,7 +976,7 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct mt7615_dev *dev = phy->dev; struct sk_buff *skb; - skb = mt7615_mcu_alloc_sta_req(mvif, NULL); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, NULL); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1001,7 +1003,7 @@ mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev, struct sk_buff *skb = NULL; int err; - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, NULL, &skb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); @@ -1012,7 +1014,7 @@ mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev, if (err < 0) return err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1033,7 +1035,7 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, struct sk_buff *skb; int err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1045,7 +1047,7 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, return err; skb = NULL; - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, NULL, &skb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); @@ -1067,7 +1069,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; - sskb = mt7615_mcu_alloc_sta_req(mvif, msta); + sskb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(sskb)) return PTR_ERR(sskb); @@ -1075,8 +1077,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, if (enable && sta) mt7615_mcu_sta_ht_tlv(sskb, sta); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_RESET_AND_SET, NULL, - &wskb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, + NULL, &wskb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); @@ -1120,7 +1122,7 @@ mt7615_mcu_sta_ba(struct mt7615_dev *dev, struct tlv *sta_wtbl; struct sk_buff *skb; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1128,7 +1130,8 @@ mt7615_mcu_sta_ba(struct mt7615_dev *dev, sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); mt7615_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); return __mt76_mcu_skb_send_msg(&dev->mt76, skb, @@ -1163,7 +1166,7 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1173,7 +1176,7 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_RESET_AND_SET, + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, sta_wtbl, &skb); if (enable) { mt7615_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); @@ -1499,13 +1502,14 @@ mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, struct sk_buff *skb; int err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); @@ -1517,7 +1521,7 @@ mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, if (err < 0) return err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1539,7 +1543,7 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, struct sk_buff *skb; int err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1550,13 +1554,14 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, if (err < 0 || !enable) return err; - skb = mt7615_mcu_alloc_sta_req(mvif, msta); + skb = mt7615_mcu_alloc_sta_req(dev, mvif, msta); if (IS_ERR(skb)) return PTR_ERR(skb); sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); - wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb); + wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); @@ -2114,6 +2119,7 @@ static int mt7663_load_firmware(struct mt7615_dev *dev) int mt7615_mcu_init(struct mt7615_dev *dev) { static const struct mt76_mcu_ops mt7615_mcu_ops = { + .headroom = sizeof(struct mt7615_mcu_txd), .mcu_skb_send_msg = mt7615_mcu_send_message, .mcu_send_msg = mt7615_mcu_msg_send, .mcu_restart = mt7615_mcu_restart, @@ -2186,7 +2192,7 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) req_hdr.len = cpu_to_le16(eep_len); - skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + eep_len); + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len); if (!skb) return -ENOMEM; @@ -2601,7 +2607,7 @@ int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) if (!mt7615_firmware_offload(dev)) return 0; - skb = mt7615_mcu_msg_alloc(NULL, len); + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; @@ -2646,7 +2652,7 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (!mt7615_firmware_offload(dev)) return 1; - skb = mt7615_mcu_msg_alloc(NULL, sizeof(*req)); + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(*req)); if (!skb) return -ENOMEM; @@ -2746,7 +2752,8 @@ int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, if (!mt7615_firmware_offload(dev)) return -ENOTSUPP; - skb = mt7615_mcu_msg_alloc(NULL, sizeof(*req) + sreq->ie_len); + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(*req) + sreq->ie_len); if (!skb) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 43c13a47cea2..69cb68d6465d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -845,11 +845,4 @@ enum { CH_SWITCH_SCAN_BYPASS_DPD = 9 }; -static inline struct sk_buff * -mt7615_mcu_msg_alloc(const void *data, int len) -{ - return mt76_mcu_msg_alloc(data, sizeof(struct mt7615_mcu_txd), - len, 0); -} - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 8247611d9b18..89a8992d84fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -23,7 +23,7 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, if (mt76_is_mmio(&dev->mt76) && dev->mcu_timeout) return -EIO; - skb = mt76x02_mcu_msg_alloc(data, len); + skb = mt76_mcu_msg_alloc(mdev, data, len); if (!skb) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index c81a9655c4c9..5fba1266c648 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -85,12 +85,6 @@ struct mt76x02_patch_header { u8 pad[2]; }; -static inline struct sk_buff * -mt76x02_mcu_msg_alloc(const void *data, int len) -{ - return mt76_mcu_msg_alloc(data, 0, len, 0); -} - int mt76x02_mcu_cleanup(struct mt76x02_dev *dev); int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param); int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 843b86560ed4..a30bb536fc8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -123,7 +123,7 @@ mt76x02u_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, struct sk_buff *skb; int err; - skb = mt76_mcu_msg_alloc(data, MT_CMD_HDR_LEN, len, 8); + skb = mt76_mcu_msg_alloc(dev, data, len); if (!skb) return -ENOMEM; @@ -291,6 +291,8 @@ EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data); void mt76x02u_init_mcu(struct mt76_dev *dev) { static const struct mt76_mcu_ops mt76x02u_mcu_ops = { + .headroom = MT_CMD_HDR_LEN, + .tailroom = 8, .mcu_send_msg = mt76x02u_mcu_send_msg, .mcu_wr_rp = mt76x02u_mcu_wr_rp, .mcu_rd_rp = mt76x02u_mcu_rd_rp, -- cgit From d4bf77bd749300123481a22df82b8ab618844153 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:49 +0200 Subject: mt76: mt7615: introduce mt7663u support to mt7615_write_txwi Extend mt7615_write_txwi routine to support usb txwi configuration Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 12 ++++++++---- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index c9534fab2911..dafd47cc7f6a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -528,11 +528,12 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->mphy; bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + bool is_usb = mt76_is_usb(&dev->mt76); int tx_count = 8; u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; __le16 fc = hdr->frame_control; + u32 val, sz_txd = is_usb ? MT_USB_TXD_SIZE : MT_TXD_SIZE; u16 seqno = 0; - u32 val; if (vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; @@ -556,7 +557,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { q_idx = wmm_idx * MT7615_MAX_WMM_SETS + skb_get_queue_mapping(skb); - p_fmt = MT_TX_TYPE_CT; + p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; } else if (beacon) { if (ext_phy) q_idx = MT_LMAC_BCN1; @@ -568,10 +569,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, q_idx = MT_LMAC_ALTX1; else q_idx = MT_LMAC_ALTX0; - p_fmt = MT_TX_TYPE_CT; + p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; } - val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); @@ -665,6 +666,9 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + if (is_usb) + txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | + FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index e0b89257db90..422a140fd812 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -165,6 +165,7 @@ enum tx_phy_bandwidth { #define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) #define MT_CT_INFO_HSR2_TX BIT(4) +#define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) #define MT_TXD_SIZE (8 * 4) #define MT_TXD0_P_IDX BIT(31) -- cgit From 8f93af9cac300e063e7a66447e29810e9f44eabf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:50 +0200 Subject: mt76: mt7615: introduce mt7615_mac_update_rate_desc routine Move register configuration out of mt7615_mac_set_rates since usb driver can't access device register in interrupt context. Introduce mt7615_mac_update_rate_desc routine to report rate info to mt7615_mac_set_rates Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 102 ++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 12 +++ 2 files changed, 71 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index dafd47cc7f6a..6c8a479a3a11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -813,26 +813,19 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev) rcu_read_unlock(); } -void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, - struct ieee80211_tx_rate *probe_rate, - struct ieee80211_tx_rate *rates) +static void +mt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, + struct ieee80211_tx_rate *probe_rate, + struct ieee80211_tx_rate *rates, + struct mt7615_rate_desc *rd) { struct mt7615_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_tx_rate *ref; - int wcid = sta->wcid.idx; - u32 addr = mt7615_mac_wtbl_addr(dev, wcid); - bool stbc = false; + bool rateset, stbc = false; int n_rates = sta->n_rates; - u8 bw, bw_prev, bw_idx = 0; - u16 val[4]; - u16 probe_val; - u32 w5, w27; - bool rateset; - int i, k; - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) - return; + u8 bw, bw_prev; + int i, j; for (i = n_rates; i < 4; i++) rates[i] = rates[n_rates - 1]; @@ -860,10 +853,10 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; - for (k = 0; k < i; k++) { - if (rates[i].idx != rates[k].idx) + for (j = 0; j < i; j++) { + if (rates[i].idx != rates[j].idx) continue; - if ((rates[i].flags ^ rates[k].flags) & + if ((rates[i].flags ^ rates[j].flags) & (IEEE80211_TX_RC_40_MHZ_WIDTH | IEEE80211_TX_RC_80_MHZ_WIDTH | IEEE80211_TX_RC_160_MHZ_WIDTH)) @@ -876,65 +869,87 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, } } - val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw); + rd->val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw); bw_prev = bw; if (probe_rate) { - probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate, - stbc, &bw); + rd->probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate, + stbc, &bw); if (bw) - bw_idx = 1; + rd->bw_idx = 1; else bw_prev = 0; } else { - probe_val = val[0]; + rd->probe_val = rd->val[0]; } - val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw); + rd->val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw); if (bw_prev) { - bw_idx = 3; + rd->bw_idx = 3; bw_prev = bw; } - val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw); + rd->val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw); if (bw_prev) { - bw_idx = 5; + rd->bw_idx = 5; bw_prev = bw; } - val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw); + rd->val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw); if (bw_prev) - bw_idx = 7; + rd->bw_idx = 7; + + rd->rateset = rateset; + rd->sta = sta; + rd->bw = bw; +} + +void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, + struct ieee80211_tx_rate *probe_rate, + struct ieee80211_tx_rate *rates) +{ + int wcid = sta->wcid.idx, n_rates = sta->n_rates; + struct mt7615_dev *dev = phy->dev; + struct mt7615_rate_desc rd; + u32 w5, w27, addr; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return; + + memset(&rd, 0, sizeof(struct mt7615_rate_desc)); + mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &rd); + addr = mt7615_mac_wtbl_addr(dev, wcid); w27 = mt76_rr(dev, addr + 27 * 4); w27 &= ~MT_WTBL_W27_CC_BW_SEL; - w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw); + w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rd.bw); w5 = mt76_rr(dev, addr + 5 * 4); w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | MT_WTBL_W5_MPDU_OK_COUNT | MT_WTBL_W5_MPDU_FAIL_COUNT | MT_WTBL_W5_RATE_IDX); - w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) | - FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7); + w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rd.bw) | + FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, + rd.bw_idx ? rd.bw_idx - 1 : 7); mt76_wr(dev, MT_WTBL_RIUCR0, w5); mt76_wr(dev, MT_WTBL_RIUCR1, - FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1])); + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rd.probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rd.val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rd.val[1])); mt76_wr(dev, MT_WTBL_RIUCR2, - FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rd.val[1] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rd.val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rd.val[2]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rd.val[2])); mt76_wr(dev, MT_WTBL_RIUCR3, - FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rd.val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rd.val[3]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rd.val[3])); mt76_wr(dev, MT_WTBL_UPDATE, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | @@ -944,7 +959,8 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, mt76_wr(dev, addr + 27 * 4, w27); mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ - sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset; + sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0); + sta->rate_set_tsf |= rd.rateset; if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index a0ddb35b5e26..23c7e35e93c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -90,6 +90,18 @@ struct mt7615_rate_set { struct ieee80211_tx_rate rates[4]; }; +struct mt7615_rate_desc { + struct list_head node; + + struct mt7615_sta *sta; + + bool rateset; + u16 probe_val; + u16 val[4]; + u8 bw_idx; + u8 bw; +}; + struct mt7615_sta { struct mt76_wcid wcid; /* must be first */ -- cgit From 8915c3ceb92948a158bbce6060794b3500a006c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:51 +0200 Subject: mt76: mt7615: introduce __mt7663_load_firmware routine Introduce __mt7663_load_firmware routine to load firmware for usb devices. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 22 +++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 12759158e69a..dcd97606e827 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2078,12 +2078,10 @@ out: return ret; } -static int mt7663_load_firmware(struct mt7615_dev *dev) +int __mt7663_load_firmware(struct mt7615_dev *dev) { int ret; - mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); - ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); if (ret) { dev_dbg(dev->mt76.dev, "Firmware is already download\n"); @@ -2109,12 +2107,26 @@ static int mt7663_load_firmware(struct mt7615_dev *dev) return -EIO; } - mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); - dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; } +EXPORT_SYMBOL_GPL(__mt7663_load_firmware); + +static int mt7663_load_firmware(struct mt7615_dev *dev) +{ + int ret; + + mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); + + return 0; +} int mt7615_mcu_init(struct mt7615_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 23c7e35e93c0..d0b5c704f61c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -462,5 +462,6 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); +int __mt7663_load_firmware(struct mt7615_dev *dev); #endif -- cgit From d506017ed4854963e967d4017be33a4cc5e1285b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:52 +0200 Subject: mt76: mt7615: move mt7615_mac_wtbl_addr in mac.h Move mt7615_mac_wtbl_addr in mac.h and add inline qualifier in order to be reused adding usb support to mt7615 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 ----- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 6c8a479a3a11..6800ca3706bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -723,11 +723,6 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev, mt7615_txp_skb_unmap_hw(dev, &txp->hw); } -static u32 mt7615_mac_wtbl_addr(struct mt7615_dev *dev, int wcid) -{ - return MT_WTBL_BASE(dev) + wcid * MT_WTBL_ENTRY_SIZE; -} - bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 422a140fd812..2c368b99cc0c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -407,4 +407,9 @@ mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) return (struct mt7615_txp_common *)(txwi + MT_TXD_SIZE); } +static inline u32 mt7615_mac_wtbl_addr(struct mt7615_dev *dev, int wcid) +{ + return MT_WTBL_BASE(dev) + wcid * MT_WTBL_ENTRY_SIZE; +} + #endif -- cgit From 3a1880565aaf71818310a42fb2e2e11801d5111d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:53 +0200 Subject: mt76: mt76u: rely on mt7622 queue scheme for mt7663u Rely on the mt7622 endpoint definitions for mt7663u Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index a981da6c35a5..fb97ea25b4d4 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -1009,8 +1009,19 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) { - if (mt76_chip(dev) == 0x7663) - return ac ^ 0x3; + if (mt76_chip(dev) == 0x7663) { + static const u8 wmm_queue_map[] = { + [IEEE80211_AC_VO] = 0, + [IEEE80211_AC_VI] = 1, + [IEEE80211_AC_BE] = 2, + [IEEE80211_AC_BK] = 4, + }; + + if (WARN_ON(ac >= ARRAY_SIZE(wmm_queue_map))) + return 2; /* BE */ + + return wmm_queue_map[ac]; + } return mt76_ac_to_hwq(ac); } -- cgit From 294f17aea22aeb236cefdc9d7bd8af536291a7f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:54 +0200 Subject: mt76: mt7615: rework wtbl key configuration Remove key dependency from mt7615_mac_wtbl_update_key and export mt7615_mac_wtbl_update_key, mt7615_mac_wtbl_update_pk and mt7615_mac_wtbl_update_cipher in order to reuse them in usb code. Move mt7615_mac_get_cipher in mac.h Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 69 ++++++++-------------- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 27 +++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 14 +++++ 3 files changed, 64 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 6800ca3706bd..f2bee76b8c29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -964,58 +964,31 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; } -static enum mt7615_cipher_type -mt7615_mac_get_cipher(int cipher) -{ - switch (cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; - case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; - case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; - case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; - default: - return MT_CIPHER_NONE; - } -} - -static int -mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, - struct ieee80211_key_conf *key, - enum mt7615_cipher_type cipher, - enum set_key_cmd cmd) +int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + u8 *key, u8 keylen, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; u8 data[32] = {}; - if (key->keylen > sizeof(data)) + if (keylen > sizeof(data)) return -EINVAL; mt76_rr_copy(dev, addr, data, sizeof(data)); if (cmd == SET_KEY) { if (cipher == MT_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ - memcpy(data + 16, key->key + 24, 8); - memcpy(data + 24, key->key + 16, 8); + memcpy(data + 16, key + 24, 8); + memcpy(data + 24, key + 16, 8); } if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher) memmove(data + 16, data, 16); if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher) - memcpy(data, key->key, key->keylen); + memcpy(data, key, keylen); else if (cipher == MT_CIPHER_BIP_CMAC_128) - memcpy(data + 16, key->key, 16); + memcpy(data + 16, key, 16); } else { if (wcid->cipher & ~BIT(cipher)) { if (cipher != MT_CIPHER_BIP_CMAC_128) @@ -1029,11 +1002,12 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, return 0; } +EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_key); -static int -mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, int keyidx, - enum set_key_cmd cmd) +int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, + int keyidx, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; @@ -1065,11 +1039,12 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, return 0; } +EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_pk); -static void -mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, - enum set_key_cmd cmd) +void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); @@ -1087,6 +1062,7 @@ mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE); } } +EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_cipher); int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, @@ -1103,7 +1079,8 @@ int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, spin_lock_bh(&dev->mt76.lock); mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd); - err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cmd); + err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, + cipher, cmd); if (err < 0) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 2c368b99cc0c..f3e0070896a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -394,6 +394,33 @@ enum mt7615_cipher_type { MT_CIPHER_GCMP_256, }; +static inline enum mt7615_cipher_type +mt7615_mac_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + static inline struct mt7615_txp_common * mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d0b5c704f61c..ed34b9a0e04c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -67,6 +67,7 @@ struct mt7615_vif; struct mt7615_sta; struct mt7615_dfs_pulse; struct mt7615_dfs_pattern; +enum mt7615_cipher_type; enum mt7615_hw_txq_id { MT7615_TXQ_MAIN, @@ -412,6 +413,19 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb); int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, enum set_key_cmd cmd); +int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, + int keyidx, enum set_key_cmd cmd); +void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd); +int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + u8 *key, u8 keylen, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd); void mt7615_mac_reset_work(struct work_struct *work); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); -- cgit From 7d9f1d108c3a05905ecefaff058c5688458f2f48 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:55 +0200 Subject: mt76: mt7615: introduce mt7615_wtbl_desc data structure Generalize mt7615_rate_desc introducing mt7615_wtbl_desc and mt7615_key_desc data structures in order to configure the hw wtbl in a non-atomic context for usb devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 1 - drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 29 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f2bee76b8c29..ed6eb19f48c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -895,7 +895,6 @@ mt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, rd->bw_idx = 7; rd->rateset = rateset; - rd->sta = sta; rd->bw = bw; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index ed34b9a0e04c..f3c912672a6c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -92,10 +92,6 @@ struct mt7615_rate_set { }; struct mt7615_rate_desc { - struct list_head node; - - struct mt7615_sta *sta; - bool rateset; u16 probe_val; u16 val[4]; @@ -103,6 +99,31 @@ struct mt7615_rate_desc { u8 bw; }; +enum mt7615_wtbl_desc_type { + MT7615_WTBL_RATE_DESC, + MT7615_WTBL_KEY_DESC +}; + +struct mt7615_key_desc { + enum set_key_cmd cmd; + u32 cipher; + s8 keyidx; + u8 keylen; + u8 *key; +}; + +struct mt7615_wtbl_desc { + struct list_head node; + + enum mt7615_wtbl_desc_type type; + struct mt7615_sta *sta; + + union { + struct mt7615_rate_desc rate; + struct mt7615_key_desc key; + }; +}; + struct mt7615_sta { struct mt76_wcid wcid; /* must be first */ -- cgit From 6e5d2099a483c4ab3557d23e0c5c89ff7bd7b0a8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 2 Apr 2020 20:18:56 +0200 Subject: mt76: mt7615: add address parameter to mt7615_eeprom_init Introduce address parameter to mt7615_eeprom_init routine in order to be reused adding usb support to mt7615 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index dfa9a08b896d..23ed20553de2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -40,11 +40,11 @@ static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base, return 0; } -static int mt7615_efuse_init(struct mt7615_dev *dev) +static int mt7615_efuse_init(struct mt7615_dev *dev, u32 base) { - u32 val, base = mt7615_reg_map(dev, MT_EFUSE_BASE); int i, len = MT7615_EEPROM_SIZE; void *buf; + u32 val; val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL); if (val & MT_EFUSE_BASE_CTRL_EMPTY) @@ -67,7 +67,7 @@ static int mt7615_efuse_init(struct mt7615_dev *dev) return 0; } -static int mt7615_eeprom_load(struct mt7615_dev *dev) +static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr) { int ret; @@ -75,7 +75,7 @@ static int mt7615_eeprom_load(struct mt7615_dev *dev) if (ret < 0) return ret; - return mt7615_efuse_init(dev); + return mt7615_efuse_init(dev, addr); } static int mt7615_check_eeprom(struct mt76_dev *dev) @@ -265,11 +265,11 @@ static void mt7615_cal_free_data(struct mt7615_dev *dev) } } -int mt7615_eeprom_init(struct mt7615_dev *dev) +int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr) { int ret; - ret = mt7615_eeprom_load(dev); + ret = mt7615_eeprom_load(dev, addr); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index be0f3a77e22f..6acaaf2732df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -146,6 +146,7 @@ static void mt7615_init_work(struct work_struct *work) static int mt7615_init_hardware(struct mt7615_dev *dev) { + u32 addr = mt7615_reg_map(dev, MT_EFUSE_BASE); int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); @@ -154,7 +155,7 @@ static int mt7615_init_hardware(struct mt7615_dev *dev) spin_lock_init(&dev->token_lock); idr_init(&dev->token); - ret = mt7615_eeprom_init(dev); + ret = mt7615_eeprom_init(dev, addr); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index f3c912672a6c..170775ac8eae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -360,7 +360,7 @@ int mt7615_register_device(struct mt7615_dev *dev); void mt7615_unregister_device(struct mt7615_dev *dev); int mt7615_register_ext_phy(struct mt7615_dev *dev); void mt7615_unregister_ext_phy(struct mt7615_dev *dev); -int mt7615_eeprom_init(struct mt7615_dev *dev); +int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr); int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); -- cgit From 044883e37ddad04690e57f037e9eae48287e2613 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 3 Apr 2020 17:09:16 +0800 Subject: mt76: mt7663: correct the name of the rom patch Rom patch is shared between Bluetooth and Wifi devices, so correct the naming to allow two drivers to share the same file. Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 170775ac8eae..304abde1482e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -41,7 +41,7 @@ #define MT7615_FIRMWARE_V2 2 #define MT7615_FIRMWARE_V3 3 -#define MT7663_ROM_PATCH "mediatek/mt7663pr2h_v3.bin" +#define MT7663_ROM_PATCH "mediatek/mt7663pr2h.bin" #define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin" #define MT7615_EEPROM_SIZE 1024 -- cgit From fdb786cce0ef3615dcbb30d8baf06a1d4cb7a344 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 3 Apr 2020 21:01:56 +0200 Subject: mt76: mt7615: do not always reset the dfs state setting the channel mac80211/hostapd runs mt7615_set_channel with the same channel parameters sending multiple rdd commands overwriting the previous ones. This behaviour is causing tpt issues on dfs channels. Fix the issue checking new channel freq/width with the running one. Fixes: 5dabdf71e94e ("mt76: mt7615: add multiple wiphy support to the dfs support code") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c91f0896b09f..3e0d26183905 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -220,6 +220,25 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, spin_unlock_bh(&dev->sta_poll_lock); } +static void mt7615_init_dfs_state(struct mt7615_phy *phy) +{ + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct cfg80211_chan_def *chandef = &hw->conf.chandef; + + if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + return; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + if (mphy->chandef.chan->center_freq == chandef->chan->center_freq && + mphy->chandef.width == chandef->width) + return; + + phy->dfs_state = -1; +} + static int mt7615_set_channel(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; @@ -231,7 +250,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy) mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &phy->mt76->state); - phy->dfs_state = -1; + mt7615_init_dfs_state(phy); mt76_set_channel(phy->mt76); ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); -- cgit From 373ab334226853a71903c3f62c0d89ddfaa0aeb2 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 5 Apr 2020 16:45:48 +0200 Subject: mt76: mt7615: Delete an error message in mt7622_wmac_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function “platform_get_irq” can log an error already. Thus omit a redundant message for the exception handling in the calling function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/soc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index 43aa49706c66..9aa5183c7a56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -36,10 +36,8 @@ static int mt7622_wmac_probe(struct platform_device *pdev) int irq; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get device IRQ\n"); + if (irq < 0) return irq; - } mem_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(mem_base)) { -- cgit From b90728f82b085f97a4993ef7ed71f38e3ae031ea Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 6 Apr 2020 10:19:48 +0200 Subject: mt76: mt7615: disable merge of OTP ROM data by default The reference driver does not seem to enable it by default, only under certain conditions, e.g. when a .bin file is loaded. Make it opt-in via a device tree property for now, in case it is needed on some boards. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 23ed20553de2..34c33d23d79f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -5,6 +5,7 @@ * Felix Fietkau */ +#include #include "mt7615.h" #include "eeprom.h" @@ -255,6 +256,11 @@ static void mt7622_apply_cal_free_data(struct mt7615_dev *dev) static void mt7615_cal_free_data(struct mt7615_dev *dev) { + struct device_node *np = dev->mt76.dev->of_node; + + if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) + return; + switch (mt76_chip(&dev->mt76)) { case 0x7622: mt7622_apply_cal_free_data(dev); -- cgit From ad380ad1ebbe6a9a243150fef1123670164ae278 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 30 Mar 2020 15:02:45 +0200 Subject: mt76: mt7615: add support for applying DC offset calibration from EEPROM When the EEPROM data is read from flash, it can contain DC offset calibration data. Add support for sending the data to the firmware. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 9 +- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 19 ++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 195 ++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 + 6 files changed, 200 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 34c33d23d79f..7a09427463b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -72,7 +72,8 @@ static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr) { int ret; - ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE); + ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE + + MT7615_EEPROM_EXTRA_DATA); if (ret < 0) return ret; @@ -280,11 +281,13 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr) return ret; ret = mt7615_check_eeprom(&dev->mt76); - if (ret && dev->mt76.otp.data) + if (ret && dev->mt76.otp.data) { memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, MT7615_EEPROM_SIZE); - else + } else { + dev->flash_eeprom = true; mt7615_cal_free_data(dev); + } mt7615_eeprom_parse_hw_cap(dev); memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index 8a2a64b7fcd3..bd2ac1e0e01a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -6,6 +6,21 @@ #include "mt7615.h" + +#define MT7615_EEPROM_DCOC_OFFSET MT7615_EEPROM_SIZE +#define MT7615_EEPROM_DCOC_SIZE 256 +#define MT7615_EEPROM_DCOC_COUNT 34 + +#define MT7615_EEPROM_TXDPD_OFFSET (MT7615_EEPROM_SIZE + \ + MT7615_EEPROM_DCOC_COUNT * \ + MT7615_EEPROM_DCOC_SIZE) +#define MT7615_EEPROM_TXDPD_SIZE 216 +#define MT7615_EEPROM_TXDPD_COUNT (44 + 3) + +#define MT7615_EEPROM_EXTRA_DATA (MT7615_EEPROM_TXDPD_OFFSET + \ + MT7615_EEPROM_TXDPD_COUNT * \ + MT7615_EEPROM_TXDPD_SIZE) + enum mt7615_eeprom_field { MT_EE_CHIP_ID = 0x000, MT_EE_VERSION = 0x002, @@ -13,6 +28,7 @@ enum mt7615_eeprom_field { MT_EE_NIC_CONF_0 = 0x034, MT_EE_NIC_CONF_1 = 0x036, MT_EE_WIFI_CONF = 0x03e, + MT_EE_CALDATA_FLASH = 0x052, MT_EE_TX0_2G_TARGET_POWER = 0x058, MT_EE_TX0_5G_G0_TARGET_POWER = 0x070, MT_EE_TX1_5G_G0_TARGET_POWER = 0x098, @@ -27,6 +43,9 @@ enum mt7615_eeprom_field { MT7663_EE_MAX = 0x400, }; +#define MT_EE_CALDATA_FLASH_TX_DPD BIT(0) +#define MT_EE_CALDATA_FLASH_RX_CAL BIT(1) + #define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4) #define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3e0d26183905..ef8e9336f627 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -253,6 +253,9 @@ static int mt7615_set_channel(struct mt7615_phy *phy) mt7615_init_dfs_state(phy); mt76_set_channel(phy->mt76); + if (is_mt7615(&dev->mt76) && dev->flash_eeprom) + mt7615_mcu_apply_rx_dcoc(phy); + ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); if (ret) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index dcd97606e827..a9fd68692e96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2481,6 +2481,25 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku) } } +static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef) +{ + static const u8 width_to_bw[] = { + [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, + [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, + [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, + [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, + [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, + [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, + [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, + [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, + }; + + if (chandef->width >= ARRAY_SIZE(width_to_bw)) + return 0; + + return width_to_bw[chandef->width]; +} + int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) { struct mt7615_dev *dev = phy->dev; @@ -2521,32 +2540,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) req.switch_reason = CH_SWITCH_NORMAL; req.band_idx = phy != &dev->phy; - - switch (chandef->width) { - case NL80211_CHAN_WIDTH_40: - req.bw = CMD_CBW_40MHZ; - break; - case NL80211_CHAN_WIDTH_80: - req.bw = CMD_CBW_80MHZ; - break; - case NL80211_CHAN_WIDTH_80P80: - req.bw = CMD_CBW_8080MHZ; - break; - case NL80211_CHAN_WIDTH_160: - req.bw = CMD_CBW_160MHZ; - break; - case NL80211_CHAN_WIDTH_5: - req.bw = CMD_CBW_5MHZ; - break; - case NL80211_CHAN_WIDTH_10: - req.bw = CMD_CBW_10MHZ; - break; - case NL80211_CHAN_WIDTH_20_NOHT: - case NL80211_CHAN_WIDTH_20: - default: - req.bw = CMD_CBW_20MHZ; - break; - } + req.bw = mt7615_mcu_chan_bw(chandef); mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); @@ -2836,3 +2830,152 @@ int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy, return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req, sizeof(req), false); } + +static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) +{ + int i; + + for (i = 0; i < n_freqs; i++) + if (cur == freqs[i]) + return i; + + return -1; +} + +static int mt7615_dcoc_freq_idx(u16 freq, u8 bw) +{ + static const u16 freq_list[] = { + 4980, 5805, 5905, 5190, + 5230, 5270, 5310, 5350, + 5390, 5430, 5470, 5510, + 5550, 5590, 5630, 5670, + 5710, 5755, 5795, 5835, + 5875, 5210, 5290, 5370, + 5450, 5530, 5610, 5690, + 5775, 5855 + }; + static const u16 freq_bw40[] = { + 5190, 5230, 5270, 5310, + 5350, 5390, 5430, 5470, + 5510, 5550, 5590, 5630, + 5670, 5710, 5755, 5795, + 5835, 5875 + }; + int offset_2g = ARRAY_SIZE(freq_list); + int idx; + + if (freq < 4000) { + if (freq < 2427) + return offset_2g; + if (freq < 2442) + return offset_2g + 1; + if (freq < 2457) + return offset_2g + 2; + + return offset_2g + 3; + } + + switch (bw) { + case NL80211_CHAN_WIDTH_80: + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + break; + default: + idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), + freq + 10); + if (idx >= 0) { + freq = freq_bw40[idx]; + break; + } + + idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), + freq - 10); + if (idx >= 0) { + freq = freq_bw40[idx]; + break; + } + /* fall through */ + case NL80211_CHAN_WIDTH_40: + idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), + freq); + if (idx >= 0) + break; + + return -1; + + } + + return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); +} + +int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy) +{ + struct mt7615_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq2 = chandef->center_freq2; + int ret; + struct { + u8 direction; + u8 runtime_calibration; + u8 _rsv[2]; + + __le16 center_freq; + u8 bw; + u8 band; + u8 is_freq2; + u8 success; + u8 dbdc_en; + + u8 _rsv2; + + struct { + __le32 sx0_i_lna[4]; + __le32 sx0_q_lna[4]; + + __le32 sx2_i_lna[4]; + __le32 sx2_q_lna[4]; + } dcoc_data[4]; + } req = { + .direction = 1, + + .bw = mt7615_mcu_chan_bw(chandef), + .band = chandef->center_freq1 > 4000, + .dbdc_en = !!dev->mt76.phy2, + }; + u16 center_freq = chandef->center_freq1; + int freq_idx; + u8 *eep = dev->mt76.eeprom.data; + + if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL)) + return 0; + + if (chandef->width == NL80211_CHAN_WIDTH_160) { + freq2 = center_freq + 40; + center_freq -= 40; + } + +again: + req.runtime_calibration = 1; + freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width); + if (freq_idx < 0) + goto out; + + memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET + + freq_idx * MT7615_EEPROM_DCOC_SIZE, + sizeof(req.dcoc_data)); + req.runtime_calibration = 0; + +out: + req.center_freq = cpu_to_le16(center_freq); + ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RXDCOC_CAL, &req, + sizeof(req), true); + + if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || + chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { + req.is_freq2 = true; + center_freq = freq2; + goto again; + } + + return ret; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 69cb68d6465d..427478002e67 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -270,6 +270,7 @@ enum { MCU_EXT_CMD_BCN_OFFLOAD = 0x49, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, + MCU_EXT_CMD_RXDCOC_CAL = 0x59, MCU_EXT_CMD_SET_RDD_TH = 0x7c, MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 304abde1482e..39c792826c48 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -258,6 +258,7 @@ struct mt7615_dev { u8 mac_work_count; bool fw_debug; + bool flash_eeprom; spinlock_t token_lock; struct idr token; @@ -494,6 +495,7 @@ int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern); int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); +int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); -- cgit From 371a59d151df588795f43c22dc3f882b9719559b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 6 Apr 2020 11:14:56 +0200 Subject: mt76: mt7615: add support for applying tx DPD calibration from EEPROM When the EEPROM data is read from flash, it can contain tx DPD calibration data. Add support for sending the data to the firmware. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 121 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 4 files changed, 126 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index ef8e9336f627..b346080458bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -253,8 +253,10 @@ static int mt7615_set_channel(struct mt7615_phy *phy) mt7615_init_dfs_state(phy); mt76_set_channel(phy->mt76); - if (is_mt7615(&dev->mt76) && dev->flash_eeprom) + if (is_mt7615(&dev->mt76) && dev->flash_eeprom) { mt7615_mcu_apply_rx_dcoc(phy); + mt7615_mcu_apply_tx_dpd(phy); + } ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index a9fd68692e96..f51d252c5f49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2979,3 +2979,124 @@ out: return ret; } + +static int mt7615_dpd_freq_idx(u16 freq, u8 bw) +{ + static const u16 freq_list[] = { + 4920, 4940, 4960, 4980, + 5040, 5060, 5080, 5180, + 5200, 5220, 5240, 5260, + 5280, 5300, 5320, 5340, + 5360, 5380, 5400, 5420, + 5440, 5460, 5480, 5500, + 5520, 5540, 5560, 5580, + 5600, 5620, 5640, 5660, + 5680, 5700, 5720, 5745, + 5765, 5785, 5805, 5825, + 5845, 5865, 5885, 5905 + }; + int offset_2g = ARRAY_SIZE(freq_list); + int idx; + + if (freq < 4000) { + if (freq < 2432) + return offset_2g; + if (freq < 2457) + return offset_2g + 1; + + return offset_2g + 2; + } + + if (bw != NL80211_CHAN_WIDTH_20) { + idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), + freq + 10); + if (idx >= 0) + return idx; + + idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), + freq - 10); + if (idx >= 0) + return idx; + } + + return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); +} + + +int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy) +{ + struct mt7615_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq2 = chandef->center_freq2; + int ret; + struct { + u8 direction; + u8 runtime_calibration; + u8 _rsv[2]; + + __le16 center_freq; + u8 bw; + u8 band; + u8 is_freq2; + u8 success; + u8 dbdc_en; + + u8 _rsv2; + + struct { + struct { + u32 dpd_g0; + u8 data[32]; + } wf0, wf1; + + struct { + u32 dpd_g0_prim; + u32 dpd_g0_sec; + u8 data_prim[32]; + u8 data_sec[32]; + } wf2, wf3; + } dpd_data; + } req = { + .direction = 1, + + .bw = mt7615_mcu_chan_bw(chandef), + .band = chandef->center_freq1 > 4000, + .dbdc_en = !!dev->mt76.phy2, + }; + u16 center_freq = chandef->center_freq1; + int freq_idx; + u8 *eep = dev->mt76.eeprom.data; + + if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD)) + return 0; + + if (chandef->width == NL80211_CHAN_WIDTH_160) { + freq2 = center_freq + 40; + center_freq -= 40; + } + +again: + req.runtime_calibration = 1; + freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width); + if (freq_idx < 0) + goto out; + + memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET + + freq_idx * MT7615_EEPROM_TXDPD_SIZE, + sizeof(req.dpd_data)); + req.runtime_calibration = 0; + +out: + req.center_freq = cpu_to_le16(center_freq); + ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXDPD_CAL, &req, + sizeof(req), true); + + if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || + chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { + req.is_freq2 = true; + center_freq = freq2; + goto again; + } + + return ret; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 427478002e67..983625fb72ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -271,6 +271,7 @@ enum { MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, MCU_EXT_CMD_RXDCOC_CAL = 0x59, + MCU_EXT_CMD_TXDPD_CAL = 0x60, MCU_EXT_CMD_SET_RDD_TH = 0x7c, MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 39c792826c48..65a2b30fc588 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -496,6 +496,7 @@ int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern); int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); +int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); -- cgit From 6d3390a664bbac544d1656503a3ccf947f154770 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 6 Apr 2020 14:01:56 +0200 Subject: mt76: mt7603: disable merge of OTP ROM data by default The reference driver does not seem to enable it by default, only under certain conditions, e.g. when a .bin file is loaded. Make it opt-in via a device tree property for now, in case it is needed on some boards. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c index 2b6a4d8a8dc7..3ee06e2577b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: ISC +#include #include "mt7603.h" #include "eeprom.h" @@ -100,10 +101,14 @@ mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse) MT_EE_TX_POWER_1_START_2G, MT_EE_TX_POWER_1_START_2G + 1, }; + struct device_node *np = dev->mt76.dev->of_node; u8 *eeprom = dev->mt76.eeprom.data; int n = ARRAY_SIZE(cal_free_bytes); int i; + if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) + return; + if (!mt7603_has_cal_free_data(dev, efuse)) return; -- cgit From 9a865741d84ec08dfd04fc28a5fca210f919f54d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 6 Apr 2020 14:03:06 +0200 Subject: mt76: mt76x2: disable merge of OTP ROM data by default The reference driver does not seem to enable it by default, only under certain conditions, e.g. when a .bin file is loaded. Make it opt-in via a device tree property for now, in case it is needed on some boards. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 4a748a6f0ce2..410ffce3baff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -4,6 +4,7 @@ */ #include +#include #include #include "mt76x2.h" #include "eeprom.h" @@ -76,6 +77,7 @@ mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, }; + struct device_node *np = dev->mt76.dev->of_node; u8 *eeprom = dev->mt76.eeprom.data; u8 prev_grp0[4] = { eeprom[MT_EE_TX_POWER_0_START_5G], @@ -86,6 +88,9 @@ mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) u16 val; int i; + if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) + return; + if (!mt76x2_has_cal_free_data(dev, efuse)) return; -- cgit From 1855ad5360a18131e5c4b4afa1a1c5dea6e456c6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 6 Apr 2020 23:56:30 +0200 Subject: mt76: mt7615: fix possible division by 0 in mt7615_mac_update_mib_stats Check that val is not zero before aggr_per estimation in order to avoid a possible division by 0 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index ed6eb19f48c5..1ef988883660 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1773,9 +1773,11 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy), MT_MIB_AMPDU_MPDU_COUNT); - val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy), - MT_MIB_AMPDU_ACK_COUNT); - mib->aggr_per = 1000 * (val - val2) / val; + if (val) { + val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy), + MT_MIB_AMPDU_ACK_COUNT); + mib->aggr_per = 1000 * (val - val2) / val; + } aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < 4; i++) { -- cgit From 6bcfdabbadffa19fabafb5b6c7bcf41322b62695 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 8 Apr 2020 14:20:39 +0200 Subject: mt76: mt7663: fix aggr range entry in debugfs Fix register definitions for aggr range counter registers for mt7663 chipset Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 5 +++++ 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 777c7f9bd760..2163a22967c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -129,16 +129,18 @@ mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy, struct seq_file *file) { struct mt7615_dev *dev = file->private; + u32 reg = is_mt7663(&dev->mt76) ? MT_MIB_ARNG(0) : MT_AGG_ASRCR0; bool ext_phy = phy != &dev->phy; int bound[7], i, range; if (!phy) return; - range = mt76_rr(dev, MT_AGG_ASRCR0); + range = mt76_rr(dev, reg); for (i = 0; i < 4; i++) bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; - range = mt76_rr(dev, MT_AGG_ASRCR1); + + range = mt76_rr(dev, reg + 4); for (i = 0; i < 3; i++) bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 6acaaf2732df..07d4b259fe8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -116,6 +116,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev) mt76_wr(dev, MT_DMA_DCR0, FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) | MT_DMA_DCR0_RX_VEC_DROP); + mt76_set(dev, MT_WF_MIB_SCR0, MT_MIB_SCR0_AGG_CNT_RANGE_EN); if (is_mt7663(&dev->mt76)) { mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02); mt76_wr(dev, MT_WF_AGG(0x164), 0x70708040); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 481e4d941e72..a3333f382350 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -384,6 +384,9 @@ enum mt7615_reg_base { #define MT_WF_MIB_BASE (dev->reg_map[MT_MIB_BASE]) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE + (ofs) + (_band) * 0x200) +#define MT_WF_MIB_SCR0 MT_WF_MIB(0, 0) +#define MT_MIB_SCR0_AGG_CNT_RANGE_EN BIT(21) + #define MT_MIB_M0_MISC_CR(_band) MT_WF_MIB(_band, 0x00c) #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) @@ -414,6 +417,8 @@ enum mt7615_reg_base { #define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) +#define MT_MIB_ARNG(n) MT_WF_MIB(0, 0x4b8 + ((n) << 2)) + #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa8 + ((n) << 2)) #define MT_DMA_SHDL(ofs) (dev->reg_map[MT_DMA_SHDL_BASE] + (ofs)) -- cgit From 635cb0105e01f4c90e69b3cf8e2c1569479e4bf7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 9 Apr 2020 11:51:17 +0200 Subject: mt76: mt7615: disable hw/sched scan ops for non-offload firmware Avoid having to attempt hw scan and fall back to software for every scan on devices/firmware without hw scan support Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 8 +++++++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 07d4b259fe8a..7f3683205b8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -143,6 +143,13 @@ static void mt7615_init_work(struct work_struct *work) mt7615_mac_init(dev); mt7615_phy_init(dev); mt7615_mcu_del_wtbl_all(dev); + + if (!mt7615_firmware_offload(dev)) { + dev->ops->hw_scan = NULL; + dev->ops->cancel_hw_scan = NULL; + dev->ops->sched_scan_start = NULL; + dev->ops->sched_scan_stop = NULL; + } } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index d2eff5442824..3849bb6b49d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -139,11 +139,16 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, }; + struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; int ret; - mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7615_ops, &drv_ops); + ops = devm_kmemdup(pdev, &mt7615_ops, sizeof(mt7615_ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + + mdev = mt76_alloc_device(pdev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; @@ -151,6 +156,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, mt76_mmio_init(&dev->mt76, mem_base); dev->reg_map = map; + dev->ops = ops; mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 65a2b30fc588..4f0d29e5e595 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -235,6 +235,7 @@ struct mt7615_dev { u16 chainmask; + struct ieee80211_ops *ops; const struct mt7615_mcu_ops *mcu_ops; struct regmap *infracfg; const u32 *reg_map; -- cgit From 639e25a125857be1cba52892959d47384177dd72 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 8 Apr 2020 18:10:35 +0200 Subject: mt76: mt7615: set hw scan limits only for firmware with offload support They do not apply to software scan Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 7f3683205b8e..96b7c6284833 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -145,10 +145,19 @@ static void mt7615_init_work(struct work_struct *work) mt7615_mcu_del_wtbl_all(dev); if (!mt7615_firmware_offload(dev)) { + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + dev->ops->hw_scan = NULL; dev->ops->cancel_hw_scan = NULL; dev->ops->sched_scan_start = NULL; dev->ops->sched_scan_stop = NULL; + + wiphy->max_sched_scan_plan_interval = 0; + wiphy->max_sched_scan_ie_len = 0; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_reqs = 0; } } -- cgit From c0f8055b3986f9c9f990268b578173259769ba1c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 9 Apr 2020 13:14:56 +0200 Subject: mt76: mt7622: fix DMA unmap length Fix DMA unmap length estimation in mt7615_txp_skb_unmap_hw for mt7622 chipset Fixes: 6aa4ed7927f1 ("mt76: mt7615: implement DMA support for MT7622") Signed-off-by: Lorenzo Bianconi --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1ef988883660..b7a96d514656 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -695,7 +695,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) len = le16_to_cpu(ptr->len0); last = len & MT_TXD_LEN_MSDU_LAST; - len &= ~MT_TXD_LEN_MSDU_LAST; + len &= MT_TXD_LEN_MASK; dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, DMA_TO_DEVICE); if (last) @@ -703,7 +703,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) len = le16_to_cpu(ptr->len1); last = len & MT_TXD_LEN_MSDU_LAST; - len &= ~MT_TXD_LEN_MSDU_LAST; + len &= MT_TXD_LEN_MASK; dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, DMA_TO_DEVICE); if (last) @@ -1114,8 +1114,8 @@ mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); for (i = 0; i < nbuf; i++) { + u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; u32 addr = tx_info->buf[i + 1].addr; - u16 len = tx_info->buf[i + 1].len; if (i == nbuf - 1) len |= MT_TXD_LEN_MSDU_LAST | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index f3e0070896a1..6260f97432a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -253,6 +253,7 @@ enum tx_phy_bandwidth { #define MT_MSDU_ID_VALID BIT(15) +#define MT_TXD_LEN_MASK GENMASK(11, 0) #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) -- cgit From 89829c9e65ab680f7e5a1658cb74bc6316ab036e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 9 Apr 2020 13:14:57 +0200 Subject: mt76: mt7663: fix DMA unmap length Fix DMA unmap length for mt7663e devices in mt7615_txp_skb_unmap_hw Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Lorenzo Bianconi --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 20 ++++++++++++++------ drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index b7a96d514656..c38bc395c5a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -686,15 +686,18 @@ mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp) static void mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) { + u32 last_mask; int i; + last_mask = is_mt7663(dev) ? MT_TXD_LEN_LAST : MT_TXD_LEN_MSDU_LAST; + for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { struct mt7615_txp_ptr *ptr = &txp->ptr[i]; bool last; u16 len; len = le16_to_cpu(ptr->len0); - last = len & MT_TXD_LEN_MSDU_LAST; + last = len & last_mask; len &= MT_TXD_LEN_MASK; dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len, DMA_TO_DEVICE); @@ -702,7 +705,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) break; len = le16_to_cpu(ptr->len1); - last = len & MT_TXD_LEN_MSDU_LAST; + last = len & last_mask; len &= MT_TXD_LEN_MASK; dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, DMA_TO_DEVICE); @@ -1105,21 +1108,26 @@ mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, { struct mt7615_hw_txp *txp = txp_ptr; struct mt7615_txp_ptr *ptr = &txp->ptr[0]; - int nbuf = tx_info->nbuf - 1; - int i; + int i, nbuf = tx_info->nbuf - 1; + u32 last_mask; tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); tx_info->nbuf = 1; txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); + if (is_mt7663(&dev->mt76)) + last_mask = MT_TXD_LEN_LAST; + else + last_mask = MT_TXD_LEN_AMSDU_LAST | + MT_TXD_LEN_MSDU_LAST; + for (i = 0; i < nbuf; i++) { u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; u32 addr = tx_info->buf[i + 1].addr; if (i == nbuf - 1) - len |= MT_TXD_LEN_MSDU_LAST | - MT_TXD_LEN_AMSDU_LAST; + len |= last_mask; if (i & 1) { ptr->buf1 = cpu_to_le32(addr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 6260f97432a0..8ee57d220d71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -256,6 +256,8 @@ enum tx_phy_bandwidth { #define MT_TXD_LEN_MASK GENMASK(11, 0) #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) +/* mt7663 */ +#define MT_TXD_LEN_LAST BIT(15) struct mt7615_txp_ptr { __le32 buf0; -- cgit From 9b90ab32f871eae0de982a6567fe32039a756af5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 9 Apr 2020 14:37:50 +0200 Subject: mt76: mt7615: rework IRQ handling to prepare for MSI support With MSI interrupts, IRQs must not be enabled from within the IRQ handler, because that can lead to lost events. Defer IRQ processing to a tasklet, which is also responsible for enabling IRQs (to avoid race conditions against the handler) Co-developed-by: Soul Huang Acked-by: Lorenzo Bianconi Signed-off-by: Soul Huang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 29 ++++++++++++++++------ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 9 +++---- 4 files changed, 29 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 7ead6620bb8b..26353b6bce97 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -73,7 +73,8 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, spin_lock_irqsave(&dev->mmio.irq_lock, flags); dev->mmio.irqmask &= ~clear; dev->mmio.irqmask |= set; - mt76_mmio_wr(dev, addr, dev->mmio.irqmask); + if (addr) + mt76_mmio_wr(dev, addr, dev->mmio.irqmask); spin_unlock_irqrestore(&dev->mmio.irq_lock, flags); } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 96b7c6284833..cb626a2d9197 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -561,5 +561,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev) spin_unlock_bh(&dev->token_lock); idr_destroy(&dev->token); + tasklet_disable(&dev->irq_tasklet); + mt76_free_device(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 3849bb6b49d0..e9f9cda6bb59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -80,30 +80,42 @@ mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance) { struct mt7615_dev *dev = dev_instance; - u32 intr; - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + mt76_wr(dev, MT_INT_MASK_CSR, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; - trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + tasklet_schedule(&dev->irq_tasklet); + + return IRQ_HANDLED; +} + +static void mt7615_irq_tasklet(unsigned long data) +{ + struct mt7615_dev *dev = (struct mt7615_dev *)data; + u32 intr, mask = 0; + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); intr &= dev->mt76.mmio.irqmask; if (intr & MT_INT_TX_DONE_ALL) { - mt7615_irq_disable(dev, MT_INT_TX_DONE_ALL); + mask |= MT_INT_TX_DONE_ALL; napi_schedule(&dev->mt76.tx_napi); } if (intr & MT_INT_RX_DONE(0)) { - mt7615_irq_disable(dev, MT_INT_RX_DONE(0)); + mask |= MT_INT_RX_DONE(0); napi_schedule(&dev->mt76.napi[0]); } if (intr & MT_INT_RX_DONE(1)) { - mt7615_irq_disable(dev, MT_INT_RX_DONE(1)); + mask |= MT_INT_RX_DONE(1); napi_schedule(&dev->mt76.napi[1]); } @@ -117,7 +129,7 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance) } } - return IRQ_HANDLED; + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, @@ -154,6 +166,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, dev = container_of(mdev, struct mt7615_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + tasklet_init(&dev->irq_tasklet, mt7615_irq_tasklet, (unsigned long)dev); dev->reg_map = map; dev->ops = ops; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 4f0d29e5e595..10a98d38f77e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -229,6 +229,8 @@ struct mt7615_dev { struct mt76_phy mphy; }; + struct tasklet_struct irq_tasklet; + struct mt7615_phy phy; u32 vif_mask; u32 omac_mask; @@ -404,12 +406,9 @@ static inline bool is_mt7663(struct mt76_dev *dev) static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask) { - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); -} + mt76_set_irq_mask(&dev->mt76, 0, 0, mask); -static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) -{ - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); + tasklet_schedule(&dev->irq_tasklet); } static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) -- cgit From 9fbb4b8621d7cac34b5b4b20462341b00d9d596c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 9 Apr 2020 18:37:04 +0200 Subject: mt76: mt7615: enable MSI by default Enable MSI/MSI-X PCI interrupts by default. This patch has been tested using Banana Pi r64 board Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index c8d0f893a47f..4f8a3c637a98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -33,6 +33,10 @@ static int mt7615_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) return ret; @@ -48,6 +52,7 @@ static void mt7615_pci_remove(struct pci_dev *pdev) struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); mt7615_unregister_device(dev); + pci_free_irq_vectors(pdev); } struct pci_driver mt7615_pci_driver = { -- cgit From 5da612090d9a7b1481b7587b3b1deede30a11baf Mon Sep 17 00:00:00 2001 From: Jules Irenge Date: Sat, 11 Apr 2020 01:19:26 +0100 Subject: mt76: remove unnecessary annotations Sparse report warnings at mt76_tx_status_unlock() and mt76_tx_status_lock() warning: context imbalance in mt76_tx_status_lock() - wrong count at exit warning: context imbalance in mt76_tx_status_unlock() - unexpected unlock The root cause is the additional __acquire(&dev->status_list.lock) and __release(&dev->status_list.unlock) called from inside mt76_tx_status_lock() and mt76_tx_status_unlock(). Remove __acquire(&dev->status_list.lock) annotation Remove __releases(&dev->status_list.unlock) Correct &dev->status_list.unlock to &dev->status_list.lock -unlock not defined in the sk_buff_head struct Signed-off-by: Jules Irenge Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index eff522dbda34..fca38ea2441f 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -101,19 +101,17 @@ mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list) { __skb_queue_head_init(list); spin_lock_bh(&dev->status_list.lock); - __acquire(&dev->status_list.lock); } EXPORT_SYMBOL_GPL(mt76_tx_status_lock); void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) - __releases(&dev->status_list.unlock) + __releases(&dev->status_list.lock) { struct ieee80211_hw *hw; struct sk_buff *skb; spin_unlock_bh(&dev->status_list.lock); - __release(&dev->status_list.unlock); while ((skb = __skb_dequeue(list)) != NULL) { hw = mt76_tx_status_get_hw(dev, skb); -- cgit From 4fcf6e770b4487db3dbcf48993a36f16f8836680 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Apr 2020 16:28:48 +0200 Subject: mt76: mt7615: fix possible deadlock in mt7615_stop make mac_work per phy instead of per device and fix a possible deadlock in mt7615_stop since mt7615_mac_work runs holding mt76 mutex Fixes: fdd2e570764c2 ("mt76: mt7615: add dual-phy support for mac80211 ops") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 58 ++++++++++++---------- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 19 +++---- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- 4 files changed, 45 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index cb626a2d9197..f06de74d009d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -429,6 +429,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) if (phy) return 0; + INIT_DELAYED_WORK(&phy->mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); skb_queue_head_init(&phy->scan_event_list); @@ -487,7 +488,7 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); + INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); skb_queue_head_init(&dev->phy.scan_event_list); INIT_LIST_HEAD(&dev->sta_poll_list); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index c38bc395c5a3..5614cd691885 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1815,31 +1815,27 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) void mt7615_mac_work(struct work_struct *work) { - struct mt7615_dev *dev; - struct mt7615_phy *ext_phy; + struct mt7615_phy *phy; + struct mt76_dev *mdev; - dev = (struct mt7615_dev *)container_of(work, struct mt76_dev, + phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, mac_work.work); + mdev = &phy->dev->mt76; - mutex_lock(&dev->mt76.mutex); - mt76_update_survey(&dev->mt76); - if (++dev->mac_work_count == 5) { - ext_phy = mt7615_ext_phy(dev); - - mt7615_mac_update_mib_stats(&dev->phy); - mt7615_mac_scs_check(&dev->phy); - if (ext_phy) { - mt7615_mac_update_mib_stats(ext_phy); - mt7615_mac_scs_check(ext_phy); - } + mutex_lock(&mdev->mutex); - dev->mac_work_count = 0; + mt76_update_survey(mdev); + if (++phy->mac_work_count == 5) { + phy->mac_work_count = 0; + + mt7615_mac_update_mib_stats(phy); + mt7615_mac_scs_check(phy); } - mutex_unlock(&dev->mt76.mutex); + mutex_unlock(&mdev->mutex); - mt76_tx_status_check(&dev->mt76, NULL, false); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + mt76_tx_status_check(mdev, NULL, false); + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, MT7615_WATCHDOG_TIME); } @@ -1902,26 +1898,32 @@ mt7615_dma_reset(struct mt7615_dev *dev) void mt7615_mac_reset_work(struct work_struct *work) { + struct mt7615_phy *phy2; + struct mt76_phy *ext_phy; struct mt7615_dev *dev; dev = container_of(work, struct mt7615_dev, reset_work); + ext_phy = dev->mt76.phy2; + phy2 = ext_phy ? ext_phy->priv : NULL; if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA)) return; ieee80211_stop_queues(mt76_hw(dev)); - if (dev->mt76.phy2) - ieee80211_stop_queues(dev->mt76.phy2->hw); + if (ext_phy) + ieee80211_stop_queues(ext_phy->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->phy.mac_work); + if (phy2) + cancel_delayed_work_sync(&phy2->mac_work); /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); - if (dev->mt76.phy2) - mt76_txq_schedule_all(dev->mt76.phy2); + if (ext_phy) + mt76_txq_schedule_all(ext_phy); tasklet_disable(&dev->mt76.tx_tasklet); napi_disable(&dev->mt76.napi[0]); @@ -1955,8 +1957,8 @@ void mt7615_mac_reset_work(struct work_struct *work) napi_schedule(&dev->mt76.napi[1]); ieee80211_wake_queues(mt76_hw(dev)); - if (dev->mt76.phy2) - ieee80211_wake_queues(dev->mt76.phy2->hw); + if (ext_phy) + ieee80211_wake_queues(ext_phy->hw); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); @@ -1965,8 +1967,12 @@ void mt7615_mac_reset_work(struct work_struct *work) mt7615_update_beacons(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, MT7615_WATCHDOG_TIME); + if (phy2) + ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work, + MT7615_WATCHDOG_TIME); + } static void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b346080458bc..33f67c7ccbf8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -55,15 +55,12 @@ static int mt7615_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - if (running) - goto out; - - mt7615_mac_reset_counters(dev); - - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(hw, &phy->mac_work, MT7615_WATCHDOG_TIME); -out: + if (!running) + mt7615_mac_reset_counters(dev); + mutex_unlock(&dev->mt76.mutex); return 0; @@ -74,6 +71,8 @@ static void mt7615_stop(struct ieee80211_hw *hw) struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + cancel_delayed_work_sync(&phy->mac_work); + mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -85,8 +84,6 @@ static void mt7615_stop(struct ieee80211_hw *hw) } if (!mt7615_dev_running(dev)) { - cancel_delayed_work_sync(&dev->mt76.mac_work); - mt7615_mcu_set_pm(dev, 0, 1); mt7615_mcu_set_mac_enable(dev, 0, false); } @@ -245,7 +242,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy) bool ext_phy = phy != &dev->phy; int ret; - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&phy->mac_work); mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &phy->mt76->state); @@ -276,7 +273,7 @@ out: mutex_unlock(&dev->mt76.mutex); mt76_txq_schedule_all(phy->mt76); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, MT7615_WATCHDOG_TIME); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 10a98d38f77e..57c9c1ef8ffc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -192,6 +192,9 @@ struct mt7615_phy { struct mib_stats mib; + struct delayed_work mac_work; + u8 mac_work_count; + struct sk_buff_head scan_event_list; struct delayed_work scan_work; }; @@ -259,7 +262,6 @@ struct mt7615_dev { } radar_pattern; u32 hw_pattern; - u8 mac_work_count; bool fw_debug; bool flash_eeprom; -- cgit From e90354e0452d33f3dc77d7f5c0ff7033f97e1fbf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 16 Apr 2020 16:32:50 +0200 Subject: mt76: mt7615: move core shared code in mt7615-common module Create mt7615-common module in order to collect shared code between usb and mmio code. Move the following source files in mt7615-common module: - main.c - init.c - mcu.c - mac.c - debugfs.c - eeprom.c - trace.c Create the following source files for mmio only source code and move them in mt7615e module: - pci_init.c - dma.c - pci_mac.c Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/Kconfig | 7 +- drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 7 +- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 39 ---- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 194 ++---------------- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 221 +++++---------------- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 32 +-- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 15 +- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 30 +++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 12 +- .../net/wireless/mediatek/mt76/mt7615/pci_init.c | 189 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/pci_mac.c | 184 +++++++++++++++++ 14 files changed, 503 insertions(+), 431 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d7a1ddc9e407..a1dfafec431b 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -26,4 +26,4 @@ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ -obj-$(CONFIG_MT7615E) += mt7615/ +obj-$(CONFIG_MT7615_COMMON) += mt7615/ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index 6afd4aea67ed..16385767d8b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -1,7 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only + +config MT7615_COMMON + tristate + select MT76_CORE + config MT7615E tristate "MediaTek MT7615E (PCIe) support" - select MT76_CORE + select MT7615_COMMON depends on MAC80211 depends on PCI help diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 5c6a220ed7e3..2a7937b4394f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -1,9 +1,12 @@ #SPDX-License-Identifier: ISC +obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o CFLAGS_trace.o := -I$(src) -mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o mmio.o \ - debugfs.o trace.o +mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \ + debugfs.o trace.o + +mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o mt7615e-$(CONFIG_MT7622_WMAC) += soc.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 2163a22967c7..150036488e3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -325,3 +325,4 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt7615_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index b19f208e3d54..b0ba0e7807bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -94,45 +94,6 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) return 0; } -void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - __le32 *rxd = (__le32 *)skb->data; - __le32 *end = (__le32 *)&skb->data[skb->len]; - enum rx_pkt_type type; - u16 flag; - - type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); - flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); - if (type == PKT_TYPE_RX_EVENT && flag == 0x1) - type = PKT_TYPE_NORMAL_MCU; - - switch (type) { - case PKT_TYPE_TXS: - for (rxd++; rxd + 7 <= end; rxd += 7) - mt7615_mac_add_txs(dev, rxd); - dev_kfree_skb(skb); - break; - case PKT_TYPE_TXRX_NOTIFY: - mt7615_mac_tx_free(dev, skb); - break; - case PKT_TYPE_RX_EVENT: - mt7615_mcu_rx_event(dev, skb); - break; - case PKT_TYPE_NORMAL_MCU: - case PKT_TYPE_NORMAL: - if (!mt7615_mac_fill_rx(dev, skb)) { - mt76_rx(&dev->mt76, q, skb); - return; - } - /* fall through */ - default: - dev_kfree_skb(skb); - break; - } -} - static void mt7615_tx_cleanup(struct mt7615_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 7a09427463b0..521705015036 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -297,3 +297,4 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr) return 0; } +EXPORT_SYMBOL_GPL(mt7615_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index f06de74d009d..9d9f73b4561e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -12,12 +12,13 @@ #include "mac.h" #include "eeprom.h" -static void mt7615_phy_init(struct mt7615_dev *dev) +void mt7615_phy_init(struct mt7615_dev *dev) { /* disable rf low power beacon mode */ mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(0), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(1), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); } +EXPORT_SYMBOL_GPL(mt7615_phy_init); static void mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) @@ -77,7 +78,7 @@ mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) } } -static void mt7615_mac_init(struct mt7615_dev *dev) +void mt7615_mac_init(struct mt7615_dev *dev) { int i; @@ -124,6 +125,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev) mt7615_init_mac_chain(dev, 1); } } +EXPORT_SYMBOL_GPL(mt7615_mac_init); bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) { @@ -131,68 +133,7 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) return test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); } - -static void mt7615_init_work(struct work_struct *work) -{ - struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work); - - if (mt7615_mcu_init(dev)) - return; - - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - - if (!mt7615_firmware_offload(dev)) { - struct wiphy *wiphy = mt76_hw(dev)->wiphy; - - dev->ops->hw_scan = NULL; - dev->ops->cancel_hw_scan = NULL; - dev->ops->sched_scan_start = NULL; - dev->ops->sched_scan_stop = NULL; - - wiphy->max_sched_scan_plan_interval = 0; - wiphy->max_sched_scan_ie_len = 0; - wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - wiphy->max_sched_scan_ssids = 0; - wiphy->max_match_sets = 0; - wiphy->max_sched_scan_reqs = 0; - } -} - -static int mt7615_init_hardware(struct mt7615_dev *dev) -{ - u32 addr = mt7615_reg_map(dev, MT_EFUSE_BASE); - int ret, idx; - - mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); - - INIT_WORK(&dev->mcu_work, mt7615_init_work); - spin_lock_init(&dev->token_lock); - idr_init(&dev->token); - - ret = mt7615_eeprom_init(dev, addr); - if (ret < 0) - return ret; - - ret = mt7615_dma_init(dev); - if (ret) - return ret; - - set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); - - /* Beacon and mgmt frames should occupy wcid 0 */ - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); - if (idx) - return -ENOSPC; - - dev->mt76.global_wcid.idx = idx; - dev->mt76.global_wcid.hw_key_idx = -1; - rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - - return 0; -} +EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init); #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ @@ -207,7 +148,7 @@ static int mt7615_init_hardware(struct mt7615_dev *dev) .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ } -static struct ieee80211_rate mt7615_rates[] = { +struct ieee80211_rate mt7615_rates[] = { CCK_RATE(0, 10), CCK_RATE(1, 20), CCK_RATE(2, 55), @@ -221,6 +162,7 @@ static struct ieee80211_rate mt7615_rates[] = { OFDM_RATE(8, 480), OFDM_RATE(12, 540), }; +EXPORT_SYMBOL_GPL(mt7615_rates); static const struct ieee80211_iface_limit if_limits[] = { { @@ -246,61 +188,8 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -static void -mt7615_led_set_config(struct led_classdev *led_cdev, - u8 delay_on, u8 delay_off) -{ - struct mt7615_dev *dev; - struct mt76_dev *mt76; - u32 val, addr; - - mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); - dev = container_of(mt76, struct mt7615_dev, mt76); - val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | - FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | - FIELD_PREP(MT_LED_STATUS_ON, delay_on); - - addr = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); - mt76_wr(dev, addr, val); - addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); - mt76_wr(dev, addr, val); - - val = MT_LED_CTRL_REPLAY(mt76->led_pin) | - MT_LED_CTRL_KICK(mt76->led_pin); - if (mt76->led_al) - val |= MT_LED_CTRL_POLARITY(mt76->led_pin); - addr = mt7615_reg_map(dev, MT_LED_CTRL); - mt76_wr(dev, addr, val); -} - -static int -mt7615_led_set_blink(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - u8 delta_on, delta_off; - - delta_off = max_t(u8, *delay_off / 10, 1); - delta_on = max_t(u8, *delay_on / 10, 1); - - mt7615_led_set_config(led_cdev, delta_on, delta_off); - - return 0; -} - -static void -mt7615_led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - if (!brightness) - mt7615_led_set_config(led_cdev, 0, 0xff); - else - mt7615_led_set_config(led_cdev, 0xff, 0); -} - -static void -mt7615_init_txpower(struct mt7615_dev *dev, - struct ieee80211_supported_band *sband) +void mt7615_init_txpower(struct mt7615_dev *dev, + struct ieee80211_supported_band *sband) { int i, n_chains = hweight8(dev->mphy.antenna_mask), target_chains; u8 *eep = (u8 *)dev->mt76.eeprom.data; @@ -326,6 +215,7 @@ mt7615_init_txpower(struct mt7615_dev *dev, chan->orig_mpwr = target_power; } } +EXPORT_SYMBOL_GPL(mt7615_init_txpower); static void mt7615_regd_notifier(struct wiphy *wiphy, @@ -467,6 +357,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) return ret; } +EXPORT_SYMBOL_GPL(mt7615_register_ext_phy); void mt7615_unregister_ext_phy(struct mt7615_dev *dev) { @@ -480,6 +371,7 @@ void mt7615_unregister_ext_phy(struct mt7615_dev *dev) mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); } +EXPORT_SYMBOL_GPL(mt7615_unregister_ext_phy); void mt7615_init_device(struct mt7615_dev *dev) { @@ -505,64 +397,4 @@ void mt7615_init_device(struct mt7615_dev *dev) mt7615_cap_dbdc_disable(dev); dev->phy.dfs_state = -1; } - -int mt7615_register_device(struct mt7615_dev *dev) -{ - int ret; - - mt7615_init_device(dev); - - /* init led callbacks */ - if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness; - dev->mt76.led_cdev.blink_set = mt7615_led_set_blink; - } - - ret = mt7622_wmac_init(dev); - if (ret) - return ret; - - ret = mt7615_init_hardware(dev); - if (ret) - return ret; - - ret = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); - if (ret) - return ret; - - ieee80211_queue_work(mt76_hw(dev), &dev->mcu_work); - mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); - - return mt7615_init_debugfs(dev); -} - -void mt7615_unregister_device(struct mt7615_dev *dev) -{ - struct mt76_txwi_cache *txwi; - bool mcu_running; - int id; - - mcu_running = mt7615_wait_for_mcu_init(dev); - - mt7615_unregister_ext_phy(dev); - mt76_unregister_device(&dev->mt76); - if (mcu_running) - mt7615_mcu_exit(dev); - mt7615_dma_cleanup(dev); - - spin_lock_bh(&dev->token_lock); - idr_for_each_entry(&dev->token, txwi, id) { - mt7615_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) - dev_kfree_skb_any(txwi->skb); - mt76_put_txwi(&dev->mt76, txwi); - } - spin_unlock_bh(&dev->token_lock); - idr_destroy(&dev->token); - - tasklet_disable(&dev->irq_tasklet); - - mt76_free_device(&dev->mt76); -} +EXPORT_SYMBOL_GPL(mt7615_init_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5614cd691885..adaf52058bc5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -181,7 +181,7 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } -int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) +static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -424,40 +424,7 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { } - -void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, - struct mt76_queue_entry *e) -{ - if (!e->txwi) { - dev_kfree_skb_any(e->skb); - return; - } - - /* error path */ - if (e->skb == DMA_DUMMY_DATA) { - struct mt76_txwi_cache *t; - struct mt7615_dev *dev; - struct mt7615_txp_common *txp; - u16 token; - - dev = container_of(mdev, struct mt7615_dev, mt76); - txp = mt7615_txwi_to_txp(mdev, e->txwi); - - if (is_mt7615(&dev->mt76)) - token = le16_to_cpu(txp->fw.token); - else - token = le16_to_cpu(txp->hw.msdu_id[0]) & - ~MT_MSDU_ID_VALID; - - spin_lock_bh(&dev->token_lock); - t = idr_remove(&dev->token, token); - spin_unlock_bh(&dev->token_lock); - e->skb = t ? t->skb : NULL; - } - - if (e->skb) - mt76_tx_complete_skb(mdev, e->skb); -} +EXPORT_SYMBOL_GPL(mt7615_sta_ps); static u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev, @@ -672,6 +639,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, return 0; } +EXPORT_SYMBOL_GPL(mt7615_mac_write_txwi); static void mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp) @@ -725,6 +693,7 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev, else mt7615_txp_skb_unmap_hw(dev, &txp->hw); } +EXPORT_SYMBOL_GPL(mt7615_txp_skb_unmap); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) { @@ -810,6 +779,7 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev) rcu_read_unlock(); } +EXPORT_SYMBOL_GPL(mt7615_mac_sta_poll); static void mt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, @@ -965,6 +935,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; } +EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, @@ -1102,141 +1073,6 @@ out: return err; } -static void -mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, - void *txp_ptr, u32 id) -{ - struct mt7615_hw_txp *txp = txp_ptr; - struct mt7615_txp_ptr *ptr = &txp->ptr[0]; - int i, nbuf = tx_info->nbuf - 1; - u32 last_mask; - - tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); - tx_info->nbuf = 1; - - txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); - - if (is_mt7663(&dev->mt76)) - last_mask = MT_TXD_LEN_LAST; - else - last_mask = MT_TXD_LEN_AMSDU_LAST | - MT_TXD_LEN_MSDU_LAST; - - for (i = 0; i < nbuf; i++) { - u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; - u32 addr = tx_info->buf[i + 1].addr; - - if (i == nbuf - 1) - len |= last_mask; - - if (i & 1) { - ptr->buf1 = cpu_to_le32(addr); - ptr->len1 = cpu_to_le16(len); - ptr++; - } else { - ptr->buf0 = cpu_to_le32(addr); - ptr->len0 = cpu_to_le16(len); - } - } -} - -static void -mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, - void *txp_ptr, u32 id) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); - struct ieee80211_key_conf *key = info->control.hw_key; - struct ieee80211_vif *vif = info->control.vif; - struct mt7615_fw_txp *txp = txp_ptr; - int nbuf = tx_info->nbuf - 1; - int i; - - for (i = 0; i < nbuf; i++) { - txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); - txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); - } - txp->nbuf = nbuf; - - /* pass partial skb header to fw */ - tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); - tx_info->buf[1].len = MT_CT_PARSE_LEN; - tx_info->nbuf = MT_CT_DMA_BUF_NUM; - - txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); - - if (!key) - txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); - - if (ieee80211_is_mgmt(hdr->frame_control)) - txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); - - if (vif) { - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - - txp->bss_idx = mvif->idx; - } - - txp->token = cpu_to_le16(id); - txp->rept_wds_wcid = 0xff; -} - -int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, - enum mt76_txq_id qid, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, - struct mt76_tx_info *tx_info) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); - struct ieee80211_key_conf *key = info->control.hw_key; - int pid, id; - u8 *txwi = (u8 *)txwi_ptr; - struct mt76_txwi_cache *t; - void *txp; - - if (!wcid) - wcid = &dev->mt76.global_wcid; - - pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { - struct mt7615_phy *phy = &dev->phy; - - if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2) - phy = mdev->phy2->priv; - - spin_lock_bh(&dev->mt76.lock); - mt7615_mac_set_rates(phy, msta, &info->control.rates[0], - msta->rates); - msta->rate_probe = true; - spin_unlock_bh(&dev->mt76.lock); - } - - t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); - t->skb = tx_info->skb; - - spin_lock_bh(&dev->token_lock); - id = idr_alloc(&dev->token, t, 0, MT7615_TOKEN_SIZE, GFP_ATOMIC); - spin_unlock_bh(&dev->token_lock); - if (id < 0) - return id; - - mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta, - pid, key, false); - - txp = txwi + MT_TXD_SIZE; - memset(txp, 0, sizeof(struct mt7615_txp_common)); - if (is_mt7615(&dev->mt76)) - mt7615_write_fw_txp(dev, tx_info, txp, id); - else - mt7615_write_hw_txp(dev, tx_info, txp, id); - - tx_info->skb = DMA_DUMMY_DATA; - - return 0; -} - static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_info *info, __le32 *txs_data) { @@ -1414,7 +1250,7 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, return !!skb; } -void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) +static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; @@ -1491,7 +1327,7 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token) mt76_put_txwi(mdev, txwi); } -void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) +static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data; u8 i, count; @@ -1512,6 +1348,46 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) dev_kfree_skb(skb); } +void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + __le32 *end = (__le32 *)&skb->data[skb->len]; + enum rx_pkt_type type; + u16 flag; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0])); + if (type == PKT_TYPE_RX_EVENT && flag == 0x1) + type = PKT_TYPE_NORMAL_MCU; + + switch (type) { + case PKT_TYPE_TXS: + for (rxd++; rxd + 7 <= end; rxd += 7) + mt7615_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; + case PKT_TYPE_TXRX_NOTIFY: + mt7615_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7615_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_NORMAL_MCU: + case PKT_TYPE_NORMAL: + if (!mt7615_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + /* fall through */ + default: + dev_kfree_skb(skb); + break; + } +} +EXPORT_SYMBOL_GPL(mt7615_queue_rx_skb); + static void mt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) { @@ -1764,6 +1640,7 @@ void mt7615_update_channel(struct mt76_dev *mdev) /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } +EXPORT_SYMBOL_GPL(mt7615_update_channel); static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 33f67c7ccbf8..5777e5e62ef0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -4,11 +4,10 @@ * Author: Roy Luo * Ryder Lee * Felix Fietkau + * Lorenzo Bianconi */ #include -#include -#include #include #include "mt7615.h" #include "mcu.h" @@ -496,6 +495,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; } +EXPORT_SYMBOL_GPL(mt7615_mac_sta_add); void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -512,6 +512,7 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); } +EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove); static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -832,31 +833,6 @@ const struct ieee80211_ops mt7615_ops = { .sched_scan_start = mt7615_start_sched_scan, .sched_scan_stop = mt7615_stop_sched_scan, }; +EXPORT_SYMBOL_GPL(mt7615_ops); -static int __init mt7615_init(void) -{ - int ret; - - ret = pci_register_driver(&mt7615_pci_driver); - if (ret) - return ret; - - if (IS_ENABLED(CONFIG_MT7622_WMAC)) { - ret = platform_driver_register(&mt7622_wmac_driver); - if (ret) - pci_unregister_driver(&mt7615_pci_driver); - } - - return ret; -} - -static void __exit mt7615_exit(void) -{ - if (IS_ENABLED(CONFIG_MT7622_WMAC)) - platform_driver_unregister(&mt7622_wmac_driver); - pci_unregister_driver(&mt7615_pci_driver); -} - -module_init(mt7615_init); -module_exit(mt7615_exit); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f51d252c5f49..39d596436480 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -152,6 +152,7 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, break; } } +EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg); static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq) @@ -215,6 +216,7 @@ int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq) return ret; } +EXPORT_SYMBOL_GPL(mt7615_mcu_wait_response); static int mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, @@ -238,9 +240,8 @@ out: return ret; } -static int -mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, - int len, bool wait_resp) +int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, + int len, bool wait_resp) { struct sk_buff *skb; @@ -250,6 +251,7 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp); } +EXPORT_SYMBOL_GPL(mt7615_mcu_msg_send); static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) @@ -1629,11 +1631,12 @@ static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr, &req, sizeof(req), true); } -static int mt7615_mcu_restart(struct mt76_dev *dev) +int mt7615_mcu_restart(struct mt76_dev *dev) { return __mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL, 0, true); } +EXPORT_SYMBOL_GPL(mt7615_mcu_restart); static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get) { @@ -2165,6 +2168,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt7615_mcu_init); void mt7615_mcu_exit(struct mt7615_dev *dev) { @@ -2172,6 +2176,7 @@ void mt7615_mcu_exit(struct mt7615_dev *dev) mt7615_firmware_own(dev); skb_queue_purge(&dev->mt76.mcu.res_q); } +EXPORT_SYMBOL_GPL(mt7615_mcu_exit); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) { @@ -2214,6 +2219,7 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) return __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE, true); } +EXPORT_SYMBOL_GPL(mt7615_mcu_set_eeprom); int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable) { @@ -2355,6 +2361,7 @@ int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev) return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, &req, sizeof(req), true); } +EXPORT_SYMBOL_GPL(mt7615_mcu_del_wtbl_all); int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, enum mt7615_rdd_cmd cmd, u8 index, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index e9f9cda6bb59..2c4b1a315d5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "mt7615.h" #include "regs.h" @@ -191,3 +193,31 @@ error: ieee80211_free_hw(mt76_hw(dev)); return ret; } + +static int __init mt7615_init(void) +{ + int ret; + + ret = pci_register_driver(&mt7615_pci_driver); + if (ret) + return ret; + + if (IS_ENABLED(CONFIG_MT7622_WMAC)) { + ret = platform_driver_register(&mt7622_wmac_driver); + if (ret) + pci_unregister_driver(&mt7615_pci_driver); + } + + return ret; +} + +static void __exit mt7615_exit(void) +{ + if (IS_ENABLED(CONFIG_MT7622_WMAC)) + platform_driver_unregister(&mt7622_wmac_driver); + pci_unregister_driver(&mt7615_pci_driver); +} + +module_init(mt7615_init); +module_exit(mt7615_exit); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 57c9c1ef8ffc..fb891b80718b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -342,6 +342,7 @@ mt7615_ext_phy(struct mt7615_dev *dev) return phy->priv; } +extern struct ieee80211_rate mt7615_rates[12]; extern const struct ieee80211_ops mt7615_ops; extern const u32 mt7615e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663e_reg_map[__MT_BASE_MAX]; @@ -419,6 +420,12 @@ static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) } void mt7615_scan_work(struct work_struct *work); +void mt7615_init_txpower(struct mt7615_dev *dev, + struct ieee80211_supported_band *sband); +void mt7615_phy_init(struct mt7615_dev *dev); +void mt7615_mac_init(struct mt7615_dev *dev); + +int mt7615_mcu_restart(struct mt76_dev *dev); void mt7615_update_channel(struct mt76_dev *mdev); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); @@ -431,9 +438,6 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key, bool beacon); void mt7615_mac_set_timing(struct mt7615_phy *phy); -int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb); -void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data); -void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb); int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, enum set_key_cmd cmd); @@ -453,6 +457,8 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, void mt7615_mac_reset_work(struct work_struct *work); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); +int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, + int len, bool wait_resp); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c new file mode 100644 index 000000000000..3a8dd334b53e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2019 MediaTek Inc. + * + * Author: Roy Luo + * Ryder Lee + * Felix Fietkau + * Lorenzo Bianconi + */ + +#include +#include "mt7615.h" +#include "mac.h" +#include "eeprom.h" + +static void mt7615_init_work(struct work_struct *work) +{ + struct mt7615_dev *dev = container_of(work, struct mt7615_dev, + mcu_work); + + if (mt7615_mcu_init(dev)) + return; + + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + + if (!mt7615_firmware_offload(dev)) { + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + + dev->ops->hw_scan = NULL; + dev->ops->cancel_hw_scan = NULL; + dev->ops->sched_scan_start = NULL; + dev->ops->sched_scan_stop = NULL; + + wiphy->max_sched_scan_plan_interval = 0; + wiphy->max_sched_scan_ie_len = 0; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_reqs = 0; + } +} + +static int mt7615_init_hardware(struct mt7615_dev *dev) +{ + u32 addr = mt7615_reg_map(dev, MT_EFUSE_BASE); + int ret, idx; + + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + + INIT_WORK(&dev->mcu_work, mt7615_init_work); + spin_lock_init(&dev->token_lock); + idr_init(&dev->token); + + ret = mt7615_eeprom_init(dev, addr); + if (ret < 0) + return ret; + + ret = mt7615_dma_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +static void +mt7615_led_set_config(struct led_classdev *led_cdev, + u8 delay_on, u8 delay_off) +{ + struct mt7615_dev *dev; + struct mt76_dev *mt76; + u32 val, addr; + + mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); + dev = container_of(mt76, struct mt7615_dev, mt76); + val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | + FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | + FIELD_PREP(MT_LED_STATUS_ON, delay_on); + + addr = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin)); + mt76_wr(dev, addr, val); + addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin)); + mt76_wr(dev, addr, val); + + val = MT_LED_CTRL_REPLAY(mt76->led_pin) | + MT_LED_CTRL_KICK(mt76->led_pin); + if (mt76->led_al) + val |= MT_LED_CTRL_POLARITY(mt76->led_pin); + addr = mt7615_reg_map(dev, MT_LED_CTRL); + mt76_wr(dev, addr, val); +} + +static int +mt7615_led_set_blink(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + u8 delta_on, delta_off; + + delta_off = max_t(u8, *delay_off / 10, 1); + delta_on = max_t(u8, *delay_on / 10, 1); + + mt7615_led_set_config(led_cdev, delta_on, delta_off); + + return 0; +} + +static void +mt7615_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + if (!brightness) + mt7615_led_set_config(led_cdev, 0, 0xff); + else + mt7615_led_set_config(led_cdev, 0xff, 0); +} + +int mt7615_register_device(struct mt7615_dev *dev) +{ + int ret; + + mt7615_init_device(dev); + + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness; + dev->mt76.led_cdev.blink_set = mt7615_led_set_blink; + } + + ret = mt7622_wmac_init(dev); + if (ret) + return ret; + + ret = mt7615_init_hardware(dev); + if (ret) + return ret; + + ret = mt76_register_device(&dev->mt76, true, mt7615_rates, + ARRAY_SIZE(mt7615_rates)); + if (ret) + return ret; + + ieee80211_queue_work(mt76_hw(dev), &dev->mcu_work); + mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); + mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); + + return mt7615_init_debugfs(dev); +} + +void mt7615_unregister_device(struct mt7615_dev *dev) +{ + struct mt76_txwi_cache *txwi; + bool mcu_running; + int id; + + mcu_running = mt7615_wait_for_mcu_init(dev); + + mt7615_unregister_ext_phy(dev); + mt76_unregister_device(&dev->mt76); + if (mcu_running) + mt7615_mcu_exit(dev); + mt7615_dma_cleanup(dev); + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7615_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) + dev_kfree_skb_any(txwi->skb); + mt76_put_txwi(&dev->mt76, txwi); + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); + + tasklet_disable(&dev->irq_tasklet); + + mt76_free_device(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c new file mode 100644 index 000000000000..7ec91c0856f5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Ryder Lee + * Roy Luo + * Felix Fietkau + * Lorenzo Bianconi + */ + +#include +#include + +#include "mt7615.h" +#include "../dma.h" +#include "mac.h" + +void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_txwi_cache *t; + struct mt7615_dev *dev; + struct mt7615_txp_common *txp; + u16 token; + + dev = container_of(mdev, struct mt7615_dev, mt76); + txp = mt7615_txwi_to_txp(mdev, e->txwi); + + if (is_mt7615(&dev->mt76)) + token = le16_to_cpu(txp->fw.token); + else + token = le16_to_cpu(txp->hw.msdu_id[0]) & + ~MT_MSDU_ID_VALID; + + spin_lock_bh(&dev->token_lock); + t = idr_remove(&dev->token, token); + spin_unlock_bh(&dev->token_lock); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) + mt76_tx_complete_skb(mdev, e->skb); +} + +static void +mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id) +{ + struct mt7615_hw_txp *txp = txp_ptr; + struct mt7615_txp_ptr *ptr = &txp->ptr[0]; + int i, nbuf = tx_info->nbuf - 1; + u32 last_mask; + + tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); + tx_info->nbuf = 1; + + txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); + + if (is_mt7663(&dev->mt76)) + last_mask = MT_TXD_LEN_LAST; + else + last_mask = MT_TXD_LEN_AMSDU_LAST | + MT_TXD_LEN_MSDU_LAST; + + for (i = 0; i < nbuf; i++) { + u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK; + u32 addr = tx_info->buf[i + 1].addr; + + if (i == nbuf - 1) + len |= last_mask; + + if (i & 1) { + ptr->buf1 = cpu_to_le32(addr); + ptr->len1 = cpu_to_le16(len); + ptr++; + } else { + ptr->buf0 = cpu_to_le32(addr); + ptr->len0 = cpu_to_le16(len); + } + } +} + +static void +mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, + void *txp_ptr, u32 id) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct ieee80211_vif *vif = info->control.vif; + struct mt7615_fw_txp *txp = txp_ptr; + int nbuf = tx_info->nbuf - 1; + int i; + + for (i = 0; i < nbuf; i++) { + txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); + txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + } + txp->nbuf = nbuf; + + /* pass partial skb header to fw */ + tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); + tx_info->buf[1].len = MT_CT_PARSE_LEN; + tx_info->nbuf = MT_CT_DMA_BUF_NUM; + + txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); + + if (!key) + txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); + + if (ieee80211_is_mgmt(hdr->frame_control)) + txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); + + if (vif) { + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + + txp->bss_idx = mvif->idx; + } + + txp->token = cpu_to_le16(id); + txp->rept_wds_wcid = 0xff; +} + +int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + int pid, id; + u8 *txwi = (u8 *)txwi_ptr; + struct mt76_txwi_cache *t; + void *txp; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + struct mt7615_phy *phy = &dev->phy; + + if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2) + phy = mdev->phy2->priv; + + spin_lock_bh(&dev->mt76.lock); + mt7615_mac_set_rates(phy, msta, &info->control.rates[0], + msta->rates); + msta->rate_probe = true; + spin_unlock_bh(&dev->mt76.lock); + } + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + spin_lock_bh(&dev->token_lock); + id = idr_alloc(&dev->token, t, 0, MT7615_TOKEN_SIZE, GFP_ATOMIC); + spin_unlock_bh(&dev->token_lock); + if (id < 0) + return id; + + mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta, + pid, key, false); + + txp = txwi + MT_TXD_SIZE; + memset(txp, 0, sizeof(struct mt7615_txp_common)); + if (is_mt7615(&dev->mt76)) + mt7615_write_fw_txp(dev, tx_info, txp, id); + else + mt7615_write_hw_txp(dev, tx_info, txp, id); + + tx_info->skb = DMA_DUMMY_DATA; + + return 0; +} -- cgit From eb99cc95c3b6513b495c4839ac4917206705f657 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 16 Apr 2020 16:32:51 +0200 Subject: mt76: mt7615: introduce mt7663u support Introduce support for mt7663u 802.11ac 2x2:2 chipset to mt7615 driver. Main difference respect to pcie code base is the usb code needs to configure wtbl from non-atomic context Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/Kconfig | 11 + drivers/net/wireless/mediatek/mt76/mt7615/Makefile | 3 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 28 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 5 +- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 34 ++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 5 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 10 + drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 26 ++ drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 396 +++++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7615/usb_init.c | 144 ++++++++ .../net/wireless/mediatek/mt76/mt7615/usb_mcu.c | 93 +++++ 13 files changed, 756 insertions(+), 3 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/usb.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e31d98a4f88f..577465c01827 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -285,6 +285,7 @@ enum { MT76_MCU_RESET, MT76_REMOVED, MT76_READING_STATS, + MT76_STATE_POWER_OFF, }; struct mt76_hw_cap { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index 16385767d8b9..a84317fb856f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -27,3 +27,14 @@ config MT7622_WMAC This adds support for the built-in WMAC on MT7622 SoC devices which has the same feature set as a MT7615, but limited to 2.4 GHz only. + +config MT7663U + tristate "MediaTek MT7663U (USB) support" + select MT76_USB + select MT7615_COMMON + depends on MAC80211 + depends on USB + help + This adds support for MT7663U 802.11ax 2x2:2 wireless devices. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 2a7937b4394f..99f353b8b9aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o +obj-$(CONFIG_MT7663U) += mt7663u.o CFLAGS_trace.o := -I$(src) @@ -10,3 +11,5 @@ mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \ mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o mt7615e-$(CONFIG_MT7622_WMAC) += soc.o + +mt7663u-y := usb.o usb_mcu.o usb_init.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index adaf52058bc5..571554ffe8b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -871,6 +871,29 @@ mt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, rd->bw = bw; } +static int +mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, + struct ieee80211_tx_rate *probe_rate, + struct ieee80211_tx_rate *rates) +{ + struct mt7615_dev *dev = phy->dev; + struct mt7615_wtbl_desc *wd; + + wd = kzalloc(sizeof(*wd), GFP_ATOMIC); + if (!wd) + return -ENOMEM; + + wd->type = MT7615_WTBL_RATE_DESC; + wd->sta = sta; + + mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, + &wd->rate); + list_add_tail(&wd->node, &dev->wd_head); + queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + + return 0; +} + void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -880,6 +903,11 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct mt7615_rate_desc rd; u32 w5, w27, addr; + if (mt76_is_usb(&dev->mt76)) { + mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates); + return; + } + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 8ee57d220d71..f0d4b29a52a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -165,9 +165,12 @@ enum tx_phy_bandwidth { #define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) #define MT_CT_INFO_HSR2_TX BIT(4) -#define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) #define MT_TXD_SIZE (8 * 4) +#define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) +#define MT_USB_HDR_SIZE 4 +#define MT_USB_TAIL_SIZE 4 + #define MT_TXD0_P_IDX BIT(31) #define MT_TXD0_Q_IDX GENMASK(30, 26) #define MT_TXD0_UDP_TCP_SUM BIT(24) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 5777e5e62ef0..f7fc2185da3b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -277,6 +277,37 @@ out: return ret; } +static int +mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd, + struct mt7615_sta *msta, + struct ieee80211_key_conf *key) +{ + struct mt7615_wtbl_desc *wd; + + wd = kzalloc(sizeof(*wd), GFP_KERNEL); + if (!wd) + return -ENOMEM; + + wd->type = MT7615_WTBL_KEY_DESC; + wd->sta = msta; + + wd->key.key = kzalloc(key->keylen, GFP_KERNEL); + if (!wd->key.key) { + kfree(wd); + return -ENOMEM; + } + memcpy(wd->key.key, key->key, key->keylen); + wd->key.cipher = key->cipher; + wd->key.keyidx = key->keyidx; + wd->key.keylen = key->keylen; + wd->key.cmd = cmd; + + list_add_tail(&wd->node, &dev->wd_head); + queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + + return 0; +} + static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -325,6 +356,9 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt76_wcid_key_setup(&dev->mt76, wcid, cmd == SET_KEY ? key : NULL); + if (mt76_is_usb(&dev->mt76)) + return mt7615_queue_key_update(dev, cmd, msta, key); + return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 39d596436480..939aeb03b568 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1598,8 +1598,7 @@ static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data, int ret = 0, cur_len; while (len > 0) { - cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd), - len); + cur_len = min_t(int, 4096 - dev->mt76.mcu_ops->headroom, len); ret = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_SCATTER, data, cur_len, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 983625fb72ee..dff3f3632faf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -449,6 +449,11 @@ enum { FW_STATE_CR4_RDY = 7 }; +enum { + FW_STATE_PWR_ON = 1, + FW_STATE_N9_RDY = 2, +}; + #define STA_TYPE_STA BIT(0) #define STA_TYPE_AP BIT(1) #define STA_TYPE_ADHOC BIT(2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index fb891b80718b..2bc77a0478a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -269,6 +269,9 @@ struct mt7615_dev { struct idr token; u8 fw_ver; + + struct work_struct wtbl_work; + struct list_head wd_head; }; enum { @@ -508,6 +511,13 @@ int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); +int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); + int __mt7663_load_firmware(struct mt7615_dev *dev); +/* usb */ +void mt7663u_wtbl_work(struct work_struct *work); +int mt7663u_mcu_init(struct mt7615_dev *dev); +int mt7663u_register_device(struct mt7615_dev *dev); + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index a3333f382350..370e03432e81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -43,6 +43,7 @@ enum mt7615_reg_base { #define MT_TOP_MISC2_FW_STATE GENMASK(2, 0) #define MT7663_TOP_MISC2_FW_STATE GENMASK(3, 1) +#define MT_TOP_MISC2_FW_PWR_ON BIT(1) #define MT_MCU_BASE 0x2000 #define MT_MCU(ofs) (MT_MCU_BASE + (ofs)) @@ -58,6 +59,8 @@ enum mt7615_reg_base { #define MT_PCIE_REMAP_BASE_2 ((dev)->reg_map[MT_PCIE_REMAP_BASE2]) #define MT_HIF(ofs) ((dev)->reg_map[MT_HIF_BASE] + (ofs)) +#define MT_HIF_RST MT_HIF(0x100) +#define MT_HIF_LOGIC_RST_N BIT(4) #define MT7663_MCU_PCIE_REMAP_2_OFFSET GENMASK(15, 0) #define MT7663_MCU_PCIE_REMAP_2_BASE GENMASK(31, 16) @@ -483,4 +486,27 @@ enum mt7615_reg_base { #define MT_INFRACFG_MISC 0x700 #define MT_INFRACFG_MISC_AP2CONN_WAKE BIT(1) +#define MT_UMAC_BASE 0x7c000000 +#define MT_UMAC(ofs) (MT_UMAC_BASE + (ofs)) +#define MT_UDMA_TX_QSEL MT_UMAC(0x008) +#define MT_FW_DL_EN BIT(3) + +#define MT_UDMA_WLCFG_1 MT_UMAC(0x00c) +#define MT_WL_RX_AGG_PKT_LMT GENMASK(7, 0) +#define MT_WL_TX_TMOUT_LMT GENMASK(27, 8) + +#define MT_UDMA_WLCFG_0 MT_UMAC(0x18) +#define MT_WL_RX_AGG_TO GENMASK(7, 0) +#define MT_WL_RX_AGG_LMT GENMASK(15, 8) +#define MT_WL_TX_TMOUT_FUNC_EN BIT(16) +#define MT_WL_TX_DPH_CHK_EN BIT(17) +#define MT_WL_RX_MPSZ_PAD0 BIT(18) +#define MT_WL_RX_FLUSH BIT(19) +#define MT_TICK_1US_EN BIT(20) +#define MT_WL_RX_AGG_EN BIT(21) +#define MT_WL_RX_EN BIT(22) +#define MT_WL_TX_EN BIT(23) +#define MT_WL_RX_BUSY BIT(30) +#define MT_WL_TX_BUSY BIT(31) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c new file mode 100644 index 000000000000..ad5219006987 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2019 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +static const u32 mt7663u_reg_map[] = { + [MT_TOP_CFG_BASE] = 0x80020000, + [MT_HW_BASE] = 0x80000000, + [MT_DMA_SHDL_BASE] = 0x5000a000, + [MT_HIF_BASE] = 0x50000000, + [MT_CSR_BASE] = 0x40000000, + [MT_EFUSE_ADDR_BASE] = 0x78011000, + [MT_TOP_MISC_BASE] = 0x81020000, + [MT_PHY_BASE] = 0x82070000, + [MT_WTBL_BASE_ADDR] = 0x820e0000, + [MT_CFG_BASE] = 0x820f0000, + [MT_AGG_BASE] = 0x820f2000, + [MT_ARB_BASE] = 0x820f3000, + [MT_TMAC_BASE] = 0x820f4000, + [MT_RMAC_BASE] = 0x820f5000, + [MT_DMA_BASE] = 0x820f7000, + [MT_WTBL_BASE_ON] = 0x820f9000, + [MT_WTBL_BASE_OFF] = 0x820f9800, + [MT_LPON_BASE] = 0x820fb000, + [MT_MIB_BASE] = 0x820fd000, +}; + +static const struct usb_device_id mt7615_device_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7663, 0xff, 0xff, 0xff) }, + { }, +}; + +static void mt7663u_stop(struct ieee80211_hw *hw) +{ + struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt7615_dev *dev = hw->priv; + + clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mac_work); + mt76u_stop_tx(&dev->mt76); +} + +static void mt7663u_cleanup(struct mt7615_dev *dev) +{ + clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + mt76u_queues_deinit(&dev->mt76); +} + +static void +mt7663u_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, + enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + __le32 *txwi; + int pid; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + + txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); + memset(txwi, 0, MT_USB_TXD_SIZE); + mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, + pid, info->control.hw_key, false); + skb_push(skb, MT_USB_TXD_SIZE); +} + +static int +__mt7663u_mac_set_rates(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_rate_desc *rate = &wd->rate; + struct mt7615_sta *sta = wd->sta; + u32 w5, w27, addr, val; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) + return -EINVAL; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return -ETIMEDOUT; + + addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); + + w27 = mt76_rr(dev, addr + 27 * 4); + w27 &= ~MT_WTBL_W27_CC_BW_SEL; + w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); + + w5 = mt76_rr(dev, addr + 5 * 4); + w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | + MT_WTBL_W5_MPDU_OK_COUNT | + MT_WTBL_W5_MPDU_FAIL_COUNT | + MT_WTBL_W5_RATE_IDX); + w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | + FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, + rate->bw_idx ? rate->bw_idx - 1 : 7); + + mt76_wr(dev, MT_WTBL_RIUCR0, w5); + + mt76_wr(dev, MT_WTBL_RIUCR1, + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); + + mt76_wr(dev, MT_WTBL_RIUCR2, + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); + + mt76_wr(dev, MT_WTBL_RIUCR3, + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); + + mt76_wr(dev, MT_WTBL_UPDATE, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | + MT_WTBL_UPDATE_RATE_UPDATE | + MT_WTBL_UPDATE_TX_COUNT_CLEAR); + + mt76_wr(dev, addr + 27 * 4, w27); + + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ + val = mt76_rr(dev, MT_LPON_UTTR0); + sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; + + if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; + sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + + return 0; +} + +static int +__mt7663u_mac_set_key(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_key_desc *key = &wd->key; + struct mt7615_sta *sta = wd->sta; + enum mt7615_cipher_type cipher; + struct mt76_wcid *wcid; + int err; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) + return -EINVAL; + + cipher = mt7615_mac_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) + return -EOPNOTSUPP; + + wcid = &wd->sta->wcid; + + mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd); + err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, + cipher, key->cmd); + if (err < 0) + return err; + + err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, + key->cmd); + if (err < 0) + return err; + + if (key->cmd == SET_KEY) + wcid->cipher |= BIT(cipher); + else + wcid->cipher &= ~BIT(cipher); + + return 0; +} + +void mt7663u_wtbl_work(struct work_struct *work) +{ + struct mt7615_wtbl_desc *wd, *wd_next; + struct mt7615_dev *dev; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + wtbl_work); + + list_for_each_entry_safe(wd, wd_next, &dev->wd_head, node) { + spin_lock_bh(&dev->mt76.lock); + list_del(&wd->node); + spin_unlock_bh(&dev->mt76.lock); + + mutex_lock(&dev->mt76.mutex); + switch (wd->type) { + case MT7615_WTBL_RATE_DESC: + __mt7663u_mac_set_rates(dev, wd); + break; + case MT7615_WTBL_KEY_DESC: + __mt7663u_mac_set_key(dev, wd); + break; + } + mutex_unlock(&dev->mt76.mutex); + + kfree(wd); + } +} + +static void +mt7663u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + skb_pull(e->skb, MT_USB_HDR_SIZE + MT_USB_TXD_SIZE); + mt76_tx_complete_skb(mdev, e->skb); +} + +static int +mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + struct mt7615_sta *msta; + + msta = container_of(wcid, struct mt7615_sta, wcid); + spin_lock_bh(&dev->mt76.lock); + mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], + msta->rates); + msta->rate_probe = true; + spin_unlock_bh(&dev->mt76.lock); + } + mt7663u_mac_write_txwi(dev, wcid, qid, sta, tx_info->skb); + + return mt76u_skb_dma_info(tx_info->skb, tx_info->skb->len); +} + +static int mt7663u_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = MT_USB_TXD_SIZE, + .drv_flags = MT_DRV_RX_DMA_HDR, + .tx_prepare_skb = mt7663u_tx_prepare_skb, + .tx_complete_skb = mt7663u_tx_complete_skb, + .rx_skb = mt7615_queue_rx_skb, + .sta_ps = mt7615_sta_ps, + .sta_add = mt7615_mac_sta_add, + .sta_remove = mt7615_mac_sta_remove, + .update_survey = mt7615_update_channel, + }; + struct usb_device *udev = interface_to_usbdev(usb_intf); + struct ieee80211_ops *ops; + struct mt7615_dev *dev; + struct mt76_dev *mdev; + int ret; + + ops = devm_kmemdup(&usb_intf->dev, &mt7615_ops, sizeof(mt7615_ops), + GFP_KERNEL); + if (!ops) + return -ENOMEM; + + ops->stop = mt7663u_stop; + + mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7615_dev, mt76); + udev = usb_get_dev(udev); + usb_reset_device(udev); + + usb_set_intfdata(usb_intf, dev); + + dev->reg_map = mt7663u_reg_map; + dev->ops = ops; + ret = mt76u_init(mdev, usb_intf, true); + if (ret < 0) + goto error; + + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + if (mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON, + FW_STATE_PWR_ON << 1, 500)) { + dev_dbg(dev->mt76.dev, "Usb device already powered on\n"); + set_bit(MT76_STATE_POWER_OFF, &dev->mphy.state); + goto alloc_queues; + } + + ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x0, 0x1, NULL, 0); + if (ret) + goto error; + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON, + FW_STATE_PWR_ON << 1, 500)) { + dev_err(dev->mt76.dev, "Timeout for power on\n"); + return -EIO; + } + +alloc_queues: + ret = mt76u_alloc_mcu_queue(&dev->mt76); + if (ret) + goto error; + + ret = mt76u_alloc_queues(&dev->mt76); + if (ret) + goto error; + + ret = mt7663u_register_device(dev); + if (ret) + goto error_freeq; + + return 0; + +error_freeq: + mt76u_queues_deinit(&dev->mt76); +error: + mt76u_deinit(&dev->mt76); + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); + + ieee80211_free_hw(mdev->hw); + + return ret; +} + +static void mt7663u_disconnect(struct usb_interface *usb_intf) +{ + struct mt7615_dev *dev = usb_get_intfdata(usb_intf); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return; + + ieee80211_unregister_hw(dev->mt76.hw); + mt7663u_cleanup(dev); + + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); + + mt76u_deinit(&dev->mt76); + ieee80211_free_hw(dev->mt76.hw); +} + +static int __maybe_unused +mt7663u_suspend(struct usb_interface *intf, + pm_message_t state) +{ + return 0; +} + +static int __maybe_unused +mt7663u_resume(struct usb_interface *intf) +{ + return 0; +} + +MODULE_DEVICE_TABLE(usb, mt7615_device_table); +MODULE_FIRMWARE(MT7663_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_ROM_PATCH); + +static struct usb_driver mt7663u_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7615_device_table, + .probe = mt7663u_probe, + .disconnect = mt7663u_disconnect, +#ifdef CONFIG_PM + .suspend = mt7663u_suspend, + .resume = mt7663u_resume, + .reset_resume = mt7663u_resume, +#endif /* CONFIG_PM */ + .soft_unbind = 1, + .disable_hub_initiated_lpm = 1, +}; +module_usb_driver(mt7663u_driver); + +MODULE_AUTHOR("Sean Wang "); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c new file mode 100644 index 000000000000..a05f0eda21dd --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ + +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "regs.h" + +static int mt7663u_dma_sched_init(struct mt7615_dev *dev) +{ + int i; + + mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), + MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); + + /* disable refill group 5 - group 15 and raise group 2 + * and 3 as high priority. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); + mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); + + for (i = 0; i < 5; i++) + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); + + /* group pririority from high to low: + * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); + + mt76_wr(dev, MT_UDMA_WLCFG_1, + FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | + FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); + + /* setup UDMA Rx Flush */ + mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); + /* hif reset */ + mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); + + mt76_set(dev, MT_UDMA_WLCFG_0, + MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | + MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | + MT_WL_TX_TMOUT_FUNC_EN); + mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, + FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | + FIELD_PREP(MT_WL_RX_AGG_TO, 100)); + + return 0; +} + +static int mt7663u_init_hardware(struct mt7615_dev *dev) +{ + int ret, idx; + + ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); + if (ret < 0) + return ret; + + ret = mt7663u_dma_sched_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +static void mt7663u_init_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + + dev = container_of(work, struct mt7615_dev, mcu_work); + if (mt7663u_mcu_init(dev)) + return; + + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); +} + +int mt7663u_register_device(struct mt7615_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int err; + + INIT_WORK(&dev->wtbl_work, mt7663u_wtbl_work); + INIT_WORK(&dev->mcu_work, mt7663u_init_work); + INIT_LIST_HEAD(&dev->wd_head); + mt7615_init_device(dev); + + err = mt7663u_init_hardware(dev); + if (err) + return err; + + hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE; + /* check hw sg support in order to enable AMSDU */ + hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; + + err = mt76_register_device(&dev->mt76, true, mt7615_rates, + ARRAY_SIZE(mt7615_rates)); + if (err < 0) + return err; + + if (!dev->mt76.usb.sg_en) { + struct ieee80211_sta_vht_cap *vht_cap; + + /* decrease max A-MSDU size if SG is not supported */ + vht_cap = &dev->mphy.sband_5g.sband.vht_cap; + vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + } + + ieee80211_queue_work(hw, &dev->mcu_work); + mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); + mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); + + return mt7615_init_debugfs(dev); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c new file mode 100644 index 000000000000..cd709fd617db --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +static int +mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + int ret, seq, ep; + + mutex_lock(&mdev->mcu.mutex); + + mt7615_mcu_fill_msg(dev, skb, cmd, &seq); + if (cmd != MCU_CMD_FW_SCATTER) + ep = MT_EP_OUT_INBAND_CMD; + else + ep = MT_EP_OUT_AC_BE; + + ret = mt76u_skb_dma_info(skb, skb->len); + if (ret < 0) + goto out; + + ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, + 1000, ep); + dev_kfree_skb(skb); + if (ret < 0) + goto out; + + if (wait_resp) + ret = mt7615_mcu_wait_response(dev, cmd, seq); + +out: + mutex_unlock(&mdev->mcu.mutex); + + return ret; +} + +int mt7663u_mcu_init(struct mt7615_dev *dev) +{ + static const struct mt76_mcu_ops mt7663u_mcu_ops = { + .headroom = MT_USB_HDR_SIZE + sizeof(struct mt7615_mcu_txd), + .tailroom = MT_USB_TAIL_SIZE, + .mcu_skb_send_msg = mt7663u_mcu_send_message, + .mcu_send_msg = mt7615_mcu_msg_send, + .mcu_restart = mt7615_mcu_restart, + }; + int ret; + + dev->mt76.mcu_ops = &mt7663u_mcu_ops, + + mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); + + if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { + mt7615_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_PWR_ON, 0, 500)) + return -EIO; + + ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x0, 0x1, NULL, 0); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_PWR_ON, + FW_STATE_PWR_ON << 1, 500)) { + dev_err(dev->mt76.dev, "Timeout for power on\n"); + return -EIO; + } + } + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} -- cgit From ad6b0be6f4e922ef0f2aea9d0e09f2c4cf3adc5e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 16 Apr 2020 16:36:19 +0200 Subject: mt76: mt7615: enable scs for mt7663 driver Add missing register definitions in order to enable sensitivity tuning for mt7663 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 77 +++++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 8 +++ 2 files changed, 58 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 571554ffe8b6..b6e92bb3b128 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1417,17 +1417,40 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, EXPORT_SYMBOL_GPL(mt7615_queue_rx_skb); static void -mt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) +mt7615_mac_set_sensitivity(struct mt7615_phy *phy, int val, bool ofdm) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; - mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), - MT_WF_PHY_PD_OFDM_MASK(ext_phy), - MT_WF_PHY_PD_OFDM(ext_phy, 0x13c)); - mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy), - MT_WF_PHY_PD_CCK_MASK(ext_phy), - MT_WF_PHY_PD_CCK(ext_phy, 0x92)); + if (is_mt7663(&dev->mt76)) { + if (ofdm) + mt76_rmw(dev, MT7663_WF_PHY_MIN_PRI_PWR(ext_phy), + MT_WF_PHY_PD_OFDM_MASK(0), + MT_WF_PHY_PD_OFDM(0, val)); + else + mt76_rmw(dev, MT7663_WF_PHY_RXTD_CCK_PD(ext_phy), + MT_WF_PHY_PD_CCK_MASK(ext_phy), + MT_WF_PHY_PD_CCK(ext_phy, val)); + return; + } + + if (ofdm) + mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), + MT_WF_PHY_PD_OFDM_MASK(ext_phy), + MT_WF_PHY_PD_OFDM(ext_phy, val)); + else + mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy), + MT_WF_PHY_PD_CCK_MASK(ext_phy), + MT_WF_PHY_PD_CCK(ext_phy, val)); +} + +static void +mt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) +{ + /* ofdm */ + mt7615_mac_set_sensitivity(phy, 0x13c, true); + /* cck */ + mt7615_mac_set_sensitivity(phy, 0x92, false); phy->ofdm_sensitivity = -98; phy->cck_sensitivity = -110; @@ -1438,25 +1461,29 @@ void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; + u32 reg, mask; mutex_lock(&dev->mt76.mutex); if (phy->scs_en == enable) goto out; - if (is_mt7663(&dev->mt76)) - goto out; + if (is_mt7663(&dev->mt76)) { + reg = MT7663_WF_PHY_MIN_PRI_PWR(ext_phy); + mask = MT_WF_PHY_PD_BLK(0); + } else { + reg = MT_WF_PHY_MIN_PRI_PWR(ext_phy); + mask = MT_WF_PHY_PD_BLK(ext_phy); + } if (enable) { - mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), - MT_WF_PHY_PD_BLK(ext_phy)); + mt76_set(dev, reg, mask); if (is_mt7622(&dev->mt76)) { mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8); mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7); } } else { - mt76_clear(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), - MT_WF_PHY_PD_BLK(ext_phy)); + mt76_clear(dev, reg, mask); } mt7615_mac_set_default_sensitivity(phy); @@ -1547,19 +1574,9 @@ mt7615_mac_adjust_sensitivity(struct mt7615_phy *phy, } if (update) { - u16 val; + u16 val = ofdm ? *sensitivity * 2 + 512 : *sensitivity + 256; - if (ofdm) { - val = *sensitivity * 2 + 512; - mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), - MT_WF_PHY_PD_OFDM_MASK(ext_phy), - MT_WF_PHY_PD_OFDM(ext_phy, val)); - } else { - val = *sensitivity + 256; - mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy), - MT_WF_PHY_PD_CCK_MASK(ext_phy), - MT_WF_PHY_PD_CCK(ext_phy, val)); - } + mt7615_mac_set_sensitivity(phy, val, ofdm); phy->last_cca_adj = jiffies; } } @@ -1576,11 +1593,17 @@ mt7615_mac_scs_check(struct mt7615_phy *phy) if (!phy->scs_en) return; - val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); + if (is_mt7663(&dev->mt76)) + val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); + else + val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val); pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val); - val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); + if (is_mt7663(&dev->mt76)) + val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); + else + val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val); mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 370e03432e81..ab3c6b77df07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -160,16 +160,22 @@ enum mt7615_reg_base { #define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16) #define MT_WF_PHYCTRL_STAT_PD_CCK GENMASK(15, 0) +#define MT7663_WF_PHY_R0_PHYCTRL_STS0(_phy) MT_WF_PHY(0x0210 + ((_phy) << 12)) + #define MT_WF_PHY_R0_PHYCTRL_STS5(_phy) MT_WF_PHY(0x0220 + ((_phy) << 9)) #define MT_WF_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16) #define MT_WF_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0) +#define MT7663_WF_PHY_R0_PHYCTRL_STS5(_phy) MT_WF_PHY(0x0224 + ((_phy) << 12)) + #define MT_WF_PHY_MIN_PRI_PWR(_phy) MT_WF_PHY((_phy) ? 0x084 : 0x229c) #define MT_WF_PHY_PD_OFDM_MASK(_phy) ((_phy) ? GENMASK(24, 16) : \ GENMASK(28, 20)) #define MT_WF_PHY_PD_OFDM(_phy, v) ((v) << ((_phy) ? 16 : 20)) #define MT_WF_PHY_PD_BLK(_phy) ((_phy) ? BIT(25) : BIT(19)) +#define MT7663_WF_PHY_MIN_PRI_PWR(_phy) MT_WF_PHY((_phy) ? 0x2aec : 0x22f0) + #define MT_WF_PHY_RXTD_BASE MT_WF_PHY(0x2200) #define MT_WF_PHY_RXTD(_n) (MT_WF_PHY_RXTD_BASE + ((_n) << 2)) @@ -180,6 +186,8 @@ enum mt7615_reg_base { GENMASK(8, 1) #define MT_WF_PHY_PD_CCK(_phy, v) ((v) << ((_phy) ? 24 : 1)) +#define MT7663_WF_PHY_RXTD_CCK_PD(_phy) MT_WF_PHY((_phy) ? 0x2350 : 0x234c) + #define MT_WF_PHY_RXTD2_BASE MT_WF_PHY(0x2a00) #define MT_WF_PHY_RXTD2(_n) (MT_WF_PHY_RXTD2_BASE + ((_n) << 2)) -- cgit From 450affca7b3d1964a6181e9acc033897bd8bab55 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Apr 2020 12:10:54 +0200 Subject: mt76: mt7615: disable aspm by default The vendor SDK also disables ASPM by default Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 4f8a3c637a98..21b3ec29aa12 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -41,6 +41,8 @@ static int mt7615_pci_probe(struct pci_dev *pdev, if (ret) return ret; + mt76_pci_disable_aspm(pdev); + map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map; return mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], pdev->irq, map); -- cgit From 60cb9843f33480d52eaa41ac2fc72940f3bfa17b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Apr 2020 13:10:04 +0200 Subject: mt76: mt7615: provide aid info to the mcu For sta mode mac80211 provides aid in vif->bss_conf.aid. In order to properly support 802.11 power-save, configure correct aid to mcu during sta association Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 939aeb03b568..530d6302b53a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -790,12 +790,15 @@ mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + basic->aid = cpu_to_le16(sta->aid); break; case NL80211_IFTYPE_STATION: basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + basic->aid = cpu_to_le16(vif->bss_conf.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + basic->aid = cpu_to_le16(sta->aid); break; default: WARN_ON(1); @@ -803,7 +806,6 @@ mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, } memcpy(basic->peer_addr, sta->addr, ETH_ALEN); - basic->aid = cpu_to_le16(sta->aid); basic->qos = sta->wme; } -- cgit From a7df11520997e8c67e28675e3170ae7e92e4a165 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Apr 2020 13:10:05 +0200 Subject: mt76: remove PS_NULLFUNC_STACK capability remove IEEE80211_HW_PS_NULLFUNC_STACK capability from mt76_phy_init routine since 802.11 ps is not currently supported by any devices and it will conflict with mt7663 ps fw support Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f44f99184c10..39abedc45e4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -294,7 +294,6 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) hw->max_tx_fragments = 16; ieee80211_hw_set(hw, SIGNAL_DBM); - ieee80211_hw_set(hw, PS_NULLFUNC_STACK); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); -- cgit From 7f8ebafebce3b0eae48e328ff75475d7181f83ac Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 17 Apr 2020 13:10:06 +0200 Subject: mt76: mt7663: introduce 802.11 PS support in sta mode Enable 802.11 power-save support available in mt7663 firmware Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 7 +++++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 23 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 21 ++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 ++++ .../net/wireless/mediatek/mt76/mt7615/pci_init.c | 8 ++++++-- .../net/wireless/mediatek/mt76/mt7615/usb_init.c | 3 +++ 9 files changed, 68 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 577465c01827..6106dc4fea44 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -286,6 +286,7 @@ enum { MT76_REMOVED, MT76_READING_STATS, MT76_STATE_POWER_OFF, + MT76_STATE_PS, }; struct mt76_hw_cap { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 9d9f73b4561e..6fc3f5aa94c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -323,6 +323,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); skb_queue_head_init(&phy->scan_event_list); + INIT_WORK(&dev->phy.ps_work, mt7615_ps_work); + mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); if (!mphy) @@ -386,7 +388,9 @@ void mt7615_init_device(struct mt7615_dev *dev) INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); init_waitqueue_head(&dev->reset_wait); + INIT_WORK(&dev->reset_work, mt7615_mac_reset_work); + INIT_WORK(&dev->phy.ps_work, mt7615_ps_work); mt7615_init_wiphy(hw); dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index b6e92bb3b128..3dab07d3eb1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -605,8 +605,11 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, } if (!ieee80211_is_beacon(fc)) { - val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT | - FIELD_PREP(MT_TXD5_PID, pid); + struct ieee80211_hw *hw = mt76_hw(dev); + + val = MT_TXD5_TX_STATUS_HOST | FIELD_PREP(MT_TXD5_PID, pid); + if (!ieee80211_hw_check(hw, SUPPORTS_PS)) + val |= MT_TXD5_SW_POWER_MGMT; txwi[5] = cpu_to_le32(val); } else { txwi[5] = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index f7fc2185da3b..8f8ad632d6ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -71,6 +71,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) struct mt7615_phy *phy = mt7615_hw_phy(hw); cancel_delayed_work_sync(&phy->mac_work); + cancel_work_sync(&phy->ps_work); mutex_lock(&dev->mt76.mutex); @@ -362,6 +363,20 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); } +void mt7615_ps_work(struct work_struct *work) +{ + struct mt7615_phy *phy; + + phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, + ps_work); + + mutex_lock(&phy->dev->mt76.mutex); + ieee80211_iterate_active_interfaces(phy->mt76->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + m7615_mcu_set_ps_iter, phy); + mutex_unlock(&phy->dev->mt76.mutex); +} + static int mt7615_config(struct ieee80211_hw *hw, u32 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); @@ -387,6 +402,14 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); } + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (hw->conf.flags & IEEE80211_CONF_PS) + set_bit(MT76_STATE_PS, &phy->mt76->state); + else + clear_bit(MT76_STATE_PS, &phy->mt76->state); + ieee80211_queue_work(hw, &phy->ps_work); + } + mutex_unlock(&dev->mt76.mutex); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 530d6302b53a..74cbb975be75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2586,6 +2586,27 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) sizeof(req), true); } +void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_phy *phy = priv; + struct mt76_phy *mphy = phy->mt76; + struct { + u8 bss_idx; + u8 ps_state; /* 0: device awake + * 1: static power save + * 2: dynamic power saving + */ + } req = { + .bss_idx = mvif->idx, + .ps_state = test_bit(MT76_STATE_PS, &mphy->state) ? 2 : 0, + }; + + if (vif->type == NL80211_IFTYPE_STATION) + __mt76_mcu_send_msg(&phy->dev->mt76, MCU_CMD_SET_PS_PROFILE, + &req, sizeof(req), false); +} + int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) { struct mt76_phy *mphy = phy->mt76; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index dff3f3632faf..5440f24a834a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -411,6 +411,7 @@ struct mt7615_mcu_bss_event { /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, + MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 2bc77a0478a9..c9533282e7e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -197,6 +197,8 @@ struct mt7615_phy { struct sk_buff_head scan_event_list; struct delayed_work scan_work; + + struct work_struct ps_work; }; #define mt7615_mcu_add_tx_ba(dev, ...) (dev)->mcu_ops->add_tx_ba((dev), __VA_ARGS__) @@ -423,6 +425,7 @@ static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) } void mt7615_scan_work(struct work_struct *work); +void mt7615_ps_work(struct work_struct *work); void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband); void mt7615_phy_init(struct mt7615_dev *dev); @@ -508,6 +511,7 @@ int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); +void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 3a8dd334b53e..cd3ccafa7d11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -16,6 +16,7 @@ static void mt7615_init_work(struct work_struct *work) { struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work); + struct ieee80211_hw *hw = mt76_hw(dev); if (mt7615_mcu_init(dev)) return; @@ -25,8 +26,11 @@ static void mt7615_init_work(struct work_struct *work) mt7615_phy_init(dev); mt7615_mcu_del_wtbl_all(dev); - if (!mt7615_firmware_offload(dev)) { - struct wiphy *wiphy = mt76_hw(dev)->wiphy; + if (mt7615_firmware_offload(dev)) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + } else { + struct wiphy *wiphy = hw->wiphy; dev->ops->hw_scan = NULL; dev->ops->cancel_hw_scan = NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c index a05f0eda21dd..39642065531f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c @@ -119,6 +119,9 @@ int mt7663u_register_device(struct mt7615_dev *dev) if (err) return err; + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE; /* check hw sg support in order to enable AMSDU */ hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; -- cgit From 18ab1d7a37576c10bdeb6409147ae715ddc2f925 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 17 Apr 2020 13:13:28 +0200 Subject: mt76: mt7615: make Kconfig entry obvious for MT7663E Make Kconfig entry obvious for MT7663E Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index a84317fb856f..e25db1135eda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -5,7 +5,7 @@ config MT7615_COMMON select MT76_CORE config MT7615E - tristate "MediaTek MT7615E (PCIe) support" + tristate "MediaTek MT7615E and MT7663E (PCIe) support" select MT7615_COMMON depends on MAC80211 depends on PCI -- cgit From 6ea62c50792c6ad8b283c02d19f4304c7f3a3ccf Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 19 Apr 2020 22:11:41 +0200 Subject: mt76: add rx queues info to mt76 debugfs Introduce rx-queues debugfs node in order to dump rx queues status. This would be useful for mcu fw debugging Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 21 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c | 4 ++-- .../net/wireless/mediatek/mt76/mt76x02_debugfs.c | 2 +- 4 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index d2202acb8dc6..0278e1b44576 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -46,6 +46,25 @@ int mt76_queues_read(struct seq_file *s, void *data) } EXPORT_SYMBOL_GPL(mt76_queues_read); +static int mt76_rx_queues_read(struct seq_file *s, void *data) +{ + struct mt76_dev *dev = dev_get_drvdata(s->private); + int i, queued; + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { + struct mt76_queue *q = &dev->q_rx[i]; + + if (!q->ndesc) + continue; + + queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; + seq_printf(s, "%d: queued=%d head=%d tail=%d\n", + i, queued, q->head, q->tail); + } + + return 0; +} + void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) { @@ -92,6 +111,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, mt76_read_rate_txpower); + debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir, + mt76_rx_queues_read); return dir; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index cc7c788abedd..8ce6880b2bb8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -113,7 +113,7 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) return; debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 150036488e3f..fd3ef483a87c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -293,10 +293,10 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) return -ENOMEM; if (is_mt7615(&dev->mt76)) - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, mt7615_queues_read); else - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, mt7615_queues_acq); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 68b40d63a46d..ff448a1ad4e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -144,7 +144,7 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev) if (!dir) return; - debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir, mt76_queues_read); debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); -- cgit From df5ab0d58b2e3952acef5be1c8c183a6cf31daab Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Apr 2020 13:58:44 +0200 Subject: mt76: mt7615: parse mcu return code for unified commands Add return code parsing for the following unified commands: - MCU_UNI_CMD_DEV_INFO_UPDATE - MCU_UNI_CMD_BSS_INFO_UPDATE - MCU_UNI_CMD_STA_REC_UPDATE Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 6 ++++++ 2 files changed, 16 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 74cbb975be75..5329bd4f8237 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -187,6 +187,16 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)skb->data); break; + case MCU_UNI_CMD_DEV_INFO_UPDATE: + case MCU_UNI_CMD_BSS_INFO_UPDATE: + case MCU_UNI_CMD_STA_REC_UPDATE: { + struct mt7615_mcu_uni_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7615_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + break; + } default: break; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 5440f24a834a..032b5f98608e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -282,6 +282,12 @@ enum { MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, }; +struct mt7615_mcu_uni_event { + u8 cid; + u8 pad[3]; + __le32 status; /* 0: success, others: fail */ +} __packed; + struct mt7615_mcu_scan_ssid { __le32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; -- cgit From becdf0d5d7a46f5ed1f12405ffae4b04764fe27c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Apr 2020 14:07:45 +0200 Subject: mt76: mt7615: fix mt7615_firmware_own for mt7663e Check the firmware-own configuration has been applied polling MT_CONN_HIF_ON_LPCTL register Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 5329bd4f8237..68d48b7ed06b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1710,9 +1710,8 @@ static int mt7615_firmware_own(struct mt7615_dev *dev) mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); - if (is_mt7622(&dev->mt76) && - !mt76_poll_msec(dev, MT_CFG_LPCR_HOST, - MT_CFG_LPCR_HOST_FW_OWN, + if (!is_mt7615(&dev->mt76) && + !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, MT_CFG_LPCR_HOST_FW_OWN, 3000)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); return -EIO; -- cgit From 8f997dddc0784f6a9f0abece590a97da817830f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Apr 2020 14:39:02 +0200 Subject: mt76: mt7615: fix max wtbl size for 7663 Current mt7663 offload firmware can support up to 32 wtbl entries Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 11 ++++++++++- drivers/net/wireless/mediatek/mt76/util.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index c9533282e7e3..ffb146840377 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -12,8 +12,9 @@ #define MT7615_MAX_INTERFACES 4 #define MT7615_MAX_WMM_SETS 4 +#define MT7663_WTBL_SIZE 32 #define MT7615_WTBL_SIZE 128 -#define MT7615_WTBL_RESERVED (MT7615_WTBL_SIZE - 1) +#define MT7615_WTBL_RESERVED (mt7615_wtbl_size(dev) - 1) #define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \ MT7615_MAX_INTERFACES) @@ -424,6 +425,14 @@ static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) return dev->fw_ver > MT7615_FIRMWARE_V2; } +static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) +{ + if (is_mt7663(&dev->mt76) && mt7615_firmware_offload(dev)) + return MT7663_WTBL_SIZE; + else + return MT7615_WTBL_SIZE; +} + void mt7615_scan_work(struct work_struct *work); void mt7615_ps_work(struct work_struct *work); void mt7615_init_txpower(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index 8c60c450125a..07cf71242d9e 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -46,7 +46,7 @@ int mt76_wcid_alloc(unsigned long *mask, int size) { int i, idx = 0, cur; - for (i = 0; i < size / BITS_PER_LONG; i++) { + for (i = 0; i < DIV_ROUND_UP(size, BITS_PER_LONG); i++) { idx = ffs(~mask[i]); if (!idx) continue; -- cgit From 338061619185133f56ac17365deb1e75eaecc604 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 20 Apr 2020 22:40:55 +0200 Subject: mt76: mt7615: fix mt7615_driver_own routine Introduce MT_PCIE_DOORBELL_PUSH register to fix mt7615_driver_own routine for mt7663e Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 68d48b7ed06b..c267280dab4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1686,16 +1686,20 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) static int mt7615_driver_own(struct mt7615_dev *dev) { + struct mt76_dev *mdev = &dev->mt76; u32 addr; - addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; + addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); mt7622_trigger_hif_int(dev, true); + + addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) { dev_err(dev->mt76.dev, "Timeout for driver own\n"); return -EIO; } + mt7622_trigger_hif_int(dev, false); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index ab3c6b77df07..054831ecad68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -68,6 +68,7 @@ enum mt7615_reg_base { #define MT_HIF2_BASE 0xf0000 #define MT_HIF2(ofs) (MT_HIF2_BASE + (ofs)) #define MT_PCIE_IRQ_ENABLE MT_HIF2(0x188) +#define MT_PCIE_DOORBELL_PUSH MT_HIF2(0x1484) #define MT_CFG_LPCR_HOST MT_HIF(0x1f0) #define MT_CFG_LPCR_HOST_FW_OWN BIT(0) -- cgit From fdf433121f82766ff508a6f06665d2aca3e258d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 21 Apr 2020 16:31:40 +0200 Subject: mt76: mt7615: fix aid configuration in mt7615_mcu_wtbl_generic_tlv If the vif is running in station mode the aid will be passed by mac80211 using bss_conf.aid. Fix aid configuration in mt7615_mcu_wtbl_generic_tlv Fixes: 04b8e65922f6 ("mt76: add mac80211 driver for MT7615 PCIe-based chipsets") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index c267280dab4e..e4baee37cac1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -898,8 +898,11 @@ mt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, generic = (struct wtbl_generic *)tlv; if (sta) { + if (vif->type == NL80211_IFTYPE_STATION) + generic->partial_aid = cpu_to_le16(vif->bss_conf.aid); + else + generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); - generic->partial_aid = cpu_to_le16(sta->aid); generic->muar_idx = mvif->omac_idx; generic->qos = sta->wme; } else { -- cgit From a621372a04ac6435edbf270ff85edae8a3e04c91 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 22 Apr 2020 10:47:23 +0200 Subject: mt76: mt7615: rework mt7615_mac_sta_poll for usb code Since usb code can't access device registers in interrupt context, move rcu_read_lock/rcu_read_unlock in mt7615_poll_tx routine. Moreover loop over a local msta list in mt7615_mac_sta_poll since mt7663u driver will not be able to complete the inner while loop before sta_poll_list list is refilled by mt7615_mac_add_txs/mt7615_mac_fill_rx Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 20 ++++++++------------ 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index b0ba0e7807bf..5cdbe3747901 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -121,7 +121,9 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) mt7615_tx_cleanup(dev); + rcu_read_lock(); mt7615_mac_sta_poll(dev); + rcu_read_unlock(); tasklet_schedule(&dev->mt76.tx_tasklet); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 3dab07d3eb1d..396f11e1bbf6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -724,22 +724,20 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev) struct ieee80211_sta *sta; struct mt7615_sta *msta; u32 addr, tx_time[4], rx_time[4]; + struct list_head sta_poll_list; int i; - rcu_read_lock(); + INIT_LIST_HEAD(&sta_poll_list); + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&dev->sta_poll_list, &sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); - while (true) { + while (!list_empty(&sta_poll_list)) { bool clear = false; - spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&dev->sta_poll_list)) { - spin_unlock_bh(&dev->sta_poll_lock); - break; - } - msta = list_first_entry(&dev->sta_poll_list, - struct mt7615_sta, poll_list); + msta = list_first_entry(&sta_poll_list, struct mt7615_sta, + poll_list); list_del_init(&msta->poll_list); - spin_unlock_bh(&dev->sta_poll_lock); addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4; @@ -779,8 +777,6 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev) rx_cur); } } - - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt7615_mac_sta_poll); -- cgit From 5416651c9e00f4cbc6f8528bb42fc33e6c600309 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 22 Apr 2020 10:47:24 +0200 Subject: mt76: mt7663u: enable AirTimeFairness Initialize tx_status_data pointer in order to enable Air Time Fairness for mt7663u chipset Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index ad5219006987..eee6f820959f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -249,6 +249,17 @@ mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return mt76u_skb_dma_info(tx_info->skb, tx_info->skb->len); } +static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + + mutex_lock(&dev->mt76.mutex); + mt7615_mac_sta_poll(dev); + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + static int mt7663u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -257,6 +268,7 @@ static int mt7663u_probe(struct usb_interface *usb_intf, .drv_flags = MT_DRV_RX_DMA_HDR, .tx_prepare_skb = mt7663u_tx_prepare_skb, .tx_complete_skb = mt7663u_tx_complete_skb, + .tx_status_data = mt7663u_tx_status_data, .rx_skb = mt7615_queue_rx_skb, .sta_ps = mt7615_sta_ps, .sta_add = mt7615_mac_sta_add, -- cgit From d0116058c7f637842097741cee357496326f2b9d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Apr 2020 15:49:35 +0200 Subject: mt76: mt7615: fix sta ampdu factor for VHT If VHT has a larger A-MPDU size limit, pass it to the MCU via the wtbl_ht TLV element. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index e4baee37cac1..1d1b2a7b4325 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -924,11 +924,10 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv) { struct tlv *tlv; + struct wtbl_ht *ht = NULL; u32 flags = 0; if (sta->ht_cap.ht_supported) { - struct wtbl_ht *ht; - tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), wtbl_tlv, sta_wtbl); ht = (struct wtbl_ht *)tlv; @@ -945,6 +944,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, if (sta->vht_cap.vht_supported) { struct wtbl_vht *vht; + u8 af; tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), wtbl_tlv, sta_wtbl); @@ -952,6 +952,13 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC, vht->vht = 1; + af = (sta->vht_cap.cap & + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + + if (ht) + ht->af = max(ht->af, af); + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) flags |= MT_WTBL_W5_SHORT_GI_80; if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) -- cgit From 55961d8be35d0268d66f4ffe2cbbccff4936aae5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Apr 2020 16:34:16 +0200 Subject: mt76: fix A-MPDU density handling The hardware requirements for A-MPDU density are entirely on the tx side, not the rx side. Because of that, the IE value should stay at 0 and the minimum value should instead be enforced in WTBL/TXWI MT7615 has no restrictions here Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 - drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 5 +++++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 39abedc45e4a..b6c0a6d0dfc1 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -198,7 +198,6 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; mt76_init_stream_cap(dev, sband, vht); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 39b7c5d6e6cd..73c6a3ff399c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -318,11 +318,16 @@ void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta) { struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; int idx = msta->wcid.idx; + u8 ampdu_density; u32 addr; u32 val; addr = mt7603_wtbl1_addr(idx); + ampdu_density = sta->ht_cap.ampdu_density; + if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4) + ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + val = mt76_rr(dev, addr + 2 * 4); val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL; val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR, sta->ht_cap.ampdu_factor) | diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 8b072277ea10..a5a3bcd30d6f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -409,6 +409,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { u8 ba_size = IEEE80211_MIN_AMPDU_BUF; + u8 ampdu_density = sta->ht_cap.ampdu_density; ba_size <<= sta->ht_cap.ampdu_factor; ba_size = min_t(int, 63, ba_size - 1); @@ -416,9 +417,11 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, ba_size = 0; txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); + if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4) + ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + txwi_flags |= MT_TXWI_FLAGS_AMPDU | - FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, - sta->ht_cap.ampdu_density); + FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, ampdu_density); } if (ieee80211_is_probe_resp(hdr->frame_control) || -- cgit From 61cb60758a05de1eaf5017e37a099fe52c5cce25 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Apr 2020 16:53:28 +0200 Subject: mt76: mt7615: use larger rx buffers if VHT is supported In VHT mode we can receive larger MPDUs. Increasing the buffer size reduces fragmentation here, which should improve performance. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 5cdbe3747901..0b1fbddd1c3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -192,8 +192,13 @@ static void mt7663_dma_sched_init(struct mt7615_dev *dev) int mt7615_dma_init(struct mt7615_dev *dev) { int rx_ring_size = MT7615_RX_RING_SIZE; + int rx_buf_size = MT_RX_BUF_SIZE; int ret; + /* Increase buffer size to receive large VHT MPDUs */ + if (dev->mt76.cap.has_5ghz) + rx_buf_size *= 2; + mt76_dma_attach(&dev->mt76); mt76_wr(dev, MT_WPDMA_GLO_CFG, @@ -234,7 +239,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) /* init rx queues */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, - MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, + MT7615_RX_MCU_RING_SIZE, rx_buf_size, MT_RX_RING_BASE); if (ret) return ret; @@ -243,7 +248,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) rx_ring_size /= 2; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, - rx_ring_size, MT_RX_BUF_SIZE, MT_RX_RING_BASE); + rx_ring_size, rx_buf_size, MT_RX_RING_BASE); if (ret) return ret; -- cgit From ab9a1ed229ba668c4b0481cd174096f7876933a0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 12:25:54 +0200 Subject: mt76: mt7615: never use an 802.11b CF-End rate on 5GHz Sometimes mt7615_mac_set_timing gets called while the slot time is still configured to 20. Ensure that in this case it always uses the OFDM CFend rate. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 396f11e1bbf6..63c7acfd4cc2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -117,8 +117,9 @@ void mt7615_mac_set_timing(struct mt7615_phy *phy) u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24); int sifs, offset; + bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; - if (phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ) + if (is_5ghz) sifs = 16; else sifs = 10; @@ -151,7 +152,7 @@ void mt7615_mac_set_timing(struct mt7615_phy *phy) FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); - if (phy->slottime < 20) + if (phy->slottime < 20 || is_5ghz) val = MT7615_CFEND_RATE_DEFAULT; else val = MT7615_CFEND_RATE_11B; -- cgit From e0b4fe832c3b400b34c0dfcce95f134dac2a5ef2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 17:46:58 +0200 Subject: mt76: mt7603: never use an 802.11b CF-End rate on 5GHz Sometimes mt7615_mac_set_timing gets called while the slot time is still configured to 20. Ensure that in this case it always uses the OFDM CFend rate. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 73c6a3ff399c..d34828715e1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -51,10 +51,11 @@ void mt7603_mac_set_timing(struct mt7603_dev *dev) int offset = 3 * dev->coverage_class; u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); + bool is_5ghz = dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ; int sifs; u32 val; - if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ) + if (is_5ghz) sifs = 16; else sifs = 10; @@ -71,7 +72,7 @@ void mt7603_mac_set_timing(struct mt7603_dev *dev) FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, dev->slottime)); - if (dev->slottime < 20) + if (dev->slottime < 20 || is_5ghz) val = MT7603_CFEND_RATE_DEFAULT; else val = MT7603_CFEND_RATE_11B; -- cgit From ed2bde56ab1fcda71faa24d720df06353d91e237 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 12:28:19 +0200 Subject: mt76: mt7615: adjust timing in mt7615_mac_set_timing to match fw/hw values Slightly improves performance Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 63c7acfd4cc2..88cbf5ffa290 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -115,7 +115,7 @@ void mt7615_mac_set_timing(struct mt7615_phy *phy) u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | - FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24); + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); int sifs, offset; bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; -- cgit From ad333c2ad23ec179b0c907e8553779873f4cc1c8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 12:32:10 +0200 Subject: mt76: mt7615: do not adjust MAC timings if the device is not running Avoids register writes and MAC start/stop when the hardware isn't ready for it Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 88cbf5ffa290..89aed6d67de0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -119,6 +119,9 @@ void mt7615_mac_set_timing(struct mt7615_phy *phy) int sifs, offset; bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + if (is_5ghz) sifs = 16; else -- cgit From 97507b38a4de63e55801bc91a107c2794159ccd6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 13:10:00 +0200 Subject: mt76: mt7615: fix tx status rate index calculation A switch from one rate index to the next only happens when tx count from the current slot is greater than MT7615_RATE_RETRY, which is 1 has to be subtracted from count, instead of added to it. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 89aed6d67de0..e7a76032caff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1148,7 +1148,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; - first_idx = max_t(int, 0, last_idx - (count + 1) / MT7615_RATE_RETRY); + first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY); if (fixed_rate && !probe) { info->status.rates[0].count = count; -- cgit From 40a61c9b2c725da82bd60a39bc54b8884b0a57b5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Apr 2020 13:15:06 +0200 Subject: mt76: mt7603: fix tx status rate index calculation A switch from one rate index to the next only happens when tx count from the current slot is greater than MT7615_RATE_RETRY, which is 1 has to be subtracted from count, instead of added to it. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index d34828715e1c..f8c0c957ca01 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1103,7 +1103,7 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; - first_idx = max_t(int, 0, last_idx - (count + 1) / MT7603_RATE_RETRY); + first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY); if (fixed_rate && !probe) { info->status.rates[0].count = count; -- cgit From dcc4c74f9260fdc746d6ab4af17518cfe9d4e071 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 22 Apr 2020 13:07:44 +0200 Subject: mt76: mt7615: move mcu bss upload before creating the sta Run mt7615_mcu_add_bss_info routine before mt7615_mcu_sta_add since the firmware requires the bss is created before the relative sta Tested-by: Sean Wang Suggested-by: YF Luo Suggested-by: Lucy Hsu Co-developed-by: Soul Huang Signed-off-by: Soul Huang Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 8f8ad632d6ba..3c35b8d0489c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -491,9 +491,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - if (changed & BSS_CHANGED_ASSOC) - mt7615_mcu_add_bss_info(phy, vif, info->assoc); - if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; @@ -545,9 +542,14 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->band_idx; + if (vif->type == NL80211_IFTYPE_STATION) { + struct mt7615_phy *phy; + + phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; + mt7615_mcu_add_bss_info(phy, vif, true); + } mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7615_mcu_sta_add(dev, vif, sta, true); return 0; @@ -563,6 +565,13 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7615_mcu_sta_add(dev, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + if (vif->type == NL80211_IFTYPE_STATION) { + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_phy *phy; + + phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; + mt7615_mcu_add_bss_info(phy, vif, false); + } spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) -- cgit From dd89a0133c0ce80bb8c2f873a85b28f2d33640bd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 22 Apr 2020 18:29:32 +0200 Subject: mt76: enable TDLS support Enable mac80211 TDLS support by default. Disable TDLS hw filtering for mt7615 devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 8 ++++++++ drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 1 + 6 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index b6c0a6d0dfc1..176c22a5319a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -278,7 +278,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; - wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | + WIPHY_FLAG_SUPPORTS_TDLS; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 6fc3f5aa94c0..9880643888ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -63,6 +63,7 @@ mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1)); + mt76_clear(dev, MT_DMA_RCFR0(chain), MT_DMA_RCFR0_MCU_RX_TDLS); if (!mt7615_firmware_offload(dev)) { u32 mask, set; @@ -117,6 +118,8 @@ void mt7615_mac_init(struct mt7615_dev *dev) mt76_wr(dev, MT_DMA_DCR0, FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) | MT_DMA_DCR0_RX_VEC_DROP); + /* disable TDLS filtering */ + mt76_clear(dev, MT_WF_PFCR, MT_WF_PFCR_TDLS_EN); mt76_set(dev, MT_WF_MIB_SCR0, MT_MIB_SCR0_AGG_CNT_RANGE_EN); if (is_mt7663(&dev->mt76)) { mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 3c35b8d0489c..4e1d162b2664 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -542,7 +542,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->band_idx; - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { struct mt7615_phy *phy; phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; @@ -565,7 +565,7 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7615_mcu_sta_add(dev, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_phy *phy; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 2c4b1a315d5b..c9f5b1ce70ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -21,6 +21,7 @@ const u32 mt7615e_reg_map[] = { [MT_TMAC_BASE] = 0x21000, [MT_RMAC_BASE] = 0x21200, [MT_DMA_BASE] = 0x21800, + [MT_PF_BASE] = 0x22000, [MT_WTBL_BASE_ON] = 0x23000, [MT_WTBL_BASE_OFF] = 0x23400, [MT_LPON_BASE] = 0x24200, @@ -45,6 +46,7 @@ const u32 mt7663e_reg_map[] = { [MT_TMAC_BASE] = 0x24000, [MT_RMAC_BASE] = 0x25000, [MT_DMA_BASE] = 0x27000, + [MT_PF_BASE] = 0x28000, [MT_WTBL_BASE_ON] = 0x29000, [MT_WTBL_BASE_OFF] = 0x29800, [MT_LPON_BASE] = 0x2b000, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 054831ecad68..68d30bcc087a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -18,6 +18,7 @@ enum mt7615_reg_base { MT_TMAC_BASE, MT_RMAC_BASE, MT_DMA_BASE, + MT_PF_BASE, MT_WTBL_BASE_ON, MT_WTBL_BASE_OFF, MT_LPON_BASE, @@ -321,10 +322,17 @@ enum mt7615_reg_base { #define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2) #define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3) #define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4) +#define MT_DMA_RCFR0_MCU_RX_TDLS BIT(19) #define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21) #define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24) #define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26) +#define MT_WF_PF_BASE ((dev)->reg_map[MT_PF_BASE]) +#define MT_WF_PF(ofs) (MT_WF_PF_BASE + (ofs)) + +#define MT_WF_PFCR MT_WF_PF(0x000) +#define MT_WF_PFCR_TDLS_EN BIT(9) + #define MT_WTBL_BASE(dev) ((dev)->reg_map[MT_WTBL_BASE_ADDR]) #define MT_WTBL_ENTRY_SIZE 256 diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index eee6f820959f..bcd131969923 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -31,6 +31,7 @@ static const u32 mt7663u_reg_map[] = { [MT_TMAC_BASE] = 0x820f4000, [MT_RMAC_BASE] = 0x820f5000, [MT_DMA_BASE] = 0x820f7000, + [MT_PF_BASE] = 0x820f8000, [MT_WTBL_BASE_ON] = 0x820f9000, [MT_WTBL_BASE_OFF] = 0x820f9800, [MT_LPON_BASE] = 0x820fb000, -- cgit From 5ac2e2a3485a13ac922249cd03b9dcecff59af5f Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 23 Apr 2020 15:47:54 +0200 Subject: mt76: mt7663: fix up BMC entry indicated to unicmd firmware BMC entry for MT7663 unicmd firmware should be a broadcast/multicast entry, not a unicast entry, that is GTK rekey offload would rely on. Fixes: 138860679b2a ("mt76: mt7615: add more uni mcu commands") Cc: Soul Huang Suggested-by: YF Luo Co-developed-by: Ryder Lee Signed-off-by: Ryder Lee Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 1d1b2a7b4325..b1dea61fb9ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1359,8 +1359,8 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, .short_st = true, }, }; - u8 idx, tx_wlan_idx = 0; int err; + u8 idx; idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; basic_req.basic.hw_bss_idx = idx; @@ -1369,24 +1369,8 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); - tx_wlan_idx = mvif->sta.wcid.idx; break; case NL80211_IFTYPE_STATION: - if (enable) { - struct ieee80211_sta *sta; - struct mt7615_sta *msta; - - rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) { - rcu_read_unlock(); - return -EINVAL; - } - - msta = (struct mt7615_sta *)sta->drv_priv; - tx_wlan_idx = msta->wcid.idx; - rcu_read_unlock(); - } basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); break; default: @@ -1395,8 +1379,8 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, } memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); - basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(tx_wlan_idx); - basic_req.basic.sta_idx = cpu_to_le16(tx_wlan_idx); + basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx); + basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx); basic_req.basic.conn_state = !enable; err = __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE, -- cgit From f559685035f818693a2930052283d837738dbc2f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 23 Apr 2020 15:47:55 +0200 Subject: mt76: mt7615: add sta pointer to mt7615_mcu_add_bss_info signature Introduce sta pointer to mt7615_mcu_add_bss_info signature in order to avoid sta lookup in mt7615_mcu_bss_basic_tlv routine Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 21 ++++++--------------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 +- 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 4e1d162b2664..23bc7f1262d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -501,7 +501,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - mt7615_mcu_add_bss_info(phy, vif, info->enable_beacon); + mt7615_mcu_add_bss_info(phy, vif, NULL, info->enable_beacon); mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon); } @@ -546,7 +546,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_phy *phy; phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; - mt7615_mcu_add_bss_info(phy, vif, true); + mt7615_mcu_add_bss_info(phy, vif, sta, true); } mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -570,7 +570,7 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_phy *phy; phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy; - mt7615_mcu_add_bss_info(phy, vif, false); + mt7615_mcu_add_bss_info(phy, vif, sta, false); } spin_lock_bh(&dev->sta_poll_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index b1dea61fb9ee..a65d814153ab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -645,7 +645,7 @@ mt7615_mcu_add_tlv(struct sk_buff *skb, int tag, int len) static int mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - bool enable) + struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct bss_info_basic *bss; @@ -661,20 +661,11 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, break; case NL80211_IFTYPE_STATION: /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ - if (enable) { - struct ieee80211_sta *sta; + if (enable && sta) { struct mt7615_sta *msta; - rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); - if (!sta) { - rcu_read_unlock(); - return -EINVAL; - } - msta = (struct mt7615_sta *)sta->drv_priv; wlan_idx = msta->wcid.idx; - rcu_read_unlock(); } break; case NL80211_IFTYPE_ADHOC: @@ -994,7 +985,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, static int mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, - bool enable) + struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; @@ -1007,7 +998,7 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (enable) mt7615_mcu_bss_omac_tlv(skb, vif); - mt7615_mcu_bss_basic_tlv(skb, vif, enable); + mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable); if (enable && mvif->omac_idx > EXT_BSSID_START) mt7615_mcu_bss_ext_tlv(skb, mvif); @@ -1272,8 +1263,8 @@ mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) } static int -mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, - struct ieee80211_vif *vif, bool enable) +mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index ffb146840377..44eb3d8dca78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -222,7 +222,7 @@ struct mt7615_mcu_ops { int (*add_dev_info)(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); int (*add_bss_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, - bool enable); + struct ieee80211_sta *sta, bool enable); int (*add_beacon_offload)(struct mt7615_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable); -- cgit From ffc54ee2f03d0299146323c09cebb1c1de4d73d3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 24 Apr 2020 14:51:29 +0200 Subject: mt76: mt7615: fix event report in mt7615_mcu_bss_event Currently mt7663 devices do not support DBDC so fw events have no info about it. Fix mt7615_mcu_bss_event that wrongly use bss_idx as DBDC band_idx while it is vif index. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index a65d814153ab..8f745c64e9d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -356,11 +356,12 @@ mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_mcu_bss_event *event; struct mt76_phy *mphy; + u8 band_idx = 0; /* DBDC support */ event = (struct mt7615_mcu_bss_event *)(skb->data + sizeof(struct mt7615_mcu_rxd)); - if (event->bss_idx && dev->mt76.phy2) + if (band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; else mphy = &dev->mt76.phy; -- cgit From 65ba7fa4b829588b011c8c285968c1a8d779b981 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 25 Apr 2020 14:11:09 +0200 Subject: mt76: mt76x0: enable MCS 8 and MCS9 Enable MCS8 and MCS9 for mt76x0{u,e} devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 26 +++++------------------- 1 file changed, 5 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 57f8d56737eb..dc8bf4c6969a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -12,24 +12,6 @@ #include "initvals.h" #include "../mt76x02_phy.h" -static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband) -{ - struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap; - u16 mcs_map = 0; - int i; - - vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC; - for (i = 0; i < 8; i++) { - if (!i) - mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2)); - else - mcs_map |= - (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); - } - vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); - vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); -} - static void mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable) { @@ -263,9 +245,11 @@ int mt76x0_register_device(struct mt76x02_dev *dev) return ret; if (dev->mt76.cap.has_5ghz) { - /* overwrite unsupported features */ - mt76x0_vht_cap_mask(&dev->mphy.sband_5g.sband); - mt76x0_init_txpower(dev, &dev->mphy.sband_5g.sband); + struct ieee80211_supported_band *sband; + + sband = &dev->mphy.sband_5g.sband; + sband->vht_cap.cap &= ~IEEE80211_VHT_CAP_RXLDPC; + mt76x0_init_txpower(dev, sband); } if (dev->mt76.cap.has_2ghz) -- cgit From f2dc8ea11fbeec8e8d35c30a9fbd1f97d9c079d4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 28 Apr 2020 15:34:09 +0200 Subject: mt76: mt7663: add the possibility to load firmware v2 mt7663 firmware v2 is used for embedded devices since it has more completed features in AP mode. Add the capability to specify which firmware load first (v3 or v2) using prefer_offload_fw kernel parameter and fallback to the other one if the selected firmware fails to load Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 55 +++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 6 ++- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 + drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 2 + 4 files changed, 57 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 8f745c64e9d9..f4966d29d098 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -11,6 +11,11 @@ #include "mac.h" #include "eeprom.h" +static bool prefer_offload_fw = true; +module_param(prefer_offload_fw, bool, 0644); +MODULE_PARM_DESC(prefer_offload_fw, + "Prefer client mode offload firmware (MT7663)"); + struct mt7615_patch_hdr { char build_date[16]; char platform[4]; @@ -1728,7 +1733,7 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) return -EAGAIN; } - ret = request_firmware(&fw, name, dev->mt76.dev); + ret = firmware_request_nowarn(&fw, name, dev->mt76.dev); if (ret) goto out; @@ -2081,8 +2086,49 @@ out: return ret; } +static int +mt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware) +{ + const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH; + const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH; + int ret; + + if (!prefer_offload_fw) { + secondary_rom = MT7663_OFFLOAD_ROM_PATCH; + primary_rom = MT7663_ROM_PATCH; + } + selected_rom = primary_rom; + + ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom); + if (ret) { + dev_info(dev->mt76.dev, "%s not found, switching to %s", + primary_rom, secondary_rom); + ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, + secondary_rom); + if (ret) { + dev_err(dev->mt76.dev, "failed to load %s", + secondary_rom); + return ret; + } + selected_rom = secondary_rom; + } + + if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) { + *n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9; + dev->fw_ver = MT7615_FIRMWARE_V3; + dev->mcu_ops = &uni_update_ops; + } else { + *n9_firmware = MT7663_FIRMWARE_N9; + dev->fw_ver = MT7615_FIRMWARE_V2; + dev->mcu_ops = &sta_update_ops; + } + + return 0; +} + int __mt7663_load_firmware(struct mt7615_dev *dev) { + const char *n9_firmware; int ret; ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); @@ -2091,14 +2137,11 @@ int __mt7663_load_firmware(struct mt7615_dev *dev) return -EIO; } - ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, MT7663_ROM_PATCH); + ret = mt7663_load_rom_patch(dev, &n9_firmware); if (ret) return ret; - dev->fw_ver = MT7615_FIRMWARE_V3; - dev->mcu_ops = &uni_update_ops; - - ret = mt7663_load_n9(dev, MT7663_FIRMWARE_N9); + ret = mt7663_load_n9(dev, n9_firmware); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 44eb3d8dca78..0476b9426b03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -42,8 +42,10 @@ #define MT7615_FIRMWARE_V2 2 #define MT7615_FIRMWARE_V3 3 -#define MT7663_ROM_PATCH "mediatek/mt7663pr2h.bin" -#define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin" +#define MT7663_OFFLOAD_ROM_PATCH "mediatek/mt7663pr2h.bin" +#define MT7663_OFFLOAD_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin" +#define MT7663_ROM_PATCH "mediatek/mt7663pr2h_rebb.bin" +#define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_rebb.bin" #define MT7615_EEPROM_SIZE 1024 #define MT7615_TOKEN_SIZE 4096 diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 21b3ec29aa12..f9469198cabd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -68,5 +68,7 @@ MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table); MODULE_FIRMWARE(MT7615_FIRMWARE_CR4); MODULE_FIRMWARE(MT7615_FIRMWARE_N9); MODULE_FIRMWARE(MT7615_ROM_PATCH); +MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); MODULE_FIRMWARE(MT7663_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_ROM_PATCH); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index bcd131969923..9353175b139b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -386,6 +386,8 @@ mt7663u_resume(struct usb_interface *intf) } MODULE_DEVICE_TABLE(usb, mt7615_device_table); +MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); MODULE_FIRMWARE(MT7663_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_ROM_PATCH); -- cgit From 404d1cd401cacf6922a800a63ff158f15615530d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 26 Apr 2020 16:42:52 +0200 Subject: mt76: mt7663: remove check in mt7663_load_n9 Get rid of useless check in mt7663_load_n9 since it is used only for mt7663 devices Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f4966d29d098..5fd4a4ab5120 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2005,7 +2005,7 @@ int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl) static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) { - u32 offset = 0, override_addr = 0, flag = 0; + u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL; const struct mt7663_fw_trailer *hdr; const struct mt7663_fw_buf *buf; const struct firmware *fw; @@ -2061,14 +2061,11 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) } } - if (is_mt7663(&dev->mt76)) { - flag |= FW_START_DLYCAL; - if (override_addr) - flag |= FW_START_OVERRIDE; + if (override_addr) + flag |= FW_START_OVERRIDE; - dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n", - override_addr, flag); - } + dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n", + override_addr, flag); ret = mt7615_mcu_start_firmware(dev, override_addr, flag); if (ret) { -- cgit From 801f809aeeb127736a1f871dc21c800382afc4d2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 27 Apr 2020 19:45:02 +0200 Subject: mt76: mt7615: set spatial extension index The vendor driver sets this in firmware rate control (which we don't use) Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e7a76032caff..5c09787b0d76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -639,7 +639,8 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | - FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); if (is_usb) txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 5fd4a4ab5120..cbad854d7497 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -887,6 +887,7 @@ mt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct wtbl_generic *generic; struct wtbl_rx *rx; + struct wtbl_spe *spe; struct tlv *tlv; tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), @@ -914,6 +915,11 @@ mt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; rx->rca2 = 1; rx->rv = 1; + + tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe), + wtbl_tlv, sta_wtbl); + spe = (struct wtbl_spe *)tlv; + spe->spe_idx = 24; } static void -- cgit From 89f8bc6a344b2b786210a4045256346b3f8f6c4c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 29 Apr 2020 14:34:23 +0200 Subject: mt76: mt7615: fix getting maximum tx power from eeprom On top of the EEPROM target power, each rate can also has a power offset. On many devices, this power offset is used to boost the tx power of lower rates. Take this into account when parsing rate power. The assumption here is, that the first rate (OFDM 6M or CCK 1M) has the highest tx power Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/init.c | 11 +++++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index bd2ac1e0e01a..3dd7009e5836 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -32,6 +32,8 @@ enum mt7615_eeprom_field { MT_EE_TX0_2G_TARGET_POWER = 0x058, MT_EE_TX0_5G_G0_TARGET_POWER = 0x070, MT_EE_TX1_5G_G0_TARGET_POWER = 0x098, + MT_EE_2G_RATE_POWER = 0x0be, + MT_EE_5G_RATE_POWER = 0x0d5, MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2, MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3, MT7663_EE_TX0_2G_TARGET_POWER = 0x123, @@ -43,6 +45,10 @@ enum mt7615_eeprom_field { MT7663_EE_MAX = 0x400, }; +#define MT_EE_RATE_POWER_MASK GENMASK(5, 0) +#define MT_EE_RATE_POWER_SIGN BIT(6) +#define MT_EE_RATE_POWER_EN BIT(7) + #define MT_EE_CALDATA_FLASH_TX_DPD BIT(0) #define MT_EE_CALDATA_FLASH_RX_CAL BIT(1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 9880643888ba..7e201525305b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -198,6 +198,17 @@ void mt7615_init_txpower(struct mt7615_dev *dev, u8 *eep = (u8 *)dev->mt76.eeprom.data; enum nl80211_band band = sband->band; int delta = mt76_tx_power_nss_delta(n_chains); + u8 rate_val; + + /* assume the first rate has the highest power offset */ + if (band == NL80211_BAND_2GHZ) + rate_val = eep[MT_EE_2G_RATE_POWER]; + else + rate_val = eep[MT_EE_5G_RATE_POWER]; + + if ((rate_val & ~MT_EE_RATE_POWER_MASK) == + (MT_EE_RATE_POWER_EN | MT_EE_RATE_POWER_SIGN)) + delta += rate_val & MT_EE_RATE_POWER_MASK; target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; for (i = 0; i < sband->n_channels; i++) { -- cgit From fb602b303b0eece7b8822e03f71a9ba3f35a4023 Mon Sep 17 00:00:00 2001 From: Dejin Zheng Date: Tue, 28 Apr 2020 22:31:52 +0800 Subject: mt76: mt7603: remove duplicate error message it will print an error message by itself when devm_platform_ioremap_resource() goes wrong. so remove the duplicate error message. Signed-off-by: Dejin Zheng Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/soc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index 68efb300c0d8..de170765e938 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -20,10 +20,8 @@ mt76_wmac_probe(struct platform_device *pdev) return irq; mem_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mem_base)) { - dev_err(&pdev->dev, "Failed to get memory resource\n"); + if (IS_ERR(mem_base)) return PTR_ERR(mem_base); - } mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops, &mt7603_drv_ops); -- cgit From 0fe96975d1dfd0e7aabe9400d0b82947e0a0d30e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 29 Apr 2020 19:48:53 +0200 Subject: mt76: mt7615: fix ssid configuration in mt7615_mcu_hw_scan Fix SSID configuration performing hw frequency scanning Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index cbad854d7497..f4e835f03b8d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2719,9 +2719,9 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct cfg80211_scan_request *sreq = &scan_req->req; + int n_ssids = 0, err, i, duration = MT7615_SCAN_CHANNEL_TIME; int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); struct ieee80211_channel **scan_list = sreq->channels; - int err, i, duration = MT7615_SCAN_CHANNEL_TIME; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; struct mt7615_mcu_scan_channel *chan; @@ -2744,16 +2744,21 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, req->seq_num = mvif->scan_seq_num | ext_phy << 7; req->bss_idx = mvif->idx; req->scan_type = 1; - req->ssid_type = 1; req->probe_req_num = 2; req->version = 1; req->channel_type = 4; for (i = 0; i < sreq->n_ssids; i++) { + if (!sreq->ssids[i].ssid_len) + continue; + req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, sreq->ssids[i].ssid_len); + n_ssids++; } + req->ssid_type = n_ssids ? BIT(2) : BIT(0); + req->ssids_num = n_ssids; req->timeout_value = cpu_to_le16(sreq->n_channels * duration); req->channel_min_dwell_time = cpu_to_le16(duration); -- cgit From 53b42ae291a0adf227c9f32e4024819a276ded02 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 29 Apr 2020 19:52:15 +0200 Subject: mt76: mt7615: introduce mt7615_check_offload_capability routine Introduce mt7615_check_offload_capability routine to set hw/wiphy offload capabilities according to the running firmware Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 26 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + .../net/wireless/mediatek/mt76/mt7615/pci_init.c | 21 +---------------- .../net/wireless/mediatek/mt76/mt7615/usb_init.c | 4 +--- 4 files changed, 29 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 7e201525305b..145af8a3ae57 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -130,6 +130,32 @@ void mt7615_mac_init(struct mt7615_dev *dev) } EXPORT_SYMBOL_GPL(mt7615_mac_init); +void mt7615_check_offload_capability(struct mt7615_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + + if (mt7615_firmware_offload(dev)) { + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + } else { + dev->ops->hw_scan = NULL; + dev->ops->cancel_hw_scan = NULL; + dev->ops->sched_scan_start = NULL; + dev->ops->sched_scan_stop = NULL; + + wiphy->max_sched_scan_plan_interval = 0; + wiphy->max_sched_scan_ie_len = 0; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_reqs = 0; + } +} +EXPORT_SYMBOL_GPL(mt7615_check_offload_capability); + bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) { flush_work(&dev->mcu_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 0476b9426b03..2321a1f23ec8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -370,6 +370,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); +void mt7615_check_offload_capability(struct mt7615_dev *dev); void mt7615_init_device(struct mt7615_dev *dev); int mt7615_register_device(struct mt7615_dev *dev); void mt7615_unregister_device(struct mt7615_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index cd3ccafa7d11..69cba8609edf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -16,7 +16,6 @@ static void mt7615_init_work(struct work_struct *work) { struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work); - struct ieee80211_hw *hw = mt76_hw(dev); if (mt7615_mcu_init(dev)) return; @@ -25,25 +24,7 @@ static void mt7615_init_work(struct work_struct *work) mt7615_mac_init(dev); mt7615_phy_init(dev); mt7615_mcu_del_wtbl_all(dev); - - if (mt7615_firmware_offload(dev)) { - ieee80211_hw_set(hw, SUPPORTS_PS); - ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - } else { - struct wiphy *wiphy = hw->wiphy; - - dev->ops->hw_scan = NULL; - dev->ops->cancel_hw_scan = NULL; - dev->ops->sched_scan_start = NULL; - dev->ops->sched_scan_stop = NULL; - - wiphy->max_sched_scan_plan_interval = 0; - wiphy->max_sched_scan_ie_len = 0; - wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - wiphy->max_sched_scan_ssids = 0; - wiphy->max_match_sets = 0; - wiphy->max_sched_scan_reqs = 0; - } + mt7615_check_offload_capability(dev); } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c index 39642065531f..1fbc9601391d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c @@ -103,6 +103,7 @@ static void mt7663u_init_work(struct work_struct *work) mt7615_mac_init(dev); mt7615_phy_init(dev); mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); } int mt7663u_register_device(struct mt7615_dev *dev) @@ -119,9 +120,6 @@ int mt7663u_register_device(struct mt7615_dev *dev) if (err) return err; - ieee80211_hw_set(hw, SUPPORTS_PS); - ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE; /* check hw sg support in order to enable AMSDU */ hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; -- cgit From 6c5974c10c2c6cc8166d4708b957ff3245b4eecb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 30 Apr 2020 09:59:31 +0200 Subject: mt76: mt7615: do not mark sched_scan disabled in mt7615_scan_work For the moment offload firmware supports just one entry in the scheduled scan plan and so it runs till it is disabled by the userspace. Do not mark the hw scheduled scan as disabled in mt7615_scan_work after receiving a scan result Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 23bc7f1262d0..5e54c7ffae0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -818,7 +818,6 @@ void mt7615_scan_work(struct work_struct *work) clear_bit(MT76_HW_SCANNING, &phy->mt76->state); ieee80211_scan_completed(phy->mt76->hw, &info); } else { - clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state); ieee80211_sched_scan_results(phy->mt76->hw); } dev_kfree_skb(skb); -- cgit From 4432119d17828ce7a66d74f898c52ca4a147ba92 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 30 Apr 2020 11:11:34 +0200 Subject: mt76: mt7615: add passive mode for hw scan Introduce support for passive frequency scanning to mt7615_mcu_hw_scan Tested-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index f4e835f03b8d..ae527b934926 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2743,8 +2743,8 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, req->seq_num = mvif->scan_seq_num | ext_phy << 7; req->bss_idx = mvif->idx; - req->scan_type = 1; - req->probe_req_num = 2; + req->scan_type = sreq->n_ssids ? 1 : 0; + req->probe_req_num = sreq->n_ssids ? 2 : 0; req->version = 1; req->channel_type = 4; -- cgit From a69b0b30e661eadfe1931c4c5751c2de7905f016 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 30 Apr 2020 22:31:03 +0200 Subject: mt76: mt7615: free pci_vector if mt7615_pci_probe fails Always free pci irq vector if mt7615_pci_probe routine fails Moreover free irq in mt7615_pci_remove routine Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index f9469198cabd..0605c908059e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -39,13 +39,21 @@ static int mt7615_pci_probe(struct pci_dev *pdev, ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) - return ret; + goto error; mt76_pci_disable_aspm(pdev); map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map; - return mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], - pdev->irq, map); + ret = mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], + pdev->irq, map); + if (ret) + goto error; + + return 0; +error: + pci_free_irq_vectors(pdev); + + return ret; } static void mt7615_pci_remove(struct pci_dev *pdev) @@ -54,6 +62,7 @@ static void mt7615_pci_remove(struct pci_dev *pdev) struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); mt7615_unregister_device(dev); + devm_free_irq(&pdev->dev, pdev->irq, dev); pci_free_irq_vectors(pdev); } -- cgit From c8646872d6e632f793a06a42708e282950ec982a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 May 2020 12:36:11 +0200 Subject: mt76: mt7615: introduce support for hardware beacon filter Introduce support for hw beacon filter if available in the firmware Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 41 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ 3 files changed, 45 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index ae527b934926..7de7daf4d067 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2652,6 +2652,47 @@ void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) &req, sizeof(req), false); } +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + u8 bss_idx; + u8 dtim_period; + __le16 aid; + __le16 bcn_interval; + __le16 atim_window; + u8 uapsd; + u8 bmc_delivered_ac; + u8 bmc_triggered_ac; + u8 pad; + } req = { + .bss_idx = mvif->idx, + .aid = cpu_to_le16(vif->bss_conf.aid), + .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + }; + struct { + u8 bss_idx; + u8 pad[3]; + } req_hdr = { + .bss_idx = mvif->idx, + }; + int err; + + if (vif->type != NL80211_IFTYPE_STATION || + !mt7615_firmware_offload(dev)) + return -ENOTSUPP; + + err = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, + &req_hdr, sizeof(req_hdr), false); + if (err < 0 || !enable) + return err; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, + &req, sizeof(req), false); +} + int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) { struct mt76_phy *mphy = phy->mt76; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 032b5f98608e..08dcfadceaf6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -419,6 +419,8 @@ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05, MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f, + MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16, + MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17, MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 2321a1f23ec8..fdb20fbdfb90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -474,6 +474,8 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, enum set_key_cmd cmd); void mt7615_mac_reset_work(struct work_struct *work); +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp); -- cgit From 6f117852009c8c0d7542f6de0750dfda18c6578c Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 1 May 2020 12:36:12 +0200 Subject: mt76: mt7615: introduce mt7615_mcu_set_hif_suspend mcu command Introduce the mt7615_mcu_set_hif_suspend mcu command, which is usually used to configure the interface including PCIe, USB or SDIO to the right state during operation suspend / resume. Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 36 +++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 7de7daf4d067..e7f6ab5ab2db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -194,7 +194,8 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, break; case MCU_UNI_CMD_DEV_INFO_UPDATE: case MCU_UNI_CMD_BSS_INFO_UPDATE: - case MCU_UNI_CMD_STA_REC_UPDATE: { + case MCU_UNI_CMD_STA_REC_UPDATE: + case MCU_UNI_CMD_HIF_CTRL: { struct mt7615_mcu_uni_event *event; skb_pull(skb, sizeof(*rxd)); @@ -3220,3 +3221,36 @@ out: return ret; } + +int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) +{ + struct { + struct { + u8 hif_type; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + */ + u8 pad[3]; + } __packed hdr; + struct hif_suspend_tlv { + __le16 tag; + __le16 len; + u8 suspend; + } __packed hif_suspend; + } req = { + .hif_suspend = { + .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ + .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), + .suspend = suspend, + }, + }; + + if (mt76_is_mmio(&dev->mt76)) + req.hdr.hif_type = 2; + else if (mt76_is_usb(&dev->mt76)) + req.hdr.hif_type = 1; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 08dcfadceaf6..1579ad944479 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -280,6 +280,7 @@ enum { MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01, MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02, MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, + MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, }; struct mt7615_mcu_uni_event { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index fdb20fbdfb90..6a26555dcce6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -531,6 +531,8 @@ int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); +int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); + int __mt7663_load_firmware(struct mt7615_dev *dev); /* usb */ -- cgit From c6bf20109a3fae92402cb76ad709ec5256bcd169 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 May 2020 12:36:13 +0200 Subject: mt76: mt7615: add WoW support Introduce WoW support to mt7615 driver. Current supported trigger are: - magic-packet - disconnect - user-pattern Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/main.c | 79 ++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 220 +++++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 62 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 4 +- 5 files changed, 322 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 6106dc4fea44..f1c9116b6ab4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -287,6 +287,7 @@ enum { MT76_READING_STATS, MT76_STATE_POWER_OFF, MT76_STATE_PS, + MT76_STATE_SUSPEND, }; struct mt76_hw_cap { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 5e54c7ffae0b..b93a47509423 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -864,6 +864,80 @@ mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); } +#ifdef CONFIG_PM +static int mt7615_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); + bool ext_phy = phy != &dev->phy; + int err = 0; + + mutex_lock(&dev->mt76.mutex); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mac_work); + + mt76_set(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); + + set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_mcu_set_suspend_iter, phy); + + if (!mt7615_dev_running(dev)) + err = mt7615_mcu_set_hif_suspend(dev, true); + + mutex_unlock(&dev->mt76.mutex); + + return err; +} + +static int mt7615_resume(struct ieee80211_hw *hw) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); + bool running, ext_phy = phy != &dev->phy; + + mutex_lock(&dev->mt76.mutex); + + running = mt7615_dev_running(dev); + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + if (!running) { + int err; + + err = mt7615_mcu_set_hif_suspend(dev, false); + if (err < 0) { + mutex_unlock(&dev->mt76.mutex); + return err; + } + } + + clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_mcu_set_suspend_iter, phy); + + ieee80211_queue_delayed_work(hw, &phy->mac_work, + MT7615_WATCHDOG_TIME); + mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt7615_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; + + device_set_wakeup_enable(mdev->dev, enabled); +} +#endif /* CONFIG_PM */ + const struct ieee80211_ops mt7615_ops = { .tx = mt7615_tx, .start = mt7615_start, @@ -897,6 +971,11 @@ const struct ieee80211_ops mt7615_ops = { .cancel_hw_scan = mt7615_cancel_hw_scan, .sched_scan_start = mt7615_start_sched_scan, .sched_scan_stop = mt7615_stop_sched_scan, +#ifdef CONFIG_PM + .suspend = mt7615_suspend, + .resume = mt7615_resume, + .set_wakeup = mt7615_set_wakeup, +#endif /* CONFIG_PM */ }; EXPORT_SYMBOL_GPL(mt7615_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index e7f6ab5ab2db..72e2e1cbab59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -195,7 +195,8 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, case MCU_UNI_CMD_DEV_INFO_UPDATE: case MCU_UNI_CMD_BSS_INFO_UPDATE: case MCU_UNI_CMD_STA_REC_UPDATE: - case MCU_UNI_CMD_HIF_CTRL: { + case MCU_UNI_CMD_HIF_CTRL: + case MCU_UNI_CMD_SUSPEND: { struct mt7615_mcu_uni_event *event; skb_pull(skb, sizeof(*rxd)); @@ -1835,6 +1836,13 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, return 0; } +static const struct wiphy_wowlan_support mt7615_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = 1, + .pattern_min_len = 1, + .pattern_max_len = MT7615_WOW_PATTEN_MAX_LEN, +}; + static int mt7615_load_n9(struct mt7615_dev *dev, const char *name) { const struct mt7615_fw_trailer *hdr; @@ -2157,6 +2165,11 @@ int __mt7663_load_firmware(struct mt7615_dev *dev) return -EIO; } +#ifdef CONFIG_PM + if (mt7615_firmware_offload(dev)) + dev->mt76.hw->wiphy->wowlan = &mt7615_wowlan_support; +#endif /* CONFIG_PM */ + dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; @@ -2653,47 +2666,6 @@ void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) &req, sizeof(req), false); } -int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, - bool enable) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - struct { - u8 bss_idx; - u8 dtim_period; - __le16 aid; - __le16 bcn_interval; - __le16 atim_window; - u8 uapsd; - u8 bmc_delivered_ac; - u8 bmc_triggered_ac; - u8 pad; - } req = { - .bss_idx = mvif->idx, - .aid = cpu_to_le16(vif->bss_conf.aid), - .dtim_period = vif->bss_conf.dtim_period, - .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), - }; - struct { - u8 bss_idx; - u8 pad[3]; - } req_hdr = { - .bss_idx = mvif->idx, - }; - int err; - - if (vif->type != NL80211_IFTYPE_STATION || - !mt7615_firmware_offload(dev)) - return -ENOTSUPP; - - err = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, - &req_hdr, sizeof(req_hdr), false); - if (err < 0 || !enable) - return err; - - return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, - &req, sizeof(req), false); -} - int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) { struct mt76_phy *mphy = phy->mt76; @@ -3222,6 +3194,7 @@ out: return ret; } +#ifdef CONFIG_PM int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) { struct { @@ -3254,3 +3227,166 @@ int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); + +static int +mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + u8 bss_idx; + u8 dtim_period; + __le16 aid; + __le16 bcn_interval; + __le16 atim_window; + u8 uapsd; + u8 bmc_delivered_ac; + u8 bmc_triggered_ac; + u8 pad; + } req = { + .bss_idx = mvif->idx, + .aid = cpu_to_le16(vif->bss_conf.aid), + .dtim_period = vif->bss_conf.dtim_period, + .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), + }; + struct { + u8 bss_idx; + u8 pad[3]; + } req_hdr = { + .bss_idx = mvif->idx, + }; + int err; + + if (vif->type != NL80211_IFTYPE_STATION || + !mt7615_firmware_offload(dev)) + return -ENOTSUPP; + + err = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, + &req_hdr, sizeof(req_hdr), false); + if (err < 0 || !enable) + return err; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, + &req, sizeof(req), false); +} + +static int +mt7615_mcu_set_wow_ctrl(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool suspend, struct cfg80211_wowlan *wowlan) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_wow_ctrl_tlv wow_ctrl_tlv; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .wow_ctrl_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), + .len = cpu_to_le16(sizeof(struct mt7615_wow_ctrl_tlv)), + .cmd = suspend ? 1 : 2, + }, + }; + + if (wowlan->magic_pkt) + req.wow_ctrl_tlv.trigger |= BIT(0); + if (wowlan->disconnect) + req.wow_ctrl_tlv.trigger |= BIT(2); + + if (mt76_is_mmio(&dev->mt76)) + req.wow_ctrl_tlv.wakeup_hif = 2; + else if (mt76_is_usb(&dev->mt76)) + req.wow_ctrl_tlv.wakeup_hif = 1; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, + &req, sizeof(req), true); +} + +static int +mt7615_mcu_set_wow_pattern(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + u8 index, bool enable, + struct cfg80211_pkt_pattern *pattern) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_wow_pattern_tlv *ptlv; + struct sk_buff *skb; + struct req_hdr { + u8 bss_idx; + u8 pad[3]; + } __packed hdr = { + .bss_idx = mvif->idx, + }; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(hdr) + sizeof(*ptlv)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + ptlv = (struct mt7615_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); + ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); + ptlv->len = cpu_to_le16(sizeof(*ptlv)); + ptlv->data_len = pattern->pattern_len; + ptlv->enable = enable; + ptlv->index = index; + + memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); + memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD_SUSPEND, true); +} + +static int +mt7615_mcu_set_suspend_mode(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + bool enable, u8 mdtim, bool wow_suspend) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_suspend_tlv suspend_tlv; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .suspend_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), + .len = cpu_to_le16(sizeof(struct mt7615_suspend_tlv)), + .enable = enable, + .mdtim = mdtim, + .wow_suspend = wow_suspend, + }, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, + &req, sizeof(req), true); +} + +void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt7615_phy *phy = priv; + bool suspend = test_bit(MT76_STATE_SUSPEND, &phy->mt76->state); + struct ieee80211_hw *hw = phy->mt76->hw; + struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; + int i; + + mt7615_mcu_set_bss_pm(phy->dev, vif, suspend); + + mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); + + for (i = 0; i < wowlan->n_patterns; i++) + mt7615_mcu_set_wow_pattern(phy->dev, vif, i, suspend, + &wowlan->patterns[i]); + mt7615_mcu_set_wow_ctrl(phy->dev, vif, suspend, wowlan); +} +#endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 1579ad944479..960ff234c72d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -280,6 +280,7 @@ enum { MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01, MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02, MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, + MCU_UNI_CMD_SUSPEND = MCU_UNI_PREFIX | 0x05, MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, }; @@ -415,6 +416,59 @@ struct mt7615_mcu_bss_event { u8 pad; } __packed; +struct mt7615_wow_ctrl_tlv { + __le16 tag; + __le16 len; + u8 cmd; /* 0x1: PM_WOWLAN_REQ_START + * 0x2: PM_WOWLAN_REQ_STOP + * 0x3: PM_WOWLAN_PARAM_CLEAR + */ + u8 trigger; /* 0: NONE + * BIT(0): NL80211_WOWLAN_TRIG_MAGIC_PKT + * BIT(1): NL80211_WOWLAN_TRIG_ANY + * BIT(2): NL80211_WOWLAN_TRIG_DISCONNECT + * BIT(3): NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE + * BIT(4): BEACON_LOST + * BIT(5): NL80211_WOWLAN_TRIG_NET_DETECT + */ + u8 wakeup_hif; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + * 0x3: HIF_GPIO + */ + u8 pad; + u8 rsv[4]; +} __packed; + +#define MT7615_WOW_MASK_MAX_LEN 16 +#define MT7615_WOW_PATTEN_MAX_LEN 128 +struct mt7615_wow_pattern_tlv { + __le16 tag; + __le16 len; + u8 index; /* pattern index */ + u8 enable; /* 0: disable + * 1: enable + */ + u8 data_len; /* pattern length */ + u8 pad; + u8 mask[MT7615_WOW_MASK_MAX_LEN]; + u8 pattern[MT7615_WOW_PATTEN_MAX_LEN]; + u8 rsv[4]; +} __packed; + +struct mt7615_suspend_tlv { + __le16 tag; + __le16 len; + u8 enable; /* 0: suspend mode disabled + * 1: suspend mode enabled + */ + u8 mdtim; /* LP parameter */ + u8 wow_suspend; /* 0: update by origin policy + * 1: update by wow dtim + */ + u8 pad[5]; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, @@ -439,6 +493,14 @@ enum { UNI_BSS_INFO_BCN_CONTENT = 7, }; +enum { + UNI_SUSPEND_MODE_SETTING, + UNI_SUSPEND_WOW_CTRL, + UNI_SUSPEND_WOW_GPIO_PARAM, + UNI_SUSPEND_WOW_WAKEUP_PORT, + UNI_SUSPEND_WOW_PATTERN, +}; + enum { PATCH_SEM_RELEASE = 0x0, PATCH_SEM_GET = 0x1 diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 6a26555dcce6..3e6bc3ce914a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -474,8 +474,6 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, enum set_key_cmd cmd); void mt7615_mac_reset_work(struct work_struct *work); -int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, - bool enable); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp); @@ -532,6 +530,8 @@ int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); +void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif); int __mt7663_load_firmware(struct mt7615_dev *dev); -- cgit From d0846f0867f3361c551e2f431f94f64c58646d56 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Fri, 1 May 2020 12:36:14 +0200 Subject: mt76: mt7663u: introduce suspend/resume to mt7663u Tested on Chromebok by "echo mem to /sys/power/state" to suspend and then waked up by keyboard keystrokes to resume system. Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 44 +++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f1c9116b6ab4..728a2fb8b14d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -381,6 +381,7 @@ enum mt_vendor_req { MT_VEND_READ_CFG = 0x47, MT_VEND_READ_EXT = 0x63, MT_VEND_WRITE_EXT = 0x66, + MT_VEND_FEATURE_SET = 0x91, }; enum mt76u_in_ep { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 9353175b139b..f2825b8f4539 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -372,18 +372,50 @@ static void mt7663u_disconnect(struct usb_interface *usb_intf) ieee80211_free_hw(dev->mt76.hw); } -static int __maybe_unused -mt7663u_suspend(struct usb_interface *intf, - pm_message_t state) +#ifdef CONFIG_PM +static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state) { + struct mt7615_dev *dev = usb_get_intfdata(intf); + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev)) { + int err; + + err = mt7615_mcu_set_hif_suspend(dev, true); + if (err < 0) + return err; + } + + mt76u_stop_rx(&dev->mt76); + + mt76u_stop_tx(&dev->mt76); + tasklet_kill(&dev->mt76.tx_tasklet); + return 0; } -static int __maybe_unused -mt7663u_resume(struct usb_interface *intf) +static int mt7663u_resume(struct usb_interface *intf) { - return 0; + struct mt7615_dev *dev = usb_get_intfdata(intf); + int err; + + err = mt76u_vendor_request(&dev->mt76, MT_VEND_FEATURE_SET, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x5, 0x0, NULL, 0); + if (err) + return err; + + err = mt76u_resume_rx(&dev->mt76); + if (err < 0) + return err; + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev)) + err = mt7615_mcu_set_hif_suspend(dev, false); + + return err; } +#endif /* CONFIG_PM */ MODULE_DEVICE_TABLE(usb, mt7615_device_table); MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); -- cgit From 6dd4072c1e8bc46ee81bdd5f779590bc43ab9ae4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 May 2020 12:36:15 +0200 Subject: mt76: mt7615: introduce PM support Introduce suspend/resume to mt7615e driver Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 37 +++++++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +- drivers/net/wireless/mediatek/mt76/mt7615/mmio.c | 4 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 5 + drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 108 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 28 +++++- 7 files changed, 186 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 0b1fbddd1c3f..5a124610d4af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -130,6 +130,43 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) return 0; } +int mt7615_wait_pdma_busy(struct mt7615_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + + if (!is_mt7663(mdev)) { + u32 mask = MT_PDMA_TX_BUSY | MT_PDMA_RX_BUSY; + u32 reg = mt7615_reg_map(dev, MT_PDMA_BUSY); + + if (!mt76_poll_msec(dev, reg, mask, 0, 1000)) { + dev_err(mdev->dev, "PDMA engine busy\n"); + return -EIO; + } + + return 0; + } + + if (!mt76_poll_msec(dev, MT_PDMA_BUSY_STATUS, + MT_PDMA_TX_IDX_BUSY, 0, 1000)) { + dev_err(mdev->dev, "PDMA engine tx busy\n"); + return -EIO; + } + + if (!mt76_poll_msec(dev, MT_PSE_PG_INFO, + MT_PSE_SRC_CNT, 0, 1000)) { + dev_err(mdev->dev, "PSE engine busy\n"); + return -EIO; + } + + if (!mt76_poll_msec(dev, MT_PDMA_BUSY_STATUS, + MT_PDMA_BUSY_IDX, 0, 1000)) { + dev_err(mdev->dev, "PDMA engine busy\n"); + return -EIO; + } + + return 0; +} + static void mt7622_dma_sched_init(struct mt7615_dev *dev) { u32 reg = mt7615_reg_map(dev, MT_DMASHDL_BASE); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5c09787b0d76..7d65a3fb0c23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1807,8 +1807,7 @@ mt7615_update_beacons(struct mt7615_dev *dev) mt7615_update_vif_beacon, dev->mt76.phy2->hw); } -static void -mt7615_dma_reset(struct mt7615_dev *dev) +void mt7615_dma_reset(struct mt7615_dev *dev) { int i; @@ -1827,6 +1826,7 @@ mt7615_dma_reset(struct mt7615_dev *dev) MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); } +EXPORT_SYMBOL_GPL(mt7615_dma_reset); void mt7615_mac_reset_work(struct work_struct *work) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 72e2e1cbab59..9b1340224448 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1683,7 +1683,7 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) !en * MT_INFRACFG_MISC_AP2CONN_WAKE); } -static int mt7615_driver_own(struct mt7615_dev *dev) +int mt7615_driver_own(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; u32 addr; @@ -1703,8 +1703,9 @@ static int mt7615_driver_own(struct mt7615_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt7615_driver_own); -static int mt7615_firmware_own(struct mt7615_dev *dev) +int mt7615_firmware_own(struct mt7615_dev *dev) { u32 addr; @@ -1723,6 +1724,7 @@ static int mt7615_firmware_own(struct mt7615_dev *dev) return 0; } +EXPORT_SYMBOL_GPL(mt7615_firmware_own); static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index c9f5b1ce70ae..e670393506f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -15,6 +15,8 @@ const u32 mt7615e_reg_map[] = { [MT_ARB_BASE] = 0x20c00, [MT_HIF_BASE] = 0x04000, [MT_CSR_BASE] = 0x07000, + [MT_PLE_BASE] = 0x08000, + [MT_PSE_BASE] = 0x0c000, [MT_PHY_BASE] = 0x10000, [MT_CFG_BASE] = 0x20200, [MT_AGG_BASE] = 0x20a00, @@ -40,6 +42,8 @@ const u32 mt7663e_reg_map[] = { [MT_ARB_BASE] = 0x20c00, [MT_HIF_BASE] = 0x04000, [MT_CSR_BASE] = 0x07000, + [MT_PLE_BASE] = 0x08000, + [MT_PSE_BASE] = 0x0c000, [MT_PHY_BASE] = 0x10000, [MT_CFG_BASE] = 0x20000, [MT_AGG_BASE] = 0x22000, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 3e6bc3ce914a..be9188e40259 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -380,6 +380,7 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr); int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); +int mt7615_wait_pdma_busy(struct mt7615_dev *dev); int mt7615_dma_init(struct mt7615_dev *dev); void mt7615_dma_cleanup(struct mt7615_dev *dev); int mt7615_mcu_init(struct mt7615_dev *dev); @@ -436,6 +437,7 @@ static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) return MT7615_WTBL_SIZE; } +void mt7615_dma_reset(struct mt7615_dev *dev); void mt7615_scan_work(struct work_struct *work); void mt7615_ps_work(struct work_struct *work); void mt7615_init_txpower(struct mt7615_dev *dev, @@ -526,6 +528,9 @@ int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +int mt7615_firmware_own(struct mt7615_dev *dev); +int mt7615_driver_own(struct mt7615_dev *dev); + int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 0605c908059e..88ff14564521 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -66,11 +66,119 @@ static void mt7615_pci_remove(struct pci_dev *pdev) pci_free_irq_vectors(pdev); } +#ifdef CONFIG_PM +static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + bool hif_suspend; + int i, err; + + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev); + if (hif_suspend) { + err = mt7615_mcu_set_hif_suspend(dev, true); + if (err) + return err; + } + + napi_disable(&mdev->tx_napi); + tasklet_kill(&mdev->tx_tasklet); + + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) + napi_disable(&mdev->napi[i]); + tasklet_kill(&dev->irq_tasklet); + + mt7615_dma_reset(dev); + + err = mt7615_wait_pdma_busy(dev); + if (err) + goto restore; + + if (is_mt7663(mdev)) { + mt76_set(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); + if (!mt76_poll_msec(dev, MT_PDMA_SLP_PROT, + MT_PDMA_AXI_SLPPROT_RDY, + MT_PDMA_AXI_SLPPROT_RDY, 1000)) { + dev_err(mdev->dev, "PDMA sleep protection failed\n"); + err = -EIO; + goto restore; + } + } + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + pci_save_state(pdev); + err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (err) + goto restore; + + err = mt7615_firmware_own(dev); + if (err) + goto restore; + + return 0; + +restore: + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) + napi_enable(&mdev->napi[i]); + napi_enable(&mdev->tx_napi); + if (hif_suspend) + mt7615_mcu_set_hif_suspend(dev, false); + + return err; +} + +static int mt7615_pci_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + bool pdma_reset; + int i, err; + + err = mt7615_driver_own(dev); + if (err < 0) + return err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + if (is_mt7663(&dev->mt76)) { + mt76_clear(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); + mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); + } + + pdma_reset = !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL0) && + !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL1); + if (pdma_reset) + dev_err(mdev->dev, "PDMA engine must be reinitialized\n"); + + for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) { + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && + mt7615_firmware_offload(dev)) + err = mt7615_mcu_set_hif_suspend(dev, false); + + return err; +} +#endif /* CONFIG_PM */ + struct pci_driver mt7615_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7615_pci_device_table, .probe = mt7615_pci_probe, .remove = mt7615_pci_remove, +#ifdef CONFIG_PM + .suspend = mt7615_pci_suspend, + .resume = mt7615_pci_resume, +#endif /* CONFIG_PM */ }; MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 68d30bcc087a..aee433a9eff6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -12,6 +12,8 @@ enum mt7615_reg_base { MT_ARB_BASE, MT_HIF_BASE, MT_CSR_BASE, + MT_PLE_BASE, + MT_PSE_BASE, MT_PHY_BASE, MT_CFG_BASE, MT_AGG_BASE, @@ -63,6 +65,17 @@ enum mt7615_reg_base { #define MT_HIF_RST MT_HIF(0x100) #define MT_HIF_LOGIC_RST_N BIT(4) +#define MT_PDMA_SLP_PROT MT_HIF(0x154) +#define MT_PDMA_AXI_SLPPROT_ENABLE BIT(0) +#define MT_PDMA_AXI_SLPPROT_RDY BIT(16) + +#define MT_PDMA_BUSY_STATUS MT_HIF(0x168) +#define MT_PDMA_TX_IDX_BUSY BIT(2) +#define MT_PDMA_BUSY_IDX BIT(31) + +#define MT_WPDMA_TX_RING0_CTRL0 MT_HIF(0x300) +#define MT_WPDMA_TX_RING0_CTRL1 MT_HIF(0x304) + #define MT7663_MCU_PCIE_REMAP_2_OFFSET GENMASK(15, 0) #define MT7663_MCU_PCIE_REMAP_2_BASE GENMASK(31, 16) @@ -138,8 +151,7 @@ enum mt7615_reg_base { #define MT_CSR(ofs) ((dev)->reg_map[MT_CSR_BASE] + (ofs)) #define MT_CONN_HIF_ON_LPCTL MT_CSR(0x000) -#define MT_PLE_BASE 0x8000 -#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) +#define MT_PLE(ofs) ((dev)->reg_map[MT_PLE_BASE] + (ofs)) #define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) #define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) @@ -149,6 +161,14 @@ enum mt7615_reg_base { #define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ ((n) << 2)) +#define MT_PSE(ofs) ((dev)->reg_map[MT_PSE_BASE] + (ofs)) +#define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b4) +#define MT_HIF_0_EMPTY_MASK BIT(16) +#define MT_HIF_1_EMPTY_MASK BIT(17) +#define MT_HIF_ALL_EMPTY_MASK GENMASK(17, 16) +#define MT_PSE_PG_INFO MT_PSE(0x194) +#define MT_PSE_SRC_CNT GENMASK(27, 16) + #define MT_WF_PHY_BASE ((dev)->reg_map[MT_PHY_BASE]) #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) @@ -482,6 +502,10 @@ enum mt7615_reg_base { #define MT_LED_STATUS_ON GENMASK(23, 16) #define MT_LED_STATUS_DURATION GENMASK(15, 0) +#define MT_PDMA_BUSY 0x82000504 +#define MT_PDMA_TX_BUSY BIT(0) +#define MT_PDMA_RX_BUSY BIT(1) + #define MT_EFUSE_BASE ((dev)->reg_map[MT_EFUSE_ADDR_BASE]) #define MT_EFUSE_BASE_CTRL 0x000 #define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) -- cgit From b47e21e75c80966be1afc7fe28c75c6798b3e48e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 May 2020 12:36:16 +0200 Subject: mt76: mt7615: add gtk rekey offload support Add KCK and KEK offload support to mt7615 driver in order to support GTK rekeying during PM suspend Co-developed-by: Sean Wang Signed-off-by: Sean Wang Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/main.c | 8 ++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 102 ++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 29 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 3 + 5 files changed, 142 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 145af8a3ae57..81294bb2b06b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -145,6 +145,7 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev) dev->ops->cancel_hw_scan = NULL; dev->ops->sched_scan_start = NULL; dev->ops->sched_scan_stop = NULL; + dev->ops->set_rekey_data = NULL; wiphy->max_sched_scan_plan_interval = 0; wiphy->max_sched_scan_ie_len = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b93a47509423..cfe024b71677 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -936,6 +936,13 @@ static void mt7615_set_wakeup(struct ieee80211_hw *hw, bool enabled) device_set_wakeup_enable(mdev->dev, enabled); } + +static void mt7615_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + mt7615_mcu_update_gtk_rekey(hw, vif, data); +} #endif /* CONFIG_PM */ const struct ieee80211_ops mt7615_ops = { @@ -975,6 +982,7 @@ const struct ieee80211_ops mt7615_ops = { .suspend = mt7615_suspend, .resume = mt7615_resume, .set_wakeup = mt7615_set_wakeup, + .set_rekey_data = mt7615_set_rekey_data, #endif /* CONFIG_PM */ }; EXPORT_SYMBOL_GPL(mt7615_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 9b1340224448..da50e12f1c03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -196,6 +196,7 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, case MCU_UNI_CMD_BSS_INFO_UPDATE: case MCU_UNI_CMD_STA_REC_UPDATE: case MCU_UNI_CMD_HIF_CTRL: + case MCU_UNI_CMD_OFFLOAD: case MCU_UNI_CMD_SUSPEND: { struct mt7615_mcu_uni_event *event; @@ -1839,7 +1840,8 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, } static const struct wiphy_wowlan_support mt7615_wowlan_support = { - .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY, .n_patterns = 1, .pattern_min_len = 1, .pattern_max_len = MT7615_WOW_PATTEN_MAX_LEN, @@ -3373,6 +3375,33 @@ mt7615_mcu_set_suspend_mode(struct mt7615_dev *dev, &req, sizeof(req), true); } +static int +mt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + bool suspend) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_gtk_rekey_tlv gtk_tlv; + } __packed req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .gtk_tlv = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), + .len = cpu_to_le16(sizeof(struct mt7615_gtk_rekey_tlv)), + .rekey_mode = !suspend, + }, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, + &req, sizeof(req), true); +} + void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { @@ -3384,6 +3413,8 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, mt7615_mcu_set_bss_pm(phy->dev, vif, suspend); + mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend); + mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); for (i = 0; i < wowlan->n_patterns; i++) @@ -3391,4 +3422,73 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, &wowlan->patterns[i]); mt7615_mcu_set_wow_ctrl(phy->dev, vif, suspend, wowlan); } + +static void +mt7615_mcu_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct ieee80211_key_conf *key, + void *data) +{ + struct mt7615_gtk_rekey_tlv *gtk_tlv = data; + u32 cipher; + + if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && + key->cipher != WLAN_CIPHER_SUITE_CCMP && + key->cipher != WLAN_CIPHER_SUITE_TKIP) + return; + + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1); + cipher = BIT(3); + } else { + gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2); + cipher = BIT(4); + } + + /* we are assuming here to have a single pairwise key */ + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + gtk_tlv->pairwise_cipher = cpu_to_le32(cipher); + gtk_tlv->group_cipher = cpu_to_le32(cipher); + gtk_tlv->keyid = key->keyidx; + } +} + +int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *key) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_gtk_rekey_tlv *gtk_tlv; + struct sk_buff *skb; + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr = { + .bss_idx = mvif->idx, + }; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(hdr) + sizeof(*gtk_tlv)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + gtk_tlv = (struct mt7615_gtk_rekey_tlv *)skb_put(skb, + sizeof(*gtk_tlv)); + gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); + gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); + gtk_tlv->rekey_mode = 2; + gtk_tlv->option = 1; + + rcu_read_lock(); + ieee80211_iter_keys_rcu(hw, vif, mt7615_mcu_key_iter, gtk_tlv); + rcu_read_unlock(); + + memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); + memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); + memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD_OFFLOAD, true); +} #endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 960ff234c72d..890a202acfc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -281,6 +281,7 @@ enum { MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02, MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03, MCU_UNI_CMD_SUSPEND = MCU_UNI_PREFIX | 0x05, + MCU_UNI_CMD_OFFLOAD = MCU_UNI_PREFIX | 0x06, MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, }; @@ -469,6 +470,27 @@ struct mt7615_suspend_tlv { u8 pad[5]; } __packed; +struct mt7615_gtk_rekey_tlv { + __le16 tag; + __le16 len; + u8 kek[NL80211_KEK_LEN]; + u8 kck[NL80211_KCK_LEN]; + u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; + u8 rekey_mode; /* 0: rekey offload enable + * 1: rekey offload disable + * 2: rekey update + */ + u8 keyid; + u8 pad[2]; + __le32 proto; /* WPA-RSN-WAPI-OPSN */ + __le32 pairwise_cipher; + __le32 group_cipher; + __le32 key_mgmt; /* NONE-PSK-IEEE802.1X */ + __le32 mgmt_group_cipher; + u8 option; /* 1: rekey data update without enabling offload */ + u8 reserverd[3]; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, @@ -501,6 +523,13 @@ enum { UNI_SUSPEND_WOW_PATTERN, }; +enum { + UNI_OFFLOAD_OFFLOAD_ARPNS_IPV4, + UNI_OFFLOAD_OFFLOAD_ARPNS_IPV6, + UNI_OFFLOAD_OFFLOAD_GTK_REKEY, + UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, +}; + enum { PATCH_SEM_RELEASE = 0x0, PATCH_SEM_GET = 0x1 diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index be9188e40259..d3a83f3ed54e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -537,6 +537,9 @@ int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); +int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *key); int __mt7663_load_firmware(struct mt7615_dev *dev); -- cgit From 86c60179e5537c28145cbfa5ed2c16f776a497a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 May 2020 12:36:17 +0200 Subject: mt76: mt7615: introduce beacon_loss mcu event If device has enabled beacon hw filter rx beacons are not reported to the host. Introduce beacon_loss mcu event to trigger mac80211 mlme connection state machine in this configuration. IEEE80211_VIF_BEACON_FILTER has not set in vif flags since hw beacon filter is not enabled yet Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 38 +++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 7 +++++ 2 files changed, 45 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index da50e12f1c03..6da819a06748 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -359,6 +359,40 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) MT7615_HW_SCAN_TIMEOUT); } +static void +mt7615_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_beacon_loss_event *event = priv; + + if (mvif->idx != event->bss_idx) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) + return; + + ieee80211_beacon_loss(vif); +} + +static void +mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_beacon_loss_event *event; + struct mt76_phy *mphy; + u8 band_idx = 0; /* DBDC support */ + + skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); + event = (struct mt7615_beacon_loss_event *)skb->data; + if (band_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + else + mphy = &dev->mt76.phy; + + ieee80211_iterate_active_interfaces_atomic(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_mcu_beacon_loss_iter, event); +} + static void mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) { @@ -389,6 +423,9 @@ mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7615_mcu_rx_ext_event(dev, skb); break; + case MCU_EVENT_BSS_BEACON_LOSS: + mt7615_mcu_beacon_loss_event(dev, skb); + break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: mt7615_mcu_scan_event(dev, skb); @@ -410,6 +447,7 @@ void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 890a202acfc9..737ccec6dd96 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -83,6 +83,7 @@ enum { MCU_EVENT_MT_PATCH_SEM = 0x04, MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_BSS_ABSENCE = 0x11, + MCU_EVENT_BSS_BEACON_LOSS = 0x13, MCU_EVENT_CH_PRIVILEGE = 0x18, MCU_EVENT_SCHED_SCAN_DONE = 0x23, MCU_EVENT_EXT = 0xed, @@ -291,6 +292,12 @@ struct mt7615_mcu_uni_event { __le32 status; /* 0: success, others: fail */ } __packed; +struct mt7615_beacon_loss_event { + u8 bss_idx; + u8 reason; + u8 pad[2]; +} __packed; + struct mt7615_mcu_scan_ssid { __le32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; -- cgit From eb7bd8d7fb727dcdbf4b1c145bba1169bc3c2d4a Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 2 May 2020 01:13:11 +0200 Subject: mt76: mt7663: read tx streams from eeprom Read tx stream configuration from eeprom/efuse Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 11 ++++++----- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 521705015036..7440ad13c74b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -130,14 +130,15 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev) static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; - u8 tx_mask; + u8 tx_mask, max_nss; mt7615_eeprom_parse_hw_band_cap(dev); if (is_mt7663(&dev->mt76)) { - tx_mask = 2; + max_nss = 2; + tx_mask = FIELD_GET(MT_EE_HW_CONF1_TX_MASK, + eeprom[MT7663_EE_HW_CONF1]); } else { - u8 max_nss; u32 val; /* read tx-rx mask from eeprom */ @@ -146,9 +147,9 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK, eeprom[MT_EE_NIC_CONF_0]); - if (!tx_mask || tx_mask > max_nss) - tx_mask = max_nss; } + if (!tx_mask || tx_mask > max_nss) + tx_mask = max_nss; dev->chainmask = BIT(tx_mask) - 1; dev->mphy.antenna_mask = dev->chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index 3dd7009e5836..aad82b600c63 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -39,6 +39,7 @@ enum mt7615_eeprom_field { MT7663_EE_TX0_2G_TARGET_POWER = 0x123, MT_EE_TX2_5G_G0_TARGET_POWER = 0x142, MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a, + MT7663_EE_HW_CONF1 = 0x1b0, MT7615_EE_MAX = 0x3bf, MT7622_EE_MAX = 0x3db, @@ -55,6 +56,8 @@ enum mt7615_eeprom_field { #define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4) #define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0) +#define MT_EE_HW_CONF1_TX_MASK GENMASK(2, 0) + #define MT_EE_NIC_CONF_TSSI_2G BIT(5) #define MT_EE_NIC_CONF_TSSI_5G BIT(6) -- cgit From cc5f58aee180f1f8dbdbc136ecb3cdd190b29068 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 2 May 2020 01:16:10 +0200 Subject: mt76: mt7615: check return value of mt7615_eeprom_get_power_index mt7615_eeprom_get_power_index can return negative error value. Check mt7615_eeprom_get_power_index return value before using it Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 81294bb2b06b..d831d647d237 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -247,6 +247,9 @@ void mt7615_init_txpower(struct mt7615_dev *dev, int index; index = mt7615_eeprom_get_power_index(dev, chan, j); + if (index < 0) + continue; + target_power = max(target_power, eep[index]); } -- cgit From 9582d5bdef0cbebbfa451b4894518f0d790f05c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 2 May 2020 18:00:41 +0200 Subject: mt76: mt7615: fix ibss mode for mt7663 Fix the following kernel warning adding an adhoc interface to a mt7663e device [ 233.363394] WARNING: CPU: 0 PID: 2345 at drivers/net/wireless/mt76/mt7615/mcu.c:1449 mt7615_mcu_uni_add_bss+0x15f/0x24e [mt7615_common] [ 233.363432] CPU: 0 PID: 2345 Comm: iw Tainted: G W 4.14.171 #12 [ 233.363434] Hardware name: HP Meep/Meep, BIOS Google_Meep.11297.75.0 06/17/2019 [ 233.363436] task: ffff9a1a4020e3c0 task.stack: ffffb9124113c000 [ 233.363441] RIP: 0010:mt7615_mcu_uni_add_bss+0x15f/0x24e [mt7615_common] [ 233.363443] RSP: 0018:ffffb9124113f730 EFLAGS: 00010246 [ 233.363446] RAX: 0000000000000024 RBX: ffff9a1a788c74e8 RCX: 41826d413aea9200 [ 233.363448] RDX: 0000000000000007 RSI: 0000000000000006 RDI: ffff9a1a7fc15418 [ 233.363450] RBP: ffffb9124113f7c0 R08: 0000000000000356 R09: 00000000ffff0a10 [ 233.363452] R10: 0000001000000000 R11: ffffffff93f2a4be R12: 0000000000000000 [ 233.363454] R13: ffff9a1a7383bd48 R14: ffffb9124113f77a R15: 0000000000000000 [ 233.363456] FS: 00007f203314ab80(0000) GS:ffff9a1a7fc00000(0000) knlGS:0000000000000000 [ 233.363458] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 233.363460] CR2: 00005a13d647c950 CR3: 0000000171238000 CR4: 00000000003406f0 [ 233.363462] Call Trace: [ 233.363470] mt7615_bss_info_changed+0x98/0xf4 [mt7615_common] [ 233.363484] ieee80211_bss_info_change_notify+0x139/0x1d4 [mt76_mac80211] [ 233.363496] ieee80211_ibss_disconnect+0x183/0x1bb [mt76_mac80211] [ 233.363507] ieee80211_ibss_leave+0x14/0xa0 [mt76_mac80211] [ 233.363519] __cfg80211_leave_ibss+0xa6/0x13a [cfg80211] [ 233.363528] cfg80211_netdev_notifier_call+0x8b/0x631 [cfg80211] [ 233.363535] ? packet_notifier+0x196/0x1a3 [ 233.363540] raw_notifier_call_chain+0x39/0x58 [ 233.363544] __dev_close_many+0x6b/0xf0 [ 233.363548] dev_close_many+0x62/0xe8 [ 233.363552] ? _raw_spin_unlock_irq+0xe/0x21 [ 233.363555] rollback_registered_many+0xf6/0x35c [ 233.363560] ? __rcu_read_unlock+0x4a/0x4a [ 233.363563] unregister_netdevice_queue+0x7f/0x105 [ 233.363573] ieee80211_del_iface+0x12/0x16 [mt76_mac80211] [ 233.363582] nl80211_del_interface+0xa8/0x124 [cfg80211] [ 233.363588] genl_rcv_msg+0x40b/0x481 [ 233.363592] ? genl_unbind+0xb8/0xb8 [ 233.363595] netlink_rcv_skb+0x85/0xf8 [ 233.363598] genl_rcv+0x28/0x36 [ 233.363601] netlink_unicast+0x165/0x1f8 [ 233.363604] netlink_sendmsg+0x35f/0x3a6 [ 233.363608] sock_sendmsg+0x38/0x48 [ 233.363611] ___sys_sendmsg+0x1bf/0x267 [ 233.363615] ? __inode_wait_for_writeback+0x72/0xd7 [ 233.363619] ? dentry_kill+0x69/0x76 [ 233.363622] ? dput+0xd1/0x170 [ 233.363624] __sys_sendmsg+0x52/0x8f [ 233.363628] do_syscall_64+0x6b/0xf7 [ 233.363632] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 233.363635] RIP: 0033:0x7f2032ca1264 [ 233.363637] RSP: 002b:00007ffec3668e38 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [ 233.363639] RAX: ffffffffffffffda RBX: 000058f7175e7880 RCX: 00007f2032ca1264 [ 233.363641] RDX: 0000000000000000 RSI: 00007ffec3668e98 RDI: 0000000000000003 [ 233.363643] RBP: 00007ffec3668e70 R08: 0000000000000001 R09: 00007f2032ce1fd0 [ 233.363645] R10: 000058f7175e2010 R11: 0000000000000246 R12: 000058f7175e7740 [ 233.363646] R13: 00007ffec3668ff0 R14: 000058f7175e2350 R15: 00007ffec3668e98 Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 6da819a06748..7adf0f7e7e2b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1417,6 +1417,9 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, case NL80211_IFTYPE_STATION: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); break; + case NL80211_IFTYPE_ADHOC: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; default: WARN_ON(1); break; -- cgit From e0ec633d76dcef31d8a15a3296815e7e8ad6aa73 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 May 2020 17:23:54 +0200 Subject: mt76: mt7663: fix target power parsing Fix target parsing from eeprom/efuse partition for 7663 chipsets Fixes: f40ac0f3d3c0 ("mt76: mt7615: introduce mt7663e support") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 31 +++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 4 ++- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 8 ++++-- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 6 ++--- 4 files changed, 40 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 7440ad13c74b..97f173343ae5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -156,12 +156,37 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) dev->phy.chainmask = dev->chainmask; } -int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, - struct ieee80211_channel *chan, - u8 chain_idx) +static int mt7663_eeprom_get_target_power_index(struct mt7615_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx) +{ + int index, group; + + if (chain_idx > 1) + return -EINVAL; + + if (chan->band == NL80211_BAND_2GHZ) + return MT7663_EE_TX0_2G_TARGET_POWER + (chain_idx << 4); + + group = mt7615_get_channel_group(chan->hw_value); + if (chain_idx == 1) + index = MT7663_EE_TX1_5G_G0_TARGET_POWER; + else + index = MT7663_EE_TX0_5G_G0_TARGET_POWER; + + return index + group * 3; +} + +int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx) { int index; + if (is_mt7663(&dev->mt76)) + return mt7663_eeprom_get_target_power_index(dev, chan, + chain_idx); + if (chain_idx > 3) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index aad82b600c63..a497f04b5e31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -34,12 +34,14 @@ enum mt7615_eeprom_field { MT_EE_TX1_5G_G0_TARGET_POWER = 0x098, MT_EE_2G_RATE_POWER = 0x0be, MT_EE_5G_RATE_POWER = 0x0d5, + MT7663_EE_TX0_2G_TARGET_POWER = 0x0e3, MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2, MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3, - MT7663_EE_TX0_2G_TARGET_POWER = 0x123, MT_EE_TX2_5G_G0_TARGET_POWER = 0x142, MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a, MT7663_EE_HW_CONF1 = 0x1b0, + MT7663_EE_TX0_5G_G0_TARGET_POWER = 0x245, + MT7663_EE_TX1_5G_G0_TARGET_POWER = 0x2b5, MT7615_EE_MAX = 0x3bf, MT7622_EE_MAX = 0x3db, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index d831d647d237..c6c1701e9e4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -237,7 +237,11 @@ void mt7615_init_txpower(struct mt7615_dev *dev, (MT_EE_RATE_POWER_EN | MT_EE_RATE_POWER_SIGN)) delta += rate_val & MT_EE_RATE_POWER_MASK; - target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; + if (!is_mt7663(&dev->mt76) && mt7615_ext_pa_enabled(dev, band)) + target_chains = 1; + else + target_chains = n_chains; + for (i = 0; i < sband->n_channels; i++) { struct ieee80211_channel *chan = &sband->channels[i]; u8 target_power = 0; @@ -246,7 +250,7 @@ void mt7615_init_txpower(struct mt7615_dev *dev, for (j = 0; j < target_chains; j++) { int index; - index = mt7615_eeprom_get_power_index(dev, chan, j); + index = mt7615_eeprom_get_target_power_index(dev, chan, j); if (index < 0) continue; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d3a83f3ed54e..d28e6380b338 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -377,9 +377,9 @@ void mt7615_unregister_device(struct mt7615_dev *dev); int mt7615_register_ext_phy(struct mt7615_dev *dev); void mt7615_unregister_ext_phy(struct mt7615_dev *dev); int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr); -int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, - struct ieee80211_channel *chan, - u8 chain_idx); +int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx); int mt7615_wait_pdma_busy(struct mt7615_dev *dev); int mt7615_dma_init(struct mt7615_dev *dev); void mt7615_dma_cleanup(struct mt7615_dev *dev); -- cgit From c88bf52b15872d960d5a0c30f0bac6351fb295df Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 3 May 2020 17:30:53 +0200 Subject: mt76: mt7615: fix delta tx power for mt7663 Fix mt7663 eeprom definitions for delta tx power parsing Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 17 +++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 10 +++------- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ 4 files changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 97f173343ae5..6a5ae047c63b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -225,6 +225,23 @@ int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev, return index; } +int mt7615_eeprom_get_power_delta_index(struct mt7615_dev *dev, + enum nl80211_band band) +{ + /* assume the first rate has the highest power offset */ + if (is_mt7663(&dev->mt76)) { + if (band == NL80211_BAND_2GHZ) + return MT_EE_TX0_5G_G0_TARGET_POWER; + else + return MT7663_EE_5G_RATE_POWER; + } + + if (band == NL80211_BAND_2GHZ) + return MT_EE_2G_RATE_POWER; + else + return MT_EE_5G_RATE_POWER; +} + static void mt7615_apply_cal_free_data(struct mt7615_dev *dev) { static const u16 ical[] = { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index a497f04b5e31..40fed7adc58a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -31,6 +31,7 @@ enum mt7615_eeprom_field { MT_EE_CALDATA_FLASH = 0x052, MT_EE_TX0_2G_TARGET_POWER = 0x058, MT_EE_TX0_5G_G0_TARGET_POWER = 0x070, + MT7663_EE_5G_RATE_POWER = 0x089, MT_EE_TX1_5G_G0_TARGET_POWER = 0x098, MT_EE_2G_RATE_POWER = 0x0be, MT_EE_5G_RATE_POWER = 0x0d5, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index c6c1701e9e4d..1d49d65d1acd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -222,17 +222,13 @@ void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband) { int i, n_chains = hweight8(dev->mphy.antenna_mask), target_chains; + int delta_idx, delta = mt76_tx_power_nss_delta(n_chains); u8 *eep = (u8 *)dev->mt76.eeprom.data; enum nl80211_band band = sband->band; - int delta = mt76_tx_power_nss_delta(n_chains); u8 rate_val; - /* assume the first rate has the highest power offset */ - if (band == NL80211_BAND_2GHZ) - rate_val = eep[MT_EE_2G_RATE_POWER]; - else - rate_val = eep[MT_EE_5G_RATE_POWER]; - + delta_idx = mt7615_eeprom_get_power_delta_index(dev, band); + rate_val = eep[delta_idx]; if ((rate_val & ~MT_EE_RATE_POWER_MASK) == (MT_EE_RATE_POWER_EN | MT_EE_RATE_POWER_SIGN)) delta += rate_val & MT_EE_RATE_POWER_MASK; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index d28e6380b338..dc60abb0a130 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -380,6 +380,8 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr); int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); +int mt7615_eeprom_get_power_delta_index(struct mt7615_dev *dev, + enum nl80211_band band); int mt7615_wait_pdma_busy(struct mt7615_dev *dev); int mt7615_dma_init(struct mt7615_dev *dev); void mt7615_dma_cleanup(struct mt7615_dev *dev); -- cgit From a72ad451e7049c18211f91bf12c7784a32ecbe1b Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 6 May 2020 11:53:35 +0200 Subject: mt76: mt7663: introduce WoW with net detect support Introduce WoW with net detect support Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 7adf0f7e7e2b..2775238b36ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1882,10 +1882,11 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, static const struct wiphy_wowlan_support mt7615_wowlan_support = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | - WIPHY_WOWLAN_SUPPORTS_GTK_REKEY, + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, .n_patterns = 1, .pattern_min_len = 1, .pattern_max_len = MT7615_WOW_PATTEN_MAX_LEN, + .max_nd_match_sets = 10, }; static int mt7615_load_n9(struct mt7615_dev *dev, const char *name) @@ -3316,10 +3317,11 @@ mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, } static int -mt7615_mcu_set_wow_ctrl(struct mt7615_dev *dev, struct ieee80211_vif *vif, +mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool suspend, struct cfg80211_wowlan *wowlan) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = phy->dev; struct { struct { u8 bss_idx; @@ -3341,6 +3343,11 @@ mt7615_mcu_set_wow_ctrl(struct mt7615_dev *dev, struct ieee80211_vif *vif, req.wow_ctrl_tlv.trigger |= BIT(0); if (wowlan->disconnect) req.wow_ctrl_tlv.trigger |= BIT(2); + if (wowlan->nd_config) { + mt7615_mcu_sched_scan_req(phy, vif, wowlan->nd_config); + req.wow_ctrl_tlv.trigger |= BIT(5); + } + mt7615_mcu_sched_scan_enable(phy, vif, suspend); if (mt76_is_mmio(&dev->mt76)) req.wow_ctrl_tlv.wakeup_hif = 2; @@ -3461,7 +3468,7 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, for (i = 0; i < wowlan->n_patterns; i++) mt7615_mcu_set_wow_pattern(phy->dev, vif, i, suspend, &wowlan->patterns[i]); - mt7615_mcu_set_wow_ctrl(phy->dev, vif, suspend, wowlan); + mt7615_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); } static void -- cgit From 5fdba8a77be6e7814698d5ac068cc31775b9930d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 6 May 2020 11:55:42 +0200 Subject: mt76: mt7663: add support to sched scan with randomise addr Add support to sched scan with randomise addr Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 7 ++++++- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 5 +++-- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 1d49d65d1acd..37fc70197f92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -139,7 +139,8 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev) ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; } else { dev->ops->hw_scan = NULL; dev->ops->cancel_hw_scan = NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 2775238b36ca..19b59a7550b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2907,7 +2907,12 @@ int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, req = (struct mt7615_sched_scan_req *)skb_put(skb, sizeof(*req)); req->version = 1; req->seq_num = mvif->scan_seq_num | ext_phy << 7; - req->scan_func = !!(sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR); + + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(req->random_mac, sreq->mac_addr, + sreq->mac_addr_mask); + req->scan_func = 1; + } req->ssids_num = sreq->n_ssids; for (i = 0; i < req->ssids_num; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 737ccec6dd96..0f12e6da89af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -405,10 +405,11 @@ struct mt7615_sched_scan_req { u8 channel_type; u8 channels_num; u8 intervals_num; - u8 scan_func; + u8 scan_func; /* BIT(0) eable random mac address */ struct mt7615_mcu_scan_channel channels[64]; __le16 intervals[MT7615_MAX_SCHED_SCAN_INTERVAL]; - u8 pad2[64]; + u8 random_mac[ETH_ALEN]; /* valid when BIT(0) in scan_func is set */ + u8 pad2[58]; } __packed; struct nt7615_sched_scan_done { -- cgit From 1245fe6a83a1c550d86d15501d86f9b2de5f97ff Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 6 May 2020 11:58:32 +0200 Subject: mt76: mt7615: scan all channels if not specified Configure the mcu to scan all available channels if mac80211 does not provide any frequency list Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 19b59a7550b6..96bf39a4a3da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2806,7 +2806,6 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, req->scan_type = sreq->n_ssids ? 1 : 0; req->probe_req_num = sreq->n_ssids ? 2 : 0; req->version = 1; - req->channel_type = 4; for (i = 0; i < sreq->n_ssids; i++) { if (!sreq->ssids[i].ssid_len) @@ -2835,6 +2834,7 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2; chan->channel_num = scan_list[i]->hw_value; } + req->channel_type = sreq->n_channels ? 4 : 0; if (sreq->ie_len > 0) { memcpy(req->ies, sreq->ie, sreq->ie_len); @@ -2930,7 +2930,7 @@ int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy, req->match[i].ssid_len = match->ssid.ssid_len; } - req->channel_type = 4; + req->channel_type = sreq->n_channels ? 4 : 0; req->channels_num = min_t(u8, sreq->n_channels, 64); for (i = 0; i < req->channels_num; i++) { chan = &req->channels[i]; -- cgit From 7c4f744d6703757be959f521a7a441bf34745d99 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:22 +0800 Subject: mt76: avoid rx reorder buffer overflow Enlarge slot to support 11ax 256 BA (256 MPDUs in an AMPDU) Signed-off-by: Chih-Min Chen Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index f77f03530259..acdbe6f8248d 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -152,8 +152,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) struct ieee80211_sta *sta; struct mt76_rx_tid *tid; bool sn_less; - u16 seqno, head, size; - u8 ackp, idx; + u16 seqno, head, size, idx; + u8 ackp; __skb_queue_tail(frames, skb); @@ -239,7 +239,7 @@ out: } int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno, - u16 ssn, u8 size) + u16 ssn, u16 size) { struct mt76_rx_tid *tid; @@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(mt76_rx_aggr_start); static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) { - u8 size = tid->size; + u16 size = tid->size; int i; spin_lock_bh(&tid->lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 728a2fb8b14d..67cab570bb71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -244,8 +244,8 @@ struct mt76_rx_tid { struct delayed_work reorder_work; u16 head; - u8 size; - u8 nframes; + u16 size; + u16 nframes; u8 num; @@ -798,7 +798,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, - u16 ssn, u8 size); + u16 ssn, u16 size); void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid); void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, -- cgit From af4a2f2fdd6fe4f6ffc61eec84da999dbff37d3c Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:23 +0800 Subject: mt76: add support for HE RX rate reporting Add support for encoding and reporting HE RX rates. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 176c22a5319a..f13114b07b6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -676,7 +676,6 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_hw **hw, struct ieee80211_sta **sta) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct mt76_rx_status mstat; @@ -688,6 +687,9 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, status->enc_flags = mstat.enc_flags; status->encoding = mstat.encoding; status->bw = mstat.bw; + status->he_ru = mstat.he_ru; + status->he_gi = mstat.he_gi; + status->he_dcm = mstat.he_dcm; status->rate_idx = mstat.rate_idx; status->nss = mstat.nss; status->band = mstat.band; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 67cab570bb71..083d87462533 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -462,7 +462,8 @@ struct mt76_rx_status { u16 freq; u32 flag; u8 enc_flags; - u8 encoding:2, bw:3; + u8 encoding:2, bw:3, he_ru:3; + u8 he_gi:2, he_dcm:1; u8 rate_idx; u8 nss; u8 band; -- cgit From 77ae1d5e13eb51651899fbfb6d7a34bc5ee7d4af Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:24 +0800 Subject: mt76: add Rx stats support for radiotap HE deivces need to add Rx radiotap header. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index acdbe6f8248d..df25c00d9e06 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -119,7 +119,7 @@ static void mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; + struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct mt76_rx_tid *tid; u16 seqno; @@ -147,7 +147,7 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct ieee80211_sta *sta; struct mt76_rx_tid *tid; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f13114b07b6e..f65e1b3e8f7a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -726,7 +726,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) * Validate the first fragment both here and in mac80211 * All further fragments will be validated by mac80211 only. */ - hdr = (struct ieee80211_hdr *)skb->data; + hdr = mt76_skb_get_hdr(skb); if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) return 0; @@ -799,7 +799,7 @@ mt76_airtime_flush_ampdu(struct mt76_dev *dev) static void mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; @@ -836,7 +836,7 @@ static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct ieee80211_sta *sta; struct ieee80211_hw *hw; struct mt76_wcid *wcid = status->wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 083d87462533..38c91db2dea7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -746,6 +746,25 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb) return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data); } +static inline void *mt76_skb_get_hdr(struct sk_buff *skb) +{ + struct mt76_rx_status mstat; + 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); + + mstat = *((struct mt76_rx_status *)skb->cb); + + if (mstat.flag & RX_FLAG_RADIOTAP_HE) + data += sizeof(struct ieee80211_radiotap_he); + if (mstat.flag & RX_FLAG_RADIOTAP_HE_MU) + data += sizeof(struct ieee80211_radiotap_he_mu); + + return data; +} + static inline void mt76_insert_hdr_pad(struct sk_buff *skb) { int len = ieee80211_get_hdrlen_from_skb(skb); -- cgit From 49e649c3e0a6ec8a12976e331a2c1f29dc7dd3a9 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:25 +0800 Subject: mt76: adjust wcid size to support new 802.11ax generation The newer 802.11ax devices (i.e. MT7915E) can connect to much more peers than previous generations. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 38c91db2dea7..25a7cda90766 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -181,7 +181,7 @@ enum mt76_wcid_flags { MT_WCID_FLAG_PS, }; -#define MT76_N_WCIDS 128 +#define MT76_N_WCIDS 288 /* stored in ieee80211_tx_info::hw_queue */ #define MT_TX_HW_QUEUE_EXT_PHY BIT(3) @@ -201,7 +201,7 @@ struct mt76_wcid { struct ewma_signal rssi; int inactive_count; - u8 idx; + u16 idx; u8 hw_key_idx; u8 sta:1; @@ -268,7 +268,7 @@ struct mt76_rx_tid { struct mt76_tx_cb { unsigned long jiffies; - u8 wcid; + u16 wcid; u8 pktid; u8 flags; }; @@ -445,7 +445,7 @@ struct mt76_mmio { struct mt76_rx_status { union { struct mt76_wcid *wcid; - u8 wcid_idx; + u16 wcid_idx; }; unsigned long reorder_time; @@ -622,7 +622,7 @@ enum mt76_phy_type { #define mt76_hw(dev) (dev)->mphy.hw static inline struct ieee80211_hw * -mt76_wcid_hw(struct mt76_dev *dev, u8 wcid) +mt76_wcid_hw(struct mt76_dev *dev, u16 wcid) { if (wcid <= MT76_N_WCIDS && mt76_wcid_mask_test(dev->wcid_phy_mask, wcid)) -- cgit From d3377b78cec6eb32241a2ac3dc0c43a0bf71129a Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:26 +0800 Subject: mt76: add HE phy modes and hardware queue This is a preliminary patch to support 11ax deivces. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 25a7cda90766..88959c1d5d1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -60,6 +60,7 @@ enum mt76_txq_id { MT_TXQ_BK = IEEE80211_AC_BK, MT_TXQ_PSD, MT_TXQ_MCU, + MT_TXQ_MCU_WA, MT_TXQ_BEACON, MT_TXQ_CAB, MT_TXQ_FWDL, @@ -69,6 +70,7 @@ enum mt76_txq_id { enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, + MT_RXQ_MCU_WA, __MT_RXQ_MAX }; @@ -581,6 +583,10 @@ enum mt76_phy_type { MT_PHY_TYPE_HT, MT_PHY_TYPE_HT_GF, MT_PHY_TYPE_VHT, + MT_PHY_TYPE_HE_SU = 8, + MT_PHY_TYPE_HE_EXT_SU, + MT_PHY_TYPE_HE_TB, + MT_PHY_TYPE_HE_MU, }; #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) -- cgit From e57b7901469fc0b021930b83a8094baaf3d81b09 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:27 +0800 Subject: mt76: add mac80211 driver for MT7915 PCIe-based chipsets Add support for the MediaTek latest generation IEEE 802.11ax 4x4 device MT7915E, which supports concurrent dual-band operation at both 5GHz and 2.4GHz. Note that this patch just add basic part and will add more HE capabilities support in the further patches. The driver supports AP, Station, Mesh and monitor mode. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Chih-Min Chen Suggested-by: Shihwei Lin Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Kconfig | 1 + drivers/net/wireless/mediatek/mt76/Makefile | 1 + drivers/net/wireless/mediatek/mt76/mt7915/Kconfig | 13 + drivers/net/wireless/mediatek/mt76/mt7915/Makefile | 6 + .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 245 +++ drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 285 +++ drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 125 ++ drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 78 + drivers/net/wireless/mediatek/mt76/mt7915/init.c | 395 ++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 1298 +++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 328 +++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 741 +++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2313 ++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 837 +++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 441 ++++ drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 166 ++ drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 343 +++ 17 files changed, 7616 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/Kconfig create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/Makefile create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/dma.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/init.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mac.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mac.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/main.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mcu.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/pci.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/regs.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index cbc2d8a5d354..41533a0e1720 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -24,3 +24,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig" +source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index a1dfafec431b..ef663b873b0b 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0/ obj-$(CONFIG_MT76x2_COMMON) += mt76x2/ obj-$(CONFIG_MT7603E) += mt7603/ obj-$(CONFIG_MT7615_COMMON) += mt7615/ +obj-$(CONFIG_MT7915E) += mt7915/ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig new file mode 100644 index 000000000000..d98225da694c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: ISC +config MT7915E + tristate "MediaTek MT7915E (PCIe) support" + select MT76_CORE + depends on MAC80211 + depends on PCI + help + This adds support for MT7915-based wireless PCIe devices, + which support concurrent dual-band operation at both 5GHz + and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels, + OFDMA, spatial reuse and dual carrier modulation. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile new file mode 100644 index 000000000000..57fe726cc38b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile @@ -0,0 +1,6 @@ +#SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7915E) += mt7915e.o + +mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \ + debugfs.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c new file mode 100644 index 000000000000..152ae0617f3d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "eeprom.h" + +/** global debugfs **/ + +/* test knob of system layer 1/2 error recovery */ +static int mt7915_ser_trigger_set(void *data, u64 val) +{ + enum { + SER_SET_RECOVER_L1 = 1, + SER_SET_RECOVER_L2, + SER_ENABLE = 2, + SER_RECOVER + }; + struct mt7915_dev *dev = data; + int ret = 0; + + switch (val) { + case SER_SET_RECOVER_L1: + case SER_SET_RECOVER_L2: + /* fall through */ + ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0); + if (ret) + return ret; + + return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0); + default: + break; + } + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL, + mt7915_ser_trigger_set, "%lld\n"); + +static int +mt7915_radar_trigger(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0); +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, + mt7915_radar_trigger, "%lld\n"); + +static int +mt7915_dbdc_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + + if (val) + mt7915_register_ext_phy(dev); + else + mt7915_unregister_ext_phy(dev); + + return 0; +} + +static int +mt7915_dbdc_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = !!mt7915_ext_phy(dev); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get, + mt7915_dbdc_set, "%lld\n"); + +static void +mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, + struct seq_file *file) +{ + struct mt7915_dev *dev = file->private; + bool ext_phy = phy != &dev->phy; + int bound[15], range[4], i, n; + + if (!phy) + return; + + /* Tx ampdu stat */ + for (i = 0; i < ARRAY_SIZE(range); i++) + range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i)); + + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1; + + seq_printf(file, "\nPhy %d\n", ext_phy); + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i] + 1, bound[i + 1]); + + seq_puts(file, "\nCount: "); + n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]); + seq_puts(file, "\n"); + + seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); +} + +static int +mt7915_tx_stats_read(struct seq_file *file, void *data) +{ + struct mt7915_dev *dev = file->private; + int stat[8], i, n; + + mt7915_ampdu_stat_read_phy(&dev->phy, file); + mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file); + + /* Tx amsdu info */ + seq_puts(file, "Tx MSDU stat:\n"); + for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { + stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); + n += stat[i]; + } + + for (i = 0; i < ARRAY_SIZE(stat); i++) { + seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ", + i + 1, stat[i]); + if (n != 0) + seq_printf(file, "(%d%%)\n", stat[i] * 100 / n); + else + seq_puts(file, "\n"); + } + + return 0; +} + +static int +mt7915_tx_stats_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7915_tx_stats_read, inode->i_private); +} + +static const struct file_operations fops_tx_stats = { + .open = mt7915_tx_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int mt7915_read_temperature(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + int temp; + + /* cpu */ + temp = mt7915_mcu_get_temperature(dev, 0); + seq_printf(s, "Temperature: %d\n", temp); + + return 0; +} + +static int +mt7915_queues_acq(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < 16; i++) { + int j, acs = i / 4, index = i % 4; + u32 ctrl, val, qlen = 0; + + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + ctrl = BIT(31) | BIT(15) | (acs << 8); + + for (j = 0; j < 32; j++) { + if (val & BIT(j)) + continue; + + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, + ctrl | (j + (index << 5))); + qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, + GENMASK(11, 0)); + } + seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + } + + return 0; +} + +static int +mt7915_queues_read(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + static const struct { + char *queue; + int id; + } queue_map[] = { + { "WFDMA0", MT_TXQ_BE }, + { "MCUWM", MT_TXQ_MCU }, + { "MCUWA", MT_TXQ_MCU_WA }, + { "MCUFWQ", MT_TXQ_FWDL }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) { + struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id]; + + if (!q->q) + continue; + + seq_printf(s, + "%s: queued=%d head=%d tail=%d\n", + queue_map[i].queue, q->q->queued, q->q->head, + q->q->tail); + } + + return 0; +} + +int mt7915_init_debugfs(struct mt7915_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs(&dev->mt76); + if (!dir) + return -ENOMEM; + + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt7915_queues_read); + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt7915_queues_acq); + debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); + debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); + debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + /* test knobs */ + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_trigger); + debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); + debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, + mt7915_read_temperature); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c new file mode 100644 index 000000000000..766185d1aa21 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "../dma.h" +#include "mac.h" + +static int +mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc) +{ + struct mt76_sw_queue *q; + struct mt76_queue *hwq; + int err, i; + + hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); + if (!hwq) + return -ENOMEM; + + err = mt76_queue_alloc(dev, hwq, MT7915_TXQ_BAND0, n_desc, 0, + MT_TX_RING_BASE); + if (err < 0) + return err; + + for (i = 0; i < MT_TXQ_MCU; i++) { + q = &dev->mt76.q_tx[i]; + INIT_LIST_HEAD(&q->swq); + q->q = hwq; + } + + return 0; +} + +static int +mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q, + int idx, int n_desc) +{ + struct mt76_queue *hwq; + int err; + + hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL); + if (!hwq) + return -ENOMEM; + + err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE); + if (err < 0) + return err; + + INIT_LIST_HEAD(&q->swq); + q->q = hwq; + + return 0; +} + +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7915_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7915_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_NORMAL: + if (!mt7915_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + /* fall through */ + default: + dev_kfree_skb(skb); + break; + } +} + +static int mt7915_poll_tx(struct napi_struct *napi, int budget) +{ + static const u8 queue_map[] = { + MT_TXQ_MCU, + MT_TXQ_MCU_WA, + MT_TXQ_BE + }; + struct mt7915_dev *dev; + int i; + + dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) + mt76_queue_tx_cleanup(dev, queue_map[i], false); + + if (napi_complete_done(napi, 0)) + mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL); + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) + mt76_queue_tx_cleanup(dev, queue_map[i], false); + + mt7915_mac_sta_poll(dev); + + tasklet_schedule(&dev->mt76.tx_tasklet); + + return 0; +} + +void mt7915_dma_prefetch(struct mt7915_dev *dev) +{ +#define PREFETCH(base, depth) ((base) << 16 | (depth)) + + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x40, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x80, 0x0)); + + mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL, PREFETCH(0x80, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL, PREFETCH(0xc0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL, PREFETCH(0x100, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL, PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL, PREFETCH(0x200, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL, PREFETCH(0x240, 0x4)); + + mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL, PREFETCH(0x280, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL, PREFETCH(0x2c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL, PREFETCH(0x300, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL, PREFETCH(0x340, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL, PREFETCH(0x380, 0x4)); + mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL, PREFETCH(0x3c0, 0x0)); + + mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL, PREFETCH(0x3c0, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL, PREFETCH(0x400, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL, PREFETCH(0x440, 0x4)); + mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0)); +} + +int mt7915_dma_init(struct mt7915_dev *dev) +{ + /* Increase buffer size to receive large VHT/HE MPDUs */ + int rx_buf_size = MT_RX_BUF_SIZE * 2; + int ret; + + mt76_dma_attach(&dev->mt76); + + /* configure global setting */ + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); + + /* configure perfetch settings */ + mt7915_dma_prefetch(dev); + + /* reset dma idx */ + mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); + mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0); + + /* configure delay interrupt */ + mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); + mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0); + + /* init tx queue */ + ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE); + if (ret) + return ret; + + /* command to WM */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU], + MT7915_TXQ_MCU_WM, + MT7915_TX_MCU_RING_SIZE); + if (ret) + return ret; + + /* command to WA */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA], + MT7915_TXQ_MCU_WA, + MT7915_TX_MCU_RING_SIZE); + if (ret) + return ret; + + /* firmware download */ + ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL], + MT7915_TXQ_FWDL, + MT7915_TX_FWDL_RING_SIZE); + if (ret) + return ret; + + /* event from WM */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], + MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE, + rx_buf_size, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* event from WA */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE, + rx_buf_size, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* rx data */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, + MT7915_RX_RING_SIZE, rx_buf_size, + MT_RX_DATA_RING_BASE); + if (ret) + return ret; + + ret = mt76_init_queues(dev); + if (ret < 0) + return ret; + + netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi, + mt7915_poll_tx, NAPI_POLL_WEIGHT); + napi_enable(&dev->mt76.tx_napi); + + /* hif wait WFDMA idle */ + mt76_set(dev, MT_WFDMA0_BUSY_ENA, + MT_WFDMA0_BUSY_ENA_TX_FIFO0 | + MT_WFDMA0_BUSY_ENA_TX_FIFO1 | + MT_WFDMA0_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA1_BUSY_ENA, + MT_WFDMA1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA1_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA0_PCIE1_BUSY_ENA, + MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO); + + mt76_set(dev, MT_WFDMA1_PCIE1_BUSY_ENA, + MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 | + MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 | + MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO); + + mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC, + MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000); + + /* set WFDMA Tx/Rx */ + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + + /* enable interrupts for TX/RX rings */ + mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); + + return 0; +} + +void mt7915_dma_cleanup(struct mt7915_dev *dev) +{ + /* disable */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_clear(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | + MT_WFDMA1_GLO_CFG_RX_DMA_EN); + + /* reset */ + mt76_clear(dev, MT_WFDMA1_RST, + MT_WFDMA1_RST_DMASHDL_ALL_RST | + MT_WFDMA1_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA1_RST, + MT_WFDMA1_RST_DMASHDL_ALL_RST | + MT_WFDMA1_RST_LOGIC_RST); + + mt76_clear(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + mt76_set(dev, MT_WFDMA0_RST, + MT_WFDMA0_RST_DMASHDL_ALL_RST | + MT_WFDMA0_RST_LOGIC_RST); + + tasklet_kill(&dev->mt76.tx_tasklet); + mt76_dma_cleanup(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c new file mode 100644 index 000000000000..2099dd40530f --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include "mt7915.h" +#include "eeprom.h" + +static inline bool mt7915_efuse_valid(u8 val) +{ + return !(val == 0xff); +} + +u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset) +{ + u8 *data = dev->mt76.eeprom.data; + + if (!mt7915_efuse_valid(data[offset])) + mt7915_mcu_get_eeprom(dev, offset); + + return data[offset]; +} + +static int mt7915_eeprom_load(struct mt7915_dev *dev) +{ + int ret; + + ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE); + if (ret < 0) + return ret; + + memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); + + return 0; +} + +static int mt7915_check_eeprom(struct mt7915_dev *dev) +{ + u16 val; + u8 *eeprom = dev->mt76.eeprom.data; + + mt7915_eeprom_read(dev, 0); + val = get_unaligned_le16(eeprom); + + switch (val) { + case 0x7915: + return 0; + default: + return -EINVAL; + } +} + +static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev) +{ + u8 *eeprom = dev->mt76.eeprom.data; + u8 tx_mask, max_nss = 4; + u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF); + + val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val); + switch (val) { + case MT_EE_5GHZ: + dev->mt76.cap.has_5ghz = true; + break; + case MT_EE_2GHZ: + dev->mt76.cap.has_2ghz = true; + break; + default: + dev->mt76.cap.has_2ghz = true; + dev->mt76.cap.has_5ghz = true; + break; + } + + /* read tx mask from eeprom */ + tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK, + eeprom[MT_EE_WIFI_CONF]); + if (!tx_mask || tx_mask > max_nss) + tx_mask = max_nss; + + dev->chainmask = BIT(tx_mask) - 1; + dev->mphy.antenna_mask = dev->chainmask; + dev->phy.chainmask = dev->chainmask; +} + +int mt7915_eeprom_init(struct mt7915_dev *dev) +{ + int ret; + + ret = mt7915_eeprom_load(dev); + if (ret < 0) + return ret; + + ret = mt7915_check_eeprom(dev); + if (ret) + return ret; + + mt7915_eeprom_parse_hw_cap(dev); + memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, + ETH_ALEN); + + mt76_eeprom_override(&dev->mt76); + + return 0; +} + +int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx) +{ + int index; + bool tssi_on; + + if (chain_idx > 3) + return -EINVAL; + + tssi_on = mt7915_tssi_enabled(dev, chan->band); + + if (chan->band == NL80211_BAND_2GHZ) { + index = MT_EE_TX0_POWER_2G + chain_idx * 3 + !tssi_on; + } else { + int group = tssi_on ? + mt7915_get_channel_group(chan->hw_value) : 8; + + index = MT_EE_TX0_POWER_5G + chain_idx * 12 + group; + } + + return mt7915_eeprom_read(dev, index); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h new file mode 100644 index 000000000000..30fc607e466d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_EEPROM_H +#define __MT7915_EEPROM_H + +#include "mt7915.h" + +struct cal_data { + u8 count; + u16 offset[60]; +}; + +enum mt7915_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + MT_EE_DDIE_FT_VERSION = 0x050, + MT_EE_WIFI_CONF = 0x190, + MT_EE_TX0_POWER_2G = 0x2fc, + MT_EE_TX0_POWER_5G = 0x34b, + MT_EE_ADIE_FT_VERSION = 0x9a0, + + __MT_EE_MAX = 0xe00 +}; + +#define MT_EE_WIFI_CONF_TX_MASK GENMASK(2, 0) +#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(7, 6) +#define MT_EE_WIFI_CONF_TSSI0_2G BIT(0) +#define MT_EE_WIFI_CONF_TSSI0_5G BIT(2) +#define MT_EE_WIFI_CONF_TSSI1_5G BIT(4) + +enum mt7915_eeprom_band { + MT_EE_DUAL_BAND, + MT_EE_5GHZ, + MT_EE_2GHZ, + MT_EE_DBDC, +}; + +struct sku_group { + u8 len; + u16 offset[2]; + const u8 *delta_map; +}; + +static inline int +mt7915_get_channel_group(int channel) +{ + if (channel >= 184 && channel <= 196) + return 0; + if (channel <= 48) + return 1; + if (channel <= 64) + return 2; + if (channel <= 96) + return 3; + if (channel <= 112) + return 4; + if (channel <= 128) + return 5; + if (channel <= 144) + return 6; + return 7; +} + +static inline bool +mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) +{ + u8 *eep = dev->mt76.eeprom.data; + + /* TODO: DBDC */ + if (band == NL80211_BAND_5GHZ) + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_5G; + else + return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G; +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c new file mode 100644 index 000000000000..fb596afdf0be --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include "mt7915.h" +#include "mac.h" +#include "eeprom.h" + +static void +mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) +{ + u32 mask, set; + + mt76_rmw_field(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); + mt76_set(dev, MT_TMAC_CTCR0(band), + MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | + MT_TMAC_CTCR0_INS_DDLMT_EN); + + mask = MT_MDP_RCFR0_MCU_RX_MGMT | + MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | + MT_MDP_RCFR0_MCU_RX_CTL_BAR; + set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); + + mask = MT_MDP_RCFR1_MCU_RX_BYPASS | + MT_MDP_RCFR1_RX_DROPPED_UCAST | + MT_MDP_RCFR1_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | + FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); + mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); +} + +static void mt7915_mac_init(struct mt7915_dev *dev) +{ + int i; + + mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536); + mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + /* disable hardware de-agg */ + mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); + + for (i = 0; i < MT7915_WTBL_SIZE; i++) + mt7915_mac_wtbl_update(dev, i, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7915_mac_init_band(dev, 0); + mt7915_mac_init_band(dev, 1); + mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b); +} + +static void +mt7915_init_txpower_band(struct mt7915_dev *dev, + struct ieee80211_supported_band *sband) +{ + int i, n_chains = hweight8(dev->mphy.antenna_mask); + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + u32 target_power = 0; + int j; + + for (j = 0; j < n_chains; j++) { + u32 val; + + val = mt7915_eeprom_get_target_power(dev, chan, j); + target_power = max(target_power, val); + } + + chan->max_power = min_t(int, chan->max_reg_power, + target_power / 2); + chan->orig_mpwr = target_power / 2; + } +} + +static void mt7915_init_txpower(struct mt7915_dev *dev) +{ + mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband); + mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband); +} + +static void mt7915_init_work(struct work_struct *work) +{ + struct mt7915_dev *dev = container_of(work, struct mt7915_dev, + init_work); + + mt7915_mcu_set_eeprom(dev); + mt7915_mac_init(dev); + mt7915_init_txpower(dev); +} + +static int mt7915_init_hardware(struct mt7915_dev *dev) +{ + int ret, idx; + + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + + INIT_WORK(&dev->init_work, mt7915_init_work); + spin_lock_init(&dev->token_lock); + idr_init(&dev->token); + + ret = mt7915_dma_init(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + ret = mt7915_mcu_init(dev); + if (ret) + return ret; + + ret = mt7915_eeprom_init(dev); + if (ret < 0) + return ret; + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +static struct ieee80211_rate mt7915_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; + +static const struct ieee80211_iface_limit if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = MT7915_MAX_INTERFACES, + .types = BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_STATION) + } +}; + +static const struct ieee80211_iface_combination if_comb[] = { + { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = 4, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160) | + BIT(NL80211_CHAN_WIDTH_80P80), + } +}; + +static void +mt7915_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + struct mt7915_phy *phy = mphy->priv; + struct cfg80211_chan_def *chandef = &mphy->chandef; + + dev->mt76.region = request->dfs_region; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + mt7915_dfs_init_radar_detector(phy); +} + +static void +mt7915_init_wiphy(struct ieee80211_hw *hw) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct wiphy *wiphy = hw->wiphy; + + hw->queues = 4; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + + phy->slottime = 9; + + hw->sta_data_size = sizeof(struct mt7915_sta); + hw->vif_data_size = sizeof(struct mt7915_vif); + + wiphy->iface_combinations = if_comb; + wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + wiphy->reg_notifier = mt7915_regd_notifier; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + + hw->max_tx_fragments = 4; +} + +static void +mt7915_cap_dbdc_enable(struct mt7915_dev *dev) +{ + dev->mphy.sband_5g.sband.vht_cap.cap &= + ~(IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); + + if (dev->chainmask == 0xf) + dev->mphy.antenna_mask = dev->chainmask >> 2; + else + dev->mphy.antenna_mask = dev->chainmask >> 1; + + dev->phy.chainmask = dev->mphy.antenna_mask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; + + mt76_set_stream_caps(&dev->mt76, true); +} + +static void +mt7915_cap_dbdc_disable(struct mt7915_dev *dev) +{ + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + + dev->mphy.antenna_mask = dev->chainmask; + dev->phy.chainmask = dev->chainmask; + dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; + dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; + + mt76_set_stream_caps(&dev->mt76, true); +} + +int mt7915_register_ext_phy(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy = mt7915_ext_phy(dev); + struct mt76_phy *mphy; + int ret; + bool bound; + + /* TODO: enble DBDC */ + bound = mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5); + if (!bound) + return -EINVAL; + + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return -EINVAL; + + if (phy) + return 0; + + mt7915_cap_dbdc_enable(dev); + mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops); + if (!mphy) + return -ENOMEM; + + phy = mphy->priv; + phy->dev = dev; + phy->mt76 = mphy; + phy->chainmask = dev->chainmask & ~dev->phy.chainmask; + mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1; + mt7915_init_wiphy(mphy->hw); + + /* + * Make the secondary PHY MAC address local without overlapping with + * the usual MAC address allocation scheme on multiple virtual interfaces + */ + mphy->hw->wiphy->perm_addr[0] |= 2; + mphy->hw->wiphy->perm_addr[0] ^= BIT(7); + + /* The second interface does not get any packets unless it has a vif */ + ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF); + + ret = mt76_register_phy(mphy); + if (ret) + ieee80211_free_hw(mphy->hw); + + return ret; +} + +void mt7915_unregister_ext_phy(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy = mt7915_ext_phy(dev); + struct mt76_phy *mphy = dev->mt76.phy2; + + if (!phy) + return; + + mt7915_cap_dbdc_disable(dev); + mt76_unregister_phy(mphy); + ieee80211_free_hw(mphy->hw); +} + +int mt7915_register_device(struct mt7915_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int ret; + + dev->phy.dev = dev; + dev->phy.mt76 = &dev->mt76.phy; + dev->mt76.phy.priv = &dev->phy; + INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7915_mac_work); + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); + + init_waitqueue_head(&dev->reset_wait); + INIT_WORK(&dev->reset_work, mt7915_mac_reset_work); + + ret = mt7915_init_hardware(dev); + if (ret) + return ret; + + mt7915_init_wiphy(hw); + dev->mphy.sband_2g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + mt7915_cap_dbdc_disable(dev); + dev->phy.dfs_state = -1; + + ret = mt76_register_device(&dev->mt76, true, mt7915_rates, + ARRAY_SIZE(mt7915_rates)); + if (ret) + return ret; + + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + + return mt7915_init_debugfs(dev); +} + +void mt7915_unregister_device(struct mt7915_dev *dev) +{ + struct mt76_txwi_cache *txwi; + int id; + + mt7915_unregister_ext_phy(dev); + mt76_unregister_device(&dev->mt76); + mt7915_mcu_exit(dev); + mt7915_dma_cleanup(dev); + + spin_lock_bh(&dev->token_lock); + idr_for_each_entry(&dev->token, txwi, id) { + mt7915_txp_skb_unmap(&dev->mt76, txwi); + if (txwi->skb) + dev_kfree_skb_any(txwi->skb); + mt76_put_txwi(&dev->mt76, txwi); + } + spin_unlock_bh(&dev->token_lock); + idr_destroy(&dev->token); + + mt76_free_device(&dev->mt76); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c new file mode 100644 index 000000000000..ddba360046c3 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -0,0 +1,1298 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include "mt7915.h" +#include "../dma.h" +#include "mac.h" + +#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) + +static const struct mt7915_dfs_radar_spec etsi_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, + [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, + [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, + [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, + [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, + [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, + [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, + [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, + }, +}; + +static const struct mt7915_dfs_radar_spec fcc_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, + [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, + [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, + [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, + [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, + }, +}; + +static const struct mt7915_dfs_radar_spec jp_radar_specs = { + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, + .radar_pattern = { + [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, + [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, + [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, + [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, + [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, + [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, + [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, + [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, + }, +}; + +static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev, + u16 idx, bool unicast) +{ + struct mt7915_sta *sta; + struct mt76_wcid *wcid; + + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + return NULL; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (unicast || !wcid) + return wcid; + + if (!wcid->sta) + return NULL; + + sta = container_of(wcid, struct mt7915_sta, wcid); + if (!sta->vif) + return NULL; + + return &sta->vif->sta.wcid; +} + +void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) +{ +} + +bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + +static u32 mt7915_mac_wtbl_lmac_read(struct mt7915_dev *dev, u16 wcid, + u16 addr) +{ + mt76_wr(dev, MT_WTBLON_TOP_WDUCR, + FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); + + return mt76_rr(dev, MT_WTBL_LMAC_OFFS(wcid, addr)); +} + +/* TODO: use txfree airtime info to avoid runtime accessing in the long run */ +void mt7915_mac_sta_poll(struct mt7915_dev *dev) +{ + static const u8 ac_to_tid[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + static const u8 hw_queue_map[] = { + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + struct ieee80211_sta *sta; + struct mt7915_sta *msta; + u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; + int i; + + rcu_read_lock(); + + while (true) { + bool clear = false; + u16 idx; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + msta = list_first_entry(&dev->sta_poll_list, + struct mt7915_sta, poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + for (i = 0, idx = msta->wcid.idx; i < IEEE80211_NUM_ACS; i++) { + u32 tx_last = msta->airtime_ac[i]; + u32 rx_last = msta->airtime_ac[i + IEEE80211_NUM_ACS]; + + msta->airtime_ac[i] = + mt7915_mac_wtbl_lmac_read(dev, idx, 20 + i); + msta->airtime_ac[i + IEEE80211_NUM_ACS] = + mt7915_mac_wtbl_lmac_read(dev, idx, 21 + i); + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i + IEEE80211_NUM_ACS] - + rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + } + + if (clear) { + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u32 tx_cur = tx_time[i]; + u32 rx_cur = rx_time[hw_queue_map[i]]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + ieee80211_sta_register_airtime(sta, tid, tx_cur, + rx_cur); + } + } + + rcu_read_unlock(); +} + +int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_phy *phy = &dev->phy; + struct ieee80211_supported_band *sband; + struct ieee80211_hdr *hdr; + struct mt7915_rxv rxv = {}; + __le32 *rxd = (__le32 *)skb->data; + u32 rxd1 = le32_to_cpu(rxd[1]); + u32 rxd2 = le32_to_cpu(rxd[2]); + u32 rxd3 = le32_to_cpu(rxd[3]); + bool unicast, insert_ccmp_hdr = false; + u8 remove_pad; + int i, idx; + + memset(status, 0, sizeof(*status)); + + if (rxd1 & MT_RXD1_NORMAL_BAND_IDX) { + mphy = dev->mt76.phy2; + if (!mphy) + return -EINVAL; + + phy = mphy->priv; + status->ext_phy = true; + } + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return -EINVAL; + + unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; + idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + status->wcid = mt7915_rx_get_wcid(dev, idx, unicast); + + if (status->wcid) { + struct mt7915_sta *msta; + + msta = container_of(status->wcid, struct mt7915_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + + status->freq = mphy->chandef.chan->center_freq; + status->band = mphy->chandef.chan->band; + if (status->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + if (!sband->channels) + return -EINVAL; + + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && + !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED; + status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; + } + + if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (phy->rx_ampdu_ts != rxd[14]) { + if (!++phy->ampdu_ref) + phy->ampdu_ref++; + } + phy->rx_ampdu_ts = rxd[14]; + + status->ampdu_ref = phy->ampdu_ref; + } + + remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); + + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) + return -EINVAL; + + rxd += 6; + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { + u8 *data = (u8 *)rxd; + + if (status->flag & RX_FLAG_DECRYPTED) { + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + + insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + } + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + /* RXD Group 3 - P-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { + memcpy(rxv.v, rxd, sizeof(rxv.v)); + + rxd += 2; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + if (rxv.v[0] & MT_PRXV_HT_AD_CODE) + status->enc_flags |= RX_ENC_FLAG_LDPC; + + status->chains = mphy->antenna_mask; + status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, rxv.v[1]); + status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, rxv.v[1]); + status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, rxv.v[1]); + status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, rxv.v[1]); + status->signal = status->chain_signal[0]; + + for (i = 1; i < hweight8(mphy->antenna_mask); i++) { + if (!(status->chains & BIT(i))) + continue; + + status->signal = max(status->signal, + status->chain_signal[i]); + } + + /* RXD Group 5 - C-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { + u8 stbc = FIELD_GET(MT_CRXV_HT_STBC, rxv.v[2]); + u8 gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, rxv.v[2]); + bool cck = false; + + rxd += 18; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + idx = i = FIELD_GET(MT_PRXV_TX_RATE, rxv.v[0]); + rxv.phy = FIELD_GET(MT_CRXV_TX_MODE, rxv.v[2]); + + switch (rxv.phy) { + case MT_PHY_TYPE_CCK: + cck = true; + /* fall through */ + case MT_PHY_TYPE_OFDM: + i = mt76_get_rate(&dev->mt76, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + if (i > 31) + return -EINVAL; + break; + case MT_PHY_TYPE_VHT: + status->nss = + FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; + status->encoding = RX_ENC_VHT; + if (i > 9) + return -EINVAL; + break; + default: + return -EINVAL; + } + status->rate_idx = i; + + switch (FIELD_GET(MT_CRXV_FRAME_MODE, rxv.v[2])) { + case IEEE80211_STA_RX_BW_20: + break; + case IEEE80211_STA_RX_BW_40: + status->bw = RATE_INFO_BW_40; + break; + case IEEE80211_STA_RX_BW_80: + status->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; + default: + return -EINVAL; + } + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + } + } + + skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); + + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + + mt76_insert_ccmp_hdr(skb, key_id); + } + + hdr = mt76_skb_get_hdr(skb); + if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) + return 0; + + status->aggr = unicast && + !ieee80211_is_qos_nullfunc(hdr->frame_control); + status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + return 0; +} + +void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool multicast = is_multicast_ether_addr(hdr->addr1); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_phy *mphy = &dev->mphy; + bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; + u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; + __le16 fc = hdr->frame_control; + u16 tx_count = 4, seqno = 0; + u32 val; + + if (vif) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + } + + if (ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; + fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + + if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { + q_idx = wmm_idx * MT7915_MAX_WMM_SETS + + skb_get_queue_mapping(skb); + p_fmt = MT_TX_TYPE_CT; + } else if (beacon) { + q_idx = MT_LMAC_BCN0; + p_fmt = MT_TX_TYPE_FW; + } else { + q_idx = MT_LMAC_ALTX0; + p_fmt = MT_TX_TYPE_CT; + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, q_idx); + txwi[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, + ieee80211_get_hdrlen_from_skb(skb) / 2) | + FIELD_PREP(MT_TXD1_TID, + skb->priority & IEEE80211_QOS_CTL_TID_MASK) | + FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) + val |= cpu_to_le32(MT_TXD1_TGID); + + txwi[1] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | + FIELD_PREP(MT_TXD2_MULTICAST, multicast); + if (key) { + if (multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txwi[3] = 0; + } else { + txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + } else { + txwi[3] = 0; + } + txwi[2] = cpu_to_le32(val); + + txwi[4] = 0; + txwi[5] = 0; + txwi[6] = 0; + + if (!ieee80211_is_data(fc) || multicast) { + u16 rate; + + /* hardware won't add HTC for mgmt/ctrl frame */ + txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE | MT_TXD2_HTC_VLD); + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + rate = MT7915_5G_RATE_DEFAULT; + else + rate = MT7915_2G_RATE_DEFAULT; + + val = MT_TXD6_FIXED_BW | + FIELD_PREP(MT_TXD6_TX_RATE, rate); + txwi[6] |= cpu_to_le32(val); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + } + + if (!ieee80211_is_beacon(fc)) + txwi[3] |= cpu_to_le32(MT_TXD3_SW_POWER_MGMT); + else + tx_count = 0x1f; + + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); + + val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | + FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); + txwi[7] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); + if (ieee80211_is_data_qos(fc)) { + seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + val |= MT_TXD3_SN_VALID; + } else if (ieee80211_is_back_req(fc)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); + val |= MT_TXD3_SN_VALID; + } + val |= FIELD_PREP(MT_TXD3_SEQ, seqno); + txwi[3] |= cpu_to_le32(val); +} + +int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct ieee80211_vif *vif = info->control.vif; + struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); + struct mt76_txwi_cache *t; + struct mt7915_txp *txp; + int id, i, nbuf = tx_info->nbuf - 1; + u8 *txwi = (u8 *)txwi_ptr; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + cb->wcid = wcid->idx; + + mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + false); + + txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); + for (i = 0; i < nbuf; i++) { + txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); + txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + } + txp->nbuf = nbuf; + + /* pass partial skb header to fw */ + tx_info->buf[1].len = MT_CT_PARSE_LEN; + tx_info->nbuf = MT_CT_DMA_BUF_NUM; + + txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); + + if (!key) + txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); + + if (ieee80211_is_mgmt(hdr->frame_control)) + txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); + + if (vif) { + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + txp->bss_idx = mvif->idx; + } + + t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); + t->skb = tx_info->skb; + + spin_lock_bh(&dev->token_lock); + id = idr_alloc(&dev->token, t, 0, MT7915_TOKEN_SIZE, GFP_ATOMIC); + spin_unlock_bh(&dev->token_lock); + if (id < 0) + return id; + + txp->token = cpu_to_le16(id); + txp->rept_wds_wcid = 0xff; + tx_info->skb = DMA_DUMMY_DATA; + + return 0; +} + +static inline bool +mt7915_tx_check_aggr_tid(struct mt7915_sta *msta, u8 tid) +{ + bool ret = false; + + spin_lock_bh(&msta->ampdu_lock); + if (msta->ampdu_state[tid] == MT7915_AGGR_STOP) + ret = true; + spin_unlock_bh(&msta->ampdu_lock); + + return ret; +} + +static void +mt7915_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct mt7915_sta *msta; + u16 tid; + + if (!sta->ht_cap.ht_supported) + return; + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) + return; + + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return; + + msta = (struct mt7915_sta *)sta->drv_priv; + tid = ieee80211_get_tid(hdr); + + if (mt7915_tx_check_aggr_tid(msta, tid)) { + ieee80211_start_tx_ba_session(sta, tid, 0); + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_PROGRESS); + } +} + +static inline void +mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw, + struct ieee80211_tx_info *info, struct sk_buff *skb) +{ + struct ieee80211_tx_status status = { + .sta = sta, + .info = info, + }; + + if (skb) + status.skb = skb; + + if (sta) { + struct mt7915_sta *msta; + + msta = (struct mt7915_sta *)sta->drv_priv; + status.rate = &msta->stats.tx_rate; + } + + /* use status_ext to report HE rate */ + ieee80211_tx_status_ext(hw, &status); +} + +static void +mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, + struct ieee80211_sta *sta, u8 stat) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hw *hw; + + hw = mt76_tx_status_get_hw(mdev, skb); + + if (info->flags & IEEE80211_TX_CTL_AMPDU) + info->flags |= IEEE80211_TX_STAT_AMPDU; + else if (sta) + mt7915_tx_check_aggr(sta, skb); + + if (stat) + ieee80211_tx_info_clear_status(info); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.tx_time = 0; + + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { + mt7915_tx_status(sta, hw, info, skb); + return; + } + + if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK)) + mt7915_tx_status(sta, hw, info, NULL); + + dev_kfree_skb(skb); +} + +void mt7915_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *t) +{ + struct mt7915_txp *txp; + int i; + + txp = mt7915_txwi_to_txp(dev, t); + for (i = 1; i < txp->nbuf; i++) + dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]), + le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); +} + +void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + struct ieee80211_sta *sta = NULL; + u8 i, count; + + /* + * TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE, + * to the time ack is received or dropped by hw (air + hw queue time). + * Should avoid accessing WTBL to get Tx airtime, and use it instead. + */ + count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl)); + for (i = 0; i < count; i++) { + u32 msdu, info = le32_to_cpu(free->info[i]); + u8 stat; + + /* + * 1'b1: new wcid pair. + * 1'b0: msdu_id with the same 'wcid pair' as above. + */ + if (info & MT_TX_FREE_PAIR) { + struct mt7915_sta *msta; + struct mt76_wcid *wcid; + u16 idx; + + count++; + idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info); + wcid = rcu_dereference(dev->mt76.wcid[idx]); + sta = wcid_to_sta(wcid); + if (!sta) + continue; + + msta = container_of(wcid, struct mt7915_sta, wcid); + ieee80211_queue_work(mt76_hw(dev), &msta->stats_work); + continue; + } + + msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); + stat = FIELD_GET(MT_TX_FREE_STATUS, info); + + spin_lock_bh(&dev->token_lock); + txwi = idr_remove(&dev->token, msdu); + spin_unlock_bh(&dev->token_lock); + + if (!txwi) + continue; + + mt7915_txp_skb_unmap(mdev, txwi); + if (txwi->skb) { + mt7915_tx_complete_status(mdev, txwi->skb, sta, stat); + txwi->skb = NULL; + } + + mt76_put_txwi(mdev, txwi); + } + dev_kfree_skb(skb); +} + +void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + struct mt7915_dev *dev; + + if (!e->txwi) { + dev_kfree_skb_any(e->skb); + return; + } + + dev = container_of(mdev, struct mt7915_dev, mt76); + + /* error path */ + if (e->skb == DMA_DUMMY_DATA) { + struct mt76_txwi_cache *t; + struct mt7915_txp *txp; + + txp = mt7915_txwi_to_txp(mdev, e->txwi); + + spin_lock_bh(&dev->token_lock); + t = idr_remove(&dev->token, le16_to_cpu(txp->token)); + spin_unlock_bh(&dev->token_lock); + e->skb = t ? t->skb : NULL; + } + + if (e->skb) { + struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); + + mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0); + } +} + +void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + u32 reg = MT_WF_PHY_RX_CTRL1(ext_phy); + + mt7915_l2_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN); + mt7915_l2_set(dev, reg, BIT(11) | BIT(9)); +} + +void mt7915_mac_reset_counters(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int i; + + for (i = 0; i < 4; i++) { + mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); + mt76_rr(dev, MT_TX_AGG_CNT2(ext_phy, i)); + } + + if (ext_phy) { + dev->mt76.phy2->survey_time = ktime_get_boottime(); + i = ARRAY_SIZE(dev->mt76.aggr_stats) / 2; + } else { + dev->mt76.phy.survey_time = ktime_get_boottime(); + i = 0; + } + memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2); + + /* reset airtime counters */ + mt76_rr(dev, MT_MIB_SDR9(ext_phy)); + mt76_rr(dev, MT_MIB_SDR36(ext_phy)); + mt76_rr(dev, MT_MIB_SDR37(ext_phy)); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(ext_phy), + MT_WF_RMAC_MIB_RXTIME_CLR); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(ext_phy), + MT_WF_RMAC_MIB_RXTIME_CLR); +} + +void mt7915_mac_set_timing(struct mt7915_phy *phy) +{ + s16 coverage_class = phy->coverage_class; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + u32 val, reg_offset; + u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); + u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); + int sifs, offset; + bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ; + + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + + if (is_5ghz) + sifs = 16; + else + sifs = 10; + + if (ext_phy) { + coverage_class = max_t(s16, dev->phy.coverage_class, + coverage_class); + } else { + struct mt7915_phy *phy_ext = mt7915_ext_phy(dev); + + if (phy_ext) + coverage_class = max_t(s16, phy_ext->coverage_class, + coverage_class); + } + mt76_set(dev, MT_ARB_SCR(ext_phy), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); + udelay(1); + + offset = 3 * coverage_class; + reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | + FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); + + mt76_wr(dev, MT_TMAC_CDTR(ext_phy), cck + reg_offset); + mt76_wr(dev, MT_TMAC_ODTR(ext_phy), ofdm + reg_offset); + mt76_wr(dev, MT_TMAC_ICR0(ext_phy), + FIELD_PREP(MT_IFS_EIFS, 360) | + FIELD_PREP(MT_IFS_RIFS, 2) | + FIELD_PREP(MT_IFS_SIFS, sifs) | + FIELD_PREP(MT_IFS_SLOT, phy->slottime)); + + if (phy->slottime < 20 || is_5ghz) + val = MT7915_CFEND_RATE_DEFAULT; + else + val = MT7915_CFEND_RATE_11B; + + mt76_rmw_field(dev, MT_AGG_ACR0(ext_phy), MT_AGG_ACR_CFEND_RATE, val); + mt76_clear(dev, MT_ARB_SCR(ext_phy), + MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); +} + +/* + * TODO: mib counters are read-clear and there're many HE functionalities need + * such info, hence firmware prepares a task to read the fields out to a shared + * structure. User should switch to use event format to avoid race condition. + */ +static void +mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) +{ + struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76); + struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; + + busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), + MT_MIB_SDR9_BUSY_MASK); + tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), + MT_MIB_SDR36_TXTIME_MASK); + rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), + MT_MIB_SDR37_RXTIME_MASK); + obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), + MT_MIB_OBSSTIME_MASK); + + /* TODO: state->noise */ + state = mphy->chan_state; + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; +} + +void mt7915_update_channel(struct mt76_dev *mdev) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_phy_update_channel(&mdev->phy, 0); + if (mdev->phy2) + mt7915_phy_update_channel(mdev->phy2, 1); + + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); + if (mdev->phy2) + mt76_set(dev, MT_WF_RMAC_MIB_TIME0(1), + MT_WF_RMAC_MIB_RXTIME_CLR); +} + +static bool +mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) +{ + bool ret; + + ret = wait_event_timeout(dev->reset_wait, + (READ_ONCE(dev->reset_state) & state), + MT7915_RESET_TIMEOUT); + + WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); + return ret; +} + +static void +mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct ieee80211_hw *hw = priv; + + mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); +} + +static void +mt7915_update_beacons(struct mt7915_dev *dev) +{ + ieee80211_iterate_active_interfaces(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_update_vif_beacon, dev->mt76.hw); + + if (!dev->mt76.phy2) + return; + + ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_update_vif_beacon, dev->mt76.phy2->hw); +} + +static void +mt7915_dma_reset(struct mt7915_dev *dev) +{ + int i; + + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_clear(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + usleep_range(1000, 2000); + + for (i = 0; i < __MT_TXQ_MAX; i++) + mt76_queue_tx_cleanup(dev, i, true); + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++) + mt76_queue_rx_reset(dev, i); + + /* re-init prefetch settings after reset */ + mt7915_dma_prefetch(dev); + + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_set(dev, MT_WFDMA1_GLO_CFG, + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); +} + +/* system error recovery */ +void mt7915_mac_reset_work(struct work_struct *work) +{ + struct mt7915_dev *dev; + + dev = container_of(work, struct mt7915_dev, reset_work); + + if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) + return; + + ieee80211_stop_queues(mt76_hw(dev)); + if (dev->mt76.phy2) + ieee80211_stop_queues(dev->mt76.phy2->hw); + + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + cancel_delayed_work_sync(&dev->mt76.mac_work); + + /* lock/unlock all queues to ensure that no tx is pending */ + mt76_txq_schedule_all(&dev->mphy); + if (dev->mt76.phy2) + mt76_txq_schedule_all(dev->mt76.phy2); + + tasklet_disable(&dev->mt76.tx_tasklet); + napi_disable(&dev->mt76.napi[0]); + napi_disable(&dev->mt76.napi[1]); + napi_disable(&dev->mt76.napi[2]); + napi_disable(&dev->mt76.tx_napi); + + mutex_lock(&dev->mt76.mutex); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); + + if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { + mt7915_dma_reset(dev); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); + mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); + } + + clear_bit(MT76_MCU_RESET, &dev->mphy.state); + clear_bit(MT76_RESET, &dev->mphy.state); + + tasklet_enable(&dev->mt76.tx_tasklet); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + + napi_enable(&dev->mt76.napi[0]); + napi_schedule(&dev->mt76.napi[0]); + + napi_enable(&dev->mt76.napi[1]); + napi_schedule(&dev->mt76.napi[1]); + + napi_enable(&dev->mt76.napi[2]); + napi_schedule(&dev->mt76.napi[2]); + + ieee80211_wake_queues(mt76_hw(dev)); + if (dev->mt76.phy2) + ieee80211_wake_queues(dev->mt76.phy2->hw); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); + mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); + + mutex_unlock(&dev->mt76.mutex); + + mt7915_update_beacons(dev); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +} + +static void +mt7915_mac_update_mib_stats(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mib_stats *mib = &phy->mib; + bool ext_phy = phy != &dev->phy; + int i, aggr0, aggr1; + + memset(mib, 0, sizeof(*mib)); + + mib->fcs_err_cnt = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), + MT_MIB_SDR3_FCS_ERR_MASK); + + aggr0 = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; + for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { + u32 val, val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i)); + + val2 = FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); + if (val2 > mib->ack_fail_cnt) + mib->ack_fail_cnt = val2; + + val2 = FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); + if (val2 > mib->ba_miss_cnt) + mib->ba_miss_cnt = val2; + + val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); + val2 = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); + if (val2 > mib->rts_retries_cnt) { + mib->rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); + mib->rts_retries_cnt = val2; + } + + val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); + val2 = mt76_rr(dev, MT_TX_AGG_CNT2(ext_phy, i)); + + dev->mt76.aggr_stats[aggr0++] += val & 0xffff; + dev->mt76.aggr_stats[aggr0++] += val >> 16; + dev->mt76.aggr_stats[aggr1++] += val2 & 0xffff; + dev->mt76.aggr_stats[aggr1++] += val2 >> 16; + } +} + +void mt7915_mac_sta_stats_work(struct work_struct *work) +{ + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + struct mt7915_sta_stats *stats; + struct mt7915_sta *msta; + struct mt7915_dev *dev; + + msta = container_of(work, struct mt7915_sta, stats_work); + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + dev = msta->vif->dev; + stats = &msta->stats; + + /* use MT_TX_FREE_RATE to report Tx rate for further devices */ + if (time_after(jiffies, stats->jiffies + HZ)) { + mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, + msta->wcid.idx); + + stats->jiffies = jiffies; + } + + if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED | + IEEE80211_RC_NSS_CHANGED | + IEEE80211_RC_BW_CHANGED, &stats->changed)) + mt7915_mcu_add_rate_ctrl(dev, vif, sta); + + if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed)) + mt7915_mcu_add_smps(dev, vif, sta); + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +void mt7915_mac_work(struct work_struct *work) +{ + struct mt7915_dev *dev; + + dev = (struct mt7915_dev *)container_of(work, struct mt76_dev, + mac_work.work); + + mutex_lock(&dev->mt76.mutex); + mt76_update_survey(&dev->mt76); + if (++dev->mac_work_count == 5) { + struct mt7915_phy *ext_phy = mt7915_ext_phy(dev); + + mt7915_mac_update_mib_stats(&dev->phy); + if (ext_phy) + mt7915_mac_update_mib_stats(ext_phy); + + dev->mac_work_count = 0; + } + mutex_unlock(&dev->mt76.mutex); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +} + +static void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + + if (phy->rdd_state & BIT(0)) + mt7915_mcu_rdd_cmd(dev, RDD_STOP, 0, MT_RX_SEL0, 0); + if (phy->rdd_state & BIT(1)) + mt7915_mcu_rdd_cmd(dev, RDD_STOP, 1, MT_RX_SEL0, 0); +} + +static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) +{ + int err; + + err = mt7915_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0); + if (err < 0) + return err; + + return mt7915_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, MT_RX_SEL0, 1); +} + +static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int err; + + /* start CAC */ + err = mt7915_mcu_rdd_cmd(dev, RDD_CAC_START, ext_phy, MT_RX_SEL0, 0); + if (err < 0) + return err; + + err = mt7915_dfs_start_rdd(dev, ext_phy); + if (err < 0) + return err; + + phy->rdd_state |= BIT(ext_phy); + + if (chandef->width == NL80211_CHAN_WIDTH_160 || + chandef->width == NL80211_CHAN_WIDTH_80P80) { + err = mt7915_dfs_start_rdd(dev, 1); + if (err < 0) + return err; + + phy->rdd_state |= BIT(1); + } + + return 0; +} + +static int +mt7915_dfs_init_radar_specs(struct mt7915_phy *phy) +{ + const struct mt7915_dfs_radar_spec *radar_specs; + struct mt7915_dev *dev = phy->dev; + int err, i; + + switch (dev->mt76.region) { + case NL80211_DFS_FCC: + radar_specs = &fcc_radar_specs; + err = mt7915_mcu_set_fcc5_lpn(dev, 8); + if (err < 0) + return err; + break; + case NL80211_DFS_ETSI: + radar_specs = &etsi_radar_specs; + break; + case NL80211_DFS_JP: + radar_specs = &jp_radar_specs; + break; + default: + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { + err = mt7915_mcu_set_radar_th(dev, i, + &radar_specs->radar_pattern[i]); + if (err < 0) + return err; + } + + return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th); +} + +int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + int err; + + if (dev->mt76.region == NL80211_DFS_UNSET) { + phy->dfs_state = -1; + if (phy->rdd_state) + goto stop; + + return 0; + } + + if (test_bit(MT76_SCANNING, &phy->mt76->state)) + return 0; + + if (phy->dfs_state == chandef->chan->dfs_state) + return 0; + + err = mt7915_dfs_init_radar_specs(phy); + if (err < 0) { + phy->dfs_state = -1; + goto stop; + } + + phy->dfs_state = chandef->chan->dfs_state; + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) { + if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + return mt7915_dfs_start_radar_detector(phy); + + return mt7915_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy, + MT_RX_SEL0, 0); + } + +stop: + err = mt7915_mcu_rdd_cmd(dev, RDD_NORMAL_START, ext_phy, + MT_RX_SEL0, 0); + if (err < 0) + return err; + + mt7915_dfs_stop_radar_detector(phy); + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h new file mode 100644 index 000000000000..7da7551f98e4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_MAC_H +#define __MT7915_MAC_H + +#define MT_CT_PARSE_LEN 72 +#define MT_CT_DMA_BUF_NUM 2 + +#define MT_RXD0_LENGTH GENMASK(15, 0) +#define MT_RXD0_PKT_TYPE GENMASK(31, 27) + +#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) +#define MT_RXD0_NORMAL_IP_SUM BIT(23) +#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) + +enum rx_pkt_type { + PKT_TYPE_TXS, + PKT_TYPE_TXRXV, + PKT_TYPE_NORMAL, + PKT_TYPE_RX_DUP_RFB, + PKT_TYPE_RX_TMR, + PKT_TYPE_RETRIEVE, + PKT_TYPE_TXRX_NOTIFY, + PKT_TYPE_RX_EVENT, +}; + +/* RXD DW1 */ +#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) +#define MT_RXD1_NORMAL_GROUP_1 BIT(11) +#define MT_RXD1_NORMAL_GROUP_2 BIT(12) +#define MT_RXD1_NORMAL_GROUP_3 BIT(13) +#define MT_RXD1_NORMAL_GROUP_4 BIT(14) +#define MT_RXD1_NORMAL_GROUP_5 BIT(15) +#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) +#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) +#define MT_RXD1_NORMAL_CM BIT(23) +#define MT_RXD1_NORMAL_CLM BIT(24) +#define MT_RXD1_NORMAL_ICV_ERR BIT(25) +#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) +#define MT_RXD1_NORMAL_FCS_ERR BIT(27) +#define MT_RXD1_NORMAL_BAND_IDX BIT(28) +#define MT_RXD1_NORMAL_SPP_EN BIT(29) +#define MT_RXD1_NORMAL_ADD_OM BIT(30) +#define MT_RXD1_NORMAL_SEC_DONE BIT(31) + +/* RXD DW2 */ +#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) +#define MT_RXD2_NORMAL_CO_ANT BIT(6) +#define MT_RXD2_NORMAL_BF_CQI BIT(7) +#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) +#define MT_RXD2_NORMAL_HDR_TRANS BIT(13) +#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) +#define MT_RXD2_NORMAL_TID GENMASK(19, 16) +#define MT_RXD2_NORMAL_MU_BAR BIT(21) +#define MT_RXD2_NORMAL_SW_BIT BIT(22) +#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) +#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) +#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) +#define MT_RXD2_NORMAL_INT_FRAME BIT(26) +#define MT_RXD2_NORMAL_FRAG BIT(27) +#define MT_RXD2_NORMAL_NULL_FRAME BIT(28) +#define MT_RXD2_NORMAL_NDATA BIT(29) +#define MT_RXD2_NORMAL_NON_AMPDU BIT(30) +#define MT_RXD2_NORMAL_BF_REPORT BIT(31) + +/* RXD DW3 */ +#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) +#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) +#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) +#define MT_RXD3_NORMAL_U2M BIT(0) +#define MT_RXD3_NORMAL_HTC_VLD BIT(0) +#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) +#define MT_RXD3_NORMAL_BEACON_MC BIT(20) +#define MT_RXD3_NORMAL_BEACON_UC BIT(21) +#define MT_RXD3_NORMAL_AMSDU BIT(22) +#define MT_RXD3_NORMAL_MESH BIT(23) +#define MT_RXD3_NORMAL_MHCP BIT(24) +#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) +#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) +#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) +#define MT_RXD3_NORMAL_MORE BIT(28) +#define MT_RXD3_NORMAL_UNWANT BIT(29) +#define MT_RXD3_NORMAL_RX_DROP BIT(30) +#define MT_RXD3_NORMAL_VLAN2ETH BIT(31) + +/* RXD DW4 */ +#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) +#define MT_RXD4_NORMAL_CLS BIT(10) +#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) +#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) +#define MT_RXD4_NORMAL_WOL GENMASK(18, 14) +#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) +#define MT_RXD3_NORMAL_PF_MODE BIT(29) +#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) + +/* P-RXV */ +#define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_NSTS GENMASK(9, 7) +#define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_RCPI3 GENMASK(31, 24) +#define MT_PRXV_RCPI2 GENMASK(23, 16) +#define MT_PRXV_RCPI1 GENMASK(15, 8) +#define MT_PRXV_RCPI0 GENMASK(7, 0) + +/* C-RXV */ +#define MT_CRXV_HT_STBC GENMASK(1, 0) +#define MT_CRXV_TX_MODE GENMASK(7, 4) +#define MT_CRXV_FRAME_MODE GENMASK(10, 8) +#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) + +struct mt7915_rxv { + u32 phy; + + /* P-RXV: bit 0~1, C-RXV: bit 2~19 */ + __le32 v[20]; +}; + +enum tx_header_format { + MT_HDR_FORMAT_802_3, + MT_HDR_FORMAT_CMD, + MT_HDR_FORMAT_802_11, + MT_HDR_FORMAT_802_11_EXT, +}; + +enum tx_pkt_type { + MT_TX_TYPE_CT, + MT_TX_TYPE_SF, + MT_TX_TYPE_CMD, + MT_TX_TYPE_FW, +}; + +enum tx_pkt_queue_idx { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0 = 0x10, + MT_LMAC_BCN0 = 0x12, +}; + +enum tx_port_idx { + MT_TX_PORT_IDX_LMAC, + MT_TX_PORT_IDX_MCU +}; + +enum tx_mcu_port_q_idx { + MT_TX_MCU_PORT_RX_Q0 = 0x20, + MT_TX_MCU_PORT_RX_Q1, + MT_TX_MCU_PORT_RX_Q2, + MT_TX_MCU_PORT_RX_Q3, + MT_TX_MCU_PORT_RX_FWDL = 0x3e +}; + +#define MT_CT_INFO_APPLY_TXD BIT(0) +#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) +#define MT_CT_INFO_MGMT_FRAME BIT(2) +#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) +#define MT_CT_INFO_HSR2_TX BIT(4) + +#define MT_TXD_SIZE (8 * 4) + +#define MT_TXD0_Q_IDX GENMASK(31, 25) +#define MT_TXD0_PKT_FMT GENMASK(24, 23) +#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16) +#define MT_TXD0_TX_BYTES GENMASK(15, 0) + +#define MT_TXD1_LONG_FORMAT BIT(31) +#define MT_TXD1_TGID BIT(30) +#define MT_TXD1_OWN_MAC GENMASK(29, 24) +#define MT_TXD1_AMSDU BIT(23) +#define MT_TXD1_TID GENMASK(22, 20) +#define MT_TXD1_HDR_PAD GENMASK(19, 18) +#define MT_TXD1_HDR_FORMAT GENMASK(17, 16) +#define MT_TXD1_HDR_INFO GENMASK(15, 11) +#define MT_TXD1_VTA BIT(10) +#define MT_TXD1_WLAN_IDX GENMASK(9, 0) + +#define MT_TXD2_FIX_RATE BIT(31) +#define MT_TXD2_FIXED_RATE BIT(30) +#define MT_TXD2_POWER_OFFSET GENMASK(29, 24) +#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) +#define MT_TXD2_FRAG GENMASK(15, 14) +#define MT_TXD2_HTC_VLD BIT(13) +#define MT_TXD2_DURATION BIT(12) +#define MT_TXD2_BIP BIT(11) +#define MT_TXD2_MULTICAST BIT(10) +#define MT_TXD2_RTS BIT(9) +#define MT_TXD2_SOUNDING BIT(8) +#define MT_TXD2_NDPA BIT(7) +#define MT_TXD2_NDP BIT(6) +#define MT_TXD2_FRAME_TYPE GENMASK(5, 4) +#define MT_TXD2_SUB_TYPE GENMASK(3, 0) + +#define MT_TXD3_SN_VALID BIT(31) +#define MT_TXD3_PN_VALID BIT(30) +#define MT_TXD3_SW_POWER_MGMT BIT(29) +#define MT_TXD3_BA_DISABLE BIT(28) +#define MT_TXD3_SEQ GENMASK(27, 16) +#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) +#define MT_TXD3_TX_COUNT GENMASK(10, 6) +#define MT_TXD3_TIMING_MEASURE BIT(5) +#define MT_TXD3_DAS BIT(4) +#define MT_TXD3_EEOSP BIT(3) +#define MT_TXD3_EMRD BIT(2) +#define MT_TXD3_PROTECT_FRAME BIT(1) +#define MT_TXD3_NO_ACK BIT(0) + +#define MT_TXD4_PN_LOW GENMASK(31, 0) + +#define MT_TXD5_PN_HIGH GENMASK(31, 16) +#define MT_TXD5_MD BIT(15) +#define MT_TXD5_ADD_BA BIT(14) +#define MT_TXD5_TX_STATUS_HOST BIT(10) +#define MT_TXD5_TX_STATUS_MCU BIT(9) +#define MT_TXD5_TX_STATUS_FMT BIT(8) +#define MT_TXD5_PID GENMASK(7, 0) + +#define MT_TXD6_TX_IBF BIT(31) +#define MT_TXD6_TX_EBF BIT(30) +#define MT_TXD6_TX_RATE GENMASK(29, 16) +#define MT_TXD6_SGI GENMASK(15, 14) +#define MT_TXD6_HELTF GENMASK(13, 12) +#define MT_TXD6_LDPC BIT(11) +#define MT_TXD6_SPE_ID_IDX BIT(10) +#define MT_TXD6_ANT_ID GENMASK(7, 4) +#define MT_TXD6_DYN_BW BIT(3) +#define MT_TXD6_FIXED_BW BIT(2) +#define MT_TXD6_BW GENMASK(2, 0) + +#define MT_TXD7_TXD_LEN GENMASK(31, 30) +#define MT_TXD7_UDP_TCP_SUM BIT(29) +#define MT_TXD7_IP_SUM BIT(28) + +#define MT_TXD7_TYPE GENMASK(21, 20) +#define MT_TXD7_SUB_TYPE GENMASK(19, 16) + +#define MT_TXD7_PSE_FID GENMASK(27, 16) +#define MT_TXD7_SPE_IDX GENMASK(15, 11) +#define MT_TXD7_HW_AMSDU BIT(10) +#define MT_TXD7_TX_TIME GENMASK(9, 0) + +#define MT_TX_RATE_STBC BIT(13) +#define MT_TX_RATE_NSS GENMASK(12, 10) +#define MT_TX_RATE_MODE GENMASK(9, 6) +#define MT_TX_RATE_IDX GENMASK(5, 0) + +#define MT_TXP_MAX_BUF_NUM 6 + +struct mt7915_txp { + __le16 flags; + __le16 token; + u8 bss_idx; + u8 rept_wds_wcid; + u8 rsv; + u8 nbuf; + __le32 buf[MT_TXP_MAX_BUF_NUM]; + __le16 len[MT_TXP_MAX_BUF_NUM]; +} __packed __aligned(4); + +struct mt7915_tx_free { + __le16 rx_byte_cnt; + __le16 ctrl; + u8 txd_cnt; + u8 rsv[3]; + __le32 info[]; +} __packed __aligned(4); + +#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) +#define MT_TX_FREE_WLAN_ID GENMASK(23, 14) +#define MT_TX_FREE_LATENCY GENMASK(12, 0) +/* 0: success, others: dropped */ +#define MT_TX_FREE_STATUS GENMASK(14, 13) +#define MT_TX_FREE_MSDU_ID GENMASK(30, 16) +#define MT_TX_FREE_PAIR BIT(31) +/* will support this field in further revision */ +#define MT_TX_FREE_RATE GENMASK(13, 0) + +struct mt7915_dfs_pulse { + u32 max_width; /* us */ + int max_pwr; /* dbm */ + int min_pwr; /* dbm */ + u32 min_stgr_pri; /* us */ + u32 max_stgr_pri; /* us */ + u32 min_cr_pri; /* us */ + u32 max_cr_pri; /* us */ +}; + +struct mt7915_dfs_pattern { + u8 enb; + u8 stgr; + u8 min_crpn; + u8 max_crpn; + u8 min_crpr; + u8 min_pw; + u32 min_pri; + u32 max_pri; + u8 max_pw; + u8 min_crbn; + u8 max_crbn; + u8 min_stgpn; + u8 max_stgpn; + u8 min_stgpr; + u8 rsv[2]; + u32 min_stgpr_diff; +} __packed; + +struct mt7915_dfs_radar_spec { + struct mt7915_dfs_pulse pulse_th; + struct mt7915_dfs_pattern radar_pattern[16]; +}; + +static inline struct mt7915_txp * +mt7915_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + u8 *txwi; + + if (!t) + return NULL; + + txwi = mt76_get_txwi_ptr(dev, t); + + return (struct mt7915_txp *)(txwi + MT_TXD_SIZE); +} + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c new file mode 100644 index 000000000000..ae5ed41d337b --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -0,0 +1,741 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include +#include +#include "mt7915.h" +#include "mcu.h" + +static bool mt7915_dev_running(struct mt7915_dev *dev) +{ + struct mt7915_phy *phy; + + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) + return true; + + phy = mt7915_ext_phy(dev); + + return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); +} + +static int mt7915_start(struct ieee80211_hw *hw) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool running; + + mutex_lock(&dev->mt76.mutex); + + running = mt7915_dev_running(dev); + + if (!running) { + mt7915_mcu_set_pm(dev, 0, 0); + mt7915_mcu_set_mac(dev, 0, true, false); + mt7915_mcu_set_scs(dev, 0, true); + } + + if (phy != &dev->phy) { + mt7915_mcu_set_pm(dev, 1, 0); + mt7915_mcu_set_mac(dev, 1, true, false); + mt7915_mcu_set_scs(dev, 1, true); + } + + mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + if (running) + goto out; + + mt7915_mac_reset_counters(phy); + + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); +out: + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt7915_stop(struct ieee80211_hw *hw) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + mutex_lock(&dev->mt76.mutex); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + if (phy != &dev->phy) { + mt7915_mcu_set_pm(dev, 1, 1); + mt7915_mcu_set_mac(dev, 1, false, false); + } + + if (!mt7915_dev_running(dev)) { + cancel_delayed_work_sync(&dev->mt76.mac_work); + + mt7915_mcu_set_pm(dev, 0, 1); + mt7915_mcu_set_mac(dev, 0, false, false); + } + + mutex_unlock(&dev->mt76.mutex); +} + +static int get_omac_idx(enum nl80211_iftype type, u32 mask) +{ + int i; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP: + /* ap uses hw bssid 0 and ext bssid */ + if (~mask & BIT(HW_BSSID_0)) + return HW_BSSID_0; + + for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++) + if (~mask & BIT(i)) + return i; + break; + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + /* station uses hw bssid other than 0 */ + for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++) + if (~mask & BIT(i)) + return i; + break; + default: + WARN_ON(1); + break; + } + + return -1; +} + +static int mt7915_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt76_txq *mtxq; + bool ext_phy = phy != &dev->phy; + int idx, ret = 0; + + mutex_lock(&dev->mt76.mutex); + + mvif->idx = ffs(~phy->vif_mask) - 1; + if (mvif->idx >= MT7915_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + idx = get_omac_idx(vif->type, phy->omac_mask); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + mvif->omac_idx = idx; + mvif->dev = dev; + mvif->band_idx = ext_phy; + + if (ext_phy) + mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) + + mvif->idx % (MT7915_MAX_WMM_SETS / 2); + else + mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS; + + ret = mt7915_mcu_add_dev_info(dev, vif, true); + if (ret) + goto out; + + phy->vif_mask |= BIT(mvif->idx); + phy->omac_mask |= BIT(mvif->omac_idx); + + idx = MT7915_WTBL_RESERVED - mvif->idx; + + INIT_LIST_HEAD(&mvif->sta.poll_list); + mvif->sta.wcid.idx = idx; + mvif->sta.wcid.ext_phy = mvif->band_idx; + mvif->sta.wcid.hw_key_idx = -1; + mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = &mvif->sta.wcid; + mt76_txq_init(&dev->mt76, vif->txq); + } + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static void mt7915_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = &mvif->sta; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + int idx = msta->wcid.idx; + + /* TODO: disable beacon for the bss */ + + mt7915_mcu_add_dev_info(dev, vif, false); + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + if (vif->txq) + mt76_txq_remove(&dev->mt76, vif->txq); + + mutex_lock(&dev->mt76.mutex); + phy->vif_mask &= ~BIT(mvif->idx); + phy->omac_mask &= ~BIT(mvif->omac_idx); + mutex_unlock(&dev->mt76.mutex); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +static void mt7915_init_dfs_state(struct mt7915_phy *phy) +{ + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct cfg80211_chan_def *chandef = &hw->conf.chandef; + + if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + return; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + if (mphy->chandef.chan->center_freq == chandef->chan->center_freq && + mphy->chandef.width == chandef->width) + return; + + phy->dfs_state = -1; +} + +static int mt7915_set_channel(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + int ret; + + cancel_delayed_work_sync(&dev->mt76.mac_work); + + mutex_lock(&dev->mt76.mutex); + set_bit(MT76_RESET, &phy->mt76->state); + + mt7915_init_dfs_state(phy); + mt76_set_channel(phy->mt76); + + ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH); + if (ret) + goto out; + + mt7915_mac_set_timing(phy); + ret = mt7915_dfs_init_radar_detector(phy); + mt7915_mac_cca_stats_reset(phy); + + mt7915_mac_reset_counters(phy); + phy->noise = 0; + +out: + clear_bit(MT76_RESET, &phy->mt76->state); + mutex_unlock(&dev->mt76.mutex); + + mt76_txq_schedule_all(phy->mt76); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + MT7915_WATCHDOG_TIME); + + return ret; +} + +static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv : + &mvif->sta; + struct mt76_wcid *wcid = &msta->wcid; + int idx = key->keyidx; + + /* The hardware does not support per-STA RX GTK, fallback + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + case WLAN_CIPHER_SUITE_SMS4: + break; + default: + return -EOPNOTSUPP; + } + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx = -1; + } + mt76_wcid_key_setup(&dev->mt76, wcid, + cmd == SET_KEY ? key : NULL); + + return mt7915_mcu_add_key(dev, vif, msta, key, cmd); +} + +static int mt7915_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + int ret; + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt7915_set_channel(phy); + if (ret) + return ret; + ieee80211_wake_queues(hw); + } + + mutex_lock(&dev->mt76.mutex); + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) + phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + } + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + + /* no need to update right away, we'll get BSS_CHANGED_QOS */ + mvif->wmm[queue].cw_min = params->cw_min; + mvif->wmm[queue].cw_max = params->cw_max; + mvif->wmm[queue].aifs = params->aifs; + mvif->wmm[queue].txop = params->txop; + + return 0; +} + +static void mt7915_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + phy->rxfilter &= ~(_hw); \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI); + + MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | + MT_WF_RFCR_DROP_A3_MAC | + MT_WF_RFCR_DROP_A3_BSSID); + + MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); + + MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_NDPA); + + *total_flags = flags; + mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + + if (*total_flags & FIF_CONTROL) + mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); + else + mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); +} + +static void mt7915_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + + /* + * station mode uses BSSID to map the wlan entry to a peer, + * and then peer references bss_info_rfch to set bandwidth cap. + */ + if (changed & BSS_CHANGED_BSSID && + vif->type == NL80211_IFTYPE_STATION) { + bool join = !is_zero_ether_addr(info->bssid); + + mt7915_mcu_add_bss_info(phy, vif, join); + mt7915_mcu_add_sta(dev, vif, NULL, join); + } + + if (changed & BSS_CHANGED_ASSOC) + mt7915_mcu_add_bss_info(phy, vif, info->assoc); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + if (slottime != phy->slottime) { + phy->slottime = slottime; + mt7915_mac_set_timing(phy); + } + } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + mt7915_mcu_add_bss_info(phy, vif, info->enable_beacon); + mt7915_mcu_add_sta(dev, vif, NULL, info->enable_beacon); + } + + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7915_mcu_set_tx(dev, vif); + + if (changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) + mt7915_mcu_add_beacon(hw, vif, info->enable_beacon); + + mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7915_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mcu_add_beacon(hw, vif, true); + mutex_unlock(&dev->mt76.mutex); +} + +int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int idx; + + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; + + INIT_LIST_HEAD(&msta->poll_list); + INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work); + spin_lock_init(&msta->ampdu_lock); + msta->vif = mvif; + msta->wcid.sta = 1; + msta->wcid.idx = idx; + msta->wcid.ext_phy = mvif->band_idx; + msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->stats.jiffies = jiffies; + + mt7915_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7915_mcu_add_sta(dev, vif, sta, true); + + return 0; +} + +void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + mt7915_mcu_add_sta(dev, vif, sta, false); + + mt7915_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} + +static void mt7915_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + + if (control->sta) { + struct mt7915_sta *sta; + + sta = (struct mt7915_sta *)control->sta->drv_priv; + wcid = &sta->wcid; + } + + if (vif && !control->sta) { + struct mt7915_vif *mvif; + + mvif = (struct mt7915_vif *)vif->drv_priv; + wcid = &mvif->sta.wcid; + } + + mt76_tx(mphy, control->sta, wcid, skb); +} + +static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + mutex_lock(&dev->mt76.mutex); + mt7915_mcu_set_rts_thresh(phy, val); + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct ieee80211_sta *sta = params->sta; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + u16 tid = params->tid; + u16 ssn = params->ssn; + struct mt76_txq *mtxq; + int ret = 0; + + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; + + mutex_lock(&dev->mt76.mutex); + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + params->buf_size); + mt7915_mcu_add_rx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt7915_mcu_add_rx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL); + mt7915_mcu_add_tx_ba(dev, params, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP); + mt7915_mcu_add_tx_ba(dev, params, false); + break; + case IEEE80211_AMPDU_TX_START: + mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP); + mt7915_mcu_add_tx_ba(dev, params, false); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static int +mt7915_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, + IEEE80211_STA_NONE); +} + +static int +mt7915_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, + IEEE80211_STA_NOTEXIST); +} + +static int +mt7915_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount = mib->rts_cnt; + stats->dot11RTSFailureCount = mib->rts_retries_cnt; + stats->dot11FCSErrorCount = mib->fcs_err_cnt; + stats->dot11ACKFailureCount = mib->ack_fail_cnt; + + return 0; +} + +static void +mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + phy->coverage_class = max_t(s16, coverage_class, 0); + mt7915_mac_set_timing(phy); +} + +static int +mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + int max_nss = hweight8(hw->wiphy->available_antennas_tx); + bool ext_phy = phy != &dev->phy; + + if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + return -EINVAL; + + if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) + tx_ant = BIT(ffs(tx_ant) - 1) - 1; + + mutex_lock(&dev->mt76.mutex); + + phy->mt76->antenna_mask = tx_ant; + + if (ext_phy) { + if (dev->chainmask == 0xf) + tx_ant <<= 2; + else + tx_ant <<= 1; + } + phy->chainmask = tx_ant; + + mt76_set_stream_caps(&dev->mt76, true); + + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void +mt7915_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, sta->addr); + if (!sta) { + rcu_read_unlock(); + return; + } + rcu_read_lock(); + + set_bit(changed, &msta->stats.changed); + ieee80211_queue_work(hw, &msta->stats_work); +} + +const struct ieee80211_ops mt7915_ops = { + .tx = mt7915_tx, + .start = mt7915_start, + .stop = mt7915_stop, + .add_interface = mt7915_add_interface, + .remove_interface = mt7915_remove_interface, + .config = mt7915_config, + .conf_tx = mt7915_conf_tx, + .configure_filter = mt7915_configure_filter, + .bss_info_changed = mt7915_bss_info_changed, + .sta_add = mt7915_sta_add, + .sta_remove = mt7915_sta_remove, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_rc_update = mt7915_sta_rc_update, + .set_key = mt7915_set_key, + .ampdu_action = mt7915_ampdu_action, + .set_rts_threshold = mt7915_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, + .sw_scan_start = mt76_sw_scan, + .sw_scan_complete = mt76_sw_scan_complete, + .release_buffered_frames = mt76_release_buffered_frames, + .get_txpower = mt76_get_txpower, + .channel_switch_beacon = mt7915_channel_switch_beacon, + .get_stats = mt7915_get_stats, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, + .set_antenna = mt7915_set_antenna, + .set_coverage_class = mt7915_set_coverage_class, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c new file mode 100644 index 000000000000..dad2c300d0f2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -0,0 +1,2313 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. */ + +#include +#include +#include "mt7915.h" +#include "mcu.h" +#include "mac.h" +#include "eeprom.h" + +struct mt7915_patch_hdr { + char build_date[16]; + char platform[4]; + __be32 hw_sw_ver; + __be32 patch_ver; + __be16 checksum; + u16 reserved; + struct { + __be32 patch_ver; + __be32 subsys; + __be32 feature; + __be32 n_region; + __be32 crc; + u32 reserved[11]; + } desc; +} __packed; + +struct mt7915_patch_sec { + __be32 type; + __be32 offs; + __be32 size; + union { + __be32 spec[13]; + struct { + __be32 addr; + __be32 len; + __be32 sec_key_idx; + __be32 align_len; + u32 reserved[9]; + } info; + }; +} __packed; + +struct mt7915_fw_trailer { + u8 chip_id; + u8 eco_code; + u8 n_region; + u8 format_ver; + u8 format_flag; + u8 reserved[2]; + char fw_ver[10]; + char build_date[15]; + u32 crc; +} __packed; + +struct mt7915_fw_region { + __le32 decomp_crc; + __le32 decomp_len; + __le32 decomp_blk_sz; + u8 reserved[4]; + __le32 addr; + __le32 len; + u8 feature_set; + u8 reserved1[15]; +} __packed; + +#define MCU_PATCH_ADDRESS 0x200000 + +#define FW_FEATURE_SET_ENCRYPT BIT(0) +#define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) +#define FW_FEATURE_OVERRIDE_ADDR BIT(5) + +#define DL_MODE_ENCRYPT BIT(0) +#define DL_MODE_KEY_IDX GENMASK(2, 1) +#define DL_MODE_RESET_SEC_IV BIT(3) +#define DL_MODE_WORKING_PDA_CR4 BIT(4) +#define DL_MODE_NEED_RSP BIT(31) + +#define FW_START_OVERRIDE BIT(0) +#define FW_START_WORKING_PDA_CR4 BIT(2) + +#define PATCH_SEC_TYPE_MASK GENMASK(15, 0) +#define PATCH_SEC_TYPE_INFO 0x2 + +#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) +#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) + +static enum mt7915_cipher_type +mt7915_mcu_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + +static u8 mt7915_mcu_chan_bw(struct cfg80211_chan_def *chandef) +{ + static const u8 width_to_bw[] = { + [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, + [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, + [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, + [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, + [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, + [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, + [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, + [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, + }; + + if (chandef->width >= ARRAY_SIZE(width_to_bw)) + return 0; + + return width_to_bw[chandef->width]; +} + +static u8 +mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, + enum nl80211_band band, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_ht_cap *ht_cap; + struct ieee80211_sta_vht_cap *vht_cap; + u8 mode = 0; + + if (sta) { + ht_cap = &sta->ht_cap; + vht_cap = &sta->vht_cap; + } else { + struct ieee80211_supported_band *sband; + + if (band == NL80211_BAND_2GHZ) + sband = &dev->mphy.sband_2g.sband; + else + sband = &dev->mphy.sband_5g.sband; + + ht_cap = &sband->ht_cap; + vht_cap = &sband->vht_cap; + } + + if (band == NL80211_BAND_2GHZ) { + mode |= PHY_MODE_B | PHY_MODE_G; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_GN; + } else if (band == NL80211_BAND_5GHZ) { + mode |= PHY_MODE_A; + + if (ht_cap->ht_supported) + mode |= PHY_MODE_AN; + + if (vht_cap->vht_supported) + mode |= PHY_MODE_AC; + } + + return mode; +} + +static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb, + int cmd, int *wait_seq) +{ + struct mt7915_mcu_txd *mcu_txd; + u8 seq, pkt_fmt, qidx; + enum mt7915_txq_id txq; + __le32 *txd; + u32 val; + + seq = ++dev->mt76.mcu.msg_seq & 0xf; + if (!seq) + seq = ++dev->mt76.mcu.msg_seq & 0xf; + + if (cmd == -MCU_CMD_FW_SCATTER) { + txq = MT_TXQ_FWDL; + goto exit; + } + + mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd)); + + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { + txq = MT_TXQ_MCU_WA; + qidx = MT_TX_MCU_PORT_RX_Q0; + pkt_fmt = MT_TX_TYPE_CMD; + } else { + txq = MT_TXQ_MCU; + qidx = MT_TX_MCU_PORT_RX_Q0; + pkt_fmt = MT_TX_TYPE_CMD; + } + + txd = mcu_txd->txd; + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | + FIELD_PREP(MT_TXD0_PKT_FMT, pkt_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, qidx); + txd[0] = cpu_to_le32(val); + + val = MT_TXD1_LONG_FORMAT | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); + txd[1] = cpu_to_le32(val); + + mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, qidx)); + mcu_txd->pkt_type = MCU_PKT_ID; + mcu_txd->seq = seq; + + if (cmd < 0) { + mcu_txd->set_query = MCU_Q_NA; + mcu_txd->cid = -cmd; + } else { + mcu_txd->cid = MCU_CMD_EXT_CID; + mcu_txd->ext_cid = cmd; + mcu_txd->ext_cid_ack = 1; + + /* do not use Q_SET for efuse */ + if (cmd == MCU_EXT_CMD_EFUSE_ACCESS) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + } + + mcu_txd->s2d_index = MCU_S2D_H2N; + BUILD_BUG_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && + mcu_txd->set_query != MCU_Q_QUERY); + +exit: + if (wait_seq) + *wait_seq = seq; + + return mt76_tx_queue_skb_raw(dev, txq, skb, 0); +} + +static int +mt7915_mcu_parse_eeprom(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_eeprom_info *res; + u8 *buf; + + if (!skb) + return -EINVAL; + + skb_pull(skb, sizeof(struct mt7915_mcu_rxd)); + + res = (struct mt7915_mcu_eeprom_info *)skb->data; + buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); + memcpy(buf, res->data, 16); + + return 0; +} + +static int +mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, + struct sk_buff *skb, int seq) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + int ret = 0; + + if (seq != rxd->seq) + return -EAGAIN; + + switch (cmd) { + case -MCU_CMD_PATCH_SEM_CONTROL: + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; + break; + case MCU_EXT_CMD_THERMAL_CTRL: + skb_pull(skb, sizeof(*rxd) + 4); + ret = le32_to_cpu(*(__le32 *)skb->data); + break; + case MCU_EXT_CMD_EFUSE_ACCESS: + ret = mt7915_mcu_parse_eeprom(dev, skb); + break; + default: + break; + } + dev_kfree_skb(skb); + + return ret; +} + +static int +mt7915_mcu_wait_response(struct mt7915_dev *dev, int cmd, int seq) +{ + unsigned long expires = jiffies + 20 * HZ; + struct sk_buff *skb; + int ret = 0; + + while (true) { + skb = mt76_mcu_get_response(&dev->mt76, expires); + if (!skb) { + dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n", + cmd, seq); + return -ETIMEDOUT; + } + + ret = mt7915_mcu_parse_response(dev, cmd, skb, seq); + if (ret != -EAGAIN) + break; + } + + return ret; +} + +static int +mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + int ret, seq; + + mutex_lock(&mdev->mcu.mutex); + + ret = __mt7915_mcu_msg_send(dev, skb, cmd, &seq); + if (ret) + goto out; + + if (wait_resp) + ret = mt7915_mcu_wait_response(dev, cmd, seq); + +out: + mutex_unlock(&mdev->mcu.mutex); + + return ret; +} + +static int +mt7915_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, + int len, bool wait_resp) +{ + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(mdev, data, len); + if (!skb) + return -ENOMEM; + + return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp); +} + +static void +mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + if (vif->csa_active) + ieee80211_csa_finish(vif); +} + +static void +mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_mcu_rdd_report *r; + + r = (struct mt7915_mcu_rdd_report *)skb->data; + + if (r->idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + ieee80211_radar_detected(mphy->hw); + dev->hw_pattern++; +} + +static void +mt7915_mcu_tx_rate_cal(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra, + struct rate_info *rate, u16 r) +{ + struct ieee80211_supported_band *sband; + u16 ru_idx = le16_to_cpu(ra->ru_idx); + u16 flags = 0; + + rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r); + rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1; + + switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else + sband = &mphy->sband_2g.sband; + + rate->legacy = sband->bitrates[rate->mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + rate->mcs += (rate->nss - 1) * 8; + flags |= RATE_INFO_FLAGS_MCS; + + if (ra->gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + flags |= RATE_INFO_FLAGS_VHT_MCS; + + if (ra->gi) + flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + rate->he_gi = ra->gi; + rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r); + + flags |= RATE_INFO_FLAGS_HE_MCS; + break; + default: + break; + } + rate->flags = flags; + + if (ru_idx) { + switch (ru_idx) { + case 1 ... 2: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 3 ... 6: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_484; + break; + case 7 ... 14: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_242; + break; + default: + rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106; + break; + } + rate->bw = RATE_INFO_BW_HE_RU; + } else { + u8 bw = mt7915_mcu_chan_bw(&mphy->chandef) - + FIELD_GET(MT_RA_RATE_BW, r); + + switch (bw) { + case IEEE80211_STA_RX_BW_160: + rate->bw = RATE_INFO_BW_160; + break; + case IEEE80211_STA_RX_BW_80: + rate->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_40: + rate->bw = RATE_INFO_BW_40; + break; + default: + rate->bw = RATE_INFO_BW_20; + break; + } + } +} + +static void +mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; + u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + struct mt7915_sta *msta = container_of(wcid, struct mt7915_sta, wcid); + struct mt7915_sta_stats *stats = &msta->stats; + struct mt76_phy *mphy = &dev->mphy; + struct rate_info rate = {}, prob_rate = {}; + u16 attempts = le16_to_cpu(ra->attempts); + u16 curr = le16_to_cpu(ra->curr_rate); + u16 probe = le16_to_cpu(ra->prob_up_rate); + + if (msta->wcid.ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + /* current rate */ + mt7915_mcu_tx_rate_cal(mphy, ra, &rate, curr); + stats->tx_rate = rate; + + /* probing rate */ + mt7915_mcu_tx_rate_cal(mphy, ra, &prob_rate, probe); + stats->prob_rate = prob_rate; + + if (attempts) { + u16 success = le16_to_cpu(ra->success); + + stats->per = 1000 * (attempts - success) / attempts; + } +} + +static void +mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + switch (rxd->ext_eid) { + case MCU_EXT_EVENT_RDD_REPORT: + mt7915_mcu_rx_radar_detected(dev, skb); + break; + case MCU_EXT_EVENT_CSA_NOTIFY: + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7915_mcu_csa_finish, dev); + break; + case MCU_EXT_EVENT_RATE_REPORT: + mt7915_mcu_tx_rate_report(dev, skb); + break; + default: + break; + } +} + +static void +mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + switch (rxd->eid) { + case MCU_EVENT_EXT: + mt7915_mcu_rx_ext_event(dev, skb); + break; + default: + break; + } + dev_kfree_skb(skb); +} + +void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + + if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || + rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || + rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || + !rxd->seq) + mt7915_mcu_rx_unsolicited_event(dev, skb); + else + mt76_mcu_rx_event(&dev->mt76, skb); +} + +static struct sk_buff * +mt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif, + struct mt7915_sta *msta, int len) +{ + struct sta_req_hdr hdr = { + .bss_idx = mvif->idx, + .wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0, + .wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0, + .muar_idx = msta ? mvif->omac_idx : 0, + .is_tlv_append = 1, + }; + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb_put_data(skb, &hdr, sizeof(hdr)); + + return skb; +} + +static struct wtbl_req_hdr * +mt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta, + int cmd, void *sta_wtbl, struct sk_buff **skb) +{ + struct tlv *sta_hdr = sta_wtbl; + struct wtbl_req_hdr hdr = { + .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), + .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), + .operation = cmd, + }; + struct sk_buff *nskb = *skb; + + if (!nskb) { + nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + MT7915_WTBL_UPDATE_BA_SIZE); + if (!nskb) + return ERR_PTR(-ENOMEM); + + *skb = nskb; + } + + if (sta_hdr) + sta_hdr->len = cpu_to_le16(sizeof(hdr)); + + return skb_put_data(nskb, &hdr, sizeof(hdr)); +} + +static struct tlv * +mt7915_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, + void *sta_ntlv, void *sta_wtbl) +{ + struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; + struct tlv *sta_hdr = sta_wtbl; + struct tlv *ptlv, tlv = { + .tag = cpu_to_le16(tag), + .len = cpu_to_le16(len), + }; + u16 ntlv; + + ptlv = skb_put(skb, len); + memcpy(ptlv, &tlv, sizeof(tlv)); + + ntlv = le16_to_cpu(ntlv_hdr->tlv_num); + ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); + + if (sta_hdr) { + u16 size = le16_to_cpu(sta_hdr->len); + + sta_hdr->len = cpu_to_le16(size + len); + } + + return ptlv; +} + +static struct tlv * +mt7915_mcu_add_tlv(struct sk_buff *skb, int tag, int len) +{ + return mt7915_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); +} + +static struct tlv * +mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len, + __le16 *sub_ntlv, __le16 *len) +{ + struct tlv *ptlv, tlv = { + .tag = cpu_to_le16(sub_tag), + .len = cpu_to_le16(sub_len), + }; + + ptlv = skb_put(skb, sub_len); + memcpy(ptlv, &tlv, sizeof(tlv)); + + *sub_ntlv = cpu_to_le16(le16_to_cpu(*sub_ntlv) + 1); + *len = cpu_to_le16(le16_to_cpu(*len) + sub_len); + + return ptlv; +} + +/** bss info **/ +static int +mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct bss_info_basic *bss; + u16 wlan_idx = mvif->sta.wcid.idx; + u32 type = NETWORK_INFRA; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + break; + case NL80211_IFTYPE_STATION: + /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ + if (enable) { + struct ieee80211_sta *sta; + struct mt7915_sta *msta; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) { + rcu_read_unlock(); + return -EINVAL; + } + + msta = (struct mt7915_sta *)sta->drv_priv; + wlan_idx = msta->wcid.idx; + rcu_read_unlock(); + } + break; + case NL80211_IFTYPE_ADHOC: + type = NETWORK_IBSS; + break; + default: + WARN_ON(1); + break; + } + + bss = (struct bss_info_basic *)tlv; + memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + bss->network_type = cpu_to_le32(type); + bss->dtim_period = vif->bss_conf.dtim_period; + bss->bmc_wcid_lo = to_wcid_lo(wlan_idx); + bss->bmc_wcid_hi = to_wcid_hi(wlan_idx); + bss->phy_mode = mt7915_get_phy_mode(phy->dev, vif, band, NULL); + bss->wmm_idx = mvif->wmm_idx; + bss->active = enable; + + return 0; +} + +static void +mt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct bss_info_omac *omac; + struct tlv *tlv; + u32 type = 0; + u8 idx; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + type = CONNECTION_INFRA_AP; + break; + case NL80211_IFTYPE_STATION: + type = CONNECTION_INFRA_STA; + break; + case NL80211_IFTYPE_ADHOC: + type = CONNECTION_IBSS_ADHOC; + break; + default: + WARN_ON(1); + break; + } + + omac = (struct bss_info_omac *)tlv; + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; + omac->conn_type = cpu_to_le32(type); + omac->omac_idx = mvif->omac_idx; + omac->band_idx = mvif->band_idx; + omac->hw_bss_idx = idx; +} + +static void +mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + struct bss_info_rf_ch *ch; + struct tlv *tlv; + int freq1 = chandef->center_freq1; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch)); + + ch = (struct bss_info_rf_ch *)tlv; + ch->pri_ch = chandef->chan->hw_value; + ch->center_ch0 = ieee80211_frequency_to_channel(freq1); + ch->bw = mt7915_mcu_chan_bw(chandef); + + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { + int freq2 = chandef->center_freq2; + + ch->center_ch1 = ieee80211_frequency_to_channel(freq2); + } + + ch->he_all_disable = true; +} + +static void +mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ + struct bss_info_ra *ra; + struct tlv *tlv; + int max_nss = hweight8(phy->chainmask); + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); + + ra = (struct bss_info_ra *)tlv; + ra->op_mode = vif->type == NL80211_IFTYPE_AP; + ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC; + ra->short_preamble = true; + ra->tx_streams = max_nss; + ra->rx_streams = max_nss; + ra->algo = 4; + ra->train_up_rule = 2; + ra->train_up_high_thres = 110; + ra->train_up_rule_rssi = -70; + ra->low_traffic_thres = 2; + ra->phy_cap = cpu_to_le32(0xfdf); + ra->interval = cpu_to_le32(500); + ra->fast_interval = cpu_to_le32(100); +} + +static void +mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif) +{ +/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */ +#define BCN_TX_ESTIMATE_TIME (4096 + 20) + struct bss_info_ext_bss *ext; + int ext_bss_idx, tsf_offset; + struct tlv *tlv; + + ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; + if (ext_bss_idx < 0) + return; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); + + ext = (struct bss_info_ext_bss *)tlv; + tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; + ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); +} + +static void +mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy) +{ + struct bss_info_bmc_rate *bmc; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc)); + + bmc = (struct bss_info_bmc_rate *)tlv; + if (band == NL80211_BAND_2GHZ) { + bmc->short_preamble = true; + } else { + bmc->bc_trans = cpu_to_le16(0x2000); + bmc->mc_trans = cpu_to_le16(0x2080); + } +} + +static void +mt7915_mcu_bss_sync_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +{ + struct bss_info_sync_mode *sync; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_SYNC_MODE, sizeof(*sync)); + + sync = (struct bss_info_sync_mode *)tlv; + sync->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + sync->dtim_period = vif->bss_conf.dtim_period; + sync->enable = true; +} + +int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, + struct ieee80211_vif *vif, int enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(phy->dev, mvif, NULL, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* bss_omac must be first */ + if (enable) + mt7915_mcu_bss_omac_tlv(skb, vif); + + mt7915_mcu_bss_basic_tlv(skb, vif, phy, enable); + + if (enable) { + mt7915_mcu_bss_rfch_tlv(skb, vif, phy); + mt7915_mcu_bss_bmc_tlv(skb, phy); + mt7915_mcu_bss_ra_tlv(skb, vif, phy); + + if (mvif->omac_idx > HW_BSSID_MAX) + mt7915_mcu_bss_ext_tlv(skb, mvif); + else + mt7915_mcu_bss_sync_tlv(skb, vif); + } + + return __mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, + MCU_EXT_CMD_BSS_INFO_UPDATE, true); +} + +/** starec & wtbl **/ +static int +mt7915_mcu_sta_key_tlv(struct sk_buff *skb, struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + struct sta_rec_sec *sec; + struct tlv *tlv; + u32 len = sizeof(*sec); + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); + + sec = (struct sta_rec_sec *)tlv; + sec->add = cmd; + + if (cmd == SET_KEY) { + struct sec_key *sec_key; + u8 cipher; + + cipher = mt7915_mcu_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) + return -EOPNOTSUPP; + + sec_key = &sec->key[0]; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_id = key->keyidx; + + if (cipher == MT_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MT_CIPHER_AES_CCMP; + sec_key->key_len = 16; + memcpy(sec_key->key, key->key, 16); + + sec_key = &sec->key[1]; + sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_len = 16; + memcpy(sec_key->key, key->key + 16, 16); + + sec->n_cipher = 2; + } else { + sec_key->cipher_id = cipher; + sec_key->key_len = key->keylen; + memcpy(sec_key->key, key->key, key->keylen); + + if (cipher == MT_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); + } + + len -= sizeof(*sec_key); + sec->n_cipher = 1; + } + } else { + len -= sizeof(sec->key); + sec->n_cipher = 0; + } + sec->len = cpu_to_le16(len); + + return 0; +} + +int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct mt7915_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct sk_buff *skb; + int ret; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = mt7915_mcu_sta_key_tlv(skb, key, cmd); + if (ret) + return ret; + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +static void +mt7915_mcu_sta_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct sta_rec_ba *ba; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); + + ba = (struct sta_rec_ba *)tlv; + ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT, + ba->winsize = cpu_to_le16(params->buf_size); + ba->ssn = cpu_to_le16(params->ssn); + ba->ba_en = enable << params->tid; + ba->amsdu = params->amsdu; + ba->tid = params->tid; +} + +static void +mt7915_mcu_wtbl_ba_tlv(struct sk_buff *skb, + struct ieee80211_ampdu_params *params, + bool enable, bool tx, void *sta_wtbl, + void *wtbl_tlv) +{ + struct wtbl_ba *ba; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), + wtbl_tlv, sta_wtbl); + + ba = (struct wtbl_ba *)tlv; + ba->tid = params->tid; + + if (tx) { + ba->ba_type = MT_BA_TYPE_ORIGINATOR; + ba->sn = enable ? cpu_to_le16(params->ssn) : 0; + ba->ba_en = enable; + } else { + memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); + ba->ba_type = MT_BA_TYPE_RECIPIENT; + ba->rst_ba_tid = params->tid; + ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; + ba->rst_ba_sb = 1; + } + + if (enable && tx) + ba->ba_winsize = cpu_to_le16(params->buf_size); +} + +static int +mt7915_mcu_sta_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; + struct mt7915_vif *mvif = msta->vif; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); + mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + return mt7915_mcu_sta_ba(dev, params, enable, true); +} + +int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable) +{ + return mt7915_mcu_sta_ba(dev, params, enable, false); +} + +static void +mt7915_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *sta_wtbl, + void *wtbl_tlv) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct wtbl_generic *generic; + struct wtbl_rx *rx; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), + wtbl_tlv, sta_wtbl); + + generic = (struct wtbl_generic *)tlv; + + if (sta) { + memcpy(generic->peer_addr, sta->addr, ETH_ALEN); + generic->partial_aid = cpu_to_le16(sta->aid); + generic->muar_idx = mvif->omac_idx; + generic->qos = sta->wme; + } else { + /* use BSSID in station mode */ + if (vif->type == NL80211_IFTYPE_STATION) + memcpy(generic->peer_addr, vif->bss_conf.bssid, + ETH_ALEN); + else + eth_broadcast_addr(generic->peer_addr); + + generic->muar_idx = 0xe; + } + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), + wtbl_tlv, sta_wtbl); + + rx = (struct wtbl_rx *)tlv; + rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; + rx->rca2 = 1; + rx->rv = 1; +} + +static void +mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ +#define EXTRA_INFO_VER BIT(0) +#define EXTRA_INFO_NEW BIT(1) + struct sta_rec_basic *basic; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); + + basic = (struct sta_rec_basic *)tlv; + basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); + + if (enable) { + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + basic->conn_state = CONN_STATE_PORT_SECURE; + } else { + basic->conn_state = CONN_STATE_DISCONNECT; + } + + if (!sta) { + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); + eth_broadcast_addr(basic->peer_addr); + return; + } + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + break; + case NL80211_IFTYPE_STATION: + basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + break; + case NL80211_IFTYPE_ADHOC: + basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; + default: + WARN_ON(1); + break; + } + + memcpy(basic->peer_addr, sta->addr, ETH_ALEN); + basic->aid = cpu_to_le16(sta->aid); + basic->qos = sta->wme; +} + +static void +mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta) +{ + struct tlv *tlv; + + if (sta->ht_cap.ht_supported) { + struct sta_rec_ht *ht; + + /* starec ht */ + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); + ht = (struct sta_rec_ht *)tlv; + ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); + } + + /* starec vht */ + if (sta->vht_cap.vht_supported) { + struct sta_rec_vht *vht; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); + vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; + } +} + +static void +mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct wtbl_smps *smps; + struct tlv *tlv; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), + wtbl_tlv, sta_wtbl); + smps = (struct wtbl_smps *)tlv; + + if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) + smps->smps = true; +} + +static void +mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + void *sta_wtbl, void *wtbl_tlv) +{ + struct wtbl_ht *ht = NULL; + struct tlv *tlv; + + /* wtbl ht */ + if (sta->ht_cap.ht_supported) { + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), + wtbl_tlv, sta_wtbl); + ht = (struct wtbl_ht *)tlv; + ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; + ht->af = sta->ht_cap.ampdu_factor; + ht->mm = sta->ht_cap.ampdu_density; + ht->ht = true; + } + + /* wtbl vht */ + if (sta->vht_cap.vht_supported) { + struct wtbl_vht *vht; + u8 af; + + tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), + wtbl_tlv, sta_wtbl); + vht = (struct wtbl_vht *)tlv; + vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC, + vht->vht = true; + + af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + sta->vht_cap.cap); + if (ht) + ht->af = max_t(u8, ht->af, af); + } + + mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); +} + +int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, + &skb); + mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +static void +mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct cfg80211_chan_def *chandef = &dev->mphy.chandef; + struct sta_rec_ra *ra; + struct tlv *tlv; + enum nl80211_band band = chandef->chan->band; + u32 supp_rate = sta->supp_rates[band]; + int n_rates = hweight32(supp_rate); + u32 cap = sta->wme ? STA_CAP_WMM : 0; + u8 i, nss = sta->rx_nss, mcs = 0; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); + + ra = (struct sta_rec_ra *)tlv; + ra->valid = true; + ra->auto_rate = true; + ra->phy_mode = mt7915_get_phy_mode(dev, vif, band, sta); + ra->channel = chandef->chan->hw_value; + ra->bw = sta->bandwidth; + ra->rate_len = n_rates; + ra->phy.bw = sta->bandwidth; + + if (n_rates) { + if (band == NL80211_BAND_2GHZ) { + ra->supp_mode = MODE_CCK; + ra->supp_cck_rate = supp_rate & GENMASK(3, 0); + ra->phy.type = MT_PHY_TYPE_CCK; + + if (n_rates > 4) { + ra->supp_mode |= MODE_OFDM; + ra->supp_ofdm_rate = supp_rate >> 4; + ra->phy.type = MT_PHY_TYPE_OFDM; + } + } else { + ra->supp_mode = MODE_OFDM; + ra->supp_ofdm_rate = supp_rate; + ra->phy.type = MT_PHY_TYPE_OFDM; + } + } + + if (sta->ht_cap.ht_supported) { + for (i = 0; i < nss; i++) + ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i]; + + ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; + ra->supp_mode |= MODE_HT; + mcs = hweight32(ra->supp_ht_mcs) - 1; + ra->af = sta->ht_cap.ampdu_factor; + ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); + + cap |= STA_CAP_HT; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) + cap |= STA_CAP_SGI_20; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) + cap |= STA_CAP_SGI_40; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) + cap |= STA_CAP_TX_STBC; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + cap |= STA_CAP_RX_STBC; + if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) + cap |= STA_CAP_LDPC; + } + + if (sta->vht_cap.vht_supported) { + __le16 mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + u16 vht_mcs; + u8 af, mcs_prev; + + af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + sta->vht_cap.cap); + ra->af = max_t(u8, ra->af, af); + + cap |= STA_CAP_VHT; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) + cap |= STA_CAP_VHT_SGI_80; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) + cap |= STA_CAP_VHT_SGI_160; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) + cap |= STA_CAP_VHT_TX_STBC; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) + cap |= STA_CAP_VHT_RX_STBC; + if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) + cap |= STA_CAP_VHT_LDPC; + + ra->supp_mode |= MODE_VHT; + for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) { + switch (mcs_map & 0x3) { + case IEEE80211_VHT_MCS_SUPPORT_0_9: + vht_mcs = GENMASK(9, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_8: + vht_mcs = GENMASK(8, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_7: + vht_mcs = GENMASK(7, 0); + break; + default: + vht_mcs = 0; + } + + ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); + + mcs_prev = hweight16(vht_mcs) - 1; + if (mcs_prev > mcs) + mcs = mcs_prev; + + /* only support 2ss on 160MHz */ + if (i > 1 && (ra->bw == CMD_CBW_160MHZ || + ra->bw == CMD_CBW_8080MHZ)) + break; + } + } + + ra->sta_status = cpu_to_le32(cap); + + switch (BIT(fls(ra->supp_mode) - 1)) { + case MODE_VHT: + ra->phy.type = MT_PHY_TYPE_VHT; + ra->phy.mcs = mcs; + ra->phy.nss = nss; + ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC); + ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + ra->phy.sgi = + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + break; + case MODE_HT: + ra->phy.type = MT_PHY_TYPE_HT; + ra->phy.mcs = mcs; + ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; + ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC); + ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + break; + default: + break; + } +} + +int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + +int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct mt7915_sta *msta; + struct tlv *sta_wtbl; + struct sk_buff *skb; + int ret; + + msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable); + if (enable && sta) + mt7915_mcu_sta_tlv(dev, skb, sta); + + sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); + + wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, + sta_wtbl, &skb); + if (enable) { + mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr); + if (sta) + mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); + } + + ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + if (ret) + return ret; + + if (enable && sta) + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); + + return 0; +} + +int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct { + struct req_hdr { + u8 omac_idx; + u8 dbdc_idx; + __le16 tlv_num; + u8 is_tlv_append; + u8 rsv[3]; + } __packed hdr; + struct req_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 dbdc_idx; + u8 omac_addr[ETH_ALEN]; + } __packed tlv; + } data = { + .hdr = { + .omac_idx = mvif->omac_idx, + .dbdc_idx = mvif->band_idx, + .tlv_num = cpu_to_le16(1), + .is_tlv_append = 1, + }, + .tlv = { + .tag = cpu_to_le16(DEV_INFO_ACTIVE), + .len = cpu_to_le16(sizeof(struct req_tlv)), + .active = enable, + .dbdc_idx = mvif->band_idx, + }, + }; + + memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE, + &data, sizeof(data), true); +} + +static void +mt7915_mcu_beacon_csa(struct sk_buff *rskb, struct sk_buff *skb, + struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) +{ + if (offs->csa_counter_offs[0]) { + struct tlv *tlv; + struct bss_info_bcn_csa *csa; + + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CSA, + sizeof(*csa), &bcn->sub_ntlv, + &bcn->len); + csa = (struct bss_info_bcn_csa *)tlv; + csa->cnt = skb->data[offs->csa_counter_offs[0]]; + } +} + +static void +mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, + struct sk_buff *skb, struct bss_info_bcn *bcn, + struct ieee80211_mutable_offsets *offs) +{ + struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct bss_info_bcn_cont *cont; + struct tlv *tlv; + u8 *buf; + int len = sizeof(*cont) + MT_TXD_SIZE + skb->len; + + tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT, + len, &bcn->sub_ntlv, &bcn->len); + + cont = (struct bss_info_bcn_cont *)tlv; + cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); + cont->tim_ofs = cpu_to_le16(offs->tim_offset); + + if (offs->csa_counter_offs[0]) + cont->csa_ofs = cpu_to_le16(offs->csa_counter_offs[0] - 4); + + buf = (u8 *)tlv + sizeof(*cont); + mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, + true); + memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); +} + +int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int en) +{ +#define MAX_BEACON_SIZE 512 + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_mutable_offsets offs; + struct ieee80211_tx_info *info; + struct sk_buff *skb, *rskb; + struct tlv *tlv; + struct bss_info_bcn *bcn; + int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE; + + rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len); + if (IS_ERR(rskb)) + return PTR_ERR(rskb); + + tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); + bcn = (struct bss_info_bcn *)tlv; + bcn->enable = en; + + skb = ieee80211_beacon_get_template(hw, vif, &offs); + if (!skb) + return -EINVAL; + + if (skb->len > MAX_BEACON_SIZE - MT_TXD_SIZE) { + dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (mvif->band_idx) { + info = IEEE80211_SKB_CB(skb); + info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY; + } + + /* TODO: subtag - bss color count & 11v MBSSID */ + mt7915_mcu_beacon_csa(rskb, skb, bcn, &offs); + mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs); + dev_kfree_skb(skb); + + return __mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, + MCU_EXT_CMD_BSS_INFO_UPDATE, true); +} + +static int mt7915_mcu_send_firmware(struct mt7915_dev *dev, const void *data, + int len) +{ + int ret = 0, cur_len; + + while (len > 0) { + cur_len = min_t(int, 4096 - sizeof(struct mt7915_mcu_txd), + len); + + ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER, + data, cur_len, false); + if (ret) + break; + + data += cur_len; + len -= cur_len; + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); + } + + return ret; +} + +static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr, + u32 option) +{ + struct { + __le32 option; + __le32 addr; + } req = { + .option = cpu_to_le32(option), + .addr = cpu_to_le32(addr), + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, + &req, sizeof(req), true); +} + +static int mt7915_mcu_restart(struct mt76_dev *dev) +{ + struct { + u8 power_mode; + u8 rsv[3]; + } req = { + .power_mode = 1, + }; + + return __mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req, + sizeof(req), false); +} + +static int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get) +{ + struct { + __le32 op; + } req = { + .op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE), + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, + &req, sizeof(req), true); +} + +static int mt7915_mcu_start_patch(struct mt7915_dev *dev) +{ + struct { + u8 check_crc; + u8 reserved[3]; + } req = { + .check_crc = 0, + }; + + return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, + &req, sizeof(req), true); +} + +static int mt7915_driver_own(struct mt7915_dev *dev) +{ + u32 reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN); + if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN, + 0, 500)) { + dev_err(dev->mt76.dev, "Timeout for driver own\n"); + return -EIO; + } + + return 0; +} + +static int mt7915_mcu_init_download(struct mt7915_dev *dev, u32 addr, + u32 len, u32 mode) +{ + struct { + __le32 addr; + __le32 len; + __le32 mode; + } req = { + .addr = cpu_to_le32(addr), + .len = cpu_to_le32(len), + .mode = cpu_to_le32(mode), + }; + int attr; + + if (req.addr == MCU_PATCH_ADDRESS) + attr = -MCU_CMD_PATCH_START_REQ; + else + attr = -MCU_CMD_TARGET_ADDRESS_LEN_REQ; + + return __mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true); +} + +static int mt7915_load_patch(struct mt7915_dev *dev) +{ + const struct mt7915_patch_hdr *hdr; + const struct firmware *fw = NULL; + int i, ret, sem; + + sem = mt7915_mcu_patch_sem_ctrl(dev, 1); + switch (sem) { + case PATCH_IS_DL: + return 0; + case PATCH_NOT_DL_SEM_SUCCESS: + break; + default: + dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); + return -EAGAIN; + } + + ret = request_firmware(&fw, MT7915_ROM_PATCH, dev->mt76.dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_patch_hdr *)(fw->data); + + dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); + + for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { + struct mt7915_patch_sec *sec; + const u8 *dl; + u32 len, addr; + + sec = (struct mt7915_patch_sec *)(fw->data + sizeof(*hdr) + + i * sizeof(*sec)); + if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != + PATCH_SEC_TYPE_INFO) { + ret = -EINVAL; + goto out; + } + + addr = be32_to_cpu(sec->info.addr); + len = be32_to_cpu(sec->info.len); + dl = fw->data + be32_to_cpu(sec->offs); + + ret = mt7915_mcu_init_download(dev, addr, len, + DL_MODE_NEED_RSP); + if (ret) { + dev_err(dev->mt76.dev, "Download request failed\n"); + goto out; + } + + ret = mt7915_mcu_send_firmware(dev, dl, len); + if (ret) { + dev_err(dev->mt76.dev, "Failed to send patch\n"); + goto out; + } + } + + ret = mt7915_mcu_start_patch(dev); + if (ret) + dev_err(dev->mt76.dev, "Failed to start patch\n"); + +out: + sem = mt7915_mcu_patch_sem_ctrl(dev, 0); + switch (sem) { + case PATCH_REL_SEM_SUCCESS: + break; + default: + ret = -EAGAIN; + dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); + goto out; + } + release_firmware(fw); + + return ret; +} + +static u32 mt7915_mcu_gen_dl_mode(u8 feature_set, bool is_wa) +{ + u32 ret = 0; + + ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ? + (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0; + ret |= FIELD_PREP(DL_MODE_KEY_IDX, + FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); + ret |= DL_MODE_NEED_RSP; + ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; + + return ret; +} + +static int +mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev, + const struct mt7915_fw_trailer *hdr, + const u8 *data, bool is_wa) +{ + int i, offset = 0; + u32 override = 0, option = 0; + + for (i = 0; i < hdr->n_region; i++) { + const struct mt7915_fw_region *region; + int err; + u32 len, addr, mode; + + region = (const struct mt7915_fw_region *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + mode = mt7915_mcu_gen_dl_mode(region->feature_set, is_wa); + len = le32_to_cpu(region->len); + addr = le32_to_cpu(region->addr); + + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) + override = addr; + + err = mt7915_mcu_init_download(dev, addr, len, mode); + if (err) { + dev_err(dev->mt76.dev, "Download request failed\n"); + return err; + } + + err = mt7915_mcu_send_firmware(dev, data + offset, len); + if (err) { + dev_err(dev->mt76.dev, "Failed to send firmware.\n"); + return err; + } + + offset += len; + } + + if (override) + option |= FW_START_OVERRIDE; + + if (is_wa) + option |= FW_START_WORKING_PDA_CR4; + + return mt7915_mcu_start_firmware(dev, override, option); +} + +static int mt7915_load_ram(struct mt7915_dev *dev) +{ + const struct mt7915_fw_trailer *hdr; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, MT7915_FIRMWARE_WM, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - + sizeof(*hdr)); + + dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, false); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start WM firmware\n"); + goto out; + } + + release_firmware(fw); + + ret = request_firmware(&fw, MT7915_FIRMWARE_WA, dev->mt76.dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->mt76.dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const struct mt7915_fw_trailer *)(fw->data + fw->size - + sizeof(*hdr)); + + dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt7915_mcu_send_ram_firmware(dev, hdr, fw->data, true); + if (ret) { + dev_err(dev->mt76.dev, "Failed to start WA firmware\n"); + goto out; + } + + snprintf(dev->mt76.hw->wiphy->fw_version, + sizeof(dev->mt76.hw->wiphy->fw_version), + "%.10s-%.15s", hdr->fw_ver, hdr->build_date); + +out: + release_firmware(fw); + + return ret; +} + +static int mt7915_load_firmware(struct mt7915_dev *dev) +{ + int ret; + u32 val, reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); + + val = FIELD_PREP(MT_TOP_MISC_FW_STATE, FW_STATE_FW_DOWNLOAD); + + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, val, 1000)) { + /* restart firmware once */ + __mt76_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + val, 1000)) { + dev_err(dev->mt76.dev, + "Firmware is not ready for download\n"); + return -EIO; + } + } + + ret = mt7915_load_patch(dev); + if (ret) + return ret; + + ret = mt7915_load_ram(dev); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + FIELD_PREP(MT_TOP_MISC_FW_STATE, + FW_STATE_WACPU_RDY), 1000)) { + dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); + return -EIO; + } + + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); + + dev_dbg(dev->mt76.dev, "Firmware init done\n"); + + return 0; +} + +int mt7915_mcu_init(struct mt7915_dev *dev) +{ + static const struct mt76_mcu_ops mt7915_mcu_ops = { + .headroom = sizeof(struct mt7915_mcu_txd), + .mcu_skb_send_msg = mt7915_mcu_send_message, + .mcu_send_msg = mt7915_mcu_msg_send, + .mcu_restart = mt7915_mcu_restart, + }; + int ret; + + dev->mt76.mcu_ops = &mt7915_mcu_ops, + + ret = mt7915_driver_own(dev); + if (ret) + return ret; + + ret = mt7915_load_firmware(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} + +void mt7915_mcu_exit(struct mt7915_dev *dev) +{ + u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC); + + __mt76_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE, + FIELD_PREP(MT_TOP_MISC_FW_STATE, + FW_STATE_FW_DOWNLOAD), 1000)) { + dev_err(dev->mt76.dev, "Failed to exit mcu\n"); + return; + } + + reg = mt7915_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0); + mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN); + skb_queue_purge(&dev->mt76.mcu.res_q); +} + +int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, + bool enable, bool hdr_trans) +{ + struct { + u8 operation; + u8 enable; + u8 check_bssid; + u8 insert_vlan; + u8 remove_vlan; + u8 tid; + u8 mode; + u8 rsv; + } __packed req_trans = { + .enable = hdr_trans, + }; + struct { + u8 enable; + u8 band; + u8 rsv[2]; + } __packed req_mac = { + .enable = enable, + .band = band, + }; + int ret; + + ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS, + &req_trans, sizeof(req_trans), false); + if (ret) + return ret; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, + &req_mac, sizeof(req_mac), true); +} + +int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable) +{ + struct { + __le32 cmd; + u8 band; + u8 enable; + } __packed req = { + .cmd = cpu_to_le32(SCS_ENABLE), + .band = band, + .enable = enable + 1, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req, + sizeof(req), false); +} + +int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val) +{ + struct mt7915_dev *dev = phy->dev; + struct { + u8 prot_idx; + u8 band; + u8 rsv[2]; + __le32 len_thresh; + __le32 pkt_thresh; + } __packed req = { + .prot_idx = 1, + .band = phy != &dev->phy, + .len_thresh = cpu_to_le32(val), + .pkt_thresh = cpu_to_le32(0x2), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) +{ +#define WMM_AIFS_SET BIT(0) +#define WMM_CW_MIN_SET BIT(1) +#define WMM_CW_MAX_SET BIT(2) +#define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET GENMASK(3, 0) +#define TX_CMD_MODE 1 + struct edca { + u8 queue; + u8 set; + u8 aifs; + u8 cw_min; + __le16 cw_max; + __le16 txop; + }; + struct mt7915_mcu_tx { + u8 total; + u8 action; + u8 valid; + u8 mode; + + struct edca edca[IEEE80211_NUM_ACS]; + } __packed req = { + .valid = true, + .mode = TX_CMD_MODE, + .total = IEEE80211_NUM_ACS, + }; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct edca *e = &req.edca[ac]; + + e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS; + e->aifs = mvif->wmm[ac].aifs; + e->txop = cpu_to_le16(mvif->wmm[ac].txop); + + if (mvif->wmm[ac].cw_min) + e->cw_min = fls(mvif->wmm[ac].cw_max); + else + e->cw_min = 5; + + if (mvif->wmm[ac].cw_max) + e->cw_max = cpu_to_le16(fls(mvif->wmm[ac].cw_max)); + else + e->cw_max = cpu_to_le16(10); + } + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter) +{ +#define ENTER_PM_STATE 1 +#define EXIT_PM_STATE 2 + struct { + u8 pm_number; + u8 pm_state; + u8 bssid[ETH_ALEN]; + u8 dtim_period; + u8 wlan_idx_lo; + __le16 bcn_interval; + __le32 aid; + __le32 rx_filter; + u8 band_idx; + u8 wlan_idx_hi; + u8 rsv[2]; + __le32 feature; + u8 omac_idx; + u8 wmm_idx; + u8 bcn_loss_cnt; + u8 bcn_sp_duration; + } __packed req = { + .pm_number = 5, + .pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE, + .band_idx = band, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, + enum mt7915_rdd_cmd cmd, u8 index, + u8 rx_sel, u8 val) +{ + struct { + u8 ctrl; + u8 rdd_idx; + u8 rdd_rx_sel; + u8 val; + u8 rsv[4]; + } __packed req = { + .ctrl = cmd, + .rdd_idx = index, + .rdd_rx_sel = rx_sel, + .val = val, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) +{ + struct { + u32 tag; + u16 min_lpn; + u8 rsv[2]; + } __packed req = { + .tag = 0x1, + .min_lpn = val, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, + const struct mt7915_dfs_pulse *pulse) +{ + struct { + u32 tag; + struct mt7915_dfs_pulse pulse; + } __packed req = { + .tag = 0x3, + }; + + memcpy(&req.pulse, pulse, sizeof(*pulse)); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, + const struct mt7915_dfs_pattern *pattern) +{ + struct { + u32 tag; + u16 radar_type; + struct mt7915_dfs_pattern pattern; + } __packed req = { + .tag = 0x2, + .radar_type = index, + }; + + memcpy(&req.pattern, pattern, sizeof(*pattern)); + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) +{ + struct mt7915_dev *dev = phy->dev; + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + int freq1 = chandef->center_freq1; + struct { + u8 control_ch; + u8 center_ch; + u8 bw; + u8 tx_streams_num; + u8 rx_streams; /* mask or num */ + u8 switch_reason; + u8 band_idx; + u8 center_ch2; /* for 80+80 only */ + __le16 cac_case; + u8 channel_band; + u8 rsv0; + __le32 outband_freq; + u8 txpower_drop; + u8 ap_bw; + u8 ap_center_ch; + u8 rsv1[57]; + } __packed req = { + .control_ch = chandef->chan->hw_value, + .center_ch = ieee80211_frequency_to_channel(freq1), + .bw = mt7915_mcu_chan_bw(chandef), + .tx_streams_num = hweight8(phy->mt76->antenna_mask), + .rx_streams = phy->chainmask, + .band_idx = phy != &dev->phy, + .channel_band = chandef->chan->band, + }; + + if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + req.switch_reason = CH_SWITCH_DFS; + else + req.switch_reason = CH_SWITCH_NORMAL; + + if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH) + req.rx_streams = hweight8(req.rx_streams); + + if (chandef->width == NL80211_CHAN_WIDTH_80P80) { + int freq2 = chandef->center_freq2; + + req.center_ch2 = ieee80211_frequency_to_channel(freq2); + } + + return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); +} + +int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) +{ + struct req_hdr { + u8 buffer_mode; + u8 format; + __le16 len; + } __packed req = { + .buffer_mode = EE_MODE_EFUSE, + .format = EE_FORMAT_WHOLE, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE, + &req, sizeof(req), true); +} + +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) +{ + struct mt7915_mcu_eeprom_info req = { + .addr = cpu_to_le32(round_down(offset, 16)), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req, + sizeof(req), true); +} + +int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) +{ + struct { + u8 ctrl_id; + u8 action; + u8 band; + u8 rsv[5]; + } req = { + .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, + .action = index, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req, + sizeof(req), true); +} + +int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) +{ + struct { + __le32 cmd; + __le16 wlan_idx; + __le16 ru_idx; + __le16 direction; + __le16 dump_group; + } req = { + .cmd = cpu_to_le32(cmd), + .wlan_idx = cpu_to_le16(wlan_idx), + .dump_group = cpu_to_le16(1), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req, + sizeof(req), false); +} + +int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) +{ + struct { + u8 action; + u8 set; + u8 band; + u8 rsv; + } req = { + .action = action, + .set = set, + .band = band, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER, + &req, sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h new file mode 100644 index 000000000000..5e4708861ede --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -0,0 +1,837 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_MCU_H +#define __MT7915_MCU_H + +struct mt7915_mcu_txd { + __le32 txd[8]; + + __le16 len; + __le16 pq_id; + + u8 cid; + u8 pkt_type; + u8 set_query; /* FW don't care */ + u8 seq; + + u8 uc_d2b0_rev; + u8 ext_cid; + u8 s2d_index; + u8 ext_cid_ack; + + u32 reserved[5]; +} __packed __aligned(4); + +/* event table */ +enum { + MCU_EVENT_TARGET_ADDRESS_LEN = 0x01, + MCU_EVENT_FW_START = 0x01, + MCU_EVENT_GENERIC = 0x01, + MCU_EVENT_ACCESS_REG = 0x02, + MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_CH_PRIVILEGE = 0x18, + MCU_EVENT_EXT = 0xed, + MCU_EVENT_RESTART_DL = 0xef, +}; + +/* ext event table */ +enum { + MCU_EXT_EVENT_PS_SYNC = 0x5, + MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, + MCU_EXT_EVENT_ASSERT_DUMP = 0x23, + MCU_EXT_EVENT_RDD_REPORT = 0x3a, + MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, + MCU_EXT_EVENT_RATE_REPORT = 0x87, +}; + +struct mt7915_mcu_rxd { + __le32 rxd[6]; + + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + __le16 __rsv; + + u8 ext_eid; + u8 __rsv1[2]; + u8 s2d_index; +}; + +struct mt7915_mcu_rdd_report { + struct mt7915_mcu_rxd rxd; + + u8 idx; + u8 long_detected; + u8 constant_prf_detected; + u8 staggered_prf_detected; + u8 radar_type_idx; + u8 periodic_pulse_num; + u8 long_pulse_num; + u8 hw_pulse_num; + + u8 out_lpn; + u8 out_spn; + u8 out_crpn; + u8 out_crpw; + u8 out_crbn; + u8 out_stgpn; + u8 out_stgpw; + + u8 rsv; + + __le32 out_pri_const; + __le32 out_pri_stg[3]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 mdrdy_flag; + u8 rsv[3]; + } long_pulse[32]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 mdrdy_flag; + u8 rsv[3]; + } periodic_pulse[32]; + + struct { + __le32 start; + __le16 pulse_width; + __le16 pulse_power; + u8 sc_pass; + u8 sw_reset; + u8 mdrdy_flag; + u8 tx_active; + } hw_pulse[32]; +} __packed; + +struct mt7915_mcu_eeprom_info { + __le32 addr; + __le32 valid; + u8 data[16]; +} __packed; + +struct mt7915_mcu_ra_info { + struct mt7915_mcu_rxd rxd; + + __le32 event_id; + __le16 wlan_idx; + __le16 ru_idx; + __le16 direction; + __le16 dump_group; + + __le32 suggest_rate; + __le32 min_rate; /* for dynamic sounding */ + __le32 max_rate; /* for dynamic sounding */ + __le32 init_rate_down_rate; + + __le16 curr_rate; + __le16 init_rate_down_total; + __le16 init_rate_down_succ; + __le16 success; + __le16 attempts; + + __le16 prev_rate; + __le16 prob_up_rate; + u8 no_rate_up_cnt; + u8 ppdu_cnt; + u8 gi; + + u8 try_up_fail; + u8 try_up_total; + u8 suggest_wf; + u8 try_up_check; + u8 prob_up_period; + u8 prob_down_pending; +} __packed; + +#define MT_RA_RATE_NSS GENMASK(8, 6) +#define MT_RA_RATE_MCS GENMASK(3, 0) +#define MT_RA_RATE_TX_MODE GENMASK(12, 9) +#define MT_RA_RATE_DCM_EN BIT(4) +#define MT_RA_RATE_BW GENMASK(14, 13) + +#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) +#define MCU_PKT_ID 0xa0 + +enum { + MCU_Q_QUERY, + MCU_Q_SET, + MCU_Q_RESERVED, + MCU_Q_NA +}; + +enum { + MCU_S2D_H2N, + MCU_S2D_C2N, + MCU_S2D_H2C, + MCU_S2D_H2CN +}; + +enum { + MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, + MCU_CMD_FW_START_REQ = 0x02, + MCU_CMD_INIT_ACCESS_REG = 0x3, + MCU_CMD_NIC_POWER_CTRL = 0x4, + MCU_CMD_PATCH_START_REQ = 0x05, + MCU_CMD_PATCH_FINISH_REQ = 0x07, + MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_EXT_CID = 0xED, + MCU_CMD_FW_SCATTER = 0xEE, + MCU_CMD_RESTART_DL_REQ = 0xEF, +}; + +enum { + MCU_EXT_CMD_EFUSE_ACCESS = 0x01, + MCU_EXT_CMD_PM_STATE_CTRL = 0x07, + MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_STA_REC_UPDATE = 0x25, + MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, + MCU_EXT_CMD_EDCA_UPDATE = 0x27, + MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, + MCU_EXT_CMD_THERMAL_CTRL = 0x2c, + MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, + MCU_EXT_CMD_PROTECT_CTRL = 0x3e, + MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, + MCU_EXT_CMD_RX_HDR_TRANS = 0x47, + MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, + MCU_EXT_CMD_SCS_CTRL = 0x82, + MCU_EXT_CMD_RATE_CTRL = 0x87, + MCU_EXT_CMD_SET_RDD_TH = 0x9d, +}; + +enum { + PATCH_SEM_RELEASE, + PATCH_SEM_GET +}; + +enum { + PATCH_NOT_DL_SEM_FAIL, + PATCH_IS_DL, + PATCH_NOT_DL_SEM_SUCCESS, + PATCH_REL_SEM_SUCCESS +}; + +enum { + FW_STATE_INITIAL, + FW_STATE_FW_DOWNLOAD, + FW_STATE_NORMAL_OPERATION, + FW_STATE_NORMAL_TRX, + FW_STATE_WACPU_RDY = 7 +}; + +enum { + EE_MODE_EFUSE, + EE_MODE_BUFFER, +}; + +enum { + EE_FORMAT_BIN, + EE_FORMAT_WHOLE, + EE_FORMAT_MULTIPLE, +}; + +#define STA_TYPE_STA BIT(0) +#define STA_TYPE_AP BIT(1) +#define STA_TYPE_ADHOC BIT(2) +#define STA_TYPE_WDS BIT(4) +#define STA_TYPE_BC BIT(5) + +#define NETWORK_INFRA BIT(16) +#define NETWORK_P2P BIT(17) +#define NETWORK_IBSS BIT(18) +#define NETWORK_WDS BIT(21) + +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) +#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) + +#define CONN_STATE_DISCONNECT 0 +#define CONN_STATE_CONNECT 1 +#define CONN_STATE_PORT_SECURE 2 + +enum { + DEV_INFO_ACTIVE, + DEV_INFO_MAX_NUM +}; + +enum { + SCS_SEND_DATA, + SCS_SET_MANUAL_PD_TH, + SCS_CONFIG, + SCS_ENABLE, + SCS_SHOW_INFO, + SCS_GET_GLO_ADDR, + SCS_GET_GLO_ADDR_EVENT, +}; + +enum { + CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, + CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, + CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80, + CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160, + CMD_CBW_10MHZ, + CMD_CBW_5MHZ, + CMD_CBW_8080MHZ, + + CMD_HE_MCS_BW80 = 0, + CMD_HE_MCS_BW160, + CMD_HE_MCS_BW8080, + CMD_HE_MCS_BW_NUM +}; + +struct tlv { + __le16 tag; + __le16 len; +} __packed; + +struct bss_info_omac { + __le16 tag; + __le16 len; + u8 hw_bss_idx; + u8 omac_idx; + u8 band_idx; + u8 rsv0; + __le32 conn_type; + u32 rsv1; +} __packed; + +struct bss_info_basic { + __le16 tag; + __le16 len; + __le32 network_type; + u8 active; + u8 rsv0; + __le16 bcn_interval; + u8 bssid[ETH_ALEN]; + u8 wmm_idx; + u8 dtim_period; + u8 bmc_wcid_lo; + u8 cipher; + u8 phy_mode; + u8 max_bssid; /* max BSSID. range: 1 ~ 8, 0: MBSSID disabled */ + u8 non_tx_bssid;/* non-transmitted BSSID, 0: transmitted BSSID */ + u8 bmc_wcid_hi; /* high Byte and version */ + u8 rsv[2]; +} __packed; + +struct bss_info_rf_ch { + __le16 tag; + __le16 len; + u8 pri_ch; + u8 center_ch0; + u8 center_ch1; + u8 bw; + u8 he_ru26_block; /* 1: don't send HETB in RU26, 0: allow */ + u8 he_all_disable; /* 1: disallow all HETB, 0: allow */ + u8 rsv[2]; +} __packed; + +struct bss_info_ext_bss { + __le16 tag; + __le16 len; + __le32 mbss_tsf_offset; /* in unit of us */ + u8 rsv[8]; +} __packed; + +struct bss_info_sync_mode { + __le16 tag; + __le16 len; + __le16 bcn_interval; + u8 enable; + u8 dtim_period; + u8 rsv[8]; +} __packed; + +struct bss_info_bmc_rate { + __le16 tag; + __le16 len; + __le16 bc_trans; + __le16 mc_trans; + u8 short_preamble; + u8 rsv[7]; +} __packed; + +struct bss_info_ra { + __le16 tag; + __le16 len; + u8 op_mode; + u8 adhoc_en; + u8 short_preamble; + u8 tx_streams; + u8 rx_streams; + u8 algo; + u8 force_sgi; + u8 force_gf; + u8 ht_mode; + u8 has_20_sta; /* Check if any sta support GF. */ + u8 bss_width_trigger_events; + u8 vht_nss_cap; + u8 vht_bw_signal; /* not use */ + u8 vht_force_sgi; /* not use */ + u8 se_off; + u8 antenna_idx; + u8 train_up_rule; + u8 rsv[3]; + unsigned short train_up_high_thres; + short train_up_rule_rssi; + unsigned short low_traffic_thres; + __le16 max_phyrate; + __le32 phy_cap; + __le32 interval; + __le32 fast_interval; +} __packed; + +struct bss_info_bcn { + __le16 tag; + __le16 len; + u8 ver; + u8 enable; + __le16 sub_ntlv; +} __packed __aligned(4); + +struct bss_info_bcn_csa { + __le16 tag; + __le16 len; + u8 cnt; + u8 rsv[3]; +} __packed __aligned(4); + +struct bss_info_bcn_bcc { + __le16 tag; + __le16 len; + u8 cnt; + u8 rsv[3]; +} __packed __aligned(4); + +struct bss_info_bcn_mbss { +#define MAX_BEACON_NUM 32 + __le16 tag; + __le16 len; + __le32 bitmap; + __le16 offset[MAX_BEACON_NUM]; + u8 rsv[8]; +} __packed __aligned(4); + +struct bss_info_bcn_cont { + __le16 tag; + __le16 len; + __le16 tim_ofs; + __le16 csa_ofs; + __le16 bcc_ofs; + __le16 pkt_len; +} __packed __aligned(4); + +enum { + BSS_INFO_BCN_CSA, + BSS_INFO_BCN_BCC, + BSS_INFO_BCN_MBSSID, + BSS_INFO_BCN_CONTENT, + BSS_INFO_BCN_MAX +}; + +enum { + BSS_INFO_OMAC, + BSS_INFO_BASIC, + BSS_INFO_RF_CH, /* optional, for BT/LTE coex */ + BSS_INFO_PM, /* sta only */ + BSS_INFO_UAPSD, /* sta only */ + BSS_INFO_ROAM_DETECT, /* obsoleted */ + BSS_INFO_LQ_RM, /* obsoleted */ + BSS_INFO_EXT_BSS, + BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */ + BSS_INFO_SYNC_MODE, + BSS_INFO_RA, + BSS_INFO_HW_AMSDU, + BSS_INFO_BSS_COLOR, + BSS_INFO_HE_BASIC, + BSS_INFO_PROTECT_INFO, + BSS_INFO_OFFLOAD, + BSS_INFO_11V_MBSSID, + BSS_INFO_MAX_NUM +}; + +enum { + WTBL_RESET_AND_SET = 1, + WTBL_SET, + WTBL_QUERY, + WTBL_RESET_ALL +}; + +struct wtbl_req_hdr { + u8 wlan_idx_lo; + u8 operation; + __le16 tlv_num; + u8 wlan_idx_hi; + u8 rsv[3]; +} __packed; + +struct wtbl_generic { + __le16 tag; + __le16 len; + u8 peer_addr[ETH_ALEN]; + u8 muar_idx; + u8 skip_tx; + u8 cf_ack; + u8 qos; + u8 mesh; + u8 adm; + __le16 partial_aid; + u8 baf_en; + u8 aad_om; +} __packed; + +struct wtbl_rx { + __le16 tag; + __le16 len; + u8 rcid; + u8 rca1; + u8 rca2; + u8 rv; + u8 rsv[4]; +} __packed; + +struct wtbl_ht { + __le16 tag; + __le16 len; + u8 ht; + u8 ldpc; + u8 af; + u8 mm; + u8 rsv[4]; +} __packed; + +struct wtbl_vht { + __le16 tag; + __le16 len; + u8 ldpc; + u8 dyn_bw; + u8 vht; + u8 txop_ps; + u8 rsv[4]; +} __packed; + +enum { + MT_BA_TYPE_INVALID, + MT_BA_TYPE_ORIGINATOR, + MT_BA_TYPE_RECIPIENT +}; + +enum { + RST_BA_MAC_TID_MATCH, + RST_BA_MAC_MATCH, + RST_BA_NO_MATCH +}; + +struct wtbl_ba { + __le16 tag; + __le16 len; + /* common */ + u8 tid; + u8 ba_type; + u8 rsv0[2]; + /* originator only */ + __le16 sn; + u8 ba_en; + u8 ba_winsize_idx; + __le16 ba_winsize; + /* recipient only */ + u8 peer_addr[ETH_ALEN]; + u8 rst_ba_tid; + u8 rst_ba_sel; + u8 rst_ba_sb; + u8 band_idx; + u8 rsv1[4]; +} __packed; + +struct wtbl_bf { + __le16 tag; + __le16 len; + u8 ibf; + u8 ebf; + u8 ibf_vht; + u8 ebf_vht; + u8 gid; + u8 pfmu_idx; + u8 rsv[2]; +} __packed; + +struct wtbl_smps { + __le16 tag; + __le16 len; + u8 smps; + u8 rsv[3]; +} __packed; + +struct wtbl_spe { + __le16 tag; + __le16 len; + u8 spe_idx; + u8 rsv[3]; +} __packed; + +enum { + WTBL_GENERIC, + WTBL_RX, + WTBL_HT, + WTBL_VHT, + WTBL_PEER_PS, /* not used */ + WTBL_TX_PS, + WTBL_HDR_TRANS, + WTBL_SEC_KEY, + WTBL_BA, + WTBL_RDG, /* obsoleted */ + WTBL_PROTECT, /* not used */ + WTBL_CLEAR, /* not used */ + WTBL_BF, + WTBL_SMPS, + WTBL_RAW_DATA, /* debug only */ + WTBL_PN, + WTBL_SPE, + WTBL_MAX_NUM +}; + +struct sta_ntlv_hdr { + u8 rsv[2]; + __le16 tlv_num; +} __packed; + +struct sta_req_hdr { + u8 bss_idx; + u8 wlan_idx_lo; + __le16 tlv_num; + u8 is_tlv_append; + u8 muar_idx; + u8 wlan_idx_hi; + u8 rsv; +} __packed; + +struct sta_rec_basic { + __le16 tag; + __le16 len; + __le32 conn_type; + u8 conn_state; + u8 qos; + __le16 aid; + u8 peer_addr[ETH_ALEN]; + __le16 extra_info; +} __packed; + +struct sta_rec_ht { + __le16 tag; + __le16 len; + __le16 ht_cap; + u16 rsv; +} __packed; + +struct sta_rec_vht { + __le16 tag; + __le16 len; + __le32 vht_cap; + __le16 vht_rx_mcs_map; + __le16 vht_tx_mcs_map; + u8 rts_bw_sig; + u8 rsv[3]; +} __packed; + +struct sta_rec_ba { + __le16 tag; + __le16 len; + u8 tid; + u8 ba_type; + u8 amsdu; + u8 ba_en; + __le16 ssn; + __le16 winsize; +} __packed; + +struct sec_key { + u8 cipher_id; + u8 cipher_len; + u8 key_id; + u8 key_len; + u8 key[32]; +} __packed; + +struct sta_rec_sec { + __le16 tag; + __le16 len; + u8 add; + u8 n_cipher; + u8 rsv[2]; + + struct sec_key key[2]; +} __packed; + +struct ra_phy { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; +}; + +struct sta_rec_ra { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_status; + + struct ra_phy phy; +} __packed; + +enum { + STA_REC_BASIC, + STA_REC_RA, + STA_REC_RA_CMM_INFO, + STA_REC_RA_UPDATE, + STA_REC_BF, + STA_REC_AMSDU, + STA_REC_BA, + STA_REC_RED, /* not used */ + STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */ + STA_REC_HT, + STA_REC_VHT, + STA_REC_APPS, + STA_REC_KEY, + STA_REC_WTBL, + STA_REC_HE, + STA_REC_HW_AMSDU, + STA_REC_WTBL_AADOM, + STA_REC_KEY_V2, + STA_REC_MURU, + STA_REC_MUEDCA, + STA_REC_MAX_NUM +}; + +enum mt7915_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_WEP104, + MT_CIPHER_WEP128, + MT_CIPHER_TKIP, + MT_CIPHER_AES_CCMP, + MT_CIPHER_CCMP_256, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, + MT_CIPHER_WAPI, + MT_CIPHER_BIP_CMAC_128, +}; + +enum { + CH_SWITCH_NORMAL = 0, + CH_SWITCH_SCAN = 3, + CH_SWITCH_MCC = 4, + CH_SWITCH_DFS = 5, + CH_SWITCH_BACKGROUND_SCAN_START = 6, + CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7, + CH_SWITCH_BACKGROUND_SCAN_STOP = 8, + CH_SWITCH_SCAN_BYPASS_DPD = 9 +}; + +enum { + THERMAL_SENSOR_TEMP_QUERY, + THERMAL_SENSOR_MANUAL_CTRL, + THERMAL_SENSOR_INFO_QUERY, + THERMAL_SENSOR_TASK_CTRL, +}; + +#define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_generic) + \ + sizeof(struct wtbl_rx) + \ + sizeof(struct wtbl_ht) + \ + sizeof(struct wtbl_vht) + \ + sizeof(struct wtbl_ba) + \ + sizeof(struct wtbl_bf) + \ + sizeof(struct wtbl_smps) + \ + sizeof(struct wtbl_spe)) + +#define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct sta_rec_basic) + \ + sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_ba) + \ + sizeof(struct sta_rec_vht) + \ + sizeof(struct tlv) + \ + sizeof(struct sta_rec_sec) + \ + sizeof(struct sta_rec_ra) + \ + MT7915_WTBL_UPDATE_MAX_SIZE) + +#define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ + sizeof(struct wtbl_ba)) + +#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct bss_info_bcn_csa) + \ + sizeof(struct bss_info_bcn_bcc) + \ + sizeof(struct bss_info_bcn_mbss) + \ + sizeof(struct bss_info_bcn_cont)) + +#define PHY_MODE_A BIT(0) +#define PHY_MODE_B BIT(1) +#define PHY_MODE_G BIT(2) +#define PHY_MODE_GN BIT(3) +#define PHY_MODE_AN BIT(4) +#define PHY_MODE_AC BIT(5) + +#define MODE_CCK BIT(0) +#define MODE_OFDM BIT(1) +#define MODE_HT BIT(2) +#define MODE_VHT BIT(3) + +#define STA_CAP_WMM BIT(0) +#define STA_CAP_SGI_20 BIT(4) +#define STA_CAP_SGI_40 BIT(5) +#define STA_CAP_TX_STBC BIT(6) +#define STA_CAP_RX_STBC BIT(7) +#define STA_CAP_VHT_SGI_80 BIT(16) +#define STA_CAP_VHT_SGI_160 BIT(17) +#define STA_CAP_VHT_TX_STBC BIT(18) +#define STA_CAP_VHT_RX_STBC BIT(19) +#define STA_CAP_VHT_LDPC BIT(23) +#define STA_CAP_LDPC BIT(24) +#define STA_CAP_HT BIT(26) +#define STA_CAP_VHT BIT(27) + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h new file mode 100644 index 000000000000..b23ab3f215e0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_H +#define __MT7915_H + +#include +#include +#include "../mt76.h" +#include "regs.h" + +#define MT7915_MAX_INTERFACES 4 +#define MT7915_MAX_WMM_SETS 4 +#define MT7915_WTBL_SIZE 288 +#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1) +#define MT7915_WTBL_STA (MT7915_WTBL_RESERVED - \ + MT7915_MAX_INTERFACES) + +#define MT7915_WATCHDOG_TIME (HZ / 10) +#define MT7915_RESET_TIMEOUT (30 * HZ) + +#define MT7915_TX_RING_SIZE 2048 +#define MT7915_TX_MCU_RING_SIZE 256 +#define MT7915_TX_FWDL_RING_SIZE 128 + +#define MT7915_RX_RING_SIZE 1536 +#define MT7915_RX_MCU_RING_SIZE 512 + +#define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin" +#define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin" +#define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" + +#define MT7915_EEPROM_SIZE 3584 +#define MT7915_TOKEN_SIZE 8192 + +#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ +#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ +#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ + + +struct mt7915_vif; +struct mt7915_sta; +struct mt7915_dfs_pulse; +struct mt7915_dfs_pattern; + +enum mt7915_txq_id { + MT7915_TXQ_FWDL = 16, + MT7915_TXQ_MCU_WM, + MT7915_TXQ_BAND0, + MT7915_TXQ_BAND1, + MT7915_TXQ_MCU_WA, +}; + +enum mt7915_rxq_id { + MT7915_RXQ_BAND0 = 0, + MT7915_RXQ_BAND1, + MT7915_RXQ_MCU_WM = 0, + MT7915_RXQ_MCU_WA, +}; + +enum mt7915_ampdu_state { + MT7915_AGGR_STOP, + MT7915_AGGR_PROGRESS, + MT7915_AGGR_START, + MT7915_AGGR_OPERATIONAL +}; + +struct mt7915_sta_stats { + struct rate_info prob_rate; + struct rate_info tx_rate; + + unsigned long per; + unsigned long changed; + unsigned long jiffies; +}; + +struct mt7915_sta { + struct mt76_wcid wcid; /* must be first */ + + struct mt7915_vif *vif; + + struct list_head poll_list; + u32 airtime_ac[8]; + + struct mt7915_sta_stats stats; + struct work_struct stats_work; + + spinlock_t ampdu_lock; + enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS]; +}; + +struct mt7915_vif { + u16 idx; + u8 omac_idx; + u8 band_idx; + u8 wmm_idx; + + struct { + u16 cw_min; + u16 cw_max; + u16 txop; + u8 aifs; + } wmm[IEEE80211_NUM_ACS]; + + struct mt7915_sta sta; + struct mt7915_dev *dev; +}; + +struct mib_stats { + u16 ack_fail_cnt; + u16 fcs_err_cnt; + u16 rts_cnt; + u16 rts_retries_cnt; + u16 ba_miss_cnt; +}; + +struct mt7915_phy { + struct mt76_phy *mt76; + struct mt7915_dev *dev; + + u32 rxfilter; + u32 vif_mask; + u32 omac_mask; + + u16 noise; + u16 chainmask; + + s16 coverage_class; + u8 slottime; + + u8 rdd_state; + int dfs_state; + + __le32 rx_ampdu_ts; + u32 ampdu_ref; + + struct mib_stats mib; +}; + +struct mt7915_dev { + union { /* must be first */ + struct mt76_dev mt76; + struct mt76_phy mphy; + }; + + struct mt7915_phy phy; + + u16 chainmask; + + struct work_struct init_work; + struct work_struct reset_work; + wait_queue_head_t reset_wait; + u32 reset_state; + + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + + u32 hw_pattern; + + spinlock_t token_lock; + struct idr token; + + u8 mac_work_count; + bool fw_debug; +}; + +enum { + HW_BSSID_0 = 0x0, + HW_BSSID_1, + HW_BSSID_2, + HW_BSSID_3, + HW_BSSID_MAX, + EXT_BSSID_START = 0x10, + EXT_BSSID_1, + EXT_BSSID_2, + EXT_BSSID_3, + EXT_BSSID_4, + EXT_BSSID_5, + EXT_BSSID_6, + EXT_BSSID_7, + EXT_BSSID_8, + EXT_BSSID_9, + EXT_BSSID_10, + EXT_BSSID_11, + EXT_BSSID_12, + EXT_BSSID_13, + EXT_BSSID_14, + EXT_BSSID_15, + EXT_BSSID_END +}; + +enum { + MT_RX_SEL0, + MT_RX_SEL1, +}; + +enum mt7915_rdd_cmd { + RDD_STOP, + RDD_START, + RDD_DET_MODE, + RDD_RADAR_EMULATE, + RDD_START_TXQ = 20, + RDD_CAC_START = 50, + RDD_CAC_END, + RDD_NORMAL_START, + RDD_DISABLE_DFS_CAL, + RDD_PULSE_DBG, + RDD_READ_PULSE, + RDD_RESUME_BF, + RDD_IRQ_OFF, +}; + +enum { + RATE_CTRL_RU_INFO, + RATE_CTRL_FIXED_RATE_INFO, + RATE_CTRL_DUMP_INFO, + RATE_CTRL_MU_INFO, +}; + +static inline struct mt7915_phy * +mt7915_hw_phy(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return phy->priv; +} + +static inline struct mt7915_dev * +mt7915_hw_dev(struct ieee80211_hw *hw) +{ + struct mt76_phy *phy = hw->priv; + + return container_of(phy->dev, struct mt7915_dev, mt76); +} + +static inline struct mt7915_phy * +mt7915_ext_phy(struct mt7915_dev *dev) +{ + struct mt76_phy *phy = dev->mt76.phy2; + + if (!phy) + return NULL; + + return phy->priv; +} + +static inline void +mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid, + enum mt7915_ampdu_state state) +{ + spin_lock_bh(&msta->ampdu_lock); + msta->ampdu_state[tid] = state; + spin_unlock_bh(&msta->ampdu_lock); +} + +extern const struct ieee80211_ops mt7915_ops; +extern struct pci_driver mt7915_pci_driver; + +u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr); + +int mt7915_register_device(struct mt7915_dev *dev); +void mt7915_unregister_device(struct mt7915_dev *dev); +int mt7915_register_ext_phy(struct mt7915_dev *dev); +void mt7915_unregister_ext_phy(struct mt7915_dev *dev); +int mt7915_eeprom_init(struct mt7915_dev *dev); +u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset); +int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, + struct ieee80211_channel *chan, + u8 chain_idx); +int mt7915_dma_init(struct mt7915_dev *dev); +void mt7915_dma_prefetch(struct mt7915_dev *dev); +void mt7915_dma_cleanup(struct mt7915_dev *dev); +int mt7915_mcu_init(struct mt7915_dev *dev); +int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable); +int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, + struct ieee80211_vif *vif, int enable); +int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable); +int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool add); +int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, + struct ieee80211_ampdu_params *params, + bool add); +int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct mt7915_sta *msta, struct ieee80211_key_conf *key, + enum set_key_cmd cmd); +int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int enable); +int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); +int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); +int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); +int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, + bool hdr_trans); +int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable); +int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); +int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); +int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); +int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); +int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, + const struct mt7915_dfs_pulse *pulse); +int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, + const struct mt7915_dfs_pattern *pattern); +int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); +int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); +int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd, + u8 index, u8 rx_sel, u8 val); +void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb); +void mt7915_mcu_exit(struct mt7915_dev *dev); + +static inline bool is_mt7915(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7915; +} + +static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) +{ + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); +} + +static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) +{ + mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); +} + +static inline u32 +mt7915_reg_map_l1(struct mt7915_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); + + mt76_rmw_field(dev, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, base); + /* use read to push write */ + mt76_rr(dev, MT_HIF_REMAP_L1); + + return MT_HIF_REMAP_BASE_L1 + offset; +} + +static inline u32 +mt7915_l1_rr(struct mt7915_dev *dev, u32 addr) +{ + return mt76_rr(dev, mt7915_reg_map_l1(dev, addr)); +} + +static inline void +mt7915_l1_wr(struct mt7915_dev *dev, u32 addr, u32 val) +{ + mt76_wr(dev, mt7915_reg_map_l1(dev, addr), val); +} + +static inline u32 +mt7915_l1_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val) +{ + val |= mt7915_l1_rr(dev, addr) & ~mask; + mt7915_l1_wr(dev, addr, val); + + return val; +} + +#define mt7915_l1_set(dev, addr, val) mt7915_l1_rmw(dev, addr, 0, val) +#define mt7915_l1_clear(dev, addr, val) mt7915_l1_rmw(dev, addr, val, 0) + +static inline u32 +mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); + + mt76_rmw_field(dev, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, base); + /* use read to push write */ + mt76_rr(dev, MT_HIF_REMAP_L2); + + return MT_HIF_REMAP_BASE_L2 + offset; +} + +static inline u32 +mt7915_l2_rr(struct mt7915_dev *dev, u32 addr) +{ + return mt76_rr(dev, mt7915_reg_map_l2(dev, addr)); +} + +static inline void +mt7915_l2_wr(struct mt7915_dev *dev, u32 addr, u32 val) +{ + mt76_wr(dev, mt7915_reg_map_l2(dev, addr), val); +} + +static inline u32 +mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val) +{ + val |= mt7915_l2_rr(dev, addr) & ~mask; + mt7915_l2_wr(dev, addr, val); + + return val; +} + +#define mt7915_l2_set(dev, addr, val) mt7915_l2_rmw(dev, addr, 0, val) +#define mt7915_l2_clear(dev, addr, val) mt7915_l2_rmw(dev, addr, val, 0) + +bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); +void mt7915_mac_reset_counters(struct mt7915_phy *phy); +void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); +void mt7915_mac_sta_poll(struct mt7915_dev *dev); +void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, bool beacon); +void mt7915_mac_set_timing(struct mt7915_phy *phy); +int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb); +void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb); +int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7915_mac_work(struct work_struct *work); +void mt7915_mac_reset_work(struct work_struct *work); +void mt7915_mac_sta_stats_work(struct work_struct *work); +int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, + struct mt76_queue_entry *e); +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb); +void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); +void mt7915_stats_work(struct work_struct *work); +void mt7915_txp_skb_unmap(struct mt76_dev *dev, + struct mt76_txwi_cache *txwi); +int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); +int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); +void mt7915_update_channel(struct mt76_dev *mdev); +int mt7915_init_debugfs(struct mt7915_dev *dev); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c new file mode 100644 index 000000000000..b79b5060cd77 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Ryder Lee + */ + +#include +#include +#include + +#include "mt7915.h" +#include "mac.h" +#include "../trace.h" + +static const struct pci_device_id mt7915_pci_device_table[] = { + { PCI_DEVICE(0x14c3, 0x7915) }, + { }, +}; + +static void +mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_irq_enable(dev, MT_INT_RX_DONE(q)); +} + +/* TODO: support 2/4/6/8 MSI-X vectors */ +static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +{ + struct mt7915_dev *dev = dev_instance; + u32 intr; + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return IRQ_NONE; + + trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); + + intr &= dev->mt76.mmio.irqmask; + + if (intr & MT_INT_TX_DONE_ALL) { + mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL); + napi_schedule(&dev->mt76.tx_napi); + } + + if (intr & MT_INT_RX_DONE_DATA) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA); + napi_schedule(&dev->mt76.napi[0]); + } + + if (intr & MT_INT_RX_DONE_WM) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_WM); + napi_schedule(&dev->mt76.napi[1]); + } + + if (intr & MT_INT_RX_DONE_WA) { + mt7915_irq_disable(dev, MT_INT_RX_DONE_WA); + napi_schedule(&dev->mt76.napi[2]); + } + + if (intr & MT_INT_MCU_CMD) { + u32 val = mt76_rr(dev, MT_MCU_CMD); + + mt76_wr(dev, MT_MCU_CMD, val); + if (val & MT_MCU_CMD_ERROR_MASK) { + dev->reset_state = val; + ieee80211_queue_work(mt76_hw(dev), &dev->reset_work); + wake_up(&dev->reset_wait); + } + } + + return IRQ_HANDLED; +} + +static int mt7915_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + /* txwi_size = txd size + txp size */ + .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), + .drv_flags = MT_DRV_TXWI_NO_FREE, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, + .tx_prepare_skb = mt7915_tx_prepare_skb, + .tx_complete_skb = mt7915_tx_complete_skb, + .rx_skb = mt7915_queue_rx_skb, + .rx_poll_complete = mt7915_rx_poll_complete, + .sta_ps = mt7915_sta_ps, + .sta_add = mt7915_mac_sta_add, + .sta_remove = mt7915_mac_sta_remove, + .update_survey = mt7915_update_channel, + }; + struct mt7915_dev *dev; + struct mt76_dev *mdev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops, + &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7915_dev, mt76); + + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | + (mt7915_l1_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + /* master switch of PCIe tnterrupt enable */ + mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto error; + + ret = mt7915_register_device(dev); + if (ret) + goto error; + + return 0; +error: + ieee80211_free_hw(mt76_hw(dev)); + return ret; +} + +static void mt7915_pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + + mt7915_unregister_device(dev); +} + +struct pci_driver mt7915_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7915_pci_device_table, + .probe = mt7915_pci_probe, + .remove = mt7915_pci_remove, +}; + +module_pci_driver(mt7915_pci_driver); + +MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); +MODULE_FIRMWARE(MT7915_FIRMWARE_WA); +MODULE_FIRMWARE(MT7915_FIRMWARE_WM); +MODULE_FIRMWARE(MT7915_ROM_PATCH); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h new file mode 100644 index 000000000000..ef87579056fe --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2020 MediaTek Inc. */ + +#ifndef __MT7915_REGS_H +#define __MT7915_REGS_H + +/* MCU WFDMA1 */ +#define MT_MCU_WFDMA1_BASE 0x3000 +#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs)) + +#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108) +#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) +#define MT_MCU_INT_EVENT_DMA_INIT BIT(1) +#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) +#define MT_MCU_INT_EVENT_RESET_DONE BIT(3) + +#define MT_PLE_BASE 0x8000 +#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) + +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) + +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ + ((n) << 2)) +#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) + +#define MT_MDP_BASE 0xf000 +#define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + +#define MT_MDP_DCR0 MT_MDP(0x000) +#define MT_MDP_DCR0_DAMSDU_EN BIT(15) + +#define MT_MDP_DCR1 MT_MDP(0x004) +#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3) + +#define MT_MDP_BNRCFR0(_band) MT_MDP(0x070 + ((_band) << 8)) +#define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4) +#define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6) +#define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8) + +#define MT_MDP_BNRCFR1(_band) MT_MDP(0x074 + ((_band) << 8)) +#define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22) +#define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27) +#define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29) +#define MT_MDP_TO_HIF 0 +#define MT_MDP_TO_WM 1 + +/* TMAC: band 0(0x21000), band 1(0xa1000) */ +#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000) +#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) + +#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090) +#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094) +#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) +#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) + +#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) +#define MT_IFS_EIFS GENMASK(8, 0) +#define MT_IFS_RIFS GENMASK(14, 10) +#define MT_IFS_SIFS GENMASK(22, 16) +#define MT_IFS_SLOT GENMASK(30, 24) + +#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4) +#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) +#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) +#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) + +/* DMA Band 0 */ +#define MT_WF_DMA_BASE 0x21e00 +#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) + +#define MT_DMA_DCR0 MT_WF_DMA(0x000) +#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) + +/* MIB: band 0(0x24800), band 1(0xa4800) */ +#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) +#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) + +#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) +#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) + +#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) +#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) +#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) +#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) +#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) + +#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) +#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) +#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) + +#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4)) +#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) +#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) + +#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) +#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) + +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2)) +#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2)) +#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2)) +#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0)) + +#define MT_WTBLON_TOP_BASE 0x34000 +#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) +#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x0) +#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0) + +#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x030) +#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) +#define MT_WTBL_UPDATE_BUSY BIT(31) + +#define MT_WTBL_BASE 0x38000 +#define MT_WTBL_LMAC_ID GENMASK(14, 8) +#define MT_WTBL_LMAC_DW GENMASK(7, 2) +#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \ + FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ + FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) + +/* AGG: band 0(0x20800), band 1(0xa0800) */ +#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800) +#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs)) + +#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084) +#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) +#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) + +/* ARB: band 0(0x20c00), band 1(0xa0c00) */ +#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00) +#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs)) + +#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080) +#define MT_ARB_SCR_TX_DISABLE BIT(8) +#define MT_ARB_SCR_RX_DISABLE BIT(9) + +/* RMAC: band 0(0x21400), band 1(0xa1400) */ +#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400) +#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) + +#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) +#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) +#define MT_WF_RFCR_DROP_FCSFAIL BIT(1) +#define MT_WF_RFCR_DROP_VERSION BIT(3) +#define MT_WF_RFCR_DROP_PROBEREQ BIT(4) +#define MT_WF_RFCR_DROP_MCAST BIT(5) +#define MT_WF_RFCR_DROP_BCAST BIT(6) +#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) +#define MT_WF_RFCR_DROP_A3_MAC BIT(8) +#define MT_WF_RFCR_DROP_A3_BSSID BIT(9) +#define MT_WF_RFCR_DROP_A2_BSSID BIT(10) +#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) +#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) +#define MT_WF_RFCR_DROP_CTL_RSV BIT(13) +#define MT_WF_RFCR_DROP_CTS BIT(14) +#define MT_WF_RFCR_DROP_RTS BIT(15) +#define MT_WF_RFCR_DROP_DUPLICATE BIT(16) +#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) +#define MT_WF_RFCR_DROP_OTHER_UC BIT(18) +#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) +#define MT_WF_RFCR_DROP_NDPA BIT(20) +#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) + +#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) +#define MT_WF_RFCR1_DROP_ACK BIT(4) +#define MT_WF_RFCR1_DROP_BF_POLL BIT(5) +#define MT_WF_RFCR1_DROP_BA BIT(6) +#define MT_WF_RFCR1_DROP_CFEND BIT(7) +#define MT_WF_RFCR1_DROP_CFACK BIT(8) + +#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) +#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) + +#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) +#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) + +/* WFDMA0 */ +#define MT_WFDMA0_BASE 0xd4000 +#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) + +#define MT_WFDMA0_RST MT_WFDMA0(0x100) +#define MT_WFDMA0_RST_LOGIC_RST BIT(4) +#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) + +#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) +#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) + +#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) +#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) + +#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x500) + +#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680) +#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684) +#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688) + +/* WFDMA1 */ +#define MT_WFDMA1_BASE 0xd5000 +#define MT_WFDMA1(ofs) (MT_WFDMA1_BASE + (ofs)) + +#define MT_WFDMA1_RST MT_WFDMA1(0x100) +#define MT_WFDMA1_RST_LOGIC_RST BIT(4) +#define MT_WFDMA1_RST_DMASHDL_ALL_RST BIT(5) + +#define MT_WFDMA1_BUSY_ENA MT_WFDMA1(0x13c) +#define MT_WFDMA1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA1_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_MCU_CMD MT_WFDMA1(0x1f0) +#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1) +#define MT_MCU_CMD_STOP_DMA BIT(2) +#define MT_MCU_CMD_RESET_DONE BIT(3) +#define MT_MCU_CMD_RECOVERY_DONE BIT(4) +#define MT_MCU_CMD_NORMAL_STATE BIT(5) +#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) + +#define MT_WFDMA1_GLO_CFG MT_WFDMA1(0x208) +#define MT_WFDMA1_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WFDMA1_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WFDMA1_GLO_CFG_OMIT_TX_INFO BIT(28) +#define MT_WFDMA1_GLO_CFG_OMIT_RX_INFO BIT(27) + +#define MT_WFDMA1_RST_DTX_PTR MT_WFDMA1(0x20c) +#define MT_WFDMA1_PRI_DLY_INT_CFG0 MT_WFDMA1(0x2f0) + +#define MT_TX_RING_BASE MT_WFDMA1(0x300) +#define MT_RX_EVENT_RING_BASE MT_WFDMA1(0x500) + +#define MT_WFDMA1_TX_RING0_EXT_CTRL MT_WFDMA1(0x600) +#define MT_WFDMA1_TX_RING1_EXT_CTRL MT_WFDMA1(0x604) +#define MT_WFDMA1_TX_RING2_EXT_CTRL MT_WFDMA1(0x608) +#define MT_WFDMA1_TX_RING3_EXT_CTRL MT_WFDMA1(0x60c) +#define MT_WFDMA1_TX_RING4_EXT_CTRL MT_WFDMA1(0x610) +#define MT_WFDMA1_TX_RING5_EXT_CTRL MT_WFDMA1(0x614) +#define MT_WFDMA1_TX_RING6_EXT_CTRL MT_WFDMA1(0x618) +#define MT_WFDMA1_TX_RING7_EXT_CTRL MT_WFDMA1(0x61c) + +#define MT_WFDMA1_TX_RING16_EXT_CTRL MT_WFDMA1(0x640) +#define MT_WFDMA1_TX_RING17_EXT_CTRL MT_WFDMA1(0x644) +#define MT_WFDMA1_TX_RING18_EXT_CTRL MT_WFDMA1(0x648) +#define MT_WFDMA1_TX_RING19_EXT_CTRL MT_WFDMA1(0x64c) +#define MT_WFDMA1_TX_RING20_EXT_CTRL MT_WFDMA1(0x650) +#define MT_WFDMA1_TX_RING21_EXT_CTRL MT_WFDMA1(0x654) +#define MT_WFDMA1_TX_RING22_EXT_CTRL MT_WFDMA1(0x658) +#define MT_WFDMA1_TX_RING23_EXT_CTRL MT_WFDMA1(0x65c) + +#define MT_WFDMA1_RX_RING0_EXT_CTRL MT_WFDMA1(0x680) +#define MT_WFDMA1_RX_RING1_EXT_CTRL MT_WFDMA1(0x684) +#define MT_WFDMA1_RX_RING2_EXT_CTRL MT_WFDMA1(0x688) +#define MT_WFDMA1_RX_RING3_EXT_CTRL MT_WFDMA1(0x68c) + +/* WFDMA CSR */ +#define MT_WFDMA_EXT_CSR_BASE 0xd7000 +#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) + +#define MT_INT_SOURCE_CSR MT_WFDMA_EXT_CSR(0x10) +#define MT_INT_MASK_CSR MT_WFDMA_EXT_CSR(0x14) +#define MT_INT_RX_DONE_DATA BIT(16) +#define MT_INT_RX_DONE_WM BIT(0) +#define MT_INT_RX_DONE_WA BIT(1) +#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16)) +#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16)) +#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30)) +#define MT_INT_MCU_CMD BIT(29) + +#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) +#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) + +/* WFDMA0 PCIE1 */ +#define MT_WFDMA0_PCIE1_BASE 0xd8000 +#define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) + +#define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) +#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO BIT(2) + +/* WFDMA1 PCIE1 */ +#define MT_WFDMA1_PCIE1_BASE 0xd9000 +#define MT_WFDMA1_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) + +#define MT_WFDMA1_PCIE1_BUSY_ENA MT_WFDMA1_PCIE1(0x13c) +#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) +#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) +#define MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO BIT(2) + +#define MT_INFRA_CFG_BASE 0xf1000 +#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs)) + +#define MT_HIF_REMAP_L1 MT_INFRA(0x1ac) +#define MT_HIF_REMAP_L1_MASK GENMASK(15, 0) +#define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) +#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_L1 0xe0000 + +#define MT_HIF_REMAP_L2 MT_INFRA(0x1b0) +#define MT_HIF_REMAP_L2_MASK GENMASK(19, 0) +#define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0) +#define MT_HIF_REMAP_L2_BASE GENMASK(31, 12) +#define MT_HIF_REMAP_BASE_L2 0x00000 + +#define MT_TOP_BASE 0x18060000 +#define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) + +#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10) +#define MT_TOP_LPCR_HOST_FW_OWN BIT(0) +#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) + +#define MT_TOP_MISC MT_TOP(0xf0) +#define MT_TOP_MISC_FW_STATE GENMASK(2, 0) + +#define MT_HW_BOUND 0x70010020 +#define MT_HW_CHIPID 0x70010200 +#define MT_HW_REV 0x70010204 + +#define MT_PCIE_MAC_BASE 0x74030000 +#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) +#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) + +/* PHY: band 0(0x83080000), band 1(0x83090000) */ +#define MT_WF_PHY_BASE 0x83080000 +#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) + +#define MT_WF_PHY_RX_CTRL1(_phy) MT_WF_PHY(0x2004 + ((_phy) << 16)) +#define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9) + +#endif -- cgit From 5205071a519c5dd7b479343e17a109fb3cb19629 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:28 +0800 Subject: mt76: mt7915: enable Rx HE rate reporting Enable HE rate reporting in Rx path Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 27 ++++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 1 + 4 files changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index fb596afdf0be..f9384e1dab74 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -43,6 +43,8 @@ static void mt7915_mac_init(struct mt7915_dev *dev) mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536); mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); + /* enable rx rate report */ + mt76_set(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN); /* disable hardware de-agg */ mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index ddba360046c3..dd5b30a066b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -347,6 +347,22 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (i > 9) return -EINVAL; break; + case MT_PHY_TYPE_HE_MU: + /* fall through */ + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + status->nss = + FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; + status->encoding = RX_ENC_HE; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) + status->he_gi = gi; + + if (idx & MT_PRXV_TX_DCM) + status->he_dcm = true; + break; default: return -EINVAL; } @@ -356,7 +372,14 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - status->bw = RATE_INFO_BW_40; + if (rxv.phy & MT_PHY_TYPE_HE_EXT_SU && + (idx & MT_PRXV_TX_ER_SU_106T)) { + status->bw = RATE_INFO_BW_HE_RU; + status->he_ru = + NL80211_RATE_INFO_HE_RU_ALLOC_106; + } else { + status->bw = RATE_INFO_BW_40; + } break; case IEEE80211_STA_RX_BW_80: status->bw = RATE_INFO_BW_80; @@ -369,7 +392,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (gi) + if (rxv.phy < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 7da7551f98e4..712753484aee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -97,6 +97,8 @@ enum rx_pkt_type { /* P-RXV */ #define MT_PRXV_TX_RATE GENMASK(6, 0) +#define MT_PRXV_TX_DCM BIT(4) +#define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) #define MT_PRXV_HT_AD_CODE BIT(11) #define MT_PRXV_RCPI3 GENMASK(31, 24) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index ef87579056fe..572bdc16fb2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -73,6 +73,7 @@ #define MT_DMA_DCR0 MT_WF_DMA(0x000) #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) +#define MT_DMA_DCR0_RXD_G5_EN BIT(23) /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) -- cgit From f1d962369d5687b08d3270dad421e9346caee0ca Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:29 +0800 Subject: mt76: mt7915: implement HE per-rate tx power support Use firmware support for applying per-rate limit and power offsets. This can support all HE RU types. Signed-off-by: Shayne Chen Signed-off-by: Ryder Lee Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 59 +++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 118 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 47 ++++++++ drivers/net/wireless/mediatek/mt76/mt7915/init.c | 2 + drivers/net/wireless/mediatek/mt76/mt7915/main.c | 7 ++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 48 +++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 8 ++ drivers/net/wireless/mediatek/mt76/mt7915/pci.c | 25 +++++ 9 files changed, 315 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 152ae0617f3d..2e3f05f73697 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -219,6 +219,63 @@ mt7915_queues_read(struct seq_file *s, void *data) return 0; } +static void +mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta, + s8 txpower_cur, int band) +{ + static const char * const sku_group_name[] = { + "CCK", "OFDM", "HT20", "HT40", + "VHT20", "VHT40", "VHT80", "VHT160", + "RU26", "RU52", "RU106", "RU242/SU20", + "RU484/SU40", "RU996/SU80", "RU2x996/SU160" + }; + s8 txpower[MT7915_SKU_RATE_NUM]; + int i, idx = 0; + + for (i = 0; i < MT7915_SKU_RATE_NUM; i++) + txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2); + + for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) { + const struct sku_group *sku = &mt7915_sku_groups[i]; + u32 offset = sku->offset[band]; + + if (!offset) { + idx += sku->len; + continue; + } + + mt76_seq_puts_array(s, sku_group_name[i], + txpower + idx, sku->len); + idx += sku->len; + } +} + +static int +mt7915_read_rate_txpower(struct seq_file *s, void *data) +{ + struct mt7915_dev *dev = dev_get_drvdata(s->private); + struct mt76_phy *mphy = &dev->mphy; + enum nl80211_band band = mphy->chandef.chan->band; + s8 *delta = dev->rate_power[band]; + s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX]; + + seq_puts(s, "Band 0:\n"); + mt7915_puts_rate_txpower(s, delta, txpower_base, band); + + if (dev->mt76.phy2) { + mphy = dev->mt76.phy2; + band = mphy->chandef.chan->band; + delta = dev->rate_power[band]; + txpower_base = mphy->txpower_cur - + delta[MT7915_SKU_MAX_DELTA_IDX]; + + seq_puts(s, "Band 1:\n"); + mt7915_puts_rate_txpower(s, delta, txpower_base, band); + } + + return 0; +} + int mt7915_init_debugfs(struct mt7915_dev *dev) { struct dentry *dir; @@ -240,6 +297,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, mt7915_read_temperature); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, + mt7915_read_rate_txpower); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 2099dd40530f..7deba7ebd68a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -123,3 +123,121 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, return mt7915_eeprom_read(dev, index); } + +static const u8 sku_cck_delta_map[] = { + SKU_CCK_GROUP0, + SKU_CCK_GROUP0, + SKU_CCK_GROUP1, + SKU_CCK_GROUP1, +}; + +static const u8 sku_ofdm_delta_map[] = { + SKU_OFDM_GROUP0, + SKU_OFDM_GROUP0, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP3, + SKU_OFDM_GROUP4, +}; + +static const u8 sku_mcs_delta_map[] = { + SKU_MCS_GROUP0, + SKU_MCS_GROUP1, + SKU_MCS_GROUP1, + SKU_MCS_GROUP2, + SKU_MCS_GROUP2, + SKU_MCS_GROUP3, + SKU_MCS_GROUP4, + SKU_MCS_GROUP5, + SKU_MCS_GROUP6, + SKU_MCS_GROUP7, + SKU_MCS_GROUP8, + SKU_MCS_GROUP9, +}; + +#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map) \ + [_mode] = { \ + .len = _len, \ + .offset = { \ + _ofs_2g, \ + _ofs_5g, \ + }, \ + .delta_map = _map \ +} + +const struct sku_group mt7915_sku_groups[] = { + SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map), + SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map), + + SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map), + SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map), + SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map), + + SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map), + SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map), +}; + +static s8 +mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr) +{ + u32 val = mt7915_eeprom_read(dev, addr); + s8 delta = FIELD_GET(SKU_DELTA_VAL, val); + + if (!(val & SKU_DELTA_EN)) + return 0; + + return val & SKU_DELTA_ADD ? delta : -delta; +} + +static void +mt7915_eeprom_init_sku_band(struct mt7915_dev *dev, + struct ieee80211_supported_band *sband) +{ + int i, band = sband->band; + s8 *rate_power = dev->rate_power[band], max_delta = 0; + u8 idx = 0; + + for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) { + const struct sku_group *sku = &mt7915_sku_groups[i]; + u32 offset = sku->offset[band]; + int j; + + if (!offset) { + idx += sku->len; + continue; + } + + rate_power[idx++] = mt7915_get_sku_delta(dev, offset); + if (rate_power[idx - 1] > max_delta) + max_delta = rate_power[idx - 1]; + + if (i == SKU_HT_BW20 || i == SKU_VHT_BW20) + offset += 1; + + for (j = 1; j < sku->len; j++) { + u32 addr = offset + sku->delta_map[j]; + + rate_power[idx++] = mt7915_get_sku_delta(dev, addr); + if (rate_power[idx - 1] > max_delta) + max_delta = rate_power[idx - 1]; + } + } + + rate_power[idx] = max_delta; +} + +void mt7915_eeprom_init_sku(struct mt7915_dev *dev) +{ + mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband); + mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 30fc607e466d..4e31d6ab4fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -37,6 +37,51 @@ enum mt7915_eeprom_band { MT_EE_DBDC, }; +#define SKU_DELTA_VAL GENMASK(5, 0) +#define SKU_DELTA_ADD BIT(6) +#define SKU_DELTA_EN BIT(7) + +enum mt7915_sku_delta_group { + SKU_CCK_GROUP0, + SKU_CCK_GROUP1, + + SKU_OFDM_GROUP0 = 0, + SKU_OFDM_GROUP1, + SKU_OFDM_GROUP2, + SKU_OFDM_GROUP3, + SKU_OFDM_GROUP4, + + SKU_MCS_GROUP0 = 0, + SKU_MCS_GROUP1, + SKU_MCS_GROUP2, + SKU_MCS_GROUP3, + SKU_MCS_GROUP4, + SKU_MCS_GROUP5, + SKU_MCS_GROUP6, + SKU_MCS_GROUP7, + SKU_MCS_GROUP8, + SKU_MCS_GROUP9, +}; + +enum mt7915_sku_rate_group { + SKU_CCK, + SKU_OFDM, + SKU_HT_BW20, + SKU_HT_BW40, + SKU_VHT_BW20, + SKU_VHT_BW40, + SKU_VHT_BW80, + SKU_VHT_BW160, + SKU_HE_RU26, + SKU_HE_RU52, + SKU_HE_RU106, + SKU_HE_RU242, + SKU_HE_RU484, + SKU_HE_RU996, + SKU_HE_RU2x996, + MAX_SKU_RATE_GROUP_NUM, +}; + struct sku_group { u8 len; u16 offset[2]; @@ -75,4 +120,6 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G; } +extern const struct sku_group mt7915_sku_groups[]; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index f9384e1dab74..abce37ca9252 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -85,6 +85,8 @@ static void mt7915_init_txpower(struct mt7915_dev *dev) { mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband); mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband); + + mt7915_eeprom_init_sku(dev); } static void mt7915_init_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ae5ed41d337b..231bae4184ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -42,6 +42,7 @@ static int mt7915_start(struct ieee80211_hw *hw) mt7915_mcu_set_scs(dev, 1, true); } + mt7915_mcu_set_sku_en(phy, true); mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -325,6 +326,12 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & IEEE80211_CONF_CHANGE_POWER) { + ret = mt7915_mcu_set_sku(phy); + if (ret) + return ret; + } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index dad2c300d0f2..b275d18e5d9b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2295,6 +2295,54 @@ int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) sizeof(req), false); } +int mt7915_mcu_set_sku(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct mt7915_sku_val { + u8 format_id; + u8 limit_type; + u8 dbdc_idx; + s8 val[MT7915_SKU_RATE_NUM]; + } __packed req = { + .format_id = 4, + .dbdc_idx = phy != &dev->phy, + }; + int i; + s8 *delta; + + delta = dev->rate_power[mphy->chandef.chan->band]; + mphy->txpower_cur = hw->conf.power_level * 2 + + delta[MT7915_SKU_MAX_DELTA_IDX]; + + for (i = 0; i < MT7915_SKU_RATE_NUM; i++) + req.val[i] = hw->conf.power_level * 2 + delta[i]; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_sku { + u8 format_id; + u8 sku_enable; + u8 dbdc_idx; + u8 rsv; + } __packed req = { + .format_id = 0, + .dbdc_idx = phy != &dev->phy, + .sku_enable = enable, + }; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, + &req, sizeof(req), true); +} + int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 5e4708861ede..d9c9aab7e6dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -203,6 +203,7 @@ enum { MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, MCU_EXT_CMD_RX_HDR_TRANS = 0x47, MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, MCU_EXT_CMD_RATE_CTRL = 0x87, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b23ab3f215e0..6d3fde7f635a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -38,6 +38,9 @@ #define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ #define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ +#define MT7915_SKU_RATE_NUM 161 +#define MT7915_SKU_MAX_DELTA_IDX MT7915_SKU_RATE_NUM +#define MT7915_SKU_TABLE_SIZE (MT7915_SKU_RATE_NUM + 1) struct mt7915_vif; struct mt7915_sta; @@ -161,6 +164,8 @@ struct mt7915_dev { spinlock_t token_lock; struct idr token; + s8 **rate_power; /* TODO: use mt76_rate_power */ + u8 mac_work_count; bool fw_debug; }; @@ -268,6 +273,7 @@ u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset); int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); +void mt7915_eeprom_init_sku(struct mt7915_dev *dev); int mt7915_dma_init(struct mt7915_dev *dev); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); @@ -303,6 +309,8 @@ int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable); int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); +int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); +int mt7915_mcu_set_sku(struct mt7915_phy *phy); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index b79b5060cd77..7937c6965f59 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -75,6 +75,28 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } +static int +mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev) +{ +#define NUM_BANDS 2 + int i; + s8 **sku; + + sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL); + if (!sku) + return -ENOMEM; + + for (i = 0; i < NUM_BANDS; i++) { + sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE * + sizeof(**sku), GFP_KERNEL); + if (!sku[i]) + return -ENOMEM; + } + dev->rate_power = sku; + + return 0; +} + static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -118,6 +140,9 @@ static int mt7915_pci_probe(struct pci_dev *pdev, return -ENOMEM; dev = container_of(mdev, struct mt7915_dev, mt76); + ret = mt7915_alloc_device(pdev, dev); + if (ret) + return ret; mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) | -- cgit From 37f4ca907c462d7c8a1ac9e7e3473681b5f893dd Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:30 +0800 Subject: mt76: mt7915: register per-phy HE capabilities for each interface The capabilities for the HE interfaces are generated from the capabilities reported by the firmware. This should move to common file once we got other HE devices support. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 190 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 9 + drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 3 + drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 3 + 5 files changed, 206 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index abce37ca9252..bb8325e2edbd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -239,6 +239,194 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) hw->max_tx_fragments = 4; } +static void +mt7915_gen_ppe_thresh(u8 *he_ppet) +{ + int ru, nss, max_nss = 1, max_ru = 3; + u8 bit = 7, ru_bit_mask = 0x7; + u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71}; + + he_ppet[0] = max_nss & IEEE80211_PPE_THRES_NSS_MASK; + he_ppet[0] |= (ru_bit_mask << + IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) & + IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK; + + for (nss = 0; nss <= max_nss; nss++) { + for (ru = 0; ru < max_ru; ru++) { + u8 val; + int i; + + if (!(ru_bit_mask & BIT(ru))) + continue; + + val = (ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) & + 0x3f; + val = ((val >> 3) & 0x7) | ((val & 0x7) << 3); + for (i = 5; i >= 0; i--) { + he_ppet[bit / 8] |= + ((val >> i) & 0x1) << ((bit % 8)); + bit++; + } + } + } +} + +static int +mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, + struct ieee80211_sband_iftype_data *data) +{ + int i, idx = 0; + int nss = hweight8(phy->chainmask); + u16 mcs_map = 0; + + for (i = 0; i < 8; i++) { + if (i < nss) + mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2)); + else + mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2)); + } + + for (i = 0; i < NUM_NL80211_IFTYPES; i++) { + struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; + struct ieee80211_he_cap_elem *he_cap_elem = + &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *he_mcs = + &he_cap->he_mcs_nss_supp; + + switch (i) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: +#endif + break; + default: + continue; + } + + data[idx].types_mask = BIT(i); + he_cap->has_he = true; + + he_cap_elem->mac_cap_info[0] = + IEEE80211_HE_MAC_CAP0_HTC_HE; + he_cap_elem->mac_cap_info[1] = + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US | + IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1; + he_cap_elem->mac_cap_info[2] = + IEEE80211_HE_MAC_CAP2_BSR; + he_cap_elem->mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; + he_cap_elem->mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + he_cap_elem->phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + he_cap_elem->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; + + /* TODO: TxBF & MU & MESH */ + + switch (i) { + case NL80211_IFTYPE_AP: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_RES; + he_cap_elem->mac_cap_info[4] |= + IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->phy_cap_info[3] |= + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + case NL80211_IFTYPE_STATION: + he_cap_elem->mac_cap_info[0] |= + IEEE80211_HE_MAC_CAP0_TWT_REQ; + he_cap_elem->mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; + else if (band == NL80211_BAND_5GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; + + he_cap_elem->phy_cap_info[1] |= + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A; + he_cap_elem->phy_cap_info[8] |= + 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; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + break; +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: + break; +#endif + } + + he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map); + he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map); + he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map); + + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); + if (he_cap_elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { + mt7915_gen_ppe_thresh(he_cap->ppe_thres); + } else { + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US; + } + idx++; + } + + return idx; +} + +void mt7915_set_stream_he_caps(struct mt7915_phy *phy) +{ + struct ieee80211_sband_iftype_data *data; + struct ieee80211_supported_band *band; + struct mt76_dev *mdev = &phy->dev->mt76; + int n; + + if (mdev->cap.has_2ghz) { + data = phy->iftype[NL80211_BAND_2GHZ]; + n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data); + + band = &phy->mt76->sband_2g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } + + if (mdev->cap.has_5ghz) { + data = phy->iftype[NL80211_BAND_5GHZ]; + n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data); + + band = &phy->mt76->sband_5g.sband; + band->iftype_data = data; + band->n_iftype_data = n; + } +} + static void mt7915_cap_dbdc_enable(struct mt7915_dev *dev) { @@ -256,6 +444,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(&dev->phy); } static void @@ -271,6 +460,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(&dev->phy); } int mt7915_register_ext_phy(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 231bae4184ca..097225692026 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -691,6 +691,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) phy->chainmask = tx_ant; mt76_set_stream_caps(&dev->mt76, true); + mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b275d18e5d9b..47c0ff8f41bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -137,11 +137,13 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; + const struct ieee80211_sta_he_cap *he_cap; u8 mode = 0; if (sta) { ht_cap = &sta->ht_cap; vht_cap = &sta->vht_cap; + he_cap = &sta->he_cap; } else { struct ieee80211_supported_band *sband; @@ -152,6 +154,7 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; + he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); } if (band == NL80211_BAND_2GHZ) { @@ -159,6 +162,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (ht_cap->ht_supported) mode |= PHY_MODE_GN; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_24G; } else if (band == NL80211_BAND_5GHZ) { mode |= PHY_MODE_A; @@ -167,6 +173,9 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, if (vht_cap->vht_supported) mode |= PHY_MODE_AC; + + if (he_cap->has_he) + mode |= PHY_MODE_AX_5G; } return mode; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index d9c9aab7e6dc..c71161aec767 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -815,6 +815,9 @@ enum { #define PHY_MODE_GN BIT(3) #define PHY_MODE_AN BIT(4) #define PHY_MODE_AC BIT(5) +#define PHY_MODE_AX_24G BIT(6) +#define PHY_MODE_AX_5G BIT(7) +#define PHY_MODE_AX_6G BIT(8) #define MODE_CCK BIT(0) #define MODE_OFDM BIT(1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 6d3fde7f635a..92a6bf746d73 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -122,6 +122,8 @@ struct mt7915_phy { struct mt76_phy *mt76; struct mt7915_dev *dev; + struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; + u32 rxfilter; u32 vif_mask; u32 omac_mask; @@ -443,6 +445,7 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); +void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_dev *mdev); int mt7915_init_debugfs(struct mt7915_dev *dev); -- cgit From 6094f86fb3713e1b7d0c7f264c3a76263745efae Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:31 +0800 Subject: mt76: mt7915: add HE bss_conf support for interfaces Add basic HE BSS's info for interfaces. As for the advanced features will be added gradually in the future patches. (i.e. BSS color, TWT, spatial reuse and OFDMA) Signed-off-by: Ryder Lee Tested-by: Shayne Chen Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 95 ++++++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 10 +++ 2 files changed, 104 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 47c0ff8f41bf..61bab6bdcea0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -744,6 +744,47 @@ mt7915_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) omac->hw_bss_idx = idx; } +struct mt7915_he_obss_narrow_bw_ru_data { + bool tolerated; +}; + +static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, + struct cfg80211_bss *bss, + void *_data) +{ + struct mt7915_he_obss_narrow_bw_ru_data *data = _data; + const struct element *elem; + + elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, bss->ies->data, + bss->ies->len); + + if (!elem || elem->datalen < 10 || + !(elem->data[10] & + WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) + data->tolerated = false; +} + +static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7915_he_obss_narrow_bw_ru_data iter_data = { + .tolerated = true, + }; + + if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) + return false; + + cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, + mt7915_check_he_obss_narrow_bw_ru_iter, + &iter_data); + + /* + * If there is at least one AP on radar channel that cannot + * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU. + */ + return !iter_data.tolerated; +} + static void mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) @@ -766,7 +807,20 @@ mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ch->center_ch1 = ieee80211_frequency_to_channel(freq2); } - ch->he_all_disable = true; + if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) { + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = &dev->mt76.phy; + bool ext_phy = phy != &dev->phy; + + if (ext_phy && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + ch->he_ru26_block = + mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif); + ch->he_all_disable = false; + } else { + ch->he_all_disable = true; + } } static void @@ -795,6 +849,42 @@ mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ra->fast_interval = cpu_to_le32(100); } +static void +mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct mt7915_phy *phy) +{ +#define DEFAULT_HE_PE_DURATION 4 +#define DEFAULT_HE_DURATION_RTS_THRES 1023 + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; + enum nl80211_band band = chandef->chan->band; + struct ieee80211_supported_band *sband; + const struct ieee80211_sta_he_cap *cap; + struct bss_info_he *he; + struct tlv *tlv; + + if (band == NL80211_BAND_2GHZ) + sband = &phy->mt76->sband_2g.sband; + else + sband = &phy->mt76->sband_5g.sband; + + cap = ieee80211_get_he_iftype_cap(sband, vif->type); + + tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); + + he = (struct bss_info_he *)tlv; + he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext * 4; + if (!he->he_pe_duration) + he->he_pe_duration = DEFAULT_HE_PE_DURATION; + + he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th * 32); + if (!he->he_rts_thres) + he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; + he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; + he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; +} + static void mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif) { @@ -870,6 +960,9 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, mt7915_mcu_bss_bmc_tlv(skb, phy); mt7915_mcu_bss_ra_tlv(skb, vif, phy); + if (vif->bss_conf.he_support) + mt7915_mcu_bss_he_tlv(skb, vif, phy); + if (mvif->omac_idx > HW_BSSID_MAX) mt7915_mcu_bss_ext_tlv(skb, mvif); else diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index c71161aec767..85ef1b35b265 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -396,6 +396,16 @@ struct bss_info_ra { __le32 fast_interval; } __packed; +struct bss_info_he { + __le16 tag; + __le16 len; + u8 he_pe_duration; + u8 vht_op_info_present; + __le16 he_rts_thres; + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + u8 rsv[6]; +} __packed; + struct bss_info_bcn { __le16 tag; __le16 len; -- cgit From c336318f57a92d3971719598ef4416b531811d72 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:32 +0800 Subject: mt76: mt7915: add HE capabilities support for peers Set peer's bsic HE capabilities through starec. Signed-off-by: Ryder Lee Suggested-by: Shihwei Lin Tested-by: Shayne Chen Tested-by: Chih-Min Chen Tested-by: Evelyn Tsai Acked-by: Yiwei Chung Acked-by: YF Luo Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 197 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 100 ++++++++++++ 2 files changed, 297 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 61bab6bdcea0..aa24f1306941 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -85,6 +85,9 @@ struct mt7915_fw_region { #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) +#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) +#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) + static enum mt7915_cipher_type mt7915_mcu_get_cipher(int cipher) { @@ -1234,6 +1237,187 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, basic->qos = sta->wme; } +static void +mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct sta_rec_he *he; + struct tlv *tlv; + u32 cap = 0; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); + + he = (struct sta_rec_he *)tlv; + + if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) + cap |= STA_REC_HE_CAP_HTC; + + if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) + cap |= STA_REC_HE_CAP_BSR; + + if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) + cap |= STA_REC_HE_CAP_OM; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) + cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) + cap |= STA_REC_HE_CAP_BQR; + + if (elem->phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) + cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) + cap |= STA_REC_HE_CAP_LDPC; + + if (elem->phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) + cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) + cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; + + if (elem->phy_cap_info[2] & + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) + cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; + + if (elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) + cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; + + if (elem->phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) + cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; + + if (elem->phy_cap_info[8] & + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) + cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) + cap |= STA_REC_HE_CAP_TRIG_CQI_FK; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; + + if (elem->phy_cap_info[9] & + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) + cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; + + he->he_cap = cpu_to_le32(cap); + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + if (elem->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + he->max_nss_mcs[CMD_HE_MCS_BW8080] = + he_cap->he_mcs_nss_supp.rx_mcs_80p80; + + he->max_nss_mcs[CMD_HE_MCS_BW160] = + he_cap->he_mcs_nss_supp.rx_mcs_160; + /* fall through */ + default: + he->max_nss_mcs[CMD_HE_MCS_BW80] = + he_cap->he_mcs_nss_supp.rx_mcs_80; + break; + } + + he->t_frame_dur = + HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); + he->max_ampdu_exp = + HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); + + he->bw_set = + HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); + he->device_class = + HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); + he->punc_pream_rx = + HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); + + he->dcm_tx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); + he->dcm_tx_max_nss = + HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_mode = + HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); + he->dcm_rx_max_nss = + HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); + + he->pkt_ext = 2; +} + +static void +mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) +{ + struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct sta_rec_muru *muru; + struct tlv *tlv; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); + + muru = (struct sta_rec_muru *)tlv; + muru->cfg.ofdma_dl_en = true; + muru->cfg.ofdma_ul_en = true; + muru->cfg.mimo_dl_en = true; + muru->cfg.mimo_ul_en = true; + + muru->ofdma_dl.punc_pream_rx = + HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); + muru->ofdma_dl.he_20m_in_40m_2g = + HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); + muru->ofdma_dl.he_20m_in_160m = + HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); + muru->ofdma_dl.he_80m_in_160m = + HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); + muru->ofdma_dl.lt16_sigb = 0; + muru->ofdma_dl.rx_su_comp_sigb = 0; + muru->ofdma_dl.rx_su_non_comp_sigb = 0; + + muru->ofdma_ul.t_frame_dur = + HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); + muru->ofdma_ul.mu_cascading = + HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); + muru->ofdma_ul.uo_ra = + HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); + muru->ofdma_ul.he_2x996_tone = 0; + muru->ofdma_ul.rx_t_frame_11ac = 0; + + muru->mimo_dl.vht_mu_bfee = + !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + muru->mimo_dl.partial_bw_dl_mimo = + HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); + + muru->mimo_ul.full_ul_mimo = + HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); + muru->mimo_ul.partial_ul_mimo = + HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); +} + static void mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta) @@ -1259,6 +1443,14 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; } + + /* starec he */ + if (sta->he_cap.has_he) + mt7915_mcu_sta_he_tlv(skb, sta); + + /* starec muru */ + if (sta->he_cap.has_he || sta->vht_cap.vht_supported) + mt7915_mcu_sta_muru_tlv(skb, sta); } static void @@ -1454,6 +1646,11 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, } } + if (sta->he_cap.has_he) { + ra->supp_mode |= MODE_HE; + cap |= STA_CAP_HE; + } + ra->sta_status = cpu_to_le32(cap); switch (BIT(fls(ra->supp_mode) - 1)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 85ef1b35b265..cc0e27730aab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -658,6 +658,75 @@ struct sta_rec_vht { u8 rsv[3]; } __packed; +struct sta_rec_muru { + __le16 tag; + __le16 len; + + struct { + bool ofdma_dl_en; + bool ofdma_ul_en; + bool mimo_dl_en; + bool mimo_ul_en; + bool rsv[4]; + } cfg; + + struct { + u8 punc_pream_rx; + bool he_20m_in_40m_2g; + bool he_20m_in_160m; + bool he_80m_in_160m; + bool lt16_sigb; + bool rx_su_comp_sigb; + bool rx_su_non_comp_sigb; + bool rsv; + } ofdma_dl; + + struct { + u8 t_frame_dur; + u8 mu_cascading; + u8 uo_ra; + u8 he_2x996_tone; + u8 rx_t_frame_11ac; + u8 rsv[3]; + } ofdma_ul; + + struct { + bool vht_mu_bfee; + bool partial_bw_dl_mimo; + u8 rsv[2]; + } mimo_dl; + + struct { + bool full_ul_mimo; + bool partial_ul_mimo; + u8 rsv[2]; + } mimo_ul; +} __packed; + +struct sta_rec_he { + __le16 tag; + __le16 len; + + __le32 he_cap; + + u8 t_frame_dur; + u8 max_ampdu_exp; + u8 bw_set; + u8 device_class; + u8 dcm_tx_mode; + u8 dcm_tx_max_nss; + u8 dcm_rx_mode; + u8 dcm_rx_max_nss; + u8 dcm_max_ru; + u8 punc_pream_rx; + u8 pkt_ext; + u8 rsv1; + + __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; + + u8 rsv2[2]; +} __packed; + struct sta_rec_ba { __le16 tag; __le16 len; @@ -803,9 +872,11 @@ enum { #define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_he) + \ sizeof(struct sta_rec_ba) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct tlv) + \ + sizeof(struct sta_rec_muru) + \ sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra) + \ MT7915_WTBL_UPDATE_MAX_SIZE) @@ -833,6 +904,7 @@ enum { #define MODE_OFDM BIT(1) #define MODE_HT BIT(2) #define MODE_VHT BIT(3) +#define MODE_HE BIT(4) #define STA_CAP_WMM BIT(0) #define STA_CAP_SGI_20 BIT(4) @@ -847,5 +919,33 @@ enum { #define STA_CAP_LDPC BIT(24) #define STA_CAP_HT BIT(26) #define STA_CAP_VHT BIT(27) +#define STA_CAP_HE BIT(28) + +/* HE MAC */ +#define STA_REC_HE_CAP_HTC BIT(0) +#define STA_REC_HE_CAP_BQR BIT(1) +#define STA_REC_HE_CAP_BSR BIT(2) +#define STA_REC_HE_CAP_OM BIT(3) +#define STA_REC_HE_CAP_AMSDU_IN_AMPDU BIT(4) +/* HE PHY */ +#define STA_REC_HE_CAP_DUAL_BAND BIT(5) +#define STA_REC_HE_CAP_LDPC BIT(6) +#define STA_REC_HE_CAP_TRIG_CQI_FK BIT(7) +#define STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE BIT(8) +/* STBC */ +#define STA_REC_HE_CAP_LE_EQ_80M_TX_STBC BIT(9) +#define STA_REC_HE_CAP_LE_EQ_80M_RX_STBC BIT(10) +#define STA_REC_HE_CAP_GT_80M_TX_STBC BIT(11) +#define STA_REC_HE_CAP_GT_80M_RX_STBC BIT(12) +/* GI */ +#define STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI BIT(13) +#define STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI BIT(14) +#define STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI BIT(15) +#define STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI BIT(16) +#define STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI BIT(17) +/* 242 TONE */ +#define STA_REC_HE_CAP_BW20_RU242_SUPPORT BIT(18) +#define STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242 BIT(19) +#define STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242 BIT(20) #endif -- cgit From a82dd24d128d6399bfcb7f692732caf33827e1df Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:33 +0800 Subject: mt76: mt7915: add Rx radiotap header support mac80211 expects the definition of what HE rate info is available inside astruct prepended to the skb. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 141 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mac.h | 16 +++ 2 files changed, 157 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index dd5b30a066b3..751363b4b7a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -9,6 +9,10 @@ #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) +#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ + IEEE80211_RADIOTAP_HE_##f) + static const struct mt7915_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { @@ -172,6 +176,138 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } +static void +mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, + struct mt7915_rxv *rxv, + struct ieee80211_radiotap_he *he) +{ + u32 ru_h, ru_l; + u8 ru, offs = 0; + + ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv->v[0])); + ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv->v[1])); + ru = (u8)(ru_l | ru_h << 4); + + status->bw = RATE_INFO_BW_HE_RU; + + switch (ru) { + case 0 ... 36: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; + offs = ru; + break; + case 37 ... 52: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; + offs = ru - 37; + break; + case 53 ... 60: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; + offs = ru - 53; + break; + case 61 ... 64: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; + offs = ru - 61; + break; + case 65 ... 66: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; + offs = ru - 65; + break; + case 67: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case 68: + status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + } + + he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); + he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | + le16_encode_bits(offs, + IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); +} + +static void +mt7915_mac_decode_he_radiotap(struct sk_buff *skb, + struct mt76_rx_status *status, + struct mt7915_rxv *rxv) +{ + /* TODO: struct ieee80211_radiotap_he_mu */ + static const struct ieee80211_radiotap_he known = { + .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | + HE_BITS(DATA1_DATA_DCM_KNOWN) | + HE_BITS(DATA1_STBC_KNOWN) | + HE_BITS(DATA1_CODING_KNOWN), + .data2 = HE_BITS(DATA2_GI_KNOWN) | + HE_BITS(DATA2_TXBF_KNOWN), + }; + struct ieee80211_radiotap_he *he = NULL; + __le32 v2 = rxv->v[2]; + __le32 v11 = rxv->v[11]; + __le32 v14 = rxv->v[14]; + u32 ltf_size = le32_get_bits(v2, MT_CRXV_HE_LTF_SIZE) + 1; + + he = skb_push(skb, sizeof(known)); + memcpy(he, &known, sizeof(known)); + + he->data1 = HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) | + HE_BITS(DATA1_DOPPLER_KNOWN) | + HE_BITS(DATA1_BSS_COLOR_KNOWN); + he->data2 = HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | + HE_BITS(DATA2_TXOP_KNOWN); + + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, v14) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, v2); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, v2) | + le16_encode_bits(ltf_size, + IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, v14) | + HE_PREP(DATA6_DOPPLER, DOPPLER, v14); + + switch (rxv->phy) { + case MT_PHY_TYPE_HE_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, v14) | + HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + break; + case MT_PHY_TYPE_HE_EXT_SU: + he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | + HE_BITS(DATA1_UL_DL_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + break; + case MT_PHY_TYPE_HE_MU: + he->data1 |= HE_BITS(DATA1_FORMAT_MU) | + HE_BITS(DATA1_UL_DL_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN); + + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + + mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + break; + case MT_PHY_TYPE_HE_TB: + he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | + HE_BITS(DATA1_SPTL_REUSE_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE2_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | + HE_BITS(DATA1_SPTL_REUSE4_KNOWN); + + he->data4 = HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, v11) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, v11); + + mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + break; + default: + break; + } +} + int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -348,6 +484,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return -EINVAL; break; case MT_PHY_TYPE_HE_MU: + status->flag |= RX_FLAG_RADIOTAP_HE_MU; /* fall through */ case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: @@ -355,6 +492,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) status->nss = FIELD_GET(MT_PRXV_NSTS, rxv.v[0]) + 1; status->encoding = RX_ENC_HE; + status->flag |= RX_FLAG_RADIOTAP_HE; i &= GENMASK(3, 0); if (gi <= NL80211_RATE_INFO_HE_GI_3_2) @@ -405,6 +543,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) mt76_insert_ccmp_hdr(skb, key_id); } + if (status->flag & RX_FLAG_RADIOTAP_HE) + mt7915_mac_decode_he_radiotap(skb, status, &rxv); + hdr = mt76_skb_get_hdr(skb); if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 712753484aee..b9bc8b25b031 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -101,6 +101,8 @@ enum rx_pkt_type { #define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(9, 7) #define MT_PRXV_HT_AD_CODE BIT(11) +#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28) +#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) #define MT_PRXV_RCPI3 GENMASK(31, 24) #define MT_PRXV_RCPI2 GENMASK(23, 16) #define MT_PRXV_RCPI1 GENMASK(15, 8) @@ -111,6 +113,20 @@ enum rx_pkt_type { #define MT_CRXV_TX_MODE GENMASK(7, 4) #define MT_CRXV_FRAME_MODE GENMASK(10, 8) #define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) +#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17) +#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20) +#define MT_CRXV_HE_PE_DISAMBIG BIT(23) +#define MT_CRXV_HE_UPLINK BIT(31) + +#define MT_CRXV_HE_SR_MASK GENMASK(11, 8) +#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12) +#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17) +#define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) + +#define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) +#define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) +#define MT_CRXV_HE_BEAM_CHNG BIT(13) +#define MT_CRXV_HE_DOPPLER BIT(16) struct mt7915_rxv { u32 phy; -- cgit From ec9742a8f38ef69876e9f04be68d985c6bbb8f5f Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:34 +0800 Subject: mt76: mt7915: add .sta_add_debugfs support This generation supports much more per-peer statistics than legacy ones, so add .sta_add_debugfs accordingly. This is convenient to set/get more settings/counters in the long run. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 65 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 + drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++ 3 files changed, 72 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 2e3f05f73697..7f67a1a8013b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -302,3 +302,68 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) return 0; } + +/** per-station debugfs **/ + +static int +mt7915_sta_stats_read(struct seq_file *s, void *data) +{ + struct ieee80211_sta *sta = s->private; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_sta_stats *stats = &msta->stats; + struct rate_info *rate = &stats->prob_rate; + static const char * const bw[] = { + "BW20", "BW5", "BW10", "BW40", + "BW80", "BW160", "BW_HE_RU" + }; + + if (!rate->legacy && !rate->flags) + return 0; + + seq_puts(s, "Probing rate - "); + if (rate->flags & RATE_INFO_FLAGS_MCS) + seq_puts(s, "HT "); + else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) + seq_puts(s, "VHT "); + else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) + seq_puts(s, "HE "); + else + seq_printf(s, "Bitrate %d\n", rate->legacy); + + if (rate->flags) { + seq_printf(s, "%s NSS%d MCS%d ", + bw[rate->bw], rate->nss, rate->mcs); + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + seq_puts(s, "SGI "); + else if (rate->he_gi) + seq_puts(s, "HE GI "); + + if (rate->he_dcm) + seq_puts(s, "DCM "); + } + + seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n", + stats->per / 10, stats->per % 10); + + return 0; +} + +static int +mt7915_sta_stats_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7915_sta_stats_read, inode->i_private); +} + +static const struct file_operations fops_sta_stats = { + .open = mt7915_sta_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir) +{ + debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 097225692026..6cb69ae6cb0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -746,4 +746,7 @@ const struct ieee80211_ops mt7915_ops = { .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, .set_coverage_class = mt7915_set_coverage_class, +#ifdef CONFIG_MAC80211_DEBUGFS + .sta_add_debugfs = mt7915_sta_add_debugfs, +#endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 92a6bf746d73..35e34d270c15 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -448,5 +448,9 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_dev *mdev); int mt7915_init_debugfs(struct mt7915_dev *dev); +#ifdef CONFIG_MAC80211_DEBUGFS +void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct dentry *dir); +#endif #endif -- cgit From b02eafae42099943928bf7c253640d3bb0a3a949 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:35 +0800 Subject: mt76: mt7915: add .sta_statistics support Add useful debug counters since this generation uses struct rate_info to report HE tx rate. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 6cb69ae6cb0e..b3e26ff32287 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -698,6 +698,31 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) return 0; } +static void mt7915_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_sta_stats *stats = &msta->stats; + + if (!stats->tx_rate.legacy && !stats->tx_rate.flags) + return; + + if (stats->tx_rate.legacy) { + sinfo->txrate.legacy = stats->tx_rate.legacy; + } else { + sinfo->txrate.mcs = stats->tx_rate.mcs; + sinfo->txrate.nss = stats->tx_rate.nss; + sinfo->txrate.bw = stats->tx_rate.bw; + sinfo->txrate.he_gi = stats->tx_rate.he_gi; + sinfo->txrate.he_dcm = stats->tx_rate.he_dcm; + sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc; + } + sinfo->txrate.flags = stats->tx_rate.flags; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); +} + static void mt7915_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -746,6 +771,7 @@ const struct ieee80211_ops mt7915_ops = { .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, .set_coverage_class = mt7915_set_coverage_class, + .sta_statistics = mt7915_sta_statistics, #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = mt7915_sta_add_debugfs, #endif -- cgit From 9fac3c81eebd81bbce8b050e15b03d3490841717 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:36 +0800 Subject: mt76: mt7915: set peer Tx fixed rate through debugfs Driver can manually set fixed rate for each peer through debugfs. May use .set_bitrate_mask callback and iterate stations under the current vif to achieve the aim once it supports HE rate. Signed-off-by: Ryder Lee Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 13 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 46 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 28 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 + 4 files changed, 89 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 7f67a1a8013b..cf3b60ded6ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -305,6 +305,18 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) /** per-station debugfs **/ +/* usage: */ +static int mt7915_sta_fixed_rate_set(void *data, u64 rate) +{ + struct ieee80211_sta *sta = data; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate); +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL, + mt7915_sta_fixed_rate_set, "%llx\n"); + static int mt7915_sta_stats_read(struct seq_file *s, void *data) { @@ -365,5 +377,6 @@ static const struct file_operations fops_sta_stats = { void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { + debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index aa24f1306941..cbf96a56947a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1735,6 +1735,52 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; } +int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, + struct ieee80211_sta *sta, u32 rate) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_vif *mvif = msta->vif; + struct sta_rec_ra_fixed *ra; + struct sk_buff *skb; + struct tlv *tlv; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); + ra = (struct sta_rec_ra_fixed *)tlv; + + if (!rate) { + ra->field = cpu_to_le32(RATE_PARAM_AUTO); + goto out; + } else { + ra->field = cpu_to_le32(RATE_PARAM_FIXED); + } + + ra->phy.type = FIELD_GET(RATE_CFG_PHY_TYPE, rate); + ra->phy.bw = FIELD_GET(RATE_CFG_BW, rate); + ra->phy.nss = FIELD_GET(RATE_CFG_NSS, rate); + ra->phy.mcs = FIELD_GET(RATE_CFG_MCS, rate); + ra->phy.stbc = FIELD_GET(RATE_CFG_STBC, rate); + + if (ra->phy.bw) + ra->phy.ldpc = 7; + else + ra->phy.ldpc = FIELD_GET(RATE_CFG_LDPC, rate) * 7; + + /* HT/VHT - SGI: 1, LGI: 0; HE - SGI: 0, MGI: 1, LGI: 2 */ + if (ra->phy.type > MT_PHY_TYPE_VHT) + ra->phy.sgi = ra->phy.mcs * 85; + else + ra->phy.sgi = ra->phy.mcs * 15; + +out: + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + int mt7915_mcu_add_dev_info(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index cc0e27730aab..b8d28d971974 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -803,6 +803,34 @@ struct sta_rec_ra { struct ra_phy phy; } __packed; +struct sta_rec_ra_fixed { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct ra_phy phy; + + u8 spe_en; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + +#define RATE_PARAM_FIXED 3 +#define RATE_PARAM_AUTO 20 +#define RATE_CFG_MCS GENMASK(3, 0) +#define RATE_CFG_NSS GENMASK(7, 4) +#define RATE_CFG_GI GENMASK(11, 8) +#define RATE_CFG_BW GENMASK(15, 12) +#define RATE_CFG_STBC GENMASK(19, 16) +#define RATE_CFG_LDPC GENMASK(23, 20) +#define RATE_CFG_PHY_TYPE GENMASK(27, 24) + enum { STA_REC_BASIC, STA_REC_RA, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 35e34d270c15..e5821d144c85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -303,6 +303,8 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); +int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, + struct ieee80211_sta *sta, u32 rate); int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, -- cgit From 32add88f641bc0b3b63661771aea8dcee1d84396 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:37 +0800 Subject: mt76: mt7915: add tsf related callbacks It is useful for IBSS Mesh to adjust t_clockdrift. Signed-off-by: Ryder Lee Reported-by: Shayne Chen Tested-by: Evelyn Tsai Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 53 ++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 11 +++++ 2 files changed, 64 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index b3e26ff32287..ef0c91990b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -655,6 +655,57 @@ mt7915_get_stats(struct ieee80211_hw *hw, return 0; } +static u64 +mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + /* TSF software read */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE); + tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); + tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); + + mutex_unlock(&dev->mt76.mutex); + + return tsf.t64; +} + +static void +mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 timestamp) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); + /* TSF software overwrite */ + mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE); + + mutex_unlock(&dev->mt76.mutex); +} + static void mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { @@ -767,6 +818,8 @@ const struct ieee80211_ops mt7915_ops = { .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7915_channel_switch_beacon, .get_stats = mt7915_get_stats, + .get_tsf = mt7915_get_tsf, + .set_tsf = mt7915_set_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 572bdc16fb2d..6600fc625196 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -75,6 +75,17 @@ #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) +/* LPON: band 0(0x24200), band 1(0xa4200) */ +#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200) +#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) + +#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080) +#define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084) + +#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) +#define MT_LPON_TCR_SW_MODE GENMASK(1, 0) +#define MT_LPON_TCR_SW_WRITE BIT(0) + /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) -- cgit From 5517f78b0063d0463d042c68ac0c651db47ecf90 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:38 +0800 Subject: mt76: mt7915: enable firmware module debug support This allows host driver to get useful information of some important modules. Signed-off-by: Ryder Lee Signed-off-by: Chih-Min Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 36 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 58 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 3 ++ drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 + 4 files changed, 99 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index cf3b60ded6ef..c6c009cd773e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -74,6 +74,41 @@ mt7915_dbdc_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get, mt7915_dbdc_set, "%lld\n"); +static int +mt7915_fw_debug_set(void *data, u64 val) +{ + struct mt7915_dev *dev = data; + enum { + DEBUG_TXCMD = 62, + DEBUG_CMD_RPT_TX, + DEBUG_CMD_RPT_TRIG, + DEBUG_SPL, + DEBUG_RPT_RX, + } debug; + + dev->fw_debug = !!val; + + mt7915_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0); + + for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) + mt7915_mcu_fw_dbg_ctrl(dev, debug, dev->fw_debug); + + return 0; +} + +static int +mt7915_fw_debug_get(void *data, u64 *val) +{ + struct mt7915_dev *dev = data; + + *val = dev->fw_debug; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7915_fw_debug_get, + mt7915_fw_debug_set, "%lld\n"); + static void mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, struct seq_file *file) @@ -290,6 +325,7 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) mt7915_queues_acq); debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats); debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); + debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); /* test knobs */ debugfs_create_file("radar_trigger", 0200, dir, dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index cbf96a56947a..3e3d6f1d555a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -502,6 +502,28 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) } } +static void +mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; + const char *data = (char *)&rxd[1]; + const char *type; + + switch (rxd->s2d_index) { + case 0: + type = "WM"; + break; + case 2: + type = "WA"; + break; + default: + type = "unknown"; + break; + } + + wiphy_info(mt76_hw(dev)->wiphy, "%s: %s", type, data); +} + static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -519,6 +541,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) case MCU_EXT_EVENT_RATE_REPORT: mt7915_mcu_tx_rate_report(dev, skb); break; + case MCU_EXT_EVENT_FW_LOG_2_HOST: + mt7915_mcu_rx_log_message(dev, skb); + break; default: break; } @@ -544,6 +569,7 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || + rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || @@ -2265,6 +2291,37 @@ static int mt7915_load_firmware(struct mt7915_dev *dev) return 0; } +int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl) +{ + struct { + u8 ctrl_val; + u8 pad[3]; + } data = { + .ctrl_val = ctrl + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, + &data, sizeof(data), true); +} + +int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) +{ + struct { + u8 ver; + u8 pad; + u16 len; + u8 level; + u8 rsv[3]; + u32 module_idx; + } data = { + .module_idx = cpu_to_le32(module), + .level = level, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL, + &data, sizeof(data), false); +} + int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { @@ -2286,6 +2343,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + mt7915_mcu_fw_log_2_host(dev, 0); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index b8d28d971974..f68d2094ac6f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -38,6 +38,7 @@ enum { /* ext event table */ enum { MCU_EXT_EVENT_PS_SYNC = 0x5, + MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, MCU_EXT_EVENT_ASSERT_DUMP = 0x23, MCU_EXT_EVENT_RDD_REPORT = 0x3a, @@ -192,6 +193,7 @@ enum { MCU_EXT_CMD_EFUSE_ACCESS = 0x01, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, + MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, @@ -207,6 +209,7 @@ enum { MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, MCU_EXT_CMD_RATE_CTRL = 0x87, + MCU_EXT_CMD_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_SET_RDD_TH = 0x9d, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index e5821d144c85..43c956bc09f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -324,6 +324,8 @@ int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd, u8 index, u8 rx_sel, u8 val); +int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl); +int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level); void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb); void mt7915_mcu_exit(struct mt7915_dev *dev); -- cgit From bb3e3fec509e2b6103b8782b652f447a42212ae8 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Sat, 25 Apr 2020 03:32:39 +0800 Subject: mt76: set runtime stream caps by mt76_phy This patch can support concurrent dual-band operation. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++-------- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index f65e1b3e8f7a..21407704f1b3 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -116,12 +116,12 @@ static void mt76_led_cleanup(struct mt76_dev *dev) led_classdev_unregister(&dev->led_cdev); } -static void mt76_init_stream_cap(struct mt76_dev *dev, +static void mt76_init_stream_cap(struct mt76_phy *phy, struct ieee80211_supported_band *sband, bool vht) { struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; - int i, nstream = hweight8(dev->phy.antenna_mask); + int i, nstream = hweight8(phy->antenna_mask); struct ieee80211_sta_vht_cap *vht_cap; u16 mcs_map = 0; @@ -153,12 +153,12 @@ static void mt76_init_stream_cap(struct mt76_dev *dev, vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); } -void mt76_set_stream_caps(struct mt76_dev *dev, bool vht) +void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) { - if (dev->cap.has_2ghz) - mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false); - if (dev->cap.has_5ghz) - mt76_init_stream_cap(dev, &dev->phy.sband_5g.sband, vht); + if (phy->dev->cap.has_2ghz) + mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); + if (phy->dev->cap.has_5ghz) + mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); } EXPORT_SYMBOL_GPL(mt76_set_stream_caps); @@ -199,7 +199,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - mt76_init_stream_cap(dev, sband, vht); + mt76_init_stream_cap(&dev->phy, sband, vht); if (!vht) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 88959c1d5d1e..e6de4a1b8f26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -821,7 +821,7 @@ void mt76_set_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_dev *dev); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); -void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); +void mt76_set_stream_caps(struct mt76_phy *phy, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, u16 ssn, u16 size); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 37fc70197f92..6e1a17f08f5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -333,7 +333,7 @@ mt7615_cap_dbdc_enable(struct mt7615_dev *dev) dev->phy.chainmask = dev->mphy.antenna_mask; dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); } static void @@ -346,7 +346,7 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev) dev->phy.chainmask = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); } int mt7615_register_ext_phy(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index cfe024b71677..402ff38f7dcf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -784,7 +784,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } phy->chainmask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(phy->mt76, true); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index a74599f7f729..98f4cf398320 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -119,7 +119,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mphy.antenna_mask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt76x2_phy_set_antenna(dev); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index bb8325e2edbd..7d59571216e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -443,7 +443,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt7915_set_stream_he_caps(&dev->phy); } @@ -459,7 +459,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(&dev->mphy, true); mt7915_set_stream_he_caps(&dev->phy); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ef0c91990b49..697045e65b24 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -741,7 +741,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } phy->chainmask = tx_ant; - mt76_set_stream_caps(&dev->mt76, true); + mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex); -- cgit From 3fb31939b782cda8a9cd187bde60b867a5e13bf4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 8 May 2020 18:26:29 +0200 Subject: mt76: mt7663u: copy key pointer in mt7663u_mac_write_txwi Copy key pointer value before running mt76_tx_status_skb_add() in mt7663u_mac_write_txwi since it will be overwritten setting mt76_tx_cb for probing frames Co-developed-by: Johannes Berg Signed-off-by: Johannes Berg Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index f2825b8f4539..06235f83f903 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -66,6 +66,7 @@ mt7663u_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; __le32 *txwi; int pid; @@ -76,8 +77,7 @@ mt7663u_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); memset(txwi, 0, MT_USB_TXD_SIZE); - mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, - pid, info->control.hw_key, false); + mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); skb_push(skb, MT_USB_TXD_SIZE); } -- cgit From 6e7b2ebac329d5cafc5868386e01627efcd95b32 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 9 May 2020 23:38:35 +0200 Subject: mt76: mt7663u: add missing register definitions Add missing PLE/PSE base register definitions for mt7663u Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 06235f83f903..01d60c02512e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -23,6 +23,8 @@ static const u32 mt7663u_reg_map[] = { [MT_CSR_BASE] = 0x40000000, [MT_EFUSE_ADDR_BASE] = 0x78011000, [MT_TOP_MISC_BASE] = 0x81020000, + [MT_PLE_BASE] = 0x82060000, + [MT_PSE_BASE] = 0x82068000, [MT_PHY_BASE] = 0x82070000, [MT_WTBL_BASE_ADDR] = 0x820e0000, [MT_CFG_BASE] = 0x820f0000, -- cgit From da9e36ca163166fc6e53a69866b85a4ed2a273f9 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 9 May 2020 23:40:05 +0200 Subject: mt76: mt7615: usb: cancel ps work stopping the vif Cancel possible power_save work before stopping the mt7663u interface Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 01d60c02512e..d74253319622 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -51,6 +51,7 @@ static void mt7663u_stop(struct ieee80211_hw *hw) struct mt7615_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); + cancel_work_sync(&phy->ps_work); cancel_delayed_work_sync(&phy->scan_work); cancel_delayed_work_sync(&phy->mac_work); mt76u_stop_tx(&dev->mt76); -- cgit From b0efe6dd21e6a7c7fc591d95cceb203a365ffc30 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:32 +0800 Subject: mt76: mt7915: introduce mt7915_get_he_phy_cap Add a helper to reduce duplicate codes. This is a preliminary patch to add Tx beamforming support. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 31 ++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 3e3d6f1d555a..c147a033250a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -134,6 +134,18 @@ static u8 mt7915_mcu_chan_bw(struct cfg80211_chan_def *chandef) return width_to_bw[chandef->width]; } +static const struct ieee80211_sta_he_cap * +mt7915_get_he_phy_cap(struct mt7915_phy *phy, struct ieee80211_vif *vif) +{ + struct ieee80211_supported_band *sband; + enum nl80211_band band; + + band = phy->mt76->chandef.chan->band; + sband = phy->mt76->hw->wiphy->bands[band]; + + return ieee80211_get_he_iftype_cap(sband, vif->type); +} + static u8 mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, enum nl80211_band band, struct ieee80211_sta *sta) @@ -149,11 +161,12 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, he_cap = &sta->he_cap; } else { struct ieee80211_supported_band *sband; + struct mt7915_phy *phy; + struct mt7915_vif *mvif; - if (band == NL80211_BAND_2GHZ) - sband = &dev->mphy.sband_2g.sband; - else - sband = &dev->mphy.sband_5g.sband; + mvif = (struct mt7915_vif *)vif->drv_priv; + phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; + sband = phy->mt76->hw->wiphy->bands[band]; ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; @@ -884,19 +897,11 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, { #define DEFAULT_HE_PE_DURATION 4 #define DEFAULT_HE_DURATION_RTS_THRES 1023 - struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - enum nl80211_band band = chandef->chan->band; - struct ieee80211_supported_band *sband; const struct ieee80211_sta_he_cap *cap; struct bss_info_he *he; struct tlv *tlv; - if (band == NL80211_BAND_2GHZ) - sband = &phy->mt76->sband_2g.sband; - else - sband = &phy->mt76->sband_5g.sband; - - cap = ieee80211_get_he_iftype_cap(sband, vif->type); + cap = mt7915_get_he_phy_cap(phy, vif); tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); -- cgit From 89029a85482cbcf68026a89fc974e8f6898d6b37 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:33 +0800 Subject: mt76: mt7915: add Tx beamformer support Enable TxBF modules and trigger sounding process to support Tx beamformer. Signed-off-by: Ryder Lee Tested-by: Evelyn Tsai --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 20 ++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 9 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 358 ++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 78 +++-- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 4 + 5 files changed, 434 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 7d59571216e3..3721bd632b4d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -57,6 +57,25 @@ static void mt7915_mac_init(struct mt7915_dev *dev) mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b); } +static int mt7915_txbf_init(struct mt7915_dev *dev) +{ + int ret; + + /* + * TODO: DBDC & check whether iBF phase calibration data has + * been stored in eeprom offset 0x651~0x7b8, then write down + * 0x1111 into 0x651 and 0x651 to trigger iBF. + */ + + /* trigger sounding packets */ + ret = mt7915_mcu_set_txbf_sounding(dev); + if (ret) + return ret; + + /* enable iBF & eBF */ + return mt7915_mcu_set_txbf_type(dev); +} + static void mt7915_init_txpower_band(struct mt7915_dev *dev, struct ieee80211_supported_band *sband) @@ -97,6 +116,7 @@ static void mt7915_init_work(struct work_struct *work) mt7915_mcu_set_eeprom(dev); mt7915_mac_init(dev); mt7915_init_txpower(dev); + mt7915_txbf_init(dev); } static int mt7915_init_hardware(struct mt7915_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 697045e65b24..f3a373fc07e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -485,7 +485,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - int idx; + int ret, idx; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1); if (idx < 0) @@ -504,9 +504,11 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7915_mcu_add_sta(dev, vif, sta, true); + ret = mt7915_mcu_add_sta(dev, vif, sta, true); + if (ret) + return ret; - return 0; + return mt7915_mcu_add_sta_adv(dev, vif, sta, true); } void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -515,6 +517,7 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + mt7915_mcu_add_sta_adv(dev, vif, sta, false); mt7915_mcu_add_sta(dev, vif, sta, false); mt7915_mac_wtbl_update(dev, msta->wcid.idx, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c147a033250a..58d0adca8b31 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -66,6 +66,8 @@ struct mt7915_fw_region { #define MCU_PATCH_ADDRESS 0x200000 +#define MT_STA_BFER BIT(0) + #define FW_FEATURE_SET_ENCRYPT BIT(0) #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) #define FW_FEATURE_OVERRIDE_ADDR BIT(5) @@ -197,6 +199,21 @@ mt7915_get_phy_mode(struct mt7915_dev *dev, struct ieee80211_vif *vif, return mode; } +static u8 +mt7915_mcu_get_sta_nss(u16 mcs_map) +{ + u8 nss; + + for (nss = 8; nss > 0; nss--) { + u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3; + + if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) + break; + } + + return nss - 1; +} + static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq) { @@ -1561,6 +1578,279 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD_STA_REC_UPDATE, true); } +static void +mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) +{ + bf->sounding_phy = MT_PHY_TYPE_OFDM; + bf->ndp_rate = 0; /* mcs0 */ + bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ + bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ +} + +static void +mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct sta_rec_bf *bf) +{ + struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; + u8 n = 0; + + bf->tx_mode = MT_PHY_TYPE_HT; + bf->bf_cap |= MT_IBF; + + if (mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF && + (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) + n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, + mcs->tx_params); + else if (mcs->rx_mask[3]) + n = 3; + else if (mcs->rx_mask[2]) + n = 2; + else if (mcs->rx_mask[1]) + n = 1; + + bf->nc = min_t(u8, bf->nr, n); + bf->ibf_ncol = bf->nc; + + if (sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc) + bf->ibf_timeout = 0x48; +} + +static void +mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, + struct sta_rec_bf *bf) +{ + struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; + struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; + u8 bfee_nr, bfer_nr, n, tx_ant = hweight8(phy->chainmask) - 1; + u16 mcs_map; + + bf->tx_mode = MT_PHY_TYPE_VHT; + bf->bf_cap |= MT_EBF; + + mt7915_mcu_sta_sounding_rate(bf); + + bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, + pc->cap); + bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + vc->cap); + mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); + + n = min_t(u8, bfer_nr, bfee_nr); + bf->nr = min_t(u8, n, tx_ant); + n = mt7915_mcu_get_sta_nss(mcs_map); + + bf->nc = min_t(u8, n, bf->nr); + bf->ibf_ncol = bf->nc; + + /* force nr from 4 to 2 */ + if (sta->bandwidth == IEEE80211_STA_RX_BW_160) + bf->nr = 1; +} + +static void +mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, + struct mt7915_phy *phy, struct sta_rec_bf *bf) +{ + struct ieee80211_sta_he_cap *pc = &sta->he_cap; + struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; + const struct ieee80211_he_cap_elem *ve; + const struct ieee80211_sta_he_cap *vc; + u8 bfee_nr, bfer_nr, nss_mcs; + u16 mcs_map; + + vc = mt7915_get_he_phy_cap(phy, vif); + ve = &vc->he_cap_elem; + + bf->tx_mode = MT_PHY_TYPE_HE_SU; + bf->bf_cap |= MT_EBF; + + mt7915_mcu_sta_sounding_rate(bf); + + bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMER_FB, + pe->phy_cap_info[6]); + bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMER_FB, + pe->phy_cap_info[6]); + bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, + ve->phy_cap_info[5]); + bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, + pe->phy_cap_info[4]); + + mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.tx_mcs_80); + nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); + + bf->nr = min_t(u8, bfer_nr, bfee_nr); + bf->nc = min_t(u8, nss_mcs, bf->nr); + bf->ibf_ncol = bf->nc; + + if (sta->bandwidth != IEEE80211_STA_RX_BW_160) + return; + + /* go over for 160MHz and 80p80 */ + if (pe->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { + mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); + nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); + + bf->nc_bw160 = nss_mcs; + } + + if (pe->phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { + mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); + nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); + + if (bf->nc_bw160) + bf->nc_bw160 = min_t(u8, bf->nc_bw160, nss_mcs); + else + bf->nc_bw160 = nss_mcs; + } + + bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, + ve->phy_cap_info[5]); + bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, + pe->phy_cap_info[4]); + + bf->nr_bw160 = min_t(int, bfer_nr, bfee_nr); +} + +static void +mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, struct mt7915_phy *phy, + bool enable) +{ + struct sta_rec_bf *bf; + struct tlv *tlv; + int tx_ant = hweight8(phy->chainmask) - 1; + const u8 matrix[4][4] = { + {0, 0, 0, 0}, + {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ + {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ + {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ + }; + +#define MT_BFER_FREE cpu_to_le16(GENMASK(15, 0)) + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); + bf = (struct sta_rec_bf *)tlv; + + if (!enable) { + bf->pfmu = MT_BFER_FREE; + return; + } + + bf->bw = sta->bandwidth; + bf->ibf_dbw = sta->bandwidth; + bf->ibf_nrow = tx_ant; + bf->ibf_timeout = 0x18; + + if (sta->he_cap.has_he) + mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); + else if (sta->vht_cap.vht_supported) + mt7915_mcu_sta_bfer_vht(sta, phy, bf); + else if (sta->ht_cap.ht_supported) + mt7915_mcu_sta_bfer_ht(sta, bf); + + if (bf->bf_cap & MT_EBF && bf->nr != tx_ant) + bf->mem_20m = matrix[tx_ant][bf->nc]; + else + bf->mem_20m = matrix[bf->nr][bf->nc]; + + switch (sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: + case IEEE80211_STA_RX_BW_80: + bf->mem_total = bf->mem_20m * 2; + break; + case IEEE80211_STA_RX_BW_40: + bf->mem_total = bf->mem_20m; + break; + case IEEE80211_STA_RX_BW_20: + default: + break; + } +} + +static u8 +mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_sta *msta; + u8 type = 0; + + if (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP) + return 0; + + msta = (struct mt7915_sta *)sta->drv_priv; + + if (sta->he_cap.has_he) { + struct ieee80211_he_cap_elem *pe; + const struct ieee80211_he_cap_elem *ve; + const struct ieee80211_sta_he_cap *vc; + + pe = &sta->he_cap.he_cap_elem; + vc = mt7915_get_he_phy_cap(phy, vif); + ve = &vc->he_cap_elem; + + if ((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || + HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && + HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])) + type |= MT_STA_BFER; + } else if (sta->vht_cap.vht_supported) { + struct ieee80211_sta_vht_cap *pc; + struct ieee80211_sta_vht_cap *vc; + u32 cr, ce; + + pc = &sta->vht_cap; + vc = &phy->mt76->sband_5g.sband.vht_cap; + cr = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if ((vc->cap & cr) && (pc->cap & ce)) + type |= MT_STA_BFER; + } else if (sta->ht_cap.ht_supported) { + /* TODO: iBF */ + } + + return type; +} + +static int +mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_phy *phy; + struct sk_buff *skb; + int r, len; + u8 type; + + phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy; + + type = mt7915_mcu_sta_txbf_type(phy, vif, sta); + + /* must keep each tag independent */ + + /* starec bf */ + if (type & MT_STA_BFER) { + len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bf); + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable); + + r = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + if (r) + return r; + } + + return 0; +} + static void mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -1724,6 +2014,25 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD_STA_REC_UPDATE, true); } +int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable) +{ + int ret; + + if (!sta) + return 0; + + /* must keep the order */ + ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); + if (ret) + return ret; + + if (enable) + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); + + return 0; +} + int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { @@ -1732,7 +2041,6 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct mt7915_sta *msta; struct tlv *sta_wtbl; struct sk_buff *skb; - int ret; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; @@ -1755,15 +2063,8 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr); } - ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD_STA_REC_UPDATE, true); - if (ret) - return ret; - - if (enable && sta) - return mt7915_mcu_add_rate_ctrl(dev, vif, sta); - - return 0; + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); } int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, @@ -2767,3 +3068,40 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER, &req, sizeof(req), false); } + +int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) +{ +#define MT_BF_TYPE_UPDATE 20 + struct { + u8 action; + bool ebf; + bool ibf; + u8 rsv; + } __packed req = { + .action = MT_BF_TYPE_UPDATE, + .ebf = true, + .ibf = false, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, + &req, sizeof(req), true); +} + +int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev) +{ +#define MT_BF_PROCESSING 4 + struct { + u8 action; + u8 snd_mode; + u8 sta_num; + u8 rsv; + u8 wlan_idx[4]; + __le32 snd_period; /* ms */ + } __packed req = { + .action = true, + .snd_mode = MT_BF_PROCESSING, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, + &req, sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index f68d2094ac6f..53d1e1f0cea9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -194,6 +194,7 @@ enum { MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, + MCU_EXT_CMD_TXBF_ACTION = 0x1e, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, @@ -571,18 +572,6 @@ struct wtbl_ba { u8 rsv1[4]; } __packed; -struct wtbl_bf { - __le16 tag; - __le16 len; - u8 ibf; - u8 ebf; - u8 ibf_vht; - u8 ebf_vht; - u8 gid; - u8 pfmu_idx; - u8 rsv[2]; -} __packed; - struct wtbl_smps { __le16 tag; __le16 len; @@ -590,13 +579,6 @@ struct wtbl_smps { u8 rsv[3]; } __packed; -struct wtbl_spe { - __le16 tag; - __le16 len; - u8 spe_idx; - u8 rsv[3]; -} __packed; - enum { WTBL_GENERIC, WTBL_RX, @@ -834,6 +816,55 @@ struct sta_rec_ra_fixed { #define RATE_CFG_LDPC GENMASK(23, 20) #define RATE_CFG_PHY_TYPE GENMASK(27, 24) +struct sta_rec_bf { + __le16 tag; + __le16 len; + + __le16 pfmu; /* 0xffff: no access right for PFMU */ + bool su_mu; /* 0: SU, 1: MU */ + u8 bf_cap; /* 0: iBF, 1: eBF */ + u8 sounding_phy; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ + u8 ndpa_rate; + u8 ndp_rate; + u8 rept_poll_rate; + u8 tx_mode; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT ... */ + u8 nc; + u8 nr; + u8 bw; /* 0: 20M, 1: 40M, 2: 80M, 3: 160M */ + + u8 mem_total; + u8 mem_20m; + struct { + u8 row; + u8 col: 6, row_msb: 2; + } mem[4]; + + __le16 smart_ant; + u8 se_idx; + u8 auto_sounding; /* b7: low traffic indicator + * b6: Stop sounding for this entry + * b5 ~ b0: postpone sounding + */ + u8 ibf_timeout; + u8 ibf_dbw; + u8 ibf_ncol; + u8 ibf_nrow; + u8 nr_bw160; + u8 nc_bw160; + u8 ru_start_idx; + u8 ru_end_idx; + + bool trigger_su; + bool trigger_mu; + bool ng16_su; + bool ng16_mu; + bool codebook42_su; + bool codebook75_mu; + + u8 he_ltf; + u8 rsv[2]; +} __packed; + enum { STA_REC_BASIC, STA_REC_RA, @@ -890,15 +921,18 @@ enum { THERMAL_SENSOR_TASK_CTRL, }; +enum { + MT_EBF = BIT(0), /* explicit beamforming */ + MT_IBF = BIT(1) /* implicit beamforming */ +}; + #define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ sizeof(struct wtbl_ht) + \ sizeof(struct wtbl_vht) + \ sizeof(struct wtbl_ba) + \ - sizeof(struct wtbl_bf) + \ - sizeof(struct wtbl_smps) + \ - sizeof(struct wtbl_spe)) + sizeof(struct wtbl_smps)) #define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 43c956bc09f5..0d5b448292b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -286,6 +286,8 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, int enable); int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); +int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enable); int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, struct ieee80211_ampdu_params *params, bool add); @@ -315,6 +317,8 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_sku(struct mt7915_phy *phy); +int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev); +int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); -- cgit From 2af34fa3b5a76ca3ed553550f93dbc793a2965cb Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:34 +0800 Subject: mt76: mt7915: add Tx beamformee support Enable beamformee support. Signed-off-by: Ryder Lee Tested-by: Evelyn Tsai Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 54 +++++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 9 +++++ 2 files changed, 63 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 58d0adca8b31..52e349b17246 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -67,6 +67,7 @@ struct mt7915_fw_region { #define MCU_PATCH_ADDRESS 0x200000 #define MT_STA_BFER BIT(0) +#define MT_STA_BFEE BIT(1) #define FW_FEATURE_SET_ENCRYPT BIT(0) #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) @@ -1768,6 +1769,35 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, } } +static void +mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, + struct mt7915_phy *phy) +{ + struct sta_rec_bfee *bfee; + struct tlv *tlv; + int tx_ant = hweight8(phy->chainmask) - 1; + u8 nr = 0; + + tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); + bfee = (struct sta_rec_bfee *)tlv; + + if (sta->he_cap.has_he) { + struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem; + + nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, + pe->phy_cap_info[5]); + } else if (sta->vht_cap.vht_supported) { + struct ieee80211_sta_vht_cap *pc = &sta->vht_cap; + + nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + pc->cap); + } + + /* reply with identity matrix to avoid 2x2 BF negative gain */ + if (nr == 1 && tx_ant == 2) + bfee->fb_identity_matrix = true; +} + static u8 mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1790,6 +1820,11 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, vc = mt7915_get_he_phy_cap(phy, vif); ve = &vc->he_cap_elem; + if ((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || + HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && + HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])) + type |= MT_STA_BFEE; + if ((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])) @@ -1806,6 +1841,9 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif, ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if ((pc->cap & cr) && (vc->cap & ce)) + type |= MT_STA_BFEE; + if ((vc->cap & cr) && (pc->cap & ce)) type |= MT_STA_BFER; } else if (sta->ht_cap.ht_supported) { @@ -1848,6 +1886,22 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, return r; } + /* starec bfee */ + if (type & MT_STA_BFEE) { + len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee); + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_bfee_tlv(skb, sta, phy); + + r = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + if (r) + return r; + } + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 53d1e1f0cea9..cdeba5a0ef34 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -865,6 +865,14 @@ struct sta_rec_bf { u8 rsv[2]; } __packed; +struct sta_rec_bfee { + __le16 tag; + __le16 len; + bool fb_identity_matrix; /* 1: feedback identity matrix */ + bool ignore_feedback; /* 1: ignore */ + u8 rsv[2]; +} __packed; + enum { STA_REC_BASIC, STA_REC_RA, @@ -886,6 +894,7 @@ enum { STA_REC_KEY_V2, STA_REC_MURU, STA_REC_MUEDCA, + STA_REC_BFEE, STA_REC_MAX_NUM }; -- cgit From 00b2e16e006390069480e90478aa8b6e924996d7 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:35 +0800 Subject: mt76: mt7915: add TxBF capabilities This allows to set HE TxBF runtime stream capabilities Signed-off-by: Ryder Lee Tested-by: Evelyn Tsai --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 95 +++++++++++++++++++++- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 1 + 3 files changed, 95 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 3721bd632b4d..e2b0ea33053c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -259,6 +259,94 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) hw->max_tx_fragments = 4; } +void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy) +{ + int nss = hweight8(phy->chainmask); + u32 *cap = &phy->mt76->sband_5g.sband.vht_cap.cap; + + *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + + *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); + + if (nss < 2) + return; + + *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | + FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, + nss - 1); +} + +static void +mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, + int vif, int nss) +{ + struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *mcs = &he_cap->he_mcs_nss_supp; + u8 c; + +#ifdef CONFIG_MAC80211_MESH + if (vif == NL80211_IFTYPE_MESH_POINT) + return; +#endif + + elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; + elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + + c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; + elem->phy_cap_info[5] &= ~c; + + c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB; + elem->phy_cap_info[6] &= ~c; + + elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; + + c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + elem->phy_cap_info[2] |= c; + + c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + elem->phy_cap_info[4] |= c; + + /* do not support NG16 due to spec D4.0 changes subcarrier idx */ + c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU; + + if (vif == NL80211_IFTYPE_STATION) + c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; + + elem->phy_cap_info[6] |= c; + + if (nss < 2) + return; + + if (vif != NL80211_IFTYPE_AP) + return; + + elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; + elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + + /* num_snd_dim */ + c = (nss - 1) | (max_t(int, mcs->tx_mcs_160, 1) << 3); + elem->phy_cap_info[5] |= c; + + c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB; + elem->phy_cap_info[6] |= c; + + /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ + elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; +} + static void mt7915_gen_ppe_thresh(u8 *he_ppet) { @@ -352,11 +440,10 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->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; - /* TODO: TxBF & MU & MESH */ + /* TODO: OFDMA */ switch (i) { case NL80211_IFTYPE_AP: @@ -407,6 +494,8 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map); he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map); + mt7915_set_stream_he_txbf_caps(he_cap, i, nss); + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { @@ -464,6 +553,7 @@ mt7915_cap_dbdc_enable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask; mt76_set_stream_caps(&dev->mphy, true); + mt7915_set_stream_vht_txbf_caps(&dev->phy); mt7915_set_stream_he_caps(&dev->phy); } @@ -480,6 +570,7 @@ mt7915_cap_dbdc_disable(struct mt7915_dev *dev) dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; mt76_set_stream_caps(&dev->mphy, true); + mt7915_set_stream_vht_txbf_caps(&dev->phy); mt7915_set_stream_he_caps(&dev->phy); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index f3a373fc07e5..147ab7da7aa9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -745,6 +745,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) phy->chainmask = tx_ant; mt76_set_stream_caps(phy->mt76, true); + mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 0d5b448292b5..537fc126289f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -454,6 +454,7 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); +void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_dev *mdev); int mt7915_init_debugfs(struct mt7915_dev *dev); #ifdef CONFIG_MAC80211_DEBUGFS -- cgit From babdad50f781c21c2e5511bf406dbb9728da05cb Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:36 +0800 Subject: mt76: mt7915: add debugfs to track TxBF status Add debug counters to track status of beamformer and beamformee. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/debugfs.c | 45 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7915/regs.h | 20 ++++++++++ 2 files changed, 65 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index c6c009cd773e..ee0066fedd04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -143,6 +143,48 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); } +static void +mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) +{ + struct mt7915_dev *dev = s->private; + bool ext_phy = phy != &dev->phy; + int cnt; + + if (!phy) + return; + + /* Tx Beamformer monitor */ + seq_puts(s, "\nTx Beamformer applied PPDU counts: "); + + cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy)); + seq_printf(s, "iBF: %ld, eBF: %ld\n", + FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt), + FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt)); + + /* Tx Beamformer Rx feedback monitor */ + seq_puts(s, "Tx Beamformer Rx feedback statistics: "); + + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); + seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n", + FIELD_GET(MT_ETBF_RX_FB_ALL, cnt), + FIELD_GET(MT_ETBF_RX_FB_HE, cnt), + FIELD_GET(MT_ETBF_RX_FB_VHT, cnt), + FIELD_GET(MT_ETBF_RX_FB_HT, cnt)); + + /* Tx Beamformee Rx NDPA & Tx feedback report */ + cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); + seq_printf(s, "Tx Beamformee sucessful feedback frames: %ld\n", + FIELD_GET(MT_ETBF_TX_FB_CPL, cnt)); + seq_printf(s, "Tx Beamformee feedback triggerd counts: %ld\n", + FIELD_GET(MT_ETBF_TX_FB_TRI, cnt)); + + /* Tx SU counters */ + cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); + seq_printf(s, "Tx single-user sucessful MPDU counts: %d\n", cnt); + + seq_puts(s, "\n"); +} + static int mt7915_tx_stats_read(struct seq_file *file, void *data) { @@ -150,7 +192,10 @@ mt7915_tx_stats_read(struct seq_file *file, void *data) int stat[8], i, n; mt7915_ampdu_stat_read_phy(&dev->phy, file); + mt7915_txbf_stat_read_phy(&dev->phy, file); + mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file); + mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file); /* Tx amsdu info */ seq_puts(file, "Tx MSDU stat:\n"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 6600fc625196..c121715f8bff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -75,6 +75,24 @@ #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) +/* ETBF: band 0(0x24000), band 1(0xa4000) */ +#define MT_WF_ETBF_BASE(_band) ((_band) ? 0xa4000 : 0x24000) +#define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs)) + +#define MT_ETBF_TX_NDP_BFRP(_band) MT_WF_ETBF(_band, 0x040) +#define MT_ETBF_TX_FB_CPL GENMASK(31, 16) +#define MT_ETBF_TX_FB_TRI GENMASK(15, 0) + +#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x0f0) +#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16) +#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0) + +#define MT_ETBF_RX_FB_CNT(_band) MT_WF_ETBF(_band, 0x0f8) +#define MT_ETBF_RX_FB_ALL GENMASK(31, 24) +#define MT_ETBF_RX_FB_HE GENMASK(23, 16) +#define MT_ETBF_RX_FB_VHT GENMASK(15, 8) +#define MT_ETBF_RX_FB_HT GENMASK(7, 0) + /* LPON: band 0(0x24200), band 1(0xa4200) */ #define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200) #define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) @@ -104,6 +122,8 @@ #define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) #define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) +#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) + #define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) -- cgit From 3e68af622254bad75f5989c39663fd12a8efeddd Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:37 +0800 Subject: mt76: mt7915: allocate proper size for tlv tags Allocating proper memory size according to tlv usage. Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 14 +++++++------- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 12 ++++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 52e349b17246..f00ad2b66761 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -997,7 +997,7 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, struct sk_buff *skb; skb = mt7915_mcu_alloc_sta_req(phy->dev, mvif, NULL, - MT7915_STA_UPDATE_MAX_SIZE); + MT7915_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1092,10 +1092,10 @@ int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif, { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct sk_buff *skb; + int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_sec); int ret; - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, - MT7915_STA_UPDATE_MAX_SIZE); + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2056,9 +2056,9 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct sk_buff *skb; + int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_ra); - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, - MT7915_STA_UPDATE_MAX_SIZE); + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -2129,9 +2129,9 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev, struct sta_rec_ra_fixed *ra; struct sk_buff *skb; struct tlv *tlv; + int len = sizeof(struct sta_req_hdr) + sizeof(*ra); - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, - MT7915_STA_UPDATE_MAX_SIZE); + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index cdeba5a0ef34..34ace6e672d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -951,13 +951,21 @@ enum { sizeof(struct sta_rec_vht) + \ sizeof(struct tlv) + \ sizeof(struct sta_rec_muru) + \ - sizeof(struct sta_rec_sec) + \ - sizeof(struct sta_rec_ra) + \ MT7915_WTBL_UPDATE_MAX_SIZE) #define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_ba)) +#define MT7915_BSS_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct bss_info_omac) + \ + sizeof(struct bss_info_basic) +\ + sizeof(struct bss_info_rf_ch) +\ + sizeof(struct bss_info_ra) + \ + sizeof(struct bss_info_he) + \ + sizeof(struct bss_info_bmc_rate) +\ + sizeof(struct bss_info_ext_bss) +\ + sizeof(struct bss_info_sync_mode)) + #define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct bss_info_bcn_csa) + \ sizeof(struct bss_info_bcn_bcc) + \ -- cgit From 57b9df6fa5f56b98baa73f62ed92db81db3de391 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Tue, 12 May 2020 00:06:38 +0800 Subject: mt76: mt7915: fix possible deadlock in mt7915_stop make mac_work per phy instead of per device and fix a possible deadlock in mt7915_stop since mt7915_mac_work runs holding mt76 mutex Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 3 +- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 49 +++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 18 ++++---- drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h | 4 +- 4 files changed, 42 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index e2b0ea33053c..6f200ab3ac28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -592,6 +592,7 @@ int mt7915_register_ext_phy(struct mt7915_dev *dev) if (phy) return 0; + INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work); mt7915_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops); if (!mphy) @@ -642,7 +643,7 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7915_mac_work); + INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 751363b4b7a2..7ad7c2b7afdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1156,26 +1156,32 @@ mt7915_dma_reset(struct mt7915_dev *dev) /* system error recovery */ void mt7915_mac_reset_work(struct work_struct *work) { + struct mt7915_phy *phy2; + struct mt76_phy *ext_phy; struct mt7915_dev *dev; dev = container_of(work, struct mt7915_dev, reset_work); + ext_phy = dev->mt76.phy2; + phy2 = ext_phy ? ext_phy->priv : NULL; if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) return; ieee80211_stop_queues(mt76_hw(dev)); - if (dev->mt76.phy2) - ieee80211_stop_queues(dev->mt76.phy2->hw); + if (ext_phy) + ieee80211_stop_queues(ext_phy->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&dev->phy.mac_work); + if (phy2) + cancel_delayed_work_sync(&phy2->mac_work); /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); - if (dev->mt76.phy2) - mt76_txq_schedule_all(dev->mt76.phy2); + if (ext_phy) + mt76_txq_schedule_all(ext_phy); tasklet_disable(&dev->mt76.tx_tasklet); napi_disable(&dev->mt76.napi[0]); @@ -1211,8 +1217,8 @@ void mt7915_mac_reset_work(struct work_struct *work) napi_schedule(&dev->mt76.napi[2]); ieee80211_wake_queues(mt76_hw(dev)); - if (dev->mt76.phy2) - ieee80211_wake_queues(dev->mt76.phy2->hw); + if (ext_phy) + ieee80211_wake_queues(ext_phy->hw); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); @@ -1221,8 +1227,11 @@ void mt7915_mac_reset_work(struct work_struct *work) mt7915_update_beacons(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, MT7915_WATCHDOG_TIME); + if (phy2) + ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work, + MT7915_WATCHDOG_TIME); } static void @@ -1307,25 +1316,25 @@ void mt7915_mac_sta_stats_work(struct work_struct *work) void mt7915_mac_work(struct work_struct *work) { - struct mt7915_dev *dev; + struct mt7915_phy *phy; + struct mt76_dev *mdev; - dev = (struct mt7915_dev *)container_of(work, struct mt76_dev, + phy = (struct mt7915_phy *)container_of(work, struct mt7915_phy, mac_work.work); + mdev = &phy->dev->mt76; - mutex_lock(&dev->mt76.mutex); - mt76_update_survey(&dev->mt76); - if (++dev->mac_work_count == 5) { - struct mt7915_phy *ext_phy = mt7915_ext_phy(dev); + mutex_lock(&mdev->mutex); - mt7915_mac_update_mib_stats(&dev->phy); - if (ext_phy) - mt7915_mac_update_mib_stats(ext_phy); + mt76_update_survey(mdev); + if (++phy->mac_work_count == 5) { + phy->mac_work_count = 0; - dev->mac_work_count = 0; + mt7915_mac_update_mib_stats(phy); } - mutex_unlock(&dev->mt76.mutex); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + mutex_unlock(&mdev->mutex); + + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, MT7915_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 147ab7da7aa9..98567374c2c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -47,14 +47,12 @@ static int mt7915_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - if (running) - goto out; + ieee80211_queue_delayed_work(hw, &phy->mac_work, + MT7915_WATCHDOG_TIME); - mt7915_mac_reset_counters(phy); + if (!running) + mt7915_mac_reset_counters(phy); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, - MT7915_WATCHDOG_TIME); -out: mutex_unlock(&dev->mt76.mutex); return 0; @@ -65,6 +63,8 @@ static void mt7915_stop(struct ieee80211_hw *hw) struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); + cancel_delayed_work_sync(&phy->mac_work); + mutex_lock(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -75,8 +75,6 @@ static void mt7915_stop(struct ieee80211_hw *hw) } if (!mt7915_dev_running(dev)) { - cancel_delayed_work_sync(&dev->mt76.mac_work); - mt7915_mcu_set_pm(dev, 0, 1); mt7915_mcu_set_mac(dev, 0, false, false); } @@ -230,7 +228,7 @@ static int mt7915_set_channel(struct mt7915_phy *phy) struct mt7915_dev *dev = phy->dev; int ret; - cancel_delayed_work_sync(&dev->mt76.mac_work); + cancel_delayed_work_sync(&phy->mac_work); mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &phy->mt76->state); @@ -254,7 +252,7 @@ out: mutex_unlock(&dev->mt76.mutex); mt76_txq_schedule_all(phy->mt76); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, MT7915_WATCHDOG_TIME); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 537fc126289f..5392292a838e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -141,6 +141,9 @@ struct mt7915_phy { u32 ampdu_ref; struct mib_stats mib; + + struct delayed_work mac_work; + u8 mac_work_count; }; struct mt7915_dev { @@ -168,7 +171,6 @@ struct mt7915_dev { s8 **rate_power; /* TODO: use mt76_rate_power */ - u8 mac_work_count; bool fw_debug; }; -- cgit From b2fe11f0777311a764e47e2f9437809b4673b7b1 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Tue, 12 May 2020 05:03:08 -0500 Subject: brcmfmac: fix WPA/WPA2-PSK 4-way handshake offload and SAE offload failures An incorrect value of use_fwsup is set for 4-way handshake offload for WPA//WPA2-PSK, caused by commit 3b1e0a7bdfee ("brcmfmac: add support for SAE authentication offload"). It results in missing bit BRCMF_VIF_STATUS_EAP_SUCCESS set in brcmf_is_linkup() and causes the failure. This patch correct the value for the case. Also setting bit BRCMF_VIF_STATUS_EAP_SUCCESS for SAE offload case in brcmf_is_linkup() to fix SAE offload failure. Fixes: 3b1e0a7bdfee ("brcmfmac: add support for SAE authentication offload") Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1589277788-119966-1-git-send-email-chi-hsien.lin@cypress.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 579b9306f533..fbec6dd551d6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1820,6 +1820,10 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_SAE: val = WPA3_AUTH_SAE_PSK; + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; + } break; default: bphy_err(drvr, "invalid cipher group (%d)\n", @@ -2105,11 +2109,6 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - if (sme->crypto.sae_pwd) { - brcmf_dbg(INFO, "using SAE offload\n"); - profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; - } - if (sme->crypto.psk && profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { @@ -5548,7 +5547,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, u32 event = e->event_code; u32 status = e->status; - if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK && + if ((vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK || + vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_SAE) && event == BRCMF_E_PSK_SUP && status == BRCMF_E_STATUS_FWSUP_COMPLETED) set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state); -- cgit From f71eb7f603170bf8742c53c9fb72a64df04cb6e4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:13 +0800 Subject: rtw88: 8723d: Add LC calibration LC calibration is done by hardware circuit. Driver sets the LCK bit to kick start, and then poll the bit to check if it's done. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-2-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 31 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 3 +++ 3 files changed, 35 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index e0365a70c6f7..c5046986f9af 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "util.h" diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 92c742d1ce6d..0f5ddd41b019 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -64,6 +64,34 @@ static const struct rtw_hw_reg rtw8723d_txagc[] = { #define WLAN_LTR_CTRL1 0xCB004010 #define WLAN_LTR_CTRL2 0x01233425 +static void rtw8723d_lck(struct rtw_dev *rtwdev) +{ + u32 lc_cal; + u8 val_ctx, rf_val; + int ret; + + val_ctx = rtw_read8(rtwdev, REG_CTX); + if ((val_ctx & BIT_MASK_CTX_TYPE) != 0) + rtw_write8(rtwdev, REG_CTX, val_ctx & ~BIT_MASK_CTX_TYPE); + else + rtw_write8(rtwdev, REG_TXPAUSE, 0xFF); + lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal | BIT_LCK); + + ret = read_poll_timeout(rtw_read_rf, rf_val, rf_val != 0x1, + 10000, 1000000, false, + rtwdev, RF_PATH_A, RF_CFGCH, BIT_LCK); + if (ret) + rtw_warn(rtwdev, "failed to poll LCK status bit\n"); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal); + if ((val_ctx & BIT_MASK_CTX_TYPE) != 0) + rtw_write8(rtwdev, REG_CTX, val_ctx); + else + rtw_write8(rtwdev, REG_TXPAUSE, 0x00); +} + static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) { u8 xtal_cap; @@ -125,6 +153,9 @@ static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) rtw_phy_init(rtwdev); rtw_write16_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN); + + rtw8723d_lck(rtwdev); + rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50); rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x20); } diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index ac66f672bec8..6a7d58992df5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -78,6 +78,7 @@ struct rtw8723d_efuse { #define RFCFGCH_BW_20M (BIT(11) | BIT(10)) #define RFCFGCH_BW_40M BIT(10) #define BIT_MASK_RFMOD BIT(0) +#define BIT_LCK BIT(15) #define REG_PSDFN 0x0808 #define REG_ANALOG_P4 0x088c @@ -115,6 +116,8 @@ struct rtw8723d_efuse { #define REG_OFDM_FA_RSTD_11N 0x0d00 #define BIT_MASK_OFDM_FA_RST1 BIT(27) #define BIT_MASK_OFDM_FA_KEEP1 BIT(31) +#define REG_CTX 0x0d03 +#define BIT_MASK_CTX_TYPE GENMASK(6, 4) #define REG_OFDM1_CFOTRK 0x0d2c #define BIT_EN_CFOTRK BIT(28) #define REG_OFDM1_CSI1 0x0d40 -- cgit From 1d229e88e53c20717a51ef8d8f9a69573167543a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:14 +0800 Subject: rtw88: 8723d: add IQ calibration IQ calibration is used to calibrate RF characteristic to yield expected performance. Basically, we do calibration twice and compare the similarity to determine calibration is good or not, if not we do the third calibration, and then compare with the results of first and second calibration. If it still not similar, IQK is failed. Before doing calibration, we need to backup registers that will be modified in calibration procedure, and restore these registers after calibration is done. A calibration procedure can divided into four sub-procedures that are S1-TX, S1-RX, S0-TX and S0-RX. Where, S1 and S0 represent to path A and B respectively. Each sub-procedure configure proper registers, and then rigger one-shot calibration and poll until completion. For RX calibration, it needs to do twice one-shot calibration, first one is to yield parameter used by second one. The result of TX part is stored for TX power tracking that adjusts TX AGC to output expected power. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-3-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/main.h | 12 + drivers/net/wireless/realtek/rtw88/phy.c | 2 + drivers/net/wireless/realtek/rtw88/reg.h | 10 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 817 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 122 ++++ 5 files changed, 963 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index c5046986f9af..af8c50e3687d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1400,6 +1400,16 @@ struct rtw_pkt_count { DECLARE_EWMA(evm, 10, 4); DECLARE_EWMA(snr, 10, 4); +struct rtw_iqk_info { + bool done; + struct { + u32 s1_x; + u32 s1_y; + u32 s0_x; + u32 s0_y; + } result; +}; + struct rtw_dm_info { u32 cck_fa_cnt; u32 ofdm_fa_cnt; @@ -1459,6 +1469,8 @@ struct rtw_dm_info { struct rtw_pkt_count last_pkt_count; struct ewma_evm ewma_evm[RTW_EVM_NUM]; struct ewma_snr ewma_snr[RTW_SNR_NUM]; + + struct rtw_iqk_info iqk; }; struct rtw_efuse { diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 72a16eff9db3..837b7bd04126 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -134,6 +134,8 @@ void rtw_phy_init(struct rtw_dev *rtwdev) mask = chip->dig[0].mask; dm_info->igi_history[0] = rtw_read32_mask(rtwdev, addr, mask); rtw_phy_cck_pd_init(rtwdev); + + dm_info->iqk.done = false; } void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi) diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 9fdfcdc5c5cf..d57de1a6cdcc 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -69,6 +69,7 @@ #define BIT_DPDT_SEL_EN BIT(23) #define REG_LEDCFG2 0x004E #define REG_PAD_CTRL1 0x0064 +#define BIT_BT_BTG_SEL BIT(31) #define BIT_PAPE_WLBT_SEL BIT(29) #define BIT_LNAON_WLBT_SEL BIT(28) #define BIT_BTGP_JTAG_EN BIT(24) @@ -611,7 +612,10 @@ #define REG_IGN_GNTBT4 0x4160 +#define RF_MODE 0x00 #define RF_MODOPT 0x01 +#define RF_WLINT 0x01 +#define RF_WLSEL 0x02 #define RF_DTXLOK 0x08 #define RF_CFGCH 0x18 #define RF_RCK 0x1d @@ -619,9 +623,15 @@ #define RF_LUTWD1 0x3e #define RF_LUTWD0 0x3f #define RF_T_METER 0x42 +#define RF_BSPAD 0x54 +#define RF_GAINTX 0x56 +#define RF_TXATANK 0x64 +#define RF_TRXIQ 0x66 +#define RF_RXIQGEN 0x8d #define RF_XTALX2 0xb8 #define RF_MALSEL 0xbe #define RF_RCKD 0xde +#define RF_TXADBG 0xde #define RF_LUTDBG 0xdf #define RF_LUTWE2 0xee #define RF_LUTWE 0xef diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 0f5ddd41b019..0cfa493e7742 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -634,6 +634,822 @@ static void rtw8723d_false_alarm_statistics(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, REG_PAGE_F_RST_11N, BIT_MASK_F_RST_ALL, 0); } +static const u32 iqk_adda_regs[] = { + 0x85c, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, + 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec +}; + +static const u32 iqk_mac8_regs[] = {0x522, 0x550, 0x551}; +static const u32 iqk_mac32_regs[] = {0x40}; + +static const u32 iqk_bb_regs[] = { + 0xc04, 0xc08, 0x874, 0xb68, 0xb6c, 0x870, 0x860, 0x864, 0xa04 +}; + +#define IQK_ADDA_REG_NUM ARRAY_SIZE(iqk_adda_regs) +#define IQK_MAC8_REG_NUM ARRAY_SIZE(iqk_mac8_regs) +#define IQK_MAC32_REG_NUM ARRAY_SIZE(iqk_mac32_regs) +#define IQK_BB_REG_NUM ARRAY_SIZE(iqk_bb_regs) + +struct iqk_backup_regs { + u32 adda[IQK_ADDA_REG_NUM]; + u8 mac8[IQK_MAC8_REG_NUM]; + u32 mac32[IQK_MAC32_REG_NUM]; + u32 bb[IQK_BB_REG_NUM]; + + u32 lte_path; + u32 lte_gnt; + + u32 bb_sel_btg; + u8 btg_sel; + + u8 igia; + u8 igib; +}; + +static void rtw8723d_iqk_backup_regs(struct rtw_dev *rtwdev, + struct iqk_backup_regs *backup) +{ + int i; + + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + backup->adda[i] = rtw_read32(rtwdev, iqk_adda_regs[i]); + + for (i = 0; i < IQK_MAC8_REG_NUM; i++) + backup->mac8[i] = rtw_read8(rtwdev, iqk_mac8_regs[i]); + for (i = 0; i < IQK_MAC32_REG_NUM; i++) + backup->mac32[i] = rtw_read32(rtwdev, iqk_mac32_regs[i]); + + for (i = 0; i < IQK_BB_REG_NUM; i++) + backup->bb[i] = rtw_read32(rtwdev, iqk_bb_regs[i]); + + backup->igia = rtw_read32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0); + backup->igib = rtw_read32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0); + + backup->bb_sel_btg = rtw_read32(rtwdev, REG_BB_SEL_BTG); +} + +static void rtw8723d_iqk_restore_regs(struct rtw_dev *rtwdev, + const struct iqk_backup_regs *backup) +{ + int i; + + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + rtw_write32(rtwdev, iqk_adda_regs[i], backup->adda[i]); + + for (i = 0; i < IQK_MAC8_REG_NUM; i++) + rtw_write8(rtwdev, iqk_mac8_regs[i], backup->mac8[i]); + for (i = 0; i < IQK_MAC32_REG_NUM; i++) + rtw_write32(rtwdev, iqk_mac32_regs[i], backup->mac32[i]); + + for (i = 0; i < IQK_BB_REG_NUM; i++) + rtw_write32(rtwdev, iqk_bb_regs[i], backup->bb[i]); + + rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50); + rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, backup->igia); + + rtw_write32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0, 0x50); + rtw_write32_mask(rtwdev, REG_OFDM0_XBAGC1, MASKBYTE0, backup->igib); + + rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x01008c00); + rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x01008c00); +} + +static void rtw8723d_iqk_backup_path_ctrl(struct rtw_dev *rtwdev, + struct iqk_backup_regs *backup) +{ + backup->btg_sel = rtw_read8(rtwdev, REG_BTG_SEL); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] original 0x67 = 0x%x\n", + backup->btg_sel); +} + +static void rtw8723d_iqk_config_path_ctrl(struct rtw_dev *rtwdev) +{ + rtw_write32_mask(rtwdev, REG_PAD_CTRL1, BIT_BT_BTG_SEL, 0x1); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] set 0x67 = 0x%x\n", + rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3)); +} + +static void rtw8723d_iqk_restore_path_ctrl(struct rtw_dev *rtwdev, + const struct iqk_backup_regs *backup) +{ + rtw_write8(rtwdev, REG_BTG_SEL, backup->btg_sel); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] restore 0x67 = 0x%x\n", + rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3)); +} + +static void rtw8723d_iqk_backup_lte_path_gnt(struct rtw_dev *rtwdev, + struct iqk_backup_regs *backup) +{ + backup->lte_path = rtw_read32(rtwdev, REG_LTECOEX_PATH_CONTROL); + rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0x800f0038); + mdelay(1); + backup->lte_gnt = rtw_read32(rtwdev, REG_LTECOEX_READ_DATA); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] OriginalGNT = 0x%x\n", + backup->lte_gnt); +} + +static void rtw8723d_iqk_config_lte_path_gnt(struct rtw_dev *rtwdev) +{ + rtw_write32(rtwdev, REG_LTECOEX_WRITE_DATA, 0x0000ff00); + rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0xc0020038); + rtw_write32_mask(rtwdev, REG_LTECOEX_PATH_CONTROL, BIT_LTE_MUX_CTRL_PATH, 0x1); +} + +static void rtw8723d_iqk_restore_lte_path_gnt(struct rtw_dev *rtwdev, + const struct iqk_backup_regs *bak) +{ + rtw_write32(rtwdev, REG_LTECOEX_WRITE_DATA, bak->lte_gnt); + rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0xc00f0038); + rtw_write32(rtwdev, REG_LTECOEX_PATH_CONTROL, bak->lte_path); +} + +struct rtw_8723d_iqk_cfg { + const char *name; + u32 val_bb_sel_btg; + u32 reg_lutwe; + u32 val_txiqk_pi; + u32 reg_padlut; + u32 reg_gaintx; + u32 reg_bspad; + u32 val_wlint; + u32 val_wlsel; + u32 val_iqkpts; +}; + +static const struct rtw_8723d_iqk_cfg iqk_tx_cfg[PATH_NR] = { + [PATH_S1] = { + .name = "S1", + .val_bb_sel_btg = 0x99000000, + .reg_lutwe = RF_LUTWE, + .val_txiqk_pi = 0x8214019f, + .reg_padlut = RF_LUTDBG, + .reg_gaintx = RF_GAINTX, + .reg_bspad = RF_BSPAD, + .val_wlint = 0xe0d, + .val_wlsel = 0x60d, + .val_iqkpts = 0xfa000000, + }, + [PATH_S0] = { + .name = "S0", + .val_bb_sel_btg = 0x99000280, + .reg_lutwe = RF_LUTWE2, + .val_txiqk_pi = 0x8214018a, + .reg_padlut = RF_TXADBG, + .reg_gaintx = RF_TRXIQ, + .reg_bspad = RF_TXATANK, + .val_wlint = 0xe6d, + .val_wlsel = 0x66d, + .val_iqkpts = 0xf9000000, + }, +}; + +static u8 rtw8723d_iqk_check_tx_failed(struct rtw_dev *rtwdev, + const struct rtw_8723d_iqk_cfg *iqk_cfg) +{ + s32 tx_x, tx_y; + u32 tx_fail; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xeac = 0x%x\n", + rtw_read32(rtwdev, REG_IQK_RES_RY)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xe94 = 0x%x, 0xe9c = 0x%x\n", + rtw_read32(rtwdev, REG_IQK_RES_TX), + rtw_read32(rtwdev, REG_IQK_RES_TY)); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] 0xe90(before IQK)= 0x%x, 0xe98(afer IQK) = 0x%x\n", + rtw_read32(rtwdev, 0xe90), + rtw_read32(rtwdev, 0xe98)); + + tx_fail = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_IQK_TX_FAIL); + tx_x = rtw_read32_mask(rtwdev, REG_IQK_RES_TX, BIT_MASK_RES_TX); + tx_y = rtw_read32_mask(rtwdev, REG_IQK_RES_TY, BIT_MASK_RES_TY); + + if (!tx_fail && tx_x != IQK_TX_X_ERR && tx_y != IQK_TX_Y_ERR) + return IQK_TX_OK; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] %s TXIQK is failed\n", + iqk_cfg->name); + + return 0; +} + +static u8 rtw8723d_iqk_check_rx_failed(struct rtw_dev *rtwdev, + const struct rtw_8723d_iqk_cfg *iqk_cfg) +{ + s32 rx_x, rx_y; + u32 rx_fail; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xea4 = 0x%x, 0xeac = 0x%x\n", + rtw_read32(rtwdev, REG_IQK_RES_RX), + rtw_read32(rtwdev, REG_IQK_RES_RY)); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] 0xea0(before IQK)= 0x%x, 0xea8(afer IQK) = 0x%x\n", + rtw_read32(rtwdev, 0xea0), + rtw_read32(rtwdev, 0xea8)); + + rx_fail = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_IQK_RX_FAIL); + rx_x = rtw_read32_mask(rtwdev, REG_IQK_RES_RX, BIT_MASK_RES_RX); + rx_y = rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_MASK_RES_RY); + rx_y = abs(iqkxy_to_s32(rx_y)); + + if (!rx_fail && rx_x < IQK_RX_X_UPPER && rx_x > IQK_RX_X_LOWER && + rx_y < IQK_RX_Y_LMT) + return IQK_RX_OK; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] %s RXIQK STEP2 is failed\n", + iqk_cfg->name); + + return 0; +} + +static void rtw8723d_iqk_one_shot(struct rtw_dev *rtwdev, bool tx, + const struct rtw_8723d_iqk_cfg *iqk_cfg) +{ + u32 pts = (tx ? iqk_cfg->val_iqkpts : 0xf9000000); + + /* enter IQK mode */ + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, EN_IQK); + rtw8723d_iqk_config_lte_path_gnt(rtwdev); + + rtw_write32(rtwdev, REG_LTECOEX_CTRL, 0x800f0054); + mdelay(1); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] GNT_BT @%s %sIQK1 = 0x%x\n", + iqk_cfg->name, tx ? "TX" : "RX", + rtw_read32(rtwdev, REG_LTECOEX_READ_DATA)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0x948 @%s %sIQK1 = 0x%x\n", + iqk_cfg->name, tx ? "TX" : "RX", + rtw_read32(rtwdev, REG_BB_SEL_BTG)); + + /* One shot, LOK & IQK */ + rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, pts); + rtw_write32(rtwdev, REG_IQK_AGC_PTS_11N, 0xf8000000); + + if (!check_hw_ready(rtwdev, REG_IQK_RES_RY, BIT_IQK_DONE, 1)) + rtw_warn(rtwdev, "%s %s IQK isn't done\n", iqk_cfg->name, + tx ? "TX" : "RX"); +} + +static void rtw8723d_iqk_txrx_path_post(struct rtw_dev *rtwdev, + const struct rtw_8723d_iqk_cfg *iqk_cfg, + const struct iqk_backup_regs *backup) +{ + rtw8723d_iqk_restore_lte_path_gnt(rtwdev, backup); + rtw_write32(rtwdev, REG_BB_SEL_BTG, backup->bb_sel_btg); + + /* leave IQK mode */ + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + mdelay(1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_padlut, 0x800, 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, BIT(0), 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLSEL, BIT(0), 0x0); +} + +static u8 rtw8723d_iqk_tx_path(struct rtw_dev *rtwdev, + const struct rtw_8723d_iqk_cfg *iqk_cfg, + const struct iqk_backup_regs *backup) +{ + u8 status; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path %s TXIQK!!\n", iqk_cfg->name); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0x67 @%s TXIQK = 0x%x\n", + iqk_cfg->name, + rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3)); + + rtw_write32(rtwdev, REG_BB_SEL_BTG, iqk_cfg->val_bb_sel_btg); + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + mdelay(1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x00004); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD1, RFREG_MASK, 0x0005d); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0xBFFE0); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, RFREG_MASK, 0x00000); + + /* IQK setting */ + rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x08008c0c); + rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x38008c1c); + rtw_write32(rtwdev, REG_TXIQK_PI_A_11N, iqk_cfg->val_txiqk_pi); + rtw_write32(rtwdev, REG_RXIQK_PI_A_11N, 0x28160200); + rtw_write32(rtwdev, REG_TXIQK_11N, 0x01007c00); + rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800); + + /* LOK setting */ + rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x00462911); + + /* PA, PAD setting */ + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_padlut, 0x800, 0x1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_gaintx, 0x600, 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_gaintx, 0x1E0, 0x3); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXIQGEN, 0x1F, 0xf); + + /* LOK setting for 8723D */ + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, 0x10, 0x1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_bspad, 0x1, 0x1); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK, iqk_cfg->val_wlint); + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLSEL, RFREG_MASK, iqk_cfg->val_wlsel); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x1 @%s TXIQK = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x2 @%s TXIQK = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLSEL, RFREG_MASK)); + + rtw8723d_iqk_one_shot(rtwdev, true, iqk_cfg); + status = rtw8723d_iqk_check_tx_failed(rtwdev, iqk_cfg); + + rtw8723d_iqk_txrx_path_post(rtwdev, iqk_cfg, backup); + + return status; +} + +static u8 rtw8723d_iqk_rx_path(struct rtw_dev *rtwdev, + const struct rtw_8723d_iqk_cfg *iqk_cfg, + const struct iqk_backup_regs *backup) +{ + u32 tx_x, tx_y; + u8 status; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path %s RXIQK Step1!!\n", + iqk_cfg->name); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0x67 @%s RXIQK1 = 0x%x\n", + iqk_cfg->name, + rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3)); + rtw_write32(rtwdev, REG_BB_SEL_BTG, iqk_cfg->val_bb_sel_btg); + + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + + /* IQK setting */ + rtw_write32(rtwdev, REG_TXIQK_11N, 0x01007c00); + rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800); + + /* path IQK setting */ + rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x18008c1c); + rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x38008c1c); + rtw_write32(rtwdev, REG_TX_IQK_TONE_B, 0x38008c1c); + rtw_write32(rtwdev, REG_RX_IQK_TONE_B, 0x38008c1c); + rtw_write32(rtwdev, REG_TXIQK_PI_A_11N, 0x82160000); + rtw_write32(rtwdev, REG_RXIQK_PI_A_11N, 0x28160000); + + /* LOK setting */ + rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x0046a911); + + /* RXIQK mode */ + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x00006); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD1, RFREG_MASK, 0x0005f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0xa7ffb); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, RFREG_MASK, 0x00000); + + /* PA/PAD=0 */ + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_padlut, 0x800, 0x1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_gaintx, 0x600, 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK, iqk_cfg->val_wlint); + rtw_write_rf(rtwdev, RF_PATH_A, RF_WLSEL, RFREG_MASK, iqk_cfg->val_wlsel); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x1@ path %s RXIQK1 = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x2@ path %s RXIQK1 = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLSEL, RFREG_MASK)); + + rtw8723d_iqk_one_shot(rtwdev, false, iqk_cfg); + status = rtw8723d_iqk_check_tx_failed(rtwdev, iqk_cfg); + + if (!status) + goto restore; + + /* second round */ + tx_x = rtw_read32_mask(rtwdev, REG_IQK_RES_TX, BIT_MASK_RES_TX); + tx_y = rtw_read32_mask(rtwdev, REG_IQK_RES_TY, BIT_MASK_RES_TY); + + rtw_write32(rtwdev, REG_TXIQK_11N, BIT_SET_TXIQK_11N(tx_x, tx_y)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0xe40 = 0x%x u4tmp = 0x%x\n", + rtw_read32(rtwdev, REG_TXIQK_11N), + BIT_SET_TXIQK_11N(tx_x, tx_y)); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path %s RXIQK STEP2!!\n", + iqk_cfg->name); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] 0x67 @%s RXIQK2 = 0x%x\n", + iqk_cfg->name, + rtw_read32_mask(rtwdev, REG_PAD_CTRL1, MASKBYTE3)); + + rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800); + rtw_write32(rtwdev, REG_TXIQK_TONE_A_11N, 0x38008c1c); + rtw_write32(rtwdev, REG_RXIQK_TONE_A_11N, 0x18008c1c); + rtw_write32(rtwdev, REG_TX_IQK_TONE_B, 0x38008c1c); + rtw_write32(rtwdev, REG_RX_IQK_TONE_B, 0x38008c1c); + rtw_write32(rtwdev, REG_TXIQK_PI_A_11N, 0x82170000); + rtw_write32(rtwdev, REG_RXIQK_PI_A_11N, 0x28171400); + + /* LOK setting */ + rtw_write32(rtwdev, REG_IQK_AGC_RSP_11N, 0x0046a8d1); + + /* RXIQK mode */ + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + mdelay(1); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, 0x80000, 0x1); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWA, RFREG_MASK, 0x00007); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD1, RFREG_MASK, 0x0005f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWD0, RFREG_MASK, 0xb3fdb); + rtw_write_rf(rtwdev, RF_PATH_A, iqk_cfg->reg_lutwe, RFREG_MASK, 0x00000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x1 @%s RXIQK2 = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLINT, RFREG_MASK)); + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] RF0x2 @%s RXIQK2 = 0x%x\n", + iqk_cfg->name, + rtw_read_rf(rtwdev, RF_PATH_A, RF_WLSEL, RFREG_MASK)); + + rtw8723d_iqk_one_shot(rtwdev, false, iqk_cfg); + status |= rtw8723d_iqk_check_rx_failed(rtwdev, iqk_cfg); + +restore: + rtw8723d_iqk_txrx_path_post(rtwdev, iqk_cfg, backup); + + return status; +} + +static +void rtw8723d_iqk_fill_s1_matrix(struct rtw_dev *rtwdev, const s32 result[]) +{ + s32 oldval_1; + s32 x, y; + s32 tx1_a, tx1_a_ext; + s32 tx1_c, tx1_c_ext; + + if (result[IQK_S1_TX_X] == 0) + return; + + oldval_1 = rtw_read32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, + BIT_MASK_TXIQ_ELM_D); + + x = iqkxy_to_s32(result[IQK_S1_TX_X]); + tx1_a = iqk_mult(x, oldval_1, &tx1_a_ext); + rtw_write32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, + BIT_MASK_TXIQ_ELM_A, tx1_a); + rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, + BIT_MASK_OFDM0_EXT_A, tx1_a_ext); + + y = iqkxy_to_s32(result[IQK_S1_TX_Y]); + tx1_c = iqk_mult(y, oldval_1, &tx1_c_ext); + rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS, + BIT_SET_TXIQ_ELM_C1(tx1_c)); + rtw_write32_mask(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, + BIT_MASK_TXIQ_ELM_C, BIT_SET_TXIQ_ELM_C2(tx1_c)); + rtw_write32_mask(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, + BIT_MASK_OFDM0_EXT_C, tx1_c_ext); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] X = 0x%x, TX1_A = 0x%x, oldval_1 0x%x\n", + x, tx1_a, oldval_1); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] Y = 0x%x, TX1_C = 0x%x\n", y, tx1_c); + + if (result[IQK_S1_RX_X] == 0) + return; + + rtw_write32_mask(rtwdev, REG_A_RXIQI, BIT_MASK_RXIQ_S1_X, + result[IQK_S1_RX_X]); + rtw_write32_mask(rtwdev, REG_A_RXIQI, BIT_MASK_RXIQ_S1_Y1, + BIT_SET_RXIQ_S1_Y1(result[IQK_S1_RX_Y])); + rtw_write32_mask(rtwdev, REG_RXIQK_MATRIX_LSB_11N, BIT_MASK_RXIQ_S1_Y2, + BIT_SET_RXIQ_S1_Y2(result[IQK_S1_RX_Y])); +} + +static +void rtw8723d_iqk_fill_s0_matrix(struct rtw_dev *rtwdev, const s32 result[]) +{ + s32 oldval_0; + s32 x, y; + s32 tx0_a, tx0_a_ext; + s32 tx0_c, tx0_c_ext; + + if (result[IQK_S0_TX_X] == 0) + return; + + oldval_0 = rtw_read32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_D_S0); + + x = iqkxy_to_s32(result[IQK_S0_TX_X]); + tx0_a = iqk_mult(x, oldval_0, &tx0_a_ext); + + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_S0, tx0_a); + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_EXT_S0, tx0_a_ext); + + y = iqkxy_to_s32(result[IQK_S0_TX_Y]); + tx0_c = iqk_mult(y, oldval_0, &tx0_c_ext); + + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_S0, tx0_c); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_EXT_S0, tx0_c_ext); + + if (result[IQK_S0_RX_X] == 0) + return; + + rtw_write32_mask(rtwdev, REG_RXIQ_AB_S0, BIT_MASK_RXIQ_X_S0, + result[IQK_S0_RX_X]); + rtw_write32_mask(rtwdev, REG_RXIQ_AB_S0, BIT_MASK_RXIQ_Y_S0, + result[IQK_S0_RX_Y]); +} + +static void rtw8723d_iqk_path_adda_on(struct rtw_dev *rtwdev) +{ + int i; + + for (i = 0; i < IQK_ADDA_REG_NUM; i++) + rtw_write32(rtwdev, iqk_adda_regs[i], 0x03c00016); +} + +static void rtw8723d_iqk_config_mac(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_TXPAUSE, 0xff); +} + +static +void rtw8723d_iqk_rf_standby(struct rtw_dev *rtwdev, enum rtw_rf_path path) +{ + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path-%s standby mode!\n", + path == RF_PATH_A ? "S1" : "S0"); + + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + mdelay(1); + rtw_write_rf(rtwdev, path, RF_MODE, RFREG_MASK, 0x10000); + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, EN_IQK); +} + +static +bool rtw8723d_iqk_similarity_cmp(struct rtw_dev *rtwdev, s32 result[][IQK_NR], + u8 c1, u8 c2) +{ + u32 i, j, diff; + u32 bitmap = 0; + u8 candidate[PATH_NR] = {IQK_ROUND_INVALID, IQK_ROUND_INVALID}; + bool ret = true; + + s32 tmp1, tmp2; + + for (i = 0; i < IQK_NR; i++) { + tmp1 = iqkxy_to_s32(result[c1][i]); + tmp2 = iqkxy_to_s32(result[c2][i]); + + diff = abs(tmp1 - tmp2); + + if (diff <= MAX_TOLERANCE) + continue; + + if ((i == IQK_S1_RX_X || i == IQK_S0_RX_X) && !bitmap) { + if (result[c1][i] + result[c1][i + 1] == 0) + candidate[i / IQK_SX_NR] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + candidate[i / IQK_SX_NR] = c1; + else + bitmap |= BIT(i); + } else { + bitmap |= BIT(i); + } + } + + if (bitmap != 0) + goto check_sim; + + for (i = 0; i < PATH_NR; i++) { + if (candidate[i] == IQK_ROUND_INVALID) + continue; + + for (j = i * IQK_SX_NR; j < i * IQK_SX_NR + 2; j++) + result[IQK_ROUND_HYBRID][j] = result[candidate[i]][j]; + ret = false; + } + + return ret; + +check_sim: + for (i = 0; i < IQK_NR; i++) { + j = i & ~1; /* 2 bits are a pair for IQ[X, Y] */ + if (bitmap & GENMASK(j + 1, j)) + continue; + + result[IQK_ROUND_HYBRID][i] = result[c1][i]; + } + + return false; +} + +static +void rtw8723d_iqk_precfg_path(struct rtw_dev *rtwdev, enum rtw8723d_path path) +{ + if (path == PATH_S0) { + rtw8723d_iqk_rf_standby(rtwdev, RF_PATH_A); + rtw8723d_iqk_path_adda_on(rtwdev); + } + + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, EN_IQK); + rtw_write32(rtwdev, REG_TXIQK_11N, 0x01007c00); + rtw_write32(rtwdev, REG_RXIQK_11N, 0x01004800); + + if (path == PATH_S1) { + rtw8723d_iqk_rf_standby(rtwdev, RF_PATH_B); + rtw8723d_iqk_path_adda_on(rtwdev); + } +} + +static +void rtw8723d_iqk_one_round(struct rtw_dev *rtwdev, s32 result[][IQK_NR], u8 t, + const struct iqk_backup_regs *backup) +{ + u32 i; + u8 s1_ok, s0_ok; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] IQ Calibration for 1T1R_S0/S1 for %d times\n", t); + + rtw8723d_iqk_path_adda_on(rtwdev); + rtw8723d_iqk_config_mac(rtwdev); + rtw_write32_mask(rtwdev, REG_CCK_ANT_SEL_11N, 0x0f000000, 0xf); + rtw_write32(rtwdev, REG_BB_RX_PATH_11N, 0x03a05611); + rtw_write32(rtwdev, REG_TRMUX_11N, 0x000800e4); + rtw_write32(rtwdev, REG_BB_PWR_SAV1_11N, 0x25204200); + rtw8723d_iqk_precfg_path(rtwdev, PATH_S1); + + for (i = 0; i < PATH_IQK_RETRY; i++) { + s1_ok = rtw8723d_iqk_tx_path(rtwdev, &iqk_tx_cfg[PATH_S1], backup); + if (s1_ok == IQK_TX_OK) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] path S1 Tx IQK Success!!\n"); + result[t][IQK_S1_TX_X] = + rtw_read32_mask(rtwdev, REG_IQK_RES_TX, BIT_MASK_RES_TX); + result[t][IQK_S1_TX_Y] = + rtw_read32_mask(rtwdev, REG_IQK_RES_TY, BIT_MASK_RES_TY); + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S1 Tx IQK Fail!!\n"); + result[t][IQK_S1_TX_X] = 0x100; + result[t][IQK_S1_TX_Y] = 0x0; + } + + for (i = 0; i < PATH_IQK_RETRY; i++) { + s1_ok = rtw8723d_iqk_rx_path(rtwdev, &iqk_tx_cfg[PATH_S1], backup); + if (s1_ok == (IQK_TX_OK | IQK_RX_OK)) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] path S1 Rx IQK Success!!\n"); + result[t][IQK_S1_RX_X] = + rtw_read32_mask(rtwdev, REG_IQK_RES_RX, BIT_MASK_RES_RX); + result[t][IQK_S1_RX_Y] = + rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_MASK_RES_RY); + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S1 Rx IQK Fail!!\n"); + result[t][IQK_S1_RX_X] = 0x100; + result[t][IQK_S1_RX_Y] = 0x0; + } + + if (s1_ok == 0x0) + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S1 IQK is failed!!\n"); + + rtw8723d_iqk_precfg_path(rtwdev, PATH_S0); + + for (i = 0; i < PATH_IQK_RETRY; i++) { + s0_ok = rtw8723d_iqk_tx_path(rtwdev, &iqk_tx_cfg[PATH_S0], backup); + if (s0_ok == IQK_TX_OK) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] path S0 Tx IQK Success!!\n"); + result[t][IQK_S0_TX_X] = + rtw_read32_mask(rtwdev, REG_IQK_RES_TX, BIT_MASK_RES_TX); + result[t][IQK_S0_TX_Y] = + rtw_read32_mask(rtwdev, REG_IQK_RES_TY, BIT_MASK_RES_TY); + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S0 Tx IQK Fail!!\n"); + result[t][IQK_S0_TX_X] = 0x100; + result[t][IQK_S0_TX_Y] = 0x0; + } + + for (i = 0; i < PATH_IQK_RETRY; i++) { + s0_ok = rtw8723d_iqk_rx_path(rtwdev, &iqk_tx_cfg[PATH_S0], backup); + if (s0_ok == (IQK_TX_OK | IQK_RX_OK)) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] path S0 Rx IQK Success!!\n"); + + result[t][IQK_S0_RX_X] = + rtw_read32_mask(rtwdev, REG_IQK_RES_RX, BIT_MASK_RES_RX); + result[t][IQK_S0_RX_Y] = + rtw_read32_mask(rtwdev, REG_IQK_RES_RY, BIT_MASK_RES_RY); + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S0 Rx IQK Fail!!\n"); + result[t][IQK_S0_RX_X] = 0x100; + result[t][IQK_S0_RX_Y] = 0x0; + } + + if (s0_ok == 0x0) + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] path S0 IQK is failed!!\n"); + + rtw_write32_mask(rtwdev, REG_FPGA0_IQK_11N, BIT_MASK_IQK_MOD, RST_IQK); + mdelay(1); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] back to BB mode, load original value!\n"); +} + +static void rtw8723d_phy_calibration(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s32 result[IQK_ROUND_SIZE][IQK_NR]; + struct iqk_backup_regs backup; + u8 i, j; + u8 final_candidate = IQK_ROUND_INVALID; + bool good; + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] Start!!!\n"); + + memset(result, 0, sizeof(result)); + + rtw8723d_iqk_backup_path_ctrl(rtwdev, &backup); + rtw8723d_iqk_backup_lte_path_gnt(rtwdev, &backup); + rtw8723d_iqk_backup_regs(rtwdev, &backup); + + for (i = IQK_ROUND_0; i <= IQK_ROUND_2; i++) { + rtw8723d_iqk_config_path_ctrl(rtwdev); + rtw8723d_iqk_config_lte_path_gnt(rtwdev); + + rtw8723d_iqk_one_round(rtwdev, result, i, &backup); + + if (i > IQK_ROUND_0) + rtw8723d_iqk_restore_regs(rtwdev, &backup); + rtw8723d_iqk_restore_lte_path_gnt(rtwdev, &backup); + rtw8723d_iqk_restore_path_ctrl(rtwdev, &backup); + + for (j = IQK_ROUND_0; j < i; j++) { + good = rtw8723d_iqk_similarity_cmp(rtwdev, result, j, i); + + if (good) { + final_candidate = j; + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] cmp %d:%d final_candidate is %x\n", + j, i, final_candidate); + goto iqk_done; + } + } + } + + if (final_candidate == IQK_ROUND_INVALID) { + s32 reg_tmp = 0; + + for (i = 0; i < IQK_NR; i++) + reg_tmp += result[IQK_ROUND_HYBRID][i]; + + if (reg_tmp != 0) { + final_candidate = IQK_ROUND_HYBRID; + } else { + WARN(1, "IQK is failed\n"); + goto out; + } + } + +iqk_done: + rtw8723d_iqk_fill_s1_matrix(rtwdev, result[final_candidate]); + rtw8723d_iqk_fill_s0_matrix(rtwdev, result[final_candidate]); + + dm_info->iqk.result.s1_x = result[final_candidate][IQK_S1_TX_X]; + dm_info->iqk.result.s1_y = result[final_candidate][IQK_S1_TX_Y]; + dm_info->iqk.result.s0_x = result[final_candidate][IQK_S0_TX_X]; + dm_info->iqk.result.s0_y = result[final_candidate][IQK_S0_TX_Y]; + dm_info->iqk.done = true; + +out: + rtw_write32(rtwdev, REG_BB_SEL_BTG, backup.bb_sel_btg); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] final_candidate is %x\n", + final_candidate); + + for (i = IQK_ROUND_0; i < IQK_ROUND_SIZE; i++) + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK] Result %u: rege94_s1=%x rege9c_s1=%x regea4_s1=%x regeac_s1=%x rege94_s0=%x rege9c_s0=%x regea4_s0=%x regeac_s0=%x %s\n", + i, + result[i][0], result[i][1], result[i][2], result[i][3], + result[i][4], result[i][5], result[i][6], result[i][7], + final_candidate == i ? "(final candidate)" : ""); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK]0xc80 = 0x%x 0xc94 = 0x%x 0xc14 = 0x%x 0xca0 = 0x%x\n", + rtw_read32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE), + rtw_read32(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N), + rtw_read32(rtwdev, REG_A_RXIQI), + rtw_read32(rtwdev, REG_RXIQK_MATRIX_LSB_11N)); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "[IQK]0xcd0 = 0x%x 0xcd4 = 0x%x 0xcd8 = 0x%x\n", + rtw_read32(rtwdev, REG_TXIQ_AB_S0), + rtw_read32(rtwdev, REG_TXIQ_CD_S0), + rtw_read32(rtwdev, REG_RXIQ_AB_S0)); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] finished\n"); +} + static struct rtw_chip_ops rtw8723d_ops = { .phy_set_param = rtw8723d_phy_set_param, .read_efuse = rtw8723d_read_efuse, @@ -647,6 +1463,7 @@ static struct rtw_chip_ops rtw8723d_ops = { .cfg_ldo25 = rtw8723d_cfg_ldo25, .efuse_grant = rtw8723d_efuse_grant, .false_alarm_statistics = rtw8723d_false_alarm_statistics, + .phy_calibration = rtw8723d_phy_calibration, .config_bfee = NULL, .set_gid_table = NULL, .cfg_csi_rate = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index 6a7d58992df5..549dfcf7f5da 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -5,6 +5,34 @@ #ifndef __RTW8723D_H__ #define __RTW8723D_H__ +enum rtw8723d_path { + PATH_S1, + PATH_S0, + PATH_NR, +}; + +enum rtw8723d_iqk_round { + IQK_ROUND_0, + IQK_ROUND_1, + IQK_ROUND_2, + IQK_ROUND_HYBRID, + IQK_ROUND_SIZE, + IQK_ROUND_INVALID = 0xff, +}; + +enum rtw8723d_iqk_result { + IQK_S1_TX_X, + IQK_S1_TX_Y, + IQK_S1_RX_X, + IQK_S1_RX_Y, + IQK_S0_TX_X, + IQK_S0_TX_Y, + IQK_S0_RX_X, + IQK_S0_RX_Y, + IQK_NR, + IQK_SX_NR = IQK_NR / PATH_NR, +}; + struct rtw8723de_efuse { u8 mac_addr[ETH_ALEN]; /* 0xd0 */ u8 vender_id[2]; @@ -66,6 +94,34 @@ struct rtw8723d_efuse { #define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +static inline s32 iqkxy_to_s32(s32 val) +{ + /* val is Q10.8 */ + return sign_extend32(val, 9); +} + +static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) +{ + /* x, y and return value are Q10.8 */ + s32 t; + + t = x * y; + if (ext) + *ext = (t >> 7) & 0x1; /* Q.16 --> Q.9; get LSB of Q.9 */ + + return (t >> 8); /* Q.16 --> Q.8 */ +} + +#define MAX_TOLERANCE 5 +#define IQK_TX_X_ERR 0x142 +#define IQK_TX_Y_ERR 0x42 +#define IQK_RX_X_UPPER 0x11a +#define IQK_RX_X_LOWER 0xe6 +#define IQK_RX_Y_LMT 0x1a +#define IQK_TX_OK BIT(0) +#define IQK_RX_OK BIT(1) +#define PATH_IQK_RETRY 2 + #define SPUR_THRES 0x16 #define CCK_DFIR_NR 3 #define DIS_3WIRE 0xccf000c0 @@ -80,15 +136,20 @@ struct rtw8723d_efuse { #define BIT_MASK_RFMOD BIT(0) #define BIT_LCK BIT(15) +#define REG_BTG_SEL 0x0067 +#define REG_LTECOEX_PATH_CONTROL 0x0070 #define REG_PSDFN 0x0808 +#define REG_BB_PWR_SAV1_11N 0x0874 #define REG_ANALOG_P4 0x088c #define REG_PSDRPT 0x08b4 #define REG_FPGA1_RFMOD 0x0900 +#define REG_BB_SEL_BTG 0x0948 #define REG_BBRX_DFIR 0x0954 #define BIT_MASK_RXBB_DFIR GENMASK(27, 24) #define BIT_RXBB_DFIR_EN BIT(19) #define REG_CCK0_SYS 0x0a00 #define BIT_CCK_SIDE_BAND BIT(4) +#define REG_CCK_ANT_SEL_11N 0x0a04 #define REG_CCK_FA_RST_11N 0x0a2c #define BIT_MASK_CCK_CNT_KEEP BIT(12) #define BIT_MASK_CCK_CNT_EN BIT(13) @@ -103,13 +164,48 @@ struct rtw8723d_efuse { #define BIT_MASK_CCK_FA_LSB GENMASK(15, 8) #define REG_OFDM_FA_HOLDC_11N 0x0c00 #define BIT_MASK_OFDM_FA_KEEP BIT(31) +#define REG_BB_RX_PATH_11N 0x0c04 +#define REG_TRMUX_11N 0x0c08 #define REG_OFDM_FA_RSTC_11N 0x0c0c #define BIT_MASK_OFDM_FA_RST BIT(31) +#define REG_A_RXIQI 0x0c14 +#define BIT_MASK_RXIQ_S1_X 0x000003FF +#define BIT_MASK_RXIQ_S1_Y1 0x0000FC00 +#define BIT_SET_RXIQ_S1_Y1(y) ((y) & 0x3F) #define REG_OFDM0_RXDSP 0x0c40 #define BIT_MASK_RXDSP GENMASK(28, 24) #define BIT_EN_RXDSP BIT(9) +#define REG_OFDM_0_ECCA_THRESHOLD 0x0c4c +#define BIT_MASK_OFDM0_EXT_A BIT(31) +#define BIT_MASK_OFDM0_EXT_C BIT(29) +#define BIT_MASK_OFDM0_EXTS (BIT(31) | BIT(29) | BIT(28)) +#define BIT_SET_OFDM0_EXTS(a, c, d) (((a) << 31) | ((c) << 29) | ((d) << 28)) #define REG_OFDM0_XAAGC1 0x0c50 #define REG_OFDM0_XBAGC1 0x0c58 +#define REG_OFDM_0_XA_TX_IQ_IMBALANCE 0x0c80 +#define BIT_MASK_TXIQ_ELM_A 0x03ff +#define BIT_SET_TXIQ_ELM_ACD(a, c, d) (((d) << 22) | (((c) & 0x3F) << 16) | \ + ((a) & 0x03ff)) +#define BIT_MASK_TXIQ_ELM_C GENMASK(21, 16) +#define BIT_SET_TXIQ_ELM_C2(c) ((c) & 0x3F) +#define BIT_MASK_TXIQ_ELM_D GENMASK(31, 22) +#define REG_TXIQK_MATRIXA_LSB2_11N 0x0c94 +#define BIT_SET_TXIQ_ELM_C1(c) (((c) & 0x000003C0) >> 6) +#define REG_RXIQK_MATRIX_LSB_11N 0x0ca0 +#define BIT_MASK_RXIQ_S1_Y2 0xF0000000 +#define BIT_SET_RXIQ_S1_Y2(y) (((y) >> 6) & 0xF) +#define REG_TXIQ_AB_S0 0x0cd0 +#define BIT_MASK_TXIQ_A_S0 0x000007FE +#define BIT_MASK_TXIQ_A_EXT_S0 BIT(0) +#define BIT_MASK_TXIQ_B_S0 0x0007E000 +#define REG_TXIQ_CD_S0 0x0cd4 +#define BIT_MASK_TXIQ_C_S0 0x000007FE +#define BIT_MASK_TXIQ_C_EXT_S0 BIT(0) +#define BIT_MASK_TXIQ_D_S0 GENMASK(22, 13) +#define BIT_MASK_TXIQ_D_EXT_S0 BIT(12) +#define REG_RXIQ_AB_S0 0x0cd8 +#define BIT_MASK_RXIQ_X_S0 0x000003FF +#define BIT_MASK_RXIQ_Y_S0 0x003FF000 #define REG_OFDM_FA_TYPE1_11N 0x0cf0 #define BIT_MASK_OFDM_FF_CNT GENMASK(15, 0) #define BIT_MASK_OFDM_SF_CNT GENMASK(31, 16) @@ -132,6 +228,32 @@ struct rtw8723d_efuse { #define BIT_MASK_OFDM_CRC_CNT GENMASK(31, 16) #define REG_OFDM_FA_TYPE4_11N 0x0da8 #define BIT_MASK_OFDM_MNS_CNT GENMASK(15, 0) +#define REG_FPGA0_IQK_11N 0x0e28 +#define BIT_MASK_IQK_MOD 0xffffff00 +#define EN_IQK 0x808000 +#define RST_IQK 0x000000 +#define REG_TXIQK_TONE_A_11N 0x0e30 +#define REG_RXIQK_TONE_A_11N 0x0e34 +#define REG_TXIQK_PI_A_11N 0x0e38 +#define REG_RXIQK_PI_A_11N 0x0e3c +#define REG_TXIQK_11N 0x0e40 +#define BIT_SET_TXIQK_11N(x, y) (0x80007C00 | ((x) << 16) | (y)) +#define REG_RXIQK_11N 0x0e44 +#define REG_IQK_AGC_PTS_11N 0x0e48 +#define REG_IQK_AGC_RSP_11N 0x0e4c +#define REG_TX_IQK_TONE_B 0x0e50 +#define REG_RX_IQK_TONE_B 0x0e54 +#define REG_IQK_RES_TX 0x0e94 +#define BIT_MASK_RES_TX GENMASK(25, 16) +#define REG_IQK_RES_TY 0x0e9c +#define BIT_MASK_RES_TY GENMASK(25, 16) +#define REG_IQK_RES_RX 0x0ea4 +#define BIT_MASK_RES_RX GENMASK(25, 16) +#define REG_IQK_RES_RY 0x0eac +#define BIT_IQK_TX_FAIL BIT(28) +#define BIT_IQK_RX_FAIL BIT(27) +#define BIT_IQK_DONE BIT(26) +#define BIT_MASK_RES_RY GENMASK(25, 16) #define REG_PAGE_F_RST_11N 0x0f14 #define BIT_MASK_F_RST_ALL BIT(16) #define REG_IGI_C_11N 0x0f84 -- cgit From 608d2a08f842d8f1ca877ced7bf092f084717553 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:15 +0800 Subject: rtw88: 8723d: Add power tracking When chip's temperature is changed, RF characters are changed. To keep the characters to be consistent, 8723d uses thermal meter to assist in calibrating LCK, IQK, crystal and TX power. A base thermal value is programmed in efuse, all calibration data in MP process is based on this thermal value. So we calucate the delta of thermal value between the base value, and use this delta to reference XTAL and TX power offset tables to know how much we need to adjust. For IQK and LCK, driver checks if delta of thermal value is over 8, then they are triggered. For crystal adjustment, when delta of thermal value is changed, we check XTAL tables to get offset of XTAL value. If thermal value is larger than base value, positive table (_p as suffix) is used. Otherwise, we use negative table (_n as suffix). Then, we add offset to XTAL default value programmed in efuse, and write sum value to register. To compensate TX power, there are two hierarchical tables. First level use delta of thermal value to access eight tables to yield delta of TX power index. Then, plus base TX power index to get index of BB swing table (second level tables) where register value is induced. BB swing table can't deal with all cases, if index of BB swing table is over the size of the table. In this case, TX AGC is used to compensate the remnant part. Assume 'upper' is the upper bound of BB swing table, and 'target' is the desired index. Then, we can illustrate them as compensation method BB swing TX AGC ------------------- -------- -------------- target > upper upper target - upper target < 0 0 target otherwise target 0 For debug purpose, add a column 'rem' to tx_pwr_tbl entry, and it looks like path rate pwr base (byr lmt ) rem A CCK_1M 32(0x20) 34 -2 ( 0 -2) 0 Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-4-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/debug.c | 9 +- drivers/net/wireless/realtek/rtw88/main.h | 4 + drivers/net/wireless/realtek/rtw88/phy.c | 6 +- drivers/net/wireless/realtek/rtw88/phy.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 400 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 7 + 6 files changed, 422 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index b4964306de61..09f04feb8fe1 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -531,8 +531,8 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) u8 ch = hal->current_channel; u8 regd = rtwdev->regd.txpwr_regd; - seq_printf(m, "%-4s %-10s %-3s%6s %-4s %4s (%-4s %-4s)\n", - "path", "rate", "pwr", "", "base", "", "byr", "lmt"); + seq_printf(m, "%-4s %-10s %-3s%6s %-4s %4s (%-4s %-4s) %-4s\n", + "path", "rate", "pwr", "", "base", "", "byr", "lmt", "rem"); mutex_lock(&hal->tx_power_mutex); for (path = RF_PATH_A; path <= RF_PATH_B; path++) { @@ -554,13 +554,14 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) seq_printf(m, "%4c ", path + 'A'); rtw_print_rate(m, rate); - seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d)\n", + seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d) %4d\n", hal->tx_pwr_tbl[path][rate], hal->tx_pwr_tbl[path][rate], pwr_param.pwr_base, min_t(s8, pwr_param.pwr_offset, pwr_param.pwr_limit), - pwr_param.pwr_offset, pwr_param.pwr_limit); + pwr_param.pwr_offset, pwr_param.pwr_limit, + pwr_param.pwr_remnant); } } diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index af8c50e3687d..bfdc27c187f6 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1056,6 +1056,8 @@ struct rtw_pwr_track_tbl { const u8 *pwrtrk_2g_cckb_p; const u8 *pwrtrk_2g_ccka_n; const u8 *pwrtrk_2g_ccka_p; + const s8 *pwrtrk_xtal_n; + const s8 *pwrtrk_xtal_p; }; enum rtw_wlan_cpu { @@ -1447,6 +1449,8 @@ struct rtw_dm_info { bool pwr_trk_triggered; bool pwr_trk_init_trigger; struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX]; + s8 txagc_remnant_cck; + s8 txagc_remnant_ofdm; /* backup dack results for each path and I/Q */ u32 dack_adck[RTW_RF_PATH_MAX]; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 837b7bd04126..45181f602e3f 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -1785,11 +1785,13 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, u8 ch, u8 regd, struct rtw_power_params *pwr_param) { struct rtw_hal *hal = &rtwdev->hal; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; struct rtw_txpwr_idx *pwr_idx; u8 group, band; u8 *base = &pwr_param->pwr_base; s8 *offset = &pwr_param->pwr_offset; s8 *limit = &pwr_param->pwr_limit; + s8 *remnant = &pwr_param->pwr_remnant; pwr_idx = &rtwdev->efuse.txpwr_idx_table[path]; group = rtw_get_channel_group(ch); @@ -1811,6 +1813,8 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, *limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path, rate, ch, regd); + *remnant = (rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck : + dm_info->txagc_remnant_ofdm); } u8 @@ -1830,7 +1834,7 @@ rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate, if (rtwdev->chip->en_dis_dpd) offset += rtw_phy_get_dis_dpd_by_rate_diff(rtwdev, rate); - tx_power += offset; + tx_power += offset + pwr_param.pwr_remnant; if (tx_power > rtwdev->chip->max_power_index) tx_power = rtwdev->chip->max_power_index; diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index 413bf7165cc0..b924ed07630a 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -141,6 +141,7 @@ struct rtw_power_params { u8 pwr_base; s8 pwr_offset; s8 pwr_limit; + s8 pwr_remnant; }; void diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 0cfa493e7742..4fc2d0bb2704 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -92,6 +92,46 @@ static void rtw8723d_lck(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_TXPAUSE, 0x00); } +static const u32 rtw8723d_ofdm_swing_table[] = { + 0x0b40002d, 0x0c000030, 0x0cc00033, 0x0d800036, 0x0e400039, 0x0f00003c, + 0x10000040, 0x11000044, 0x12000048, 0x1300004c, 0x14400051, 0x15800056, + 0x16c0005b, 0x18000060, 0x19800066, 0x1b00006c, 0x1c800072, 0x1e400079, + 0x20000080, 0x22000088, 0x24000090, 0x26000098, 0x288000a2, 0x2ac000ab, + 0x2d4000b5, 0x300000c0, 0x32c000cb, 0x35c000d7, 0x390000e4, 0x3c8000f2, + 0x40000100, 0x43c0010f, 0x47c0011f, 0x4c000130, 0x50800142, 0x55400155, + 0x5a400169, 0x5fc0017f, 0x65400195, 0x6b8001ae, 0x71c001c7, 0x788001e2, + 0x7f8001fe, +}; + +static const u32 rtw8723d_cck_swing_table[] = { + 0x0CD, 0x0D9, 0x0E6, 0x0F3, 0x102, 0x111, 0x121, 0x132, 0x144, 0x158, + 0x16C, 0x182, 0x198, 0x1B1, 0x1CA, 0x1E5, 0x202, 0x221, 0x241, 0x263, + 0x287, 0x2AE, 0x2D6, 0x301, 0x32F, 0x35F, 0x392, 0x3C9, 0x402, 0x43F, + 0x47F, 0x4C3, 0x50C, 0x558, 0x5A9, 0x5FF, 0x65A, 0x6BA, 0x720, 0x78C, + 0x7FF, +}; + +#define RTW_OFDM_SWING_TABLE_SIZE ARRAY_SIZE(rtw8723d_ofdm_swing_table) +#define RTW_CCK_SWING_TABLE_SIZE ARRAY_SIZE(rtw8723d_cck_swing_table) + +static void rtw8723d_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 path; + + dm_info->default_ofdm_index = RTW_DEF_OFDM_SWING_INDEX; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->delta_power_index[path] = 0; + } + dm_info->pwr_trk_triggered = false; + dm_info->pwr_trk_init_trigger = true; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; + dm_info->txagc_remnant_cck = 0; + dm_info->txagc_remnant_ofdm = 0; +} + static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) { u8 xtal_cap; @@ -158,6 +198,8 @@ static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x50); rtw_write32_mask(rtwdev, REG_OFDM0_XAAGC1, MASKBYTE0, 0x20); + + rtw8723d_pwrtrack_init(rtwdev); } static void rtw8723de_efuse_parsing(struct rtw_efuse *efuse, @@ -1450,6 +1492,298 @@ out: rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] finished\n"); } +static u8 rtw8723d_pwrtrack_get_limit_ofdm(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 tx_rate = dm_info->tx_rate; + u8 limit_ofdm = 30; + + switch (tx_rate) { + case DESC_RATE1M...DESC_RATE5_5M: + case DESC_RATE11M: + break; + case DESC_RATE6M...DESC_RATE48M: + limit_ofdm = 36; + break; + case DESC_RATE54M: + limit_ofdm = 34; + break; + case DESC_RATEMCS0...DESC_RATEMCS2: + limit_ofdm = 38; + break; + case DESC_RATEMCS3...DESC_RATEMCS4: + limit_ofdm = 36; + break; + case DESC_RATEMCS5...DESC_RATEMCS7: + limit_ofdm = 34; + break; + default: + rtw_warn(rtwdev, "pwrtrack unhandled tx_rate 0x%x\n", tx_rate); + break; + } + + return limit_ofdm; +} + +static void rtw8723d_set_iqk_matrix_by_result(struct rtw_dev *rtwdev, + u32 ofdm_swing, u8 rf_path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s32 ele_A, ele_D, ele_C; + s32 ele_A_ext, ele_C_ext, ele_D_ext; + s32 iqk_result_x; + s32 iqk_result_y; + s32 value32; + + switch (rf_path) { + default: + case RF_PATH_A: + iqk_result_x = dm_info->iqk.result.s1_x; + iqk_result_y = dm_info->iqk.result.s1_y; + break; + case RF_PATH_B: + iqk_result_x = dm_info->iqk.result.s0_x; + iqk_result_y = dm_info->iqk.result.s0_y; + break; + } + + /* new element D */ + ele_D = OFDM_SWING_D(ofdm_swing); + iqk_mult(iqk_result_x, ele_D, &ele_D_ext); + /* new element A */ + iqk_result_x = iqkxy_to_s32(iqk_result_x); + ele_A = iqk_mult(iqk_result_x, ele_D, &ele_A_ext); + /* new element C */ + iqk_result_y = iqkxy_to_s32(iqk_result_y); + ele_C = iqk_mult(iqk_result_y, ele_D, &ele_C_ext); + + switch (rf_path) { + case RF_PATH_A: + default: + /* write new elements A, C, D, and element B is always 0 */ + value32 = BIT_SET_TXIQ_ELM_ACD(ele_A, ele_C, ele_D); + rtw_write32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, value32); + value32 = BIT_SET_TXIQ_ELM_C1(ele_C); + rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS, + value32); + value32 = rtw_read32(rtwdev, REG_OFDM_0_ECCA_THRESHOLD); + value32 &= ~BIT_MASK_OFDM0_EXTS; + value32 |= BIT_SET_OFDM0_EXTS(ele_A_ext, ele_C_ext, ele_D_ext); + rtw_write32(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, value32); + break; + + case RF_PATH_B: + /* write new elements A, C, D, and element B is always 0 */ + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_D_S0, ele_D); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_S0, ele_C); + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_S0, ele_A); + + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_D_EXT_S0, + ele_D_ext); + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_EXT_S0, + ele_A_ext); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_EXT_S0, + ele_C_ext); + break; + } +} + +static void rtw8723d_set_iqk_matrix(struct rtw_dev *rtwdev, s8 ofdm_index, + u8 rf_path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s32 value32; + u32 ofdm_swing; + + if (ofdm_index >= RTW_OFDM_SWING_TABLE_SIZE) + ofdm_index = RTW_OFDM_SWING_TABLE_SIZE - 1; + else if (ofdm_index < 0) + ofdm_index = 0; + + ofdm_swing = rtw8723d_ofdm_swing_table[ofdm_index]; + + if (dm_info->iqk.done) { + rtw8723d_set_iqk_matrix_by_result(rtwdev, ofdm_swing, rf_path); + return; + } + + switch (rf_path) { + case RF_PATH_A: + default: + rtw_write32(rtwdev, REG_OFDM_0_XA_TX_IQ_IMBALANCE, ofdm_swing); + rtw_write32_mask(rtwdev, REG_TXIQK_MATRIXA_LSB2_11N, MASKH4BITS, + 0x00); + value32 = rtw_read32(rtwdev, REG_OFDM_0_ECCA_THRESHOLD); + value32 &= ~BIT_MASK_OFDM0_EXTS; + rtw_write32(rtwdev, REG_OFDM_0_ECCA_THRESHOLD, value32); + break; + + case RF_PATH_B: + /* image S1:c80 to S0:Cd0 and Cd4 */ + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_S0, + OFDM_SWING_A(ofdm_swing)); + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_B_S0, + OFDM_SWING_B(ofdm_swing)); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_S0, + OFDM_SWING_C(ofdm_swing)); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_D_S0, + OFDM_SWING_D(ofdm_swing)); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_D_EXT_S0, 0x0); + rtw_write32_mask(rtwdev, REG_TXIQ_CD_S0, BIT_MASK_TXIQ_C_EXT_S0, 0x0); + rtw_write32_mask(rtwdev, REG_TXIQ_AB_S0, BIT_MASK_TXIQ_A_EXT_S0, 0x0); + break; + } +} + +static void rtw8723d_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx, + s8 txagc_idx) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->txagc_remnant_ofdm = txagc_idx; + + rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A); + rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_B); +} + +static void rtw8723d_pwrtrack_set_cck_pwr(struct rtw_dev *rtwdev, s8 swing_idx, + s8 txagc_idx) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->txagc_remnant_cck = txagc_idx; + + rtw_write32_mask(rtwdev, 0xab4, 0x000007FF, + rtw8723d_cck_swing_table[swing_idx]); +} + +static void rtw8723d_pwrtrack_set(struct rtw_dev *rtwdev, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_hal *hal = &rtwdev->hal; + u8 limit_ofdm; + u8 limit_cck = 40; + s8 final_ofdm_swing_index; + s8 final_cck_swing_index; + + limit_ofdm = rtw8723d_pwrtrack_get_limit_ofdm(rtwdev); + + final_ofdm_swing_index = RTW_DEF_OFDM_SWING_INDEX + + dm_info->delta_power_index[path]; + final_cck_swing_index = RTW_DEF_CCK_SWING_INDEX + + dm_info->delta_power_index[path]; + + if (final_ofdm_swing_index > limit_ofdm) + rtw8723d_pwrtrack_set_ofdm_pwr(rtwdev, limit_ofdm, + final_ofdm_swing_index - limit_ofdm); + else if (final_ofdm_swing_index < 0) + rtw8723d_pwrtrack_set_ofdm_pwr(rtwdev, 0, + final_ofdm_swing_index); + else + rtw8723d_pwrtrack_set_ofdm_pwr(rtwdev, final_ofdm_swing_index, 0); + + if (final_cck_swing_index > limit_cck) + rtw8723d_pwrtrack_set_cck_pwr(rtwdev, limit_cck, + final_cck_swing_index - limit_cck); + else if (final_cck_swing_index < 0) + rtw8723d_pwrtrack_set_cck_pwr(rtwdev, 0, + final_cck_swing_index); + else + rtw8723d_pwrtrack_set_cck_pwr(rtwdev, final_cck_swing_index, 0); + + rtw_phy_set_tx_power_level(rtwdev, hal->current_channel); +} + +static void rtw8723d_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path, + u8 delta) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + const s8 *pwrtrk_xtal; + s8 xtal_cap; + + if (dm_info->thermal_avg[therm_path] > + rtwdev->efuse.thermal_meter[therm_path]) + pwrtrk_xtal = tbl->pwrtrk_xtal_p; + else + pwrtrk_xtal = tbl->pwrtrk_xtal_n; + + xtal_cap = rtwdev->efuse.crystal_cap & 0x3F; + xtal_cap = clamp_t(s8, xtal_cap + pwrtrk_xtal[delta], 0, 0x3F); + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, BIT_MASK_XTAL, + xtal_cap | (xtal_cap << 6)); +} + +static void rtw8723d_phy_pwrtrack(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_swing_table swing_table; + u8 thermal_value, delta, path; + bool do_iqk = false; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[0] == 0xff) + return; + + thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A); + + do_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev); + + if (do_iqk) + rtw8723d_lck(rtwdev); + + if (dm_info->pwr_trk_init_trigger) + dm_info->pwr_trk_init_trigger = false; + else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value, + RF_PATH_A)) + goto iqk; + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + delta = min_t(u8, delta, RTW_PWR_TRK_TBL_SZ - 1); + + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { + s8 delta_cur, delta_last; + + delta_last = dm_info->delta_power_index[path]; + delta_cur = rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, + path, RF_PATH_A, delta); + if (delta_last == delta_cur) + continue; + + dm_info->delta_power_index[path] = delta_cur; + rtw8723d_pwrtrack_set(rtwdev, path); + } + + rtw8723d_pwrtrack_set_xtal(rtwdev, RF_PATH_A, delta); + +iqk: + if (do_iqk) + rtw8723d_phy_calibration(rtwdev); +} + +void rtw8723d_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (efuse->power_track_type != 0) + return; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw8723d_phy_pwrtrack(rtwdev); + dm_info->pwr_trk_triggered = false; +} + static struct rtw_chip_ops rtw8723d_ops = { .phy_set_param = rtw8723d_phy_set_param, .read_efuse = rtw8723d_read_efuse, @@ -1464,6 +1798,7 @@ static struct rtw_chip_ops rtw8723d_ops = { .efuse_grant = rtw8723d_efuse_grant, .false_alarm_statistics = rtw8723d_false_alarm_statistics, .phy_calibration = rtw8723d_phy_calibration, + .pwr_track = rtw8723d_pwr_track, .config_bfee = NULL, .set_gid_table = NULL, .cfg_csi_rate = NULL, @@ -1937,6 +2272,69 @@ static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,}, }; +static const u8 rtw8723d_pwrtrk_2gb_n[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8723d_pwrtrk_2gb_p[] = { + 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, + 7, 8, 8, 8, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8723d_pwrtrk_2ga_n[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8723d_pwrtrk_2ga_p[] = { + 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, + 7, 8, 8, 8, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8723d_pwrtrk_2g_cck_b_n[] = { + 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8723d_pwrtrk_2g_cck_b_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, + 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8723d_pwrtrk_2g_cck_a_n[] = { + 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8723d_pwrtrk_2g_cck_a_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, + 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11 +}; + +static const s8 rtw8723d_pwrtrk_xtal_n[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const s8 rtw8723d_pwrtrk_xtal_p[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, -10, -12, -14, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16 +}; + +static const struct rtw_pwr_track_tbl rtw8723d_rtw_pwr_track_tbl = { + .pwrtrk_2gb_n = rtw8723d_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8723d_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8723d_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8723d_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8723d_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8723d_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8723d_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8723d_pwrtrk_2g_cck_a_p, + .pwrtrk_xtal_p = rtw8723d_pwrtrk_xtal_p, + .pwrtrk_xtal_n = rtw8723d_pwrtrk_xtal_n, +}; + struct rtw_chip_info rtw8723d_hw_spec = { .ops = &rtw8723d_ops, .id = RTW_CHIP_TYPE_8723D, @@ -1979,6 +2377,8 @@ struct rtw_chip_info rtw8723d_hw_spec = { .rfe_defs = rtw8723d_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8723d_rfe_defs), .rx_ldpc = false, + .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, + .iqk_threshold = 8, }; EXPORT_SYMBOL(rtw8723d_hw_spec); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index 549dfcf7f5da..843472a1cd54 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -112,6 +112,13 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) return (t >> 8); /* Q.16 --> Q.8 */ } +#define OFDM_SWING_A(swing) FIELD_GET(GENMASK(9, 0), swing) +#define OFDM_SWING_B(swing) FIELD_GET(GENMASK(15, 10), swing) +#define OFDM_SWING_C(swing) FIELD_GET(GENMASK(21, 16), swing) +#define OFDM_SWING_D(swing) FIELD_GET(GENMASK(31, 22), swing) +#define RTW_DEF_OFDM_SWING_INDEX 28 +#define RTW_DEF_CCK_SWING_INDEX 28 + #define MAX_TOLERANCE 5 #define IQK_TX_X_ERR 0x142 #define IQK_TX_Y_ERR 0x42 -- cgit From 05202746ed70ea9601ab78657025adcdf945293c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:16 +0800 Subject: rtw88: 8723d: Add shutdown callback to disable BT USB suspend Without this patch, wifi card can't initialize properly due to BT in USB suspend state. So, we disable BT USB suspend (wakeup) in shutdown callback that is the moment before rebooting. To save BT USB power, we can't do this in 'remove' callback. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-5-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/pci.c | 17 +++++++++++++++++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 6 ++++++ 4 files changed, 25 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index bfdc27c187f6..592b28ed9376 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -795,6 +795,7 @@ struct rtw_regulatory { struct rtw_chip_ops { int (*mac_init)(struct rtw_dev *rtwdev); + void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); void (*phy_set_param)(struct rtw_dev *rtwdev); void (*set_channel)(struct rtw_dev *rtwdev, u8 channel, diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index a9752c34c9d8..e5ea30c04ac5 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1573,6 +1573,22 @@ static void rtw_pci_remove(struct pci_dev *pdev) ieee80211_free_hw(hw); } +static void rtw_pci_shutdown(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtw_dev *rtwdev; + struct rtw_chip_info *chip; + + if (!hw) + return; + + rtwdev = hw->priv; + chip = rtwdev->chip; + + if (chip->ops->shutdown) + chip->ops->shutdown(rtwdev); +} + static const struct pci_device_id rtw_pci_id_table[] = { #ifdef CONFIG_RTW88_8822BE { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822, rtw8822b_hw_spec) }, @@ -1593,6 +1609,7 @@ static struct pci_driver rtw_pci_driver = { .probe = rtw_pci_probe, .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, + .shutdown = rtw_pci_shutdown, }; module_pci_driver(rtw_pci_driver); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index d57de1a6cdcc..5a3e9cc7c400 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -83,6 +83,7 @@ #define BIT_DBG_GNT_WL_BT BIT(27) #define BIT_LTE_MUX_CTRL_PATH BIT(26) #define REG_HCI_OPT_CTRL 0x0074 +#define BIT_USB_SUS_DIS BIT(8) #define REG_AFE_CTRL_4 0x0078 #define BIT_CK320M_AFE_EN BIT(4) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 4fc2d0bb2704..bfad27d10c40 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -549,6 +549,11 @@ static int rtw8723d_mac_init(struct rtw_dev *rtwdev) return 0; } +static void rtw8723d_shutdown(struct rtw_dev *rtwdev) +{ + rtw_write16_set(rtwdev, REG_HCI_OPT_CTRL, BIT_USB_SUS_DIS); +} + static void rtw8723d_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { u8 ldo_pwr; @@ -1790,6 +1795,7 @@ static struct rtw_chip_ops rtw8723d_ops = { .query_rx_desc = rtw8723d_query_rx_desc, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723d_mac_init, + .shutdown = rtw8723d_shutdown, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8723d_set_tx_power_index, -- cgit From 7d754f974ac79640c8efda86d35d766704ebaa8e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:17 +0800 Subject: rtw88: 8723d: implement flush queue Flush queue is used to check if queue is empty, before doing something else. Since 8723D uses different registers and page number of availabl/reserved occupy 8 bits instead of 16 bits, so use a 'wsize' field to discriminate which rtw_read{8,16} is adopted. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-6-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/mac.c | 29 ++++++++++----------------- drivers/net/wireless/realtek/rtw88/main.h | 11 ++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.c | 17 ++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8822b.c | 17 ++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 17 ++++++++++++++++ 5 files changed, 73 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index e8ffeb338584..3a5cfebe5a62 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -919,31 +919,24 @@ static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, u32 prio_queue, bool drop) { - u32 addr; + struct rtw_chip_info *chip = rtwdev->chip; + const struct rtw_prioq_addr *addr; + bool wsize; u16 avail_page, rsvd_page; int i; - switch (prio_queue) { - case RTW_DMA_MAPPING_EXTRA: - addr = REG_FIFOPAGE_INFO_4; - break; - case RTW_DMA_MAPPING_LOW: - addr = REG_FIFOPAGE_INFO_2; - break; - case RTW_DMA_MAPPING_NORMAL: - addr = REG_FIFOPAGE_INFO_3; - break; - case RTW_DMA_MAPPING_HIGH: - addr = REG_FIFOPAGE_INFO_1; - break; - default: + if (prio_queue >= RTW_DMA_MAPPING_MAX) return; - } + + addr = &chip->prioq_addrs->prio[prio_queue]; + wsize = chip->prioq_addrs->wsize; /* check if all of the reserved pages are available for 100 msecs */ for (i = 0; i < 5; i++) { - rsvd_page = rtw_read16(rtwdev, addr); - avail_page = rtw_read16(rtwdev, addr + 2); + rsvd_page = wsize ? rtw_read16(rtwdev, addr->rsvd) : + rtw_read8(rtwdev, addr->rsvd); + avail_page = wsize ? rtw_read16(rtwdev, addr->avail) : + rtw_read8(rtwdev, addr->avail); if (rsvd_page == avail_page) return; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 592b28ed9376..28f88c44cb84 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -945,6 +945,16 @@ struct rtw_rqpn { enum rtw_dma_mapping dma_map_hi; }; +struct rtw_prioq_addr { + u32 rsvd; + u32 avail; +}; + +struct rtw_prioq_addrs { + struct rtw_prioq_addr prio[RTW_DMA_MAPPING_MAX]; + bool wsize; +}; + struct rtw_page_table { u16 hq_num; u16 nq_num; @@ -1101,6 +1111,7 @@ struct rtw_chip_info { const struct rtw_pwr_seq_cmd **pwr_on_seq; const struct rtw_pwr_seq_cmd **pwr_off_seq; const struct rtw_rqpn *rqpn_table; + const struct rtw_prioq_addrs *prioq_addrs; const struct rtw_page_table *page_table; const struct rtw_intf_phy_para_table *intf_table; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index bfad27d10c40..66bf907131d7 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2237,6 +2237,22 @@ static const struct rtw_rqpn rqpn_table_8723d[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; +static const struct rtw_prioq_addrs prioq_addrs_8723d = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2, + }, + .wsize = false, +}; + static const struct rtw_intf_phy_para pcie_gen1_param_8723d[] = { {0x0008, 0x4a22, RTW_IP_SEL_PHY, @@ -2370,6 +2386,7 @@ struct rtw_chip_info rtw8723d_hw_spec = { .pwr_off_seq = card_disable_flow_8723d, .page_table = page_table_8723d, .rqpn_table = rqpn_table_8723d, + .prioq_addrs = &prioq_addrs_8723d, .intf_table = &phy_para_table_8723d, .dig = rtw8723d_dig, .dig_cck = rtw8723d_dig_cck, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 45636382dafd..22a7baeb87f6 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2083,6 +2083,22 @@ static const struct rtw_rqpn rqpn_table_8822b[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; +static struct rtw_prioq_addrs prioq_addrs_8822b = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_FIFOPAGE_INFO_2, .avail = REG_FIFOPAGE_INFO_2 + 2, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_FIFOPAGE_INFO_3, .avail = REG_FIFOPAGE_INFO_3 + 2, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_FIFOPAGE_INFO_1, .avail = REG_FIFOPAGE_INFO_1 + 2, + }, + .wsize = true, +}; + static struct rtw_chip_ops rtw8822b_ops = { .phy_set_param = rtw8822b_phy_set_param, .read_efuse = rtw8822b_read_efuse, @@ -2433,6 +2449,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { .pwr_off_seq = card_disable_flow_8822b, .page_table = page_table_8822b, .rqpn_table = rqpn_table_8822b, + .prioq_addrs = &prioq_addrs_8822b, .intf_table = &phy_para_table_8822b, .dig = rtw8822b_dig, .dig_cck = NULL, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 64b77a7cbffd..e4b184485cad 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3933,6 +3933,22 @@ static const struct rtw_rqpn rqpn_table_8822c[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; +static struct rtw_prioq_addrs prioq_addrs_8822c = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_FIFOPAGE_INFO_2, .avail = REG_FIFOPAGE_INFO_2 + 2, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_FIFOPAGE_INFO_3, .avail = REG_FIFOPAGE_INFO_3 + 2, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_FIFOPAGE_INFO_1, .avail = REG_FIFOPAGE_INFO_1 + 2, + }, + .wsize = true, +}; + static struct rtw_chip_ops rtw8822c_ops = { .phy_set_param = rtw8822c_phy_set_param, .read_efuse = rtw8822c_read_efuse, @@ -4295,6 +4311,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .pwr_off_seq = card_disable_flow_8822c, .page_table = page_table_8822c, .rqpn_table = rqpn_table_8822c, + .prioq_addrs = &prioq_addrs_8822c, .intf_table = &phy_para_table_8822c, .dig = rtw8822c_dig, .dig_cck = NULL, -- cgit From 7e14936881caf0a36b49833bd8aca13f2c5a8efe Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:18 +0800 Subject: rtw88: 8723d: set ltecoex register address in chip_info Since 8723D use different address of ltecoex register, this commit add a new field in chip_info and fill proper address. Then, ltecoex_read_reg() and ltecoex_reg_write() can use them to access ltecoex according to chip. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-7-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/main.h | 7 +++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.c | 7 +++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 3 +++ drivers/net/wireless/realtek/rtw88/rtw8822b.c | 7 +++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 7 +++++++ drivers/net/wireless/realtek/rtw88/util.c | 18 ++++++++++++------ 6 files changed, 43 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 28f88c44cb84..c9156b9b532c 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -519,6 +519,12 @@ struct rtw_hw_reg { u32 mask; }; +struct rtw_ltecoex_addr { + u32 ctrl; + u32 wdata; + u32 rdata; +}; + struct rtw_reg_domain { u32 addr; u32 mask; @@ -1121,6 +1127,7 @@ struct rtw_chip_info { u32 rf_sipi_addr[2]; const struct rtw_rf_sipi_addr *rf_sipi_read_addr; u8 fix_rf_phy_num; + const struct rtw_ltecoex_addr *ltecoex_addr; const struct rtw_table *mac_tbl; const struct rtw_table *agc_tbl; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 66bf907131d7..e3dc27d6a6ad 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2289,6 +2289,12 @@ static const struct rtw_rf_sipi_addr rtw8723d_rf_sipi_addr[] = { .hssi_2 = 0x82c, .lssi_read_pi = 0x8bc}, }; +static const struct rtw_ltecoex_addr rtw8723d_ltecoex_addr = { + .ctrl = REG_LTECOEX_CTRL, + .wdata = REG_LTECOEX_WRITE_DATA, + .rdata = REG_LTECOEX_READ_DATA, +}; + static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl, .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,}, @@ -2393,6 +2399,7 @@ struct rtw_chip_info rtw8723d_hw_spec = { .rf_sipi_addr = {0x840, 0x844}, .rf_sipi_read_addr = rtw8723d_rf_sipi_addr, .fix_rf_phy_num = 2, + .ltecoex_addr = &rtw8723d_ltecoex_addr, .mac_tbl = &rtw8723d_mac_tbl, .agc_tbl = &rtw8723d_agc_tbl, .bb_tbl = &rtw8723d_bb_tbl, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index 843472a1cd54..d1f1c1a594ad 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -145,6 +145,9 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) #define REG_BTG_SEL 0x0067 #define REG_LTECOEX_PATH_CONTROL 0x0070 +#define REG_LTECOEX_CTRL 0x07c0 +#define REG_LTECOEX_WRITE_DATA 0x07c4 +#define REG_LTECOEX_READ_DATA 0x07c8 #define REG_PSDFN 0x0808 #define REG_BB_PWR_SAV1_11N 0x0874 #define REG_ANALOG_P4 0x088c diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 22a7baeb87f6..18c5a5a96d90 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2057,6 +2057,12 @@ static const struct rtw_hw_reg rtw8822b_dig[] = { [1] = { .addr = 0xe50, .mask = 0x7f }, }; +static const struct rtw_ltecoex_addr rtw8822b_ltecoex_addr = { + .ctrl = LTECOEX_ACCESS_CTRL, + .wdata = LTECOEX_WRITE_DATA, + .rdata = LTECOEX_READ_DATA, +}; + static const struct rtw_page_table page_table_8822b[] = { {64, 64, 64, 64, 1}, {64, 64, 64, 64, 1}, @@ -2455,6 +2461,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { .dig_cck = NULL, .rf_base_addr = {0x2800, 0x2c00}, .rf_sipi_addr = {0xc90, 0xe90}, + .ltecoex_addr = &rtw8822b_ltecoex_addr, .mac_tbl = &rtw8822b_mac_tbl, .agc_tbl = &rtw8822b_agc_tbl, .bb_tbl = &rtw8822b_bb_tbl, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index e4b184485cad..d697d70170af 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3907,6 +3907,12 @@ static const struct rtw_hw_reg rtw8822c_dig[] = { [1] = { .addr = 0x1d70, .mask = 0x7f00 }, }; +static const struct rtw_ltecoex_addr rtw8822c_ltecoex_addr = { + .ctrl = LTECOEX_ACCESS_CTRL, + .wdata = LTECOEX_WRITE_DATA, + .rdata = LTECOEX_READ_DATA, +}; + static const struct rtw_page_table page_table_8822c[] = { {64, 64, 64, 64, 1}, {64, 64, 64, 64, 1}, @@ -4317,6 +4323,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .dig_cck = NULL, .rf_base_addr = {0x3c00, 0x4c00}, .rf_sipi_addr = {0x1808, 0x4108}, + .ltecoex_addr = &rtw8822c_ltecoex_addr, .mac_tbl = &rtw8822c_mac_tbl, .agc_tbl = &rtw8822c_agc_tbl, .bb_tbl = &rtw8822c_bb_tbl, diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c index 10f1117c0cfb..42cf177cd445 100644 --- a/drivers/net/wireless/realtek/rtw88/util.c +++ b/drivers/net/wireless/realtek/rtw88/util.c @@ -22,22 +22,28 @@ bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target) bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val) { - if (!check_hw_ready(rtwdev, LTECOEX_ACCESS_CTRL, LTECOEX_READY, 1)) + struct rtw_chip_info *chip = rtwdev->chip; + const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; + + if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) return false; - rtw_write32(rtwdev, LTECOEX_ACCESS_CTRL, 0x800F0000 | offset); - *val = rtw_read32(rtwdev, LTECOEX_READ_DATA); + rtw_write32(rtwdev, ltecoex->ctrl, 0x800F0000 | offset); + *val = rtw_read32(rtwdev, ltecoex->rdata); return true; } bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value) { - if (!check_hw_ready(rtwdev, LTECOEX_ACCESS_CTRL, LTECOEX_READY, 1)) + struct rtw_chip_info *chip = rtwdev->chip; + const struct rtw_ltecoex_addr *ltecoex = chip->ltecoex_addr; + + if (!check_hw_ready(rtwdev, ltecoex->ctrl, LTECOEX_READY, 1)) return false; - rtw_write32(rtwdev, LTECOEX_WRITE_DATA, value); - rtw_write32(rtwdev, LTECOEX_ACCESS_CTRL, 0xC00F0000 | offset); + rtw_write32(rtwdev, ltecoex->wdata, value); + rtw_write32(rtwdev, ltecoex->ctrl, 0xC00F0000 | offset); return true; } -- cgit From d1391c490085156222e0baa8124b93fc494d96d8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:19 +0800 Subject: rtw88: 8723d: Add coex support 8723D is a Wifi+BT combo card. To make them work properly, we need coex mechanism to avoid interference, such as TX simultaneously. Basically, coex.c provide main algorithm to deal with many use cases, and this commit adds some parameters and ops differ from other chips, because coex hardware and WiFi generation are changed. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-8-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 327 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 3 + 2 files changed, 330 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index e3dc27d6a6ad..400364aec393 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1497,6 +1497,132 @@ out: rtw_dbg(rtwdev, RTW_DBG_RFK, "[IQK] finished\n"); } +/* for coex */ +static void rtw8723d_coex_cfg_init(struct rtw_dev *rtwdev) +{ + /* enable TBTT nterrupt */ + rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + + /* BT report packet sample rate */ + /* 0x790[5:0]=0x5 */ + rtw_write8_set(rtwdev, REG_BT_TDMA_TIME, 0x05); + + /* enable BT counter statistics */ + rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x1); + + /* enable PTA (3-wire function form BT side) */ + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN); + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_AOD_GPIO3); + + /* enable PTA (tx/rx signal form WiFi side) */ + rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN); +} + +static void rtw8723d_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{ +} + +static void rtw8723d_coex_cfg_gnt_debug(struct rtw_dev *rtwdev) +{ + rtw_write8_mask(rtwdev, REG_LEDCFG2, BIT(6), 0); + rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 3, BIT(0), 0); + rtw_write8_mask(rtwdev, REG_GPIO_INTM + 2, BIT(4), 0); + rtw_write8_mask(rtwdev, REG_GPIO_MUXCFG + 2, BIT(1), 0); + rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 3, BIT(1), 0); + rtw_write8_mask(rtwdev, REG_PAD_CTRL1 + 2, BIT(7), 0); + rtw_write8_mask(rtwdev, REG_SYS_CLKR + 1, BIT(1), 0); + rtw_write8_mask(rtwdev, REG_SYS_SDIO_CTRL + 3, BIT(3), 0); +} + +static void rtw8723d_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + bool aux = efuse->bt_setting & BIT(6); + + coex_rfe->rfe_module_type = rtwdev->efuse.rfe_option; + coex_rfe->ant_switch_polarity = 0; + coex_rfe->ant_switch_exist = false; + coex_rfe->ant_switch_with_bt = false; + coex_rfe->ant_switch_diversity = false; + coex_rfe->wlg_at_btg = true; + + /* decide antenna at main or aux */ + if (efuse->share_ant) { + if (aux) + rtw_write16(rtwdev, REG_BB_SEL_BTG, 0x80); + else + rtw_write16(rtwdev, REG_BB_SEL_BTG, 0x200); + } else { + if (aux) + rtw_write16(rtwdev, REG_BB_SEL_BTG, 0x280); + else + rtw_write16(rtwdev, REG_BB_SEL_BTG, 0x0); + } + + /* disable LTE coex in wifi side */ + rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, BIT_LTE_COEX_EN, 0x0); + rtw_coex_write_indirect_reg(rtwdev, LTE_WL_TRX_CTRL, MASKLWORD, 0xffff); + rtw_coex_write_indirect_reg(rtwdev, LTE_BT_TRX_CTRL, MASKLWORD, 0xffff); +} + +static void rtw8723d_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + static const u8 wl_tx_power[] = {0xb2, 0x90}; + u8 pwr; + + if (wl_pwr == coex_dm->cur_wl_pwr_lvl) + return; + + coex_dm->cur_wl_pwr_lvl = wl_pwr; + + if (coex_dm->cur_wl_pwr_lvl >= ARRAY_SIZE(wl_tx_power)) + coex_dm->cur_wl_pwr_lvl = ARRAY_SIZE(wl_tx_power) - 1; + + pwr = wl_tx_power[coex_dm->cur_wl_pwr_lvl]; + + rtw_write8(rtwdev, REG_ANA_PARAM1 + 3, pwr); +} + +static void rtw8723d_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + /* WL Rx Low gain on */ + static const u32 wl_rx_low_gain_on[] = { + 0xec120101, 0xeb130101, 0xce140101, 0xcd150101, 0xcc160101, + 0xcb170101, 0xca180101, 0x8d190101, 0x8c1a0101, 0x8b1b0101, + 0x4f1c0101, 0x4e1d0101, 0x4d1e0101, 0x4c1f0101, 0x0e200101, + 0x0d210101, 0x0c220101, 0x0b230101, 0xcf240001, 0xce250001, + 0xcd260001, 0xcc270001, 0x8f280001 + }; + /* WL Rx Low gain off */ + static const u32 wl_rx_low_gain_off[] = { + 0xec120101, 0xeb130101, 0xea140101, 0xe9150101, 0xe8160101, + 0xe7170101, 0xe6180101, 0xe5190101, 0xe41a0101, 0xe31b0101, + 0xe21c0101, 0xe11d0101, 0xe01e0101, 0x861f0101, 0x85200101, + 0x84210101, 0x83220101, 0x82230101, 0x81240101, 0x80250101, + 0x44260101, 0x43270101, 0x42280101 + }; + u8 i; + + if (low_gain == coex_dm->cur_wl_rx_low_gain_en) + return; + + coex_dm->cur_wl_rx_low_gain_en = low_gain; + + if (coex_dm->cur_wl_rx_low_gain_en) { + for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_on); i++) + rtw_write32(rtwdev, REG_AGCRSSI, wl_rx_low_gain_on[i]); + } else { + for (i = 0; i < ARRAY_SIZE(wl_rx_low_gain_off); i++) + rtw_write32(rtwdev, REG_AGCRSSI, wl_rx_low_gain_off[i]); + } +} + static u8 rtw8723d_pwrtrack_get_limit_ofdm(struct rtw_dev *rtwdev) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; @@ -1808,6 +1934,156 @@ static struct rtw_chip_ops rtw8723d_ops = { .config_bfee = NULL, .set_gid_table = NULL, .cfg_csi_rate = NULL, + + .coex_set_init = rtw8723d_coex_cfg_init, + .coex_set_ant_switch = NULL, + .coex_set_gnt_fix = rtw8723d_coex_cfg_gnt_fix, + .coex_set_gnt_debug = rtw8723d_coex_cfg_gnt_debug, + .coex_set_rfe_type = rtw8723d_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8723d_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8723d_coex_cfg_wl_rx_gain, +}; + +/* Shared-Antenna Coex Table */ +static const struct coex_table_para table_sant_8723d[] = { + {0xffffffff, 0xffffffff}, /* case-0 */ + {0x55555555, 0x55555555}, + {0x65555555, 0x65555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-5 */ + {0xa5555555, 0xaaaa5aaa}, + {0x6a5a5a5a, 0x5a5a5a5a}, + {0x6a5a5a5a, 0x6a5a5a5a}, + {0x65555555, 0x5a5a5a5a}, + {0x65555555, 0x6a5a5a5a}, /* case-10 */ + {0x65555555, 0xfafafafa}, + {0x65555555, 0x6a5a5aaa}, + {0x65555555, 0x5aaa5aaa}, + {0x65555555, 0xaaaa5aaa}, + {0x65555555, 0xaaaaaaaa}, /* case-15 */ + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x6afa5afa}, + {0xaaffffaa, 0xfafafafa}, + {0xaa5555aa, 0x5a5a5a5a}, + {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */ + {0xaa5555aa, 0xaaaaaaaa}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x6a5a5a5a}, + {0xffffffff, 0x55555555}, + {0xffffffff, 0x6a5a5aaa}, /* case-25 */ + {0x55555555, 0x5a5a5a5a}, + {0x55555555, 0xaaaaaaaa}, + {0x55555555, 0x6a6a6a6a}, + {0x656a656a, 0x656a656a} +}; + +/* Non-Shared-Antenna Coex Table */ +static const struct coex_table_para table_nsant_8723d[] = { + {0xffffffff, 0xffffffff}, /* case-100 */ + {0x55555555, 0x55555555}, + {0x65555555, 0x65555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-105 */ + {0x5afa5afa, 0x5afa5afa}, + {0x55555555, 0xfafafafa}, + {0x65555555, 0xfafafafa}, + {0x65555555, 0x5a5a5a5a}, + {0x65555555, 0x6a5a5a5a}, /* case-110 */ + {0x65555555, 0xaaaaaaaa}, + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0xaaaaaaaa}, + {0xaaffffaa, 0xfafafafa}, /* case-115 */ + {0xaaffffaa, 0x5afa5afa}, + {0xaaffffaa, 0xaaaaaaaa}, + {0xffffffff, 0xfafafafa}, + {0xffffffff, 0x5afa5afa}, + {0xffffffff, 0xaaaaaaaa},/* case-120 */ + {0x55ff55ff, 0x5afa5afa}, + {0x55ff55ff, 0xaaaaaaaa}, + {0x55ff55ff, 0x55ff55ff} +}; + +/* Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_sant_8723d[] = { + { {0x08, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x30, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-5 */ + { {0x61, 0x48, 0x03, 0x11, 0x10} }, + { {0x61, 0x3a, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */ + { {0x61, 0x10, 0x03, 0x11, 0x14} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x10, 0x03, 0x10, 0x54} }, + { {0x51, 0x10, 0x03, 0x10, 0x55} }, + { {0x51, 0x10, 0x07, 0x10, 0x54} }, /* case-15 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x20, 0x03, 0x10, 0x50} }, + { {0x51, 0x15, 0x03, 0x10, 0x50} }, /* case-20 */ + { {0x51, 0x4a, 0x03, 0x10, 0x50} }, + { {0x51, 0x0c, 0x03, 0x10, 0x54} }, + { {0x55, 0x08, 0x03, 0x10, 0x54} }, + { {0x65, 0x10, 0x03, 0x11, 0x11} }, + { {0x51, 0x10, 0x03, 0x10, 0x51} }, + { {0x61, 0x15, 0x03, 0x11, 0x10} } +}; + +/* Non-Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_nsant_8723d[] = { + { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-101 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x30, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x3a, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */ + { {0x61, 0x08, 0x03, 0x11, 0x14} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x20, 0x03, 0x10, 0x50} }, + { {0x51, 0x10, 0x03, 0x10, 0x50} } +}; + +/* rssi in percentage % (dbm = % - 100) */ +static const u8 wl_rssi_step_8723d[] = {60, 50, 44, 30}; +static const u8 bt_rssi_step_8723d[] = {30, 30, 30, 30}; +static const struct coex_5g_afh_map afh_5g_8723d[] = { {0, 0, 0} }; + +/* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */ +static const struct coex_rf_para rf_para_tx_8723d[] = { + {0, 0, false, 7}, /* for normal */ + {0, 10, false, 7}, /* for WL-CPT */ + {1, 0, true, 4}, + {1, 2, true, 4}, + {1, 10, true, 4}, + {1, 15, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8723d[] = { + {0, 0, false, 7}, /* for normal */ + {0, 10, false, 7}, /* for WL-CPT */ + {1, 0, true, 5}, + {1, 2, true, 5}, + {1, 10, true, 5}, + {1, 15, true, 5} }; static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8723d[] = { @@ -2363,6 +2639,28 @@ static const struct rtw_pwr_track_tbl rtw8723d_rtw_pwr_track_tbl = { .pwrtrk_xtal_n = rtw8723d_pwrtrk_xtal_n, }; +static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = { + {0x948, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x67, BIT(7), RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x964, BIT(1), RTW_REG_DOMAIN_MAC8}, + {0x864, BIT(0), RTW_REG_DOMAIN_MAC8}, + {0xab7, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0xa01, BIT(7), RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8}, + {0x40, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, +}; + struct rtw_chip_info rtw8723d_hw_spec = { .ops = &rtw8723d_ops, .id = RTW_CHIP_TYPE_8723D, @@ -2409,6 +2707,35 @@ struct rtw_chip_info rtw8723d_hw_spec = { .rx_ldpc = false, .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, .iqk_threshold = 8, + + .coex_para_ver = 0x1905302f, + .bt_desired_ver = 0x2f, + .scbd_support = true, + .new_scbd10_def = true, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 15, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8723d, + .bt_rssi_step = bt_rssi_step_8723d, + .table_sant_num = ARRAY_SIZE(table_sant_8723d), + .table_sant = table_sant_8723d, + .table_nsant_num = ARRAY_SIZE(table_nsant_8723d), + .table_nsant = table_nsant_8723d, + .tdma_sant_num = ARRAY_SIZE(tdma_sant_8723d), + .tdma_sant = tdma_sant_8723d, + .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8723d), + .tdma_nsant = tdma_nsant_8723d, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8723d), + .wl_rf_para_tx = rf_para_tx_8723d, + .wl_rf_para_rx = rf_para_rx_8723d, + .bt_afh_span_bw20 = 0x20, + .bt_afh_span_bw40 = 0x30, + .afh_5g_num = ARRAY_SIZE(afh_5g_8723d), + .afh_5g = afh_5g_8723d, + + .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8723d), + .coex_info_hw_regs = coex_info_hw_regs_8723d, }; EXPORT_SYMBOL(rtw8723d_hw_spec); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index d1f1c1a594ad..31b8ed9ee652 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -143,6 +143,7 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) #define BIT_MASK_RFMOD BIT(0) #define BIT_LCK BIT(15) +#define REG_GPIO_INTM 0x0048 #define REG_BTG_SEL 0x0067 #define REG_LTECOEX_PATH_CONTROL 0x0070 #define REG_LTECOEX_CTRL 0x07c0 @@ -150,6 +151,7 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) #define REG_LTECOEX_READ_DATA 0x07c8 #define REG_PSDFN 0x0808 #define REG_BB_PWR_SAV1_11N 0x0874 +#define REG_ANA_PARAM1 0x0880 #define REG_ANALOG_P4 0x088c #define REG_PSDRPT 0x08b4 #define REG_FPGA1_RFMOD 0x0900 @@ -192,6 +194,7 @@ static inline s32 iqk_mult(s32 x, s32 y, s32 *ext) #define BIT_SET_OFDM0_EXTS(a, c, d) (((a) << 31) | ((c) << 29) | ((d) << 28)) #define REG_OFDM0_XAAGC1 0x0c50 #define REG_OFDM0_XBAGC1 0x0c58 +#define REG_AGCRSSI 0x0c78 #define REG_OFDM_0_XA_TX_IQ_IMBALANCE 0x0c80 #define BIT_MASK_TXIQ_ELM_A 0x03ff #define BIT_SET_TXIQ_ELM_ACD(a, c, d) (((d) << 22) | (((c) & 0x3F) << 16) | \ -- cgit From 504e2b288258e8e28d46f3e314be7cb460bdd655 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:20 +0800 Subject: rtw88: fill zeros to words 0x06 and 0x07 of security cam entry 8723D adds some experimental features to word 0x06 of cam entry, so fill zeros to initialize them to off state. For existing chips, these two words are reserved and always zeros, so this change is harmless for them. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-9-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/sec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/sec.c b/drivers/net/wireless/realtek/rtw88/sec.c index d0d7fbb10d58..ce46e5b4a60a 100644 --- a/drivers/net/wireless/realtek/rtw88/sec.c +++ b/drivers/net/wireless/realtek/rtw88/sec.c @@ -44,7 +44,7 @@ void rtw_sec_write_cam(struct rtw_dev *rtwdev, write_cmd = RTW_SEC_CMD_WRITE_ENABLE | RTW_SEC_CMD_POLLING; addr = hw_key_idx << RTW_SEC_CAM_ENTRY_SHIFT; - for (i = 5; i >= 0; i--) { + for (i = 7; i >= 0; i--) { switch (i) { case 0: content = ((key->keyidx & 0x3)) | @@ -60,6 +60,10 @@ void rtw_sec_write_cam(struct rtw_dev *rtwdev, (cam->addr[4] << 16) | (cam->addr[5] << 24); break; + case 6: + case 7: + content = 0; + break; default: j = (i - 2) << 2; content = (key->key[j]) | -- cgit From f5df1a8b4376551f7fb2416135c58896b70a1467 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 12 May 2020 18:26:21 +0800 Subject: rtw88: 8723d: Add 8723DE to Kconfig and Makefile Since 8723D code is ready, we can build it. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512102621.5148-10-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/Kconfig | 10 ++++++++++ drivers/net/wireless/realtek/rtw88/Makefile | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index 33bd7ed797ff..7a5fa68945c4 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -36,6 +36,16 @@ config RTW88_8822CE 802.11ac PCIe wireless network adapter +config RTW88_8723DE + bool "Realtek 8723DE PCI wireless network adapter" + depends on PCI + select RTW88_CORE + select RTW88_PCI + help + Select this option will enable support for 8723DE chipset + + 802.11n PCIe wireless network adapter + config RTW88_DEBUG bool "Realtek rtw88 debug support" depends on RTW88_CORE diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index cac148d13cf1..385facc0dd20 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -20,6 +20,7 @@ rtw88-y += main.o \ rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o rtw88-$(CONFIG_RTW88_8822CE) += rtw8822c.o rtw8822c_table.o +rtw88-$(CONFIG_RTW88_8723DE) += rtw8723d.o rtw8723d_table.o obj-$(CONFIG_RTW88_PCI) += rtwpci.o rtwpci-objs := pci.o -- cgit From 0c4402385ac46afe5dc8c5854f9ce9028afcf69e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 12 May 2020 18:35:34 +0800 Subject: rtw88: 8723d: fix sparse warnings for power tracking sparse warnings: (new ones prefixed by >>) >> drivers/net/wireless/realtek/rtw88/rtw8723d.c:1899:6: sparse: sparse: symbol 'rtw8723d_pwr_track' was not declared. Should it be static? Reported-by: kbuild test robot Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200512103534.5889-1-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 400364aec393..b517af417e0e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1896,7 +1896,7 @@ iqk: rtw8723d_phy_calibration(rtwdev); } -void rtw8723d_pwr_track(struct rtw_dev *rtwdev) +static void rtw8723d_pwr_track(struct rtw_dev *rtwdev) { struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_dm_info *dm_info = &rtwdev->dm_info; -- cgit From b6ba5761faad24fa5d6b931682a74071f3511fdc Mon Sep 17 00:00:00 2001 From: ChenTao Date: Wed, 13 May 2020 09:17:54 +0800 Subject: rtl8187: Remove unused variable rtl8225z2_tx_power_ofdm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warning: drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c:609:17: warning: ‘rtl8225z2_tx_power_ofdm’ defined but not used static const u8 rtl8225z2_tx_power_ofdm[] = { Acked-by: Hin-Tak Leung Acked-by: Larry Finger Reported-by: Hulk Robot Signed-off-by: ChenTao Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200513011754.28432-1-chentao107@huawei.com --- drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c index b2616d61b66d..585784258c66 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/rtl8225.c @@ -606,10 +606,6 @@ static const u8 rtl8225z2_tx_power_cck[] = { 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03 }; -static const u8 rtl8225z2_tx_power_ofdm[] = { - 0x42, 0x00, 0x40, 0x00, 0x40 -}; - static const u8 rtl8225z2_tx_gain_cck_ofdm[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, -- cgit From f8d6379932dd08263d3131ab64427b134ea9e035 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 12 May 2020 21:39:13 +0200 Subject: mt76: mt7663: fix the usage WoW with net detect support mt7615_mcu_sched_scan_enable should be taken along with mt7615_mcu_sched_scan_req to have proper scan plans initialization. Fixes: bd39bd2f00c3 ("mt76: mt7663: introduce WoW with net detect support") Co-developed-by: Wan-Feng Jiang Signed-off-by: Wan-Feng Jiang Co-developed-by: Soul Huang Signed-off-by: Soul Huang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 96bf39a4a3da..ef50b9a885f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -3351,8 +3351,8 @@ mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (wowlan->nd_config) { mt7615_mcu_sched_scan_req(phy, vif, wowlan->nd_config); req.wow_ctrl_tlv.trigger |= BIT(5); + mt7615_mcu_sched_scan_enable(phy, vif, suspend); } - mt7615_mcu_sched_scan_enable(phy, vif, suspend); if (mt76_is_mmio(&dev->mt76)) req.wow_ctrl_tlv.wakeup_hif = 2; -- cgit From 7cba8c30aa7baf79650dec6b7713b985be84c5f7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 May 2020 22:02:47 +0200 Subject: mt76: mt7615: do not report scan_complete twice to mac80211 Fix the following kernel warning that occurs if scan work is scheduled and the hw scan has been cancelled by mac80211 WARNING: CPU: 1 PID: 502 at net/mac80211/scan.c:391 __ieee80211_scan_completed+0x299/0x690 Modules linked in: CPU: 1 PID: 502 Comm: kworker/u4:4 Not tainted 5.7.0-rc1+ #2882 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014 Workqueue: phy0 ieee80211_scan_work RIP: 0010:__ieee80211_scan_completed+0x299/0x690 RSP: 0018:ffffc9000036fda8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 8c6318c6318c6320 RDX: 0000000000000000 RSI: 00000000ffffffff RDI: ffff88803bb129b8 RBP: ffff88803bb10d80 R08: 0000000000000001 R09: 0000000000000001 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: ffff88803bb12ae8 FS: 0000000000000000(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f13ee5c1470 CR3: 000000003c790000 CR4: 00000000000006a0 Call Trace: ieee80211_scan_work+0x170/0x850 ? sched_clock_cpu+0x11/0xb0 process_one_work+0x24f/0x580 ? worker_thread+0xcc/0x3e0 worker_thread+0x4f/0x3e0 ? process_one_work+0x580/0x580 kthread+0x11b/0x140 ? __kthread_bind_mask+0x60/0x60 ret_from_fork+0x3a/0x50 irq event stamp: 9255532 hardirqs last enabled at (9255531): [] _raw_spin_unlock_irq+0x24/0x30 hardirqs last disabled at (9255532): [] trace_hardirqs_off_thunk+0x1a/0x1c softirqs last enabled at (9255526): [] process_one_work+0x24f/0x580 softirqs last disabled at (9255524): [] mt7615_scan_work+0x91/0xc0 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 402ff38f7dcf..c8705f91bafc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -810,15 +810,15 @@ void mt7615_scan_work(struct work_struct *work) break; rxd = (struct mt7615_mcu_rxd *)skb->data; - if (rxd->eid == MCU_EVENT_SCAN_DONE) { + if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { + ieee80211_sched_scan_results(phy->mt76->hw); + } else if (test_and_clear_bit(MT76_HW_SCANNING, + &phy->mt76->state)) { struct cfg80211_scan_info info = { .aborted = false, }; - clear_bit(MT76_HW_SCANNING, &phy->mt76->state); ieee80211_scan_completed(phy->mt76->hw, &info); - } else { - ieee80211_sched_scan_results(phy->mt76->hw); } dev_kfree_skb(skb); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index ef50b9a885f4..9cb8a9bb912b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2861,9 +2861,6 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; - struct cfg80211_scan_info info = { - .aborted = true, - }; struct { u8 seq_num; u8 is_ext_channel; @@ -2872,8 +2869,13 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy, .seq_num = mvif->scan_seq_num, }; - ieee80211_scan_completed(phy->mt76->hw, &info); - clear_bit(MT76_HW_SCANNING, &phy->mt76->state); + if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(phy->mt76->hw, &info); + } return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req, sizeof(req), false); -- cgit From 8f3dab33da2ca4f7f72ac49281b9f2ac390d0824 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 May 2020 22:02:48 +0200 Subject: mt76: mt7615: reduce hw scan timeout Differentiate hw scan channel time between passive and active scan Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 9cb8a9bb912b..e9ae7e94d8fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2773,7 +2773,7 @@ int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy) MCU_CMD_SET_CHAN_DOMAIN, false); } -#define MT7615_SCAN_CHANNEL_TIME 120 +#define MT7615_SCAN_CHANNEL_TIME 60 int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req) { @@ -2819,6 +2819,9 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif, req->ssid_type = n_ssids ? BIT(2) : BIT(0); req->ssids_num = n_ssids; + /* increase channel time for passive scan */ + if (!sreq->n_ssids) + duration *= 2; req->timeout_value = cpu_to_le16(sreq->n_channels * duration); req->channel_min_dwell_time = cpu_to_le16(duration); req->channel_dwell_time = cpu_to_le16(duration); -- cgit From 50eb0a884a4cbb158369cf3128b98a97c8f431a0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 12 May 2020 22:02:49 +0200 Subject: mt76: enable p2p support Introduce p2p-go/p2p-client suppor to mt76 driver Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 + drivers/net/wireless/mediatek/mt76/mt7603/init.c | 2 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 6 ++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 ++ drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 61 +++++++++++++++++++--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 4 ++ 8 files changed, 72 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 21407704f1b3..907098101898 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -313,6 +313,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index f641a8b56b39..94196599797e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -342,6 +342,8 @@ static const struct ieee80211_iface_limit if_limits[] = { #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 6e1a17f08f5e..b5bbe9f5f7dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -140,7 +140,9 @@ void mt7615_check_offload_capability(struct mt7615_dev *dev) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | - NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_P2P_GO_CTWIN | + NL80211_FEATURE_P2P_GO_OPPPS; } else { dev->ops->hw_scan = NULL; dev->ops->cancel_hw_scan = NULL; @@ -205,6 +207,8 @@ static const struct ieee80211_iface_limit if_limits[] = { #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION) } }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index c8705f91bafc..e87a5843c718 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -503,6 +503,9 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON_ENABLED) { mt7615_mcu_add_bss_info(phy, vif, NULL, info->enable_beacon); mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon); + + if (vif->p2p && info->enable_beacon) + mt7615_mcu_set_p2p_oppps(hw, vif); } if (changed & (BSS_CHANGED_BEACON | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index e9ae7e94d8fd..92ea9dc3c1c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -695,9 +695,9 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA; struct bss_info_basic *bss; u8 wlan_idx = mvif->sta.wcid.idx; - u32 type = NETWORK_INFRA; struct tlv *tlv; tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); @@ -749,10 +749,16 @@ mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: - type = CONNECTION_INFRA_AP; + if (vif->p2p) + type = CONNECTION_P2P_GO; + else + type = CONNECTION_INFRA_AP; break; case NL80211_IFTYPE_STATION: - type = CONNECTION_INFRA_STA; + if (vif->p2p) + type = CONNECTION_P2P_GC; + else + type = CONNECTION_INFRA_STA; break; case NL80211_IFTYPE_ADHOC: type = CONNECTION_IBSS_ADHOC; @@ -815,6 +821,7 @@ mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, { struct sta_rec_basic *basic; struct tlv *tlv; + int conn_type; tlv = mt7615_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); @@ -837,11 +844,19 @@ mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: - basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + if (vif->p2p) + conn_type = CONNECTION_P2P_GC; + else + conn_type = CONNECTION_INFRA_STA; + basic->conn_type = cpu_to_le32(conn_type); basic->aid = cpu_to_le16(sta->aid); break; case NL80211_IFTYPE_STATION: - basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + if (vif->p2p) + conn_type = CONNECTION_P2P_GO; + else + conn_type = CONNECTION_INFRA_AP; + basic->conn_type = cpu_to_le32(conn_type); basic->aid = cpu_to_le16(vif->bss_conf.aid); break; case NL80211_IFTYPE_ADHOC: @@ -1403,7 +1418,7 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, .short_st = true, }, }; - int err; + int err, conn_type; u8 idx; idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; @@ -1412,10 +1427,18 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + if (vif->p2p) + conn_type = CONNECTION_P2P_GO; + else + conn_type = CONNECTION_INFRA_AP; + basic_req.basic.conn_type = cpu_to_le32(conn_type); break; case NL80211_IFTYPE_STATION: - basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + if (vif->p2p) + conn_type = CONNECTION_P2P_GC; + else + conn_type = CONNECTION_INFRA_STA; + basic_req.basic.conn_type = cpu_to_le32(conn_type); break; case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); @@ -3550,3 +3573,25 @@ int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, MCU_UNI_CMD_OFFLOAD, true); } #endif /* CONFIG_PM */ + +int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct { + __le32 ct_win; + u8 bss_idx; + u8 rsv[3]; + } __packed req = { + .ct_win = cpu_to_le32(ct_window), + .bss_idx = mvif->idx, + }; + + if (!mt7615_firmware_offload(dev)) + return -ENOTSUPP; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, + &req, sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 0f12e6da89af..338fd077f575 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -507,6 +507,7 @@ enum { MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16, MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17, MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, + MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index dc60abb0a130..ebdfca64b079 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -530,6 +530,8 @@ int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); +int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); int mt7615_firmware_own(struct mt7615_dev *dev); int mt7615_driver_own(struct mt7615_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index b7a120b0856d..9a2c9afa2fb5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -46,6 +46,8 @@ static const struct ieee80211_iface_limit mt76x02_if_limits[] = { #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; @@ -60,6 +62,8 @@ static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; -- cgit From 7a20388ed848a9e82e878d6847e0e0021be64985 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Tue, 12 May 2020 22:02:50 +0200 Subject: mt76: mt7615: configure bss info adding the interface Introduce essential bss information for multiple vifs hw_scan in mt7615_mcu_uni_add_dev adding the interface Signed-off-by: Sean Wang Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 5 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 97 +++++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt7615/mcu.h | 26 +++++++ 3 files changed, 89 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index e87a5843c718..2e9e9d3519d7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -156,10 +156,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, else mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; - ret = mt7615_mcu_add_dev_info(dev, vif, true); - if (ret) - goto out; - dev->vif_mask |= BIT(mvif->idx); dev->omac_mask |= BIT(mvif->omac_idx); phy->omac_mask |= BIT(mvif->omac_idx); @@ -182,6 +178,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, mt76_txq_init(&dev->mt76, vif->txq); } + ret = mt7615_mcu_add_dev_info(dev, vif, true); out: mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 92ea9dc3c1c6..b944f372738a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1294,7 +1294,7 @@ mt7615_mcu_uni_add_dev(struct mt7615_dev *dev, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct { - struct req_hdr { + struct { u8 omac_idx; u8 band_idx; __le16 pad; @@ -1306,7 +1306,7 @@ mt7615_mcu_uni_add_dev(struct mt7615_dev *dev, u8 pad; u8 omac_addr[ETH_ALEN]; } __packed tlv; - } data = { + } dev_req = { .hdr = { .omac_idx = mvif->omac_idx, .band_idx = mvif->band_idx, @@ -1317,11 +1317,65 @@ mt7615_mcu_uni_add_dev(struct mt7615_dev *dev, .active = enable, }, }; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_bss_basic_tlv basic; + } basic_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .basic = { + .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), + .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), + .omac_idx = mvif->omac_idx, + .band_idx = mvif->band_idx, + .wmm_idx = mvif->wmm_idx, + .active = enable, + .bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx), + .sta_idx = cpu_to_le16(mvif->sta.wcid.idx), + .conn_state = 1, + }, + }; + int err, idx, cmd, len; + void *data; - memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); + break; + case NL80211_IFTYPE_STATION: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); + break; + case NL80211_IFTYPE_ADHOC: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; + default: + WARN_ON(1); + break; + } - return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_DEV_INFO_UPDATE, - &data, sizeof(data), true); + idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; + basic_req.basic.hw_bss_idx = idx; + + memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); + + cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE; + data = enable ? (void *)&dev_req : (void *)&basic_req; + len = enable ? sizeof(dev_req) : sizeof(basic_req); + + err = __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); + if (err < 0) + return err; + + cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE; + data = enable ? (void *)&basic_req : (void *)&dev_req; + len = enable ? sizeof(basic_req) : sizeof(dev_req); + + return __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true); } static int @@ -1343,44 +1397,20 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, u8 bss_idx; u8 pad[3]; } __packed hdr; - struct basic_tlv { - __le16 tag; - __le16 len; - u8 active; - u8 omac_idx; - u8 hw_bss_idx; - u8 band_idx; - __le32 conn_type; - u8 conn_state; - u8 wmm_idx; - u8 bssid[ETH_ALEN]; - __le16 bmc_tx_wlan_idx; - __le16 bcn_interval; - u8 dtim_period; - u8 phymode; /* bit(0): A - * bit(1): B - * bit(2): G - * bit(3): GN - * bit(4): AN - * bit(5): AC - */ - __le16 sta_idx; - u8 nonht_basic_phy; - u8 pad[3]; - } __packed basic; + struct mt7615_bss_basic_tlv basic; } basic_req = { .hdr = { .bss_idx = mvif->idx, }, .basic = { .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), - .len = cpu_to_le16(sizeof(struct basic_tlv)), + .len = cpu_to_le16(sizeof(struct mt7615_bss_basic_tlv)), .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), .dtim_period = vif->bss_conf.dtim_period, .omac_idx = mvif->omac_idx, .band_idx = mvif->band_idx, .wmm_idx = mvif->wmm_idx, - .active = enable, + .active = true, /* keep bss deactivated */ .phymode = 0x38, }, }; @@ -1458,9 +1488,6 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (err < 0) return err; - if (!mt7615_firmware_offload(dev)) - return 0; - switch (chandef->width) { case NL80211_CHAN_WIDTH_40: rlm_req.rlm.bw = CMD_CBW_40MHZ; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 338fd077f575..348521b0d44c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -425,6 +425,32 @@ struct mt7615_mcu_bss_event { u8 pad; } __packed; +struct mt7615_bss_basic_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 omac_idx; + u8 hw_bss_idx; + u8 band_idx; + __le32 conn_type; + u8 conn_state; + u8 wmm_idx; + u8 bssid[ETH_ALEN]; + __le16 bmc_tx_wlan_idx; + __le16 bcn_interval; + u8 dtim_period; + u8 phymode; /* bit(0): A + * bit(1): B + * bit(2): G + * bit(3): GN + * bit(4): AN + * bit(5): AC + */ + __le16 sta_idx; + u8 nonht_basic_phy; + u8 pad[3]; +} __packed; + struct mt7615_wow_ctrl_tlv { __le16 tag; __le16 len; -- cgit From 12a87174accd29ff943d4c5fb735e1541b92630b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 13 May 2020 15:53:04 +0200 Subject: mt76: mt7615: fix typo defining ps work Fix typo defining ps_work in mt7615_register_ext_phy(). This is not a real issue since 802.11 power save is not yet support by the external phy Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index b5bbe9f5f7dd..1d8fdc7e062b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -372,7 +372,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); skb_queue_head_init(&phy->scan_event_list); - INIT_WORK(&dev->phy.ps_work, mt7615_ps_work); + INIT_WORK(&phy->ps_work, mt7615_ps_work); mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops); -- cgit From beb12813bc75d4a23de43b85ad1c7cb28d27631e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 May 2020 12:39:51 +0300 Subject: rtlwifi: Fix a double free in _rtl_usb_tx_urb_setup() Seven years ago we tried to fix a leak but actually introduced a double free instead. It was an understandable mistake because the code was a bit confusing and the free was done in the wrong place. The "skb" pointer is freed in both _rtl_usb_tx_urb_setup() and _rtl_usb_transmit(). The free belongs _rtl_usb_transmit() instead of _rtl_usb_tx_urb_setup() and I've cleaned the code up a bit to hopefully make it more clear. Fixes: 36ef0b473fbf ("rtlwifi: usb: add missing freeing of skbuff") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200513093951.GD347693@mwanda --- drivers/net/wireless/realtek/rtlwifi/usb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 348b0072cdd6..c66c6dc00378 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -881,10 +881,8 @@ static struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw, WARN_ON(NULL == skb); _urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!_urb) { - kfree_skb(skb); + if (!_urb) return NULL; - } _rtl_install_trx_info(rtlusb, skb, ep_num); usb_fill_bulk_urb(_urb, rtlusb->udev, usb_sndbulkpipe(rtlusb->udev, ep_num), skb->data, skb->len, _rtl_tx_complete, skb); @@ -898,7 +896,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); u32 ep_num; struct urb *_urb = NULL; - struct sk_buff *_skb = NULL; WARN_ON(NULL == rtlusb->usb_tx_aggregate_hdl); if (unlikely(IS_USB_STOP(rtlusb))) { @@ -907,8 +904,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb, return; } ep_num = rtlusb->ep_map.ep_mapping[qnum]; - _skb = skb; - _urb = _rtl_usb_tx_urb_setup(hw, _skb, ep_num); + _urb = _rtl_usb_tx_urb_setup(hw, skb, ep_num); if (unlikely(!_urb)) { pr_err("Can't allocate urb. Drop skb!\n"); kfree_skb(skb); -- cgit From 449be86670f50284069cb0ddc4fe98f064ac6d87 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:21 +0800 Subject: rtw88: extract: export symbols used in chip functionalities In the current design, various chip functions and tables are built into rtw88 core. That causes kernel to load its functionalities even if a chip isn't currently used. We plan to make each chip's functionalities a separate kernel module to reduce rtw88 core. And kernel will be able to load the necessary. Before extracting chip functionalities, we export symbols inside rtw88 core which will be used in chip modules. Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-2-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/bf.c | 7 +++++++ drivers/net/wireless/realtek/rtw88/coex.c | 3 +++ drivers/net/wireless/realtek/rtw88/efuse.c | 1 + drivers/net/wireless/realtek/rtw88/fw.c | 1 + drivers/net/wireless/realtek/rtw88/mac.c | 1 + drivers/net/wireless/realtek/rtw88/phy.c | 26 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rx.c | 1 + drivers/net/wireless/realtek/rtw88/util.c | 2 ++ 8 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index a5912da327e2..8a070d5d9174 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -220,6 +220,7 @@ void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, /* ndp rx standby timer */ rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, RTW_NDP_RX_STANDBY_TIME); } +EXPORT_SYMBOL(rtw_bf_enable_bfee_su); /* nc index: 1 2T2R 0 1T1R * nr index: 1 use Nsts 0 use reg setting @@ -263,6 +264,7 @@ void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, /* accept NDPA and BF report poll */ rtw_write16_set(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF); } +EXPORT_SYMBOL(rtw_bf_enable_bfee_mu); void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, struct rtw_bfee *bfee) @@ -288,6 +290,7 @@ void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, clear_bit(bfee->su_reg_index, bfinfo->bfer_su_reg_maping); bfee->su_reg_index = 0xFF; } +EXPORT_SYMBOL(rtw_bf_remove_bfee_su); void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, struct rtw_bfee *bfee) @@ -301,6 +304,7 @@ void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, if (bfinfo->bfer_su_cnt == 0 && bfinfo->bfer_mu_cnt == 0) rtw_bf_del_sounding(rtwdev); } +EXPORT_SYMBOL(rtw_bf_remove_bfee_mu); void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf) @@ -329,6 +333,7 @@ void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtw_bf_cfg_mu_bfee(rtwdev, ¶m); } +EXPORT_SYMBOL(rtw_bf_set_gid_table); void rtw_bf_phy_init(struct rtw_dev *rtwdev) { @@ -365,6 +370,7 @@ void rtw_bf_phy_init(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, REG_BBPSF_CTRL, BIT_MASK_CSI_RATE, DESC_RATE6M); } +EXPORT_SYMBOL(rtw_bf_phy_init); void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, u8 fixrate_en, u8 *new_rate) @@ -395,3 +401,4 @@ void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, *new_rate = DESC_RATE24M; } } +EXPORT_SYMBOL(rtw_bf_cfg_csi_rate); diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 567372fb4e12..924dccd5d146 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -283,6 +283,7 @@ void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set) rtw_write16(rtwdev, REG_WIFI_BT_INFO, val); } } +EXPORT_SYMBOL(rtw_coex_write_scbd); static u16 rtw_coex_read_scbd(struct rtw_dev *rtwdev) { @@ -732,6 +733,7 @@ u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr) return val; } +EXPORT_SYMBOL(rtw_coex_read_indirect_reg); void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, u32 mask, u32 val) @@ -745,6 +747,7 @@ void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, if (!ltecoex_reg_write(rtwdev, addr, tmp)) rtw_err(rtwdev, "failed to write indirect register\n"); } +EXPORT_SYMBOL(rtw_coex_write_indirect_reg); static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) { diff --git a/drivers/net/wireless/realtek/rtw88/efuse.c b/drivers/net/wireless/realtek/rtw88/efuse.c index 13d1c58d6de5..c266c84ef233 100644 --- a/drivers/net/wireless/realtek/rtw88/efuse.c +++ b/drivers/net/wireless/realtek/rtw88/efuse.c @@ -141,6 +141,7 @@ int rtw_read8_physical_efuse(struct rtw_dev *rtwdev, u16 addr, u8 *data) return 0; } +EXPORT_SYMBOL(rtw_read8_physical_efuse); int rtw_parse_efuse_map(struct rtw_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 2c28afe525c7..6478fd7a78f6 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -330,6 +330,7 @@ void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para) rtw_fw_send_h2c_packet(rtwdev, h2c_pkt); } +EXPORT_SYMBOL(rtw_fw_do_iqk); void rtw_fw_query_bt_info(struct rtw_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 3a5cfebe5a62..19b9b7ab016b 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -56,6 +56,7 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, value8 |= BIT_CHECK_CCK_EN; rtw_write8(rtwdev, REG_CCK_CHECK, value8); } +EXPORT_SYMBOL(rtw_set_channel_mac); static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 45181f602e3f..8d93f3159746 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -82,6 +82,8 @@ u8 *rtw_rate_section[RTW_RATE_SECTION_MAX] = { rtw_ht_1s_rates, rtw_ht_2s_rates, rtw_vht_1s_rates, rtw_vht_2s_rates }; +EXPORT_SYMBOL(rtw_rate_section); + u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = { ARRAY_SIZE(rtw_cck_rates), ARRAY_SIZE(rtw_ofdm_rates), @@ -90,6 +92,8 @@ u8 rtw_rate_size[RTW_RATE_SECTION_MAX] = { ARRAY_SIZE(rtw_vht_1s_rates), ARRAY_SIZE(rtw_vht_2s_rates) }; +EXPORT_SYMBOL(rtw_rate_size); + static const u8 rtw_cck_size = ARRAY_SIZE(rtw_cck_rates); static const u8 rtw_ofdm_size = ARRAY_SIZE(rtw_ofdm_rates); static const u8 rtw_ht_1s_size = ARRAY_SIZE(rtw_ht_1s_rates); @@ -137,6 +141,7 @@ void rtw_phy_init(struct rtw_dev *rtwdev) dm_info->iqk.done = false; } +EXPORT_SYMBOL(rtw_phy_init); void rtw_phy_dig_write(struct rtw_dev *rtwdev, u8 igi) { @@ -676,6 +681,7 @@ u8 rtw_phy_rf_power_2_rssi(s8 *rf_power, u8 path_num) return rtw_phy_linear_2_db(sum); } +EXPORT_SYMBOL(rtw_phy_rf_power_2_rssi); u32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask) @@ -698,6 +704,7 @@ u32 rtw_phy_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, return val; } +EXPORT_SYMBOL(rtw_phy_read_rf); u32 rtw_phy_read_rf_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask) @@ -746,6 +753,7 @@ u32 rtw_phy_read_rf_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, return (val32 & mask) >> shift; } +EXPORT_SYMBOL(rtw_phy_read_rf_sipi); bool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask, u32 data) @@ -785,6 +793,7 @@ bool rtw_phy_write_rf_reg_sipi(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, return true; } +EXPORT_SYMBOL(rtw_phy_write_rf_reg_sipi); bool rtw_phy_write_rf_reg(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask, u32 data) @@ -818,6 +827,7 @@ bool rtw_phy_write_rf_reg_mix(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, return rtw_phy_write_rf_reg_sipi(rtwdev, rf_path, addr, mask, data); } +EXPORT_SYMBOL(rtw_phy_write_rf_reg_mix); void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg) { @@ -910,6 +920,7 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl) } } } +EXPORT_SYMBOL(rtw_parse_tbl_phy_cond); #define bcd_to_dec_pwr_by_rate(val, i) bcd2bin(val >> (i * 8)) @@ -1273,6 +1284,7 @@ void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl) p->data); } } +EXPORT_SYMBOL(rtw_parse_tbl_bb_pg); static const u8 rtw_channel_idx_5g[RTW_MAX_CHANNEL_NUM_5G] = { 36, 38, 40, 42, 44, 46, 48, /* Band 1 */ @@ -1417,18 +1429,21 @@ void rtw_parse_tbl_txpwr_lmt(struct rtw_dev *rtwdev, rtw_xref_txpwr_lmt(rtwdev); } +EXPORT_SYMBOL(rtw_parse_tbl_txpwr_lmt); void rtw_phy_cfg_mac(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data) { rtw_write8(rtwdev, addr, data); } +EXPORT_SYMBOL(rtw_phy_cfg_mac); void rtw_phy_cfg_agc(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data) { rtw_write32(rtwdev, addr, data); } +EXPORT_SYMBOL(rtw_phy_cfg_agc); void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data) @@ -1448,6 +1463,7 @@ void rtw_phy_cfg_bb(struct rtw_dev *rtwdev, const struct rtw_table *tbl, else rtw_write32(rtwdev, addr, data); } +EXPORT_SYMBOL(rtw_phy_cfg_bb); void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data) @@ -1461,6 +1477,7 @@ void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl, udelay(1); } } +EXPORT_SYMBOL(rtw_phy_cfg_rf); static void rtw_load_rfk_table(struct rtw_dev *rtwdev) { @@ -1498,6 +1515,7 @@ void rtw_phy_load_tables(struct rtw_dev *rtwdev) rtw_load_table(rtwdev, tbl); } } +EXPORT_SYMBOL(rtw_phy_load_tables); static u8 rtw_get_channel_group(u8 channel) { @@ -1841,6 +1859,7 @@ rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate, return tx_power; } +EXPORT_SYMBOL(rtw_phy_get_tx_power_index); static void rtw_phy_set_tx_power_index_by_rs(struct rtw_dev *rtwdev, u8 ch, u8 path, u8 rs) @@ -1903,6 +1922,7 @@ void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel) chip->ops->set_tx_power_index(rtwdev); mutex_unlock(&hal->tx_power_mutex); } +EXPORT_SYMBOL(rtw_phy_set_tx_power_level); static void rtw_phy_tx_power_by_rate_config_by_path(struct rtw_hal *hal, u8 path, @@ -2060,6 +2080,7 @@ void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n; } } +EXPORT_SYMBOL(rtw_phy_config_swing_table); void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path) { @@ -2069,6 +2090,7 @@ void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path) dm_info->thermal_avg[path] = ewma_thermal_read(&dm_info->avg_thermal[path]); } +EXPORT_SYMBOL(rtw_phy_pwrtrack_avg); bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, u8 path) @@ -2081,6 +2103,7 @@ bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, return true; } +EXPORT_SYMBOL(rtw_phy_pwrtrack_thermal_changed); u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path) { @@ -2093,6 +2116,7 @@ u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path) return min_t(u8, therm_delta, RTW_PWR_TRK_TBL_SZ - 1); } +EXPORT_SYMBOL(rtw_phy_pwrtrack_get_delta); s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, struct rtw_swing_table *swing_table, @@ -2126,6 +2150,7 @@ s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, else return -delta_swing_table_idx_neg[delta]; } +EXPORT_SYMBOL(rtw_phy_pwrtrack_get_pwridx); bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) { @@ -2139,3 +2164,4 @@ bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) } return false; } +EXPORT_SYMBOL(rtw_phy_pwrtrack_need_iqk); diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 9b90339ab697..7087e385a9b3 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -191,3 +191,4 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, rtw_rx_addr_match(rtwdev, pkt_stat, hdr); } +EXPORT_SYMBOL(rtw_rx_fill_rx_status); diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c index 42cf177cd445..2c515af214e7 100644 --- a/drivers/net/wireless/realtek/rtw88/util.c +++ b/drivers/net/wireless/realtek/rtw88/util.c @@ -19,6 +19,7 @@ bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target) return false; } +EXPORT_SYMBOL(check_hw_ready); bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val) { @@ -76,6 +77,7 @@ void rtw_restore_reg(struct rtw_dev *rtwdev, } } } +EXPORT_SYMBOL(rtw_restore_reg); void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) { -- cgit From 72f256c2b948622cc45ff8bc0456dd6039d8fe36 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:22 +0800 Subject: rtw88: extract: export symbols about pci interface In the current design, chip entry points are built into the pci module. That makes the pci module depend on chips. According to dependence, once the pci module is loaded, kernel will load chip functionalities, including those that may not be currently used. We plan to split chip entry points from the pci module. Thence we export pci symbols that will be used in chip entry point modules. Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-3-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/pci.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index e5ea30c04ac5..fb5d28152775 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1360,7 +1360,8 @@ static int __maybe_unused rtw_pci_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(rtw_pm_ops, rtw_pci_suspend, rtw_pci_resume); +SIMPLE_DEV_PM_OPS(rtw_pm_ops, rtw_pci_suspend, rtw_pci_resume); +EXPORT_SYMBOL(rtw_pm_ops); static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev) { @@ -1473,8 +1474,8 @@ static void rtw_pci_free_irq(struct rtw_dev *rtwdev, struct pci_dev *pdev) pci_free_irq_vectors(pdev); } -static int rtw_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +int rtw_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { struct ieee80211_hw *hw; struct rtw_dev *rtwdev; @@ -1551,8 +1552,9 @@ err_release_hw: return ret; } +EXPORT_SYMBOL(rtw_pci_probe); -static void rtw_pci_remove(struct pci_dev *pdev) +void rtw_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct rtw_dev *rtwdev; @@ -1572,8 +1574,9 @@ static void rtw_pci_remove(struct pci_dev *pdev) rtw_core_deinit(rtwdev); ieee80211_free_hw(hw); } +EXPORT_SYMBOL(rtw_pci_remove); -static void rtw_pci_shutdown(struct pci_dev *pdev) +void rtw_pci_shutdown(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct rtw_dev *rtwdev; @@ -1588,6 +1591,7 @@ static void rtw_pci_shutdown(struct pci_dev *pdev) if (chip->ops->shutdown) chip->ops->shutdown(rtwdev); } +EXPORT_SYMBOL(rtw_pci_shutdown); static const struct pci_device_id rtw_pci_id_table[] = { #ifdef CONFIG_RTW88_8822BE -- cgit From ba0fbe236fb8a7b992e82d6eafb03a600f5eba43 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:23 +0800 Subject: rtw88: extract: make 8822c an individual kernel module Make objects about 8822c functions and 8822c tables, i.e. rtw8822c.o and rtw8822c_table.o, an individual kernel module called rtw88_8822c.ko. For 8822c pcie chip, i.e. 8822CE chip, add a chip entry point module called rtw88_8822ce.ko which will depend on rtw88_8822c.ko and rtwpci.ko. Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-4-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/Kconfig | 6 +++++- drivers/net/wireless/realtek/rtw88/Makefile | 7 +++++- drivers/net/wireless/realtek/rtw88/main.h | 1 - drivers/net/wireless/realtek/rtw88/pci.c | 3 --- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 5 +++++ drivers/net/wireless/realtek/rtw88/rtw8822ce.c | 30 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8822ce.h | 14 ++++++++++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822ce.c create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822ce.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index 7a5fa68945c4..f4dbb5914bde 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -16,6 +16,9 @@ config RTW88_CORE config RTW88_PCI tristate +config RTW88_8822C + tristate + config RTW88_8822BE bool "Realtek 8822BE PCI wireless network adapter" depends on PCI @@ -27,10 +30,11 @@ config RTW88_8822BE 802.11ac PCIe wireless network adapter config RTW88_8822CE - bool "Realtek 8822CE PCI wireless network adapter" + tristate "Realtek 8822CE PCI wireless network adapter" depends on PCI select RTW88_CORE select RTW88_PCI + select RTW88_8822C help Select this option will enable support for 8822CE chipset diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 385facc0dd20..e45efd2deaa3 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -19,8 +19,13 @@ rtw88-y += main.o \ regd.o rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o -rtw88-$(CONFIG_RTW88_8822CE) += rtw8822c.o rtw8822c_table.o rtw88-$(CONFIG_RTW88_8723DE) += rtw8723d.o rtw8723d_table.o +obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o +rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o + +obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o +rtw88_8822ce-objs := rtw8822ce.o + obj-$(CONFIG_RTW88_PCI) += rtwpci.o rtwpci-objs := pci.o diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index c9156b9b532c..d6e25d4c5aed 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -41,7 +41,6 @@ extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; extern struct rtw_chip_info rtw8822b_hw_spec; -extern struct rtw_chip_info rtw8822c_hw_spec; extern struct rtw_chip_info rtw8723d_hw_spec; #define RTW_MAX_CHANNEL_NUM_2G 14 diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index fb5d28152775..af9cd23a3273 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1597,9 +1597,6 @@ static const struct pci_device_id rtw_pci_id_table[] = { #ifdef CONFIG_RTW88_8822BE { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822, rtw8822b_hw_spec) }, #endif -#ifdef CONFIG_RTW88_8822CE - { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC822, rtw8822c_hw_spec) }, -#endif #ifdef CONFIG_RTW88_8723DE { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xD723, rtw8723d_hw_spec) }, #endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index d697d70170af..5e4cc57dbd7c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2,6 +2,7 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include #include "main.h" #include "coex.h" #include "fw.h" @@ -4377,3 +4378,7 @@ EXPORT_SYMBOL(rtw8822c_hw_spec); MODULE_FIRMWARE("rtw88/rtw8822c_fw.bin"); MODULE_FIRMWARE("rtw88/rtw8822c_wow_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822c driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c new file mode 100644 index 000000000000..7b6bd990651e --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include +#include +#include "rtw8822ce.h" + +static const struct pci_device_id rtw_8822ce_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC822), + .driver_data = (kernel_ulong_t)&rtw8822c_hw_spec + }, + {} +}; +MODULE_DEVICE_TABLE(pci, rtw_8822ce_id_table); + +static struct pci_driver rtw_8822ce_driver = { + .name = "rtw_8822ce", + .id_table = rtw_8822ce_id_table, + .probe = rtw_pci_probe, + .remove = rtw_pci_remove, + .driver.pm = &rtw_pm_ops, + .shutdown = rtw_pci_shutdown, +}; +module_pci_driver(rtw_8822ce_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822ce driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.h b/drivers/net/wireless/realtek/rtw88/rtw8822ce.h new file mode 100644 index 000000000000..c2c0e8675d74 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8822ce.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_8822CE_H_ +#define __RTW_8822CE_H_ + +extern const struct dev_pm_ops rtw_pm_ops; +extern struct rtw_chip_info rtw8822c_hw_spec; +int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +void rtw_pci_remove(struct pci_dev *pdev); +void rtw_pci_shutdown(struct pci_dev *pdev); + +#endif -- cgit From 416e87fcc780cae8d72cb9370fa0f46007faa69a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:24 +0800 Subject: rtw88: extract: make 8822b an individual kernel module Make objects about 8822b functions and 8822b tables, i.e. rtw8822b.o and rtw8822b_table.o, an individual kernel module called rtw88_8822b.ko. For 8822b pcie chip, i.e. 8822BE chip, add a chip entry point module called rtw88_8822be.ko which will depend on rtw88_8822b.ko and rtwpci.ko. Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-5-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/Kconfig | 6 +++++- drivers/net/wireless/realtek/rtw88/Makefile | 7 +++++- drivers/net/wireless/realtek/rtw88/main.h | 1 - drivers/net/wireless/realtek/rtw88/pci.c | 3 --- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 5 +++++ drivers/net/wireless/realtek/rtw88/rtw8822be.c | 30 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8822be.h | 14 ++++++++++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822be.c create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8822be.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index f4dbb5914bde..dd71407a06c3 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -16,14 +16,18 @@ config RTW88_CORE config RTW88_PCI tristate +config RTW88_8822B + tristate + config RTW88_8822C tristate config RTW88_8822BE - bool "Realtek 8822BE PCI wireless network adapter" + tristate "Realtek 8822BE PCI wireless network adapter" depends on PCI select RTW88_CORE select RTW88_PCI + select RTW88_8822B help Select this option will enable support for 8822BE chipset diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index e45efd2deaa3..0b29f07e3661 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -18,9 +18,14 @@ rtw88-y += main.o \ wow.o \ regd.o -rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o rtw88-$(CONFIG_RTW88_8723DE) += rtw8723d.o rtw8723d_table.o +obj-$(CONFIG_RTW88_8822B) += rtw88_8822b.o +rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o + +obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o +rtw88_8822be-objs := rtw8822be.o + obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index d6e25d4c5aed..a4c4ce511e6a 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -40,7 +40,6 @@ extern bool rtw_bf_support; extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; -extern struct rtw_chip_info rtw8822b_hw_spec; extern struct rtw_chip_info rtw8723d_hw_spec; #define RTW_MAX_CHANNEL_NUM_2G 14 diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index af9cd23a3273..39dee8368718 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1594,9 +1594,6 @@ void rtw_pci_shutdown(struct pci_dev *pdev) EXPORT_SYMBOL(rtw_pci_shutdown); static const struct pci_device_id rtw_pci_id_table[] = { -#ifdef CONFIG_RTW88_8822BE - { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822, rtw8822b_hw_spec) }, -#endif #ifdef CONFIG_RTW88_8723DE { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xD723, rtw8723d_hw_spec) }, #endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 18c5a5a96d90..e49bdd76ab9a 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2,6 +2,7 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include #include "main.h" #include "coex.h" #include "fw.h" @@ -2506,3 +2507,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { EXPORT_SYMBOL(rtw8822b_hw_spec); MODULE_FIRMWARE("rtw88/rtw8822b_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822b driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822be.c b/drivers/net/wireless/realtek/rtw88/rtw8822be.c new file mode 100644 index 000000000000..921916ae15ca --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8822be.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include +#include +#include "rtw8822be.h" + +static const struct pci_device_id rtw_8822be_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB822), + .driver_data = (kernel_ulong_t)&rtw8822b_hw_spec + }, + {} +}; +MODULE_DEVICE_TABLE(pci, rtw_8822be_id_table); + +static struct pci_driver rtw_8822be_driver = { + .name = "rtw_8822be", + .id_table = rtw_8822be_id_table, + .probe = rtw_pci_probe, + .remove = rtw_pci_remove, + .driver.pm = &rtw_pm_ops, + .shutdown = rtw_pci_shutdown, +}; +module_pci_driver(rtw_8822be_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822be driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822be.h b/drivers/net/wireless/realtek/rtw88/rtw8822be.h new file mode 100644 index 000000000000..d823ca059f5c --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8822be.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_8822BE_H_ +#define __RTW_8822BE_H_ + +extern const struct dev_pm_ops rtw_pm_ops; +extern struct rtw_chip_info rtw8822b_hw_spec; +int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +void rtw_pci_remove(struct pci_dev *pdev); +void rtw_pci_shutdown(struct pci_dev *pdev); + +#endif -- cgit From f56f08636ddac358b4e57494b569e5c2174c5fd3 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:25 +0800 Subject: rtw88: extract: make 8723d an individual kernel module Make objects about 8723d functions and 8723d tables, i.e. rtw8723d.o and rtw8723d_table.o, an individual kernel module called rtw88_8723d.ko. For 8723d pcie chip, i.e. 8723DE chip, add a chip entry point module called rtw88_8723de.ko which will depend on rtw88_8723d.ko and rtwpci.ko. Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-6-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/Kconfig | 6 +++++- drivers/net/wireless/realtek/rtw88/Makefile | 7 +++++- drivers/net/wireless/realtek/rtw88/main.h | 1 - drivers/net/wireless/realtek/rtw88/pci.c | 3 --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 5 +++++ drivers/net/wireless/realtek/rtw88/rtw8723de.c | 30 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8723de.h | 14 ++++++++++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8723de.c create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8723de.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index dd71407a06c3..ca894c4f96ac 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -22,6 +22,9 @@ config RTW88_8822B config RTW88_8822C tristate +config RTW88_8723D + tristate + config RTW88_8822BE tristate "Realtek 8822BE PCI wireless network adapter" depends on PCI @@ -45,10 +48,11 @@ config RTW88_8822CE 802.11ac PCIe wireless network adapter config RTW88_8723DE - bool "Realtek 8723DE PCI wireless network adapter" + tristate "Realtek 8723DE PCI wireless network adapter" depends on PCI select RTW88_CORE select RTW88_PCI + select RTW88_8723D help Select this option will enable support for 8723DE chipset diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 0b29f07e3661..9e3e95360089 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -18,7 +18,6 @@ rtw88-y += main.o \ wow.o \ regd.o -rtw88-$(CONFIG_RTW88_8723DE) += rtw8723d.o rtw8723d_table.o obj-$(CONFIG_RTW88_8822B) += rtw88_8822b.o rtw88_8822b-objs := rtw8822b.o rtw8822b_table.o @@ -32,5 +31,11 @@ rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o rtw88_8822ce-objs := rtw8822ce.o +obj-$(CONFIG_RTW88_8723D) += rtw88_8723d.o +rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o + +obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o +rtw88_8723de-objs := rtw8723de.o + obj-$(CONFIG_RTW88_PCI) += rtwpci.o rtwpci-objs := pci.o diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index a4c4ce511e6a..7ee09c008cd4 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -40,7 +40,6 @@ extern bool rtw_bf_support; extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; -extern struct rtw_chip_info rtw8723d_hw_spec; #define RTW_MAX_CHANNEL_NUM_2G 14 #define RTW_MAX_CHANNEL_NUM_5G 49 diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 39dee8368718..2a188bbc6d5a 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1594,9 +1594,6 @@ void rtw_pci_shutdown(struct pci_dev *pdev) EXPORT_SYMBOL(rtw_pci_shutdown); static const struct pci_device_id rtw_pci_id_table[] = { -#ifdef CONFIG_RTW88_8723DE - { RTK_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xD723, rtw8723d_hw_spec) }, -#endif {}, }; MODULE_DEVICE_TABLE(pci, rtw_pci_id_table); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index b517af417e0e..340c8c455802 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2,6 +2,7 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include #include "main.h" #include "coex.h" #include "fw.h" @@ -2740,3 +2741,7 @@ struct rtw_chip_info rtw8723d_hw_spec = { EXPORT_SYMBOL(rtw8723d_hw_spec); MODULE_FIRMWARE("rtw88/rtw8723d_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11n wireless 8723d driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723de.c b/drivers/net/wireless/realtek/rtw88/rtw8723de.c new file mode 100644 index 000000000000..c81eb4c33642 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8723de.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include +#include +#include "rtw8723de.h" + +static const struct pci_device_id rtw_8723de_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xD723), + .driver_data = (kernel_ulong_t)&rtw8723d_hw_spec + }, + {} +}; +MODULE_DEVICE_TABLE(pci, rtw_8723de_id_table); + +static struct pci_driver rtw_8723de_driver = { + .name = "rtw_8723de", + .id_table = rtw_8723de_id_table, + .probe = rtw_pci_probe, + .remove = rtw_pci_remove, + .driver.pm = &rtw_pm_ops, + .shutdown = rtw_pci_shutdown, +}; +module_pci_driver(rtw_8723de_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11n wireless 8723de driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723de.h b/drivers/net/wireless/realtek/rtw88/rtw8723de.h new file mode 100644 index 000000000000..ba3842360c20 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8723de.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_8723DE_H_ +#define __RTW_8723DE_H_ + +extern const struct dev_pm_ops rtw_pm_ops; +extern struct rtw_chip_info rtw8723d_hw_spec; +int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +void rtw_pci_remove(struct pci_dev *pdev); +void rtw_pci_shutdown(struct pci_dev *pdev); + +#endif -- cgit From 51aab89a1808660d03559c9c33267973f6796a95 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 15 May 2020 13:23:26 +0800 Subject: rtw88: extract: remove the unused after extracting remove the unused about pci after extracting chip modules Signed-off-by: Zong-Zhe Yang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-7-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/pci.c | 15 --------------- drivers/net/wireless/realtek/rtw88/pci.h | 4 ---- 2 files changed, 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 2a188bbc6d5a..8228db9a5fc8 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1593,21 +1593,6 @@ void rtw_pci_shutdown(struct pci_dev *pdev) } EXPORT_SYMBOL(rtw_pci_shutdown); -static const struct pci_device_id rtw_pci_id_table[] = { - {}, -}; -MODULE_DEVICE_TABLE(pci, rtw_pci_id_table); - -static struct pci_driver rtw_pci_driver = { - .name = "rtw_pci", - .id_table = rtw_pci_id_table, - .probe = rtw_pci_probe, - .remove = rtw_pci_remove, - .driver.pm = &rtw_pm_ops, - .shutdown = rtw_pci_shutdown, -}; -module_pci_driver(rtw_pci_driver); - MODULE_AUTHOR("Realtek Corporation"); MODULE_DESCRIPTION("Realtek 802.11ac wireless PCI driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 3ac4fb328d31..024c2bc275cb 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -5,10 +5,6 @@ #ifndef __RTK_PCI_H_ #define __RTK_PCI_H_ -#define RTK_PCI_DEVICE(vend, dev, hw_config) \ - PCI_DEVICE(vend, dev), \ - .driver_data = (kernel_ulong_t)&(hw_config), - #define RTK_DEFAULT_TX_DESC_NUM 128 #define RTK_BEQ_TX_DESC_NUM 256 -- cgit From 6b684282afcc0cdb6828a8d92566089f6529d49c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 15 May 2020 13:23:27 +0800 Subject: rtw88: rename rtw88.ko/rtwpci.ko to rtw88_core.ko/rtw88_pci.ko Rename the name of the kernel module for rtw88's core and pci. Add proper prefix 'rtw88_' to easily recognize them, also can avoid confusion with other drivers. (ex. r8822be in staging) Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515052327.31874-8-yhchuang@realtek.com --- drivers/net/wireless/realtek/rtw88/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 9e3e95360089..f31e78a6f146 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -obj-$(CONFIG_RTW88_CORE) += rtw88.o -rtw88-y += main.o \ +obj-$(CONFIG_RTW88_CORE) += rtw88_core.o +rtw88_core-y += main.o \ mac80211.o \ util.o \ debug.o \ @@ -37,5 +37,5 @@ rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o rtw88_8723de-objs := rtw8723de.o -obj-$(CONFIG_RTW88_PCI) += rtwpci.o -rtwpci-objs := pci.o +obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o +rtw88_pci-objs := pci.o -- cgit From c5457559b626a10028ebf05419ac4d430cf2945a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 14 May 2020 19:13:29 +0100 Subject: rtw88: 8723d: fix incorrect setting of ldo_pwr Currently ldo_pwr has the LDO25 voltage bits set to zero and then it is overwritten with the new voltage setting. The assignment looks incorrect, it should be bit-wise or'ing in the new voltage setting rather than a direct assignment. Addresses-Coverity: ("Unused value") Fixes: 1afb5eb7a00d ("rtw88: 8723d: Add cfg_ldo25 to control LDO25") Signed-off-by: Colin Ian King Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200514181329.16292-1-colin.king@canonical.com --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 340c8c455802..7422baf2d41b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -562,7 +562,7 @@ static void rtw8723d_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) ldo_pwr = rtw_read8(rtwdev, REG_LDO_EFUSE_CTRL + 3); if (enable) { ldo_pwr &= ~BIT_MASK_LDO25_VOLTAGE; - ldo_pwr = (BIT_LDO25_VOLTAGE_V25 << 4) | BIT_LDO25_EN; + ldo_pwr |= (BIT_LDO25_VOLTAGE_V25 << 4) | BIT_LDO25_EN; } else { ldo_pwr &= ~BIT_LDO25_EN; } -- cgit From 07d0f5534935e2daf63a4e1012af13d68e089fed Mon Sep 17 00:00:00 2001 From: Kevin Lo Date: Fri, 15 May 2020 14:11:53 +0800 Subject: rtw88: no need to set registers for SDIO There's no need to set SDIO related registers when powering up/down the chip. Signed-off-by: Kevin Lo Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515061153.GA15714@ns.kevlo.org --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 40 ----------- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 95 --------------------------- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 20 ------ 3 files changed, 155 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 7422baf2d41b..8641ea645c4b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -2093,16 +2093,6 @@ static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8723d[] = { RTW_PWR_INTF_ALL_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), 0}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, {0x004A, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK, @@ -2113,11 +2103,6 @@ static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8723d[] = { RTW_PWR_INTF_ALL_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, - {0x0023, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(4), 0}, {0x0301, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_PCI_MSK, @@ -2325,11 +2310,6 @@ static const struct rtw_pwr_seq_cmd trans_act_to_lps_8723d[] = { RTW_PWR_INTF_ALL_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(1), 0}, - {0x0093, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, 0xFF, 0x00}, {0x0553, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -2409,11 +2389,6 @@ static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8723d[] = { }; static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8723d[] = { - {0x0007, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, 0xFF, 0x20}, {0x0005, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -2434,21 +2409,6 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8723d[] = { RTW_PWR_INTF_USB_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(0), 1}, - {0x0023, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_POLLING, BIT(1), 0}, {0xFFFF, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index e49bdd76ab9a..6abcdf4070a2 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -1551,16 +1551,6 @@ static void rtw8822b_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, } static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), 0}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, {0x004A, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK, @@ -1689,11 +1679,6 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8822b[] = { RTW_PWR_INTF_ALL_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, 0xFF, 0x0c}, - {0x0068, - RTW_PWR_CUT_C_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, {0x0029, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -1722,11 +1707,6 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8822b[] = { }; static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8822b[] = { - {0x0003, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(2), 0}, {0x0093, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -1795,11 +1775,6 @@ static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8822b[] = { }; static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = { - {0x0005, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(7), BIT(7)}, {0x0007, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -1820,46 +1795,6 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = { RTW_PWR_INTF_USB_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(0), 0}, - {0x0067, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(5), 0}, - {0x0067, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(4), 0}, - {0x004F, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(0), 0}, - {0x0067, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(1), 0}, - {0x0046, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(6), BIT(6)}, - {0x0067, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(2), 0}, - {0x0046, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(7), BIT(7)}, - {0x0062, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, {0x0081, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -1870,41 +1805,11 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = { RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_POLLING, BIT(1), 0}, {0x0090, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_PCI_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(1), 0}, - {0x0044, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, 0xFF, 0}, - {0x0040, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, 0xFF, 0x90}, - {0x0041, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, 0xFF, 0x00}, - {0x0042, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, 0xFF, 0x04}, {0xFFFF, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 5e4cc57dbd7c..fe995bb4e43e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3563,16 +3563,6 @@ static void rtw8822c_pwr_track(struct rtw_dev *rtwdev) } static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = { - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), 0}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, {0x002E, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -3783,11 +3773,6 @@ static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8822c[] = { }; static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822c[] = { - {0x0005, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_MAC, - RTW_PWR_CMD_WRITE, BIT(7), BIT(7)}, {0x0007, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -3833,11 +3818,6 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822c[] = { RTW_PWR_INTF_PCI_MSK, RTW_PWR_ADDR_MAC, RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, - {0x0086, - RTW_PWR_CUT_ALL_MSK, - RTW_PWR_INTF_SDIO_MSK, - RTW_PWR_ADDR_SDIO, - RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, {0xFFFF, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, -- cgit From 3aa42bae9c4d1641aeb36f1a8585cd1d506cf471 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Fri, 15 May 2020 09:59:24 +0200 Subject: mwifiex: Fix memory corruption in dump_station MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mwifiex_cfg80211_dump_station() uses static variable for iterating over a linked list of all associated stations (when the driver is in UAP role). This has a race condition if .dump_station is called in parallel for multiple interfaces. This corruption can be triggered by registering multiple SSIDs and calling, in parallel for multiple interfaces iw dev station dump [16750.719775] Unable to handle kernel paging request at virtual address dead000000000110 ... [16750.899173] Call trace: [16750.901696] mwifiex_cfg80211_dump_station+0x94/0x100 [mwifiex] [16750.907824] nl80211_dump_station+0xbc/0x278 [cfg80211] [16750.913160] netlink_dump+0xe8/0x320 [16750.916827] netlink_recvmsg+0x1b4/0x338 [16750.920861] ____sys_recvmsg+0x7c/0x2b0 [16750.924801] ___sys_recvmsg+0x70/0x98 [16750.928564] __sys_recvmsg+0x58/0xa0 [16750.932238] __arm64_sys_recvmsg+0x28/0x30 [16750.936453] el0_svc_common.constprop.3+0x90/0x158 [16750.941378] do_el0_svc+0x74/0x90 [16750.944784] el0_sync_handler+0x12c/0x1a8 [16750.948903] el0_sync+0x114/0x140 [16750.952312] Code: f9400003 f907f423 eb02007f 54fffd60 (b9401060) [16750.958583] ---[ end trace c8ad181c2f4b8576 ]--- This patch drops the use of the static iterator, and instead every time the function is called iterates to the idx-th position of the linked-list. It would be better to convert the code not to use linked list for associated stations storage (since the chip has a limited number of associated stations anyway - it could just be an array). Such a change may be proposed in the future. In the meantime this patch can backported into stable kernels in this simple form. Fixes: 8baca1a34d4c ("mwifiex: dump station support in uap mode") Signed-off-by: Pali Rohár Acked-by: Ganapathi Bhat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515075924.13841-1-pali@kernel.org --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 1566d2197906..12bfd653a405 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1496,7 +1496,8 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - static struct mwifiex_sta_node *node; + struct mwifiex_sta_node *node; + int i; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && priv->media_connected && idx == 0) { @@ -1506,13 +1507,10 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, mwifiex_send_cmd(priv, HOST_CMD_APCMD_STA_LIST, HostCmd_ACT_GEN_GET, 0, NULL, true); - if (node && (&node->list == &priv->sta_list)) { - node = NULL; - return -ENOENT; - } - - node = list_prepare_entry(node, &priv->sta_list, list); - list_for_each_entry_continue(node, &priv->sta_list, list) { + i = 0; + list_for_each_entry(node, &priv->sta_list, list) { + if (i++ != idx) + continue; ether_addr_copy(mac, node->mac_addr); return mwifiex_dump_station_info(priv, node, sinfo); } -- cgit From b0a4bb7693be9cca2811ac468f7f7edaf975dbcf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 May 2020 11:22:26 +0100 Subject: rtlwifi: rtl8192ee: remove redundant for-loop The for-loop seems to be redundant, the assignments for indexes 0..2 are being over-written by the last index 3 in the loop. Remove the loop and use index 3 instead. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200515102226.29819-1-colin.king@canonical.com --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index 6dba576aa81e..bb291b951f4d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -2866,14 +2866,12 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) } } - for (i = 0; i < 4; i++) { - reg_e94 = result[i][0]; - reg_e9c = result[i][1]; - reg_ea4 = result[i][2]; - reg_eb4 = result[i][4]; - reg_ebc = result[i][5]; - reg_ec4 = result[i][6]; - } + reg_e94 = result[3][0]; + reg_e9c = result[3][1]; + reg_ea4 = result[3][2]; + reg_eb4 = result[3][4]; + reg_ebc = result[3][5]; + reg_ec4 = result[3][6]; if (final_candidate != 0xff) { reg_e94 = result[final_candidate][0]; -- cgit From 472f0a240250df443ffc4f39835e829916193ca1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 22 May 2020 11:45:33 +0800 Subject: mt76: mt7915: Fix build error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In file included from ./include/linux/firmware.h:6:0, from drivers/net/wireless/mediatek/mt76/mt7915/mcu.c:4: In function ‘__mt7915_mcu_msg_send’, inlined from ‘mt7915_mcu_send_message’ at drivers/net/wireless/mediatek/mt76/mt7915/mcu.c:370:6: ./include/linux/compiler.h:396:38: error: call to ‘__compiletime_assert_545’ declared with attribute error: BUILD_BUG_ON failed: cmd == MCU_EXT_CMD_EFUSE_ACCESS && mcu_txd->set_query != MCU_Q_QUERY _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ^ ./include/linux/compiler.h:377:4: note: in definition of macro ‘__compiletime_assert’ prefix ## suffix(); \ ^~~~~~ ./include/linux/compiler.h:396:2: note: in expansion of macro ‘_compiletime_assert’ _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) ^~~~~~~~~~~~~~~~~~~ ./include/linux/build_bug.h:39:37: note: in expansion of macro ‘compiletime_assert’ #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) ^~~~~~~~~~~~~~~~~~ ./include/linux/build_bug.h:50:2: note: in expansion of macro ‘BUILD_BUG_ON_MSG’ BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) ^~~~~~~~~~~~~~~~ drivers/net/wireless/mediatek/mt76/mt7915/mcu.c:280:2: note: in expansion of macro ‘BUILD_BUG_ON’ BUILD_BUG_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && ^~~~~~~~~~~~ BUILD_BUG_ON is meaningless here, chang it to WARN_ON. Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets") Signed-off-by: YueHaibing Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20200522034533.61716-1-yuehaibing@huawei.com --- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index f00ad2b66761..99eeea42478f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -277,8 +277,8 @@ static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb, } mcu_txd->s2d_index = MCU_S2D_H2N; - BUILD_BUG_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && - mcu_txd->set_query != MCU_Q_QUERY); + WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS && + mcu_txd->set_query != MCU_Q_QUERY); exit: if (wait_seq) -- cgit