diff options
author | David S. Miller <davem@davemloft.net> | 2019-11-06 05:36:35 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-11-06 05:36:35 +0300 |
commit | a3ead21d6eec4d18b48466c7b978566bc9cab676 (patch) | |
tree | 4a4a2c7b0d11c48bc4c99e927ff232543a09c28d | |
parent | d673f56358528fca20bc140a4343a16c24ffeb97 (diff) | |
parent | 086ddf860650cfa3065d6698fae81335b1846cdb (diff) | |
download | linux-a3ead21d6eec4d18b48466c7b978566bc9cab676.tar.xz |
Merge tag 'wireless-drivers-next-2019-11-05' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for 5.5
First set of patches for 5.5. The most active driver here clearly is
rtw88, lots of patches for it. More quiet on other drivers, smaller
fixes and cleanups all over.
This pull request also has a trivial conflict, the report and example
resolution here:
https://lkml.kernel.org/r/20191031111242.50ab1eca@canb.auug.org.au
Major changes:
rtw88
* add deep power save support
* add mac80211 software tx queue (wake_tx_queue) support
* enable hardware rate control
* add TX-AMSDU support
* add NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 support
* add power tracking support
* add 802.11ac beamformee support
* add set_bitrate_mask support
* add phy_info debugfs to show Tx/Rx physical status
* add RFE type 3 support for 8822b
ath10k
* add support for hardware rfkill on devices where firmware supports it
rtl8xxxu
* add bluetooth co-existence support for single antenna
iwlwifi
* Revamp the debugging infrastructure
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
162 files changed, 8542 insertions, 2523 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt index ae661e65354e..017128394a3e 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt @@ -81,6 +81,12 @@ Optional properties: Definition: Name of external front end module used. Some valid FEM names for example: "microsemi-lx5586", "sky85703-11" and "sky85803" etc. +- qcom,snoc-host-cap-8bit-quirk: + Usage: Optional + Value type: <empty> + Definition: Quirk specifying that the firmware expects the 8bit version + of the host capability QMI request +- qcom,xo-cal-data: xo cal offset to be configured in xo trim register. Example (to supply PCI based wifi block details): diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index f4161064365c..3056f81efca4 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -233,8 +233,10 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc) switch (bus->chipinfo.id) { case BCMA_CHIP_ID_BCM4313: - /* enable 12 mA drive strenth for 4313 and set chipControl - register bit 1 */ + /* + * enable 12 mA drive strenth for 4313 and set chipControl + * register bit 1 + */ bcma_chipco_chipctl_maskset(cc, 0, ~BCMA_CCTRL_4313_12MA_LED_DRIVE, BCMA_CCTRL_4313_12MA_LED_DRIVE); @@ -246,8 +248,10 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc) break; case BCMA_CHIP_ID_BCM43224: case BCMA_CHIP_ID_BCM43421: - /* enable 12 mA drive strenth for 43224 and set chipControl - register bit 15 */ + /* + * enable 12 mA drive strenth for 43224 and set chipControl + * register bit 15 + */ if (bus->chipinfo.rev == 0) { bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL, ~BCMA_CCTRL_43224_GPIO_TOGGLE, @@ -500,8 +504,10 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) case BCMA_CHIP_ID_BCM53572: /* 5357[ab]0, 43236[ab]0, and 6362b0 */ - /* BCM5357 needs to touch PLL1_PLLCTL[02], - so offset PLL0_PLLCTL[02] by 6 */ + /* + * BCM5357 needs to touch PLL1_PLLCTL[02], + * so offset PLL0_PLLCTL[02] by 6 + */ phypll_offset = (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || bus->chipinfo.id == BCMA_CHIP_ID_BCM4749 || bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0; @@ -619,8 +625,10 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) case BCMA_CHIP_ID_BCM43228: case BCMA_CHIP_ID_BCM43428: /* LCNXN */ - /* PLL Settings for spur avoidance on/off mode, - no on2 support for 43228A0 */ + /* + * PLL Settings for spur avoidance on/off mode, + * no on2 support for 43228A0 + */ if (spuravoid == 1) { bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, 0x01100014); diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 46f1427e6e9e..ba326f6c1214 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1781,8 +1781,8 @@ static int adm8211_probe(struct pci_dev *pdev, { struct ieee80211_hw *dev; struct adm8211_priv *priv; - unsigned long mem_addr, mem_len; - unsigned int io_addr, io_len; + unsigned long mem_len; + unsigned int io_len; int err; u32 reg; u8 perm_addr[ETH_ALEN]; @@ -1794,9 +1794,7 @@ static int adm8211_probe(struct pci_dev *pdev, return err; } - io_addr = pci_resource_start(pdev, 0); io_len = pci_resource_len(pdev, 0); - mem_addr = pci_resource_start(pdev, 1); mem_len = pci_resource_len(pdev, 1); if (io_len < 256 || mem_len < 1024) { printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index b94759daeacc..da2d179430ca 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -255,7 +255,8 @@ static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, if (flags & AR5523_CMD_FLAG_MAGIC) hdr->magic = cpu_to_be32(1 << 24); - memcpy(hdr + 1, idata, ilen); + if (ilen) + memcpy(hdr + 1, idata, ilen); cmd->odata = odata; cmd->olen = olen; diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index eca87f7c5b6c..294fbc1e89ab 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1704,9 +1704,6 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id, /* Correctly initialize memory to 0 to prevent garbage * data crashing system when download firmware */ - memset(dest_ring->base_addr_owner_space_unaligned, 0, - nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN); - dest_ring->base_addr_owner_space = PTR_ALIGN(dest_ring->base_addr_owner_space_unaligned, CE_DESC_RING_ALIGN); @@ -2019,8 +2016,6 @@ void ath10k_ce_alloc_rri(struct ath10k *ar) value |= ar->hw_ce_regs->upd->mask; ath10k_ce_write32(ar, ce_base_addr + ctrl1_regs, value); } - - memset(ce->vaddr_rri, 0, CE_COUNT * sizeof(u32)); } EXPORT_SYMBOL(ath10k_ce_alloc_rri); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 383d4fa555a8..36c62d66c19e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -677,13 +677,22 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) complete(&ar->target_suspend); } -static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) +static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) { + int ret; u32 param = 0; - ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); - ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); - ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); + if (ret) + return ret; + + ret = ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); + if (ret) + return ret; + + ret = ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + if (ret) + return ret; /* Data transfer is not initiated, when reduced Tx completion * is used for SDIO. disable it until fixed @@ -700,14 +709,23 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) else param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET; - ath10k_bmi_write32(ar, hi_acs_flags, param); + ret = ath10k_bmi_write32(ar, hi_acs_flags, param); + if (ret) + return ret; /* Explicitly set fwlog prints to zero as target may turn it on * based on scratch registers. */ - ath10k_bmi_read32(ar, hi_option_flag, ¶m); + ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m); + if (ret) + return ret; + param |= HI_OPTION_DISABLE_DBGLOG; - ath10k_bmi_write32(ar, hi_option_flag, param); + ret = ath10k_bmi_write32(ar, hi_option_flag, param); + if (ret) + return ret; + + return 0; } static int ath10k_init_configure_target(struct ath10k *ar) @@ -2565,8 +2583,13 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err; - if (ar->hif.bus == ATH10K_BUS_SDIO) - ath10k_init_sdio(ar, mode); + if (ar->hif.bus == ATH10K_BUS_SDIO) { + status = ath10k_init_sdio(ar, mode); + if (status) { + ath10k_err(ar, "failed to init SDIO: %d\n", status); + goto err; + } + } } ar->htc.htc_ops.target_send_suspend_complete = @@ -2787,7 +2810,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, status = ath10k_hif_set_target_log_mode(ar, fw_diag_log); if (status && status != -EOPNOTSUPP) { - ath10k_warn(ar, "set traget log mode faileds: %d\n", status); + ath10k_warn(ar, "set target log mode failed: %d\n", status); goto err_hif_stop; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4d7db07db6ba..af68eb5d0776 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -169,6 +169,7 @@ struct ath10k_wmi { struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; + struct wmi_peer_param_map *peer_param; const struct wmi_ops *ops; const struct wmi_peer_flags_map *peer_flags; @@ -963,12 +964,20 @@ struct ath10k { u32 hw_eeprom_rd; u32 ht_cap_info; u32 vht_cap_info; + u32 vht_supp_mcs; u32 num_rf_chains; u32 max_spatial_stream; /* protected by conf_mutex */ + u32 low_2ghz_chan; + u32 high_2ghz_chan; u32 low_5ghz_chan; u32 high_5ghz_chan; bool ani_enabled; + u32 sys_cap_info; + + /* protected by data_lock */ + bool hw_rfkill_on; + /* protected by conf_mutex */ u8 ps_state_enable; diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index b6d2932383cf..2a4498067024 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -703,7 +703,7 @@ static const struct ath10k_mem_region qca99x0_hw20_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { @@ -786,7 +786,7 @@ static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { @@ -891,7 +891,7 @@ static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { @@ -951,6 +951,19 @@ static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = { }, }; +static const struct ath10k_mem_region wcn399x_hw10_mem_regions[] = { + { + /* MSA region start is not fixed, hence it is assigned at runtime */ + .type = ATH10K_MEM_REGION_TYPE_MSA, + .len = 0x100000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, @@ -1048,6 +1061,14 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca4019_hw10_mem_regions), }, }, + { + .hw_id = WCN3990_HW_1_0_DEV_VERSION, + .hw_rev = ATH10K_HW_WCN3990, + .region_table = { + .regions = wcn399x_hw10_mem_regions, + .size = ARRAY_SIZE(wcn399x_hw10_mem_regions), + }, + }, }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) @@ -1208,9 +1229,11 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA); dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len); - memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf, - crash_data->ramdump_buf_len); - sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + if (crash_data->ramdump_buf_len) { + memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf, + crash_data->ramdump_buf_len); + sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + } } mutex_unlock(&ar->dump_mutex); @@ -1257,6 +1280,9 @@ int ath10k_coredump_register(struct ath10k *ar) if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) { crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar); + if (!crash_data->ramdump_buf_len) + return 0; + crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len); if (!crash_data->ramdump_buf) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 09de41922f97..8bf03e8c1d3a 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -115,6 +115,7 @@ enum ath10k_mem_region_type { ATH10K_MEM_REGION_TYPE_IRAM2 = 5, ATH10K_MEM_REGION_TYPE_IOSRAM = 6, ATH10K_MEM_REGION_TYPE_IOREG = 7, + ATH10K_MEM_REGION_TYPE_MSA = 8, }; /* Define a section of the region which should be copied. As not all parts diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 42931a669b02..367539f2c370 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -430,7 +430,7 @@ ath10k_dbg_sta_write_peer_debug_trigger(struct file *file, } ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr, - WMI_PEER_DEBUG, peer_debug_trigger); + ar->wmi.peer_param->debug, peer_debug_trigger); if (ret) { ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 53f1095de8ff..9f0e7b4943ec 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2726,7 +2726,7 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); - if (!peer) { + if (!peer || !peer->sta) { spin_unlock_bh(&ar->data_lock); rcu_read_unlock(); continue; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index c415e971735b..55849173e55d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -155,6 +155,9 @@ const struct ath10k_hw_values qca6174_values = { .num_target_ce_config_wlan = 7, .ce_desc_meta_data_mask = 0xFFFC, .ce_desc_meta_data_lsb = 2, + .rfkill_pin = 16, + .rfkill_cfg = 0, + .rfkill_on_level = 1, }; const struct ath10k_hw_values qca99x0_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 2ae57c1de7b5..35a362329a4f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -379,6 +379,9 @@ struct ath10k_hw_values { u8 num_target_ce_config_wlan; u16 ce_desc_meta_data_mask; u8 ce_desc_meta_data_lsb; + u32 rfkill_pin; + u32 rfkill_cfg; + bool rfkill_on_level; }; extern const struct ath10k_hw_values qca988x_values; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a6d21856b7e7..3d2c8fcba952 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -12,6 +12,7 @@ #include <linux/etherdevice.h> #include <linux/acpi.h> #include <linux/of.h> +#include <linux/bitfield.h> #include "hif.h" #include "core.h" @@ -2773,7 +2774,7 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, return -EINVAL; return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, - WMI_PEER_SMPS_STATE, + ar->wmi.peer_param->smps_state, ath10k_smps_map[smps]); } @@ -2930,7 +2931,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, * poked with peer param command. */ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, - WMI_PEER_DUMMY_VAR, 1); + ar->wmi.peer_param->dummy_var, 1); if (ret) { ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n", arvif->bssid, arvif->vdev_id, ret); @@ -3708,7 +3709,7 @@ static int ath10k_mac_tx(struct ath10k *ar, struct ieee80211_vif *vif, enum ath10k_hw_txrx_mode txmode, enum ath10k_mac_tx_path txpath, - struct sk_buff *skb) + struct sk_buff *skb, bool noque_offchan) { struct ieee80211_hw *hw = ar->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -3738,10 +3739,10 @@ static int ath10k_mac_tx(struct ath10k *ar, } } - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { + if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { if (!ath10k_mac_tx_frm_has_freq(ar)) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n", + skb, skb->len); skb_queue_tail(&ar->offchan_tx_queue, skb); ieee80211_queue_work(hw, &ar->offchan_tx_work); @@ -3803,8 +3804,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) mutex_lock(&ar->conf_mutex); - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n", + skb, skb->len); hdr = (struct ieee80211_hdr *)skb->data; peer_addr = ieee80211_get_DA(hdr); @@ -3850,7 +3851,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true); if (ret) { ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", ret); @@ -3860,8 +3861,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) time_left = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); if (time_left == 0) - ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n", - skb); + ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n", + skb, skb->len); if (!peer && tmp_peer_created) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); @@ -4065,7 +4066,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, if (ret) return ret; - skb = ieee80211_tx_dequeue(hw, txq); + skb = ieee80211_tx_dequeue_ni(hw, txq); if (!skb) { spin_lock_bh(&ar->htt.tx_lock); ath10k_htt_tx_dec_pending(htt); @@ -4097,7 +4098,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (unlikely(ret)) { ath10k_warn(ar, "failed to push frame: %d\n", ret); @@ -4378,7 +4379,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (ret) { ath10k_warn(ar, "failed to transmit frame: %d\n", ret); if (is_htt) { @@ -4754,6 +4755,63 @@ static int __ath10k_fetch_bb_timing_dt(struct ath10k *ar, return 0; } +static int ath10k_mac_rfkill_config(struct ath10k *ar) +{ + u32 param; + int ret; + + if (ar->hw_values->rfkill_pin == 0) { + ath10k_warn(ar, "ath10k does not support hardware rfkill with this device\n"); + return -EOPNOTSUPP; + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", + ar->hw_values->rfkill_pin, ar->hw_values->rfkill_cfg, + ar->hw_values->rfkill_on_level); + + param = FIELD_PREP(WMI_TLV_RFKILL_CFG_RADIO_LEVEL, + ar->hw_values->rfkill_on_level) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM, + ar->hw_values->rfkill_pin) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_PIN_AS_GPIO, + ar->hw_values->rfkill_cfg); + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->rfkill_config, + param); + if (ret) { + ath10k_warn(ar, + "failed to set rfkill config 0x%x: %d\n", + param, ret); + return ret; + } + return 0; +} + +int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable) +{ + enum wmi_tlv_rfkill_enable_radio param; + int ret; + + if (enable) + param = WMI_TLV_RFKILL_ENABLE_RADIO_ON; + else + param = WMI_TLV_RFKILL_ENABLE_RADIO_OFF; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac rfkill enable %d", param); + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rfkill_enable, + param); + if (ret) { + ath10k_warn(ar, "failed to set rfkill enable param %d: %d\n", + param, ret); + return ret; + } + + return 0; +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -4788,6 +4846,16 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err; } + spin_lock_bh(&ar->data_lock); + + if (ar->hw_rfkill_on) { + ar->hw_rfkill_on = false; + spin_unlock_bh(&ar->data_lock); + goto err; + } + + spin_unlock_bh(&ar->data_lock); + ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "Could not init hif: %d\n", ret); @@ -4801,6 +4869,14 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_power_down; } + if (ar->sys_cap_info & WMI_TLV_SYS_CAP_INFO_RFKILL) { + ret = ath10k_mac_rfkill_config(ar); + if (ret && ret != -EOPNOTSUPP) { + ath10k_warn(ar, "failed to configure rfkill: %d", ret); + goto err_core_stop; + } + } + param = ar->wmi.pdev_param->pmf_qos; ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { @@ -4960,7 +5036,8 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); if (ar->state != ATH10K_STATE_OFF) { - ath10k_halt(ar); + if (!ar->hw_rfkill_on) + ath10k_halt(ar); ar->state = ATH10K_STATE_OFF; } mutex_unlock(&ar->conf_mutex); @@ -5635,6 +5712,37 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static void ath10k_recalculate_mgmt_rate(struct ath10k *ar, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *def) +{ + struct ath10k_vif *arvif = (void *)vif->drv_priv; + const struct ieee80211_supported_band *sband; + u8 basic_rate_idx; + int hw_rate_code; + u32 vdev_param; + u16 bitrate; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + sband = ar->hw->wiphy->bands[def->chan->band]; + basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; + bitrate = sband->bitrates[basic_rate_idx].bitrate; + + hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); + if (hw_rate_code < 0) { + ath10k_warn(ar, "bitrate not supported %d\n", bitrate); + return; + } + + vdev_param = ar->wmi.vdev_param->mgmt_rate; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + hw_rate_code); + if (ret) + ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); +} + static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -5645,10 +5753,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct cfg80211_chan_def def; u32 vdev_param, pdev_param, slottime, preamble; u16 bitrate, hw_value; - u8 rate, basic_rate_idx, rateidx; - int ret = 0, hw_rate_code, mcast_rate; + u8 rate, rateidx; + int ret = 0, mcast_rate; enum nl80211_band band; - const struct ieee80211_supported_band *sband; mutex_lock(&ar->conf_mutex); @@ -5872,29 +5979,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, ret); } - if (changed & BSS_CHANGED_BASIC_RATES) { - if (ath10k_mac_vif_chan(vif, &def)) { - mutex_unlock(&ar->conf_mutex); - return; - } - - sband = ar->hw->wiphy->bands[def.chan->band]; - basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; - bitrate = sband->bitrates[basic_rate_idx].bitrate; - - hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); - if (hw_rate_code < 0) { - ath10k_warn(ar, "bitrate not supported %d\n", bitrate); - mutex_unlock(&ar->conf_mutex); - return; - } - - vdev_param = ar->wmi.vdev_param->mgmt_rate; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - hw_rate_code); - if (ret) - ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); - } + if (changed & BSS_CHANGED_BASIC_RATES && + !ath10k_mac_vif_chan(arvif->vif, &def)) + ath10k_recalculate_mgmt_rate(ar, vif, &def); mutex_unlock(&ar->conf_mutex); } @@ -6239,7 +6326,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (sta && sta->tdls) ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_AUTHORIZE, 1); + ar->wmi.peer_param->authorize, 1); exit: mutex_unlock(&ar->conf_mutex); @@ -6330,7 +6417,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, bw, mode); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_PHYMODE, mode); + ar->wmi.peer_param->phymode, mode); if (err) { ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n", sta->addr, mode, err); @@ -6338,7 +6425,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) } err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_CHAN_WIDTH, bw); + ar->wmi.peer_param->chan_width, bw); if (err) ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", sta->addr, bw, err); @@ -6349,7 +6436,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, nss); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_NSS, nss); + ar->wmi.peer_param->nss, nss); if (err) ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", sta->addr, nss, err); @@ -6360,7 +6447,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_SMPS_STATE, smps); + ar->wmi.peer_param->smps_state, smps); if (err) ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", sta->addr, smps, err); @@ -6434,7 +6521,7 @@ static int ath10k_sta_set_txpwr(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_USE_FIXED_PWR, txpwr); + ar->wmi.peer_param->use_fixed_power, txpwr); if (ret) { ath10k_warn(ar, "failed to set tx power for station ret: %d\n", ret); @@ -6549,8 +6636,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); - if (!sta->tdls) + if (!sta->tdls) { + ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); + ath10k_mac_dec_num_stations(arvif, sta); + kfree(arsta->tx_stats); goto exit; + } ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, WMI_TDLS_ENABLE_ACTIVE); @@ -7419,7 +7510,7 @@ static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar, err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_PARAM_FIXED_RATE, rate); if (err) - ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n", + ath10k_warn(ar, "failed to enable STA %pM peer fixed rate: %d\n", sta->addr, err); return true; diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 1fe84948b868..98d83a26ea60 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -72,6 +72,7 @@ struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar, u8 tid); int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val); void ath10k_mac_wait_tx_complete(struct ath10k *ar); +int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable); static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a0b4d265c6eb..bb44f5a0941b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2567,35 +2567,31 @@ static void ath10k_pci_warm_reset_cpu(struct ath10k *ar) ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); } static void ath10k_pci_warm_reset_ce(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CE_RST_MASK); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CE_RST_MASK); msleep(10); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val & ~SOC_RESET_CONTROL_CE_RST_MASK); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_CE_RST_MASK); } static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_LF_TIMER_CONTROL0_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + - SOC_LF_TIMER_CONTROL0_ADDRESS, - val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); + val = ath10k_pci_soc_read32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS, + val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); } static int ath10k_pci_warm_reset(struct ath10k *ar) @@ -3490,7 +3486,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k_pci *ar_pci; enum ath10k_hw_rev hw_rev; struct ath10k_bus_params bus_params = {}; - bool pci_ps; + bool pci_ps, is_qca988x = false; int (*pci_soft_reset)(struct ath10k *ar); int (*pci_hard_reset)(struct ath10k *ar); u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr); @@ -3500,6 +3496,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; pci_ps = false; + is_qca988x = true; pci_soft_reset = ath10k_pci_warm_reset; pci_hard_reset = ath10k_pci_qca988x_chip_reset; targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; @@ -3619,25 +3616,34 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_deinit_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; + bus_params.link_can_suspend = true; + /* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that + * fall off the bus during chip_reset. These chips have the same pci + * device id as the QCA9880 BR4A or 2R4E. So that's why the check. + */ + if (is_qca988x) { + bus_params.chip_id = + ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id != 0xffffffff) { + if (!ath10k_pci_chip_is_supported(pdev->device, + bus_params.chip_id)) + goto err_unsupported; + } + } + ret = ath10k_pci_chip_reset(ar); if (ret) { ath10k_err(ar, "failed to reset chip: %d\n", ret); goto err_free_irq; } - bus_params.dev_type = ATH10K_DEV_TYPE_LL; - bus_params.link_can_suspend = true; bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (bus_params.chip_id == 0xffffffff) { - ath10k_err(ar, "failed to get chip id\n"); - goto err_free_irq; - } + if (bus_params.chip_id == 0xffffffff) + goto err_unsupported; - if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { - ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", - pdev->device, bus_params.chip_id); + if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) goto err_free_irq; - } ret = ath10k_core_register(ar, &bus_params); if (ret) { @@ -3647,6 +3653,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev, return 0; +err_unsupported: + ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", + pdev->device, bus_params.chip_id); + err_free_irq: ath10k_pci_free_irq(ar); ath10k_pci_rx_retry_sync(ar); diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 3b63b6257c43..637f83ef65f8 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -111,6 +111,7 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) struct wlfw_msa_info_resp_msg_v01 resp = {}; struct wlfw_msa_info_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + phys_addr_t max_mapped_addr; struct qmi_txn txn; int ret; int i; @@ -150,8 +151,20 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) goto out; } + max_mapped_addr = qmi->msa_pa + qmi->msa_mem_size; qmi->nr_mem_region = resp.mem_region_info_len; for (i = 0; i < resp.mem_region_info_len; i++) { + if (resp.mem_region_info[i].size > qmi->msa_mem_size || + resp.mem_region_info[i].region_addr > max_mapped_addr || + resp.mem_region_info[i].region_addr < qmi->msa_pa || + resp.mem_region_info[i].size + + resp.mem_region_info[i].region_addr > max_mapped_addr) { + ath10k_err(ar, "received out of range memory region address 0x%llx with size 0x%x, aborting\n", + resp.mem_region_info[i].region_addr, + resp.mem_region_info[i].size); + ret = -EINVAL; + goto fail_unwind; + } qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr; qmi->mem_region[i].size = resp.mem_region_info[i].size; qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag; @@ -165,6 +178,8 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n"); return 0; +fail_unwind: + memset(&qmi->mem_region[0], 0, sizeof(qmi->mem_region[0]) * i); out: return ret; } @@ -291,10 +306,16 @@ static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi) struct wlfw_cal_report_resp_msg_v01 resp = {}; struct wlfw_cal_report_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int i, j = 0; int ret; + if (ar_snoc->xo_cal_supported) { + req.xo_cal_data_valid = 1; + req.xo_cal_data = ar_snoc->xo_cal_data; + } + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, &resp); if (ret < 0) @@ -581,22 +602,29 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) { struct wlfw_host_cap_resp_msg_v01 resp = {}; struct wlfw_host_cap_req_msg_v01 req = {}; + struct qmi_elem_info *req_ei; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int ret; req.daemon_support_valid = 1; req.daemon_support = 0; - ret = qmi_txn_init(&qmi->qmi_hdl, &txn, - wlfw_host_cap_resp_msg_v01_ei, &resp); + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei, + &resp); if (ret < 0) goto out; + if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags)) + req_ei = wlfw_host_cap_8bit_req_msg_v01_ei; + else + req_ei = wlfw_host_cap_req_msg_v01_ei; + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, QMI_WLFW_HOST_CAP_REQ_V01, WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, - wlfw_host_cap_req_msg_v01_ei, &req); + req_ei, &req); if (ret < 0) { qmi_txn_cancel(&txn); ath10k_err(ar, "failed to send host capability request: %d\n", ret); @@ -643,7 +671,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) wlfw_ini_req_msg_v01_ei, &req); if (ret < 0) { qmi_txn_cancel(&txn); - ath10k_err(ar, "fail to send fw log reqest: %d\n", ret); + ath10k_err(ar, "failed to send fw log request: %d\n", ret); goto out; } @@ -652,7 +680,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) goto out; if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - ath10k_err(ar, "fw log request rejectedr: %d\n", + ath10k_err(ar, "fw log request rejected: %d\n", resp.resp.error); ret = -EINVAL; goto out; @@ -671,6 +699,7 @@ ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) struct wlfw_ind_register_resp_msg_v01 resp = {}; struct wlfw_ind_register_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int ret; @@ -681,6 +710,11 @@ ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) req.msa_ready_enable_valid = 1; req.msa_ready_enable = 1; + if (ar_snoc->xo_cal_supported) { + req.xo_cal_enable_valid = 1; + req.xo_cal_enable = 1; + } + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ind_register_resp_msg_v01_ei, &resp); if (ret < 0) @@ -795,9 +829,13 @@ ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi, static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi) { struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); ath10k_qmi_remove_msa_permission(qmi); ath10k_core_free_board_files(ar); + if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags)) + ath10k_snoc_fw_crashed_dump(ar); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND); ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n"); } diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 1fe05c6218c3..86fcf4e1de5f 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1988,6 +1988,28 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { {} }; +struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support), + }, + {} +}; + struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h index bca1186e1560..4d107e1364a8 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -575,6 +575,7 @@ struct wlfw_host_cap_req_msg_v01 { #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; +extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[]; struct wlfw_host_cap_resp_msg_v01 { struct qmi_response_type_v01 resp; diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 9870d2d095c8..120200a93bcc 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2086,9 +2086,6 @@ static int ath10k_sdio_probe(struct sdio_func *func, goto err_free_wq; } - /* TODO: remove this once SDIO support is fully implemented */ - ath10k_warn(ar, "WARNING: ath10k SDIO support is work-in-progress, problems may arise!\n"); - return 0; err_free_wq: diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index b491361e6ed4..cd22c8654aa9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -9,9 +9,11 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regulator/consumer.h> #include "ce.h" +#include "coredump.h" #include "debug.h" #include "hif.h" #include "htc.h" @@ -36,15 +38,15 @@ static char *const ce_name[] = { "WLAN_CE_11", }; -static struct ath10k_vreg_info vreg_cfg[] = { - {NULL, "vdd-0.8-cx-mx", 800000, 850000, 0, 0, false}, - {NULL, "vdd-1.8-xo", 1800000, 1850000, 0, 0, false}, - {NULL, "vdd-1.3-rfa", 1300000, 1350000, 0, 0, false}, - {NULL, "vdd-3.3-ch0", 3300000, 3350000, 0, 0, false}, +static const char * const ath10k_regulators[] = { + "vdd-0.8-cx-mx", + "vdd-1.8-xo", + "vdd-1.3-rfa", + "vdd-3.3-ch0", }; -static struct ath10k_clk_info clk_cfg[] = { - {NULL, "cxo_ref_clk_pin", 0, false}, +static const char * const ath10k_clocks[] = { + "cxo_ref_clk_pin", }; static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); @@ -976,8 +978,7 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar, sizeof(struct ath10k_svc_pipe_cfg); cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *) &target_service_to_ce_map_wlan; - cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) / - sizeof(struct ath10k_shadow_reg_cfg); + cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map); cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *) &target_shadow_reg_cfg_map; @@ -1257,10 +1258,29 @@ static int ath10k_snoc_resource_init(struct ath10k *ar) ar_snoc->ce_irqs[i].irq_line = res->start; } + ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data", + &ar_snoc->xo_cal_data); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret); + if (ret == 0) { + ar_snoc->xo_cal_supported = true; + ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n", + ar_snoc->xo_cal_data); + } + ret = 0; + out: return ret; } +static void ath10k_snoc_quirks_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct device *dev = &ar_snoc->dev->dev; + + if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk")) + set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags); +} + int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1337,296 +1357,102 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } -static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, - struct ath10k_vreg_info *vreg_info) -{ - struct regulator *reg; - int ret = 0; - - reg = devm_regulator_get_optional(dev, vreg_info->name); - - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - - if (ret == -EPROBE_DEFER) { - ath10k_err(ar, "EPROBE_DEFER for regulator: %s\n", - vreg_info->name); - return ret; - } - if (vreg_info->required) { - ath10k_err(ar, "Regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - return ret; - } - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "Optional regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - goto done; - } - - vreg_info->reg = reg; - -done: - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "snog vreg %s min_v %u max_v %u load_ua %u settle_delay %lu\n", - vreg_info->name, vreg_info->min_v, vreg_info->max_v, - vreg_info->load_ua, vreg_info->settle_delay); - - return 0; -} - -static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, - struct ath10k_clk_info *clk_info) -{ - struct clk *handle; - int ret = 0; - - handle = devm_clk_get(dev, clk_info->name); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - if (clk_info->required) { - ath10k_err(ar, "snoc clock %s isn't available: %d\n", - clk_info->name, ret); - return ret; - } - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc ignoring clock %s: %d\n", - clk_info->name, - ret); - return 0; - } - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s freq %u\n", - clk_info->name, clk_info->freq); - - clk_info->handle = handle; - - return ret; -} - -static int __ath10k_snoc_vreg_on(struct ath10k *ar, - struct ath10k_vreg_info *vreg_info) -{ - int ret; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n", - vreg_info->name); - - ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v, - vreg_info->max_v); - if (ret) { - ath10k_err(ar, - "failed to set regulator %s voltage-min: %d voltage-max: %d\n", - vreg_info->name, vreg_info->min_v, vreg_info->max_v); - return ret; - } - - if (vreg_info->load_ua) { - ret = regulator_set_load(vreg_info->reg, vreg_info->load_ua); - if (ret < 0) { - ath10k_err(ar, "failed to set regulator %s load: %d\n", - vreg_info->name, vreg_info->load_ua); - goto err_set_load; - } - } - - ret = regulator_enable(vreg_info->reg); - if (ret) { - ath10k_err(ar, "failed to enable regulator %s\n", - vreg_info->name); - goto err_enable; - } - - if (vreg_info->settle_delay) - udelay(vreg_info->settle_delay); - - return 0; - -err_enable: - regulator_set_load(vreg_info->reg, 0); -err_set_load: - regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); - - return ret; -} - -static int __ath10k_snoc_vreg_off(struct ath10k *ar, - struct ath10k_vreg_info *vreg_info) +static int ath10k_hw_power_on(struct ath10k *ar) { + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); int ret; - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n", - vreg_info->name); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n"); - ret = regulator_disable(vreg_info->reg); + ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs); if (ret) - ath10k_err(ar, "failed to disable regulator %s\n", - vreg_info->name); - - ret = regulator_set_load(vreg_info->reg, 0); - if (ret < 0) - ath10k_err(ar, "failed to set load %s\n", vreg_info->name); + return ret; - ret = regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); + ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks); if (ret) - ath10k_err(ar, "failed to set voltage %s\n", vreg_info->name); + goto vreg_off; return ret; -} - -static int ath10k_snoc_vreg_on(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_vreg_info *vreg_info; - int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - ret = __ath10k_snoc_vreg_on(ar, vreg_info); - if (ret) - goto err_reg_config; - } - - return 0; - -err_reg_config: - for (i = i - 1; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - __ath10k_snoc_vreg_off(ar, vreg_info); - } +vreg_off: + regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); return ret; } -static int ath10k_snoc_vreg_off(struct ath10k *ar) +static int ath10k_hw_power_off(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_vreg_info *vreg_info; - int ret = 0; - int i; - - for (i = ARRAY_SIZE(vreg_cfg) - 1; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - if (!vreg_info->reg) - continue; + ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); - ret = __ath10k_snoc_vreg_off(ar, vreg_info); - } + clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks); - return ret; + return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); } -static int ath10k_snoc_clk_init(struct ath10k *ar) +static void ath10k_msa_dump_memory(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_clk_info *clk_info; - int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being enabled\n", - clk_info->name); + const struct ath10k_hw_mem_layout *mem_layout; + const struct ath10k_mem_region *current_region; + struct ath10k_dump_ram_data_hdr *hdr; + size_t buf_len; + u8 *buf; - if (clk_info->freq) { - ret = clk_set_rate(clk_info->handle, clk_info->freq); - - if (ret) { - ath10k_err(ar, "failed to set clock %s freq %u\n", - clk_info->name, clk_info->freq); - goto err_clock_config; - } - } - - ret = clk_prepare_enable(clk_info->handle); - if (ret) { - ath10k_err(ar, "failed to enable clock %s\n", - clk_info->name); - goto err_clock_config; - } - } - - return 0; - -err_clock_config: - for (i = i - 1; i >= 0; i--) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - clk_disable_unprepare(clk_info->handle); - } + if (!crash_data && !crash_data->ramdump_buf) + return; - return ret; -} + mem_layout = ath10k_coredump_get_mem_layout(ar); + if (!mem_layout) + return; -static int ath10k_snoc_clk_deinit(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_clk_info *clk_info; - int i; + current_region = &mem_layout->region_table.regions[0]; - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - clk_info = &ar_snoc->clk[i]; + buf = crash_data->ramdump_buf; + buf_len = crash_data->ramdump_buf_len; + memset(buf, 0, buf_len); - if (!clk_info->handle) - continue; + /* Reserve space for the header. */ + hdr = (void *)buf; + buf += sizeof(*hdr); + buf_len -= sizeof(*hdr); - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being disabled\n", - clk_info->name); + hdr->region_type = cpu_to_le32(current_region->type); + hdr->start = cpu_to_le32((unsigned long)ar_snoc->qmi->msa_va); + hdr->length = cpu_to_le32(ar_snoc->qmi->msa_mem_size); - clk_disable_unprepare(clk_info->handle); + if (current_region->len < ar_snoc->qmi->msa_mem_size) { + memcpy(buf, ar_snoc->qmi->msa_va, current_region->len); + ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n", + current_region->len, ar_snoc->qmi->msa_mem_size); + } else { + memcpy(buf, ar_snoc->qmi->msa_va, ar_snoc->qmi->msa_mem_size); } - - return 0; } -static int ath10k_hw_power_on(struct ath10k *ar) +void ath10k_snoc_fw_crashed_dump(struct ath10k *ar) { - int ret; + struct ath10k_fw_crash_data *crash_data; + char guid[UUID_STRING_LEN + 1]; - ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n"); + mutex_lock(&ar->dump_mutex); - ret = ath10k_snoc_vreg_on(ar); - if (ret) - return ret; + spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; + spin_unlock_bh(&ar->data_lock); - ret = ath10k_snoc_clk_init(ar); - if (ret) - goto vreg_off; + crash_data = ath10k_coredump_new(ar); - return ret; - -vreg_off: - ath10k_snoc_vreg_off(ar); - return ret; -} - -static int ath10k_hw_power_off(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); - - ath10k_snoc_clk_deinit(ar); - - ret = ath10k_snoc_vreg_off(ar); + if (crash_data) + scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); + else + scnprintf(guid, sizeof(guid), "n/a"); - return ret; + ath10k_err(ar, "firmware crashed! (guid %s)\n", guid); + ath10k_print_driver_info(ar); + ath10k_msa_dump_memory(ar, crash_data); + mutex_unlock(&ar->dump_mutex); } static const struct of_device_id ath10k_snoc_dt_match[] = { @@ -1678,6 +1504,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar->ce_priv = &ar_snoc->ce; msa_size = drv_data->msa_size; + ath10k_snoc_quirks_init(ar); + ret = ath10k_snoc_resource_init(ar); if (ret) { ath10k_warn(ar, "failed to initialize resource: %d\n", ret); @@ -1695,20 +1523,37 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_release_resource; } - ar_snoc->vreg = vreg_cfg; - for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { - ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); - if (ret) - goto err_free_irq; + ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators); + ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs, + sizeof(*ar_snoc->vregs), GFP_KERNEL); + if (!ar_snoc->vregs) { + ret = -ENOMEM; + goto err_free_irq; } + for (i = 0; i < ar_snoc->num_vregs; i++) + ar_snoc->vregs[i].supply = ath10k_regulators[i]; - ar_snoc->clk = clk_cfg; - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); - if (ret) - goto err_free_irq; + ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs, + ar_snoc->vregs); + if (ret < 0) + goto err_free_irq; + + ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks); + ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks, + sizeof(*ar_snoc->clks), GFP_KERNEL); + if (!ar_snoc->clks) { + ret = -ENOMEM; + goto err_free_irq; } + for (i = 0; i < ar_snoc->num_clks; i++) + ar_snoc->clks[i].id = ath10k_clocks[i]; + + ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks, + ar_snoc->clks); + if (ret) + goto err_free_irq; + ret = ath10k_hw_power_on(ar); if (ret) { ath10k_err(ar, "failed to power on device: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index d62f53501fbb..c05df45a3945 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -42,29 +42,16 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; -struct ath10k_vreg_info { - struct regulator *reg; - const char *name; - u32 min_v; - u32 max_v; - u32 load_ua; - unsigned long settle_delay; - bool required; -}; - -struct ath10k_clk_info { - struct clk *handle; - const char *name; - u32 freq; - bool required; -}; - enum ath10k_snoc_flags { ATH10K_SNOC_FLAG_REGISTERED, ATH10K_SNOC_FLAG_UNREGISTERING, ATH10K_SNOC_FLAG_RECOVERY, + ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, }; +struct clk_bulk_data; +struct regulator_bulk_data; + struct ath10k_snoc { struct platform_device *dev; struct ath10k *ar; @@ -76,10 +63,14 @@ struct ath10k_snoc { struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; struct ath10k_ce ce; struct timer_list rx_post_retry; - struct ath10k_vreg_info *vreg; - struct ath10k_clk_info *clk; + struct regulator_bulk_data *vregs; + size_t num_vregs; + struct clk_bulk_data *clks; + size_t num_clks; struct ath10k_qmi *qmi; unsigned long flags; + bool xo_cal_supported; + u32 xo_cal_data; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) @@ -88,5 +79,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) } int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type); +void ath10k_snoc_fw_crashed_dump(struct ath10k *ar); #endif /* _SNOC_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index e1420f67f776..730ed22e08a0 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -435,6 +435,7 @@ static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ath10k_dbg(ar, ATH10K_DBG_USB_BULK, "usb bulk transmit failed: %d\n", ret); usb_unanchor_urb(urb); + usb_free_urb(urb); ret = -EINVAL; goto err_free_urb_to_pipe; } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 4d5d10c01064..69a1ec53df29 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -409,6 +409,49 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static void ath10k_wmi_tlv_event_rfkill_state_change(struct ath10k *ar, + struct sk_buff *skb) +{ + const struct wmi_tlv_rfkill_state_change_ev *ev; + const void **tb; + bool radio; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, + "failed to parse rfkill state change event: %d\n", + ret); + return; + } + + ev = tb[WMI_TLV_TAG_STRUCT_RFKILL_EVENT]; + if (!ev) { + kfree(tb); + return; + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "wmi tlv rfkill state change gpio %d type %d radio_state %d\n", + __le32_to_cpu(ev->gpio_pin_num), + __le32_to_cpu(ev->int_type), + __le32_to_cpu(ev->radio_state)); + + radio = (__le32_to_cpu(ev->radio_state) == WMI_TLV_RFKILL_RADIO_STATE_ON); + + spin_lock_bh(&ar->data_lock); + + if (!radio) + ar->hw_rfkill_on = true; + + spin_unlock_bh(&ar->data_lock); + + /* notify cfg80211 radio state change */ + ath10k_mac_rfkill_enable_radio(ar, radio); + wiphy_rfkill_set_hw_state(ar->hw->wiphy, !radio); +} + static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar, struct sk_buff *skb) { @@ -629,6 +672,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_TX_PAUSE_EVENTID: ath10k_wmi_tlv_event_tx_pause(ar, skb); break; + case WMI_TLV_RFKILL_STATE_CHANGE_EVENTID: + ath10k_wmi_tlv_event_rfkill_state_change(ar, skb); + break; case WMI_TLV_PDEV_TEMPERATURE_EVENTID: ath10k_wmi_tlv_event_temperature(ar, skb); break; @@ -1201,17 +1247,21 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->abi.abi_ver0; arg->sw_ver1 = ev->abi.abi_ver1; arg->fw_build = ev->fw_build_vers; arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = reg->eeprom_rd; + arg->low_2ghz_chan = reg->low_2ghz_chan; + arg->high_2ghz_chan = reg->high_2ghz_chan; arg->low_5ghz_chan = reg->low_5ghz_chan; arg->high_5ghz_chan = reg->high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; arg->service_map = svc_bmap; arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap); + arg->sys_cap_info = ev->sys_cap_info; ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), ath10k_wmi_tlv_parse_mem_reqs, arg); @@ -1649,8 +1699,9 @@ ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, static void ath10k_wmi_tlv_put_host_mem_chunks(struct ath10k *ar, void *host_mem_chunks) { - struct host_memory_chunk *chunk; + struct host_memory_chunk_tlv *chunk; struct wmi_tlv *tlv; + dma_addr_t paddr; int i; __le16 tlv_len, tlv_tag; @@ -1666,6 +1717,12 @@ ath10k_wmi_tlv_put_host_mem_chunks(struct ath10k *ar, void *host_mem_chunks) chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len); chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + if (test_bit(WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, + ar->wmi.svc_map)) { + paddr = ar->wmi.mem_chunks[i].paddr; + chunk->ptr_high = __cpu_to_le32(upper_32_bits(paddr)); + } + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi-tlv chunk %d len %d, addr 0x%llx, id 0x%x\n", i, @@ -1689,7 +1746,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) void *ptr; chunks_len = ar->wmi.num_mem_chunks * - (sizeof(struct host_memory_chunk) + sizeof(*tlv)); + (sizeof(struct host_memory_chunk_tlv) + sizeof(*tlv)); len = (sizeof(*tlv) + sizeof(*cmd)) + (sizeof(*tlv) + sizeof(*cfg)) + (sizeof(*tlv) + chunks_len); @@ -4204,6 +4261,26 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .rfkill_config = WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG, + .rfkill_enable = WMI_TLV_PDEV_PARAM_RFKILL_ENABLE, +}; + +static struct wmi_peer_param_map wmi_tlv_peer_param_map = { + .smps_state = WMI_TLV_PEER_SMPS_STATE, + .ampdu = WMI_TLV_PEER_AMPDU, + .authorize = WMI_TLV_PEER_AUTHORIZE, + .chan_width = WMI_TLV_PEER_CHAN_WIDTH, + .nss = WMI_TLV_PEER_NSS, + .use_4addr = WMI_TLV_PEER_USE_4ADDR, + .membership = WMI_TLV_PEER_MEMBERSHIP, + .user_pos = WMI_TLV_PEER_USERPOS, + .crit_proto_hint_enabled = WMI_TLV_PEER_CRIT_PROTO_HINT_ENABLED, + .tx_fail_cnt_thr = WMI_TLV_PEER_TX_FAIL_CNT_THR, + .set_hw_retry_cts2s = WMI_TLV_PEER_SET_HW_RETRY_CTS2S, + .ibss_atim_win_len = WMI_TLV_PEER_IBSS_ATIM_WINDOW_LENGTH, + .phymode = WMI_TLV_PEER_PHYMODE, + .use_fixed_power = WMI_TLV_PEER_USE_FIXED_PWR, + .dummy_var = WMI_TLV_PEER_DUMMY_VAR, }; static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { @@ -4394,6 +4471,7 @@ void ath10k_wmi_tlv_attach(struct ath10k *ar) ar->wmi.cmd = &wmi_tlv_cmd_map; ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.peer_param = &wmi_tlv_peer_param_map; ar->wmi.ops = &wmi_tlv_ops; ar->wmi.peer_flags = &wmi_tlv_peer_flags_map; } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 649b229a41e9..4972dc12991c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -7,6 +7,8 @@ #ifndef _WMI_TLV_H #define _WMI_TLV_H +#include <linux/bitops.h> + #define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1) #define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1) #define WMI_TLV_CMD_UNSUPPORTED 0 @@ -528,6 +530,24 @@ enum wmi_tlv_vdev_param { WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, }; +enum wmi_tlv_peer_param { + WMI_TLV_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ + WMI_TLV_PEER_AMPDU = 0x2, + WMI_TLV_PEER_AUTHORIZE = 0x3, + WMI_TLV_PEER_CHAN_WIDTH = 0x4, + WMI_TLV_PEER_NSS = 0x5, + WMI_TLV_PEER_USE_4ADDR = 0x6, + WMI_TLV_PEER_MEMBERSHIP = 0x7, + WMI_TLV_PEER_USERPOS = 0x8, + WMI_TLV_PEER_CRIT_PROTO_HINT_ENABLED = 0x9, + WMI_TLV_PEER_TX_FAIL_CNT_THR = 0xa, + WMI_TLV_PEER_SET_HW_RETRY_CTS2S = 0xb, + WMI_TLV_PEER_IBSS_ATIM_WINDOW_LENGTH = 0xc, + WMI_TLV_PEER_PHYMODE = 0xd, + WMI_TLV_PEER_USE_FIXED_PWR = 0xe, + WMI_TLV_PEER_DUMMY_VAR = 0xff, +}; + enum wmi_tlv_peer_flags { WMI_TLV_PEER_AUTH = 0x00000001, WMI_TLV_PEER_QOS = 0x00000002, @@ -1409,6 +1429,11 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WLAN_HPCS_PULSE = 172, WMI_TLV_SERVICE_PER_VDEV_CHAINMASK_CONFIG_SUPPORT = 173, WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI = 174, + WMI_TLV_SERVICE_NAN_DISABLE_SUPPORT = 175, + WMI_TLV_SERVICE_HTT_H2T_NO_HTC_HDR_LEN_IN_MSG_LEN = 176, + WMI_TLV_SERVICE_COEX_SUPPORT_UNEQUAL_ISOLATION = 177, + WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT = 178, + WMI_TLV_SERVICE_SUPPORT_EXTEND_ADDRESS = 179, WMI_TLV_MAX_EXT_SERVICE = 256, }; @@ -1588,6 +1613,9 @@ wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, size_t len) WMI_TLV_MAX_SERVICE); SVCMAP(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, WMI_SERVICE_TX_DATA_ACK_RSSI, WMI_TLV_MAX_SERVICE); + SVCMAP(WMI_TLV_SERVICE_SUPPORT_EXTEND_ADDRESS, + WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, + WMI_TLV_MAX_SERVICE); } #undef SVCMAP @@ -1743,6 +1771,21 @@ struct wmi_tlv_resource_config { __le32 host_capab; } __packed; +/* structure describing host memory chunk. */ +struct host_memory_chunk_tlv { + /* id of the request that is passed up in service ready */ + __le32 req_id; + + /* the physical address the memory chunk */ + __le32 ptr; + + /* size of the chunk */ + __le32 size; + + /* the upper 32 bit address valid only for more than 32 bit target */ + __le32 ptr_high; +} __packed; + struct wmi_tlv_init_cmd { struct wmi_tlv_abi_version abi; __le32 num_host_mem_chunks; @@ -2235,6 +2278,31 @@ struct wmi_tlv_tdls_peer_event { __le32 vdev_id; } __packed; +enum wmi_tlv_sys_cap_info_flags { + WMI_TLV_SYS_CAP_INFO_RXTX_LED = BIT(0), + WMI_TLV_SYS_CAP_INFO_RFKILL = BIT(1), +}; + +#define WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM GENMASK(5, 0) +#define WMI_TLV_RFKILL_CFG_RADIO_LEVEL BIT(6) +#define WMI_TLV_RFKILL_CFG_PIN_AS_GPIO GENMASK(10, 7) + +enum wmi_tlv_rfkill_enable_radio { + WMI_TLV_RFKILL_ENABLE_RADIO_ON = 0, + WMI_TLV_RFKILL_ENABLE_RADIO_OFF = 1, +}; + +enum wmi_tlv_rfkill_radio_state { + WMI_TLV_RFKILL_RADIO_STATE_OFF = 1, + WMI_TLV_RFKILL_RADIO_STATE_ON = 2, +}; + +struct wmi_tlv_rfkill_state_change_ev { + __le32 gpio_pin_num; + __le32 int_type; + __le32 radio_state; +}; + void ath10k_wmi_tlv_attach(struct ath10k *ar); enum wmi_nlo_auth_algorithm { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4f707c6394bb..74ad60a71a1f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -742,6 +742,19 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID, }; +static struct wmi_peer_param_map wmi_peer_param_map = { + .smps_state = WMI_PEER_SMPS_STATE, + .ampdu = WMI_PEER_AMPDU, + .authorize = WMI_PEER_AUTHORIZE, + .chan_width = WMI_PEER_CHAN_WIDTH, + .nss = WMI_PEER_NSS, + .use_4addr = WMI_PEER_USE_4ADDR, + .use_fixed_power = WMI_PEER_USE_FIXED_PWR, + .debug = WMI_PEER_DEBUG, + .phymode = WMI_PEER_PHYMODE, + .dummy_var = WMI_PEER_DUMMY_VAR, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -5344,11 +5357,14 @@ ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->sw_version; arg->sw_ver1 = ev->sw_version_1; arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->low_2ghz_chan = ev->hal_reg_capabilities.low_2ghz_chan; + arg->high_2ghz_chan = ev->hal_reg_capabilities.high_2ghz_chan; arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan; arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; @@ -5383,16 +5399,25 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->sw_version; arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->low_2ghz_chan = ev->hal_reg_capabilities.low_2ghz_chan; + arg->high_2ghz_chan = ev->hal_reg_capabilities.high_2ghz_chan; arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan; arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; arg->service_map = ev->wmi_service_bitmap; arg->service_map_len = sizeof(ev->wmi_service_bitmap); + /* Deliberately skipping ev->sys_cap_info as WMI and WMI-TLV have + * different values. We would need a translation to handle that, + * but as we don't currently need anything from sys_cap_info from + * WMI interface (only from WMI-TLV) safest it to skip it. + */ + n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), ARRAY_SIZE(arg->mem_reqs)); for (i = 0; i < n; i++) @@ -5432,6 +5457,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); ar->vht_cap_info = __le32_to_cpu(arg.vht_cap); + ar->vht_supp_mcs = __le32_to_cpu(arg.vht_supp_mcs); ar->fw_version_major = (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24; ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff); @@ -5441,11 +5467,16 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ar->phy_capability = __le32_to_cpu(arg.phy_capab); ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd); + ar->low_2ghz_chan = __le32_to_cpu(arg.low_2ghz_chan); + ar->high_2ghz_chan = __le32_to_cpu(arg.high_2ghz_chan); ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan); ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan); + ar->sys_cap_info = __le32_to_cpu(arg.sys_cap_info); ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", arg.service_map, arg.service_map_len); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sys_cap_info 0x%x\n", + ar->sys_cap_info); if (ar->num_rf_chains > ar->max_spatial_stream) { ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", @@ -5544,17 +5575,22 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) skip_mem_alloc: ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_mcs 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x low_2ghz_chan %d high_2ghz_chan %d low_5ghz_chan %d high_5ghz_chan %d num_mem_reqs 0x%08x\n", __le32_to_cpu(arg.min_tx_power), __le32_to_cpu(arg.max_tx_power), __le32_to_cpu(arg.ht_cap), __le32_to_cpu(arg.vht_cap), + __le32_to_cpu(arg.vht_supp_mcs), __le32_to_cpu(arg.sw_ver0), __le32_to_cpu(arg.sw_ver1), __le32_to_cpu(arg.fw_build), __le32_to_cpu(arg.phy_capab), __le32_to_cpu(arg.num_rf_chains), __le32_to_cpu(arg.eeprom_rd), + __le32_to_cpu(arg.low_2ghz_chan), + __le32_to_cpu(arg.high_2ghz_chan), + __le32_to_cpu(arg.low_5ghz_chan), + __le32_to_cpu(arg.high_5ghz_chan), __le32_to_cpu(arg.num_mem_reqs)); dev_kfree_skb(skb); @@ -5623,7 +5659,7 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + "wmi event ready sw_version 0x%08x abi_version %u mac_addr %pM status %d\n", __le32_to_cpu(arg.sw_version), __le32_to_cpu(arg.abi_version), arg.mac_addr, @@ -9332,6 +9368,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9340,6 +9377,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_2_4_ops; ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9348,6 +9386,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_2_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9356,6 +9395,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_1_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10x_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9364,6 +9404,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_ops; ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9440,7 +9481,5 @@ void ath10k_wmi_detach(struct ath10k *ar) } cancel_work_sync(&ar->svc_rdy_work); - - if (ar->svc_rdy_skb) - dev_kfree_skb(ar->svc_rdy_skb); + dev_kfree_skb(ar->svc_rdy_skb); } diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e80dbe7e8f4c..74adce1dd3a9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -202,6 +202,7 @@ enum wmi_service { WMI_SERVICE_REPORT_AIRTIME, WMI_SERVICE_SYNC_DELETE_CMDS, WMI_SERVICE_TX_PWR_PER_PEER, + WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, /* Remember to add the new value to wmi_service_name()! */ @@ -496,6 +497,7 @@ static inline char *wmi_service_name(enum wmi_service service_id) SVCSTR(WMI_SERVICE_REPORT_AIRTIME); SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS); SVCSTR(WMI_SERVICE_TX_PWR_PER_PEER); + SVCSTR(WMI_SERVICE_SUPPORT_EXTEND_ADDRESS); case WMI_SERVICE_MAX: return NULL; @@ -3786,6 +3788,8 @@ struct wmi_pdev_param_map { u32 arp_srcaddr; u32 arp_dstaddr; u32 enable_btcoex; + u32 rfkill_config; + u32 rfkill_enable; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -5071,6 +5075,25 @@ enum wmi_rate_preamble { /* Value to disable fixed rate setting */ #define WMI_FIXED_RATE_NONE (0xff) +struct wmi_peer_param_map { + u32 smps_state; + u32 ampdu; + u32 authorize; + u32 chan_width; + u32 nss; + u32 use_4addr; + u32 membership; + u32 use_fixed_power; + u32 user_pos; + u32 crit_proto_hint_enabled; + u32 tx_fail_cnt_thr; + u32 set_hw_retry_cts2s; + u32 ibss_atim_win_len; + u32 debug; + u32 phymode; + u32 dummy_var; +}; + struct wmi_vdev_param_map { u32 rts_threshold; u32 fragmentation_threshold; @@ -6842,6 +6865,7 @@ struct wmi_svc_rdy_ev_arg { __le32 max_tx_power; __le32 ht_cap; __le32 vht_cap; + __le32 vht_supp_mcs; __le32 sw_ver0; __le32 sw_ver1; __le32 fw_build; @@ -6849,8 +6873,11 @@ struct wmi_svc_rdy_ev_arg { __le32 num_rf_chains; __le32 eeprom_rd; __le32 num_mem_reqs; + __le32 low_2ghz_chan; + __le32 high_2ghz_chan; __le32 low_5ghz_chan; __le32 high_5ghz_chan; + __le32 sys_cap_info; const __le32 *service_map; size_t service_map_len; const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index d5ee32ce9eb3..43b4ae86e5fb 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -300,8 +300,7 @@ ath5k_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct ath5k_hw *ah = hw->priv; ath5k_led_off(ah); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 2382c6c46851..6885d2ded53a 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3650,7 +3650,7 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, if (wait) return -EINVAL; /* Offload for wait not supported */ - buf = kmalloc(data_len, GFP_KERNEL); + buf = kmemdup(data, data_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -3661,7 +3661,6 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, } kfree(wmi->last_mgmt_tx_frame); - memcpy(buf, data, data_len); wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; @@ -3689,7 +3688,7 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, if (wait) return -EINVAL; /* Offload for wait not supported */ - buf = kmalloc(data_len, GFP_KERNEL); + buf = kmemdup(data, data_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -3700,7 +3699,6 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, } kfree(wmi->last_mgmt_tx_frame); - memcpy(buf, data, data_len); wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2b29bf4730f6..b4885a700296 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4183,7 +4183,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah) static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) { - u32 data, ko, kg; + u32 data = 0, ko, kg; if (!AR_SREV_9462_20_OR_LATER(ah)) return; diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 159490f5a111..956fa7828d0c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -12,7 +12,6 @@ * initialize the chip when the user-space is ready to extract the init code. */ #include <linux/module.h> -#include <linux/version.h> #include <linux/completion.h> #include <linux/etherdevice.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4e8e80ac8341..9cec5c216e1f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -973,6 +973,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath_htc_rx_status *rxstatus; struct ath_rx_status rx_stats; bool decrypt_error = false; + __be16 rs_datalen; + bool is_phyerr; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -982,11 +984,24 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rxstatus = (struct ath_htc_rx_status *)skb->data; - if (be16_to_cpu(rxstatus->rs_datalen) - - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { + rs_datalen = be16_to_cpu(rxstatus->rs_datalen); + if (unlikely(rs_datalen - + (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) { ath_err(common, "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", - rxstatus->rs_datalen, skb->len); + rs_datalen, skb->len); + goto rx_next; + } + + is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY; + /* + * Discard zero-length packets and packets smaller than an ACK + * which are not PHY_ERROR (short radar pulses have a length of 3) + */ + if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) { + ath_warn(common, + "Short RX data len, dropping (dlen: %d)\n", + rs_datalen); goto rx_next; } @@ -1011,7 +1026,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, * Process PHY errors and return so that the packet * can be dropped. */ - if (rx_stats.rs_status & ATH9K_RXERR_PHY) { + if (unlikely(is_phyerr)) { /* TODO: Not using DFS processing now. */ if (ath_cmn_process_fft(&priv->spec_priv, hdr, &rx_stats, rx_status->mactime)) { diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 92b2dd396436..f3461b193c7a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -1021,13 +1021,12 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(device); struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { - dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); + dev_info(device, "WOW is enabled, bypassing PCI suspend\n"); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 18dd8b246022..f1a282364119 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -629,8 +629,7 @@ static int __maybe_unused wil6210_pm_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); wil_dbg_pm(wil, "Runtime idle\n"); @@ -644,8 +643,7 @@ static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); if (test_bit(wil_status_suspended, wil->status)) { wil_dbg_pm(wil, "trying to suspend while suspended\n"); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 153b84447e40..f9a006d58a95 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -2505,7 +2505,8 @@ int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie) cmd->mgmt_frm_type = type; /* BUG: FW API define ieLen as u8. Will fix FW */ cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len); kfree(cmd); out: @@ -2541,7 +2542,8 @@ int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie) } cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len); kfree(cmd); @@ -2715,7 +2717,7 @@ int wmi_get_all_temperatures(struct wil6210_priv *wil, return rc; if (reply.evt.status == WMI_FW_STATUS_FAILURE) { - wil_err(wil, "Failed geting TEMP_SENSE_ALL\n"); + wil_err(wil, "Failed getting TEMP_SENSE_ALL\n"); return -EINVAL; } diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c index 7afc9c5329fb..368eebefa741 100644 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ b/drivers/net/wireless/atmel/atmel_cs.c @@ -117,11 +117,9 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) static int atmel_config(struct pcmcia_device *link) { - struct local_info *dev; int ret; const struct pcmcia_device_id *did; - dev = link->priv; did = dev_get_drvdata(&link->dev); dev_dbg(&link->dev, "atmel_config\n"); diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 31bf71a80c26..9733c64bf978 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1400,7 +1400,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) /* This TX ring is full. */ unsigned int skb_mapping = skb_get_queue_mapping(skb); ieee80211_stop_queue(dev->wl->hw, skb_mapping); - dev->wl->tx_queue_stopped[skb_mapping] = 1; + dev->wl->tx_queue_stopped[skb_mapping] = true; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1566,7 +1566,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } if (dev->wl->tx_queue_stopped[ring->queue_prio]) { - dev->wl->tx_queue_stopped[ring->queue_prio] = 0; + dev->wl->tx_queue_stopped[ring->queue_prio] = false; } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index b85603e91c7a..39da1a4c30ac 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3600,7 +3600,7 @@ static void b43_tx_work(struct work_struct *work) else err = b43_dma_tx(dev, skb); if (err == -ENOSPC) { - wl->tx_queue_stopped[queue_num] = 1; + wl->tx_queue_stopped[queue_num] = true; ieee80211_stop_queue(wl->hw, queue_num); skb_queue_head(&wl->tx_queue[queue_num], skb); break; @@ -3611,7 +3611,7 @@ static void b43_tx_work(struct work_struct *work) } if (!err) - wl->tx_queue_stopped[queue_num] = 0; + wl->tx_queue_stopped[queue_num] = false; } #if B43_DEBUG @@ -5603,7 +5603,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) /* Initialize queues and flags. */ for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { skb_queue_head_init(&wl->tx_queue[queue_num]); - wl->tx_queue_stopped[queue_num] = 0; + wl->tx_queue_stopped[queue_num] = false; } snprintf(chip_name, ARRAY_SIZE(chip_name), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index fc12598b2dd3..96fd8e2bf773 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1108,7 +1108,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev) struct sdio_func *func; struct brcmf_bus *bus_if; struct brcmf_sdio_dev *sdiodev; - mmc_pm_flag_t sdio_flags; + mmc_pm_flag_t pm_caps, sdio_flags; + int ret = 0; func = container_of(dev, struct sdio_func, dev); brcmf_dbg(SDIO, "Enter: F%d\n", func->num); @@ -1119,19 +1120,33 @@ static int brcmf_ops_sdio_suspend(struct device *dev) bus_if = dev_get_drvdata(dev); sdiodev = bus_if->bus_priv.sdio; - brcmf_sdiod_freezer_on(sdiodev); - brcmf_sdio_wd_timer(sdiodev->bus, 0); + pm_caps = sdio_get_host_pm_caps(func); + + if (pm_caps & MMC_PM_KEEP_POWER) { + /* preserve card power during suspend */ + brcmf_sdiod_freezer_on(sdiodev); + brcmf_sdio_wd_timer(sdiodev->bus, 0); + + sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->wowl_enabled) { + if (sdiodev->settings->bus.sdio.oob_irq_supported) + enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); + else + sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } + + if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) + brcmf_err("Failed to set pm_flags %x\n", sdio_flags); - sdio_flags = MMC_PM_KEEP_POWER; - if (sdiodev->wowl_enabled) { - if (sdiodev->settings->bus.sdio.oob_irq_supported) - enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); - else - sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } else { + /* power will be cut so remove device, probe again in resume */ + brcmf_sdiod_intr_unregister(sdiodev); + ret = brcmf_sdiod_remove(sdiodev); + if (ret) + brcmf_err("Failed to remove device on suspend\n"); } - if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) - brcmf_err("Failed to set pm_flags %x\n", sdio_flags); - return 0; + + return ret; } static int brcmf_ops_sdio_resume(struct device *dev) @@ -1139,13 +1154,23 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct sdio_func *func = container_of(dev, struct sdio_func, dev); + mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func); + int ret = 0; brcmf_dbg(SDIO, "Enter: F%d\n", func->num); if (func->num != 2) return 0; - brcmf_sdiod_freezer_off(sdiodev); - return 0; + if (!(pm_caps & MMC_PM_KEEP_POWER)) { + /* bus was powered off and device removed, probe again */ + ret = brcmf_sdiod_probe(sdiodev); + if (ret) + brcmf_err("Failed to probe device on resume\n"); + } else { + brcmf_sdiod_freezer_off(sdiodev); + } + + return ret; } static const struct dev_pm_ops brcmf_sdio_pm_ops = { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index e3ebb7abbdae..5598bbd09b62 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1282,6 +1282,31 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) return err; } +static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, + u16 pwd_len) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, pwd_data, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; +} + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); @@ -1505,6 +1530,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) + val = WPA3_AUTH_SAE_PSK; else val = WPA_AUTH_DISABLED; brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); @@ -1537,6 +1564,10 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, val = 1; brcmf_dbg(CONN, "shared key\n"); break; + case NL80211_AUTHTYPE_SAE: + val = 3; + brcmf_dbg(CONN, "SAE authentication\n"); + break; default: val = 2; brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type); @@ -1647,6 +1678,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) u16 count; profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + profile->is_ft = false; if (!sme->crypto.n_akm_suites) return 0; @@ -1691,11 +1723,23 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) break; case WLAN_AKM_SUITE_FT_8021X: val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + profile->is_ft = true; if (sme->want_1x) profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_FT_PSK: val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + profile->is_ft = true; + break; + default: + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } else if (val & WPA3_AUTH_SAE_PSK) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_SAE: + val = WPA3_AUTH_SAE_PSK; break; default: bphy_err(drvr, "invalid cipher group (%d)\n", @@ -1773,7 +1817,8 @@ brcmf_set_sharedkey(struct net_device *ndev, brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise); - if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) + if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2 | + NL80211_WPA_VERSION_3)) return 0; if (!(sec->cipher_pairwise & @@ -1980,7 +2025,13 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - if (sme->crypto.psk) { + 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)) { err = -EINVAL; goto done; @@ -1998,12 +2049,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, } } - if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); - if (err) + else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { + /* clean up user-space RSNE */ + if (brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0)) { + bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; + } + err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, + sme->crypto.sae_pwd_len); + if (!err && sme->crypto.psk) + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); } + if (err) + goto done; /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only @@ -5359,7 +5421,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { brcmf_dbg(CONN, "Processing set ssid\n"); memcpy(vif->profile.bssid, e->addr, ETH_ALEN); - 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) return true; set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); @@ -5554,6 +5617,11 @@ done: cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); brcmf_dbg(CONN, "Report roaming result\n"); + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && profile->is_ft) { + cfg80211_port_authorized(ndev, profile->bssid, GFP_KERNEL); + brcmf_dbg(CONN, "Report port authorized\n"); + } + set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); brcmf_dbg(TRACE, "Exit\n"); return err; @@ -6664,6 +6732,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SAE_OFFLOAD); } wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 14d5bbad1db1..6ce48f6275a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -107,7 +107,8 @@ struct brcmf_cfg80211_security { enum brcmf_profile_fwsup { BRCMF_PROFILE_FWSUP_NONE, BRCMF_PROFILE_FWSUP_PSK, - BRCMF_PROFILE_FWSUP_1X + BRCMF_PROFILE_FWSUP_1X, + BRCMF_PROFILE_FWSUP_SAE }; /** @@ -122,6 +123,7 @@ struct brcmf_cfg80211_profile { struct brcmf_cfg80211_security sec; struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; enum brcmf_profile_fwsup use_fwsup; + bool is_ft; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 2c3526aeca6f..1c9c74cc958e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -39,7 +39,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { { BRCMF_FEAT_P2P, "p2p" }, { BRCMF_FEAT_MONITOR, "monitor" }, { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, - { BRCMF_FEAT_DOT11H, "802.11h" } + { BRCMF_FEAT_DOT11H, "802.11h" }, + { BRCMF_FEAT_SAE, "sae" }, }; #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 736a8179f62f..280a1f6412d4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -26,6 +26,7 @@ * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header * MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header * DOT11H: firmware supports 802.11h + * SAE: simultaneous authentication of equals */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -45,7 +46,8 @@ BRCMF_FEAT_DEF(MONITOR) \ BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \ BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \ - BRCMF_FEAT_DEF(DOT11H) + BRCMF_FEAT_DEF(DOT11H) \ + BRCMF_FEAT_DEF(SAE) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 37c512036e0e..de0ef1b545c4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -61,6 +61,8 @@ #define BRCMF_WSEC_MAX_PSK_LEN 32 #define BRCMF_WSEC_PASSPHRASE BIT(0) +#define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128 + /* primary (ie tx) key */ #define BRCMF_PRIMARY_KEY (1 << 1) #define DOT11_BSSTYPE_ANY 2 @@ -518,6 +520,17 @@ struct brcmf_wsec_pmk_le { u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; }; +/** + * struct brcmf_wsec_sae_pwd_le - firmware SAE password material. + * + * @key_len: number of octets in key materials. + * @key: SAE password material. + */ +struct brcmf_wsec_sae_pwd_le { + __le16 key_len; + u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; +}; + /* Used to get specific STA parameters */ struct brcmf_scb_val_le { __le32 val; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 6c463475e90b..3184dab41a5e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1024,8 +1024,6 @@ brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32); - memset(ring, 0, size); - return (ring); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index 14e530601ef3..fabfbb0b40b0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -57,6 +57,10 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) mutex_lock(&pi->req_lock); + /* Nothing to do if we have no requests */ + if (pi->n_reqs == 0) + goto done; + /* find request */ for (i = 0; i < pi->n_reqs; i++) { if (pi->reqs[i]->reqid == reqid) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index db783e94f929..5a6d9c86552a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -496,13 +496,11 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, * table and override CDD later */ if (li_mimo == &locale_bn) { - if (li_mimo == &locale_bn) { - maxpwr20 = QDB(16); - maxpwr40 = 0; + maxpwr20 = QDB(16); + maxpwr40 = 0; - if (chan >= 3 && chan <= 11) - maxpwr40 = QDB(16); - } + if (chan >= 3 && chan <= 11) + maxpwr40 = QDB(16); for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { txpwr->mcs_20_siso[i] = (u8) maxpwr20; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 080e829da9b3..6bb34a12a94b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -1816,8 +1816,7 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) udelay(2); brcms_b_core_phy_clk(wlc_hw, ON); - if (pih) - wlc_phy_anacore(pih, ON); + wlc_phy_anacore(pih, ON); } /* switch to and initialize new band */ diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 7b31c212694d..7552bdb91991 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -231,6 +231,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */ #define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ +#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */ + #define DOT11_DEFAULT_RTS_LEN 2347 #define DOT11_DEFAULT_FRAG_LEN 2346 diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 4fbcc7fba3cc..1168055da182 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -2301,9 +2301,7 @@ __il3945_down(struct il_priv *il) il3945_hw_txq_ctx_free(il); exit: memset(&il->card_alive, 0, sizeof(struct il_alive_resp)); - - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); + dev_kfree_skb(il->beacon_skb); il->beacon_skb = NULL; /* clear out any free frames */ @@ -3846,9 +3844,7 @@ il3945_pci_remove(struct pci_dev *pdev) il_free_channel_map(il); il_free_geos(il); kfree(il->scan_cmd); - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); - + dev_kfree_skb(il->beacon_skb); ieee80211_free_hw(il->hw); } diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 73f7bbf742bc..d966b29b45ee 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -1072,7 +1072,7 @@ EXPORT_SYMBOL(il_get_channel_info); static void il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) { - const __le32 interval[3][IL_POWER_VEC_SIZE] = { + static const __le32 interval[3][IL_POWER_VEC_SIZE] = { SLP_VEC(2, 2, 4, 6, 0xFF), SLP_VEC(2, 4, 7, 10, 10), SLP_VEC(4, 7, 10, 10, 0xFF) @@ -5182,8 +5182,7 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) memset(&il->current_ht_config, 0, sizeof(struct il_ht_config)); /* new association get rid of ibss beacon skb */ - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); + dev_kfree_skb(il->beacon_skb); il->beacon_skb = NULL; il->timestamp = 0; @@ -5302,10 +5301,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } spin_lock_irqsave(&il->lock, flags); - - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); - + dev_kfree_skb(il->beacon_skb); il->beacon_skb = skb; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index ff41987a7e35..0aae3fa4128c 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -14,7 +14,8 @@ iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o iwlwifi-objs += iwl-dbg-tlv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o -iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o +iwlwifi-objs += fw/dbg.o +iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 5e355c4957df..435cb8013a23 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -54,6 +54,7 @@ #include <linux/module.h> #include <linux/stringify.h> #include "iwl-config.h" +#include "iwl-prph.h" /* Highest firmware API version supported */ #define IWL_22000_UCODE_API_MAX 50 @@ -183,23 +184,49 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .min_umac_error_event_table = 0x400000, \ .d3_debug_data_base_addr = 0x401000, \ .d3_debug_data_length = 60 * 1024, \ - .fw_mon_smem_write_ptr_addr = 0xa0c16c, \ - .fw_mon_smem_write_ptr_msk = 0xfffff, \ - .fw_mon_smem_cycle_cnt_ptr_addr = 0xa0c174, \ - .fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + } #define IWL_DEVICE_22500 \ IWL_DEVICE_22000_COMMON, \ .trans.device_family = IWL_DEVICE_FAMILY_22000, \ .trans.base_params = &iwl_22000_base_params, \ .trans.csr = &iwl_csr_v1, \ - .gp2_reg_addr = 0xa02c68 + .gp2_reg_addr = 0xa02c68, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } #define IWL_DEVICE_22560 \ IWL_DEVICE_22000_COMMON, \ .trans.device_family = IWL_DEVICE_FAMILY_22560, \ .trans.base_params = &iwl_22560_base_params, \ - .trans.csr = &iwl_csr_v2 + .trans.csr = &iwl_csr_v2, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } #define IWL_DEVICE_AX210 \ IWL_DEVICE_22000_COMMON, \ @@ -209,7 +236,21 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .trans.csr = &iwl_csr_v1, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ - .min_256_ba_txq_size = 512 + .min_256_ba_txq_size = 512, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + } const struct iwl_cfg iwl22000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC 22000", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index e8372b67df03..e9155b9b5ee4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -55,6 +55,7 @@ #include <linux/stringify.h> #include "iwl-config.h" #include "fw/file.h" +#include "iwl-prph.h" /* Highest firmware API version supported */ #define IWL9000_UCODE_API_MAX 46 @@ -149,10 +150,26 @@ static const struct iwl_tt_params iwl9000_tt_params = { .ht_params = &iwl9000_ht_params, \ .nvm_ver = IWL9000_NVM_VERSION, \ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ - .fw_mon_smem_write_ptr_addr = 0xa0476c, \ - .fw_mon_smem_write_ptr_msk = 0xfffff, \ - .fw_mon_smem_cycle_cnt_ptr_addr = 0xa04774, \ - .fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + }, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } const struct iwl_cfg iwl9160_2ac_cfg = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 4c3219e7beb6..3643b6ba6385 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -65,6 +65,14 @@ #define __iwl_fw_api_d3_h__ /** + * enum iwl_d0i3_flags - d0i3 flags + * @IWL_D0I3_RESET_REQUIRE: FW require reset upon resume + */ +enum iwl_d0i3_flags { + IWL_D0I3_RESET_REQUIRE = BIT(0), +}; + +/** * enum iwl_d3_wakeup_flags - D3 manager wakeup flags * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert */ 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 ba586f148c14..b9d7ed93311c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -60,52 +60,10 @@ #include <linux/bitops.h> -/** - * struct iwl_fw_ini_header: Common Header for all debug group TLV's structures - * - * @tlv_version: version info - * @apply_point: &enum iwl_fw_ini_apply_point - * @data: TLV data followed - */ -struct iwl_fw_ini_header { - __le32 tlv_version; - __le32 apply_point; - u8 data[]; -} __packed; /* FW_DEBUG_TLV_HEADER_S */ - -/** - * struct iwl_fw_ini_allocation_tlv - (IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) - * buffer allocation TLV - for debug - * - * @iwl_fw_ini_header: header - * @allocation_id: &enum iwl_fw_ini_allocation_id - to bind allocation and hcmd - * if needed (DBGC1/DBGC2/SDFX/...) - * @buffer_location: type of iwl_fw_ini_buffer_location - * @size: size in bytes - * @max_fragments: the maximum allowed fragmentation in the desired memory - * allocation above - * @min_frag_size: the minimum allowed fragmentation size in bytes - */ -struct iwl_fw_ini_allocation_tlv { - struct iwl_fw_ini_header header; - __le32 allocation_id; - __le32 buffer_location; - __le32 size; - __le32 max_fragments; - __le32 min_frag_size; -} __packed; /* FW_DEBUG_TLV_BUFFER_ALLOCATION_TLV_S_VER_1 */ - -/** - * enum iwl_fw_ini_dbg_domain - debug domains - * allows to send host cmd or collect memory region if a given domain is enabled - * - * @IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON: the default domain, always on - * @IWL_FW_INI_DBG_DOMAIN_REPORT_PS: power save domain - */ -enum iwl_fw_ini_dbg_domain { - IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON = 0, - IWL_FW_INI_DBG_DOMAIN_REPORT_PS, -}; /* FW_DEBUG_TLV_DOMAIN_API_E_VER_1 */ +#define IWL_FW_INI_MAX_REGION_ID 64 +#define IWL_FW_INI_MAX_NAME 32 +#define IWL_FW_INI_MAX_CFG_NAME 64 +#define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 /** * struct iwl_fw_ini_hcmd @@ -123,279 +81,198 @@ struct iwl_fw_ini_hcmd { } __packed; /* FW_DEBUG_TLV_HCMD_DATA_API_S_VER_1 */ /** - * struct iwl_fw_ini_hcmd_tlv - (IWL_UCODE_TLV_TYPE_HCMD) - * Generic Host command pass through TLV - * - * @header: header - * @domain: send command only if the specific domain is enabled - * &enum iwl_fw_ini_dbg_domain - * @period_msec: period in which the hcmd will be sent to FW. Measured in msec - * (0 = one time command). - * @hcmd: a variable length host-command to be sent to apply the configuration. + * struct iwl_fw_ini_header - Common Header for all ini debug TLV's structures + * + * @version: TLV version + * @domain: domain of the TLV. One of &enum iwl_fw_ini_dbg_domain + * @data: TLV data */ -struct iwl_fw_ini_hcmd_tlv { - struct iwl_fw_ini_header header; +struct iwl_fw_ini_header { + __le32 version; __le32 domain; - __le32 period_msec; - struct iwl_fw_ini_hcmd hcmd; -} __packed; /* FW_DEBUG_TLV_HCMD_API_S_VER_1 */ + u8 data[]; +} __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ -#define IWL_FW_INI_MAX_REGION_ID 64 -#define IWL_FW_INI_MAX_NAME 32 +/** + * struct iwl_fw_ini_region_dev_addr - Configuration to read device addresses + * + * @size: size of each memory chunk + * @offset: offset to add to the base address of each chunk + */ +struct iwl_fw_ini_region_dev_addr { + __le32 size; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_DEVICE_ADDR_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_cfg_dhc - defines dhc response to dump. + * struct iwl_fw_ini_region_fifos - Configuration to read Tx/Rx fifos * - * @id_and_grp: id and group of dhc response. - * @desc: dhc response descriptor. + * @fid: fifos ids array. Used to determine what fifos to collect + * @hdr_only: if non zero, collect only the registers + * @offset: offset to add to the registers addresses */ -struct iwl_fw_ini_region_cfg_dhc { - __le32 id_and_grp; - __le32 desc; -} __packed; /* FW_DEBUG_TLV_REGION_DHC_API_S_VER_1 */ +struct iwl_fw_ini_region_fifos { + __le32 fid[2]; + __le32 hdr_only; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_REGION_FIFOS_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_cfg_internal - meta data of internal memory region + * struct iwl_fw_ini_region_err_table - error table region data + * + * Configuration to read Umac/Lmac error table * - * @num_of_range: the amount of ranges in the region - * @range_data_size: size of the data to read per range, in bytes. + * @version: version of the error table + * @base_addr: base address of the error table + * @size: size of the error table + * @offset: offset to add to &base_addr */ -struct iwl_fw_ini_region_cfg_internal { - __le32 num_of_ranges; - __le32 range_data_size; -} __packed; /* FW_DEBUG_TLV_REGION_NIC_INTERNAL_RANGES_S */ +struct iwl_fw_ini_region_err_table { + __le32 version; + __le32 base_addr; + __le32 size; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_REGION_ERROR_TABLE_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_cfg_fifos - meta data of fifos region - * - * @fid1: fifo id 1 - bitmap of lmac tx/rx fifos to include in the region - * @fid2: fifo id 2 - bitmap of umac rx fifos to include in the region. - * It is unused for tx. - * @num_of_registers: number of prph registers in the region, each register is - * 4 bytes size. - * @header_only: none zero value indicates that this region does not include - * fifo data and includes only the given registers. + * struct iwl_fw_ini_region_internal_buffer - internal buffer region data + * + * Configuration to read internal monitor buffer + * + * @alloc_id: allocation id one of &enum iwl_fw_ini_allocation_id + * @base_addr: internal buffer base address + * @size: size internal buffer size */ -struct iwl_fw_ini_region_cfg_fifos { - __le32 fid1; - __le32 fid2; - __le32 num_of_registers; - __le32 header_only; -} __packed; /* FW_DEBUG_TLV_REGION_FIFOS_S */ +struct iwl_fw_ini_region_internal_buffer { + __le32 alloc_id; + __le32 base_addr; + __le32 size; +} __packed; /* FW_TLV_DEBUG_REGION_INTERNAL_BUFFER_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_cfg - * - * @region_id: ID of this dump configuration - * @region_type: &enum iwl_fw_ini_region_type - * @domain: dump this region only if the specific domain is enabled - * &enum iwl_fw_ini_dbg_domain - * @name_len: name length - * @name: file name to use for this region - * @internal: used in case the region uses internal memory. - * @allocation_id: For DRAM type field substitutes for allocation_id - * @fifos: used in case of fifos region. - * @dhc_desc: dhc response descriptor. - * @notif_id_and_grp: dump this region only if the specific notification - * occurred. - * @offset: offset to use for each memory base address - * @start_addr: array of addresses. + * struct iwl_fw_ini_region_tlv - region TLV + * + * Configures parameters for region data collection + * + * @hdr: debug header + * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID + * @type: region type. One of &enum iwl_fw_ini_region_type + * @name: region name + * @dev_addr: device address configuration. Used by + * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, + * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, + * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, + * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and + * &IWL_FW_INI_REGION_RXF + * @err_table: error table configuration. Used by + * IWL_FW_INI_REGION_LMAC_ERROR_TABLE and + * IWL_FW_INI_REGION_UMAC_ERROR_TABLE + * @internal_buffer: internal monitor buffer configuration. Used by + * &IWL_FW_INI_REGION_INTERNAL_BUFFER + * @dram_alloc_id: dram allocation id. One of &enum iwl_fw_ini_allocation_id. + * Used by &IWL_FW_INI_REGION_DRAM_BUFFER + * @tlv_mask: tlv collection mask. Used by &IWL_FW_INI_REGION_TLV + * @addrs: array of addresses attached to the end of the region tlv */ -struct iwl_fw_ini_region_cfg { - __le32 region_id; - __le32 region_type; - __le32 domain; - __le32 name_len; +struct iwl_fw_ini_region_tlv { + struct iwl_fw_ini_header hdr; + __le32 id; + __le32 type; u8 name[IWL_FW_INI_MAX_NAME]; union { - struct iwl_fw_ini_region_cfg_internal internal; - __le32 allocation_id; - struct iwl_fw_ini_region_cfg_fifos fifos; - struct iwl_fw_ini_region_cfg_dhc dhc_desc; - __le32 notif_id_and_grp; - }; /* FW_DEBUG_TLV_REGION_EXT_INT_PARAMS_API_U_VER_1 */ - __le32 offset; - __le32 start_addr[]; -} __packed; /* FW_DEBUG_TLV_REGION_CONFIG_API_S_VER_1 */ + struct iwl_fw_ini_region_dev_addr dev_addr; + struct iwl_fw_ini_region_fifos fifos; + struct iwl_fw_ini_region_err_table err_table; + struct iwl_fw_ini_region_internal_buffer internal_buffer; + __le32 dram_alloc_id; + __le32 tlv_mask; + }; /* FW_TLV_DEBUG_REGION_CONF_PARAMS_API_U_VER_1 */ + __le32 addrs[]; +} __packed; /* FW_TLV_DEBUG_REGION_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_tlv - (IWL_UCODE_TLV_TYPE_REGIONS) - * defines memory regions to dump + * struct iwl_fw_ini_debug_info_tlv + * + * debug configuration name for a specific image * - * @header: header - * @num_regions: how many different region section and IDs are coming next - * @region_config: list of dump configurations + * @hdr: debug header + * @image_type: image type + * @debug_cfg_name: debug configuration name */ -struct iwl_fw_ini_region_tlv { - struct iwl_fw_ini_header header; - __le32 num_regions; - struct iwl_fw_ini_region_cfg region_config[]; -} __packed; /* FW_DEBUG_TLV_REGIONS_API_S_VER_1 */ +struct iwl_fw_ini_debug_info_tlv { + struct iwl_fw_ini_header hdr; + __le32 image_type; + u8 debug_cfg_name[IWL_FW_INI_MAX_CFG_NAME]; +} __packed; /* FW_TLV_DEBUG_INFO_API_S_VER_1 */ + +/** + * struct iwl_fw_ini_allocation_tlv - Allocates DRAM buffers + * + * @hdr: debug header + * @alloc_id: allocation id. One of &enum iwl_fw_ini_allocation_id + * @buf_location: buffer location. One of &enum iwl_fw_ini_buffer_location + * @req_size: requested buffer size + * @max_frags_num: maximum number of fragments + * @min_size: minimum buffer size + */ +struct iwl_fw_ini_allocation_tlv { + struct iwl_fw_ini_header hdr; + __le32 alloc_id; + __le32 buf_location; + __le32 req_size; + __le32 max_frags_num; + __le32 min_size; +} __packed; /* FW_TLV_DEBUG_BUFFER_ALLOCATION_API_S_VER_1 */ /** - * struct iwl_fw_ini_trigger - * - * @trigger_id: &enum iwl_fw_ini_trigger_id - * @override_trig: determines how apply trigger in case a trigger with the - * same id is already in use. Using the first 2 bytes: - * Byte 0: if 0, override trigger configuration, otherwise use the - * existing configuration. - * Byte 1: if 0, override trigger regions, otherwise append regions to - * existing trigger. + * struct iwl_fw_ini_trigger_tlv - trigger TLV + * + * Trigger that upon firing, determines what regions to collect + * + * @hdr: debug header + * @time_point: time point. One of &enum iwl_fw_ini_time_point + * @trigger_reason: trigger reason + * @apply_policy: uses &enum iwl_fw_ini_trigger_apply_policy * @dump_delay: delay from trigger fire to dump, in usec - * @occurrences: max amount of times to be fired - * @reserved: to align to FW struct + * @occurrences: max trigger fire occurrences allowed + * @reserved: unused * @ignore_consec: ignore consecutive triggers, in usec - * @force_restart: force FW restart + * @reset_fw: if non zero, will reset and reload the FW * @multi_dut: initiate debug dump data on several DUTs - * @trigger_data: generic data to be utilized per trigger - * @num_regions: number of dump regions defined for this trigger - * @data: region IDs + * @regions_mask: mask of regions to collect + * @data: trigger data */ -struct iwl_fw_ini_trigger { - __le32 trigger_id; - __le32 override_trig; +struct iwl_fw_ini_trigger_tlv { + struct iwl_fw_ini_header hdr; + __le32 time_point; + __le32 trigger_reason; + __le32 apply_policy; __le32 dump_delay; __le32 occurrences; __le32 reserved; __le32 ignore_consec; - __le32 force_restart; + __le32 reset_fw; __le32 multi_dut; - __le32 trigger_data; - __le32 num_regions; + __le64 regions_mask; __le32 data[]; -} __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_API_S_VER_1 */ - -/** - * struct iwl_fw_ini_trigger_tlv - (IWL_UCODE_TLV_TYPE_TRIGGERS) - * Triggers that hold memory regions to dump in case a trigger fires - * - * @header: header - * @num_triggers: how many different triggers section and IDs are coming next - * @trigger_config: list of trigger configurations - */ -struct iwl_fw_ini_trigger_tlv { - struct iwl_fw_ini_header header; - __le32 num_triggers; - struct iwl_fw_ini_trigger trigger_config[]; -} __packed; /* FW_TLV_DEBUG_TRIGGERS_API_S_VER_1 */ - -#define IWL_FW_INI_MAX_IMG_NAME_LEN 32 -#define IWL_FW_INI_MAX_DBG_CFG_NAME_LEN 64 +} __packed; /* FW_TLV_DEBUG_TRIGGER_API_S_VER_1 */ /** - * struct iwl_fw_ini_debug_info_tlv - (IWL_UCODE_TLV_TYPE_DEBUG_INFO) - * - * holds image name and debug configuration name + * struct iwl_fw_ini_hcmd_tlv - Generic Host command pass through TLV * - * @header: header - * @img_name_len: length of the image name string - * @img_name: image name string - * @dbg_cfg_name_len : length of the debug configuration name string - * @dbg_cfg_name: debug configuration name string - */ -struct iwl_fw_ini_debug_info_tlv { - struct iwl_fw_ini_header header; - __le32 img_name_len; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - __le32 dbg_cfg_name_len; - u8 dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; -} __packed; /* FW_DEBUG_TLV_INFO_API_S_VER_1 */ - -/** - * enum iwl_fw_ini_trigger_id - * - * @IWL_FW_TRIGGER_ID_FW_ASSERT: FW assert - * @IWL_FW_TRIGGER_ID_FW_HW_ERROR: HW assert - * @IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG: TFD queue hang - * @IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER: FW debug notification - * @IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFICATION: FW generic notification - * @IWL_FW_TRIGGER_ID_USER_TRIGGER: User trigger - * @IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER: triggers periodically - * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY: peer inactivity - * @IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED: TX latency - * threshold was crossed - * @IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED: TX failed - * @IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER: Deauth initiated by host - * @IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST: stop GO request - * @IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST: start GO request - * @IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST: join P2P group request - * @IWL_FW_TRIGGER_ID_HOST_SCAN_START: scan started event - * @IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED: undefined - * @IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS: undefined - * @IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG: undefined - * @IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED: BAR frame was received - * @IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED: agg TX failed - * @IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED: EAPOL TX failed - * @IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED: suspicious TX response - * @IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT: received suspicious auth - * @IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE: roaming was completed - * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED: fast assoc failed - * @IWL_FW_TRIGGER_ID_HOST_D3_START: D3 start - * @IWL_FW_TRIGGER_ID_HOST_D3_END: D3 end - * @IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS: missed beacon events - * @IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS: P2P missed beacon events - * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES: undefined - * @IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED: undefined - * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED: authentication / association - * failed - * @IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE: scan complete event - * @IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT: scan abort complete - * @IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE: nic alive message was received - * @IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE: CSA was completed - * @IWL_FW_TRIGGER_ID_NUM: number of trigger IDs + * @hdr: debug header + * @time_point: time point. One of &enum iwl_fw_ini_time_point + * @period_msec: interval at which the hcmd will be sent to the FW. + * Measured in msec (0 = one time command) + * @hcmd: a variable length host-command to be sent to apply the configuration */ -enum iwl_fw_ini_trigger_id { - IWL_FW_TRIGGER_ID_INVALID = 0, - - /* Errors triggers */ - IWL_FW_TRIGGER_ID_FW_ASSERT = 1, - IWL_FW_TRIGGER_ID_FW_HW_ERROR = 2, - IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG = 3, - - /* FW triggers */ - IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER = 4, - IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFICATION = 5, - - /* User trigger */ - IWL_FW_TRIGGER_ID_USER_TRIGGER = 6, - - /* periodic uses the data field for the interval time */ - IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER = 7, - - /* Host triggers */ - IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY = 8, - IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED = 9, - IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED = 10, - IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER = 11, - IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST = 12, - IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST = 13, - IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST = 14, - IWL_FW_TRIGGER_ID_HOST_SCAN_START = 15, - IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED = 16, - IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS = 17, - IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG = 18, - IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED = 19, - IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED = 20, - IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED = 21, - IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED = 22, - IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT = 23, - IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE = 24, - IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED = 25, - IWL_FW_TRIGGER_ID_HOST_D3_START = 26, - IWL_FW_TRIGGER_ID_HOST_D3_END = 27, - IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS = 28, - IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS = 29, - IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES = 30, - IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED = 31, - IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED = 32, - IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE = 33, - IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT = 34, - IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE = 35, - IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE = 36, - - IWL_FW_TRIGGER_ID_NUM, -}; /* FW_DEBUG_TLV_TRIGGER_ID_E_VER_1 */ +struct iwl_fw_ini_hcmd_tlv { + struct iwl_fw_ini_header hdr; + __le32 time_point; + __le32 period_msec; + struct iwl_fw_ini_hcmd hcmd; +} __packed; /* FW_TLV_DEBUG_HCMD_API_S_VER_1 */ /** * enum iwl_fw_ini_allocation_id @@ -404,9 +281,6 @@ enum iwl_fw_ini_trigger_id { * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration - * @IWL_FW_INI_ALLOCATION_ID_SDFX: for SDFX module - * @IWL_FW_INI_ALLOCATION_ID_FW_DUMP: used for crash and runtime dumps - * @IWL_FW_INI_ALLOCATION_ID_USER_DEFINED: for future user scenarios * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -414,9 +288,6 @@ enum iwl_fw_ini_allocation_id { IWL_FW_INI_ALLOCATION_ID_DBGC1, IWL_FW_INI_ALLOCATION_ID_DBGC2, IWL_FW_INI_ALLOCATION_ID_DBGC3, - IWL_FW_INI_ALLOCATION_ID_SDFX, - IWL_FW_INI_ALLOCATION_ID_FW_DUMP, - IWL_FW_INI_ALLOCATION_ID_USER_DEFINED, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ @@ -436,58 +307,47 @@ enum iwl_fw_ini_buffer_location { }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ /** - * enum iwl_fw_ini_debug_flow - * - * @IWL_FW_INI_DEBUG_INVALID: invalid - * @IWL_FW_INI_DEBUG_DBTR_FLOW: undefined - * @IWL_FW_INI_DEBUG_TB2DTF_FLOW: undefined - */ -enum iwl_fw_ini_debug_flow { - IWL_FW_INI_DEBUG_INVALID, - IWL_FW_INI_DEBUG_DBTR_FLOW, - IWL_FW_INI_DEBUG_TB2DTF_FLOW, -}; /* FW_DEBUG_TLV_FLOW_E_VER_1 */ - -/** * enum iwl_fw_ini_region_type * * @IWL_FW_INI_REGION_INVALID: invalid + * @IWL_FW_INI_REGION_TLV: uCode and debug TLVs + * @IWL_FW_INI_REGION_INTERNAL_BUFFER: monitor SMEM buffer + * @IWL_FW_INI_REGION_DRAM_BUFFER: monitor DRAM buffer + * @IWL_FW_INI_REGION_TXF: TX fifos + * @IWL_FW_INI_REGION_RXF: RX fifo + * @IWL_FW_INI_REGION_LMAC_ERROR_TABLE: lmac error table + * @IWL_FW_INI_REGION_UMAC_ERROR_TABLE: umac error table + * @IWL_FW_INI_REGION_RSP_OR_NOTIF: FW response or notification data * @IWL_FW_INI_REGION_DEVICE_MEMORY: device internal memory * @IWL_FW_INI_REGION_PERIPHERY_MAC: periphery registers of MAC * @IWL_FW_INI_REGION_PERIPHERY_PHY: periphery registers of PHY * @IWL_FW_INI_REGION_PERIPHERY_AUX: periphery registers of AUX - * @IWL_FW_INI_REGION_DRAM_BUFFER: DRAM buffer - * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory - * @IWL_FW_INI_REGION_INTERNAL_BUFFER: undefined - * @IWL_FW_INI_REGION_TXF: TX fifos - * @IWL_FW_INI_REGION_RXF: RX fifo * @IWL_FW_INI_REGION_PAGING: paging memory * @IWL_FW_INI_REGION_CSR: CSR registers - * @IWL_FW_INI_REGION_NOTIFICATION: FW notification data - * @IWL_FW_INI_REGION_DHC: dhc response to dump - * @IWL_FW_INI_REGION_LMAC_ERROR_TABLE: lmac error table - * @IWL_FW_INI_REGION_UMAC_ERROR_TABLE: umac error table + * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory + * @IWL_FW_INI_REGION_PCI_IOSF_CONFIG: PCI/IOSF config * @IWL_FW_INI_REGION_NUM: number of region types */ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_INVALID, + IWL_FW_INI_REGION_TLV, + IWL_FW_INI_REGION_INTERNAL_BUFFER, + IWL_FW_INI_REGION_DRAM_BUFFER, + IWL_FW_INI_REGION_TXF, + IWL_FW_INI_REGION_RXF, + IWL_FW_INI_REGION_LMAC_ERROR_TABLE, + IWL_FW_INI_REGION_UMAC_ERROR_TABLE, + IWL_FW_INI_REGION_RSP_OR_NOTIF, IWL_FW_INI_REGION_DEVICE_MEMORY, IWL_FW_INI_REGION_PERIPHERY_MAC, IWL_FW_INI_REGION_PERIPHERY_PHY, IWL_FW_INI_REGION_PERIPHERY_AUX, - IWL_FW_INI_REGION_DRAM_BUFFER, - IWL_FW_INI_REGION_DRAM_IMR, - IWL_FW_INI_REGION_INTERNAL_BUFFER, - IWL_FW_INI_REGION_TXF, - IWL_FW_INI_REGION_RXF, IWL_FW_INI_REGION_PAGING, IWL_FW_INI_REGION_CSR, - IWL_FW_INI_REGION_NOTIFICATION, - IWL_FW_INI_REGION_DHC, - IWL_FW_INI_REGION_LMAC_ERROR_TABLE, - IWL_FW_INI_REGION_UMAC_ERROR_TABLE, + IWL_FW_INI_REGION_DRAM_IMR, + IWL_FW_INI_REGION_PCI_IOSF_CONFIG, IWL_FW_INI_REGION_NUM -}; /* FW_DEBUG_TLV_REGION_TYPE_E_VER_1 */ +}; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ /** * enum iwl_fw_ini_time_point @@ -557,4 +417,22 @@ enum iwl_fw_ini_time_point { IWL_FW_INI_TIME_POINT_NUM, }; /* FW_TLV_DEBUG_TIME_POINT_API_E */ +/** + * enum iwl_fw_ini_trigger_apply_policy - Determines how to apply triggers + * + * @IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT: match by time point + * @IWL_FW_INI_APPLY_POLICY_MATCH_DATA: match by trigger data + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS: override regions mask. + * Append otherwise + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG: override trigger configuration + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA: override trigger data. + * Append otherwise + */ +enum iwl_fw_ini_trigger_apply_policy { + IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT = BIT(0), + IWL_FW_INI_APPLY_POLICY_MATCH_DATA = BIT(1), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS = BIT(8), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG = BIT(9), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA = BIT(10), +}; #endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 6b4d59daacd6..e7a1acedbcf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -78,6 +78,20 @@ enum iwl_mac_conf_subcmd_ids { */ CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4, /** + * @MISSED_VAP_NOTIF: &struct iwl_missed_vap_notif + */ + MISSED_VAP_NOTIF = 0xFA, + /** + * @SESSION_PROTECTION_CMD: &struct iwl_mvm_session_prot_cmd + */ + SESSION_PROTECTION_CMD = 0x5, + + /** + * @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif + */ + SESSION_PROTECTION_NOTIF = 0xFB, + + /** * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif */ PROBE_RESPONSE_DATA_NOTIF = 0xFC, @@ -131,6 +145,21 @@ struct iwl_probe_resp_data_notif { } __packed; /* PROBE_RESPONSE_DATA_NTFY_API_S_VER_1 */ /** + * struct iwl_missed_vap_notif - notification of missing vap detection + * + * @mac_id: the mac for which the ucode sends the notification for + * @num_beacon_intervals_elapsed: beacons elpased with no vap profile inside + * @profile_periodicity: beacons period to have our profile inside + * @reserved: reserved for alignment purposes + */ +struct iwl_missed_vap_notif { + __le32 mac_id; + u8 num_beacon_intervals_elapsed; + u8 profile_periodicity; + u8 reserved[2]; +} __packed; /* MISSED_VAP_NTFY_API_S_VER_1 */ + +/** * struct iwl_channel_switch_noa_notif - Channel switch NOA notification * * @id_and_color: ID and color of the MAC diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index a93449db7bb2..88bc7733065f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -260,6 +260,11 @@ enum iwl_rx_mpdu_amsdu_info { IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x80, }; +#define RX_MPDU_BAND_POS 6 +#define RX_MPDU_BAND_MASK 0xC0 +#define BAND_IN_RX_STATUS(_val) \ + (((_val) & RX_MPDU_BAND_MASK) >> RX_MPDU_BAND_POS) + enum iwl_rx_l3_proto_values { IWL_RX_L3_TYPE_NONE, IWL_RX_L3_TYPE_IPV4, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 4621ef93a2cf..416e817d7b4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -393,4 +393,80 @@ struct iwl_hs20_roc_res { __le32 status; } __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ +/** + * enum iwl_mvm_session_prot_conf_id - session protection's configurations + * @SESSION_PROTECT_CONF_ASSOC: Start a session protection for association. + * The firmware will allocate two events. + * Valid for BSS_STA and P2P_STA. + * * A rather short event that can't be fragmented and with a very + * high priority. If every goes well (99% of the cases) the + * association should complete within this first event. During + * that event, no other activity will happen in the firmware, + * which is why it can't be too long. + * The length of this event is hard-coded in the firmware: 300TUs. + * * Another event which can be much longer (it's duration is + * configurable by the driver) which has a slightly lower + * priority and that can be fragmented allowing other activities + * to run while this event is running. + * The firmware will automatically remove both events once the driver sets + * the BSS MAC as associated. Neither of the events will be removed + * for the P2P_STA MAC. + * Only the duration is configurable for this protection. + * @SESSION_PROTECT_CONF_GO_CLIENT_ASSOC: not used + * @SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV: Schedule the P2P Device to be in + * listen mode. Will be fragmented. Valid only on the P2P Device MAC. + * Valid only on the P2P Device MAC. The firmware will take into account + * the duration, the interval and the repetition count. + * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be be + * able to run the GO Negotiation. Will not be fragmented and not + * repetitive. Valid only on the P2P Device MAC. Only the duration will + * be taken into account. + */ +enum iwl_mvm_session_prot_conf_id { + SESSION_PROTECT_CONF_ASSOC, + SESSION_PROTECT_CONF_GO_CLIENT_ASSOC, + SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV, + SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION, +}; /* SESSION_PROTECTION_CONF_ID_E_VER_1 */ + +/** + * struct iwl_mvm_session_prot_cmd - configure a session protection + * @id_and_color: the id and color of the mac for which this session protection + * is sent + * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE + * @conf_id: see &enum iwl_mvm_session_prot_conf_id + * @duration_tu: the duration of the whole protection in TUs. + * @repetition_count: not used + * @interval: not used + * + * Note: the session protection will always be scheduled to start as + * early as possible, but the maximum delay is configuration dependent. + * The firmware supports only one concurrent session protection per vif. + * Adding a new session protection will remove any currently running session. + */ +struct iwl_mvm_session_prot_cmd { + /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ + __le32 id_and_color; + __le32 action; + __le32 conf_id; + __le32 duration_tu; + __le32 repetition_count; + __le32 interval; +} __packed; /* SESSION_PROTECTION_CMD_API_S_VER_1 */ + +/** + * struct iwl_mvm_session_prot_notif - session protection started / ended + * @mac_id: the mac id for which the session protection started / ended + * @status: 1 means success, 0 means failure + * @start: 1 means the session protection started, 0 means it ended + * + * Note that any session protection will always get two notifications: start + * and end even the firmware could not schedule it. + */ +struct iwl_mvm_session_prot_notif { + __le32 mac_id; + __le32 status; + __le32 start; +} __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_1 */ + #endif /* __iwl_fw_api_time_event_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 87421807e040..ed90dd104366 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1055,19 +1055,31 @@ out: return dump_file; } +/** + * struct iwl_dump_ini_region_data - region data + * @reg_tlv: region TLV + * @dump_data: dump data + */ +struct iwl_dump_ini_region_data { + struct iwl_ucode_tlv *reg_tlv; + struct iwl_fwrt_dump_data *dump_data; +}; + static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; u32 prph_val; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; - for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) { + range->range_data_size = reg->dev_addr.size; + for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { prph_val = iwl_read_prph(fwrt->trans, addr + i); if (prph_val == 0x5a5a5a5a) return -EBUSY; @@ -1078,39 +1090,42 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; - for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) + range->range_data_size = reg->dev_addr.size; + for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) *val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; + range->range_data_size = reg->dev_addr.size; iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(reg->internal.range_data_size)); + le32_to_cpu(reg->dev_addr.size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range_ptr, int idx) { /* increase idx by 1 since the pages are from 1 to @@ -1133,14 +1148,14 @@ static int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { struct iwl_fw_ini_error_dump_range *range; u32 page_size; if (!fwrt->trans->trans_cfg->gen2) - return _iwl_dump_ini_paging_iter(fwrt, reg, range_ptr, idx); + return _iwl_dump_ini_paging_iter(fwrt, range_ptr, idx); range = range_ptr; page_size = fwrt->trans->init_dram.paging[idx].size; @@ -1155,45 +1170,61 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, static int iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range_ptr, - int idx) + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; - u32 start_addr = iwl_read_umac_prph(fwrt->trans, - MON_BUFF_BASE_ADDR_VER2); + struct iwl_dram_data *frag; + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); - if (start_addr == 0x5a5a5a5a) - return -EBUSY; + frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx]; + + range->dram_base_addr = cpu_to_le64(frag->physical); + range->range_data_size = cpu_to_le32(frag->size); + + memcpy(range->data, frag->block, frag->size); - range->dram_base_addr = cpu_to_le64(start_addr); - range->range_data_size = cpu_to_le32(fwrt->trans->dbg.fw_mon[idx].size); + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} - memcpy(range->data, fwrt->trans->dbg.fw_mon[idx].block, - fwrt->trans->dbg.fw_mon[idx].size); +static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 addr = le32_to_cpu(reg->internal_buffer.base_addr); + + range->internal_base_addr = cpu_to_le32(addr); + range->range_data_size = reg->internal_buffer.size; + iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, + le32_to_cpu(reg->internal_buffer.size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, int idx) + struct iwl_dump_ini_region_data *reg_data, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; int txf_num = cfg->num_txfifo_entries; int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size); - u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid1); + u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid[0]); if (!idx) { - if (le32_to_cpu(reg->offset) && - WARN_ONCE(cfg->num_lmacs == 1, - "Invalid lmac offset: 0x%x\n", - le32_to_cpu(reg->offset))) + if (le32_to_cpu(reg->fifos.offset) && cfg->num_lmacs == 1) { + IWL_ERR(fwrt, "WRT: Invalid lmac offset 0x%x\n", + le32_to_cpu(reg->fifos.offset)); return false; + } iter->internal_txf = 0; iter->fifo_size = 0; iter->fifo = -1; - if (le32_to_cpu(reg->offset)) + if (le32_to_cpu(reg->fifos.offset)) iter->lmac = 1; else iter->lmac = 0; @@ -1224,27 +1255,28 @@ static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data; - u32 offs = le32_to_cpu(reg->offset), addr; - u32 registers_size = - le32_to_cpu(reg->fifos.num_of_registers) * sizeof(*reg_dump); + u32 offs = le32_to_cpu(reg->fifos.offset), addr; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); + u32 registers_size = registers_num * sizeof(*reg_dump); __le32 *data; unsigned long flags; int i; - if (!iwl_ini_txf_iter(fwrt, reg, idx)) + if (!iwl_ini_txf_iter(fwrt, reg_data, idx)) return -EIO; if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return -EBUSY; range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo); - range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers; + range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size); iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo); @@ -1253,8 +1285,8 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, * read txf registers. for each register, write to the dump the * register address and its value */ - for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { - addr = le32_to_cpu(reg->start_addr[i]) + offs; + for (i = 0; i < registers_num; i++) { + addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, @@ -1263,7 +1295,7 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, reg_dump++; } - if (reg->fifos.header_only) { + if (reg->fifos.hdr_only) { range->range_data_size = cpu_to_le32(registers_size); goto out; } @@ -1294,11 +1326,12 @@ struct iwl_ini_rxf_data { }; static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, struct iwl_ini_rxf_data *data) { - u32 fid1 = le32_to_cpu(reg->fifos.fid1); - u32 fid2 = le32_to_cpu(reg->fifos.fid2); + 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; if (!data) @@ -1330,20 +1363,21 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; struct iwl_ini_rxf_data rxf_data; struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data; - u32 offs = le32_to_cpu(reg->offset), addr; - u32 registers_size = - le32_to_cpu(reg->fifos.num_of_registers) * sizeof(*reg_dump); + u32 offs = le32_to_cpu(reg->fifos.offset), addr; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); + u32 registers_size = registers_num * sizeof(*reg_dump); __le32 *data; unsigned long flags; int i; - iwl_ini_get_rxf_data(fwrt, reg, &rxf_data); + iwl_ini_get_rxf_data(fwrt, reg_data, &rxf_data); if (!rxf_data.size) return -EIO; @@ -1351,15 +1385,15 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, return -EBUSY; range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num); - range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers; + range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(rxf_data.size + registers_size); /* * read rxf registers. for each register, write to the dump the * register address and its value */ - for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { - addr = le32_to_cpu(reg->start_addr[i]) + offs; + for (i = 0; i < registers_num; i++) { + addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, @@ -1368,7 +1402,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, reg_dump++; } - if (reg->fifos.header_only) { + if (reg->fifos.hdr_only) { range->range_data_size = cpu_to_le32(registers_size); goto out; } @@ -1399,9 +1433,50 @@ out: return sizeof(*range) + le32_to_cpu(range->range_data_size); } -static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) +static int +iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_region_err_table *err_table = ®->err_table; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 addr = le32_to_cpu(err_table->base_addr) + + le32_to_cpu(err_table->offset); + + range->internal_base_addr = cpu_to_le32(addr); + range->range_data_size = err_table->size; + iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, + le32_to_cpu(err_table->size)); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + struct iwl_rx_packet *pkt = reg_data->dump_data->fw_pkt; + u32 pkt_len; + + if (!pkt) + return -EIO; + + pkt_len = iwl_rx_packet_payload_len(pkt); + + memcpy(&range->fw_pkt_hdr, &pkt->hdr, sizeof(range->fw_pkt_hdr)); + range->range_data_size = cpu_to_le32(pkt_len); + + memcpy(range->data, pkt->data, pkt_len); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static void * +iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) { struct iwl_fw_ini_error_dump *dump = data; @@ -1410,14 +1485,45 @@ static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, return dump->ranges; } -static void -*iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - struct iwl_fw_ini_monitor_dump *data, - u32 write_ptr_addr, u32 write_ptr_msk, - u32 cycle_cnt_addr, u32 cycle_cnt_msk) +/** + * mask_apply_and_normalize - applies mask on val and normalize the result + * + * The normalization is based on the first set bit in the mask + * + * @val: value + * @mask: mask to apply and to normalize with + */ +static u32 mask_apply_and_normalize(u32 val, u32 mask) +{ + return (val & mask) >> (ffs(mask) - 1); +} + +static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id, + const struct iwl_fw_mon_reg *reg_info) +{ + u32 val, offs; + + /* The header addresses of DBGCi is calculate as follows: + * DBGC1 address + (0x100 * i) + */ + offs = (alloc_id - IWL_FW_INI_ALLOCATION_ID_DBGC1) * 0x100; + + if (!reg_info || !reg_info->addr || !reg_info->mask) + return 0; + + val = iwl_read_prph_no_grab(fwrt->trans, reg_info->addr + offs); + + return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask)); +} + +static void * +iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + struct iwl_fw_ini_monitor_dump *data, + const struct iwl_fw_mon_regs *addrs) { - u32 write_ptr, cycle_cnt; + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); unsigned long flags; if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) { @@ -1425,76 +1531,66 @@ static void return NULL; } - write_ptr = iwl_read_prph_no_grab(fwrt->trans, write_ptr_addr); - cycle_cnt = iwl_read_prph_no_grab(fwrt->trans, cycle_cnt_addr); + data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->write_ptr); + data->cycle_cnt = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->cycle_cnt); + data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->cur_frag); iwl_trans_release_nic_access(fwrt->trans, &flags); data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - data->write_ptr = cpu_to_le32(write_ptr & write_ptr_msk); - data->cycle_cnt = cpu_to_le32(cycle_cnt & cycle_cnt_msk); return data->ranges; } -static void -*iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) +static void * +iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) { struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; - u32 write_ptr_addr, write_ptr_msk, cycle_cnt_addr, cycle_cnt_msk; - - switch (fwrt->trans->trans_cfg->device_family) { - case IWL_DEVICE_FAMILY_9000: - case IWL_DEVICE_FAMILY_22000: - write_ptr_addr = MON_BUFF_WRPTR_VER2; - write_ptr_msk = -1; - cycle_cnt_addr = MON_BUFF_CYCLE_CNT_VER2; - cycle_cnt_msk = -1; - break; - default: - IWL_ERR(fwrt, "Unsupported device family %d\n", - fwrt->trans->trans_cfg->device_family); - return NULL; - } - return iwl_dump_ini_mon_fill_header(fwrt, reg, mon_dump, write_ptr_addr, - write_ptr_msk, cycle_cnt_addr, - cycle_cnt_msk); + return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + &fwrt->trans->cfg->mon_dram_regs); } -static void -*iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) +static void * +iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) { struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; - const struct iwl_cfg *cfg = fwrt->trans->cfg; - if (fwrt->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_9000 && - fwrt->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22000) { - IWL_ERR(fwrt, "Unsupported device family %d\n", - fwrt->trans->trans_cfg->device_family); - return NULL; - } + return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + &fwrt->trans->cfg->mon_smem_regs); +} - return iwl_dump_ini_mon_fill_header(fwrt, reg, mon_dump, - cfg->fw_mon_smem_write_ptr_addr, - cfg->fw_mon_smem_write_ptr_msk, - cfg->fw_mon_smem_cycle_cnt_ptr_addr, - cfg->fw_mon_smem_cycle_cnt_ptr_msk); +static void * +iwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_err_table_dump *dump = data; + dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); + dump->version = reg->err_table.version; + + return dump->ranges; } static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { - return le32_to_cpu(reg->internal.num_of_ranges); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + + return iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); } static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { if (fwrt->trans->trans_cfg->gen2) return fwrt->trans->init_dram.paging_cnt; @@ -1502,54 +1598,73 @@ static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, return fwrt->num_of_paging_blk; } -static u32 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 +iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { - return 1; + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_mon *fw_mon; + u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); + int i; + + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + if (!fw_mon->frags[i].size) + break; + + ranges++; + } + + return ranges; } static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { u32 num_of_fifos = 0; - while (iwl_ini_txf_iter(fwrt, reg, num_of_fifos)) + while (iwl_ini_txf_iter(fwrt, reg_data, num_of_fifos)) num_of_fifos++; return num_of_fifos; } -static u32 iwl_dump_ini_rxf_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 iwl_dump_ini_single_range(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { - /* Each Rx fifo needs a different offset and therefore, it's - * region can contain only one fifo, i.e. 1 memory range. - */ return 1; } static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { - return sizeof(struct iwl_fw_ini_error_dump) + - iwl_dump_ini_mem_ranges(fwrt, reg) * - (sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->internal.range_data_size)); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 size = le32_to_cpu(reg->dev_addr.size); + u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data); + + if (!size || !ranges) + return 0; + + return sizeof(struct iwl_fw_ini_error_dump) + ranges * + (size + sizeof(struct iwl_fw_ini_error_dump_range)); } -static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 +iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { int i; u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range); u32 size = sizeof(struct iwl_fw_ini_error_dump); if (fwrt->trans->trans_cfg->gen2) { - for (i = 0; i < iwl_dump_ini_paging_ranges(fwrt, reg); i++) + for (i = 0; i < iwl_dump_ini_paging_ranges(fwrt, reg_data); i++) size += range_header_len + fwrt->trans->init_dram.paging[i].size; } else { - for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg); i++) + for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg_data); + i++) size += range_header_len + fwrt->fw_paging_db[i].fw_paging_size; } @@ -1557,66 +1672,128 @@ static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, return size; } -static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 +iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { - u32 size = sizeof(struct iwl_fw_ini_monitor_dump) + - sizeof(struct iwl_fw_ini_error_dump_range); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_mon *fw_mon; + u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); + int i; - if (fwrt->trans->dbg.num_blocks) - size += fwrt->trans->dbg.fw_mon[0].size; + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + struct iwl_dram_data *frag = &fw_mon->frags[i]; + + if (!frag->size) + break; + + size += sizeof(struct iwl_fw_ini_error_dump_range) + frag->size; + } + + if (size) + size += sizeof(struct iwl_fw_ini_monitor_dump); return size; } -static u32 iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 +iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { - return sizeof(struct iwl_fw_ini_monitor_dump) + - iwl_dump_ini_mem_ranges(fwrt, reg) * - (sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->internal.range_data_size)); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 alloc_id = le32_to_cpu(reg->internal_buffer.alloc_id), size; + + fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id]; + if (le32_to_cpu(fw_mon_cfg->buf_location) != + IWL_FW_INI_LOCATION_SRAM_PATH) + return 0; + + size = le32_to_cpu(reg->internal_buffer.size); + if (!size) + return 0; + + size += sizeof(struct iwl_fw_ini_monitor_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; } static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); u32 size = 0; u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->fifos.num_of_registers) * - sizeof(struct iwl_fw_ini_error_dump_register); + registers_num * + sizeof(struct iwl_fw_ini_error_dump_register); - while (iwl_ini_txf_iter(fwrt, reg, size)) { + while (iwl_ini_txf_iter(fwrt, reg_data, size)) { size += fifo_hdr; - if (!reg->fifos.header_only) + if (!reg->fifos.hdr_only) size += iter->fifo_size; } - if (size) - size += sizeof(struct iwl_fw_ini_error_dump); + if (!size) + return 0; - return size; + return size + sizeof(struct iwl_fw_ini_error_dump); } static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_ini_rxf_data rx_data; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); u32 size = sizeof(struct iwl_fw_ini_error_dump) + sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->fifos.num_of_registers) * - sizeof(struct iwl_fw_ini_error_dump_register); + registers_num * sizeof(struct iwl_fw_ini_error_dump_register); - if (reg->fifos.header_only) + if (reg->fifos.hdr_only) return size; - iwl_ini_get_rxf_data(fwrt, reg, &rx_data); + iwl_ini_get_rxf_data(fwrt, reg_data, &rx_data); size += rx_data.size; return size; } +static u32 +iwl_dump_ini_err_table_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 size = le32_to_cpu(reg->err_table.size); + + if (size) + size += sizeof(struct iwl_fw_ini_err_table_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; +} + +static u32 +iwl_dump_ini_fw_pkt_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + u32 size = 0; + + if (!reg_data->dump_data->fw_pkt) + return 0; + + size += iwl_rx_packet_payload_len(reg_data->dump_data->fw_pkt); + if (size) + size += sizeof(struct iwl_fw_ini_error_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; +} + /** * struct iwl_dump_ini_mem_ops - ini memory dump operations * @get_num_of_ranges: returns the number of memory ranges in the region. @@ -1628,14 +1805,15 @@ static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, */ struct iwl_dump_ini_mem_ops { u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg); + struct iwl_dump_ini_region_data *reg_data); u32 (*get_size)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg); + struct iwl_dump_ini_region_data *reg_data); void *(*fill_mem_hdr)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *data); + struct iwl_dump_ini_region_data *reg_data, + void *data); int (*fill_range)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range, - int idx); + struct iwl_dump_ini_region_data *reg_data, + void *range, int idx); }; /** @@ -1650,60 +1828,61 @@ struct iwl_dump_ini_mem_ops { * @ops: memory dump operations */ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, const struct iwl_dump_ini_mem_ops *ops) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_error_dump_data *tlv; struct iwl_fw_ini_error_dump_header *header; - u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type), size; + u32 type = le32_to_cpu(reg->type), id = le32_to_cpu(reg->id); + u32 num_of_ranges, i, size; void *range; if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || !ops->fill_range) return 0; - size = ops->get_size(fwrt, reg); + size = ops->get_size(fwrt, reg_data); if (!size) return 0; - entry = kmalloc(sizeof(*entry) + sizeof(*tlv) + size, GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + size); if (!entry) return 0; entry->size = sizeof(*tlv) + size; tlv = (void *)entry->data; - tlv->type = cpu_to_le32(type); + tlv->type = reg->type; tlv->len = cpu_to_le32(size); - IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", id, + type); - num_of_ranges = ops->get_num_of_ranges(fwrt, reg); + num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data); header = (void *)tlv->data; - header->region_id = reg->region_id; + header->region_id = reg->id; header->num_of_ranges = cpu_to_le32(num_of_ranges); - header->name_len = cpu_to_le32(min_t(int, IWL_FW_INI_MAX_NAME, - le32_to_cpu(reg->name_len))); - memcpy(header->name, reg->name, le32_to_cpu(header->name_len)); + header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME); + memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME); - range = ops->fill_mem_hdr(fwrt, reg, header); + range = ops->fill_mem_hdr(fwrt, reg_data, header); if (!range) { IWL_ERR(fwrt, "WRT: Failed to fill region header: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + id, type); goto out_err; } for (i = 0; i < num_of_ranges; i++) { - int range_size = ops->fill_range(fwrt, reg, range, i); + int range_size = ops->fill_range(fwrt, reg_data, range, i); if (range_size < 0) { IWL_ERR(fwrt, "WRT: Failed to dump region: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + id, type); goto out_err; } range = range + range_size; @@ -1714,22 +1893,29 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, return entry->size; out_err: - kfree(entry); + vfree(entry); return 0; } static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_trigger *trigger, + struct iwl_fw_ini_trigger_tlv *trigger, struct list_head *list) { struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_error_dump_data *tlv; struct iwl_fw_ini_dump_info *dump; - u32 reg_ids_size = le32_to_cpu(trigger->num_regions) * sizeof(__le32); - u32 size = sizeof(*tlv) + sizeof(*dump) + reg_ids_size; + struct iwl_dbg_tlv_node *node; + struct iwl_fw_ini_dump_cfg_name *cfg_name; + u32 size = sizeof(*tlv) + sizeof(*dump); + u32 num_of_cfg_names = 0; + + list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { + size += sizeof(*cfg_name); + num_of_cfg_names++; + } - entry = kmalloc(sizeof(*entry) + size, GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + size); if (!entry) return 0; @@ -1737,13 +1923,14 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, tlv = (void *)entry->data; tlv->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE); - tlv->len = cpu_to_le32(sizeof(*dump) + reg_ids_size); + tlv->len = cpu_to_le32(size - sizeof(*tlv)); dump = (void *)tlv->data; dump->version = cpu_to_le32(IWL_INI_DUMP_VER); - dump->trigger_id = trigger->trigger_id; - dump->is_external_cfg = + dump->time_point = trigger->time_point; + dump->trigger_reason = trigger->trigger_reason; + dump->external_cfg_state = cpu_to_le32(fwrt->trans->dbg.external_ini_cfg); dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type); @@ -1763,26 +1950,26 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major); dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor); + dump->fw_mon_mode = cpu_to_le32(fwrt->trans->dbg.ini_dest); + dump->regions_mask = trigger->regions_mask; + dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag)); memcpy(dump->build_tag, fwrt->fw->human_readable, sizeof(dump->build_tag)); - dump->img_name_len = cpu_to_le32(sizeof(dump->img_name)); - memcpy(dump->img_name, fwrt->dump.img_name, sizeof(dump->img_name)); - - dump->internal_dbg_cfg_name_len = - cpu_to_le32(sizeof(dump->internal_dbg_cfg_name)); - memcpy(dump->internal_dbg_cfg_name, fwrt->dump.internal_dbg_cfg_name, - sizeof(dump->internal_dbg_cfg_name)); - - dump->external_dbg_cfg_name_len = - cpu_to_le32(sizeof(dump->external_dbg_cfg_name)); - - memcpy(dump->external_dbg_cfg_name, fwrt->dump.external_dbg_cfg_name, - sizeof(dump->external_dbg_cfg_name)); - - dump->regions_num = trigger->num_regions; - memcpy(dump->region_ids, trigger->data, reg_ids_size); + cfg_name = dump->cfg_names; + dump->num_of_cfg_names = cpu_to_le32(num_of_cfg_names); + list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { + struct iwl_fw_ini_debug_info_tlv *debug_info = + (void *)node->tlv.data; + + cfg_name->image_type = debug_info->image_type; + cfg_name->cfg_name_len = + cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME); + memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name, + sizeof(cfg_name->cfg_name)); + cfg_name++; + } /* add dump info TLV to the beginning of the list since it needs to be * the first TLV in the dump @@ -1794,33 +1981,18 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { [IWL_FW_INI_REGION_INVALID] = {}, - [IWL_FW_INI_REGION_DEVICE_MEMORY] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mem_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, - }, - [IWL_FW_INI_REGION_PERIPHERY_MAC] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mem_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_prph_iter, + [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_mon_smem_get_size, + .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header, + .fill_range = iwl_dump_ini_mon_smem_iter, }, - [IWL_FW_INI_REGION_PERIPHERY_PHY] = {}, - [IWL_FW_INI_REGION_PERIPHERY_AUX] = {}, [IWL_FW_INI_REGION_DRAM_BUFFER] = { .get_num_of_ranges = iwl_dump_ini_mon_dram_ranges, .get_size = iwl_dump_ini_mon_dram_get_size, .fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header, .fill_range = iwl_dump_ini_mon_dram_iter, }, - [IWL_FW_INI_REGION_DRAM_IMR] = {}, - [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mon_smem_get_size, - .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, - }, [IWL_FW_INI_REGION_TXF] = { .get_num_of_ranges = iwl_dump_ini_txf_ranges, .get_size = iwl_dump_ini_txf_get_size, @@ -1828,70 +2000,91 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_range = iwl_dump_ini_txf_iter, }, [IWL_FW_INI_REGION_RXF] = { - .get_num_of_ranges = iwl_dump_ini_rxf_ranges, + .get_num_of_ranges = iwl_dump_ini_single_range, .get_size = iwl_dump_ini_rxf_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_rxf_iter, }, - [IWL_FW_INI_REGION_PAGING] = { + [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_err_table_get_size, + .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, + .fill_range = iwl_dump_ini_err_table_iter, + }, + [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_err_table_get_size, + .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, + .fill_range = iwl_dump_ini_err_table_iter, + }, + [IWL_FW_INI_REGION_RSP_OR_NOTIF] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_fw_pkt_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .get_num_of_ranges = iwl_dump_ini_paging_ranges, - .get_size = iwl_dump_ini_paging_get_size, - .fill_range = iwl_dump_ini_paging_iter, + .fill_range = iwl_dump_ini_fw_pkt_iter, }, - [IWL_FW_INI_REGION_CSR] = { + [IWL_FW_INI_REGION_DEVICE_MEMORY] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_csr_iter, + .fill_range = iwl_dump_ini_dev_mem_iter, }, - [IWL_FW_INI_REGION_NOTIFICATION] = {}, - [IWL_FW_INI_REGION_DHC] = {}, - [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = { + [IWL_FW_INI_REGION_PERIPHERY_MAC] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, + .fill_range = iwl_dump_ini_prph_iter, }, - [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = { + [IWL_FW_INI_REGION_PERIPHERY_PHY] = {}, + [IWL_FW_INI_REGION_PERIPHERY_AUX] = {}, + [IWL_FW_INI_REGION_PAGING] = { + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .get_num_of_ranges = iwl_dump_ini_paging_ranges, + .get_size = iwl_dump_ini_paging_get_size, + .fill_range = iwl_dump_ini_paging_iter, + }, + [IWL_FW_INI_REGION_CSR] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, + .fill_range = iwl_dump_ini_csr_iter, }, + [IWL_FW_INI_REGION_DRAM_IMR] = {}, + [IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = {}, }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_trigger *trigger, + struct iwl_fwrt_dump_data *dump_data, struct list_head *list) { + struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig; + struct iwl_dump_ini_region_data reg_data = { + .dump_data = dump_data, + }; int i; u32 size = 0; + u64 regions_mask = le64_to_cpu(trigger->regions_mask); - for (i = 0; i < le32_to_cpu(trigger->num_regions); i++) { - u32 reg_id = le32_to_cpu(trigger->data[i]), reg_type; - struct iwl_fw_ini_region_cfg *reg; + for (i = 0; i < 64; i++) { + u32 reg_type; + struct iwl_fw_ini_region_tlv *reg; - if (WARN_ON(reg_id >= ARRAY_SIZE(fwrt->dump.active_regs))) + if (!(BIT_ULL(i) & regions_mask)) continue; - reg = fwrt->dump.active_regs[reg_id]; - if (!reg) { + reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i]; + if (!reg_data.reg_tlv) { IWL_WARN(fwrt, - "WRT: Unassigned region id %d, skipping\n", - reg_id); + "WRT: Unassigned region id %d, skipping\n", i); continue; } - /* currently the driver supports always on domain only */ - if (le32_to_cpu(reg->domain) != IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON) - continue; - - reg_type = le32_to_cpu(reg->region_type); + reg = (void *)reg_data.reg_tlv->data; + reg_type = le32_to_cpu(reg->type); if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; - size += iwl_dump_ini_mem(fwrt, list, reg, + size += iwl_dump_ini_mem(fwrt, list, ®_data, &iwl_dump_ini_region_ops[reg_type]); } @@ -1901,31 +2094,43 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, return size; } +static bool iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_trigger_tlv *trig) +{ + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); + u32 usec = le32_to_cpu(trig->ignore_consec); + + if (!iwl_trans_dbg_ini_valid(fwrt->trans) || + tp_id == IWL_FW_INI_TIME_POINT_INVALID || + tp_id >= IWL_FW_INI_TIME_POINT_NUM || + iwl_fw_dbg_no_trig_window(fwrt, tp_id, usec)) + return false; + + return true; +} + static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id trig_id, + struct iwl_fwrt_dump_data *dump_data, struct list_head *list) { + struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig; struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_ini_dump_file_hdr *hdr; - struct iwl_fw_ini_trigger *trigger; u32 size; - if (!iwl_fw_ini_trigger_on(fwrt, trig_id)) - return 0; - - trigger = fwrt->dump.active_trigs[trig_id].trig; - if (!trigger || !le32_to_cpu(trigger->num_regions)) + if (!trigger || !iwl_fw_ini_trigger_on(fwrt, trigger) || + !le64_to_cpu(trigger->regions_mask)) return 0; - entry = kmalloc(sizeof(*entry) + sizeof(*hdr), GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + sizeof(*hdr)); if (!entry) return 0; entry->size = sizeof(*hdr); - size = iwl_dump_ini_trigger(fwrt, trigger, list); + size = iwl_dump_ini_trigger(fwrt, dump_data, list); if (!size) { - kfree(entry); + vfree(entry); return 0; } @@ -1991,18 +2196,24 @@ static void iwl_dump_ini_list_free(struct list_head *list) list_entry(list->next, typeof(*entry), list); list_del(&entry->list); - kfree(entry); + vfree(entry); } } -static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx) +static void iwl_fw_error_dump_data_free(struct iwl_fwrt_dump_data *dump_data) +{ + dump_data->trig = NULL; + kfree(dump_data->fw_pkt); + dump_data->fw_pkt = NULL; +} + +static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data) { - enum iwl_fw_ini_trigger_id trig_id = fwrt->dump.wks[wk_idx].ini_trig_id; struct list_head dump_list = LIST_HEAD_INIT(dump_list); struct scatterlist *sg_dump_data; - u32 file_len; + u32 file_len = iwl_dump_ini_file_gen(fwrt, dump_data, &dump_list); - file_len = iwl_dump_ini_file_gen(fwrt, trig_id, &dump_list); if (!file_len) goto out; @@ -2023,7 +2234,7 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx) iwl_dump_ini_list_free(&dump_list); out: - fwrt->dump.wks[wk_idx].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID; + iwl_fw_error_dump_data_free(dump_data); } const struct iwl_fw_dump_desc iwl_dump_desc_assert = { @@ -2038,15 +2249,9 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, bool monitor_only, unsigned int delay) { - u32 trig_type = le32_to_cpu(desc->trig_desc.type); - int ret; - if (iwl_trans_dbg_ini_valid(fwrt->trans)) { - ret = iwl_fw_dbg_ini_collect(fwrt, trig_type); - if (!ret) - iwl_fw_free_dump_desc(fwrt); - - return ret; + iwl_fw_free_dump_desc(fwrt); + return 0; } /* use wks[0] since dump flow prior to ini does not need to support @@ -2138,35 +2343,29 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); -int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id) +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data) { - struct iwl_fw_ini_active_triggers *active; + struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); u32 occur, delay; unsigned long idx; - if (WARN_ON(!iwl_fw_ini_trigger_on(fwrt, id))) - return -EINVAL; + if (test_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status)) + return -EBUSY; - if (!iwl_fw_ini_trigger_on(fwrt, id)) { + if (!iwl_fw_ini_trigger_on(fwrt, trig)) { IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", - id); + tp_id); return -EINVAL; } - active = &fwrt->dump.active_trigs[id]; - delay = le32_to_cpu(active->trig->dump_delay); - occur = le32_to_cpu(active->trig->occurrences); + delay = le32_to_cpu(trig->dump_delay); + occur = le32_to_cpu(trig->occurrences); if (!occur) return 0; - active->trig->occurrences = cpu_to_le32(--occur); - - if (le32_to_cpu(active->trig->force_restart)) { - IWL_WARN(fwrt, "WRT: Force restart: trigger %d fired.\n", id); - iwl_force_nmi(fwrt->trans); - return 0; - } + trig->occurrences = cpu_to_le32(--occur); /* Check there is an available worker. * ffz return value is undefined if no zero exists, @@ -2181,36 +2380,14 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) return -EBUSY; - fwrt->dump.wks[idx].ini_trig_id = id; + fwrt->dump.wks[idx].dump_data = *dump_data; - IWL_WARN(fwrt, "WRT: Collecting data: ini trigger %d fired.\n", id); + IWL_WARN(fwrt, "WRT: Collecting data: ini trigger %d fired.\n", tp_id); schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); return 0; } -IWL_EXPORT_SYMBOL(_iwl_fw_dbg_ini_collect); - -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, u32 legacy_trigger_id) -{ - int id; - - switch (legacy_trigger_id) { - case FW_DBG_TRIGGER_FW_ASSERT: - case FW_DBG_TRIGGER_ALIVE_TIMEOUT: - case FW_DBG_TRIGGER_DRIVER: - id = IWL_FW_TRIGGER_ID_FW_ASSERT; - break; - case FW_DBG_TRIGGER_USER: - id = IWL_FW_TRIGGER_ID_USER_TRIGGER; - break; - default: - return -EIO; - } - - return _iwl_fw_dbg_ini_collect(fwrt, id); -} -IWL_EXPORT_SYMBOL(iwl_fw_dbg_ini_collect); int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, @@ -2219,6 +2396,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, int ret, len = 0; char buf[64]; + if (iwl_trans_dbg_ini_valid(fwrt->trans)) + return 0; + if (fmt) { va_list ap; @@ -2322,7 +2502,7 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n"); if (iwl_trans_dbg_ini_valid(fwrt->trans)) - iwl_fw_error_ini_dump(fwrt, wk_idx); + iwl_fw_error_ini_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data); else iwl_fw_error_dump(fwrt); IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection done\n"); @@ -2335,11 +2515,10 @@ out: void iwl_fw_error_dump_wk(struct work_struct *work) { - struct iwl_fw_runtime *fwrt; - typeof(fwrt->dump.wks[0]) *wks; - - wks = container_of(work, typeof(fwrt->dump.wks[0]), wk.work); - fwrt = container_of(wks, struct iwl_fw_runtime, dump.wks[wks->idx]); + struct iwl_fwrt_wk_data *wks = + container_of(work, typeof(*wks), wk.work); + struct iwl_fw_runtime *fwrt = + container_of(wks, typeof(*fwrt), dump.wks[wks->idx]); /* assumes the op mode mutex is locked in dump_start since * iwl_fw_dbg_collect_sync can't run in parallel diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index e3b5dd34643f..179f2905d56b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -114,9 +114,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, bool monitor_only, unsigned int delay); int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig_type); -int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id); -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, u32 legacy_trigger_id); +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, struct iwl_fw_dbg_trigger_tlv *trigger); @@ -222,29 +221,6 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt, _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \ }) -static inline bool -iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id) -{ - struct iwl_fw_ini_trigger *trig; - u32 usec; - - if (!iwl_trans_dbg_ini_valid(fwrt->trans) || - id == IWL_FW_TRIGGER_ID_INVALID || id >= IWL_FW_TRIGGER_ID_NUM || - !fwrt->dump.active_trigs[id].active) - return false; - - trig = fwrt->dump.active_trigs[id].trig; - usec = le32_to_cpu(trig->ignore_consec); - - if (iwl_fw_dbg_no_trig_window(fwrt, id, usec)) { - IWL_WARN(fwrt, "Trigger %d fired in no-collect window\n", id); - return false; - } - - return true; -} - static inline void _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, struct wireless_dev *wdev, @@ -315,10 +291,8 @@ static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt) int i; iwl_dbg_tlv_del_timers(fwrt->trans); - for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) { + for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) flush_delayed_work(&fwrt->dump.wks[i].wk); - fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID; - } } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -381,12 +355,21 @@ static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans, static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) { - if (iwl_trans_dbg_ini_valid(fwrt->trans) && fwrt->trans->dbg.hw_error) { - _iwl_fw_dbg_ini_collect(fwrt, IWL_FW_TRIGGER_ID_FW_HW_ERROR); + enum iwl_fw_ini_time_point tp_id; + + if (!iwl_trans_dbg_ini_valid(fwrt->trans)) { + iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0); + return; + } + + if (fwrt->trans->dbg.hw_error) { + tp_id = IWL_FW_INI_TIME_POINT_FW_HW_ERROR; fwrt->trans->dbg.hw_error = false; } else { - iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0); + tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT; } + + iwl_dbg_tlv_time_point(fwrt, tp_id, NULL); } void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index c1aa4360736b..ca3b1a461dea 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -320,10 +320,45 @@ out: FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512); +static ssize_t iwl_dbgfs_fw_dbg_domain_write(struct iwl_fw_runtime *fwrt, + char *buf, size_t count) +{ + u32 new_domain; + int ret; + + if (!iwl_trans_fw_running(fwrt->trans)) + return -EIO; + + ret = kstrtou32(buf, 0, &new_domain); + if (ret) + return ret; + + if (new_domain != fwrt->trans->dbg.domains_bitmap) { + ret = iwl_dbg_tlv_gen_active_trigs(fwrt, new_domain); + if (ret) + return ret; + + iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_PERIODIC, + NULL); + } + + return count; +} + +static ssize_t iwl_dbgfs_fw_dbg_domain_read(struct iwl_fw_runtime *fwrt, + size_t size, char *buf) +{ + return scnprintf(buf, size, "0x%08x\n", + fwrt->trans->dbg.domains_bitmap); +} + +FWRT_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_domain, 20); + void iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) { INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk); FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200); FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200); + FWRT_DEBUGFS_ADD_FILE(fw_dbg_domain, dbgfs_dir, 0600); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 2e763678dbdb..f008e1bbfdf4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -65,6 +65,7 @@ #define __fw_error_dump_h__ #include <linux/types.h> +#include "fw/api/cmdhdr.h" #define IWL_FW_ERROR_DUMP_BARKER 0x14789632 #define IWL_FW_INI_ERROR_DUMP_BARKER 0x14789633 @@ -327,6 +328,7 @@ struct iwl_fw_ini_fifo_hdr { * @dram_base_addr: base address of dram monitor range * @page_num: page number of memory range * @fifo_hdr: fifo header of memory range + * @fw_pkt: FW packet header of memory range * @data: the actual memory */ struct iwl_fw_ini_error_dump_range { @@ -336,6 +338,7 @@ struct iwl_fw_ini_error_dump_range { __le64 dram_base_addr; __le32 page_num; struct iwl_fw_ini_fifo_hdr fifo_hdr; + struct iwl_cmd_header fw_pkt_hdr; }; __le32 data[]; } __packed; @@ -379,12 +382,23 @@ struct iwl_fw_ini_error_dump_register { __le32 data; } __packed; +/** + * struct iwl_fw_ini_dump_cfg_name - configuration name + * @image_type: image type the configuration is related to + * @cfg_name_len: length of the configuration name + * @cfg_name: name of the configuraiton + */ +struct iwl_fw_ini_dump_cfg_name { + __le32 image_type; + __le32 cfg_name_len; + u8 cfg_name[IWL_FW_INI_MAX_CFG_NAME]; +} __packed; + /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version - * @trigger_id: trigger id that caused the dump collection - * @trigger_reason: not supported yet - * @is_external_cfg: 1 if an external debug configuration was loaded - * and 0 otherwise + * @time_point: time point that caused the dump collection + * @trigger_reason: reason of the trigger + * @external_cfg_state: &enum iwl_ini_cfg_state * @ver_type: FW version type * @ver_subtype: FW version subype * @hw_step: HW step @@ -397,22 +411,18 @@ struct iwl_fw_ini_error_dump_register { * @lmac_minor: lmac minor version * @umac_major: umac major version * @umac_minor: umac minor version + * @fw_mon_mode: FW monitor mode &enum iwl_fw_ini_buffer_location + * @regions_mask: bitmap mask of regions ids in the dump * @build_tag_len: length of the build tag * @build_tag: build tag string - * @img_name_len: length of the FW image name - * @img_name: FW image name - * @internal_dbg_cfg_name_len: length of the internal debug configuration name - * @internal_dbg_cfg_name: internal debug configuration name - * @external_dbg_cfg_name_len: length of the external debug configuration name - * @external_dbg_cfg_name: external debug configuration name - * @regions_num: number of region ids - * @region_ids: region ids the trigger configured to collect + * @num_of_cfg_names: number of configuration name structs + * @cfg_names: configuration names */ struct iwl_fw_ini_dump_info { __le32 version; - __le32 trigger_id; + __le32 time_point; __le32 trigger_reason; - __le32 is_external_cfg; + __le32 external_cfg_state; __le32 ver_type; __le32 ver_subtype; __le32 hw_step; @@ -425,17 +435,24 @@ struct iwl_fw_ini_dump_info { __le32 lmac_minor; __le32 umac_major; __le32 umac_minor; + __le32 fw_mon_mode; + __le64 regions_mask; __le32 build_tag_len; u8 build_tag[FW_VER_HUMAN_READABLE_SZ]; - __le32 img_name_len; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - __le32 internal_dbg_cfg_name_len; - u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - __le32 external_dbg_cfg_name_len; - u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - __le32 regions_num; - __le32 region_ids[]; + __le32 num_of_cfg_names; + struct iwl_fw_ini_dump_cfg_name cfg_names[]; +} __packed; +/** + * struct iwl_fw_ini_err_table_dump - ini error table dump + * @header: header of the region + * @version: error table version + * @ranges: the memory ranges of this this region + */ +struct iwl_fw_ini_err_table_dump { + struct iwl_fw_ini_error_dump_header header; + __le32 version; + struct iwl_fw_ini_error_dump_range ranges[]; } __packed; /** @@ -457,12 +474,14 @@ struct iwl_fw_error_dump_rb { * @header: header of the region * @write_ptr: write pointer position in the buffer * @cycle_cnt: cycles count + * @cur_frag: current fragment in use * @ranges: the memory ranges of this this region */ struct iwl_fw_ini_monitor_dump { struct iwl_fw_ini_error_dump_header header; __le32 write_ptr; __le32 cycle_cnt; + __le32 cur_frag; struct iwl_fw_ini_error_dump_range ranges[]; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 0d5bc4ce5c07..1554f5fdd483 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -93,7 +93,7 @@ struct iwl_ucode_header { } u; }; -#define IWL_UCODE_INI_TLV_GROUP 0x1000000 +#define IWL_UCODE_TLV_DEBUG_BASE 0x1000005 /* * new TLV uCode file layout @@ -151,7 +151,6 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_RECOVERY_INFO = 57, IWL_UCODE_TLV_FW_FSEQ_VERSION = 60, - IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_INI_TLV_GROUP, IWL_UCODE_TLV_TYPE_DEBUG_INFO = IWL_UCODE_TLV_DEBUG_BASE + 0, IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_TLV_DEBUG_BASE + 1, IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_TLV_DEBUG_BASE + 2, @@ -326,6 +325,8 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG = (__force iwl_ucode_tlv_api_t)56, IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57, IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER = (__force iwl_ucode_tlv_api_t)58, + IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, + NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ @@ -449,6 +450,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_CS_MODIFY = (__force iwl_ucode_tlv_capa_t)49, IWL_UCODE_TLV_CAPA_SET_LTR_GEN2 = (__force iwl_ucode_tlv_capa_t)50, IWL_UCODE_TLV_CAPA_SET_PPAG = (__force iwl_ucode_tlv_capa_t)52, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD = (__force iwl_ucode_tlv_capa_t)54, /* set 2 */ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 039576d71276..dbeab093171e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -228,18 +228,6 @@ struct iwl_fw_dbg { }; /** - * struct iwl_fw_ini_active_triggers - * @active: is this trigger active - * @size: allocated memory size of the trigger - * @trig: trigger - */ -struct iwl_fw_ini_active_triggers { - bool active; - size_t size; - struct iwl_fw_ini_trigger *trig; -}; - -/** * struct iwl_fw - variables associated with the firmware * * @ucode_ver: ucode version from the ucode file diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index be436c18a047..ec2ab0281f18 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -67,6 +67,8 @@ #include "fw/api/paging.h" #include "iwl-eeprom-parse.h" +#define IWL_FW_DBG_DOMAIN IWL_FW_INI_DOMAIN_ALWAYS_ON + struct iwl_fw_runtime_ops { int (*dump_start)(void *ctx); void (*dump_end)(void *ctx); @@ -91,6 +93,27 @@ struct iwl_fwrt_shared_mem_cfg { #define IWL_FW_RUNTIME_DUMP_WK_NUM 5 /** + * struct iwl_fwrt_dump_data - dump data + * @trig: trigger the worker was scheduled upon + * @fw_pkt: packet received from FW + */ +struct iwl_fwrt_dump_data { + struct iwl_fw_ini_trigger_tlv *trig; + struct iwl_rx_packet *fw_pkt; +}; + +/** + * struct iwl_fwrt_wk_data - dump worker data struct + * @idx: index of the worker + * @wk: worker + */ +struct iwl_fwrt_wk_data { + u8 idx; + struct delayed_work wk; + struct iwl_fwrt_dump_data dump_data; +}; + +/** * struct iwl_txf_iter_data - Tx fifo iterator data struct * @fifo: fifo number * @lmac: lmac number @@ -105,6 +128,14 @@ struct iwl_txf_iter_data { }; /** + * enum iwl_fw_runtime_status - fw runtime status flags + * @STATUS_GEN_ACTIVE_TRIGS: generating active trigger list + */ +enum iwl_fw_runtime_status { + STATUS_GEN_ACTIVE_TRIGS, +}; + +/** * struct iwl_fw_runtime - runtime data for firmware * @fw: firmware image * @cfg: NIC configuration @@ -117,6 +148,7 @@ struct iwl_txf_iter_data { * @smem_cfg: saved firmware SMEM configuration * @cur_fw_img: current firmware image, must be maintained by * the driver by calling &iwl_fw_set_current_image() + * @status: &enum iwl_fw_runtime_status * @dump: debug dump data */ struct iwl_fw_runtime { @@ -137,33 +169,25 @@ struct iwl_fw_runtime { /* memory configuration */ struct iwl_fwrt_shared_mem_cfg smem_cfg; + unsigned long status; + /* debug */ struct { const struct iwl_fw_dump_desc *desc; bool monitor_only; - struct { - u8 idx; - enum iwl_fw_ini_trigger_id ini_trig_id; - struct delayed_work wk; - } wks[IWL_FW_RUNTIME_DUMP_WK_NUM]; + struct iwl_fwrt_wk_data wks[IWL_FW_RUNTIME_DUMP_WK_NUM]; unsigned long active_wks; u8 conf; /* ts of the beginning of a non-collect fw dbg data period */ - unsigned long non_collect_ts_start[IWL_FW_TRIGGER_ID_NUM]; + unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM]; u32 *d3_debug_data; - struct iwl_fw_ini_region_cfg *active_regs[IWL_FW_INI_MAX_REGION_ID]; - struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM]; u32 lmac_err_id[MAX_NUM_LMAC]; u32 umac_err_id; struct iwl_txf_iter_data txf_iter_data; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - struct { u8 type; u8 subtype; @@ -194,16 +218,6 @@ static inline void iwl_fw_runtime_free(struct iwl_fw_runtime *fwrt) kfree(fwrt->dump.d3_debug_data); fwrt->dump.d3_debug_data = NULL; - for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++) { - struct iwl_fw_ini_active_triggers *active = - &fwrt->dump.active_trigs[i]; - - active->active = false; - active->size = 0; - kfree(active->trig); - active->trig = NULL; - } - iwl_dbg_tlv_del_timers(fwrt->trans); for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) cancel_delayed_work_sync(&fwrt->dump.wks[i].wk); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 214495a7165f..1b027a138b6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -360,6 +360,28 @@ struct iwl_cfg_trans_params { }; /** + * struct iwl_fw_mon_reg - FW monitor register info + * @addr: register address + * @mask: register mask + */ +struct iwl_fw_mon_reg { + u32 addr; + u32 mask; +}; + +/** + * struct iwl_fw_mon_regs - FW monitor registers + * @write_ptr: write pointer register + * @cycle_cnt: cycle count register + * @cur_frag: current fragment in use + */ +struct iwl_fw_mon_regs { + struct iwl_fw_mon_reg write_ptr; + struct iwl_fw_mon_reg cycle_cnt; + struct iwl_fw_mon_reg cur_frag; +}; + +/** * struct iwl_cfg * @trans: the trans-specific configuration part * @name: Official name of the device @@ -471,12 +493,10 @@ struct iwl_cfg { u32 d3_debug_data_base_addr; u32 d3_debug_data_length; u32 min_txq_size; - u32 fw_mon_smem_write_ptr_addr; - u32 fw_mon_smem_write_ptr_msk; - u32 fw_mon_smem_cycle_cnt_ptr_addr; - u32 fw_mon_smem_cycle_cnt_ptr_msk; u32 gp2_reg_addr; u32 min_256_ba_txq_size; + const struct iwl_fw_mon_regs mon_dram_regs; + const struct iwl_fw_mon_regs mon_smem_regs; }; extern const struct iwl_csr_params iwl_csr_v1; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 3d7f8ff8ef58..f266647dc08c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -95,6 +95,20 @@ struct iwl_dbg_tlv_ver_data { int max_ver; }; +/** + * struct iwl_dbg_tlv_timer_node - timer node struct + * @list: list of &struct iwl_dbg_tlv_timer_node + * @timer: timer + * @fwrt: &struct iwl_fw_runtime + * @tlv: TLV attach to the timer node + */ +struct iwl_dbg_tlv_timer_node { + struct list_head list; + struct timer_list timer; + struct iwl_fw_runtime *fwrt; + struct iwl_ucode_tlv *tlv; +}; + static const struct iwl_dbg_tlv_ver_data dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, @@ -104,12 +118,27 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, }; +static int iwl_dbg_tlv_add(struct iwl_ucode_tlv *tlv, struct list_head *list) +{ + u32 len = le32_to_cpu(tlv->length); + struct iwl_dbg_tlv_node *node; + + node = kzalloc(sizeof(*node) + len, GFP_KERNEL); + if (!node) + return -ENOMEM; + + memcpy(&node->tlv, tlv, sizeof(node->tlv) + len); + list_add_tail(&node->list, list); + + return 0; +} + static bool iwl_dbg_tlv_ver_support(struct iwl_ucode_tlv *tlv) { struct iwl_fw_ini_header *hdr = (void *)&tlv->data[0]; u32 type = le32_to_cpu(tlv->type); u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE; - u32 ver = le32_to_cpu(hdr->tlv_version); + u32 ver = le32_to_cpu(hdr->version); if (ver < dbg_ver_table[tlv_idx].min_ver || ver > dbg_ver_table[tlv_idx].max_ver) @@ -118,27 +147,169 @@ static bool iwl_dbg_tlv_ver_support(struct iwl_ucode_tlv *tlv) return true; } +static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_debug_info_tlv *debug_info = (void *)tlv->data; + + if (le32_to_cpu(tlv->length) != sizeof(*debug_info)) + return -EINVAL; + + IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", + debug_info->debug_cfg_name); + + return iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list); +} + +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); + + if (le32_to_cpu(tlv->length) != sizeof(*alloc) || + (buf_location != IWL_FW_INI_LOCATION_SRAM_PATH && + buf_location != IWL_FW_INI_LOCATION_DRAM_PATH)) + return -EINVAL; + + if ((buf_location == IWL_FW_INI_LOCATION_SRAM_PATH && + alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) || + (buf_location == IWL_FW_INI_LOCATION_DRAM_PATH && + (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; + } + + trans->dbg.fw_mon_cfg[alloc_id] = *alloc; + + return 0; +} + +static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_hcmd_tlv *hcmd = (void *)tlv->data; + u32 tp = le32_to_cpu(hcmd->time_point); + + if (le32_to_cpu(tlv->length) <= sizeof(*hcmd)) + return -EINVAL; + + /* Host commands can not be sent in early time point since the FW + * is not ready + */ + if (tp == IWL_FW_INI_TIME_POINT_INVALID || + tp >= IWL_FW_INI_TIME_POINT_NUM || + tp == IWL_FW_INI_TIME_POINT_EARLY) { + IWL_ERR(trans, + "WRT: Invalid time point %u for host command TLV\n", + tp); + return -EINVAL; + } + + return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list); +} + +static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)tlv->data; + struct iwl_ucode_tlv **active_reg; + u32 id = le32_to_cpu(reg->id); + u32 type = le32_to_cpu(reg->type); + u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); + + if (le32_to_cpu(tlv->length) < sizeof(*reg)) + return -EINVAL; + + if (id >= IWL_FW_INI_MAX_REGION_ID) { + IWL_ERR(trans, "WRT: Invalid region id %u\n", id); + return -EINVAL; + } + + if (type <= IWL_FW_INI_REGION_INVALID || + type >= IWL_FW_INI_REGION_NUM) { + IWL_ERR(trans, "WRT: Invalid region type %u\n", type); + return -EINVAL; + } + + active_reg = &trans->dbg.active_regions[id]; + if (*active_reg) { + IWL_WARN(trans, "WRT: Overriding region id %u\n", id); + + kfree(*active_reg); + } + + *active_reg = kmemdup(tlv, tlv_len, GFP_KERNEL); + if (!*active_reg) + return -ENOMEM; + + IWL_DEBUG_FW(trans, "WRT: Enabling region id %u type %u\n", id, type); + + return 0; +} + +static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_trigger_tlv *trig = (void *)tlv->data; + u32 tp = le32_to_cpu(trig->time_point); + + if (le32_to_cpu(tlv->length) < sizeof(*trig)) + return -EINVAL; + + if (tp <= IWL_FW_INI_TIME_POINT_INVALID || + tp >= IWL_FW_INI_TIME_POINT_NUM) { + IWL_ERR(trans, + "WRT: Invalid time point %u for trigger TLV\n", + tp); + return -EINVAL; + } + + if (!le32_to_cpu(trig->occurrences)) + trig->occurrences = cpu_to_le32(-1); + + return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); +} + +static int (*dbg_tlv_alloc[])(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) = { + [IWL_DBG_TLV_TYPE_DEBUG_INFO] = iwl_dbg_tlv_alloc_debug_info, + [IWL_DBG_TLV_TYPE_BUF_ALLOC] = iwl_dbg_tlv_alloc_buf_alloc, + [IWL_DBG_TLV_TYPE_HCMD] = iwl_dbg_tlv_alloc_hcmd, + [IWL_DBG_TLV_TYPE_REGION] = iwl_dbg_tlv_alloc_region, + [IWL_DBG_TLV_TYPE_TRIGGER] = iwl_dbg_tlv_alloc_trigger, +}; + void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, bool ext) { struct iwl_fw_ini_header *hdr = (void *)&tlv->data[0]; u32 type = le32_to_cpu(tlv->type); - u32 pnt = le32_to_cpu(hdr->apply_point); u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE; enum iwl_ini_cfg_state *cfg_state = ext ? &trans->dbg.external_ini_cfg : &trans->dbg.internal_ini_cfg; + int ret; - IWL_DEBUG_FW(trans, "WRT: read TLV 0x%x, apply point %d\n", - type, pnt); - - if (tlv_idx >= IWL_DBG_TLV_TYPE_NUM) { - IWL_ERR(trans, "WRT: Unsupported TLV 0x%x\n", type); + if (tlv_idx >= ARRAY_SIZE(dbg_tlv_alloc) || !dbg_tlv_alloc[tlv_idx]) { + IWL_ERR(trans, "WRT: Unsupported TLV type 0x%x\n", type); goto out_err; } if (!iwl_dbg_tlv_ver_support(tlv)) { IWL_ERR(trans, "WRT: Unsupported TLV 0x%x version %u\n", type, - le32_to_cpu(hdr->tlv_version)); + le32_to_cpu(hdr->version)); + goto out_err; + } + + ret = dbg_tlv_alloc[tlv_idx](trans, tlv); + if (ret) { + IWL_ERR(trans, + "WRT: Failed to allocate TLV 0x%x, ret %d, (ext=%d)\n", + type, ret, ext); goto out_err; } @@ -153,13 +324,91 @@ out_err: void iwl_dbg_tlv_del_timers(struct iwl_trans *trans) { - /* will be used later */ + struct list_head *timer_list = &trans->dbg.periodic_trig_list; + struct iwl_dbg_tlv_timer_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, timer_list, list) { + del_timer(&node->timer); + list_del(&node->list); + kfree(node); + } } IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers); +static void iwl_dbg_tlv_fragments_free(struct iwl_trans *trans, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + int i; + + if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return; + + fw_mon = &trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + struct iwl_dram_data *frag = &fw_mon->frags[i]; + + dma_free_coherent(trans->dev, frag->size, frag->block, + frag->physical); + + frag->physical = 0; + frag->block = NULL; + frag->size = 0; + } + + kfree(fw_mon->frags); + fw_mon->frags = NULL; + fw_mon->num_frags = 0; +} + void iwl_dbg_tlv_free(struct iwl_trans *trans) { - /* will be used again later */ + struct iwl_dbg_tlv_node *tlv_node, *tlv_node_tmp; + int i; + + iwl_dbg_tlv_del_timers(trans); + + for (i = 0; i < ARRAY_SIZE(trans->dbg.active_regions); i++) { + struct iwl_ucode_tlv **active_reg = + &trans->dbg.active_regions[i]; + + kfree(*active_reg); + *active_reg = NULL; + } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, + &trans->dbg.debug_info_tlv_list, list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + + for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &trans->dbg.time_point[i]; + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->trig_list, + list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->hcmd_list, + list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, + &tp->active_trig_list, list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + } + + for (i = 0; i < ARRAY_SIZE(trans->dbg.fw_mon_ini); i++) + iwl_dbg_tlv_fragments_free(trans, i); } static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data, @@ -196,7 +445,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) if (!iwlwifi_mod_params.enable_ini) return; - res = request_firmware(&fw, "iwl-dbg-tlv.ini", dev); + res = request_firmware(&fw, "iwl-debug-yoyo.bin", dev); if (res) return; @@ -205,10 +454,628 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) release_firmware(fw); } +void iwl_dbg_tlv_init(struct iwl_trans *trans) +{ + int i; + + INIT_LIST_HEAD(&trans->dbg.debug_info_tlv_list); + INIT_LIST_HEAD(&trans->dbg.periodic_trig_list); + + for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &trans->dbg.time_point[i]; + + INIT_LIST_HEAD(&tp->trig_list); + INIT_LIST_HEAD(&tp->hcmd_list); + INIT_LIST_HEAD(&tp->active_trig_list); + } +} + +static int iwl_dbg_tlv_alloc_fragment(struct iwl_fw_runtime *fwrt, + struct iwl_dram_data *frag, u32 pages) +{ + void *block = NULL; + dma_addr_t physical; + + if (!frag || frag->size || !pages) + return -EIO; + + while (pages) { + block = dma_alloc_coherent(fwrt->dev, pages * PAGE_SIZE, + &physical, + GFP_KERNEL | __GFP_NOWARN); + if (block) + break; + + IWL_WARN(fwrt, "WRT: Failed to allocate fragment size %lu\n", + pages * PAGE_SIZE); + + pages = DIV_ROUND_UP(pages, 2); + } + + if (!block) + return -ENOMEM; + + frag->physical = physical; + frag->block = block; + frag->size = pages * PAGE_SIZE; + + return pages; +} + +static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 num_frags, remain_pages, frag_pages; + int i; + + if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return -EIO; + + fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id]; + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + if (fw_mon->num_frags || + fw_mon_cfg->buf_location != + cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH)) + return 0; + + num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num); + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) { + if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) + return -EIO; + num_frags = 1; + } + + remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size), + PAGE_SIZE); + num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS); + num_frags = min_t(u32, num_frags, remain_pages); + frag_pages = DIV_ROUND_UP(remain_pages, num_frags); + + fw_mon->frags = kcalloc(num_frags, sizeof(*fw_mon->frags), GFP_KERNEL); + if (!fw_mon->frags) + return -ENOMEM; + + for (i = 0; i < num_frags; i++) { + int pages = min_t(u32, frag_pages, remain_pages); + + IWL_DEBUG_FW(fwrt, + "WRT: Allocating DRAM buffer (alloc_id=%u, fragment=%u, size=0x%lx)\n", + alloc_id, i, pages * PAGE_SIZE); + + pages = iwl_dbg_tlv_alloc_fragment(fwrt, &fw_mon->frags[i], + pages); + if (pages < 0) { + u32 alloc_size = le32_to_cpu(fw_mon_cfg->req_size) - + (remain_pages * PAGE_SIZE); + + if (alloc_size < le32_to_cpu(fw_mon_cfg->min_size)) { + iwl_dbg_tlv_fragments_free(fwrt->trans, + alloc_id); + return pages; + } + break; + } + + remain_pages -= pages; + fw_mon->num_frags++; + } + + return 0; +} + +static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + u32 remain_frags, num_commands; + int i, fw_mon_idx = 0; + + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) + return 0; + + if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return -EIO; + + if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) != + IWL_FW_INI_LOCATION_DRAM_PATH) + return 0; + + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + /* the first fragment of DBGC1 is given to the FW via register + * or context info + */ + if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1) + fw_mon_idx++; + + remain_frags = fw_mon->num_frags - fw_mon_idx; + if (!remain_frags) + return 0; + + num_commands = DIV_ROUND_UP(remain_frags, BUF_ALLOC_MAX_NUM_FRAGS); + + IWL_DEBUG_FW(fwrt, "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + for (i = 0; i < num_commands; i++) { + u32 num_frags = min_t(u32, remain_frags, + BUF_ALLOC_MAX_NUM_FRAGS); + struct iwl_buf_alloc_cmd data = { + .alloc_id = cpu_to_le32(alloc_id), + .num_frags = cpu_to_le32(num_frags), + .buf_location = + cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH), + }; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION), + .data[0] = &data, + .len[0] = sizeof(data), + }; + int ret, j; + + for (j = 0; j < num_frags; j++) { + struct iwl_buf_alloc_frag *frag = &data.frags[j]; + struct iwl_dram_data *fw_mon_frag = + &fw_mon->frags[fw_mon_idx++]; + + frag->addr = cpu_to_le64(fw_mon_frag->physical); + frag->size = cpu_to_le32(fw_mon_frag->size); + } + ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); + if (ret) + return ret; + + remain_frags -= num_frags; + } + + return 0; +} + +static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt) +{ + int ret, i; + + for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) { + ret = iwl_dbg_tlv_apply_buffer(fwrt, i); + if (ret) + IWL_WARN(fwrt, + "WRT: Failed to apply DRAM buffer for allocation id %d, ret=%d\n", + i, ret); + } +} + +static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt, + struct list_head *hcmd_list) +{ + struct iwl_dbg_tlv_node *node; + + list_for_each_entry(node, hcmd_list, list) { + struct iwl_fw_ini_hcmd_tlv *hcmd = (void *)node->tlv.data; + struct iwl_fw_ini_hcmd *hcmd_data = &hcmd->hcmd; + u32 domain = le32_to_cpu(hcmd->hdr.domain); + u16 hcmd_len = le32_to_cpu(node->tlv.length) - sizeof(*hcmd); + struct iwl_host_cmd cmd = { + .id = WIDE_ID(hcmd_data->group, hcmd_data->id), + .len = { hcmd_len, }, + .data = { hcmd_data->data, }, + }; + + if (domain != IWL_FW_INI_DOMAIN_ALWAYS_ON && + !(domain & fwrt->trans->dbg.domains_bitmap)) + continue; + + iwl_trans_send_cmd(fwrt->trans, &cmd); + } +} + +static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t) +{ + struct iwl_dbg_tlv_timer_node *timer_node = + from_timer(timer_node, t, timer); + struct iwl_fwrt_dump_data dump_data = { + .trig = (void *)timer_node->tlv->data, + }; + int ret; + + ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data); + if (!ret || ret == -EBUSY) { + u32 occur = le32_to_cpu(dump_data.trig->occurrences); + u32 collect_interval = le32_to_cpu(dump_data.trig->data[0]); + + if (!occur) + return; + + mod_timer(t, jiffies + msecs_to_jiffies(collect_interval)); + } +} + +static void iwl_dbg_tlv_set_periodic_trigs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_dbg_tlv_node *node; + struct list_head *trig_list = + &fwrt->trans->dbg.time_point[IWL_FW_INI_TIME_POINT_PERIODIC].active_trig_list; + + list_for_each_entry(node, trig_list, list) { + struct iwl_fw_ini_trigger_tlv *trig = (void *)node->tlv.data; + struct iwl_dbg_tlv_timer_node *timer_node; + u32 occur = le32_to_cpu(trig->occurrences), collect_interval; + u32 min_interval = 100; + + if (!occur) + continue; + + /* make sure there is at least one dword of data for the + * interval value + */ + if (le32_to_cpu(node->tlv.length) < + sizeof(*trig) + sizeof(__le32)) { + IWL_ERR(fwrt, + "WRT: Invalid periodic trigger data was not given\n"); + continue; + } + + if (le32_to_cpu(trig->data[0]) < min_interval) { + IWL_WARN(fwrt, + "WRT: Override min interval from %u to %u msec\n", + le32_to_cpu(trig->data[0]), min_interval); + trig->data[0] = cpu_to_le32(min_interval); + } + + collect_interval = le32_to_cpu(trig->data[0]); + + timer_node = kzalloc(sizeof(*timer_node), GFP_KERNEL); + if (!timer_node) { + IWL_ERR(fwrt, + "WRT: Failed to allocate periodic trigger\n"); + continue; + } + + timer_node->fwrt = fwrt; + timer_node->tlv = &node->tlv; + timer_setup(&timer_node->timer, + iwl_dbg_tlv_periodic_trig_handler, 0); + + list_add_tail(&timer_node->list, + &fwrt->trans->dbg.periodic_trig_list); + + IWL_DEBUG_FW(fwrt, "WRT: Enabling periodic trigger\n"); + + mod_timer(&timer_node->timer, + jiffies + msecs_to_jiffies(collect_interval)); + } +} + +static bool is_trig_data_contained(struct iwl_ucode_tlv *new, + struct iwl_ucode_tlv *old) +{ + struct iwl_fw_ini_trigger_tlv *new_trig = (void *)new->data; + struct iwl_fw_ini_trigger_tlv *old_trig = (void *)old->data; + __le32 *new_data = new_trig->data, *old_data = old_trig->data; + u32 new_dwords_num = iwl_tlv_array_len(new, new_trig, data); + u32 old_dwords_num = iwl_tlv_array_len(new, new_trig, data); + int i, j; + + for (i = 0; i < new_dwords_num; i++) { + bool match = false; + + for (j = 0; j < old_dwords_num; j++) { + if (new_data[i] == old_data[j]) { + match = true; + break; + } + } + if (!match) + return false; + } + + return true; +} + +static int iwl_dbg_tlv_override_trig_node(struct iwl_fw_runtime *fwrt, + struct iwl_ucode_tlv *trig_tlv, + struct iwl_dbg_tlv_node *node) +{ + struct iwl_ucode_tlv *node_tlv = &node->tlv; + struct iwl_fw_ini_trigger_tlv *node_trig = (void *)node_tlv->data; + struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data; + u32 policy = le32_to_cpu(trig->apply_policy); + u32 size = le32_to_cpu(trig_tlv->length); + u32 trig_data_len = size - sizeof(*trig); + u32 offset = 0; + + if (!(policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA)) { + u32 data_len = le32_to_cpu(node_tlv->length) - + sizeof(*node_trig); + + IWL_DEBUG_FW(fwrt, + "WRT: Appending trigger data (time point %u)\n", + le32_to_cpu(trig->time_point)); + + offset += data_len; + size += data_len; + } else { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger data (time point %u)\n", + le32_to_cpu(trig->time_point)); + } + + if (size != le32_to_cpu(node_tlv->length)) { + struct list_head *prev = node->list.prev; + struct iwl_dbg_tlv_node *tmp; + + list_del(&node->list); + + tmp = krealloc(node, sizeof(*node) + size, GFP_KERNEL); + if (!tmp) { + IWL_WARN(fwrt, + "WRT: No memory to override trigger (time point %u)\n", + le32_to_cpu(trig->time_point)); + + list_add(&node->list, prev); + + return -ENOMEM; + } + + list_add(&tmp->list, prev); + node_tlv = &tmp->tlv; + node_trig = (void *)node_tlv->data; + } + + memcpy(node_trig->data + offset, trig->data, trig_data_len); + node_tlv->length = cpu_to_le32(size); + + if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG) { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger configuration (time point %u)\n", + le32_to_cpu(trig->time_point)); + + /* the first 11 dwords are configuration related */ + memcpy(node_trig, trig, sizeof(__le32) * 11); + } + + if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS) { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger regions (time point %u)\n", + le32_to_cpu(trig->time_point)); + + node_trig->regions_mask = trig->regions_mask; + } else { + IWL_DEBUG_FW(fwrt, + "WRT: Appending trigger regions (time point %u)\n", + le32_to_cpu(trig->time_point)); + + node_trig->regions_mask |= trig->regions_mask; + } + + return 0; +} + +static int +iwl_dbg_tlv_add_active_trigger(struct iwl_fw_runtime *fwrt, + struct list_head *trig_list, + struct iwl_ucode_tlv *trig_tlv) +{ + struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data; + struct iwl_dbg_tlv_node *node, *match = NULL; + u32 policy = le32_to_cpu(trig->apply_policy); + + list_for_each_entry(node, trig_list, list) { + if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT)) + break; + + if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_DATA) || + is_trig_data_contained(trig_tlv, &node->tlv)) { + match = node; + break; + } + } + + if (!match) { + IWL_DEBUG_FW(fwrt, "WRT: Enabling trigger (time point %u)\n", + le32_to_cpu(trig->time_point)); + return iwl_dbg_tlv_add(trig_tlv, trig_list); + } + + return iwl_dbg_tlv_override_trig_node(fwrt, trig_tlv, match); +} + +static void +iwl_dbg_tlv_gen_active_trig_list(struct iwl_fw_runtime *fwrt, + struct iwl_dbg_tlv_time_point_data *tp) +{ + struct iwl_dbg_tlv_node *node, *tmp; + struct list_head *trig_list = &tp->trig_list; + struct list_head *active_trig_list = &tp->active_trig_list; + + list_for_each_entry_safe(node, tmp, active_trig_list, list) { + list_del(&node->list); + kfree(node); + } + + list_for_each_entry(node, trig_list, list) { + struct iwl_ucode_tlv *tlv = &node->tlv; + struct iwl_fw_ini_trigger_tlv *trig = (void *)tlv->data; + u32 domain = le32_to_cpu(trig->hdr.domain); + + if (domain != IWL_FW_INI_DOMAIN_ALWAYS_ON && + !(domain & fwrt->trans->dbg.domains_bitmap)) + continue; + + iwl_dbg_tlv_add_active_trigger(fwrt, active_trig_list, tlv); + } +} + +int iwl_dbg_tlv_gen_active_trigs(struct iwl_fw_runtime *fwrt, u32 new_domain) +{ + int i; + + if (test_and_set_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status)) + return -EBUSY; + + iwl_fw_flush_dumps(fwrt); + + fwrt->trans->dbg.domains_bitmap = new_domain; + + IWL_DEBUG_FW(fwrt, + "WRT: Generating active triggers list, domain 0x%x\n", + fwrt->trans->dbg.domains_bitmap); + + for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &fwrt->trans->dbg.time_point[i]; + + iwl_dbg_tlv_gen_active_trig_list(fwrt, tp); + } + + clear_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status); + + return 0; +} + +static bool iwl_dbg_tlv_check_fw_pkt(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + union iwl_dbg_tlv_tp_data *tp_data, + u32 trig_data) +{ + struct iwl_rx_packet *pkt = tp_data->fw_pkt; + struct iwl_cmd_header *wanted_hdr = (void *)&trig_data; + + if (pkt && ((wanted_hdr->cmd == 0 && wanted_hdr->group_id == 0) || + (pkt->hdr.cmd == wanted_hdr->cmd && + pkt->hdr.group_id == wanted_hdr->group_id))) { + struct iwl_rx_packet *fw_pkt = + kmemdup(pkt, + sizeof(*pkt) + iwl_rx_packet_payload_len(pkt), + GFP_ATOMIC); + + if (!fw_pkt) + return false; + + dump_data->fw_pkt = fw_pkt; + + return true; + } + + return false; +} + +static int +iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, + struct list_head *active_trig_list, + union iwl_dbg_tlv_tp_data *tp_data, + bool (*data_check)(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + union iwl_dbg_tlv_tp_data *tp_data, + u32 trig_data)) +{ + struct iwl_dbg_tlv_node *node; + + list_for_each_entry(node, active_trig_list, list) { + struct iwl_fwrt_dump_data dump_data = { + .trig = (void *)node->tlv.data, + }; + u32 num_data = iwl_tlv_array_len(&node->tlv, dump_data.trig, + data); + int ret, i; + + if (!num_data) { + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + if (ret) + return ret; + } + + for (i = 0; i < num_data; i++) { + if (!data_check || + data_check(fwrt, &dump_data, tp_data, + le32_to_cpu(dump_data.trig->data[i]))) { + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + if (ret) + return ret; + + break; + } + } + } + + return 0; +} + +static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) +{ + enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest; + int ret, i; + + iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN); + + *ini_dest = IWL_FW_INI_LOCATION_INVALID; + for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) { + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg = + &fwrt->trans->dbg.fw_mon_cfg[i]; + u32 dest = le32_to_cpu(fw_mon_cfg->buf_location); + + if (dest == IWL_FW_INI_LOCATION_INVALID) + continue; + + if (*ini_dest == IWL_FW_INI_LOCATION_INVALID) + *ini_dest = dest; + + if (dest != *ini_dest) + continue; + + ret = iwl_dbg_tlv_alloc_fragments(fwrt, i); + if (ret) + IWL_WARN(fwrt, + "WRT: Failed to allocate DRAM buffer for allocation id %d, ret=%d\n", + i, ret); + } +} + void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data) { - /* will be used later */ + struct list_head *hcmd_list, *trig_list; + + if (!iwl_trans_dbg_ini_valid(fwrt->trans) || + tp_id == IWL_FW_INI_TIME_POINT_INVALID || + tp_id >= IWL_FW_INI_TIME_POINT_NUM) + return; + + hcmd_list = &fwrt->trans->dbg.time_point[tp_id].hcmd_list; + trig_list = &fwrt->trans->dbg.time_point[tp_id].active_trig_list; + + switch (tp_id) { + case IWL_FW_INI_TIME_POINT_EARLY: + iwl_dbg_tlv_init_cfg(fwrt); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: + iwl_dbg_tlv_apply_buffers(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + case IWL_FW_INI_TIME_POINT_PERIODIC: + iwl_dbg_tlv_set_periodic_trigs(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + break; + case IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF: + case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, + iwl_dbg_tlv_check_fw_pkt); + break; + default: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + } } IWL_EXPORT_SYMBOL(iwl_dbg_tlv_time_point); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index e257ad358c94..f18946872569 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -65,11 +65,11 @@ #include <linux/types.h> /** - * struct iwl_apply_point_data - * @list: list to go through the TLVs of the apply point - * @tlv: a debug TLV + * struct iwl_dbg_tlv_node - debug TLV node + * @list: list of &struct iwl_dbg_tlv_node + * @tlv: debug TLV */ -struct iwl_apply_point_data { +struct iwl_dbg_tlv_node { struct list_head list; struct iwl_ucode_tlv tlv; }; @@ -82,6 +82,18 @@ union iwl_dbg_tlv_tp_data { struct iwl_rx_packet *fw_pkt; }; +/** + * struct iwl_dbg_tlv_time_point_data + * @trig_list: list of triggers + * @active_trig_list: list of active triggers + * @hcmd_list: list of host commands + */ +struct iwl_dbg_tlv_time_point_data { + struct list_head trig_list; + struct list_head active_trig_list; + struct list_head hcmd_list; +}; + struct iwl_trans; struct iwl_fw_runtime; @@ -89,9 +101,11 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans); void iwl_dbg_tlv_free(struct iwl_trans *trans); void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, bool ext); +void iwl_dbg_tlv_init(struct iwl_trans *trans); void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data); +int iwl_dbg_tlv_gen_active_trigs(struct iwl_fw_runtime *fwrt, u32 new_domain); void iwl_dbg_tlv_del_timers(struct iwl_trans *trans); #endif /* __iwl_dbg_tlv_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ff0519ea00a5..b0881e713b48 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1560,6 +1560,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) IWL_INFO(drv, "loaded firmware version %s op_mode %s\n", drv->fw.fw_version, op->name); + iwl_dbg_tlv_load_bin(drv->trans->dev, drv->trans); + /* add this device to the list of devices using this op_mode */ list_add_tail(&drv->list, &op->drv); @@ -1636,8 +1638,6 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) init_completion(&drv->request_firmware_complete); INIT_LIST_HEAD(&drv->list); - iwl_dbg_tlv_load_bin(drv->trans->dev, drv->trans); - #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the device debugfs entries. */ drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index c8972f6e38ba..b0a0901ce0f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -256,12 +256,12 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, #undef CHECK_AND_PRINT_I } -static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, +static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, u32 nvm_flags, const struct iwl_cfg *cfg) { u32 flags = IEEE80211_CHAN_NO_HT40; - if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { + if (band == NL80211_BAND_2GHZ && (nvm_flags & NVM_CHANNEL_40MHZ)) { if (ch_num <= LAST_2GHZ_HT_PLUS) flags &= ~IEEE80211_CHAN_NO_HT40PLUS; if (ch_num >= FIRST_2GHZ_HT_MINUS) @@ -299,6 +299,13 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, return flags; } +static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx) +{ + if (ch_idx >= NUM_2GHZ_CHANNELS) + return NL80211_BAND_5GHZ; + return NL80211_BAND_2GHZ; +} + static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const void * const nvm_ch_flags, @@ -308,7 +315,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, int n_channels = 0; struct ieee80211_channel *channel; u32 ch_flags; - int num_of_ch, num_2ghz_channels = NUM_2GHZ_CHANNELS; + int num_of_ch; const u16 *nvm_chan; if (cfg->uhb_supported) { @@ -323,7 +330,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { - bool is_5ghz = (ch_idx >= num_2ghz_channels); + enum nl80211_band band = + iwl_nl80211_band_from_channel_idx(ch_idx); if (v4) ch_flags = @@ -332,12 +340,13 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ch_flags = __le16_to_cpup((__le16 *)nvm_ch_flags + ch_idx); - if (is_5ghz && !data->sku_cap_band_52ghz_enable) + if (band == NL80211_BAND_5GHZ && + !data->sku_cap_band_52ghz_enable) continue; /* workaround to disable wide channels in 5GHz */ if ((sbands_flags & IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ) && - is_5ghz) { + band == NL80211_BAND_5GHZ) { ch_flags &= ~(NVM_CHANNEL_40MHZ | NVM_CHANNEL_80MHZ | NVM_CHANNEL_160MHZ); @@ -362,8 +371,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, n_channels++; channel->hw_value = nvm_chan[ch_idx]; - channel->band = is_5ghz ? - NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; + channel->band = band; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); @@ -379,7 +387,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, /* don't put limitations in case we're using LAR */ if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR)) channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], - ch_idx, is_5ghz, + ch_idx, band, ch_flags, cfg); else channel->flags = 0; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 23c25a7665f2..14c8ba23f3b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -374,6 +374,7 @@ #define DBGC_CUR_DBGBUF_STATUS (0xd03c1c) #define DBGC_DBGBUF_WRAP_AROUND (0xd03c2c) #define DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK (0x00ffffff) +#define DBGC_CUR_DBGBUF_STATUS_IDX_MSK (0x0f000000) #define MON_DMARB_RD_CTL_ADDR (0xa03c60) #define MON_DMARB_RD_DATA_ADDR (0xa03c5c) @@ -381,6 +382,12 @@ #define DBGC_IN_SAMPLE (0xa03c00) #define DBGC_OUT_CTRL (0xa03c0c) +/* M2S registers */ +#define LDBG_M2S_BUF_WPTR (0xa0476c) +#define LDBG_M2S_BUF_WRAP_CNT (0xa04774) +#define LDBG_M2S_BUF_WPTR_VAL_MSK (0x000fffff) +#define LDBG_M2S_BUF_WRAP_CNT_VAL_MSK (0x000fffff) + /* enable the ID buf for read */ #define WFPM_PS_CTL_CLR 0xA0300C #define WFMP_MAC_ADDR_0 0xA03080 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a31408188ed0..8cadad7364ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -679,6 +679,16 @@ struct iwl_dram_data { }; /** + * struct iwl_fw_mon - fw monitor per allocation id + * @num_frags: number of fragments + * @frags: an array of DRAM buffer fragments + */ +struct iwl_fw_mon { + u32 num_frags; + struct iwl_dram_data *frags; +}; + +/** * struct iwl_self_init_dram - dram data used by self init process * @fw: lmac and umac dram data * @fw_cnt: total number of items in array @@ -706,10 +716,17 @@ struct iwl_self_init_dram { * pointers was recevied via TLV. uses enum &iwl_error_event_table_status * @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state * @external_ini_cfg: external debug cfg state. Uses &enum iwl_ini_cfg_state - * @num_blocks: number of blocks in fw_mon - * @fw_mon: address of the buffers for firmware monitor + * @fw_mon_cfg: debug buffer allocation configuration + * @fw_mon_ini: DRAM buffer fragments per allocation id + * @fw_mon: DRAM buffer for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location + * @active_regions: active regions + * @debug_info_tlv_list: list of debug info TLVs + * @time_point: array of debug time points + * @periodic_trig_list: periodic triggers list + * @domains_bitmap: bitmap of active domains other than + * &IWL_FW_INI_DOMAIN_ALWAYS_ON */ struct iwl_trans_debug { u8 n_dest_reg; @@ -726,11 +743,21 @@ struct iwl_trans_debug { enum iwl_ini_cfg_state internal_ini_cfg; enum iwl_ini_cfg_state external_ini_cfg; - int num_blocks; - struct iwl_dram_data fw_mon[IWL_FW_INI_ALLOCATION_NUM]; + struct iwl_fw_ini_allocation_tlv fw_mon_cfg[IWL_FW_INI_ALLOCATION_NUM]; + struct iwl_fw_mon fw_mon_ini[IWL_FW_INI_ALLOCATION_NUM]; + + struct iwl_dram_data fw_mon; bool hw_error; enum iwl_fw_ini_buffer_location ini_dest; + + struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID]; + struct list_head debug_info_tlv_list; + struct iwl_dbg_tlv_time_point_data + time_point[IWL_FW_INI_TIME_POINT_NUM]; + struct list_head periodic_trig_list; + + u32 domains_bitmap; }; /** @@ -1222,6 +1249,11 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans) iwl_op_mode_nic_error(trans->op_mode); } +static inline bool iwl_trans_fw_running(struct iwl_trans *trans) +{ + return trans->state == IWL_TRANS_FW_ALIVE; +} + static inline void iwl_trans_sync_nmi(struct iwl_trans *trans) { if (trans->ops->sync_nmi) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 86c2c587e755..1a9d83d6230f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1955,12 +1955,39 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) } if (d0i3_first) { - ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + struct iwl_host_cmd cmd = { + .id = D0I3_END_CMD, + .flags = CMD_WANT_SKB, + }; + int len; + + ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret < 0) { IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n", ret); goto err; } + switch (mvm->cmd_ver.d0i3_resp) { + case 0: + break; + case 1: + len = iwl_rx_packet_payload_len(cmd.resp_pkt); + if (len != sizeof(u32)) { + IWL_ERR(mvm, + "Error with D0I3_END_CMD response size (%d)\n", + len); + goto err; + } + if (IWL_D0I3_RESET_REQUIRE & + le32_to_cpu(*(__le32 *)cmd.resp_pkt->data)) { + iwl_write32(mvm->trans, CSR_RESET, + CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_free_resp(&cmd); + } + break; + default: + WARN_ON(1); + } } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index ad18c2f1a806..b6db1f8f40cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1375,6 +1375,9 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (count == 0) return 0; + iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, + NULL); + iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, (count - 1), NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9c417dd06291..b78992e341d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -855,11 +855,10 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, struct ieee80211_vif *vif) { u8 rate; - - if (info->band == NL80211_BAND_5GHZ || vif->p2p) - rate = IWL_FIRST_OFDM_RATE; - else + if (info->band == NL80211_BAND_2GHZ && !vif->p2p) rate = IWL_FIRST_CCK_RATE; + else + rate = IWL_FIRST_OFDM_RATE; return rate; } @@ -1404,6 +1403,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, u32 rx_missed_bcon, rx_missed_bcon_since_rx; struct ieee80211_vif *vif; u32 id = le32_to_cpu(mb->mac_id); + union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; IWL_DEBUG_INFO(mvm, "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", @@ -1432,7 +1432,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, ieee80211_beacon_loss(vif); iwl_dbg_tlv_time_point(&mvm->fwrt, - IWL_FW_INI_TIME_POINT_MISSED_BEACONS, NULL); + IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), FW_DBG_TRIGGER_MISSED_BEACONS); @@ -1609,3 +1609,26 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, out_unlock: rcu_read_unlock(); } + +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_missed_vap_notif *mb = (void *)pkt->data; + struct ieee80211_vif *vif; + u32 id = le32_to_cpu(mb->mac_id); + + IWL_DEBUG_INFO(mvm, + "missed_vap notify mac_id=%u, num_beacon_intervals_elapsed=%u, profile_periodicity=%u\n", + le32_to_cpu(mb->mac_id), + mb->num_beacon_intervals_elapsed, + mb->profile_periodicity); + + rcu_read_lock(); + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + if (vif) + iwl_mvm_connection_loss(mvm, vif, "missed vap beacon"); + + rcu_read_unlock(); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d31f96c3f925..61c33b9335e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -339,14 +339,14 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) return ret; } -const static u8 he_if_types_ext_capa_sta[] = { +static const u8 he_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; -const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { +static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { { .iftype = NL80211_IFTYPE_STATION, .extended_capabilities = he_if_types_ext_capa_sta, @@ -2280,7 +2280,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, - &mvm->status)) { + &mvm->status) && + !fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { /* * If we're restarting then the firmware will * obviously have lost synchronisation with @@ -2294,6 +2296,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * * Set a large maximum delay to allow for more * than a single interface. + * + * For new firmware versions, rely on the + * firmware. This is relevant for DCM scenarios + * only anyway. */ u32 dur = (11 * vif->bss_conf.beacon_int) / 10; iwl_mvm_protect_session(mvm, vif, dur, dur, @@ -2384,8 +2390,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* * We received a beacon from the associated AP so * remove the session protection. + * A firmware with the new API will remove it automatically. */ - iwl_mvm_stop_session_protection(mvm, vif); + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_stop_session_protection(mvm, vif); iwl_mvm_sf_update(mvm, vif, false); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); @@ -3255,8 +3264,22 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, duration = req_duration; mutex_lock(&mvm->mutex); - /* Try really hard to protect the session and hear a beacon */ - iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); + /* Try really hard to protect the session and hear a beacon + * The new session protection command allows us to protect the + * session for a much longer time since the firmware will internally + * create two events: a 300TU one with a very high priority that + * won't be fragmented which should be enough for 99% of the cases, + * and another one (which we configure here to be 900TU long) which + * will have a slightly lower priority, but more importantly, can be + * fragmented so that it'll allow other activities to run. + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_schedule_session_protection(mvm, vif, 900, + min_duration); + else + iwl_mvm_protect_session(mvm, vif, duration, + min_duration, 500, false); mutex_unlock(&mvm->mutex); } @@ -3613,8 +3636,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value, - (channel->band == NL80211_BAND_2GHZ) ? - PHY_BAND_24 : PHY_BAND_5, + iwl_mvm_phy_band_from_nl80211(channel->band), PHY_VHT_CHANNEL_MODE20, 0); @@ -3848,7 +3870,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter\n"); mutex_lock(&mvm->mutex); - iwl_mvm_stop_roc(mvm); + iwl_mvm_stop_roc(mvm, vif); mutex_unlock(&mvm->mutex); IWL_DEBUG_MAC80211(mvm, "leave\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5ca50f39a023..735436f5253f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1122,6 +1122,10 @@ struct iwl_mvm { int responses[IWL_MVM_TOF_MAX_APS]; } ftm_initiator; + struct { + u8 d0i3_resp; + } cmd_ver; + struct ieee80211_vif *nan_vif; #define IWL_MAX_BAID 32 struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID]; @@ -1405,12 +1409,19 @@ static inline bool iwl_mvm_is_scan_ext_chan_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER); } + static inline bool iwl_mvm_is_reduced_config_scan_supported(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG); } +static inline bool iwl_mvm_is_band_in_rx_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BAND_IN_RX_DATA); +} + static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, @@ -1682,6 +1693,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); /* Bindings */ @@ -2077,6 +2090,19 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct dentry *dir); #endif +static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band) +{ + switch (band) { + case NL80211_BAND_2GHZ: + return PHY_BAND_24; + case NL80211_BAND_5GHZ: + return PHY_BAND_5; + default: + WARN_ONCE(1, "Unsupported band (%u)\n", band); + return PHY_BAND_5; + } +} + /* Channel info utils */ static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) { @@ -2125,11 +2151,12 @@ iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm, struct iwl_fw_channel_info *ci, struct cfg80211_chan_def *chandef) { + enum nl80211_band band = chandef->chan->band; + iwl_mvm_set_chan_info(mvm, ci, chandef->chan->hw_value, - (chandef->chan->band == NL80211_BAND_2GHZ ? - PHY_BAND_24 : PHY_BAND_5), - iwl_mvm_get_channel_width(chandef), - iwl_mvm_get_ctrl_pos(chandef)); + iwl_mvm_phy_band_from_nl80211(band), + iwl_mvm_get_channel_width(chandef), + iwl_mvm_get_ctrl_pos(chandef)); } #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3acbd5b7ab4b..dcdc195ac1d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -263,6 +263,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, RX_HANDLER_SYNC), + RX_HANDLER_GRP(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF, + iwl_mvm_rx_session_protect_notif, RX_HANDLER_SYNC), RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, RX_HANDLER_ASYNC_LOCKED), @@ -432,6 +434,8 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), + HCMD_NAME(SESSION_PROTECTION_CMD), + HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF), }; @@ -608,6 +612,27 @@ static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .d3_debug_enable = iwl_mvm_d3_debug_enable, }; +static u8 iwl_mvm_lookup_notif_ver(struct iwl_mvm *mvm, u8 grp, u8 cmd, u8 def) +{ + const struct iwl_fw_cmd_version *entry; + unsigned int i; + + if (!mvm->fw->ucode_capa.cmd_versions || + !mvm->fw->ucode_capa.n_cmd_versions) + return def; + + entry = mvm->fw->ucode_capa.cmd_versions; + for (i = 0; i < mvm->fw->ucode_capa.n_cmd_versions; i++, entry++) { + if (entry->group == grp && entry->cmd == cmd) { + if (entry->notif_ver == IWL_FW_CMD_VER_UNKNOWN) + return def; + return entry->notif_ver; + } + } + + return def; +} + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -722,6 +747,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork); + mvm->cmd_ver.d0i3_resp = + iwl_mvm_lookup_notif_ver(mvm, LEGACY_GROUP, D0I3_END_CMD, 0); + /* we only support version 1 */ + if (WARN_ON_ONCE(mvm->cmd_ver.d0i3_resp > 1)) + goto out_free; + /* * Populate the state variables that the transport layer needs * to know about. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 8f50e2b121bd..098d48153a38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -350,7 +350,13 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, u16 size = le32_to_cpu(notif->amsdu_size); int i; - if (WARN_ON(sta->max_amsdu_len < size)) + /* + * In debug sta->max_amsdu_len < size + * so also check with orig_amsdu_len which holds the original + * data before debugfs changed the value + */ + if (WARN_ON(sta->max_amsdu_len < size && + mvmsta->orig_amsdu_len < size)) goto out; mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 428642e66658..7cd62c5622ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -445,10 +445,6 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif -#ifdef CONFIG_MAC80211_DEBUGFS -void rs_remove_sta_debugfs(void *mvm, void *mvm_sta); -#endif - void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta); void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 77b03b757193..b488cd702058 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1542,6 +1542,19 @@ static void iwl_mvm_decode_lsig(struct sk_buff *skb, } } +static inline u8 iwl_mvm_nl80211_band_from_rx_msdu(u8 phy_band) +{ + switch (phy_band) { + case PHY_BAND_24: + return NL80211_BAND_2GHZ; + case PHY_BAND_5: + return NL80211_BAND_5GHZ; + default: + WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band); + return NL80211_BAND_5GHZ; + } +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -1678,8 +1691,14 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, } rx_status->device_timestamp = gp2_on_air_rise; - rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : - NL80211_BAND_2GHZ; + if (iwl_mvm_is_band_in_rx_supported(mvm)) { + u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx); + + rx_status->band = iwl_mvm_nl80211_band_from_rx_msdu(band); + } else { + rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : + NL80211_BAND_2GHZ; + } rx_status->freq = ieee80211_channel_to_frequency(channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index fcafa22ec6ce..0de5cf1c519d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -79,9 +79,6 @@ #define IWL_SCAN_NUM_OF_FRAGS 3 #define IWL_SCAN_LAST_2_4_CHN 14 -#define IWL_SCAN_BAND_5_2 0 -#define IWL_SCAN_BAND_2_4 1 - /* adaptive dwell max budget time [TU] for full scan */ #define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 /* adaptive dwell max budget time [TU] for directed scan */ @@ -196,14 +193,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static __le32 iwl_mvm_scan_rxon_flags(enum nl80211_band band) -{ - if (band == NL80211_BAND_2GHZ) - return cpu_to_le32(PHY_BAND_24); - else - return cpu_to_le32(PHY_BAND_5); -} - static inline __le32 iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band, bool no_cck) @@ -981,6 +970,7 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->fw->ucode_capa.n_scan_channels); u32 ssid_bitmap = 0; int i; + u8 band; lockdep_assert_held(&mvm->mutex); @@ -1000,7 +990,8 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params, vif)); - cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band); + band = iwl_mvm_phy_band_from_nl80211(params->channels[0]->band); + cmd->flags = cpu_to_le32(band); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck); @@ -1426,9 +1417,10 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); channel_cfg[i].v1.channel_num = channels[i]->hw_value; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { + enum nl80211_band band = channels[i]->band; + channel_cfg[i].v2.band = - channels[i]->hw_value <= IWL_SCAN_LAST_2_4_CHN ? - IWL_SCAN_BAND_2_4 : IWL_SCAN_BAND_5_2; + iwl_mvm_phy_band_from_nl80211(band); channel_cfg[i].v2.iter_count = 1; channel_cfg[i].v2.iter_interval = 0; } else { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index a06bc63fb516..51b138673ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -734,6 +734,11 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, return; } +/* + * When the firmware supports the session protection API, + * this is not needed since it'll automatically remove the + * session protection after association + beacon reception. + */ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -757,6 +762,101 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, iwl_mvm_remove_time_event(mvm, mvmvif, te_data); } +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; + struct ieee80211_vif *vif; + + rcu_read_lock(); + vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id), + true); + + if (!vif) + goto out_unlock; + + /* The vif is not a P2P_DEVICE, maintain its time_event_data */ + if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = + &mvmvif->time_event_data; + + if (!le32_to_cpu(notif->status)) { + iwl_mvm_te_check_disconnect(mvm, vif, + "Session protection failure"); + iwl_mvm_te_clear_data(mvm, te_data); + } + + if (le32_to_cpu(notif->start)) { + spin_lock_bh(&mvm->time_event_lock); + te_data->running = le32_to_cpu(notif->start); + te_data->end_jiffies = + TU_TO_EXP_TIME(te_data->duration); + spin_unlock_bh(&mvm->time_event_lock); + } else { + /* + * By now, we should have finished association + * and know the dtim period. + */ + iwl_mvm_te_check_disconnect(mvm, vif, + "No beacon heard and the session protection is over already..."); + iwl_mvm_te_clear_data(mvm, te_data); + } + + goto out_unlock; + } + + if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { + /* End TE, notify mac80211 */ + ieee80211_remain_on_channel_expired(mvm->hw); + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_roc_finished(mvm); + } else if (le32_to_cpu(notif->start)) { + set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + ieee80211_ready_on_channel(mvm->hw); /* Start TE */ + } + + out_unlock: + rcu_read_unlock(); +} + +static int +iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int duration, + enum ieee80211_roc_type type) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + + lockdep_assert_held(&mvm->mutex); + + switch (type) { + case IEEE80211_ROC_TYPE_NORMAL: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV); + break; + case IEEE80211_ROC_TYPE_MGMT_TX: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION); + break; + default: + WARN_ONCE(1, "Got an invalid ROC type\n"); + return -EINVAL; + } + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); +} + int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum ieee80211_roc_type type) { @@ -770,6 +870,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EBUSY; } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + return iwl_mvm_start_p2p_roc_session_protection(mvm, vif, + duration, + type); + time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); @@ -847,11 +953,44 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) __iwl_mvm_remove_time_event(mvm, te_data, &uid); } -void iwl_mvm_stop_roc(struct iwl_mvm *mvm) +static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif) +{ + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + int ret; + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); +} + +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif; struct iwl_mvm_time_event_data *te_data; + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + iwl_mvm_cancel_session_protection(mvm, mvmvif); + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + + iwl_mvm_roc_finished(mvm); + + return; + } + te_data = iwl_mvm_get_roc_te(mvm); if (!te_data) { IWL_WARN(mvm, "No remain on channel event\n"); @@ -916,3 +1055,51 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } + +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + if (te_data->running && + time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { + IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", + jiffies_to_msecs(te_data->end_jiffies - jiffies)); + spin_unlock_bh(&mvm->time_event_lock); + + return; + } + + iwl_mvm_te_clear_data(mvm, te_data); + te_data->duration = le32_to_cpu(cmd.duration_tu); + spin_unlock_bh(&mvm->time_event_lock); + + IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", + le32_to_cpu(cmd.duration_tu)); + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) { + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); + spin_lock_bh(&mvm->time_event_lock); + iwl_mvm_te_clear_data(mvm, te_data); + spin_unlock_bh(&mvm->time_event_lock); + } +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 1dd3d01245ea..df6832b79666 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -178,12 +180,13 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /** * iwl_mvm_stop_roc - stop remain on channel functionality * @mvm: the mvm component + * @vif: the virtual interface for which the roc is stopped * * This function can be used to cancel an ongoing ROC session. * The function is async, it will instruct the FW to stop serving the ROC * session, but will not wait for the actual stopping of the session. */ -void iwl_mvm_stop_roc(struct iwl_mvm *mvm); +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /** * iwl_mvm_remove_time_event - general function to clean up of time event @@ -242,4 +245,20 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) return !!te_data->uid; } +/** + * iwl_mvm_schedule_session_protection - schedule a session protection + * @mvm: the mvm component + * @vif: the virtual interface for which the protection issued + * @duration: the duration of the protection + */ +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration); + +/** + * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF + */ +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); + #endif /* __time_event_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8a059da7a1fa..f4778a6a40b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -341,8 +341,11 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, rate_idx = rate_lowest_index( &mvm->nvm_data->bands[info->band], sta); - /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ - if (info->band == NL80211_BAND_5GHZ) + /* + * For non 2 GHZ band, remap mac80211 rate + * indices into driver indices + */ + if (info->band != NL80211_BAND_2GHZ) rate_idx += IWL_FIRST_OFDM_RATE; /* For 2.4 GHZ band, check that there is no need to remap */ @@ -935,7 +938,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid); + /* + * Take the min of ieee80211 station and mvm station + */ + max_amsdu_len = + min_t(unsigned int, sta->max_amsdu_len, + iwl_mvm_max_amsdu_size(mvm, sta, tid)); /* * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8686107da116..6096276cb0d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -217,7 +217,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, int band_offset = 0; /* Legacy rate format, search for match in table */ - if (band == NL80211_BAND_5GHZ) + if (band != NL80211_BAND_2GHZ) band_offset = IWL_FIRST_OFDM_RATE; for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) if (fw_rate_idx_to_plcp[idx] == rate) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 74980382e64c..a4e09a5b1816 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -55,6 +55,66 @@ #include "internal.h" #include "iwl-prph.h" +static void +iwl_pcie_ctxt_info_dbg_enable(struct iwl_trans *trans, + struct iwl_prph_scratch_hwm_cfg *dbg_cfg, + u32 *control_flags) +{ + enum iwl_fw_ini_allocation_id alloc_id = IWL_FW_INI_ALLOCATION_ID_DBGC1; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 dbg_flags = 0; + + if (!iwl_trans_dbg_ini_valid(trans)) { + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; + + iwl_pcie_alloc_fw_monitor(trans, 0); + + if (fw_mon->size) { + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; + + IWL_DEBUG_FW(trans, + "WRT: Applying DRAM buffer destination\n"); + + dbg_cfg->hwm_base_addr = cpu_to_le64(fw_mon->physical); + dbg_cfg->hwm_size = cpu_to_le32(fw_mon->size); + } + + goto out; + } + + fw_mon_cfg = &trans->dbg.fw_mon_cfg[alloc_id]; + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_SRAM_PATH) { + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL; + + IWL_DEBUG_FW(trans, + "WRT: Applying SMEM buffer destination\n"); + + goto out; + } + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_DRAM_PATH && + trans->dbg.fw_mon_ini[alloc_id].num_frags) { + struct iwl_dram_data *frag = + &trans->dbg.fw_mon_ini[alloc_id].frags[0]; + + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; + + IWL_DEBUG_FW(trans, + "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + dbg_cfg->hwm_base_addr = cpu_to_le64(frag->physical); + dbg_cfg->hwm_size = cpu_to_le32(frag->size); + } + +out: + if (dbg_flags) + *control_flags |= IWL_PRPH_SCRATCH_EARLY_DEBUG_EN | dbg_flags; +} + int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, const struct fw_img *fw) { @@ -86,24 +146,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, control_flags = IWL_PRPH_SCRATCH_RB_SIZE_4K | IWL_PRPH_SCRATCH_MTR_MODE | (IWL_PRPH_MTR_FORMAT_256B & - IWL_PRPH_SCRATCH_MTR_FORMAT) | - IWL_PRPH_SCRATCH_EARLY_DEBUG_EN | - IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; - prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags); + IWL_PRPH_SCRATCH_MTR_FORMAT); /* initialize RX default queue */ prph_sc_ctrl->rbd_cfg.free_rbd_addr = cpu_to_le64(trans_pcie->rxq->bd_dma); - /* Configure debug, for integration */ - if (!iwl_trans_dbg_ini_valid(trans)) - iwl_pcie_alloc_fw_monitor(trans, 0); - if (trans->dbg.num_blocks) { - prph_sc_ctrl->hwm_cfg.hwm_base_addr = - cpu_to_le64(trans->dbg.fw_mon[0].physical); - prph_sc_ctrl->hwm_cfg.hwm_size = - cpu_to_le32(trans->dbg.fw_mon[0].size); - } + iwl_pcie_ctxt_info_dbg_enable(trans, &prph_sc_ctrl->hwm_cfg, + &control_flags); + prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags); /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 6961f00ff812..6aa89d9ea72c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -190,32 +190,36 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) { - int i; + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; - for (i = 0; i < trans->dbg.num_blocks; i++) { - dma_free_coherent(trans->dev, trans->dbg.fw_mon[i].size, - trans->dbg.fw_mon[i].block, - trans->dbg.fw_mon[i].physical); - trans->dbg.fw_mon[i].block = NULL; - trans->dbg.fw_mon[i].physical = 0; - trans->dbg.fw_mon[i].size = 0; - trans->dbg.num_blocks--; - } + if (!fw_mon->size) + return; + + dma_free_coherent(trans->dev, fw_mon->size, fw_mon->block, + fw_mon->physical); + + fw_mon->block = NULL; + fw_mon->physical = 0; + fw_mon->size = 0; } static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, u8 max_power, u8 min_power) { - void *cpu_addr = NULL; - dma_addr_t phys = 0; + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; + void *block = NULL; + dma_addr_t physical = 0; u32 size = 0; u8 power; + if (fw_mon->size) + return; + for (power = max_power; power >= min_power; power--) { size = BIT(power); - cpu_addr = dma_alloc_coherent(trans->dev, size, &phys, - GFP_KERNEL | __GFP_NOWARN); - if (!cpu_addr) + block = dma_alloc_coherent(trans->dev, size, &physical, + GFP_KERNEL | __GFP_NOWARN); + if (!block) continue; IWL_INFO(trans, @@ -224,7 +228,7 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, break; } - if (WARN_ON_ONCE(!cpu_addr)) + if (WARN_ON_ONCE(!block)) return; if (power != max_power) @@ -233,10 +237,9 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, (unsigned long)BIT(power - 10), (unsigned long)BIT(max_power - 10)); - trans->dbg.fw_mon[trans->dbg.num_blocks].block = cpu_addr; - trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys; - trans->dbg.fw_mon[trans->dbg.num_blocks].size = size; - trans->dbg.num_blocks++; + fw_mon->block = block; + fw_mon->physical = physical; + fw_mon->size = size; } void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) @@ -253,11 +256,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) max_power)) return; - /* - * This function allocats the default fw monitor. - * The optional additional ones will be allocated in runtime - */ - if (trans->dbg.num_blocks) + if (trans->dbg.fw_mon.size) return; iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11); @@ -891,24 +890,51 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, return 0; } +static void iwl_pcie_apply_destination_ini(struct iwl_trans *trans) +{ + enum iwl_fw_ini_allocation_id alloc_id = IWL_FW_INI_ALLOCATION_ID_DBGC1; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg = + &trans->dbg.fw_mon_cfg[alloc_id]; + struct iwl_dram_data *frag; + + if (!iwl_trans_dbg_ini_valid(trans)) + return; + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_SRAM_PATH) { + IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n"); + /* set sram monitor by enabling bit 7 */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM); + + return; + } + + if (le32_to_cpu(fw_mon_cfg->buf_location) != + IWL_FW_INI_LOCATION_DRAM_PATH || + !trans->dbg.fw_mon_ini[alloc_id].num_frags) + return; + + frag = &trans->dbg.fw_mon_ini[alloc_id].frags[0]; + + IWL_DEBUG_FW(trans, "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, + frag->physical >> MON_BUFF_SHIFT_VER2); + iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, + (frag->physical + frag->size - 256) >> + MON_BUFF_SHIFT_VER2); +} + void iwl_pcie_apply_destination(struct iwl_trans *trans) { const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg.dest_tlv; + const struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; int i; if (iwl_trans_dbg_ini_valid(trans)) { - if (!trans->dbg.num_blocks) - return; - - IWL_DEBUG_FW(trans, - "WRT: Applying DRAM buffer[0] destination\n"); - iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, - trans->dbg.fw_mon[0].physical >> - MON_BUFF_SHIFT_VER2); - iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size - 256) >> - MON_BUFF_SHIFT_VER2); + iwl_pcie_apply_destination_ini(trans); return; } @@ -959,20 +985,17 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) } monitor: - if (dest->monitor_mode == EXTERNAL_MODE && trans->dbg.fw_mon[0].size) { + if (dest->monitor_mode == EXTERNAL_MODE && fw_mon->size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), - trans->dbg.fw_mon[0].physical >> - dest->base_shift); + fw_mon->physical >> dest->base_shift); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size - 256) >> - dest->end_shift); + (fw_mon->physical + fw_mon->size - + 256) >> dest->end_shift); else iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size) >> - dest->end_shift); + (fw_mon->physical + fw_mon->size) >> + dest->end_shift); } } @@ -1006,14 +1029,14 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, /* supported for 7000 only for the moment */ if (iwlwifi_mod_params.fw_monitor && trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_pcie_alloc_fw_monitor(trans, 0); + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; - if (trans->dbg.fw_mon[0].size) { + iwl_pcie_alloc_fw_monitor(trans, 0); + if (fw_mon->size) { iwl_write_prph(trans, MON_BUFF_BASE_ADDR, - trans->dbg.fw_mon[0].physical >> 4); + fw_mon->physical >> 4); iwl_write_prph(trans, MON_BUFF_END_ADDR, - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size) >> 4); + (fw_mon->physical + fw_mon->size) >> 4); } } else if (iwl_pcie_dbg_on(trans)) { iwl_pcie_apply_destination(trans); @@ -2801,7 +2824,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, { struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - void *cpu_addr = (void *)trans->dbg.fw_mon[0].block, *curr_buf; + void *cpu_addr = (void *)trans->dbg.fw_mon.block, *curr_buf; struct cont_rec *data = &trans_pcie->fw_mon_data; u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt; ssize_t size, bytes_copied = 0; @@ -2840,7 +2863,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, } else if (data->prev_wrap_cnt == wrap_cnt - 1 && write_ptr < data->prev_wr_ptr) { - size = trans->dbg.fw_mon[0].size - data->prev_wr_ptr; + size = trans->dbg.fw_mon.size - data->prev_wr_ptr; curr_buf = cpu_addr + data->prev_wr_ptr; b_full = iwl_write_to_user_buf(user_buf, count, curr_buf, &size, @@ -3087,10 +3110,11 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, struct iwl_fw_error_dump_data **data, u32 monitor_len) { + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; u32 len = 0; if (trans->dbg.dest_tlv || - (trans->dbg.num_blocks && + (fw_mon->size && (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000 || trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210))) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; @@ -3101,12 +3125,9 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, iwl_trans_pcie_dump_pointers(trans, fw_mon_data); len += sizeof(**data) + sizeof(*fw_mon_data); - if (trans->dbg.num_blocks) { - memcpy(fw_mon_data->data, - trans->dbg.fw_mon[0].block, - trans->dbg.fw_mon[0].size); - - monitor_len = trans->dbg.fw_mon[0].size; + if (fw_mon->size) { + memcpy(fw_mon_data->data, fw_mon->block, fw_mon->size); + monitor_len = fw_mon->size; } else if (trans->dbg.dest_tlv->monitor_mode == SMEM_MODE) { u32 base = le32_to_cpu(fw_mon_data->fw_mon_base_ptr); /* @@ -3145,11 +3166,11 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len) { - if (trans->dbg.num_blocks) { + if (trans->dbg.fw_mon.size) { *len += sizeof(struct iwl_fw_error_dump_data) + sizeof(struct iwl_fw_error_dump_fw_mon) + - trans->dbg.fw_mon[0].size; - return trans->dbg.fw_mon[0].size; + trans->dbg.fw_mon.size; + return trans->dbg.fw_mon.size; } else if (trans->dbg.dest_tlv) { u32 base, end, cfg_reg, monitor_len; @@ -3604,6 +3625,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, mutex_init(&trans_pcie->fw_mon_data.mutex); #endif + iwl_dbg_tlv_init(trans); + return trans; out_free_ict: diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 242d8845da3f..30f1025ecb9b 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1179,6 +1179,10 @@ static int if_sdio_probe(struct sdio_func *func, spin_lock_init(&card->lock); card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0); + if (unlikely(!card->workqueue)) { + ret = -ENOMEM; + goto err_queue; + } INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); init_waitqueue_head(&card->pwron_waitq); @@ -1230,6 +1234,7 @@ err_activate_card: lbs_remove_card(priv); free: destroy_workqueue(card->workqueue); +err_queue: while (card->packets) { packet = card->packets; card->packets = card->packets->next; diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index 2747c957d18c..44c8a550da4c 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -1003,7 +1003,6 @@ static int lbs_add_mesh(struct lbs_private *priv) if (priv->mesh_tlv) { sprintf(mesh_wdev->ssid, "mesh"); mesh_wdev->mesh_id_up_len = 4; - ret = 1; } mesh_wdev->netdev = mesh_dev; diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index eff06d59e9df..fc1706d0647d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -687,8 +687,11 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) skb_put(skb, MAX_EVENT_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); + kfree(card->evtbd_ring_vbase); return -1; + } buf_pa = MWIFIEX_SKB_DMA_ADDR(skb); @@ -1029,8 +1032,10 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) } skb_put(skb, MWIFIEX_UPLD_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); return -1; + } card->cmdrsp_buf = skb; diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 593c594982cb..98f942b797f7 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1270,7 +1270,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_FH_PARAMS: - if (element_len + 2 < sizeof(*fh_param_set)) + if (total_ie_len < sizeof(*fh_param_set)) return -EINVAL; fh_param_set = (struct ieee_types_fh_param_set *) current_ptr; @@ -1280,7 +1280,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_DS_PARAMS: - if (element_len + 2 < sizeof(*ds_param_set)) + if (total_ie_len < sizeof(*ds_param_set)) return -EINVAL; ds_param_set = (struct ieee_types_ds_param_set *) current_ptr; @@ -1293,7 +1293,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_CF_PARAMS: - if (element_len + 2 < sizeof(*cf_param_set)) + if (total_ie_len < sizeof(*cf_param_set)) return -EINVAL; cf_param_set = (struct ieee_types_cf_param_set *) current_ptr; @@ -1303,7 +1303,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_IBSS_PARAMS: - if (element_len + 2 < sizeof(*ibss_param_set)) + if (total_ie_len < sizeof(*ibss_param_set)) return -EINVAL; ibss_param_set = (struct ieee_types_ibss_param_set *) @@ -1460,10 +1460,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; } - current_ptr += element_len + 2; - - /* Need to account for IE ID and IE Len */ - bytes_left -= (element_len + 2); + current_ptr += total_ie_len; + bytes_left -= total_ie_len; } /* while (bytes_left > 2) */ return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index 92305bd31aa1..4209209ac940 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -77,10 +77,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { if (vif_idx == i) { force_update = !!dev->beacons[i] ^ !!skb; - - if (dev->beacons[i]) - dev_kfree_skb(dev->beacons[i]); - + dev_kfree_skb(dev->beacons[i]); dev->beacons[i] = skb; __mt76x02_mac_set_beacon(dev, bcn_idx, skb); } else if (force_update && dev->beacons[i]) { diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index 5e549831370c..300242bce799 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -27,7 +27,7 @@ mt76_reg_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); static int mt7601u_ampdu_stat_read(struct seq_file *file, void *data) diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 06f5702ab4bd..d863ab4a66c9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -213,7 +213,7 @@ int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) do { val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); - if (val && ~val) + if (val && val != 0xff) break; } while (--i); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 3aa3714d4dfd..5ec1c9bc1612 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -244,8 +244,6 @@ static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps) /* tx bd */ - memset(vaddr, 0, len); - ps->bd_table_vaddr = vaddr; ps->bd_table_paddr = paddr; ps->bd_table_len = len; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index 9a4380ed7f1b..1f91088e3dff 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -199,8 +199,6 @@ static int topaz_alloc_bd_table(struct qtnf_pcie_topaz_state *ts, if (!vaddr) return -ENOMEM; - memset(vaddr, 0, len); - /* tx bd */ ts->tx_bd_vbase = vaddr; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index ade057d868f7..6598c8d786ea 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1187,6 +1187,79 @@ struct rtl8723bu_c2h { struct rtl8xxxu_fileops; +/*mlme related.*/ +enum wireless_mode { + WIRELESS_MODE_UNKNOWN = 0, + /* Sub-Element */ + WIRELESS_MODE_B = BIT(0), + WIRELESS_MODE_G = BIT(1), + WIRELESS_MODE_A = BIT(2), + WIRELESS_MODE_N_24G = BIT(3), + WIRELESS_MODE_N_5G = BIT(4), + WIRELESS_AUTO = BIT(5), + WIRELESS_MODE_AC = BIT(6), + WIRELESS_MODE_MAX = 0x7F, +}; + +/* from rtlwifi/wifi.h */ +enum ratr_table_mode_new { + RATEID_IDX_BGN_40M_2SS = 0, + RATEID_IDX_BGN_40M_1SS = 1, + RATEID_IDX_BGN_20M_2SS_BN = 2, + RATEID_IDX_BGN_20M_1SS_BN = 3, + RATEID_IDX_GN_N2SS = 4, + RATEID_IDX_GN_N1SS = 5, + RATEID_IDX_BG = 6, + RATEID_IDX_G = 7, + RATEID_IDX_B = 8, + RATEID_IDX_VHT_2SS = 9, + RATEID_IDX_VHT_1SS = 10, + RATEID_IDX_MIX1 = 11, + RATEID_IDX_MIX2 = 12, + RATEID_IDX_VHT_3SS = 13, + RATEID_IDX_BGN_3SS = 14, +}; + +#define BT_INFO_8723B_1ANT_B_FTP BIT(7) +#define BT_INFO_8723B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8723B_1ANT_B_HID BIT(5) +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT(0) + +enum _BT_8723B_1ANT_STATUS { + BT_8723B_1ANT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_STATUS_MAX +}; + +struct rtl8xxxu_btcoex { + u8 bt_status; + bool bt_busy; + bool has_sco; + bool has_a2dp; + bool has_hid; + bool has_pan; + bool hid_only; + bool a2dp_only; + bool c2h_bt_inquiry; +}; + +#define RTL8XXXU_RATR_STA_INIT 0 +#define RTL8XXXU_RATR_STA_HIGH 1 +#define RTL8XXXU_RATR_STA_MID 2 +#define RTL8XXXU_RATR_STA_LOW 3 + +#define RTL8XXXU_NOISE_FLOOR_MIN -100 +#define RTL8XXXU_SNR_THRESH_HIGH 50 +#define RTL8XXXU_SNR_THRESH_LOW 20 + struct rtl8xxxu_priv { struct ieee80211_hw *hw; struct usb_device *udev; @@ -1291,6 +1364,17 @@ struct rtl8xxxu_priv { u8 pi_enabled:1; u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; + u8 rssi_level; + /* + * Only one virtual interface permitted because only STA mode + * is supported and no iface_combinations are provided. + */ + struct ieee80211_vif *vif; + struct delayed_work ra_watchdog; + struct work_struct c2hcmd_work; + struct sk_buff_head c2hcmd_queue; + spinlock_t c2hcmd_lock; + struct rtl8xxxu_btcoex bt_coex; }; struct rtl8xxxu_rx_urb { @@ -1326,7 +1410,7 @@ struct rtl8xxxu_fileops { void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel, bool ht40); void (*update_rate_mask) (struct rtl8xxxu_priv *priv, - u32 ramask, int sgi); + u32 ramask, u8 rateid, int sgi); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, @@ -1341,6 +1425,7 @@ struct rtl8xxxu_fileops { u8 has_s0s1:1; u8 has_tx_report:1; u8 gen2_thermal_meter:1; + u8 needs_full_init:1; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; @@ -1411,9 +1496,9 @@ void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen2_usb_quirks(struct rtl8xxxu_priv *priv); void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi); + u32 ramask, u8 rateid, int sgi); void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi); + u32 ramask, u8 rateid, int sgi); void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, @@ -1437,6 +1522,8 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, u32 rts_rate); +void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); extern struct rtl8xxxu_fileops rtl8192cu_fops; extern struct rtl8xxxu_fileops rtl8192eu_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index c747f6a1922d..9f1f93d04145 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1011,7 +1011,7 @@ static void rtl8192eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok, path_b_ok; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -1021,11 +1021,11 @@ static void rtl8192eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index ceffe05bd65b..a71e1816e632 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -882,7 +882,7 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok /*, path_b_ok */; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -892,11 +892,11 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, @@ -1580,9 +1580,7 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) /* * Software control, antenna at WiFi side */ -#ifdef NEED_PS_TDMA rtl8723bu_set_ps_tdma(priv, 0x08, 0x00, 0x00, 0x00, 0x00); -#endif rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); @@ -1670,6 +1668,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .has_s0s1 = 1, .has_tx_report = 1, .gen2_thermal_meter = 1, + .needs_full_init = 1, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, .adda_2t_path_on_a = 0x01c00014, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index c6c41fb962ff..bcb92831d376 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3115,7 +3115,7 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok, path_b_ok; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -3125,11 +3125,11 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, @@ -3820,9 +3820,8 @@ void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } -#ifdef NEED_PS_TDMA -static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, - u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) +void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) { struct h2c_cmd h2c; @@ -3835,7 +3834,6 @@ static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, h2c.b_type_dma.data5 = arg5; rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma)); } -#endif void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv) { @@ -3902,6 +3900,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) else macpower = true; + if (fops->needs_full_init) + macpower = false; + ret = fops->power_on(priv); if (ret < 0) { dev_warn(dev, "%s: Failed power on\n", __func__); @@ -4304,7 +4305,8 @@ static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw, rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); } -void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, int sgi) +void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, u8 rateid, int sgi) { struct h2c_cmd h2c; @@ -4324,7 +4326,7 @@ void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, int sgi) } void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi) + u32 ramask, u8 rateid, int sgi) { struct h2c_cmd h2c; u8 bw = 0; @@ -4338,7 +4340,7 @@ void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, h2c.b_macid_cfg.ramask3 = (ramask >> 24) & 0xff; h2c.ramask.arg = 0x80; - h2c.b_macid_cfg.data1 = 0; + h2c.b_macid_cfg.data1 = rateid; if (sgi) h2c.b_macid_cfg.data1 |= BIT(7); @@ -4478,6 +4480,35 @@ static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); } +static u16 +rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) +{ + u16 network_type = WIRELESS_MODE_UNKNOWN; + + if (hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) { + if (sta->vht_cap.vht_supported) + network_type = WIRELESS_MODE_AC; + else if (sta->ht_cap.ht_supported) + network_type = WIRELESS_MODE_N_5G; + + network_type |= WIRELESS_MODE_A; + } else { + if (sta->vht_cap.vht_supported) + network_type = WIRELESS_MODE_AC; + else if (sta->ht_cap.ht_supported) + network_type = WIRELESS_MODE_N_24G; + + if (sta->supp_rates[0] <= 0xf) + network_type |= WIRELESS_MODE_B; + else if (sta->supp_rates[0] & 0xf) + network_type |= (WIRELESS_MODE_B | WIRELESS_MODE_G); + else + network_type |= WIRELESS_MODE_G; + } + + return network_type; +} + static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -4520,7 +4551,10 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sgi = 1; rcu_read_unlock(); - priv->fops->update_rate_mask(priv, ramask, sgi); + priv->vif = vif; + priv->rssi_level = RTL8XXXU_RATR_STA_INIT; + + priv->fops->update_rate_mask(priv, ramask, 0, sgi); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -5148,12 +5182,269 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) } } +/* + * The RTL8723BU/RTL8192EU vendor driver use coexistence table type + * 0-7 to represent writing different combinations of register values + * to REG_BT_COEX_TABLEs. It's for different kinds of coexistence use + * cases which Realtek doesn't provide detail for these settings. Keep + * this aligned with vendor driver for easier maintenance. + */ +static +void rtl8723bu_set_coex_with_type(struct rtl8xxxu_priv *priv, u8 type) +{ + switch (type) { + case 0: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 1: + case 3: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 2: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 4: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaa5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 5: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaa5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 6: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 7: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + default: + break; + } +} + +static +void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) +{ + struct rtl8xxxu_btcoex *btcoex = &priv->bt_coex; + + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) + btcoex->c2h_bt_inquiry = true; + else + btcoex->c2h_bt_inquiry = false; + + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { + btcoex->bt_status = BT_8723B_1ANT_STATUS_NON_CONNECTED_IDLE; + btcoex->has_sco = false; + btcoex->has_hid = false; + btcoex->has_pan = false; + btcoex->has_a2dp = false; + } else { + if ((bt_info & 0x1f) == BT_INFO_8723B_1ANT_B_CONNECTION) + btcoex->bt_status = BT_8723B_1ANT_STATUS_CONNECTED_IDLE; + else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) + btcoex->bt_status = BT_8723B_1ANT_STATUS_SCO_BUSY; + else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) + btcoex->bt_status = BT_8723B_1ANT_STATUS_ACL_BUSY; + else + btcoex->bt_status = BT_8723B_1ANT_STATUS_MAX; + + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + btcoex->has_pan = true; + else + btcoex->has_pan = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + btcoex->has_a2dp = true; + else + btcoex->has_a2dp = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_HID) + btcoex->has_hid = true; + else + btcoex->has_hid = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + btcoex->has_sco = true; + else + btcoex->has_sco = false; + } + + if (!btcoex->has_a2dp && !btcoex->has_sco && + !btcoex->has_pan && btcoex->has_hid) + btcoex->hid_only = true; + else + btcoex->hid_only = false; + + if (!btcoex->has_sco && !btcoex->has_pan && + !btcoex->has_hid && btcoex->has_a2dp) + btcoex->has_a2dp = true; + else + btcoex->has_a2dp = false; + + if (btcoex->bt_status == BT_8723B_1ANT_STATUS_SCO_BUSY || + btcoex->bt_status == BT_8723B_1ANT_STATUS_ACL_BUSY) + btcoex->bt_busy = true; + else + btcoex->bt_busy = false; +} + +static +void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_btcoex *btcoex; + bool wifi_connected; + + vif = priv->vif; + btcoex = &priv->bt_coex; + wifi_connected = (vif && vif->bss_conf.assoc); + + if (!wifi_connected) { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 0); + } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else if (btcoex->has_pan) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x3f, 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 7); + } +} + +static +void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_btcoex *btcoex; + bool wifi_connected; + + vif = priv->vif; + btcoex = &priv->bt_coex; + wifi_connected = (vif && vif->bss_conf.assoc); + + if (wifi_connected) { + u32 val32 = 0; + u32 high_prio_tx = 0, high_prio_rx = 0; + + val32 = rtl8xxxu_read32(priv, 0x770); + high_prio_tx = val32 & 0x0000ffff; + high_prio_rx = (val32 & 0xffff0000) >> 16; + + if (btcoex->bt_busy) { + if (btcoex->hid_only) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x20, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 5); + } else if (btcoex->a2dp_only) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else if ((btcoex->has_a2dp && btcoex->has_pan) || + (btcoex->has_hid && btcoex->has_a2dp && + btcoex->has_pan)) { + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, + 0x3, 0x10, 0x10); + rtl8723bu_set_coex_with_type(priv, 4); + } else if (btcoex->has_hid && btcoex->has_a2dp) { + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, + 0x3, 0x10, 0x10); + rtl8723bu_set_coex_with_type(priv, 3); + } else { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + if (high_prio_tx + high_prio_rx <= 60) + rtl8723bu_set_coex_with_type(priv, 2); + else + rtl8723bu_set_coex_with_type(priv, 7); + } + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 0); + } +} + +static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv; + struct rtl8723bu_c2h *c2h; + struct ieee80211_vif *vif; + struct device *dev; + struct sk_buff *skb = NULL; + unsigned long flags; + int len; + u8 bt_info = 0; + struct rtl8xxxu_btcoex *btcoex; + + priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); + vif = priv->vif; + btcoex = &priv->bt_coex; + dev = &priv->udev->dev; + + if (priv->rf_paths > 1) + goto out; + + while (!skb_queue_empty(&priv->c2hcmd_queue)) { + spin_lock_irqsave(&priv->c2hcmd_lock, flags); + skb = __skb_dequeue(&priv->c2hcmd_queue); + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); + + c2h = (struct rtl8723bu_c2h *)skb->data; + len = skb->len - 2; + + switch (c2h->id) { + case C2H_8723B_BT_INFO: + bt_info = c2h->bt_info.bt_info; + + rtl8723bu_update_bt_link_info(priv, bt_info); + if (btcoex->c2h_bt_inquiry) { + rtl8723bu_handle_bt_inquiry(priv); + break; + } + rtl8723bu_handle_bt_info(priv); + break; + default: + break; + } + } + +out: + dev_kfree_skb(skb); +} + static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; struct device *dev = &priv->udev->dev; int len; + unsigned long flags; len = skb->len - 2; @@ -5191,6 +5482,12 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, 16, 1, c2h->raw.payload, len, false); break; } + + spin_lock_irqsave(&priv->c2hcmd_lock, flags); + __skb_queue_tail(&priv->c2hcmd_queue, skb); + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); + + schedule_work(&priv->c2hcmd_work); } int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) @@ -5315,7 +5612,6 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) struct device *dev = &priv->udev->dev; dev_dbg(dev, "%s: C2H packet\n", __func__); rtl8723bu_handle_c2h(priv, skb); - dev_kfree_skb(skb); return RX_TYPE_C2H; } @@ -5444,6 +5740,7 @@ static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw) ret = usb_submit_urb(urb, GFP_KERNEL); if (ret) { usb_unanchor_urb(urb); + usb_free_urb(urb); goto error; } @@ -5464,6 +5761,10 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: + if (!priv->vif) + priv->vif = vif; + else + return -EOPNOTSUPP; rtl8xxxu_stop_tx_beacon(priv); val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); @@ -5487,6 +5788,9 @@ static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, struct rtl8xxxu_priv *priv = hw->priv; dev_dbg(&priv->udev->dev, "%s\n", __func__); + + if (priv->vif) + priv->vif = NULL; } static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) @@ -5772,6 +6076,178 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } +static u8 rtl8xxxu_signal_to_snr(int signal) +{ + if (signal < RTL8XXXU_NOISE_FLOOR_MIN) + signal = RTL8XXXU_NOISE_FLOOR_MIN; + else if (signal > 0) + signal = 0; + return (u8)(signal - RTL8XXXU_NOISE_FLOOR_MIN); +} + +static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, + int signal, struct ieee80211_sta *sta) +{ + struct ieee80211_hw *hw = priv->hw; + u16 wireless_mode; + u8 rssi_level, ratr_idx; + u8 txbw_40mhz; + u8 snr, snr_thresh_high, snr_thresh_low; + u8 go_up_gap = 5; + + rssi_level = priv->rssi_level; + snr = rtl8xxxu_signal_to_snr(signal); + snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH; + snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW; + txbw_40mhz = (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) ? 1 : 0; + + switch (rssi_level) { + case RTL8XXXU_RATR_STA_MID: + snr_thresh_high += go_up_gap; + break; + case RTL8XXXU_RATR_STA_LOW: + snr_thresh_high += go_up_gap; + snr_thresh_low += go_up_gap; + break; + default: + break; + } + + if (snr > snr_thresh_high) + rssi_level = RTL8XXXU_RATR_STA_HIGH; + else if (snr > snr_thresh_low) + rssi_level = RTL8XXXU_RATR_STA_MID; + else + rssi_level = RTL8XXXU_RATR_STA_LOW; + + if (rssi_level != priv->rssi_level) { + int sgi = 0; + u32 rate_bitmap = 0; + + rcu_read_lock(); + rate_bitmap = (sta->supp_rates[0] & 0xfff) | + (sta->ht_cap.mcs.rx_mask[0] << 12) | + (sta->ht_cap.mcs.rx_mask[1] << 20); + if (sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) + sgi = 1; + rcu_read_unlock(); + + wireless_mode = rtl8xxxu_wireless_mode(hw, sta); + switch (wireless_mode) { + case WIRELESS_MODE_B: + ratr_idx = RATEID_IDX_B; + if (rate_bitmap & 0x0000000c) + rate_bitmap &= 0x0000000d; + else + rate_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_A: + case WIRELESS_MODE_G: + ratr_idx = RATEID_IDX_G; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else + rate_bitmap &= 0x00000ff0; + break; + case (WIRELESS_MODE_B | WIRELESS_MODE_G): + ratr_idx = RATEID_IDX_BG; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else if (rssi_level == RTL8XXXU_RATR_STA_MID) + rate_bitmap &= 0x00000ff0; + else + rate_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + case (WIRELESS_MODE_G | WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_A | WIRELESS_MODE_N_5G): + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_GN_N2SS; + else + ratr_idx = RATEID_IDX_GN_N1SS; + break; + case (WIRELESS_MODE_B | WIRELESS_MODE_G | WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_B | WIRELESS_MODE_N_24G): + if (txbw_40mhz) { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_BGN_40M_2SS; + else + ratr_idx = RATEID_IDX_BGN_40M_1SS; + } else { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_BGN_20M_2SS_BN; + else + ratr_idx = RATEID_IDX_BGN_20M_1SS_BN; + } + + if (priv->tx_paths == 2 && priv->rx_paths == 2) { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { + rate_bitmap &= 0x0f8f0000; + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { + rate_bitmap &= 0x0f8ff000; + } else { + if (txbw_40mhz) + rate_bitmap &= 0x0f8ff015; + else + rate_bitmap &= 0x0f8ff005; + } + } else { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { + rate_bitmap &= 0x000f0000; + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { + rate_bitmap &= 0x000ff000; + } else { + if (txbw_40mhz) + rate_bitmap &= 0x000ff015; + else + rate_bitmap &= 0x000ff005; + } + } + break; + default: + ratr_idx = RATEID_IDX_BGN_40M_2SS; + rate_bitmap &= 0x0fffffff; + break; + } + + priv->rssi_level = rssi_level; + priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi); + } +} + +static void rtl8xxxu_watchdog_callback(struct work_struct *work) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_priv *priv; + + priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); + vif = priv->vif; + + if (vif && vif->type == NL80211_IFTYPE_STATION) { + int signal; + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) { + struct device *dev = &priv->udev->dev; + + dev_dbg(dev, "%s: no sta found\n", __func__); + rcu_read_unlock(); + goto out; + } + rcu_read_unlock(); + + signal = ieee80211_ave_rssi(vif); + rtl8xxxu_refresh_rate_mask(priv, signal, sta); + } + +out: + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); +} + static int rtl8xxxu_start(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -5828,6 +6304,8 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); } + + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); exit: /* * Accept all data and mgmt frames @@ -5879,6 +6357,8 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) if (priv->usb_interrupts) rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + cancel_delayed_work_sync(&priv->ra_watchdog); + rtl8xxxu_free_rx_resources(priv); rtl8xxxu_free_tx_resources(priv); } @@ -6051,6 +6531,10 @@ static int rtl8xxxu_probe(struct usb_interface *interface, INIT_LIST_HEAD(&priv->rx_urb_pending_list); spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); + INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); + spin_lock_init(&priv->c2hcmd_lock); + INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); + skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 3ebc7c93b1e9..3c96c320236c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -1578,10 +1578,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, { struct rtl_priv *rtlpriv = btcoexist->adapter; static int up, dn, m, n, wait_cnt; - /* 0: no change, +1: increase WiFi duration, - * -1: decrease WiFi duration - */ - int result; u8 retry_cnt = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -1669,7 +1665,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, dn = 0; m = 1; n = 3; - result = 0; wait_cnt = 0; } else { /* accquire the BT TRx retry count from BT_Info byte2 */ @@ -1679,7 +1674,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n", up, dn, m, n, wait_cnt); - result = 0; wait_cnt++; /* no retry in the last 2-second duration */ if (retry_cnt == 0) { @@ -1694,7 +1688,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, n = 3; up = 0; dn = 0; - result = 1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex]Increase wifi duration!!\n"); } @@ -1718,7 +1711,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, up = 0; dn = 0; wait_cnt = 0; - result = -1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "Reduce wifi duration for retry<3\n"); } @@ -1735,7 +1727,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, up = 0; dn = 0; wait_cnt = 0; - result = -1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "Decrease wifi duration for retryCounter>3!!\n"); } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 5f5739904edf..528e442f25a4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1424,17 +1424,11 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, * -1: decrease WiFi duration */ s32 result; - u8 retry_count = 0, bt_info_ext; - bool wifi_busy = false; + u8 retry_count = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], TdmaDurationAdjustForAcl()\n"); - if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY) - wifi_busy = true; - else - wifi_busy = false; - if ((wifi_status == BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN) || (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN) || @@ -1472,7 +1466,6 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, } else { /* acquire the BT TRx retry count from BT_Info byte2 */ retry_count = coex_sta->bt_retry_cnt; - bt_info_ext = coex_sta->bt_info_ext; if ((coex_sta->low_priority_tx) > 1050 || (coex_sta->low_priority_rx) > 1250) diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 264667203f6f..cef9f2a9303b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -915,7 +915,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int continual = true, dataempty = true, result = true; + int continual = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -942,7 +942,6 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, while (continual && (efuse_addr < (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { if (write_state == PG_STATE_HEADER) { - dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER\n"); @@ -1179,13 +1178,12 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) { int continual = true; u16 efuse_addr = 0; - u8 hoffset, hworden; + u8 hworden; u8 efuse_data, word_cnts; while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { - hoffset = (efuse_data >> 4) & 0x0F; hworden = efuse_data & 0x0F; word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index fff8dda14023..e5e1ec5a41dc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -68,7 +68,6 @@ static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - enum rf_pwrstate rtstate; bool actionallowed = false; u16 rfwait_cnt = 0; @@ -102,8 +101,6 @@ static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, } } - rtstate = ppsc->rfpwr_state; - switch (state_toset) { case ERFON: ppsc->rfoff_reason &= (~changesource); @@ -161,8 +158,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && - rtlhal->interface == INTF_PCI) { + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { rtlpriv->intf_ops->disable_aspm(hw); RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index c10432cd703e..8be31e0ad878 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -386,7 +386,7 @@ int rtl_regd_init(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; struct country_code_to_enum_rd *country = NULL; - if (wiphy == NULL || &rtlpriv->regd == NULL) + if (!wiphy) return -EINVAL; /* init country_code from efuse channel plan */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c index 333e355c9281..dceb04a9b3f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c @@ -759,14 +759,8 @@ static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw) rtlpriv->dm.entry_min_undec_sm_pwdb = 0; } /* Indicate Rx signal strength to FW. */ - if (rtlpriv->dm.useramask) { - u8 h2c_parameter[3] = { 0 }; - - h2c_parameter[2] = (u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF); - h2c_parameter[0] = 0x20; - } else { + if (!rtlpriv->dm.useramask) rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb); - } } void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c index 96d8f25b120f..978e6a169654 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c @@ -649,7 +649,7 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) int i; u32 *phy_reg_page; u16 phy_reg_page_len; - u32 v1 = 0, v2 = 0, v3 = 0; + u32 v1 = 0, v2 = 0; phy_reg_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN; phy_reg_page = RTL8188EEPHY_REG_ARRAY_PG; @@ -658,7 +658,6 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) for (i = 0; i < phy_reg_page_len; i = i + 3) { v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; if (v1 < 0xcdcdcdcd) { if (phy_reg_page[i] == 0xfe) @@ -689,13 +688,11 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; while (v2 != 0xDEAD && i < phy_reg_page_len - 5) { i += 3; v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; } } } @@ -769,7 +766,6 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { struct rtl_priv *rtlpriv = rtl_priv(hw); - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; @@ -778,7 +774,6 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", radioa_arraylen); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: process_path_a(hw, radioa_arraylen, radioa_array_table); @@ -1940,9 +1935,9 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) struct rtl_phy *rtlphy = &rtlpriv->phy; long result[4][8]; u8 i, final_candidate; - bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + bool b_patha_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[9] = { ROFDM0_XARXIQIMBALANCE, @@ -1971,7 +1966,6 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) } final_candidate = 0xff; b_patha_ok = false; - b_pathb_ok = false; is12simular = false; is23simular = false; is13simular = false; @@ -2014,27 +2008,20 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; - reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { reg_e94 = result[final_candidate][0]; reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; reg_ebc = result[final_candidate][5]; - reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; rtlphy->reg_eb4 = reg_eb4; rtlphy->reg_ebc = reg_ebc; rtlphy->reg_e94 = reg_e94; rtlphy->reg_e9c = reg_e9c; b_patha_ok = true; - b_pathb_ok = true; } else { rtlphy->reg_e94 = 0x100; rtlphy->reg_eb4 = 0x100; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c index f2908ee5f860..4bef237f488d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c @@ -1649,8 +1649,6 @@ static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw, u8 tmp1byte) (rtlpriv->btcoexist.bt_rssi_state & BT_RSSI_STATE_SPECIAL_LOW)) { rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); - } else if (rtlpriv->btcoexist.bt_service == BT_PAN) { - rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte); } else { rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 0efd19aa4fe5..661249d618c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -1369,8 +1369,8 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[10] = { ROFDM0_XARXIQIMBALANCE, @@ -1445,21 +1445,17 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 67305ce915ec..05462422d247 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -108,7 +108,6 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; - int err; enum version_8192e version = rtlhal->version; if (!rtlhal->pfirmware) @@ -146,9 +145,7 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) _rtl92ee_write_fw(hw, version, pfwdata, fwsize); _rtl92ee_enable_fw_download(hw, false); - err = _rtl92ee_fw_free_to_go(hw); - - return 0; + return _rtl92ee_fw_free_to_go(hw); } static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index 222abc41669c..f03de8bdd2d1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -2801,8 +2801,8 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac; - long reg_eb4, reg_ebc, reg_ec4, reg_ecc; + long reg_e94, reg_e9c, reg_ea4; + long reg_eb4, reg_ebc, reg_ec4; bool is12simular, is13simular, is23simular; u8 idx; u32 iqk_bb_reg[IQK_BB_REG_NUM] = { @@ -2873,11 +2873,9 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { @@ -2886,13 +2884,11 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e9c = result[final_candidate][1]; rtlphy->reg_e9c = reg_e9c; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; rtlphy->reg_eb4 = reg_eb4; reg_ebc = result[final_candidate][5]; rtlphy->reg_ebc = reg_ebc; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 27f1a631b569..dc7b515bdc85 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -651,7 +651,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb); u16 seq_number; __le16 fc = hdr->frame_control; - unsigned int buf_len; u8 fw_qsel = _rtl92ee_map_hwqueue_to_fwqueue(skb, hw_queue); bool firstseg = ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); @@ -659,7 +658,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); dma_addr_t mapping; u8 bw_40 = 0; - u8 short_gi; __le32 *pdesc = (__le32 *)pdesc8; if (mac->opmode == NL80211_IFTYPE_STATION) { @@ -677,7 +675,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, skb_push(skb, EM_HDR_LEN); memset(skb->data, 0, EM_HDR_LEN); } - buf_len = skb->len; mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { @@ -724,11 +721,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, } } - if (ptcb_desc->hw_rate > DESC_RATEMCS0) - short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; - else - short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; - if (info->flags & IEEE80211_TX_CTL_AMPDU) { set_tx_desc_agg_enable(pdesc, 1); set_tx_desc_max_agg_num(pdesc, 0x14); @@ -1010,14 +1002,13 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; { - u16 cur_tx_rp, cur_tx_wp; + u16 cur_tx_rp; u32 tmpu32; tmpu32 = rtl_read_dword(rtlpriv, get_desc_addr_fr_q_idx(hw_queue)); cur_tx_rp = (u16)((tmpu32 >> 16) & 0x0fff); - cur_tx_wp = (u16)(tmpu32 & 0x0fff); /* don't need to update ring->cur_tx_wp */ ring->cur_tx_rp = cur_tx_rp; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h index bb6b60814762..f43331224851 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h @@ -24,192 +24,186 @@ #define TX_DESC_SIZE_RTL8192S (16 * 4) #define TX_CMDDESC_SIZE_RTL8192S (16 * 4) -/* Define a macro that takes a le32 word, converts it to host ordering, - * right shifts by a specified count, creates a mask of the specified - * bit count, and extracts that number of bits. - */ - -#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ - ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ - BIT_LEN_MASK_32(__mask)) - -/* Define a macro that clears a bit field in an le32 word and - * sets the specified value into that bit field. The resulting - * value remains in le32 ordering; however, it is properly converted - * to host ordering for the clear and set operations before conversion - * back to le32. - */ - -#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ - (*(__le32 *)(__pdesc) = \ - (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ - (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ - (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); - /* macros to read/write various fields in RX or TX descriptors */ /* Dword 0 */ -#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) -#define SET_TX_DESC_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) -#define SET_TX_DESC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) -#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) -#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) -#define SET_TX_DESC_LINIP(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) -#define SET_TX_DESC_AMSDU(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) -#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) -#define SET_TX_DESC_OWN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) - -#define GET_TX_DESC_OWN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 31, 1) +static inline void set_tx_desc_pkt_size(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, GENMASK(15, 0)); +} + +static inline void set_tx_desc_offset(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, GENMASK(23, 16)); +} + +static inline void set_tx_desc_last_seg(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(26)); +} + +static inline void set_tx_desc_first_seg(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(27)); +} + +static inline void set_tx_desc_linip(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(28)); +} + +static inline void set_tx_desc_own(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(31)); +} + +static inline u32 get_tx_desc_own(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(31)); +} /* Dword 1 */ -#define SET_TX_DESC_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) -#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) -#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) -#define SET_TX_DESC_PIFS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) -#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) -#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) -#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) -#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) -#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) -#define SET_TX_DESC_OUI(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) -#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) -#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) -#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) -#define SET_TX_DESC_WDS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) -#define SET_TX_DESC_HTC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) -#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) -#define SET_TX_DESC_HWPC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) +static inline void set_tx_desc_macid(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 1), __val, GENMASK(4, 0)); +} + +static inline void set_tx_desc_queue_sel(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 1), __val, GENMASK(12, 8)); +} + +static inline void set_tx_desc_non_qos(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 1), __val, BIT(16)); +} + +static inline void set_tx_desc_sec_type(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 1), __val, GENMASK(23, 22)); +} /* Dword 2 */ -#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) -#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) -#define SET_TX_DESC_TSFL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) -#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) -#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) -#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) -#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) -#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) -#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) +static inline void set_tx_desc_rsvd_macid(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 2), __val, GENMASK(28, 24)); +} + +static inline void set_tx_desc_agg_enable(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 2), __val, BIT(29)); +} /* Dword 3 */ -#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) -#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) -#define SET_TX_DESC_SEQ(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) -#define SET_TX_DESC_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) +static inline void set_tx_desc_seq(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 3), __val, GENMASK(27, 16)); +} /* Dword 4 */ -#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) -#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) -#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) -#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) -#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) -#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) -#define SET_TX_DESC_TXHT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) -#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) -#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) -#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) -#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) -#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) -#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) -#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) -#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) -#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) -#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) -#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) +static inline void set_tx_desc_rts_rate(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, GENMASK(5, 0)); +} + +static inline void set_tx_desc_cts_enable(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(11)); +} + +static inline void set_tx_desc_rts_enable(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(12)); +} + +static inline void set_tx_desc_ra_brsr_id(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, GENMASK(15, 13)); +} + +static inline void set_tx_desc_txht(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(16)); +} + +static inline void set_tx_desc_tx_short(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(17)); +} + +static inline void set_tx_desc_tx_bandwidth(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(18)); +} + +static inline void set_tx_desc_tx_sub_carrier(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, GENMASK(20, 19)); +} + +static inline void set_tx_desc_rts_short(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(25)); +} + +static inline void set_tx_desc_rts_bandwidth(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(26)); +} + +static inline void set_tx_desc_rts_sub_carrier(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, GENMASK(28, 27)); +} + +static inline void set_tx_desc_rts_stbc(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, GENMASK(30, 29)); +} + +static inline void set_tx_desc_user_rate(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 4), __val, BIT(31)); +} /* Dword 5 */ -#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) -#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) -#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) -#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) -#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) - -/* Dword 6 */ -#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) -#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) +static inline void set_tx_desc_packet_id(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 5), __val, GENMASK(8, 0)); +} + +static inline void set_tx_desc_tx_rate(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 5), __val, GENMASK(14, 9)); +} + +static inline void set_tx_desc_data_rate_fb_limit(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 5), __val, GENMASK(20, 16)); +} /* Dword 7 */ -#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) -#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) -#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) +static inline void set_tx_desc_tx_buffer_size(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits((__pdesc + 7), __val, GENMASK(15, 0)); +} /* Dword 8 */ -#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) -#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) +static inline void set_tx_desc_tx_buffer_address(__le32 *__pdesc, u32 __val) +{ + *(__pdesc + 8) = cpu_to_le32(__val); +} + +static inline u32 get_tx_desc_tx_buffer_address(__le32 *__pdesc) +{ + return le32_to_cpu(*((__pdesc + 8))); +} /* Dword 9 */ -#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) +static inline void set_tx_desc_next_desc_address(__le32 *__pdesc, u32 __val) +{ + *(__pdesc + 9) = cpu_to_le32(__val); +} /* Because the PCI Tx descriptors are chaied at the * initialization and all the NextDescAddresses in @@ -226,208 +220,115 @@ #define RX_DRV_INFO_SIZE_UNIT 8 /* DWORD 0 */ -#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) -#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) -#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) -#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) -#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) -#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) -#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) -#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) -#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) -#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) -#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) -#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) -#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) - -#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 0, 14) -#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 14, 1) -#define GET_RX_STATUS_DESC_ICV(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 15, 1) -#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 16, 4) -#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 20, 3) -#define GET_RX_STATUS_DESC_QOS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 23, 1) -#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 24, 2) -#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 26, 1) -#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 27, 1) -#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 28, 1) -#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 29, 1) -#define GET_RX_STATUS_DESC_EOR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 30, 1) -#define GET_RX_STATUS_DESC_OWN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 31, 1) +static inline void set_rx_status_desc_pkt_len(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, GENMASK(13, 0)); +} + +static inline void set_rx_status_desc_eor(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(30)); +} + +static inline void set_rx_status_desc_own(__le32 *__pdesc, u32 __val) +{ + le32p_replace_bits(__pdesc, __val, BIT(31)); +} + +static inline u32 get_rx_status_desc_pkt_len(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), GENMASK(13, 0)); +} + +static inline u32 get_rx_status_desc_crc32(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(14)); +} + +static inline u32 get_rx_status_desc_icv(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(15)); +} + +static inline u32 get_rx_status_desc_drvinfo_size(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), GENMASK(19, 16)); +} + +static inline u32 get_rx_status_desc_shift(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), GENMASK(25, 24)); +} + +static inline u32 get_rx_status_desc_phy_status(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(26)); +} + +static inline u32 get_rx_status_desc_swdec(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(27)); +} + +static inline u32 get_rx_status_desc_own(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc), BIT(31)); +} /* DWORD 1 */ -#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) -#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) -#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) -#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) -#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) -#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) -#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) -#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) -#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) -#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) -#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) -#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) -#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) - -#define GET_RX_STATUS_DEC_MACID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) -#define GET_RX_STATUS_DESC_TID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) -#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) -#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) -#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) -#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) -#define GET_RX_STATUS_DESC_PAM(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) -#define GET_RX_STATUS_DESC_PWR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) -#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) -#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) -#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) -#define GET_RX_STATUS_DESC_MC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) -#define GET_RX_STATUS_DESC_BC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) - -/* DWORD 2 */ -#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) -#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) -#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) -#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) - -#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) -#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) -#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) -#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) +static inline u32 get_rx_status_desc_paggr(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 1), BIT(14)); +} + +static inline u32 get_rx_status_desc_faggr(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 1), BIT(15)); +} /* DWORD 3 */ -#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) -#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) -#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) -#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) -#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) -#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) -#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) -#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) -#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) -#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) -#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) -#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) - -#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) -#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) -#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) -#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) -#define GET_RX_STATUS_DESC_BW(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) -#define GET_RX_STATUS_DESC_HTC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) -#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) -#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) -#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) -#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) -#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) -#define GET_RX_STATUS_DESC_IV0(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) - -/* DWORD 4 */ -#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) -#define GET_RX_STATUS_DESC_IV1(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) +static inline u32 get_rx_status_desc_rx_mcs(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 3), GENMASK(5, 0)); +} + +static inline u32 get_rx_status_desc_rx_ht(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 3), BIT(6)); +} + +static inline u32 get_rx_status_desc_splcp(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 3), BIT(8)); +} + +static inline u32 get_rx_status_desc_bw(__le32 *__pdesc) +{ + return le32_get_bits(*(__pdesc + 3), BIT(9)); +} /* DWORD 5 */ -#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) -#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) +static inline u32 get_rx_status_desc_tsfl(__le32 *__pdesc) +{ + return le32_to_cpu(*((__pdesc + 5))); +} /* DWORD 6 */ -#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) -#define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) +static inline void set_rx_status__desc_buff_addr(__le32 *__pdesc, u32 __val) +{ + *(__pdesc + 6) = cpu_to_le32(__val); +} + +static inline u32 get_rx_status_desc_buff_addr(__le32 *__pdesc) +{ + return le32_to_cpu(*(__pdesc + 6)); +} #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE2M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE5_5M ||\ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE11M) + (get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE1M || \ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE2M || \ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE5_5M ||\ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE11M) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c index 541b7881735e..47a5b95ca2b9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c @@ -442,17 +442,20 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, memset((ph2c_buffer + totallen + tx_desclen), 0, len); /* CMD len */ - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 0, 16, pcmd_len[i]); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), pcmd_len[i], + GENMASK(15, 0)); /* CMD ID */ - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 16, 8, pelement_id[i]); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), pelement_id[i], + GENMASK(23, 16)); /* CMD Sequence */ *cmd_start_seq = *cmd_start_seq % 0x80; - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 24, 7, *cmd_start_seq); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), *cmd_start_seq, + GENMASK(30, 24)); ++*cmd_start_seq; /* Copy memory */ @@ -462,8 +465,9 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, /* CMD continue */ /* set the continue in prevoius cmd. */ if (i < cmd_num - 1) - SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), - 31, 1, 1); + le32p_replace_bits((__le32 *)(ph2c_buffer + + pre_continueoffset), + 1, BIT(31)); pre_continueoffset = totallen; @@ -559,8 +563,8 @@ void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) pwrmode.flag_dps_en = 0; pwrmode.bcn_rx_en = 0; pwrmode.bcn_to = 0; - SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, - mac->vif->bss_conf.beacon_int); + le16p_replace_bits((__le16 *)(((u8 *)(&pwrmode) + 8)), + mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); pwrmode.app_itv = 0; pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; pwrmode.smart_ps = 1; @@ -602,9 +606,10 @@ void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, joinbss_rpt.bssid[3] = mac->bssid[3]; joinbss_rpt.bssid[4] = mac->bssid[4]; joinbss_rpt.bssid[5] = mac->bssid[5]; - SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, - mac->vif->bss_conf.beacon_int); - SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); + le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 8)), + mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); + le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 10)), + mac->assoc_id, GENMASK(15, 0)); _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index efb432c6d785..9eaa5348b556 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -33,7 +33,7 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) } static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, - struct rtl_stats *pstats, u8 *pdesc, + struct rtl_stats *pstats, __le32 *pdesc, struct rx_fwinfo *p_drvinfo, bool packet_match_bssid, bool packet_toself, @@ -193,11 +193,10 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_stats *pstats, - u8 *pdesc, struct rx_fwinfo *p_drvinfo) + __le32 *pdesc, struct rx_fwinfo *p_drvinfo) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; @@ -232,29 +231,30 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, } bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, - struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct ieee80211_rx_status *rx_status, u8 *pdesc8, struct sk_buff *skb) { struct rx_fwinfo *p_drvinfo; - u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + __le32 *pdesc = (__le32 *)pdesc8; + u32 phystatus = (u32)get_rx_status_desc_phy_status(pdesc); struct ieee80211_hdr *hdr; - stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); - stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; - stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); - stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); - stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); + stats->length = (u16)get_rx_status_desc_pkt_len(pdesc); + stats->rx_drvinfo_size = (u8)get_rx_status_desc_drvinfo_size(pdesc) * 8; + stats->rx_bufshift = (u8)(get_rx_status_desc_shift(pdesc) & 0x03); + stats->icv = (u16)get_rx_status_desc_icv(pdesc); + stats->crc = (u16)get_rx_status_desc_crc32(pdesc); stats->hwerror = (u16)(stats->crc | stats->icv); - stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); - - stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); - stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); - stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); - stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1) - && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1)); - stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); - stats->rx_is40mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); - stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc); + stats->decrypted = !get_rx_status_desc_swdec(pdesc); + + stats->rate = (u8)get_rx_status_desc_rx_mcs(pdesc); + stats->shortpreamble = (u16)get_rx_status_desc_splcp(pdesc); + stats->isampdu = (bool)(get_rx_status_desc_paggr(pdesc) == 1); + stats->isfirst_ampdu = (bool)((get_rx_status_desc_paggr(pdesc) == 1) && + (get_rx_status_desc_faggr(pdesc) == 1)); + stats->timestamp_low = get_rx_status_desc_tsfl(pdesc); + stats->rx_is40mhzpacket = (bool)get_rx_status_desc_bw(pdesc); + stats->is_ht = (bool)get_rx_status_desc_rx_ht(pdesc); stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc); if (stats->hwerror) @@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, } void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_hdr *hdr, u8 *pdesc8, u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, @@ -320,7 +320,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 *pdesc = pdesc_tx; + __le32 *pdesc = (__le32 *)pdesc8; u16 seq_number; __le16 fc = hdr->frame_control; u8 reserved_macid = 0; @@ -360,13 +360,13 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, if (rtlpriv->dm.useramask) { /* set txdesc macId */ if (ptcb_desc->mac_id < 32) { - SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + set_tx_desc_macid(pdesc, ptcb_desc->mac_id); reserved_macid |= ptcb_desc->mac_id; } } - SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); + set_tx_desc_rsvd_macid(pdesc, reserved_macid); - SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= + set_tx_desc_txht(pdesc, ((ptcb_desc->hw_rate >= DESC_RATEMCS0) ? 1 : 0)); if (rtlhal->version == VERSION_8192S_ACUT) { @@ -378,31 +378,32 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, } } - SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + set_tx_desc_tx_rate(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) - SET_TX_DESC_TX_SHORT(pdesc, 0); + set_tx_desc_tx_short(pdesc, 0); /* Aggregation related */ if (info->flags & IEEE80211_TX_CTL_AMPDU) - SET_TX_DESC_AGG_ENABLE(pdesc, 1); + set_tx_desc_agg_enable(pdesc, 1); /* For AMPDU, we must insert SSN into TX_DESC */ - SET_TX_DESC_SEQ(pdesc, seq_number); + set_tx_desc_seq(pdesc, seq_number); /* Protection mode related */ /* For 92S, if RTS/CTS are set, HW will execute RTS. */ /* We choose only one protection mode to execute */ - SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && - !ptcb_desc->cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? + set_tx_desc_rts_enable(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? + 1 : 0)); + set_tx_desc_cts_enable(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + set_tx_desc_rts_stbc(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); - SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); - SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); - SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + set_tx_desc_rts_rate(pdesc, ptcb_desc->rts_rate); + set_tx_desc_rts_bandwidth(pdesc, 0); + set_tx_desc_rts_sub_carrier(pdesc, ptcb_desc->rts_sc); + set_tx_desc_rts_short(pdesc, ((ptcb_desc->rts_rate <= DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); @@ -411,27 +412,27 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, /* Set Bandwidth and sub-channel settings. */ if (bw_40) { if (ptcb_desc->packet_bw) { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); + set_tx_desc_tx_bandwidth(pdesc, 1); /* use duplicated mode */ - SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, 0); } else { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); - SET_TX_DESC_TX_SUB_CARRIER(pdesc, + set_tx_desc_tx_bandwidth(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, mac->cur_40_prime_sc); } } else { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); - SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + set_tx_desc_tx_bandwidth(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, 0); } /* 3 Fill necessary field in First Descriptor */ /*DWORD 0*/ - SET_TX_DESC_LINIP(pdesc, 0); - SET_TX_DESC_OFFSET(pdesc, 32); - SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + set_tx_desc_linip(pdesc, 0); + set_tx_desc_offset(pdesc, 32); + set_tx_desc_pkt_size(pdesc, (u16)skb->len); /*DWORD 1*/ - SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); + set_tx_desc_ra_brsr_id(pdesc, ptcb_desc->ratr_index); /* Fill security related */ if (info->control.hw_key) { @@ -441,62 +442,63 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + set_tx_desc_sec_type(pdesc, 0x1); break; case WLAN_CIPHER_SUITE_TKIP: - SET_TX_DESC_SEC_TYPE(pdesc, 0x2); + set_tx_desc_sec_type(pdesc, 0x2); break; case WLAN_CIPHER_SUITE_CCMP: - SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + set_tx_desc_sec_type(pdesc, 0x3); break; default: - SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + set_tx_desc_sec_type(pdesc, 0x0); break; } } /* Set Packet ID */ - SET_TX_DESC_PACKET_ID(pdesc, 0); + set_tx_desc_packet_id(pdesc, 0); /* We will assign magement queue to BK. */ - SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + set_tx_desc_queue_sel(pdesc, fw_qsel); /* Alwasy enable all rate fallback range */ - SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + set_tx_desc_data_rate_fb_limit(pdesc, 0x1F); /* Fix: I don't kown why hw use 6.5M to tx when set it */ - SET_TX_DESC_USER_RATE(pdesc, + set_tx_desc_user_rate(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); /* Set NON_QOS bit. */ if (!ieee80211_is_data_qos(fc)) - SET_TX_DESC_NON_QOS(pdesc, 1); + set_tx_desc_non_qos(pdesc, 1); } /* Fill fields that are required to be initialized * in all of the descriptors */ /*DWORD 0 */ - SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); - SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + set_tx_desc_first_seg(pdesc, (firstseg ? 1 : 0)); + set_tx_desc_last_seg(pdesc, (lastseg ? 1 : 0)); /* DWORD 7 */ - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + set_tx_desc_tx_buffer_size(pdesc, (u16)skb->len); /* DOWRD 8 */ - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + set_tx_desc_tx_buffer_address(pdesc, mapping); RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); } -void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, - bool firstseg, bool lastseg, struct sk_buff *skb) +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc8, + bool firstseg, bool lastseg, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + __le32 *pdesc = (__le32 *)pdesc8; dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -512,53 +514,55 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, /* This bit indicate this packet is used for FW download. */ if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { /* For firmware downlaod we only need to set LINIP */ - SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); + set_tx_desc_linip(pdesc, tcb_desc->last_inipkt); /* 92SE must set as 1 for firmware download HW DMA error */ - SET_TX_DESC_FIRST_SEG(pdesc, 1); - SET_TX_DESC_LAST_SEG(pdesc, 1); + set_tx_desc_first_seg(pdesc, 1); + set_tx_desc_last_seg(pdesc, 1); /* 92SE need not to set TX packet size when firmware download */ - SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + set_tx_desc_pkt_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_address(pdesc, mapping); wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); } else { /* H2C Command Desc format (Host TXCMD) */ /* 92SE must set as 1 for firmware download HW DMA error */ - SET_TX_DESC_FIRST_SEG(pdesc, 1); - SET_TX_DESC_LAST_SEG(pdesc, 1); + set_tx_desc_first_seg(pdesc, 1); + set_tx_desc_last_seg(pdesc, 1); - SET_TX_DESC_OFFSET(pdesc, 0x20); + set_tx_desc_offset(pdesc, 0x20); /* Buffer size + command header */ - SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + set_tx_desc_pkt_size(pdesc, (u16)(skb->len)); /* Fixed queue of H2C command */ - SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); - - SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); + set_tx_desc_queue_sel(pdesc, 0x13); - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + le32p_replace_bits((__le32 *)skb->data, rtlhal->h2c_txcmd_seq, + GENMASK(30, 24)); + set_tx_desc_tx_buffer_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_address(pdesc, mapping); wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); } } -void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc8, bool istx, u8 desc_name, u8 *val) { + __le32 *pdesc = (__le32 *)pdesc8; + if (istx) { switch (desc_name) { case HW_DESC_OWN: wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); break; case HW_DESC_TX_NEXTDESC_ADDR: - SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + set_tx_desc_next_desc_address(pdesc, *(u32 *)val); break; default: WARN_ONCE(true, "rtl8192se: ERR txdesc :%d not processed\n", @@ -569,16 +573,16 @@ void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, switch (desc_name) { case HW_DESC_RXOWN: wmb(); - SET_RX_STATUS_DESC_OWN(pdesc, 1); + set_rx_status_desc_own(pdesc, 1); break; case HW_DESC_RXBUFF_ADDR: - SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); + set_rx_status__desc_buff_addr(pdesc, *(u32 *)val); break; case HW_DESC_RXPKT_LEN: - SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); + set_rx_status_desc_pkt_len(pdesc, *(u32 *)val); break; case HW_DESC_RXERO: - SET_RX_STATUS_DESC_EOR(pdesc, 1); + set_rx_status_desc_eor(pdesc, 1); break; default: WARN_ONCE(true, "rtl8192se: ERR rxdesc :%d not processed\n", @@ -589,17 +593,18 @@ void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, } u64 rtl92se_get_desc(struct ieee80211_hw *hw, - u8 *desc, bool istx, u8 desc_name) + u8 *desc8, bool istx, u8 desc_name) { u32 ret = 0; + __le32 *desc = (__le32 *)desc8; if (istx) { switch (desc_name) { case HW_DESC_OWN: - ret = GET_TX_DESC_OWN(desc); + ret = get_tx_desc_own(desc); break; case HW_DESC_TXBUFF_ADDR: - ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); + ret = get_tx_desc_tx_buffer_address(desc); break; default: WARN_ONCE(true, "rtl8192se: ERR txdesc :%d not processed\n", @@ -609,13 +614,13 @@ u64 rtl92se_get_desc(struct ieee80211_hw *hw, } else { switch (desc_name) { case HW_DESC_OWN: - ret = GET_RX_STATUS_DESC_OWN(desc); + ret = get_rx_status_desc_own(desc); break; case HW_DESC_RXPKT_LEN: - ret = GET_RX_STATUS_DESC_PKT_LEN(desc); + ret = get_rx_status_desc_pkt_len(desc); break; case HW_DESC_RXBUFF_ADDR: - ret = GET_RX_STATUS_DESC_BUFF_ADDR(desc); + ret = get_rx_status_desc_buff_addr(desc); break; default: WARN_ONCE(true, "rtl8192se: ERR rxdesc :%d not processed\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c index 54a3aec1dfa7..1385e5a2e0b0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c @@ -485,15 +485,12 @@ bool rtl8723e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { int i; - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; radioa_arraylen = RTL8723ERADIOA_1TARRAYLENGTH; radioa_array_table = RTL8723E_RADIOA_1TARRAY; - rtstatus = true; - switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { @@ -1341,9 +1338,9 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; - bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + bool b_patha_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[10] = { ROFDM0_XARXIQIMBALANCE, @@ -1372,7 +1369,6 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) } final_candidate = 0xff; b_patha_ok = false; - b_pathb_ok = false; is12simular = false; is23simular = false; is13simular = false; @@ -1412,23 +1408,16 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; - reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; - reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; - b_pathb_ok = true; } else { rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index aa8a0950fcea..d48364460922 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -2251,8 +2251,8 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate, idx; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4; - long reg_ecc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4; + long reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[9] = { ROFDM0_XARXIQIMBALANCE, @@ -2334,11 +2334,9 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { reg_e94 = result[final_candidate][0]; @@ -2346,13 +2344,11 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e9c = result[final_candidate][1]; rtlphy->reg_e9c = reg_e9c; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; rtlphy->reg_eb4 = reg_eb4; reg_ebc = result[final_candidate][5]; rtlphy->reg_ebc = reg_ebc; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c index 18ce2856a91b..37036e653e56 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c @@ -223,7 +223,6 @@ bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; struct sk_buff *pskb = NULL; - u8 own; unsigned long flags; ring = &rtlpci->tx_ring[BEACON_QUEUE]; @@ -233,9 +232,6 @@ bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); pdesc = &ring->desc[0]; - own = (u8)rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, true, - HW_DESC_OWN); - rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); __skb_queue_tail(&ring->queue, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 979e434a4e73..c1a04efa69ea 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -2076,7 +2076,6 @@ static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { - bool rtstatus = true; u32 *radioa_array_table_a, *radioa_array_table_b; u16 radioa_arraylen_a, radioa_arraylen_b; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -2088,7 +2087,6 @@ bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen_a); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: return __rtl8821ae_phy_config_with_headerfile(hw, @@ -2111,7 +2109,6 @@ bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -2121,7 +2118,6 @@ bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: return __rtl8821ae_phy_config_with_headerfile(hw, @@ -2351,7 +2347,7 @@ static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, struct rtl_phy *rtlphy = &rtlpriv->phy; short band_temp = -1, regulation = -1, bandwidth_temp = -1, rate_section = -1, channel_temp = -1; - u16 bd, regu, bdwidth, sec, chnl; + u16 regu, bdwidth, sec, chnl; s8 power_limit = MAX_POWER_INDEX; if (rtlefuse->eeprom_regulatory == 2) @@ -2472,7 +2468,6 @@ static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, return MAX_POWER_INDEX; } - bd = band_temp; regu = regulation; bdwidth = bandwidth_temp; sec = rate_section; @@ -3553,8 +3548,6 @@ void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw) if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { if (36 <= channel && channel <= 64) data = 0x114E9; - else if (100 <= channel && channel <= 140) - data = 0x110E9; else data = 0x110E9; rtl8821ae_phy_set_rf_reg(hw, path, RF_APK, diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 4b59f3b46b28..348b0072cdd6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1021,8 +1021,10 @@ int rtl_usb_probe(struct usb_interface *intf, rtlpriv->hw = hw; rtlpriv->usb_data = kcalloc(RTL_USB_MAX_RX_COUNT, sizeof(u32), GFP_KERNEL); - if (!rtlpriv->usb_data) + if (!rtlpriv->usb_data) { + ieee80211_free_hw(hw); return -ENOMEM; + } /* this spin lock must be initialized early */ spin_lock_init(&rtlpriv->locks.usb_lock); @@ -1083,6 +1085,7 @@ error_out2: _rtl_usb_io_handler_release(hw); usb_put_dev(udev); complete(&rtlpriv->firmware_loading_complete); + kfree(rtlpriv->usb_data); return -ENODEV; } EXPORT_SYMBOL(rtl_usb_probe); diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 77edee2df8b8..15e12155a04c 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -14,6 +14,7 @@ rtw88-y += main.o \ fw.o \ ps.o \ sec.o \ + bf.o \ regd.o rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c new file mode 100644 index 000000000000..fda771d23f71 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation. + */ + +#include "main.h" +#include "reg.h" +#include "bf.h" +#include "debug.h" + +void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + if (bfee->role == RTW_BFEE_NONE) + return; + + if (bfee->role == RTW_BFEE_MU) + bfinfo->bfer_mu_cnt--; + else if (bfee->role == RTW_BFEE_SU) + bfinfo->bfer_su_cnt--; + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, false); + + bfee->role = RTW_BFEE_NONE; +} + +void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_hw *hw = rtwdev->hw; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + struct rtw_chip_info *chip = rtwdev->chip; + struct ieee80211_sta *sta; + struct ieee80211_sta_vht_cap *vht_cap; + struct ieee80211_sta_vht_cap *ic_vht_cap; + const u8 *bssid = bss_conf->bssid; + u32 sound_dim; + u8 bfee_role = RTW_BFEE_NONE; + u8 i; + + if (!(chip->band & RTW_BAND_5G)) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta(vif, bssid); + if (!sta) { + rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", + bssid); + goto out_unlock; + } + + ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; + vht_cap = &sta->vht_cap; + + if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && + (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { + if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { + rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); + goto out_unlock; + } + + ether_addr_copy(bfee->mac_addr, bssid); + bfee_role = RTW_BFEE_MU; + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); + bfee->aid = bss_conf->aid; + bfinfo->bfer_mu_cnt++; + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); + } else if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) && + (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { + rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); + goto out_unlock; + } + + sound_dim = vht_cap->cap & + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; + sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; + + ether_addr_copy(bfee->mac_addr, bssid); + bfee_role = RTW_BFEE_SU; + bfee->sound_dim = (u8)sound_dim; + bfee->g_id = 0; + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); + bfinfo->bfer_su_cnt++; + for (i = 0; i < chip->bfer_su_max_num; i++) { + if (!test_bit(i, bfinfo->bfer_su_reg_maping)) { + set_bit(i, bfinfo->bfer_su_reg_maping); + bfee->su_reg_index = i; + break; + } + } + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); + } + +out_unlock: + bfee->role = bfee_role; + rcu_read_unlock(); +} + +void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, + struct mu_bfer_init_para *param) +{ + u16 mu_bf_ctl = 0; + u8 *addr = param->bfer_address; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtw_write8(rtwdev, REG_ASSOCIATED_BFMER0_INFO + i, addr[i]); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 6, param->paid); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, param->csi_para); + + mu_bf_ctl = rtw_read16(rtwdev, REG_WMAC_MU_BF_CTL) & 0xC000; + mu_bf_ctl |= param->my_aid | (param->csi_length_sel << 12); + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, mu_bf_ctl); +} + +void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, + enum rtw_trx_desc_rate rate) +{ + u32 psf_ctl = 0; + u8 csi_rsc = 0x1; + + psf_ctl = rtw_read32(rtwdev, REG_BBPSF_CTRL) | + BIT_WMAC_USE_NDPARATE | + (csi_rsc << 13); + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, 0x26); + rtw_write8_clr(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF_REPORT_POLL); + rtw_write8_clr(rtwdev, REG_RXFLTMAP4, BIT_RXFLTMAP4_BF_REPORT_POLL); + + if (vif->net_type == RTW_NET_AP_MODE) + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl | BIT(12)); + else + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl & ~BIT(12)); +} + +void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param) +{ + u8 mu_tbl_sel; + u8 mu_valid; + + mu_valid = rtw_read8(rtwdev, REG_MU_TX_CTL) & + ~BIT_MASK_R_MU_TABLE_VALID; + + rtw_write8(rtwdev, REG_MU_TX_CTL, + (mu_valid | BIT(0) | BIT(1)) & ~(BIT(7))); + + mu_tbl_sel = rtw_read8(rtwdev, REG_MU_TX_CTL + 1) & 0xF8; + + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel); + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[0]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[0]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, + param->given_user_pos[1]); + + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel | 1); + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[1]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[2]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, + param->given_user_pos[3]); +} + +void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev) +{ + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); + rtw_write8(rtwdev, REG_MU_TX_CTL, 0); +} + +void rtw_bf_del_sounding(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, 0); +} + +void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + u8 nc_index = 1; + u8 nr_index = bfee->sound_dim; + u8 grouping = 0, codebookinfo = 1, coefficientsize = 3; + u32 addr_bfer_info, addr_csi_rpt, csi_param; + u8 i; + + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an su bfee\n"); + + switch (bfee->su_reg_index) { + case 1: + addr_bfer_info = REG_ASSOCIATED_BFMER1_INFO; + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20 + 2; + break; + case 0: + default: + addr_bfer_info = REG_ASSOCIATED_BFMER0_INFO; + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20; + break; + } + + /* Sounding protocol control */ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); + + /* MAC address/Partial AID of Beamformer */ + for (i = 0; i < ETH_ALEN; i++) + rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]); + + csi_param = (u16)((coefficientsize << 10) | + (codebookinfo << 8) | + (grouping << 6) | + (nr_index << 3) | + nc_index); + rtw_write16(rtwdev, addr_csi_rpt, csi_param); + + /* ndp rx standby timer */ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, RTW_NDP_RX_STANDBY_TIME); +} + +/* nc index: 1 2T2R 0 1T1R + * nr index: 1 use Nsts 0 use reg setting + * codebookinfo: 1 802.11ac 3 802.11n + */ +void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bf_info = &rtwdev->bf_info; + struct mu_bfer_init_para param; + u8 nc_index = 1, nr_index = 1; + u8 grouping = 0, codebookinfo = 1, coefficientsize = 0; + u32 csi_param; + + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an mu bfee\n"); + + csi_param = (u16)((coefficientsize << 10) | + (codebookinfo << 8) | + (grouping << 6) | + (nr_index << 3) | + nc_index); + + rtw_dbg(rtwdev, RTW_DBG_BF, "nc=%d nr=%d group=%d codebookinfo=%d coefficientsize=%d\n", + nc_index, nr_index, grouping, codebookinfo, + coefficientsize); + + param.paid = bfee->p_aid; + param.csi_para = csi_param; + param.my_aid = bfee->aid & 0xfff; + param.csi_length_sel = HAL_CSI_SEG_4K; + ether_addr_copy(param.bfer_address, bfee->mac_addr); + + rtw_bf_init_bfer_entry_mu(rtwdev, ¶m); + + bf_info->cur_csi_rpt_rate = DESC_RATE6M; + rtw_bf_cfg_sounding(rtwdev, vif, DESC_RATE6M); + + /* accept action_no_ack */ + rtw_write16_set(rtwdev, REG_RXFLTMAP0, BIT_RXFLTMAP0_ACTIONNOACK); + + /* accept NDPA and BF report poll */ + rtw_write16_set(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF); +} + +void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + rtw_dbg(rtwdev, RTW_DBG_BF, "remove as a su bfee\n"); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); + + switch (bfee->su_reg_index) { + case 0: + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, 0); + break; + case 1: + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER1_INFO, 0); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER1_INFO + 4, 0); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20 + 2, 0); + break; + } + + clear_bit(bfee->su_reg_index, bfinfo->bfer_su_reg_maping); + bfee->su_reg_index = 0xFF; +} + +void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); + + rtw_bf_del_bfer_entry_mu(rtwdev); + + if (bfinfo->bfer_su_cnt == 0 && bfinfo->bfer_mu_cnt == 0) + rtw_bf_del_sounding(rtwdev); +} + +void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf) +{ + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct cfg_mumimo_para param; + + if (bfee->role != RTW_BFEE_MU) { + rtw_dbg(rtwdev, RTW_DBG_BF, "this vif is not mu bfee\n"); + return; + } + + param.grouping_bitmap = 0; + param.mu_tx_en = 0; + memset(param.sounding_sts, 0, 6); + memcpy(param.given_gid_tab, conf->mu_group.membership, 8); + memcpy(param.given_user_pos, conf->mu_group.position, 16); + rtw_dbg(rtwdev, RTW_DBG_BF, "STA0: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", + param.given_gid_tab[0], param.given_user_pos[0], + param.given_user_pos[1]); + + rtw_dbg(rtwdev, RTW_DBG_BF, "STA1: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", + param.given_gid_tab[1], param.given_user_pos[2], + param.given_user_pos[3]); + + rtw_bf_cfg_mu_bfee(rtwdev, ¶m); +} + +void rtw_bf_phy_init(struct rtw_dev *rtwdev) +{ + u8 tmp8; + u32 tmp32; + u8 retry_limit = 0xA; + u8 ndpa_rate = 0x10; + u8 ack_policy = 3; + + tmp32 = rtw_read32(rtwdev, REG_MU_TX_CTL); + /* Enable P1 aggr new packet according to P0 transfer time */ + tmp32 |= BIT_MU_P1_WAIT_STATE_EN; + /* MU Retry Limit */ + tmp32 &= ~BIT_MASK_R_MU_RL; + tmp32 |= (retry_limit << BIT_SHIFT_R_MU_RL) & BIT_MASK_R_MU_RL; + /* Disable Tx MU-MIMO until sounding done */ + tmp32 &= ~BIT_EN_MU_MIMO; + /* Clear validity of MU STAs */ + tmp32 &= ~BIT_MASK_R_MU_TABLE_VALID; + rtw_write32(rtwdev, REG_MU_TX_CTL, tmp32); + + /* MU-MIMO Option as default value */ + tmp8 = ack_policy << BIT_SHIFT_WMAC_TXMU_ACKPOLICY; + tmp8 |= BIT_WMAC_TXMU_ACKPOLICY_EN; + rtw_write8(rtwdev, REG_WMAC_MU_BF_OPTION, tmp8); + + /* MU-MIMO Control as default value */ + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); + /* Set MU NDPA rate & BW source */ + rtw_write32_set(rtwdev, REG_TXBF_CTRL, BIT_USE_NDPA_PARAMETER); + /* Set NDPA Rate */ + rtw_write8(rtwdev, REG_NDPA_OPT_CTRL, ndpa_rate); + + rtw_write32_mask(rtwdev, REG_BBPSF_CTRL, BIT_MASK_CSI_RATE, + DESC_RATE6M); +} + +void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate) +{ + u32 csi_cfg; + u16 cur_rrsr; + + csi_cfg = rtw_read32(rtwdev, REG_BBPSF_CTRL) & ~BIT_MASK_CSI_RATE; + cur_rrsr = rtw_read16(rtwdev, REG_RRSR); + + if (rssi >= 40) { + if (cur_rate != DESC_RATE54M) { + cur_rrsr |= BIT(DESC_RATE54M); + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << + BIT_SHIFT_CSI_RATE; + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); + } + *new_rate = DESC_RATE54M; + } else { + if (cur_rate != DESC_RATE24M) { + cur_rrsr &= ~BIT(DESC_RATE54M); + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << + BIT_SHIFT_CSI_RATE; + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); + } + *new_rate = DESC_RATE24M; + } +} diff --git a/drivers/net/wireless/realtek/rtw88/bf.h b/drivers/net/wireless/realtek/rtw88/bf.h new file mode 100644 index 000000000000..96a8216dd11f --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/bf.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation. + */ + +#ifndef __RTW_BF_H_ +#define __RTW_BF_H_ + +#define REG_TXBF_CTRL 0x042C +#define REG_RRSR 0x0440 +#define REG_NDPA_OPT_CTRL 0x045F + +#define REG_ASSOCIATED_BFMER0_INFO 0x06E4 +#define REG_ASSOCIATED_BFMER1_INFO 0x06EC +#define REG_TX_CSI_RPT_PARAM_BW20 0x06F4 +#define REG_SND_PTCL_CTRL 0x0718 +#define REG_MU_TX_CTL 0x14C0 +#define REG_MU_STA_GID_VLD 0x14C4 +#define REG_MU_STA_USER_POS_INFO 0x14C8 +#define REG_CSI_RRSR 0x1678 +#define REG_WMAC_MU_BF_OPTION 0x167C +#define REG_WMAC_MU_BF_CTL 0x1680 + +#define BIT_WMAC_USE_NDPARATE BIT(30) +#define BIT_WMAC_TXMU_ACKPOLICY_EN BIT(6) +#define BIT_USE_NDPA_PARAMETER BIT(30) +#define BIT_MU_P1_WAIT_STATE_EN BIT(16) +#define BIT_EN_MU_MIMO BIT(7) + +#define R_MU_RL 0xf +#define BIT_SHIFT_R_MU_RL 12 +#define BIT_SHIFT_WMAC_TXMU_ACKPOLICY 4 +#define BIT_SHIFT_CSI_RATE 24 + +#define BIT_MASK_R_MU_RL (R_MU_RL << BIT_SHIFT_R_MU_RL) +#define BIT_MASK_R_MU_TABLE_VALID 0x3f +#define BIT_MASK_CSI_RATE_VAL 0x3F +#define BIT_MASK_CSI_RATE (BIT_MASK_CSI_RATE_VAL << BIT_SHIFT_CSI_RATE) + +#define BIT_RXFLTMAP0_ACTIONNOACK BIT(14) +#define BIT_RXFLTMAP1_BF (BIT(4) | BIT(5)) +#define BIT_RXFLTMAP1_BF_REPORT_POLL BIT(4) +#define BIT_RXFLTMAP4_BF_REPORT_POLL BIT(4) + +#define RTW_NDP_RX_STANDBY_TIME 0x70 +#define RTW_SND_CTRL_REMOVE 0xD8 +#define RTW_SND_CTRL_SOUNDING 0xDB + +enum csi_seg_len { + HAL_CSI_SEG_4K = 0, + HAL_CSI_SEG_8K = 1, + HAL_CSI_SEG_11K = 2, +}; + +struct cfg_mumimo_para { + u8 sounding_sts[6]; + u16 grouping_bitmap; + u8 mu_tx_en; + u32 given_gid_tab[2]; + u32 given_user_pos[4]; +}; + +struct mu_bfer_init_para { + u16 paid; + u16 csi_para; + u16 my_aid; + enum csi_seg_len csi_length_sel; + u8 bfer_address[ETH_ALEN]; +}; + +void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); +void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); +void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, + struct mu_bfer_init_para *param); +void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, + enum rtw_trx_desc_rate rate); +void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param); +void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev); +void rtw_bf_del_sounding(struct rtw_dev *rtwdev); +void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee); +void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee); +void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); +void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); +void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf); +void rtw_bf_phy_init(struct rtw_dev *rtwdev); +void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate); +#endif diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 793b40bdbf7c..4dfb2ec395ee 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -383,9 +383,9 @@ static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) u8 rssi_step; u8 rssi; - scan = rtw_flag_check(rtwdev, RTW_FLAG_SCANNING); + scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags); coex_stat->wl_connected = !!rtwdev->sta_cnt; - coex_stat->wl_gl_busy = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); if (stats->tx_throughput > stats->rx_throughput) coex_stat->wl_tput_dir = COEX_WL_TPUT_TX; @@ -810,8 +810,6 @@ static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable) static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, u8 lps_val, u8 rpwm_val) { - struct rtw_lps_conf *lps_conf = &rtwdev->lps_conf; - struct rtw_vif *rtwvif; struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex_stat *coex_stat = &coex->stat; u8 lps_mode = 0x0; @@ -823,18 +821,14 @@ static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, /* recover to original 32k low power setting */ coex_stat->wl_force_lps_ctrl = false; - rtwvif = lps_conf->rtwvif; - if (rtwvif && rtw_in_lps(rtwdev)) - rtw_leave_lps(rtwdev, rtwvif); + rtw_leave_lps(rtwdev); break; case COEX_PS_LPS_OFF: coex_stat->wl_force_lps_ctrl = true; if (lps_mode) rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0); - rtwvif = lps_conf->rtwvif; - if (rtwvif && rtw_in_lps(rtwdev)) - rtw_leave_lps(rtwdev, rtwvif); + rtw_leave_lps(rtwdev); break; default: break; @@ -1308,6 +1302,7 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) struct rtw_chip_info *chip = rtwdev->chip; bool wl_hi_pri = false; u8 table_case, tdma_case; + u32 slot_type = 0; if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 || coex_stat->wl_hi_pri_task2) @@ -1318,14 +1313,16 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) if (wl_hi_pri) { table_case = 15; if (coex_stat->bt_a2dp_exist && - !coex_stat->bt_pan_exist) + !coex_stat->bt_pan_exist) { + slot_type = TDMA_4SLOT; tdma_case = 11; - else if (coex_stat->wl_hi_pri_task1) + } else if (coex_stat->wl_hi_pri_task1) { tdma_case = 6; - else if (!coex_stat->bt_page) + } else if (!coex_stat->bt_page) { tdma_case = 8; - else + } else { tdma_case = 9; + } } else if (coex_stat->wl_connected) { table_case = 10; tdma_case = 10; @@ -1361,7 +1358,7 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); rtw_coex_table(rtwdev, table_case); - rtw_coex_tdma(rtwdev, false, tdma_case); + rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); } static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev) @@ -1475,13 +1472,13 @@ static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev) if (efuse->share_ant) { /* Shared-Ant */ + slot_type = TDMA_4SLOT; + if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) table_case = 10; else table_case = 9; - slot_type = TDMA_4SLOT; - if (coex_stat->wl_gl_busy) tdma_case = 13; else @@ -1585,13 +1582,14 @@ static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev) if (efuse->share_ant) { /* Shared-Ant */ + slot_type = TDMA_4SLOT; + if (coex_stat->bt_ble_exist) table_case = 26; else table_case = 9; if (coex_stat->wl_gl_busy) { - slot_type = TDMA_4SLOT; tdma_case = 13; } else { tdma_case = 14; @@ -1794,10 +1792,12 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_chip_info *chip = rtwdev->chip; u8 table_case, tdma_case; + u32 slot_type = 0; if (efuse->share_ant) { /* Shared-Ant */ if (coex_stat->bt_a2dp_exist) { + slot_type = TDMA_4SLOT; table_case = 9; tdma_case = 11; } else { @@ -1818,7 +1818,7 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); rtw_coex_table(rtwdev, table_case); - rtw_coex_tdma(rtwdev, false, tdma_case); + rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); } static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 6ad985e98e42..5a181e01ebef 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -498,12 +498,32 @@ static void rtw_print_vht_rate_txt(struct seq_file *m, u8 rate) seq_printf(m, " VHT%uSMCS%u", n_ss, mcs_n); } +static void rtw_print_rate(struct seq_file *m, u8 rate) +{ + switch (rate) { + case DESC_RATE1M...DESC_RATE11M: + rtw_print_cck_rate_txt(m, rate); + break; + case DESC_RATE6M...DESC_RATE54M: + rtw_print_ofdm_rate_txt(m, rate); + break; + case DESC_RATEMCS0...DESC_RATEMCS15: + rtw_print_ht_rate_txt(m, rate); + break; + case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT2SS_MCS9: + rtw_print_vht_rate_txt(m, rate); + break; + default: + seq_printf(m, " Unknown rate=0x%x\n", rate); + break; + } +} + static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) { struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_hal *hal = &rtwdev->hal; - void (*print_rate)(struct seq_file *, u8) = NULL; u8 path, rate; struct rtw_power_params pwr_param = {0}; u8 bw = hal->current_band_width; @@ -528,30 +548,11 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) rate < DESC_RATEVHT1SS_MCS0) continue; - switch (rate) { - case DESC_RATE1M...DESC_RATE11M: - print_rate = rtw_print_cck_rate_txt; - break; - case DESC_RATE6M...DESC_RATE54M: - print_rate = rtw_print_ofdm_rate_txt; - break; - case DESC_RATEMCS0...DESC_RATEMCS15: - print_rate = rtw_print_ht_rate_txt; - break; - case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT2SS_MCS9: - print_rate = rtw_print_vht_rate_txt; - break; - default: - print_rate = NULL; - break; - } - rtw_get_tx_power_params(rtwdev, path, rate, bw, ch, regd, &pwr_param); seq_printf(m, "%4c ", path + 'A'); - if (print_rate) - print_rate(m, rate); + rtw_print_rate(m, rate); seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d)\n", hal->tx_pwr_tbl[path][rate], hal->tx_pwr_tbl[path][rate], @@ -567,6 +568,132 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) return 0; } +static int rtw_debugfs_get_phy_info(struct seq_file *m, void *v) +{ + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_traffic_stats *stats = &rtwdev->stats; + struct rtw_pkt_count *last_cnt = &dm_info->last_pkt_count; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct ewma_evm *ewma_evm = dm_info->ewma_evm; + struct ewma_snr *ewma_snr = dm_info->ewma_snr; + u8 ss, rate_id; + + seq_puts(m, "==========[Common Info]========\n"); + seq_printf(m, "Is link = %c\n", rtw_is_assoc(rtwdev) ? 'Y' : 'N'); + seq_printf(m, "Current CH(fc) = %u\n", rtwdev->hal.current_channel); + seq_printf(m, "Current BW = %u\n", rtwdev->hal.current_band_width); + seq_printf(m, "Current IGI = 0x%x\n", dm_info->igi_history[0]); + seq_printf(m, "TP {Tx, Rx} = {%u, %u}Mbps\n\n", + stats->tx_throughput, stats->rx_throughput); + + seq_puts(m, "==========[Tx Phy Info]========\n"); + seq_puts(m, "[Tx Rate] = "); + rtw_print_rate(m, dm_info->tx_rate); + seq_printf(m, "(0x%x)\n\n", dm_info->tx_rate); + + seq_puts(m, "==========[Rx Phy Info]========\n"); + seq_printf(m, "[Rx Beacon Count] = %u\n", last_cnt->num_bcn_pkt); + seq_puts(m, "[Rx Rate] = "); + rtw_print_rate(m, dm_info->curr_rx_rate); + seq_printf(m, "(0x%x)\n", dm_info->curr_rx_rate); + + seq_puts(m, "[Rx Rate Count]:\n"); + seq_printf(m, " * CCK = {%u, %u, %u, %u}\n", + last_cnt->num_qry_pkt[DESC_RATE1M], + last_cnt->num_qry_pkt[DESC_RATE2M], + last_cnt->num_qry_pkt[DESC_RATE5_5M], + last_cnt->num_qry_pkt[DESC_RATE11M]); + + seq_printf(m, " * OFDM = {%u, %u, %u, %u, %u, %u, %u, %u}\n", + last_cnt->num_qry_pkt[DESC_RATE6M], + last_cnt->num_qry_pkt[DESC_RATE9M], + last_cnt->num_qry_pkt[DESC_RATE12M], + last_cnt->num_qry_pkt[DESC_RATE18M], + last_cnt->num_qry_pkt[DESC_RATE24M], + last_cnt->num_qry_pkt[DESC_RATE36M], + last_cnt->num_qry_pkt[DESC_RATE48M], + last_cnt->num_qry_pkt[DESC_RATE54M]); + + for (ss = 0; ss < efuse->hw_cap.nss; ss++) { + rate_id = DESC_RATEMCS0 + ss * 8; + seq_printf(m, " * HT_MCS[%u:%u] = {%u, %u, %u, %u, %u, %u, %u, %u}\n", + ss * 8, ss * 8 + 7, + last_cnt->num_qry_pkt[rate_id], + last_cnt->num_qry_pkt[rate_id + 1], + last_cnt->num_qry_pkt[rate_id + 2], + last_cnt->num_qry_pkt[rate_id + 3], + last_cnt->num_qry_pkt[rate_id + 4], + last_cnt->num_qry_pkt[rate_id + 5], + last_cnt->num_qry_pkt[rate_id + 6], + last_cnt->num_qry_pkt[rate_id + 7]); + } + + for (ss = 0; ss < efuse->hw_cap.nss; ss++) { + rate_id = DESC_RATEVHT1SS_MCS0 + ss * 10; + seq_printf(m, " * VHT_MCS-%uss MCS[0:9] = {%u, %u, %u, %u, %u, %u, %u, %u, %u, %u}\n", + ss + 1, + last_cnt->num_qry_pkt[rate_id], + last_cnt->num_qry_pkt[rate_id + 1], + last_cnt->num_qry_pkt[rate_id + 2], + last_cnt->num_qry_pkt[rate_id + 3], + last_cnt->num_qry_pkt[rate_id + 4], + last_cnt->num_qry_pkt[rate_id + 5], + last_cnt->num_qry_pkt[rate_id + 6], + last_cnt->num_qry_pkt[rate_id + 7], + last_cnt->num_qry_pkt[rate_id + 8], + last_cnt->num_qry_pkt[rate_id + 9]); + } + + seq_printf(m, "[RSSI(dBm)] = {%d, %d}\n", + dm_info->rssi[RF_PATH_A] - 100, + dm_info->rssi[RF_PATH_B] - 100); + seq_printf(m, "[Rx EVM(dB)] = {-%d, -%d}\n", + dm_info->rx_evm_dbm[RF_PATH_A], + dm_info->rx_evm_dbm[RF_PATH_B]); + seq_printf(m, "[Rx SNR] = {%d, %d}\n", + dm_info->rx_snr[RF_PATH_A], + dm_info->rx_snr[RF_PATH_B]); + seq_printf(m, "[CFO_tail(KHz)] = {%d, %d}\n", + dm_info->cfo_tail[RF_PATH_A], + dm_info->cfo_tail[RF_PATH_B]); + + if (dm_info->curr_rx_rate >= DESC_RATE11M) { + seq_puts(m, "[Rx Average Status]:\n"); + seq_printf(m, " * OFDM, EVM: {-%d}, SNR: {%d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_OFDM]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_OFDM_A])); + seq_printf(m, " * 1SS, EVM: {-%d}, SNR: {%d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_1SS]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_1SS_A])); + seq_printf(m, " * 2SS, EVM: {-%d, -%d}, SNR: {%d, %d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_2SS_A]), + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_2SS_B]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_2SS_A]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_2SS_B])); + } + + seq_puts(m, "[Rx Counter]:\n"); + seq_printf(m, " * CCA (CCK, OFDM, Total) = (%u, %u, %u)\n", + dm_info->cck_cca_cnt, + dm_info->ofdm_cca_cnt, + dm_info->total_cca_cnt); + seq_printf(m, " * False Alarm (CCK, OFDM, Total) = (%u, %u, %u)\n", + dm_info->cck_fa_cnt, + dm_info->ofdm_fa_cnt, + dm_info->total_fa_cnt); + seq_printf(m, " * CCK cnt (ok, err) = (%u, %u)\n", + dm_info->cck_ok_cnt, dm_info->cck_err_cnt); + seq_printf(m, " * OFDM cnt (ok, err) = (%u, %u)\n", + dm_info->ofdm_ok_cnt, dm_info->ofdm_err_cnt); + seq_printf(m, " * HT cnt (ok, err) = (%u, %u)\n", + dm_info->ht_ok_cnt, dm_info->ht_err_cnt); + seq_printf(m, " * VHT cnt (ok, err) = (%u, %u)\n", + dm_info->vht_ok_cnt, dm_info->vht_err_cnt); + return 0; +} + #define rtw_debug_impl_mac(page, addr) \ static struct rtw_debugfs_priv rtw_debug_priv_mac_ ##page = { \ .cb_read = rtw_debug_get_mac_page, \ @@ -653,6 +780,10 @@ static struct rtw_debugfs_priv rtw_debug_priv_rsvd_page = { .cb_read = rtw_debugfs_get_rsvd_page, }; +static struct rtw_debugfs_priv rtw_debug_priv_phy_info = { + .cb_read = rtw_debugfs_get_phy_info, +}; + #define rtw_debugfs_add_core(name, mode, fopname, parent) \ do { \ rtw_debug_priv_ ##name.rtwdev = rtwdev; \ @@ -682,6 +813,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_rw(rf_read); rtw_debugfs_add_rw(dump_cam); rtw_debugfs_add_rw(rsvd_page); + rtw_debugfs_add_r(phy_info); rtw_debugfs_add_r(mac_0); rtw_debugfs_add_r(mac_1); rtw_debugfs_add_r(mac_2); diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index 45851cbbd2ab..cd28f675e9cb 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -16,6 +16,8 @@ enum rtw_debug_mask { RTW_DBG_RFK = 0x00000080, RTW_DBG_REGD = 0x00000100, RTW_DBG_DEBUGFS = 0x00000200, + RTW_DBG_PS = 0x00000400, + RTW_DBG_BF = 0x00000800, RTW_DBG_ALL = 0xffffffff }; diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index b082e2cc95f5..b8c581161f61 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -7,7 +7,9 @@ #include "fw.h" #include "tx.h" #include "reg.h" +#include "sec.h" #include "debug.h" +#include "util.h" static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb) @@ -27,6 +29,100 @@ static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, } } +static u16 get_max_amsdu_len(u32 bit_rate) +{ + /* lower than ofdm, do not aggregate */ + if (bit_rate < 550) + return 1; + + /* lower than 20M 2ss mcs8, make it small */ + if (bit_rate < 1800) + return 1200; + + /* lower than 40M 2ss mcs9, make it medium */ + if (bit_rate < 4000) + return 2600; + + /* not yet 80M 2ss mcs8/9, make it twice regular packet size */ + if (bit_rate < 7000) + return 3500; + + /* unlimited */ + return 0; +} + +struct rtw_fw_iter_ra_data { + struct rtw_dev *rtwdev; + u8 *payload; +}; + +static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_fw_iter_ra_data *ra_data = data; + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + u8 mac_id, rate, sgi, bw; + u8 mcs, nss; + u32 bit_rate; + + mac_id = GET_RA_REPORT_MACID(ra_data->payload); + if (si->mac_id != mac_id) + return; + + si->ra_report.txrate.flags = 0; + + rate = GET_RA_REPORT_RATE(ra_data->payload); + sgi = GET_RA_REPORT_SGI(ra_data->payload); + bw = GET_RA_REPORT_BW(ra_data->payload); + + if (rate < DESC_RATEMCS0) { + si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate); + goto legacy; + } + + rtw_desc_to_mcsrate(rate, &mcs, &nss); + if (rate >= DESC_RATEVHT1SS_MCS0) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + else if (rate >= DESC_RATEMCS0) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_MCS; + + if (rate >= DESC_RATEMCS0) { + si->ra_report.txrate.mcs = mcs; + si->ra_report.txrate.nss = nss; + } + + if (sgi) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + + if (bw == RTW_CHANNEL_WIDTH_80) + si->ra_report.txrate.bw = RATE_INFO_BW_80; + else if (bw == RTW_CHANNEL_WIDTH_40) + si->ra_report.txrate.bw = RATE_INFO_BW_40; + else + si->ra_report.txrate.bw = RATE_INFO_BW_20; + +legacy: + bit_rate = cfg80211_calculate_bitrate(&si->ra_report.txrate); + + si->ra_report.desc_rate = rate; + si->ra_report.bit_rate = bit_rate; + + sta->max_rc_amsdu_len = get_max_amsdu_len(bit_rate); +} + +static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_fw_iter_ra_data ra_data; + + if (WARN(length < 7, "invalid ra report c2h length\n")) + return; + + rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload); + ra_data.rtwdev = rtwdev; + ra_data.payload = payload; + rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); +} + void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; @@ -49,6 +145,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) case C2H_HALMAC: rtw_fw_c2h_cmd_handle_ext(rtwdev, skb); break; + case C2H_RA_RPT: + rtw_fw_ra_report_handle(rtwdev, c2h->payload, len); + break; default: break; } @@ -397,6 +496,24 @@ static u8 rtw_get_rsvd_page_location(struct rtw_dev *rtwdev, return location; } +void rtw_fw_set_pg_info(struct rtw_dev *rtwdev) +{ + struct rtw_lps_conf *conf = &rtwdev->lps_conf; + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + u8 loc_pg, loc_dpk; + + loc_pg = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_INFO); + loc_dpk = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_DPK); + + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_LPS_PG_INFO); + + LPS_PG_INFO_LOC(h2c_pkt, loc_pg); + LPS_PG_DPK_LOC(h2c_pkt, loc_dpk); + LPS_PG_SEC_CAM_EN(h2c_pkt, conf->sec_cam_backup); + + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} + void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev) { u8 h2c_pkt[H2C_PKT_SIZE] = {0}; @@ -442,6 +559,58 @@ rtw_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return skb_new; } +static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; + struct rtw_lps_pg_dpk_hdr *dpk_hdr; + struct sk_buff *skb; + u32 size; + + size = chip->tx_pkt_desc_sz + sizeof(*dpk_hdr); + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, chip->tx_pkt_desc_sz); + dpk_hdr = skb_put_zero(skb, sizeof(*dpk_hdr)); + dpk_hdr->dpk_ch = dpk_info->dpk_ch; + dpk_hdr->dpk_path_ok = dpk_info->dpk_path_ok[0]; + memcpy(dpk_hdr->dpk_txagc, dpk_info->dpk_txagc, 2); + memcpy(dpk_hdr->dpk_gs, dpk_info->dpk_gs, 4); + memcpy(dpk_hdr->coef, dpk_info->coef, 160); + + return skb; +} + +static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_lps_conf *conf = &rtwdev->lps_conf; + struct rtw_lps_pg_info_hdr *pg_info_hdr; + struct sk_buff *skb; + u32 size; + + size = chip->tx_pkt_desc_sz + sizeof(*pg_info_hdr); + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, chip->tx_pkt_desc_sz); + pg_info_hdr = skb_put_zero(skb, sizeof(*pg_info_hdr)); + pg_info_hdr->tx_bu_page_count = rtwdev->fifo.rsvd_drv_pg_num; + pg_info_hdr->macid = find_first_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM); + pg_info_hdr->sec_cam_count = + rtw_sec_cam_pg_backup(rtwdev, pg_info_hdr->sec_cam); + + conf->sec_cam_backup = pg_info_hdr->sec_cam_count != 0; + + return skb; +} + static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum rtw_rsvd_packet_type type) @@ -464,6 +633,12 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, case RSVD_QOS_NULL: skb_new = ieee80211_nullfunc_get(hw, vif, true); break; + case RSVD_LPS_PG_DPK: + skb_new = rtw_lps_pg_dpk_get(hw); + break; + case RSVD_LPS_PG_INFO: + skb_new = rtw_lps_pg_info_get(hw, vif); + break; default: return NULL; } @@ -498,9 +673,6 @@ static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size, { struct sk_buff *skb = rsvd_pkt->skb; - if (rsvd_pkt->add_txdesc) - rtw_fill_rsvd_page_desc(rtwdev, skb); - if (page >= 1) memcpy(buf + page_margin + page_size * (page - 1), skb->data, skb->len); @@ -625,16 +797,37 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) { iter = rtw_get_rsvd_page_skb(hw, vif, rsvd_pkt->type); if (!iter) { - rtw_err(rtwdev, "fail to build rsvd packet\n"); + rtw_err(rtwdev, "failed to build rsvd packet\n"); goto release_skb; } + + /* Fill the tx_desc for the rsvd pkt that requires one. + * And iter->len will be added with size of tx_desc_sz. + */ + if (rsvd_pkt->add_txdesc) + rtw_fill_rsvd_page_desc(rtwdev, iter); + rsvd_pkt->skb = iter; rsvd_pkt->page = total_page; - if (rsvd_pkt->add_txdesc) + + /* Reserved page is downloaded via TX path, and TX path will + * generate a tx_desc at the header to describe length of + * the buffer. If we are not counting page numbers with the + * size of tx_desc added at the first rsvd_pkt (usually a + * beacon, firmware default refer to the first page as the + * content of beacon), we could generate a buffer which size + * is smaller than the actual size of the whole rsvd_page + */ + if (total_page == 0) { + if (rsvd_pkt->type != RSVD_BEACON) { + rtw_err(rtwdev, "first page should be a beacon\n"); + goto release_skb; + } total_page += rtw_len_to_page(iter->len + tx_desc_sz, page_size); - else + } else { total_page += rtw_len_to_page(iter->len, page_size); + } } if (total_page > rtwdev->fifo.rsvd_drv_pg_num) { @@ -647,13 +840,24 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, if (!buf) goto release_skb; + /* Copy the content of each rsvd_pkt to the buf, and they should + * be aligned to the pages. + * + * Note that the first rsvd_pkt is a beacon no matter what vif->type. + * And that rsvd_pkt does not require tx_desc because when it goes + * through TX path, the TX path will generate one for it. + */ list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) { rtw_rsvd_page_list_to_buf(rtwdev, page_size, page_margin, page, buf, rsvd_pkt); - page += rtw_len_to_page(rsvd_pkt->skb->len, page_size); - } - list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) + if (page == 0) + page += rtw_len_to_page(rsvd_pkt->skb->len + + tx_desc_sz, page_size); + else + page += rtw_len_to_page(rsvd_pkt->skb->len, page_size); + kfree_skb(rsvd_pkt->skb); + } return buf; @@ -706,6 +910,11 @@ int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) goto free; } + /* The last thing is to download the *ONLY* beacon again, because + * the previous tx_desc is to describe the total rsvd page. Download + * the beacon again to replace the TX desc header, and we will get + * a correct tx_desc for the beacon in the rsvd page. + */ ret = rtw_download_beacon(rtwdev, vif); if (ret) { rtw_err(rtwdev, "failed to download beacon\n"); diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index e95d85bd097f..73d1b9ca8efc 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -11,22 +11,6 @@ /* FW bin information */ #define FW_HDR_SIZE 64 #define FW_HDR_CHKSUM_SIZE 8 -#define FW_HDR_VERSION 4 -#define FW_HDR_SUBVERSION 6 -#define FW_HDR_SUBINDEX 7 -#define FW_HDR_MONTH 16 -#define FW_HDR_DATE 17 -#define FW_HDR_HOUR 18 -#define FW_HDR_MIN 19 -#define FW_HDR_YEAR 20 -#define FW_HDR_MEM_USAGE 24 -#define FW_HDR_H2C_FMT_VER 28 -#define FW_HDR_DMEM_ADDR 32 -#define FW_HDR_DMEM_SIZE 36 -#define FW_HDR_IMEM_SIZE 48 -#define FW_HDR_EMEM_SIZE 52 -#define FW_HDR_EMEM_ADDR 56 -#define FW_HDR_IMEM_ADDR 60 #define FIFO_PAGE_SIZE_SHIFT 12 #define FIFO_PAGE_SIZE 4096 @@ -36,6 +20,7 @@ enum rtw_c2h_cmd_id { C2H_BT_INFO = 0x09, C2H_BT_MP_INFO = 0x0b, + C2H_RA_RPT = 0x0c, C2H_HW_FEATURE_REPORT = 0x19, C2H_WLAN_INFO = 0x27, C2H_HW_FEATURE_DUMP = 0xfd, @@ -58,6 +43,8 @@ enum rtw_rsvd_packet_type { RSVD_PROBE_RESP, RSVD_NULL, RSVD_QOS_NULL, + RSVD_LPS_PG_DPK, + RSVD_LPS_PG_INFO, }; enum rtw_fw_rf_type { @@ -86,6 +73,25 @@ struct rtw_iqk_para { u8 segment_iqk; }; +struct rtw_lps_pg_dpk_hdr { + u16 dpk_path_ok; + u8 dpk_txagc[2]; + u16 dpk_gs[2]; + u32 coef[2][20]; + u8 dpk_ch; +} __packed; + +struct rtw_lps_pg_info_hdr { + u8 macid; + u8 mbssid; + u8 pattern_count; + u8 mu_tab_group_id; + u8 sec_cam_count; + u8 tx_bu_page_count; + u16 rsvd; + u8 sec_cam[MAX_PG_CAM_BACKUP_NUM]; +} __packed; + struct rtw_rsvd_page { struct list_head list; struct sk_buff *skb; @@ -94,10 +100,44 @@ struct rtw_rsvd_page { bool add_txdesc; }; +struct rtw_fw_hdr { + __le16 signature; + u8 category; + u8 function; + __le16 version; /* 0x04 */ + u8 subversion; + u8 subindex; + __le32 rsvd; /* 0x08 */ + __le32 rsvd2; /* 0x0C */ + u8 month; /* 0x10 */ + u8 day; + u8 hour; + u8 min; + __le16 year; /* 0x14 */ + __le16 rsvd3; + u8 mem_usage; /* 0x18 */ + u8 rsvd4[3]; + __le16 h2c_fmt_ver; /* 0x1C */ + __le16 rsvd5; + __le32 dmem_addr; /* 0x20 */ + __le32 dmem_size; + __le32 rsvd6; + __le32 rsvd7; + __le32 imem_size; /* 0x30 */ + __le32 emem_size; + __le32 emem_addr; + __le32 imem_addr; +} __packed; + /* C2H */ #define GET_CCX_REPORT_SEQNUM(c2h_payload) (c2h_payload[8] & 0xfc) #define GET_CCX_REPORT_STATUS(c2h_payload) (c2h_payload[9] & 0xc0) +#define GET_RA_REPORT_RATE(c2h_payload) (c2h_payload[0] & 0x7f) +#define GET_RA_REPORT_SGI(c2h_payload) ((c2h_payload[0] & 0x80) >> 7) +#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) +#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) + /* PKT H2C */ #define H2C_PKT_CMD_ID 0xFF #define H2C_PKT_CATEGORY 0x01 @@ -146,6 +186,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_RSVD_PAGE 0x0 #define H2C_CMD_MEDIA_STATUS_RPT 0x01 #define H2C_CMD_SET_PWR_MODE 0x20 +#define H2C_CMD_LPS_PG_INFO 0x2b #define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RSSI_MONITOR 0x42 @@ -177,6 +218,12 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 5)) #define SET_PWR_MODE_SET_PWR_STATE(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8)) +#define LPS_PG_INFO_LOC(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16)) +#define LPS_PG_DPK_LOC(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24)) +#define LPS_PG_SEC_CAM_EN(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) #define SET_RSSI_INFO_MACID(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8)) #define SET_RSSI_INFO_RSSI(h2c_pkt, value) \ @@ -270,6 +317,7 @@ void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev); void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para); void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev); +void rtw_fw_set_pg_info(struct rtw_dev *rtwdev); void rtw_fw_query_bt_info(struct rtw_dev *rtwdev); void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw); void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h index aba329c9d0cf..4afbf0d163d1 100644 --- a/drivers/net/wireless/realtek/rtw88/hci.h +++ b/drivers/net/wireless/realtek/rtw88/hci.h @@ -13,6 +13,7 @@ struct rtw_hci_ops { int (*setup)(struct rtw_dev *rtwdev); int (*start)(struct rtw_dev *rtwdev); void (*stop)(struct rtw_dev *rtwdev); + void (*deep_ps)(struct rtw_dev *rtwdev, bool enter); int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size); int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size); @@ -47,6 +48,11 @@ static inline void rtw_hci_stop(struct rtw_dev *rtwdev) rtwdev->hci.ops->stop(rtwdev); } +static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter) +{ + rtwdev->hci.ops->deep_ps(rtwdev, enter); +} + static inline int rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) { diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index b61b073031e5..507970387b2a 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -47,7 +47,7 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, value8 = rtw_read8(rtwdev, REG_CCK_CHECK); value8 = value8 & ~BIT_CHECK_CCK_EN; - if (channel > 35) + if (IS_CH_5G_BAND(channel)) value8 |= BIT_CHECK_CCK_EN; rtw_write8(rtwdev, REG_CCK_CHECK, value8); } @@ -261,7 +261,7 @@ static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN; rtw_write32(rtwdev, REG_CPU_DMEM_CON, value); - rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); + rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C; rtw_write8(rtwdev, REG_CR_EXT + 3, value8); @@ -312,15 +312,16 @@ void rtw_mac_power_off(struct rtw_dev *rtwdev) static bool check_firmware_size(const u8 *data, u32 size) { + const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; u32 dmem_size; u32 imem_size; u32 emem_size; u32 real_size; - dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); - imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); - emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? - le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; + dmem_size = le32_to_cpu(fw_hdr->dmem_size); + imem_size = le32_to_cpu(fw_hdr->imem_size); + emem_size = (fw_hdr->mem_usage & BIT(4)) ? + le32_to_cpu(fw_hdr->emem_size) : 0; dmem_size += FW_HDR_CHKSUM_SIZE; imem_size += FW_HDR_CHKSUM_SIZE; @@ -566,27 +567,10 @@ download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, return 0; } -static void update_firmware_info(struct rtw_dev *rtwdev, - struct rtw_fw_state *fw) -{ - const u8 *data = fw->firmware->data; - - fw->h2c_version = - le16_to_cpu(*((__le16 *)(data + FW_HDR_H2C_FMT_VER))); - fw->version = - le16_to_cpu(*((__le16 *)(data + FW_HDR_VERSION))); - fw->sub_version = *(data + FW_HDR_SUBVERSION); - fw->sub_index = *(data + FW_HDR_SUBINDEX); - - rtw_dbg(rtwdev, RTW_DBG_FW, "fw h2c version: %x\n", fw->h2c_version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw version: %x\n", fw->version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub version: %x\n", fw->sub_version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub index: %x\n", fw->sub_index); -} - static int start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) { + const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; const u8 *cur_fw; u16 val; u32 imem_size; @@ -595,10 +579,10 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) u32 addr; int ret; - dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); - imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); - emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? - le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; + dmem_size = le32_to_cpu(fw_hdr->dmem_size); + imem_size = le32_to_cpu(fw_hdr->imem_size); + emem_size = (fw_hdr->mem_usage & BIT(4)) ? + le32_to_cpu(fw_hdr->emem_size) : 0; dmem_size += FW_HDR_CHKSUM_SIZE; imem_size += FW_HDR_CHKSUM_SIZE; emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; @@ -608,14 +592,14 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) rtw_write16(rtwdev, REG_MCUFW_CTRL, val); cur_fw = data + FW_HDR_SIZE; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->dmem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size); if (ret) return ret; cur_fw = data + FW_HDR_SIZE + dmem_size; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->imem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size); if (ret) @@ -623,7 +607,7 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) if (emem_size) { cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->emem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, emem_size); @@ -699,15 +683,13 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) if (ret) goto dlfw_fail; - update_firmware_info(rtwdev, fw); - /* reset desc and index */ rtw_hci_setup(rtwdev); rtwdev->h2c.last_box_num = 0; rtwdev->h2c.seq = 0; - rtw_flag_set(rtwdev, RTW_FLAG_FW_RUNNING); + set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); return 0; @@ -719,6 +701,93 @@ dlfw_fail: return ret; } +static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) +{ + struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; + u32 prio_queues = 0; + + if (queues & BIT(IEEE80211_AC_VO)) + prio_queues |= BIT(rqpn->dma_map_vo); + if (queues & BIT(IEEE80211_AC_VI)) + prio_queues |= BIT(rqpn->dma_map_vi); + if (queues & BIT(IEEE80211_AC_BE)) + prio_queues |= BIT(rqpn->dma_map_be); + if (queues & BIT(IEEE80211_AC_BK)) + prio_queues |= BIT(rqpn->dma_map_bk); + + return prio_queues; +} + +static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, + u32 prio_queue, bool drop) +{ + u32 addr; + 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: + return; + } + + /* 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); + if (rsvd_page == avail_page) + return; + + msleep(20); + } + + /* priority queue is still not empty, throw a warning, + * + * Note that if we want to flush the tx queue when having a lot of + * traffic (ex, 100Mbps up), some of the packets could be dropped. + * And it requires like ~2secs to flush the full priority queue. + */ + if (!drop) + rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue); +} + +static void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev, + u32 prio_queues, bool drop) +{ + u32 q; + + for (q = 0; q < RTW_DMA_MAPPING_MAX; q++) + if (prio_queues & BIT(q)) + __rtw_mac_flush_prio_queue(rtwdev, q, drop); +} + +void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop) +{ + u32 prio_queues = 0; + + /* If all of the hardware queues are requested to flush, + * or the priority queues are not mapped yet, + * flush all of the priority queues + */ + if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn) + prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1; + else + prio_queues = get_priority_queues(rtwdev, queues); + + rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop); +} + static int txdma_queue_mapping(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -743,6 +812,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) return -EINVAL; } + rtwdev->fifo.rqpn = rqpn; txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index efe6f731f240..592dc830160c 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -31,5 +31,11 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev); void rtw_mac_power_off(struct rtw_dev *rtwdev); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); +void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); + +static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop) +{ + rtw_mac_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, drop); +} #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index a203b4705b94..34a1c3b53cd4 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -10,6 +10,7 @@ #include "coex.h" #include "ps.h" #include "reg.h" +#include "bf.h" #include "debug.h" static void rtw_ops_tx(struct ieee80211_hw *hw, @@ -17,19 +18,30 @@ static void rtw_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtw_dev *rtwdev = hw->priv; - struct rtw_tx_pkt_info pkt_info = {0}; - if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING)) - goto out; + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) { + ieee80211_free_txskb(hw, skb); + return; + } - rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb); - if (rtw_hci_tx(rtwdev, &pkt_info, skb)) - goto out; + rtw_tx(rtwdev, control, skb); +} - return; +static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; -out: - ieee80211_free_txskb(hw, skb); + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) + return; + + spin_lock_bh(&rtwdev->txq_lock); + if (list_empty(&rtwtxq->list)) + list_add_tail(&rtwtxq->list, &rtwdev->txqs); + spin_unlock_bh(&rtwdev->txq_lock); + + tasklet_schedule(&rtwdev->tx_tasklet); } static int rtw_ops_start(struct ieee80211_hw *hw) @@ -60,6 +72,8 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (hw->conf.flags & IEEE80211_CONF_IDLE) { rtw_enter_ips(rtwdev); @@ -72,6 +86,15 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) } } + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (hw->conf.flags & IEEE80211_CONF_PS) { + rtwdev->ps_enabled = true; + } else { + rtwdev->ps_enabled = false; + rtw_leave_lps(rtwdev); + } + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) rtw_set_channel(rtwdev); @@ -135,10 +158,14 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, rtwvif->stats.tx_cnt = 0; rtwvif->stats.rx_cnt = 0; rtwvif->in_lps = false; + memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); rtwvif->conf = &rtw_vif_port[port]; + rtw_txq_init(rtwdev, vif->txq); mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: @@ -181,6 +208,10 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + + rtw_txq_cleanup(rtwdev, vif->txq); + eth_zero_addr(rtwvif->mac_addr); config |= PORT_SET_MAC_ADDR; rtwvif->net_type = RTW_NET_NO_LINK; @@ -204,6 +235,8 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) rtwdev->hal.rcr |= BIT_AM | BIT_AB; @@ -238,6 +271,54 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +/* Only have one group of EDCA parameters now */ +static const u32 ac_to_edca_param[IEEE80211_NUM_ACS] = { + [IEEE80211_AC_VO] = REG_EDCA_VO_PARAM, + [IEEE80211_AC_VI] = REG_EDCA_VI_PARAM, + [IEEE80211_AC_BE] = REG_EDCA_BE_PARAM, + [IEEE80211_AC_BK] = REG_EDCA_BK_PARAM, +}; + +static u8 rtw_aifsn_to_aifs(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, u8 aifsn) +{ + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + u8 slot_time; + u8 sifs; + + slot_time = vif->bss_conf.use_short_slot ? 9 : 20; + sifs = rtwdev->hal.current_band_type == RTW_BAND_5G ? 16 : 10; + + return aifsn * slot_time + sifs; +} + +static void __rtw_conf_tx(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, u16 ac) +{ + struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + u32 edca_param = ac_to_edca_param[ac]; + u8 ecw_max, ecw_min; + u8 aifs; + + /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ + ecw_max = ilog2(params->cw_max + 1); + ecw_min = ilog2(params->cw_min + 1); + aifs = rtw_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_TXOP_LMT, params->txop); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMAX, ecw_max); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMIN, ecw_min); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_AIFS, aifs); +} + +static void rtw_conf_tx(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif) +{ + u16 ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + __rtw_conf_tx(rtwdev, rtwvif, ac); +} + static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, @@ -249,6 +330,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed & BSS_CHANGED_ASSOC) { struct rtw_chip_info *chip = rtwdev->chip; enum rtw_net_type net_type; @@ -262,13 +345,19 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true); rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true); rtw_add_rsvd_page(rtwdev, RSVD_NULL, true); + rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_DPK, true); + rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_INFO, true); rtw_fw_download_rsvd_page(rtwdev, vif); rtw_send_rsvd_page_h2c(rtwdev); rtw_coex_media_status_notify(rtwdev, conf->assoc); + if (rtw_bf_support) + rtw_bf_assoc(rtwdev, vif, conf); } else { + rtw_leave_lps(rtwdev); net_type = RTW_NET_NO_LINK; rtwvif->aid = 0; rtw_reset_rsvd_page(rtwdev); + rtw_bf_disassoc(rtwdev, vif, conf); } rtwvif->net_type = net_type; @@ -284,11 +373,39 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON) rtw_fw_download_rsvd_page(rtwdev, vif); + if (changed & BSS_CHANGED_MU_GROUPS) { + struct rtw_chip_info *chip = rtwdev->chip; + + chip->ops->set_gid_table(rtwdev, vif, conf); + } + + if (changed & BSS_CHANGED_ERP_SLOT) + rtw_conf_tx(rtwdev, rtwvif); + rtw_vif_port_config(rtwdev, rtwvif, config); mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 ac, + const struct ieee80211_tx_queue_params *params) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + + mutex_lock(&rtwdev->mutex); + + rtw_leave_lps_deep(rtwdev); + + rtwvif->tx_params[ac] = *params; + __rtw_conf_tx(rtwdev, rtwvif, ac); + + mutex_unlock(&rtwdev->mutex); + + return 0; +} + static u8 rtw_acquire_macid(struct rtw_dev *rtwdev) { unsigned long mac_id; @@ -311,6 +428,7 @@ static int rtw_ops_sta_add(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int i; int ret = 0; mutex_lock(&rtwdev->mutex); @@ -325,6 +443,8 @@ static int rtw_ops_sta_add(struct ieee80211_hw *hw, si->vif = vif; si->init_ra_lv = 1; ewma_rssi_init(&si->avg_rssi); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw_txq_init(rtwdev, sta->txq[i]); rtw_update_sta_info(rtwdev, si); rtw_fw_media_status_report(rtwdev, si->mac_id, true); @@ -345,12 +465,18 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int i; mutex_lock(&rtwdev->mutex); rtw_release_macid(rtwdev, si->mac_id); rtw_fw_media_status_report(rtwdev, si->mac_id, false); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw_txq_cleanup(rtwdev, sta->txq[i]); + + kfree(si->mask); + rtwdev->sta_cnt--; rtw_info(rtwdev, "sta %pM with macid %d left\n", @@ -397,6 +523,8 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { hw_key_idx = rtw_sec_get_free_cam(sec); } else { @@ -418,10 +546,15 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, hw_key_type, hw_key_idx); break; case DISABLE_KEY: + rtw_mac_flush_all_queues(rtwdev, false); rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx); break; } + /* download new cam settings for PG to backup */ + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + rtw_fw_download_rsvd_page(rtwdev, vif); + out: mutex_unlock(&rtwdev->mutex); @@ -434,6 +567,8 @@ static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, { struct ieee80211_sta *sta = params->sta; u16 tid = params->tid; + struct ieee80211_txq *txq = sta->txq[tid]; + struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; switch (params->action) { case IEEE80211_AMPDU_TX_START: @@ -441,9 +576,12 @@ static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); + break; case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: break; @@ -463,18 +601,18 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; u32 config = 0; - rtw_leave_lps(rtwdev, rtwvif); - mutex_lock(&rtwdev->mutex); + rtw_leave_lps(rtwdev); + ether_addr_copy(rtwvif->mac_addr, mac_addr); config |= PORT_SET_MAC_ADDR; rtw_vif_port_config(rtwdev, rtwvif, config); rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); - rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE); - rtw_flag_set(rtwdev, RTW_FLAG_SCANNING); + set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); + set_bit(RTW_FLAG_SCANNING, rtwdev->flags); mutex_unlock(&rtwdev->mutex); } @@ -488,8 +626,8 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); - rtw_flag_clear(rtwdev, RTW_FLAG_SCANNING); - rtw_flag_clear(rtwdev, RTW_FLAG_DIG_DISABLE); + clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); + clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); ether_addr_copy(rtwvif->mac_addr, vif->addr); config |= PORT_SET_MAC_ADDR; @@ -507,12 +645,99 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, struct rtw_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START); mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rtw_dev *rtwdev = hw->priv; + + mutex_lock(&rtwdev->mutex); + rtwdev->rts_threshold = value; + mutex_unlock(&rtwdev->mutex); + + return 0; +} + +static void rtw_ops_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + + sinfo->txrate = si->ra_report.txrate; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); +} + +static void rtw_ops_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct rtw_dev *rtwdev = hw->priv; + + mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + + rtw_mac_flush_queues(rtwdev, queues, drop); + mutex_unlock(&rtwdev->mutex); +} + +struct rtw_iter_bitrate_mask_data { + struct rtw_dev *rtwdev; + struct ieee80211_vif *vif; + const struct cfg80211_bitrate_mask *mask; +}; + +static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_iter_bitrate_mask_data *br_data = data; + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + + if (si->vif != br_data->vif) + return; + + /* free previous mask setting */ + kfree(si->mask); + si->mask = kmemdup(br_data->mask, sizeof(struct cfg80211_bitrate_mask), + GFP_ATOMIC); + if (!si->mask) { + si->use_cfg_mask = false; + return; + } + + si->use_cfg_mask = true; + rtw_update_sta_info(br_data->rtwdev, si); +} + +static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw_iter_bitrate_mask_data br_data; + + br_data.rtwdev = rtwdev; + br_data.vif = vif; + br_data.mask = mask; + rtw_iterate_stas_atomic(rtwdev, rtw_ra_mask_info_update_iter, &br_data); +} + +static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw_dev *rtwdev = hw->priv; + + rtw_ra_mask_info_update(rtwdev, vif, mask); + + return 0; +} + const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, + .wake_tx_queue = rtw_ops_wake_tx_queue, .start = rtw_ops_start, .stop = rtw_ops_stop, .config = rtw_ops_config, @@ -520,6 +745,7 @@ const struct ieee80211_ops rtw_ops = { .remove_interface = rtw_ops_remove_interface, .configure_filter = rtw_ops_configure_filter, .bss_info_changed = rtw_ops_bss_info_changed, + .conf_tx = rtw_ops_conf_tx, .sta_add = rtw_ops_sta_add, .sta_remove = rtw_ops_sta_remove, .set_key = rtw_ops_set_key, @@ -527,5 +753,9 @@ const struct ieee80211_ops rtw_ops = { .sw_scan_start = rtw_ops_sw_scan_start, .sw_scan_complete = rtw_ops_sw_scan_complete, .mgd_prepare_tx = rtw_ops_mgd_prepare_tx, + .set_rts_threshold = rtw_ops_set_rts_threshold, + .sta_statistics = rtw_ops_sta_statistics, + .flush = rtw_ops_flush, + .set_bitrate_mask = rtw_ops_set_bitrate_mask, }; EXPORT_SYMBOL(rtw_ops); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 6dd457741b15..021668f1b74f 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -12,16 +12,22 @@ #include "phy.h" #include "reg.h" #include "efuse.h" +#include "tx.h" #include "debug.h" +#include "bf.h" -static bool rtw_fw_support_lps; +unsigned int rtw_fw_lps_deep_mode; +EXPORT_SYMBOL(rtw_fw_lps_deep_mode); +bool rtw_bf_support = true; unsigned int rtw_debug_mask; EXPORT_SYMBOL(rtw_debug_mask); -module_param_named(support_lps, rtw_fw_support_lps, bool, 0644); +module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); +module_param_named(support_bf, rtw_bf_support, bool, 0644); module_param_named(debug_mask, rtw_debug_mask, uint, 0644); -MODULE_PARM_DESC(support_lps, "Set Y to enable Leisure Power Save support, to turn radio off between beacons"); +MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); +MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); MODULE_PARM_DESC(debug_mask, "Debugging mask"); static struct ieee80211_channel rtw_channeltable_2g[] = { @@ -84,6 +90,18 @@ static struct ieee80211_rate rtw_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +u16 rtw_desc_to_bitrate(u8 desc_rate) +{ + struct ieee80211_rate rate; + + if (WARN(desc_rate >= ARRAY_SIZE(rtw_ratetable), "invalid desc rate\n")) + return 0; + + rate = rtw_ratetable[desc_rate]; + + return rate.bitrate; +} + static struct ieee80211_supported_band rtw_band_2ghz = { .band = NL80211_BAND_2GHZ, @@ -112,29 +130,40 @@ static struct ieee80211_supported_band rtw_band_5ghz = { }; struct rtw_watch_dog_iter_data { + struct rtw_dev *rtwdev; struct rtw_vif *rtwvif; - bool active; - u8 assoc_cnt; }; +static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +{ + struct rtw_bf_info *bf_info = &rtwdev->bf_info; + struct rtw_chip_info *chip = rtwdev->chip; + u8 fix_rate_enable = 0; + u8 new_csi_rate_idx; + + if (rtwvif->bfee.role != RTW_BFEE_SU && + rtwvif->bfee.role != RTW_BFEE_MU) + return; + + chip->ops->cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi, + bf_info->cur_csi_rpt_rate, + fix_rate_enable, &new_csi_rate_idx); + + if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) + bf_info->cur_csi_rpt_rate = new_csi_rate_idx; +} + static void rtw_vif_watch_dog_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct rtw_watch_dog_iter_data *iter_data = data; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; - if (vif->type == NL80211_IFTYPE_STATION) { - if (vif->bss_conf.assoc) { - iter_data->assoc_cnt++; + if (vif->type == NL80211_IFTYPE_STATION) + if (vif->bss_conf.assoc) iter_data->rtwvif = rtwvif; - } - if (rtwvif->stats.tx_cnt > RTW_LPS_THRESHOLD || - rtwvif->stats.rx_cnt > RTW_LPS_THRESHOLD) - iter_data->active = true; - } else { - /* only STATION mode can enter lps */ - iter_data->active = true; - } + + rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); rtwvif->stats.tx_unicast = 0; rtwvif->stats.rx_unicast = 0; @@ -149,46 +178,74 @@ static void rtw_watch_dog_work(struct work_struct *work) { struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, watch_dog_work.work); + struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_watch_dog_iter_data data = {}; - bool busy_traffic = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + bool ps_active; - if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING)) - return; + mutex_lock(&rtwdev->mutex); + + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) + goto unlock; ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); if (rtwdev->stats.tx_cnt > 100 || rtwdev->stats.rx_cnt > 100) - rtw_flag_set(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + set_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); else - rtw_flag_clear(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); - if (busy_traffic != rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC)) + if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) rtw_coex_wl_status_change_notify(rtwdev); + if (stats->tx_cnt > RTW_LPS_THRESHOLD || + stats->rx_cnt > RTW_LPS_THRESHOLD) + ps_active = true; + else + ps_active = false; + + ewma_tp_add(&stats->tx_ewma_tp, + (u32)(stats->tx_unicast >> RTW_TP_SHIFT)); + ewma_tp_add(&stats->rx_ewma_tp, + (u32)(stats->rx_unicast >> RTW_TP_SHIFT)); + stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); + stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); + /* reset tx/rx statictics */ - rtwdev->stats.tx_unicast = 0; - rtwdev->stats.rx_unicast = 0; - rtwdev->stats.tx_cnt = 0; - rtwdev->stats.rx_cnt = 0; + stats->tx_unicast = 0; + stats->rx_unicast = 0; + stats->tx_cnt = 0; + stats->rx_cnt = 0; + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) + goto unlock; + + /* make sure BB/RF is working for dynamic mech */ + rtw_leave_lps(rtwdev); + + rtw_phy_dynamic_mechanism(rtwdev); + + data.rtwdev = rtwdev; /* use atomic version to avoid taking local->iflist_mtx mutex */ rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter * lps, because fw does not handle the overlapped beacon interval + * + * mac80211 should iterate vifs and determine if driver can enter + * ps by passing IEEE80211_CONF_PS to us, all we need to do is to + * get that vif and check if device is having traffic more than the + * threshold. */ - if (rtw_fw_support_lps && - data.rtwvif && !data.active && data.assoc_cnt == 1) - rtw_enter_lps(rtwdev, data.rtwvif); - - if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING)) - return; - - rtw_phy_dynamic_mechanism(rtwdev); + if (rtwdev->ps_enabled && data.rtwvif && !ps_active) + rtw_enter_lps(rtwdev, data.rtwvif->port); rtwdev->watch_dog_cnt++; + +unlock: + mutex_unlock(&rtwdev->mutex); } static void rtw_c2h_work(struct work_struct *work) @@ -203,6 +260,40 @@ static void rtw_c2h_work(struct work_struct *work) } } +struct rtw_txq_ba_iter_data { +}; + +static void rtw_txq_ba_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int ret; + u8 tid; + + tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); + while (tid != IEEE80211_NUM_TIDS) { + clear_bit(tid, si->tid_ba); + ret = ieee80211_start_tx_ba_session(sta, tid, 0); + if (ret == -EINVAL) { + struct ieee80211_txq *txq; + struct rtw_txq *rtwtxq; + + txq = sta->txq[tid]; + rtwtxq = (struct rtw_txq *)txq->drv_priv; + set_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags); + } + + tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); + } +} + +static void rtw_txq_ba_work(struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ba_work); + struct rtw_txq_ba_iter_data data; + + rtw_iterate_stas_atomic(rtwdev, rtw_txq_ba_iter, &data); +} + void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *chan_params) { @@ -311,7 +402,7 @@ void rtw_set_channel(struct rtw_dev *rtwdev) if (hal->current_band_type == RTW_BAND_5G) { rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G); } else { - if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING)) + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G); else rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G_NOFORSCAN); @@ -529,12 +620,71 @@ static u8 get_rate_id(u8 wireless_set, enum rtw_bandwidth bw_mode, u8 tx_num) #define RA_MASK_OFDM_IN_HT_2G 0x00010 #define RA_MASK_OFDM_IN_HT_5G 0x00030 +static u64 rtw_update_rate_mask(struct rtw_dev *rtwdev, + struct rtw_sta_info *si, + u64 ra_mask, bool is_vht_enable, + u8 wireless_set) +{ + struct rtw_hal *hal = &rtwdev->hal; + const struct cfg80211_bitrate_mask *mask = si->mask; + u64 cfg_mask = GENMASK_ULL(63, 0); + u8 rssi_level, band; + + if (wireless_set != WIRELESS_CCK) { + rssi_level = si->rssi_level; + if (rssi_level == 0) + ra_mask &= 0xffffffffffffffffULL; + else if (rssi_level == 1) + ra_mask &= 0xfffffffffffffff0ULL; + else if (rssi_level == 2) + ra_mask &= 0xffffffffffffefe0ULL; + else if (rssi_level == 3) + ra_mask &= 0xffffffffffffcfc0ULL; + else if (rssi_level == 4) + ra_mask &= 0xffffffffffff8f80ULL; + else if (rssi_level >= 5) + ra_mask &= 0xffffffffffff0f00ULL; + } + + if (!si->use_cfg_mask) + return ra_mask; + + band = hal->current_band_type; + if (band == RTW_BAND_2G) { + band = NL80211_BAND_2GHZ; + cfg_mask = mask->control[band].legacy; + } else if (band == RTW_BAND_5G) { + band = NL80211_BAND_5GHZ; + cfg_mask = u64_encode_bits(mask->control[band].legacy, + RA_MASK_OFDM_RATES); + } + + if (!is_vht_enable) { + if (ra_mask & RA_MASK_HT_RATES_1SS) + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], + RA_MASK_HT_RATES_1SS); + if (ra_mask & RA_MASK_HT_RATES_2SS) + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], + RA_MASK_HT_RATES_2SS); + } else { + if (ra_mask & RA_MASK_VHT_RATES_1SS) + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], + RA_MASK_VHT_RATES_1SS); + if (ra_mask & RA_MASK_VHT_RATES_2SS) + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], + RA_MASK_VHT_RATES_2SS); + } + + ra_mask &= cfg_mask; + + return ra_mask; +} + void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) { struct ieee80211_sta *sta = si->sta; struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_hal *hal = &rtwdev->hal; - u8 rssi_level; u8 wireless_set; u8 bw_mode; u8 rate_id; @@ -627,21 +777,8 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) rate_id = get_rate_id(wireless_set, bw_mode, tx_num); - if (wireless_set != WIRELESS_CCK) { - rssi_level = si->rssi_level; - if (rssi_level == 0) - ra_mask &= 0xffffffffffffffffULL; - else if (rssi_level == 1) - ra_mask &= 0xfffffffffffffff0ULL; - else if (rssi_level == 2) - ra_mask &= 0xffffffffffffefe0ULL; - else if (rssi_level == 3) - ra_mask &= 0xffffffffffffcfc0ULL; - else if (rssi_level == 4) - ra_mask &= 0xffffffffffff8f80ULL; - else if (rssi_level >= 5) - ra_mask &= 0xffffffffffff0f00ULL; - } + ra_mask = rtw_update_rate_mask(rtwdev, si, ra_mask, is_vht_enable, + wireless_set); si->bw_mode = bw_mode; si->stbc_en = stbc_en; @@ -737,7 +874,7 @@ int rtw_core_start(struct rtw_dev *rtwdev) ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); - rtw_flag_set(rtwdev, RTW_FLAG_RUNNING); + set_bit(RTW_FLAG_RUNNING, rtwdev->flags); return 0; } @@ -752,8 +889,8 @@ void rtw_core_stop(struct rtw_dev *rtwdev) { struct rtw_coex *coex = &rtwdev->coex; - rtw_flag_clear(rtwdev, RTW_FLAG_RUNNING); - rtw_flag_clear(rtwdev, RTW_FLAG_FW_RUNNING); + clear_bit(RTW_FLAG_RUNNING, rtwdev->flags); + clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); cancel_delayed_work_sync(&rtwdev->watch_dog_work); cancel_delayed_work_sync(&coex->bt_relink_work); @@ -814,6 +951,12 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, IEEE80211_VHT_CAP_HTC_VHT | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 0; + + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << + IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | @@ -879,12 +1022,22 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context) { struct rtw_dev *rtwdev = context; struct rtw_fw_state *fw = &rtwdev->fw; + const struct rtw_fw_hdr *fw_hdr; if (!firmware) rtw_err(rtwdev, "failed to request firmware\n"); + fw_hdr = (const struct rtw_fw_hdr *)firmware->data; + fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); + fw->version = le16_to_cpu(fw_hdr->version); + fw->sub_version = fw_hdr->subversion; + fw->sub_index = fw_hdr->subindex; + fw->firmware = firmware; complete_all(&fw->completion); + + rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", + fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); } static int rtw_load_firmware(struct rtw_dev *rtwdev, const char *fw_name) @@ -914,6 +1067,7 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) switch (rtw_hci_type(rtwdev)) { case RTW_HCI_TYPE_PCIE: rtwdev->hci.rpwm_addr = 0x03d9; + rtwdev->hci.cpwm_addr = 0x03da; break; default: rtw_err(rtwdev, "unsupported hci type\n"); @@ -948,6 +1102,8 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) /* default use ack */ rtwdev->hal.rcr |= BIT_VHT_DACK; + hal->bfee_sts_cap = 3; + return ret; } @@ -1020,7 +1176,8 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) rtw_hw_config_rf_ant_num(rtwdev, efuse->hw_cap.ant_num); - if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE) + if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE || + efuse->hw_cap.nss > rtwdev->hal.rf_path_num) efuse->hw_cap.nss = rtwdev->hal.rf_path_num; rtw_dbg(rtwdev, RTW_DBG_EFUSE, @@ -1047,19 +1204,19 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) /* power on mac to read efuse */ ret = rtw_chip_efuse_enable(rtwdev); if (ret) - goto out; + goto out_unlock; ret = rtw_parse_efuse_map(rtwdev); if (ret) - goto out; + goto out_disable; ret = rtw_dump_hw_feature(rtwdev); if (ret) - goto out; + goto out_disable; ret = rtw_check_supported_rfe(rtwdev); if (ret) - goto out; + goto out_disable; if (efuse->crystal_cap == 0xff) efuse->crystal_cap = 0; @@ -1086,9 +1243,10 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; +out_disable: rtw_chip_efuse_disable(rtwdev); -out: +out_unlock: mutex_unlock(&rtwdev->mutex); return ret; } @@ -1141,22 +1299,41 @@ err_out: } EXPORT_SYMBOL(rtw_chip_info_setup); +static void rtw_stats_init(struct rtw_dev *rtwdev) +{ + struct rtw_traffic_stats *stats = &rtwdev->stats; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + int i; + + ewma_tp_init(&stats->tx_ewma_tp); + ewma_tp_init(&stats->rx_ewma_tp); + + for (i = 0; i < RTW_EVM_NUM; i++) + ewma_evm_init(&dm_info->ewma_evm[i]); + for (i = 0; i < RTW_SNR_NUM; i++) + ewma_snr_init(&dm_info->ewma_snr[i]); +} + int rtw_core_init(struct rtw_dev *rtwdev) { + struct rtw_chip_info *chip = rtwdev->chip; struct rtw_coex *coex = &rtwdev->coex; int ret; INIT_LIST_HEAD(&rtwdev->rsvd_page_list); + INIT_LIST_HEAD(&rtwdev->txqs); timer_setup(&rtwdev->tx_report.purge_timer, rtw_tx_report_purge_timer, 0); + tasklet_init(&rtwdev->tx_tasklet, rtw_tx_tasklet, + (unsigned long)rtwdev); INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); - INIT_DELAYED_WORK(&rtwdev->lps_work, rtw_lps_work); INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work); + INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); skb_queue_head_init(&rtwdev->c2h_queue); skb_queue_head_init(&rtwdev->coex.queue); skb_queue_head_init(&rtwdev->tx_report.queue); @@ -1164,6 +1341,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) spin_lock_init(&rtwdev->dm_lock); spin_lock_init(&rtwdev->rf_lock); spin_lock_init(&rtwdev->h2c.lock); + spin_lock_init(&rtwdev->txq_lock); spin_lock_init(&rtwdev->tx_report.q_lock); mutex_init(&rtwdev->mutex); @@ -1175,11 +1353,17 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); + if (!(BIT(rtw_fw_lps_deep_mode) & chip->lps_deep_mode_supported)) + rtwdev->lps_conf.deep_mode = LPS_DEEP_MODE_NONE; + else + rtwdev->lps_conf.deep_mode = rtw_fw_lps_deep_mode; mutex_lock(&rtwdev->mutex); rtw_add_rsvd_page(rtwdev, RSVD_BEACON, false); mutex_unlock(&rtwdev->mutex); + rtw_stats_init(rtwdev); + /* default rx filter setting */ rtwdev->hal.rcr = BIT_APP_FCS | BIT_APP_MIC | BIT_APP_ICV | BIT_HTC_LOC_CTRL | BIT_APP_PHYSTS | @@ -1204,6 +1388,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) if (fw->firmware) release_firmware(fw->firmware); + tasklet_kill(&rtwdev->tx_tasklet); spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); skb_queue_purge(&rtwdev->tx_report.queue); spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); @@ -1229,6 +1414,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->extra_tx_headroom = max_tx_headroom; hw->queues = IEEE80211_NUM_ACS; + hw->txq_data_size = sizeof(struct rtw_txq); hw->sta_data_size = sizeof(struct rtw_sta_info); hw->vif_data_size = sizeof(struct rtw_vif); @@ -1241,6 +1427,8 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, TX_AMSDU); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | @@ -1252,6 +1440,8 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); + rtw_set_supported_band(hw, rtwdev->chip); SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr); @@ -1268,6 +1458,9 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) rtw_debugfs_init(rtwdev); + rtwdev->bf_info.bfer_mu_cnt = 0; + rtwdev->bf_info.bfer_su_cnt = 0; + return 0; } EXPORT_SYMBOL(rtw_register_hw); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index bede3f38516e..d012eefcd0da 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -11,11 +11,13 @@ #include <linux/average.h> #include <linux/bitops.h> #include <linux/bitfield.h> +#include <linux/interrupt.h> #include "util.h" #define RTW_MAX_MAC_ID_NUM 32 #define RTW_MAX_SEC_CAM_NUM 32 +#define MAX_PG_CAM_BACKUP_NUM 8 #define RTW_WATCH_DOG_DELAY_TIME round_jiffies_relative(HZ * 2) @@ -27,6 +29,10 @@ #define RTW_RF_PATH_MAX 4 #define HW_FEATURE_LEN 13 +#define RTW_TP_SHIFT 18 /* bytes/2s --> Mbps */ + +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; @@ -50,10 +56,24 @@ struct rtw_hci { enum rtw_hci_type type; u32 rpwm_addr; + u32 cpwm_addr; u8 bulkout_num; }; +#define IS_CH_5G_BAND_1(channel) ((channel) >= 36 && (channel <= 48)) +#define IS_CH_5G_BAND_2(channel) ((channel) >= 52 && (channel <= 64)) +#define IS_CH_5G_BAND_3(channel) ((channel) >= 100 && (channel <= 144)) +#define IS_CH_5G_BAND_4(channel) ((channel) >= 149 && (channel <= 177)) + +#define IS_CH_5G_BAND_MID(channel) \ + (IS_CH_5G_BAND_2(channel) || IS_CH_5G_BAND_3(channel)) + +#define IS_CH_2G_BAND(channel) ((channel) <= 14) +#define IS_CH_5G_BAND(channel) \ + (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel) || \ + IS_CH_5G_BAND_3(channel) || IS_CH_5G_BAND_4(channel)) + enum rtw_supported_band { RTW_BAND_2G = 1 << 0, RTW_BAND_5G = 1 << 1, @@ -303,18 +323,50 @@ enum rtw_regulatory_domains { RTW_REGD_MAX }; +enum rtw_txq_flags { + RTW_TXQ_AMPDU, + RTW_TXQ_BLOCK_BA, +}; + enum rtw_flags { RTW_FLAG_RUNNING, RTW_FLAG_FW_RUNNING, RTW_FLAG_SCANNING, RTW_FLAG_INACTIVE_PS, RTW_FLAG_LEISURE_PS, + RTW_FLAG_LEISURE_PS_DEEP, RTW_FLAG_DIG_DISABLE, RTW_FLAG_BUSY_TRAFFIC, NUM_OF_RTW_FLAGS, }; +enum rtw_evm { + RTW_EVM_OFDM = 0, + RTW_EVM_1SS, + RTW_EVM_2SS_A, + RTW_EVM_2SS_B, + /* keep it last */ + RTW_EVM_NUM +}; + +enum rtw_snr { + RTW_SNR_OFDM_A = 0, + RTW_SNR_OFDM_B, + RTW_SNR_OFDM_C, + RTW_SNR_OFDM_D, + RTW_SNR_1SS_A, + RTW_SNR_1SS_B, + RTW_SNR_1SS_C, + RTW_SNR_1SS_D, + RTW_SNR_2SS_A, + RTW_SNR_2SS_B, + RTW_SNR_2SS_C, + RTW_SNR_2SS_D, + /* keep it last */ + RTW_SNR_NUM +}; + /* the power index is represented by differences, which cck-1s & ht40-1s are * the base values, so for 1s's differences, there are only ht20 & ofdm */ @@ -480,6 +532,7 @@ struct rtw_tx_pkt_info { bool fs; bool short_gi; bool report; + bool rts; }; struct rtw_rx_pkt_stat { @@ -502,10 +555,16 @@ struct rtw_rx_pkt_stat { s8 rx_power[RTW_RF_PATH_MAX]; u8 rssi; u8 rxsc; + s8 rx_snr[RTW_RF_PATH_MAX]; + u8 rx_evm[RTW_RF_PATH_MAX]; + s8 cfo_tail[RTW_RF_PATH_MAX]; + struct rtw_sta_info *si; struct ieee80211_vif *vif; }; +DECLARE_EWMA(tp, 10, 2); + struct rtw_traffic_stats { /* units in bytes */ u64 tx_unicast; @@ -518,6 +577,8 @@ struct rtw_traffic_stats { /* units in Mbps */ u32 tx_throughput; u32 rx_throughput; + struct ewma_tp tx_ewma_tp; + struct ewma_tp rx_ewma_tp; }; enum rtw_lps_mode { @@ -526,6 +587,12 @@ enum rtw_lps_mode { RTW_MODE_WMM_PS = 2, }; +enum rtw_lps_deep_mode { + LPS_DEEP_MODE_NONE = 0, + LPS_DEEP_MODE_LCLK = 1, + LPS_DEEP_MODE_PG = 2, +}; + enum rtw_pwr_state { RTW_RF_OFF = 0x0, RTW_RF_ON = 0x4, @@ -533,14 +600,14 @@ enum rtw_pwr_state { }; struct rtw_lps_conf { - /* the interface to enter lps */ - struct rtw_vif *rtwvif; enum rtw_lps_mode mode; + enum rtw_lps_deep_mode deep_mode; enum rtw_pwr_state state; u8 awake_interval; u8 rlbm; u8 smart_ps; u8 port_id; + bool sec_cam_backup; }; enum rtw_hw_key_type { @@ -576,6 +643,19 @@ struct rtw_tx_report { struct timer_list purge_timer; }; +struct rtw_ra_report { + struct rate_info txrate; + u32 bit_rate; + u8 desc_rate; +}; + +struct rtw_txq { + struct list_head list; + + unsigned long flags; + unsigned long last_push; +}; + #define RTW_BC_MC_MACID 1 DECLARE_EWMA(rssi, 10, 16); @@ -598,6 +678,41 @@ struct rtw_sta_info { bool updated; u8 init_ra_lv; u64 ra_mask; + + DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS); + + struct rtw_ra_report ra_report; + + bool use_cfg_mask; + struct cfg80211_bitrate_mask *mask; +}; + +enum rtw_bfee_role { + RTW_BFEE_NONE, + RTW_BFEE_SU, + RTW_BFEE_MU +}; + +struct rtw_bfee { + enum rtw_bfee_role role; + + u16 p_aid; + u8 g_id; + u8 mac_addr[ETH_ALEN]; + u8 sound_dim; + + /* SU-MIMO */ + u8 su_reg_index; + + /* MU-MIMO */ + u16 aid; +}; + +struct rtw_bf_info { + u8 bfer_mu_cnt; + u8 bfer_su_cnt; + DECLARE_BITMAP(bfer_su_reg_maping, 2); + u8 cur_csi_rpt_rate; }; struct rtw_vif { @@ -608,10 +723,13 @@ struct rtw_vif { u8 bssid[ETH_ALEN]; u8 port; u8 bcn_ctrl; + struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; const struct rtw_vif_port *conf; struct rtw_traffic_stats stats; bool in_lps; + + struct rtw_bfee bfee; }; struct rtw_regulatory { @@ -643,6 +761,14 @@ struct rtw_chip_ops { void (*phy_calibration)(struct rtw_dev *rtwdev); void (*dpk_track)(struct rtw_dev *rtwdev); void (*cck_pd_set)(struct rtw_dev *rtwdev, u8 level); + void (*pwr_track)(struct rtw_dev *rtwdev); + void (*config_bfee)(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable); + void (*set_gid_table)(struct rtw_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf); + void (*cfg_csi_rate)(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate); /* for coex */ void (*coex_set_init)(struct rtw_dev *rtwdev); @@ -747,6 +873,7 @@ enum rtw_dma_mapping { RTW_DMA_MAPPING_NORMAL = 2, RTW_DMA_MAPPING_HIGH = 3, + RTW_DMA_MAPPING_MAX, RTW_DMA_MAPPING_UNDEF, }; @@ -818,6 +945,34 @@ struct rtw_rfe_def { .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ } +#define RTW_PWR_TRK_5G_1 0 +#define RTW_PWR_TRK_5G_2 1 +#define RTW_PWR_TRK_5G_3 2 +#define RTW_PWR_TRK_5G_NUM 3 + +#define RTW_PWR_TRK_TBL_SZ 30 + +/* This table stores the values of TX power that will be adjusted by power + * tracking. + * + * For 5G bands, there are 3 different settings. + * For 2G there are cck rate and ofdm rate with different settings. + */ +struct rtw_pwr_track_tbl { + const u8 *pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_2gb_n; + const u8 *pwrtrk_2gb_p; + const u8 *pwrtrk_2ga_n; + const u8 *pwrtrk_2ga_p; + const u8 *pwrtrk_2g_cckb_n; + const u8 *pwrtrk_2g_cckb_p; + const u8 *pwrtrk_2g_ccka_n; + const u8 *pwrtrk_2g_ccka_p; +}; + /* hardware configuration for each IC */ struct rtw_chip_info { struct rtw_chip_ops *ops; @@ -844,6 +999,7 @@ struct rtw_chip_info { bool ht_supported; bool vht_supported; + u8 lps_deep_mode_supported; /* init values */ u8 sys_func_en; @@ -868,6 +1024,11 @@ struct rtw_chip_info { bool en_dis_dpd; u16 dpd_ratemask; + u8 iqk_threshold; + const struct rtw_pwr_track_tbl *pwr_track_tbl; + + u8 bfer_su_max_num; + u8 bfer_mu_max_num; /* coex paras */ u32 coex_para_ver; @@ -1121,10 +1282,26 @@ struct rtw_phy_cck_pd_reg { #define DACK_MSBK_BACKUP_NUM 0xf #define DACK_DCK_BACKUP_NUM 0x2 +struct rtw_swing_table { + const u8 *p[RTW_RF_PATH_MAX]; + const u8 *n[RTW_RF_PATH_MAX]; +}; + +struct rtw_pkt_count { + u16 num_bcn_pkt; + u16 num_qry_pkt[DESC_RATE_MAX]; +}; + +DECLARE_EWMA(evm, 10, 4); +DECLARE_EWMA(snr, 10, 4); + struct rtw_dm_info { u32 cck_fa_cnt; u32 ofdm_fa_cnt; u32 total_fa_cnt; + u32 cck_cca_cnt; + u32 ofdm_cca_cnt; + u32 total_cca_cnt; u32 cck_ok_cnt; u32 cck_err_cnt; @@ -1147,6 +1324,15 @@ struct rtw_dm_info { u8 cck_gi_u_bnd; u8 cck_gi_l_bnd; + u8 tx_rate; + u8 thermal_avg[RTW_RF_PATH_MAX]; + u8 thermal_meter_k; + s8 delta_power_index[RTW_RF_PATH_MAX]; + u8 default_ofdm_index; + bool pwr_trk_triggered; + bool pwr_trk_init_trigger; + struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX]; + /* backup dack results for each path and I/Q */ u32 dack_adck[RTW_RF_PATH_MAX]; u16 dack_msbk[RTW_RF_PATH_MAX][2][DACK_MSBK_BACKUP_NUM]; @@ -1157,6 +1343,17 @@ struct rtw_dm_info { /* [bandwidth 0:20M/1:40M][number of path] */ u8 cck_pd_lv[2][RTW_RF_PATH_MAX]; u32 cck_fa_avg; + + /* save the last rx phy status for debug */ + s8 rx_snr[RTW_RF_PATH_MAX]; + u8 rx_evm_dbm[RTW_RF_PATH_MAX]; + s16 cfo_tail[RTW_RF_PATH_MAX]; + u8 rssi[RTW_RF_PATH_MAX]; + u8 curr_rx_rate; + struct rtw_pkt_count cur_pkt_count; + 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_efuse { @@ -1170,7 +1367,9 @@ struct rtw_efuse { u8 country_code[2]; u8 rf_board_option; u8 rfe_option; - u8 thermal_meter; + u8 power_track_type; + u8 thermal_meter[RTW_RF_PATH_MAX]; + u8 thermal_meter_k; u8 crystal_cap; u8 ant_div_cfg; u8 ant_div_type; @@ -1252,7 +1451,7 @@ struct rtw_fifo_conf { u16 rsvd_cpu_instr_addr; u16 rsvd_fw_txbuf_addr; u16 rsvd_csibuf_addr; - enum rtw_dma_mapping pq_map[RTW_PQ_MAP_NUM]; + struct rtw_rqpn *rqpn; }; struct rtw_fw_state { @@ -1289,6 +1488,7 @@ struct rtw_hal { u8 rf_path_num; u8 antenna_tx; u8 antenna_rx; + u8 bfee_sts_cap; /* protect tx power section */ struct mutex tx_power_mutex; @@ -1326,6 +1526,7 @@ struct rtw_dev { struct rtw_sec_desc sec; struct rtw_traffic_stats stats; struct rtw_regulatory regd; + struct rtw_bf_info bf_info; struct rtw_dm_info dm_info; struct rtw_coex coex; @@ -1349,6 +1550,12 @@ struct rtw_dev { struct sk_buff_head c2h_queue; struct work_struct c2h_work; + /* used to protect txqs list */ + spinlock_t txq_lock; + struct list_head txqs; + struct tasklet_struct tx_tasklet; + struct work_struct ba_work; + struct rtw_tx_report tx_report; struct { @@ -1361,11 +1568,12 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; - struct delayed_work lps_work; + bool ps_enabled; struct dentry *debugfs; u8 sta_cnt; + u32 rts_threshold; DECLARE_BITMAP(mac_id_map, RTW_MAX_MAC_ID_NUM); DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS); @@ -1378,24 +1586,23 @@ struct rtw_dev { #include "hci.h" -static inline bool rtw_flag_check(struct rtw_dev *rtwdev, enum rtw_flags flag) +static inline bool rtw_is_assoc(struct rtw_dev *rtwdev) { - return test_bit(flag, rtwdev->flags); + return !!rtwdev->sta_cnt; } -static inline void rtw_flag_clear(struct rtw_dev *rtwdev, enum rtw_flags flag) +static inline struct ieee80211_txq *rtwtxq_to_txq(struct rtw_txq *rtwtxq) { - clear_bit(flag, rtwdev->flags); -} + void *p = rtwtxq; -static inline void rtw_flag_set(struct rtw_dev *rtwdev, enum rtw_flags flag) -{ - set_bit(flag, rtwdev->flags); + return container_of(p, struct ieee80211_txq, drv_priv); } -static inline bool rtw_is_assoc(struct rtw_dev *rtwdev) +static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw_vif *rtwvif) { - return !!rtwdev->sta_cnt; + void *p = rtwvif; + + return container_of(p, struct ieee80211_vif, drv_priv); } void rtw_get_channel_params(struct cfg80211_chan_def *chandef, @@ -1405,6 +1612,7 @@ bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val); bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value); void rtw_restore_reg(struct rtw_dev *rtwdev, struct rtw_backup_info *bckp, u32 num); +void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss); void rtw_set_channel(struct rtw_dev *rtwdev); void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, u32 config); @@ -1417,5 +1625,6 @@ int rtw_core_init(struct rtw_dev *rtwdev); void rtw_core_deinit(struct rtw_dev *rtwdev); int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw); void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw); +u16 rtw_desc_to_bitrate(u8 desc_rate); #endif diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index d90928be663b..17b9cdf9cb05 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -9,6 +9,7 @@ #include "tx.h" #include "rx.h" #include "fw.h" +#include "ps.h" #include "debug.h" static bool rtw_disable_msi; @@ -457,9 +458,9 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) /* reset read/write point */ rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff); - /* rest H2C Queue index */ - rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HOST_IDX); - rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HW_IDX); + /* reset H2C Queue index in a single write */ + rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, + BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX); } static void rtw_pci_reset_trx_ring(struct rtw_dev *rtwdev) @@ -536,6 +537,69 @@ static void rtw_pci_stop(struct rtw_dev *rtwdev) spin_unlock_irqrestore(&rtwpci->irq_lock, flags); } +static void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + struct rtw_pci_tx_ring *tx_ring; + bool tx_empty = true; + u8 queue; + + lockdep_assert_held(&rtwpci->irq_lock); + + /* Deep PS state is not allowed to TX-DMA */ + for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { + /* BCN queue is rsvd page, does not have DMA interrupt + * H2C queue is managed by firmware + */ + if (queue == RTW_TX_QUEUE_BCN || + queue == RTW_TX_QUEUE_H2C) + continue; + + tx_ring = &rtwpci->tx_rings[queue]; + + /* check if there is any skb DMAing */ + if (skb_queue_len(&tx_ring->queue)) { + tx_empty = false; + break; + } + } + + if (!tx_empty) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "TX path not empty, cannot enter deep power save state\n"); + return; + } + + set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags); + rtw_power_mode_change(rtwdev, true); +} + +static void rtw_pci_deep_ps_leave(struct rtw_dev *rtwdev) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + + lockdep_assert_held(&rtwpci->irq_lock); + + if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_power_mode_change(rtwdev, false); +} + +static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + unsigned long flags; + + spin_lock_irqsave(&rtwpci->irq_lock, flags); + + if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_pci_deep_ps_enter(rtwdev); + + if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_pci_deep_ps_leave(rtwdev); + + spin_unlock_irqrestore(&rtwpci->irq_lock, flags); +} + static u8 ac_to_hwq[] = { [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, @@ -616,6 +680,7 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, u8 *pkt_desc; struct rtw_pci_tx_buffer_desc *buf_desc; u32 bd_idx; + unsigned long flags; ring = &rtwpci->tx_rings[queue]; @@ -651,6 +716,10 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, tx_data = rtw_pci_get_tx_data(skb); tx_data->dma = dma; tx_data->sn = pkt_info->sn; + + spin_lock_irqsave(&rtwpci->irq_lock, flags); + + rtw_pci_deep_ps_leave(rtwdev); skb_queue_tail(&ring->queue, skb); /* kick off tx queue */ @@ -666,6 +735,7 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, reg_bcn_work |= BIT_PCI_BCNQ_FLAG; rtw_write8(rtwdev, RTK_PCI_TXBD_BCN_WORK, reg_bcn_work); } + spin_unlock_irqrestore(&rtwpci->irq_lock, flags); return 0; } @@ -1120,8 +1190,6 @@ static int rtw_pci_setup_resource(struct rtw_dev *rtwdev, struct pci_dev *pdev) goto err_io_unmap; } - rtw_pci_phy_cfg(rtwdev); - return 0; err_io_unmap: @@ -1142,6 +1210,7 @@ static struct rtw_hci_ops rtw_pci_ops = { .setup = rtw_pci_setup, .start = rtw_pci_start, .stop = rtw_pci_stop, + .deep_ps = rtw_pci_deep_ps, .read8 = rtw_pci_read8, .read16 = rtw_pci_read16, @@ -1233,6 +1302,8 @@ static int rtw_pci_probe(struct pci_dev *pdev, goto err_destroy_pci; } + rtw_pci_phy_cfg(rtwdev); + ret = rtw_register_hw(rtwdev, hw); if (ret) { rtw_err(rtwdev, "failed to register hw\n"); diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index d3d3f40de75e..a3e1e9578b65 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -20,15 +20,6 @@ union phy_table_tile { struct phy_cfg_pair cfg; }; -struct phy_pg_cfg_pair { - u32 band; - u32 rf_path; - u32 tx_num; - u32 addr; - u32 bitmask; - u32 data; -}; - static const u32 db_invert_table[12][8] = { {10, 13, 16, 20, 25, 32, 40, 50}, @@ -118,7 +109,7 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev) for (i = 0; i <= RTW_CHANNEL_WIDTH_40; i++) { for (j = 0; j < RTW_RF_PATH_MAX; j++) - dm_info->cck_pd_lv[i][j] = 0; + dm_info->cck_pd_lv[i][j] = CCK_PD_LV0; } dm_info->cck_fa_avg = CCK_FA_AVG_RESET; @@ -222,10 +213,19 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev) dm_info->min_rssi = data.min_rssi; } +static void rtw_phy_stat_rate_cnt(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->last_pkt_count = dm_info->cur_pkt_count; + memset(&dm_info->cur_pkt_count, 0, sizeof(dm_info->cur_pkt_count)); +} + static void rtw_phy_statistics(struct rtw_dev *rtwdev) { rtw_phy_stat_rssi(rtwdev); rtw_phy_stat_false_alarm(rtwdev); + rtw_phy_stat_rate_cnt(rtwdev); } #define DIG_PERF_FA_TH_LOW 250 @@ -394,7 +394,7 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev) u8 step[3]; bool linked; - if (rtw_flag_check(rtwdev, RTW_FLAG_DIG_DISABLE)) + if (test_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags)) return; if (rtw_phy_dig_check_damping(dm_info)) @@ -461,7 +461,6 @@ static void rtw_phy_dpk_track(struct rtw_dev *rtwdev) chip->ops->dpk_track(rtwdev); } -#define CCK_PD_LV_MAX 5 #define CCK_PD_FA_LV1_MIN 1000 #define CCK_PD_FA_LV0_MAX 500 @@ -471,10 +470,10 @@ static u8 rtw_phy_cck_pd_lv_unlink(struct rtw_dev *rtwdev) u32 cck_fa_avg = dm_info->cck_fa_avg; if (cck_fa_avg > CCK_PD_FA_LV1_MIN) - return 1; + return CCK_PD_LV1; if (cck_fa_avg < CCK_PD_FA_LV0_MAX) - return 0; + return CCK_PD_LV0; return CCK_PD_LV_MAX; } @@ -494,15 +493,15 @@ static u8 rtw_phy_cck_pd_lv_link(struct rtw_dev *rtwdev) u32 cck_fa_avg = dm_info->cck_fa_avg; if (igi > CCK_PD_IGI_LV4_VAL && rssi > CCK_PD_RSSI_LV4_VAL) - return 4; + return CCK_PD_LV4; if (igi > CCK_PD_IGI_LV3_VAL && rssi > CCK_PD_RSSI_LV3_VAL) - return 3; + return CCK_PD_LV3; if (igi > CCK_PD_IGI_LV2_VAL || rssi > CCK_PD_RSSI_LV2_VAL) - return 2; + return CCK_PD_LV2; if (cck_fa_avg > CCK_PD_FA_LV1_MIN) - return 1; + return CCK_PD_LV1; if (cck_fa_avg < CCK_PD_FA_LV0_MAX) - return 0; + return CCK_PD_LV0; return CCK_PD_LV_MAX; } @@ -539,6 +538,11 @@ static void rtw_phy_cck_pd(struct rtw_dev *rtwdev) chip->ops->cck_pd_set(rtwdev, level); } +static void rtw_phy_pwr_track(struct rtw_dev *rtwdev) +{ + rtwdev->chip->ops->pwr_track(rtwdev); +} + void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) { /* for further calculation */ @@ -547,6 +551,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) rtw_phy_cck_pd(rtwdev); rtw_phy_ra_info_update(rtwdev); rtw_phy_dpk_track(rtwdev); + rtw_phy_pwr_track(rtwdev); } #define FRAC_BITS 3 @@ -1211,10 +1216,8 @@ static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev, void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl) { - const struct phy_pg_cfg_pair *p = tbl->data; - const struct phy_pg_cfg_pair *end = p + tbl->size / 6; - - BUILD_BUG_ON(sizeof(struct phy_pg_cfg_pair) != sizeof(u32) * 6); + const struct rtw_phy_pg_cfg_pair *p = tbl->data; + const struct rtw_phy_pg_cfg_pair *end = p + tbl->size; for (; p < end; p++) { if (p->addr == 0xfe || p->addr == 0xffe) { @@ -1748,7 +1751,7 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, group = rtw_get_channel_group(ch); /* base power index for 2.4G/5G */ - if (ch <= 14) { + if (IS_CH_2G_BAND(ch)) { band = PHY_BAND_2G; *base = rtw_phy_get_2g_tx_power_index(rtwdev, &pwr_idx->pwr_idx_2g, @@ -1968,3 +1971,123 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev) rtw_phy_init_tx_power_limit(rtwdev, regd, bw, rs); } + +void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table) +{ + const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + u8 channel = rtwdev->hal.current_channel; + + if (IS_CH_2G_BAND(channel)) { + if (rtwdev->dm_info.tx_rate <= DESC_RATE11M) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2g_ccka_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2g_ccka_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2g_cckb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2g_cckb_n; + } else { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n; + } + } else if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_1]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_1]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_1]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_1]; + } else if (IS_CH_5G_BAND_3(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_2]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_2]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_2]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_2]; + } else if (IS_CH_5G_BAND_4(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_3]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_3]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_3]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_3]; + } else { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n; + } +} + +void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + ewma_thermal_add(&dm_info->avg_thermal[path], thermal); + dm_info->thermal_avg[path] = + ewma_thermal_read(&dm_info->avg_thermal[path]); +} + +bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 avg = ewma_thermal_read(&dm_info->avg_thermal[path]); + + if (avg == thermal) + return false; + + return true; +} + +u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 therm_avg, therm_efuse, therm_delta; + + therm_avg = dm_info->thermal_avg[path]; + therm_efuse = rtwdev->efuse.thermal_meter[path]; + therm_delta = abs(therm_avg - therm_efuse); + + return min_t(u8, therm_delta, RTW_PWR_TRK_TBL_SZ - 1); +} + +s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 tbl_path, u8 therm_path, u8 delta) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + const u8 *delta_swing_table_idx_pos; + const u8 *delta_swing_table_idx_neg; + + if (delta >= RTW_PWR_TRK_TBL_SZ) { + rtw_warn(rtwdev, "power track table overflow\n"); + return 0; + } + + if (!swing_table) { + rtw_warn(rtwdev, "swing table not configured\n"); + return 0; + } + + delta_swing_table_idx_pos = swing_table->p[tbl_path]; + delta_swing_table_idx_neg = swing_table->n[tbl_path]; + + if (!delta_swing_table_idx_pos || !delta_swing_table_idx_neg) { + rtw_warn(rtwdev, "invalid swing table index\n"); + return 0; + } + + if (dm_info->thermal_avg[therm_path] > + rtwdev->efuse.thermal_meter[therm_path]) + return delta_swing_table_idx_pos[delta]; + else + return -delta_swing_table_idx_neg[delta]; +} + +bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 delta_iqk; + + delta_iqk = abs(dm_info->thermal_avg[0] - dm_info->thermal_meter_k); + if (delta_iqk >= rtwdev->chip->iqk_threshold) { + dm_info->thermal_meter_k = dm_info->thermal_avg[0]; + return true; + } + return false; +} diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index e79b084628e7..af916d8784cd 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -41,9 +41,21 @@ void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data); void rtw_phy_init_tx_power(struct rtw_dev *rtwdev); void rtw_phy_load_tables(struct rtw_dev *rtwdev); +u8 rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate, + enum rtw_bandwidth bw, u8 channel, u8 regd); void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel); void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal); void rtw_phy_tx_power_limit_config(struct rtw_hal *hal); +void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path); +bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, + u8 path); +u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path); +s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 tbl_path, u8 therm_path, u8 delta); +bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev); +void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table); struct rtw_txpwr_lmt_cfg_pair { u8 regd; @@ -54,6 +66,15 @@ struct rtw_txpwr_lmt_cfg_pair { s8 txpwr_lmt; }; +struct rtw_phy_pg_cfg_pair { + u32 band; + u32 rf_path; + u32 tx_num; + u32 addr; + u32 bitmask; + u32 data; +}; + #define RTW_DECL_TABLE_PHY_COND_CORE(name, cfg, path) \ const struct rtw_table name ## _tbl = { \ .data = name, \ @@ -125,6 +146,15 @@ 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); +enum rtw_phy_cck_pd_lv { + CCK_PD_LV0, + CCK_PD_LV1, + CCK_PD_LV2, + CCK_PD_LV3, + CCK_PD_LV4, + CCK_PD_LV_MAX, +}; + #define MASKBYTE0 0xff #define MASKBYTE1 0xff00 #define MASKBYTE2 0xff0000 diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 9ecd14feb76b..820e0a3a141c 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -3,11 +3,13 @@ */ #include "main.h" +#include "reg.h" #include "fw.h" #include "ps.h" #include "mac.h" #include "coex.h" #include "debug.h" +#include "reg.h" static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) { @@ -18,14 +20,14 @@ static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) rtw_err(rtwdev, "leave idle state failed\n"); rtw_set_channel(rtwdev); - rtw_flag_clear(rtwdev, RTW_FLAG_INACTIVE_PS); + clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); return ret; } int rtw_enter_ips(struct rtw_dev *rtwdev) { - rtw_flag_set(rtwdev, RTW_FLAG_INACTIVE_PS); + set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); @@ -61,6 +63,85 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) return 0; } +void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) +{ + u8 request, confirm, polling; + u8 polling_cnt; + u8 retry_cnt = 0; + + for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { + request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); + confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + + /* toggle to request power mode, others remain 0 */ + request ^= request | BIT_RPWM_TOGGLE; + if (!enter) { + request |= POWER_MODE_ACK; + } else { + request |= POWER_MODE_LCLK; + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + request |= POWER_MODE_PG; + } + + rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); + + if (enter) + return; + + /* check confirm power mode has left power save state */ + for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) { + polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + if ((polling ^ confirm) & BIT_RPWM_TOGGLE) + return; + mdelay(20); + } + + /* in case of fw/hw missed the request, retry */ + rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", + retry_cnt); + } + + /* Hit here means that driver failed to change hardware power mode to + * active state after retry 3 times. If the power state is locked at + * Deep sleep, most of the hardware circuits is not working, even + * register read/write. It should be treated as fatal error and + * requires an entire analysis about the firmware/hardware + */ + WARN(1, "Hardware power state locked\n"); +} +EXPORT_SYMBOL(rtw_power_mode_change); + +static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev) +{ + rtw_hci_deep_ps(rtwdev, false); +} + +static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev) +{ + int i; + + /* Driver needs to wait for firmware to leave LPS state + * successfully. Firmware will send null packet to inform AP, + * and see if AP sends an ACK back, then firmware will restore + * the REG_TCR register. + * + * If driver does not wait for firmware, null packet with + * PS bit could be sent due to incorrect REG_TCR setting. + * + * In our test, 100ms should be enough for firmware to finish + * the flow. If REG_TCR Register is still incorrect after 100ms, + * just modify it directly, and throw a warn message. + */ + for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) { + if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0) + return; + msleep(20); + } + + rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0); + rtw_warn(rtwdev, "firmware failed to restore hardware setting\n"); +} + static void rtw_leave_lps_core(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -71,11 +152,30 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) conf->smart_ps = 0; rtw_fw_set_pwr_mode(rtwdev); - rtw_flag_clear(rtwdev, RTW_FLAG_LEISURE_PS); + rtw_fw_leave_lps_state_check(rtwdev); + + clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); } +static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) +{ + if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE) + return; + + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "Should enter LPS before entering deep PS\n"); + return; + } + + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + rtw_fw_set_pg_info(rtwdev); + + rtw_hci_deep_ps(rtwdev, true); +} + static void rtw_enter_lps_core(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -88,88 +188,62 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE); rtw_fw_set_pwr_mode(rtwdev); - rtw_flag_set(rtwdev, RTW_FLAG_LEISURE_PS); + set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -void rtw_lps_work(struct work_struct *work) +static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { - struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, - lps_work.work); struct rtw_lps_conf *conf = &rtwdev->lps_conf; - struct rtw_vif *rtwvif = conf->rtwvif; - if (WARN_ON(!rtwvif)) - return; - - if (conf->mode == RTW_MODE_LPS) - rtw_enter_lps_core(rtwdev); - else - rtw_leave_lps_core(rtwdev); -} - -void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) -{ - struct rtw_lps_conf *conf = &rtwdev->lps_conf; - - if (rtwvif->in_lps) + if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; conf->mode = RTW_MODE_LPS; - conf->rtwvif = rtwvif; - rtwvif->in_lps = true; + conf->port_id = port_id; - ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); + rtw_enter_lps_core(rtwdev); } -void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +static void __rtw_leave_lps(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; - if (!rtwvif->in_lps) + if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "Should leave deep PS before leaving LPS\n"); + __rtw_leave_lps_deep(rtwdev); + } + + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; conf->mode = RTW_MODE_ACTIVE; - conf->rtwvif = rtwvif; - rtwvif->in_lps = false; - ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); -} - -bool rtw_in_lps(struct rtw_dev *rtwdev) -{ - return rtw_flag_check(rtwdev, RTW_FLAG_LEISURE_PS); + rtw_leave_lps_core(rtwdev); } -void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { - struct rtw_lps_conf *conf = &rtwdev->lps_conf; + lockdep_assert_held(&rtwdev->mutex); - if (WARN_ON(!rtwvif)) + if (rtwdev->coex.stat.wl_force_lps_ctrl) return; - if (rtwvif->in_lps) - return; - - conf->mode = RTW_MODE_LPS; - conf->rtwvif = rtwvif; - rtwvif->in_lps = true; - - rtw_enter_lps_core(rtwdev); + __rtw_enter_lps(rtwdev, port_id); + __rtw_enter_lps_deep(rtwdev); } -void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +void rtw_leave_lps(struct rtw_dev *rtwdev) { - struct rtw_lps_conf *conf = &rtwdev->lps_conf; - - if (WARN_ON(!rtwvif)) - return; + lockdep_assert_held(&rtwdev->mutex); - if (!rtwvif->in_lps) - return; + __rtw_leave_lps_deep(rtwdev); + __rtw_leave_lps(rtwdev); +} - conf->mode = RTW_MODE_ACTIVE; - conf->rtwvif = rtwvif; - rtwvif->in_lps = false; +void rtw_leave_lps_deep(struct rtw_dev *rtwdev) +{ + lockdep_assert_held(&rtwdev->mutex); - rtw_leave_lps_core(rtwdev); + __rtw_leave_lps_deep(rtwdev); } diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 09e57405dc1b..25925eedbad4 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -7,14 +7,18 @@ #define RTW_LPS_THRESHOLD 2 +#define POWER_MODE_ACK BIT(6) +#define POWER_MODE_PG BIT(4) +#define POWER_MODE_LCLK BIT(0) + +#define LEAVE_LPS_TRY_CNT 5 + int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); -void rtw_lps_work(struct work_struct *work); -void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -bool rtw_in_lps(struct rtw_dev *rtwdev); +void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter); +void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id); +void rtw_leave_lps(struct rtw_dev *rtwdev); +void rtw_leave_lps_deep(struct rtw_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index fe793e270d22..7e817bc997eb 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -239,6 +239,10 @@ #define REG_EDCA_VI_PARAM 0x0504 #define REG_EDCA_BE_PARAM 0x0508 #define REG_EDCA_BK_PARAM 0x050C +#define BIT_MASK_TXOP_LMT GENMASK(26, 16) +#define BIT_MASK_CWMAX GENMASK(15, 12) +#define BIT_MASK_CWMIN GENMASK(11, 8) +#define BIT_MASK_AIFS GENMASK(7, 0) #define REG_PIFS 0x0512 #define REG_SIFS 0x0514 #define BIT_SHIFT_SIFS_OFDM_CTX 8 @@ -271,6 +275,7 @@ #define BIT_TSFT_SEL_TIMER0 (BIT(4) | BIT(5) | BIT(6)) #define REG_TCR 0x0604 +#define BIT_PWRMGT_HWDATA_EN BIT(7) #define REG_RCR 0x0608 #define BIT_APP_FCS BIT(31) #define BIT_APP_MIC BIT(30) @@ -305,6 +310,7 @@ #define REG_RX_PKT_LIMIT 0x060C #define REG_RX_DRVINFO_SZ 0x060F #define BIT_APP_PHYSTS BIT(28) +#define REG_MAR 0x0620 #define REG_USTIME_EDCA 0x0638 #define REG_ACKTO_CCK 0x0639 #define REG_RESP_SIFS_CCK 0x063C @@ -320,6 +326,7 @@ #define REG_RXFLTMAP0 0x06A0 #define REG_RXFLTMAP1 0x06A2 #define REG_RXFLTMAP2 0x06A4 +#define REG_RXFLTMAP4 0x068A #define REG_BT_COEX_TABLE0 0x06C0 #define REG_BT_COEX_TABLE1 0x06C4 #define REG_BT_COEX_BRK_TABLE 0x06C8 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 63abda3b0ebf..4bc14b1a6340 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -13,6 +13,7 @@ #include "mac.h" #include "reg.h" #include "debug.h" +#include "bf.h" static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, u8 rx_path, bool is_tx2_path); @@ -43,6 +44,8 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) efuse->country_code[1] = map->country_code[1]; efuse->bt_setting = map->rf_bt_setting; efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[RF_PATH_A] = map->thermal_meter; + efuse->thermal_meter_k = map->thermal_meter; for (i = 0; i < 4; i++) efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; @@ -75,6 +78,56 @@ static void rtw8822b_phy_rfe_init(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, 0x974, (BIT(11) | BIT(10)), 0x3); } +#define RTW_TXSCALE_SIZE 37 +static const u32 rtw8822b_txscale_tbl[RTW_TXSCALE_SIZE] = { + 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8, + 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180, + 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab, + 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe +}; + +static const u8 rtw8822b_get_swing_index(struct rtw_dev *rtwdev) +{ + u8 i = 0; + u32 swing, table_value; + + swing = rtw_read32_mask(rtwdev, 0xc1c, 0xffe00000); + for (i = 0; i < RTW_TXSCALE_SIZE; i++) { + table_value = rtw8822b_txscale_tbl[i]; + if (swing == table_value) + break; + } + + return i; +} + +static void rtw8822b_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 swing_idx = rtw8822b_get_swing_index(rtwdev); + u8 path; + + if (swing_idx >= RTW_TXSCALE_SIZE) + dm_info->default_ofdm_index = 24; + else + dm_info->default_ofdm_index = swing_idx; + + 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; +} + +static void rtw8822b_phy_bf_init(struct rtw_dev *rtwdev) +{ + rtw_bf_phy_init(rtwdev); + /* Grouping bitmap parameters */ + rtw_write32(rtwdev, 0x1C94, 0xAFFFAFFF); +} + static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) { struct rtw_hal *hal = &rtwdev->hal; @@ -106,6 +159,9 @@ static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) rtw_phy_init(rtwdev); rtw8822b_phy_rfe_init(rtwdev); + rtw8822b_pwrtrack_init(rtwdev); + + rtw8822b_phy_bf_init(rtwdev); } #define WLAN_SLOT_TIME 0x09 @@ -211,9 +267,8 @@ static int rtw8822b_mac_init(struct rtw_dev *rtwdev) static void rtw8822b_set_channel_rfe_efem(struct rtw_dev *rtwdev, u8 channel) { struct rtw_hal *hal = &rtwdev->hal; - bool is_channel_2g = (channel <= 14) ? true : false; - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { rtw_write32s_mask(rtwdev, REG_RFESEL0, 0xffffff, 0x705770); rtw_write32s_mask(rtwdev, REG_RFESEL8, MASKBYTE1, 0x57); rtw_write32s_mask(rtwdev, REG_RFECTL, BIT(4), 0); @@ -241,9 +296,8 @@ static void rtw8822b_set_channel_rfe_efem(struct rtw_dev *rtwdev, u8 channel) static void rtw8822b_set_channel_rfe_ifem(struct rtw_dev *rtwdev, u8 channel) { struct rtw_hal *hal = &rtwdev->hal; - bool is_channel_2g = (channel <= 14) ? true : false; - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { /* signal source */ rtw_write32s_mask(rtwdev, REG_RFESEL0, 0xffffff, 0x745774); rtw_write32s_mask(rtwdev, REG_RFESEL8, MASKBYTE1, 0x57); @@ -255,7 +309,7 @@ static void rtw8822b_set_channel_rfe_ifem(struct rtw_dev *rtwdev, u8 channel) rtw_write32s_mask(rtwdev, REG_RFEINV, BIT(11) | BIT(10) | 0x3f, 0x0); - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { if (hal->antenna_rx == BB_PATH_AB || hal->antenna_tx == BB_PATH_AB) { /* 2TX or 2RX */ @@ -337,6 +391,7 @@ struct rtw8822b_rfe_info { static const struct rtw8822b_rfe_info rtw8822b_rfe_info[] = { [2] = I2GE5G_CCUT(efem), + [3] = IFEM_EXT_CCUT(ifem), [5] = IFEM_EXT_CCUT(ifem), }; @@ -350,7 +405,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, u32 reg82c, reg830, reg838; bool is_efem_cca = false, is_ifem_cca = false, is_rfe_type = false; - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { cca_ccut = rfe_info->cca_ccut_2g; if (hal->antenna_rx == BB_PATH_A || @@ -381,7 +436,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, is_efem_cca = true; break; case RTW_RFE_IFEM2G_EFEM5G: - if (channel <= 14) + if (IS_CH_2G_BAND(channel)) is_ifem_cca = true; else is_efem_cca = true; @@ -405,9 +460,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, if (is_efem_cca && !(hal->cut_version == RTW_CHIP_VER_CUT_B)) rtw_write32_mask(rtwdev, REG_L1WT, MASKDWORD, 0x9194b2b9); - if (bw == RTW_CHANNEL_WIDTH_20 && - ((channel >= 52 && channel <= 64) || - (channel >= 100 && channel <= 144))) + if (bw == RTW_CHANNEL_WIDTH_20 && IS_CH_5G_BAND_MID(channel)) rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0, 0x4); } @@ -442,7 +495,7 @@ static void rtw8822b_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) rf_reg18 &= ~(RF18_BAND_MASK | RF18_CHANNEL_MASK | RF18_RFSI_MASK | RF18_BW_MASK); - rf_reg18 |= (channel <= 14 ? RF18_BAND_2G : RF18_BAND_5G); + rf_reg18 |= (IS_CH_2G_BAND(channel) ? RF18_BAND_2G : RF18_BAND_5G); rf_reg18 |= (channel & RF18_CHANNEL_MASK); if (channel > 144) rf_reg18 |= RF18_RFSI_GT_CH144; @@ -464,13 +517,13 @@ static void rtw8822b_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) break; } - if (channel <= 14) + if (IS_CH_2G_BAND(channel)) rf_reg_be = 0x0; - else if (channel >= 36 && channel <= 64) + else if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) rf_reg_be = low_band[(channel - 36) >> 1]; - else if (channel >= 100 && channel <= 144) + else if (IS_CH_5G_BAND_3(channel)) rf_reg_be = middle_band[(channel - 100) >> 1]; - else if (channel >= 149 && channel <= 177) + else if (IS_CH_5G_BAND_4(channel)) rf_reg_be = high_band[(channel - 149) >> 1]; else goto err; @@ -539,7 +592,7 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 rfe_option = efuse->rfe_option; u32 val32; - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x1); rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x0); rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x0); @@ -556,22 +609,22 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, } rtw_write32_mask(rtwdev, REG_RFEINV, 0x300, 0x2); - } else if (channel > 35) { + } else if (IS_CH_5G_BAND(channel)) { rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1); rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x1); rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x0); rtw_write32_mask(rtwdev, REG_RXCCAMSK, 0x0000FC00, 34); - if (channel >= 36 && channel <= 64) + if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x1); - else if (channel >= 100 && channel <= 144) + else if (IS_CH_5G_BAND_3(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x2); - else if (channel >= 149) + else if (IS_CH_5G_BAND_4(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x3); - if (channel >= 36 && channel <= 48) + if (IS_CH_5G_BAND_1(channel)) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x494); - else if (channel >= 52 && channel <= 64) + else if (IS_CH_5G_BAND_2(channel)) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x453); else if (channel >= 100 && channel <= 116) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x452); @@ -612,7 +665,7 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x1); - if (rfe_option == 2) { + if (rfe_option == 2 || rfe_option == 3) { rtw_write32_mask(rtwdev, REG_L1PKWT, 0x0000f000, 0x6); rtw_write32_mask(rtwdev, REG_ADC40, BIT(10), 0x1); } @@ -763,6 +816,7 @@ static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; s8 min_rx_power = -120; u8 pwdb = GET_PHY_STAT_P0_PWDB(phy_status); @@ -772,13 +826,19 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->bw = RTW_CHANNEL_WIDTH_20; pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], min_rx_power); + dm_info->rssi[RF_PATH_A] = pkt_stat->rssi; } static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; + s8 rx_evm; + u8 evm_dbm = 0; + u8 rssi; + int path; if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0) rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status); @@ -801,6 +861,34 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->signal_power = max3(pkt_stat->rx_power[RF_PATH_A], pkt_stat->rx_power[RF_PATH_B], min_rx_power); + + dm_info->curr_rx_rate = pkt_stat->rate; + + pkt_stat->rx_evm[RF_PATH_A] = GET_PHY_STAT_P1_RXEVM_A(phy_status); + pkt_stat->rx_evm[RF_PATH_B] = GET_PHY_STAT_P1_RXEVM_B(phy_status); + + pkt_stat->rx_snr[RF_PATH_A] = GET_PHY_STAT_P1_RXSNR_A(phy_status); + pkt_stat->rx_snr[RF_PATH_B] = GET_PHY_STAT_P1_RXSNR_B(phy_status); + + pkt_stat->cfo_tail[RF_PATH_A] = GET_PHY_STAT_P1_CFO_TAIL_A(phy_status); + pkt_stat->cfo_tail[RF_PATH_B] = GET_PHY_STAT_P1_CFO_TAIL_B(phy_status); + + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; + dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; + + rx_evm = pkt_stat->rx_evm[path]; + + if (rx_evm < 0) { + if (rx_evm == S8_MIN) + evm_dbm = 0; + else + evm_dbm = ((u8)-rx_evm >> 1); + } + dm_info->rx_evm_dbm[path] = evm_dbm; + } } static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, @@ -836,7 +924,8 @@ static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc); + pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && + GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); @@ -946,6 +1035,7 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev) u32 cck_fa_cnt; u32 ofdm_fa_cnt; u32 crc32_cnt; + u32 cca32_cnt; cck_enable = rtw_read32(rtwdev, 0x808) & BIT(28); cck_fa_cnt = rtw_read16(rtwdev, 0xa5c); @@ -969,6 +1059,15 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev) dm_info->vht_ok_cnt = crc32_cnt & 0xffff; dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16; + cca32_cnt = rtw_read32(rtwdev, 0xf08); + dm_info->ofdm_cca_cnt = ((cca32_cnt & 0xffff0000) >> 16); + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) { + cca32_cnt = rtw_read32(rtwdev, 0xfcc); + dm_info->cck_cca_cnt = cca32_cnt & 0xffff; + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + } + rtw_write32_set(rtwdev, 0x9a4, BIT(17)); rtw_write32_clr(rtwdev, 0x9a4, BIT(17)); rtw_write32_clr(rtwdev, 0xa2c, BIT(15)); @@ -1255,6 +1354,195 @@ static void rtw8822b_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) } } +static void rtw8822b_txagc_swing_offset(struct rtw_dev *rtwdev, u8 path, + u8 tx_pwr_idx_offset, + s8 *txagc_idx, u8 *swing_idx) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s8 delta_pwr_idx = dm_info->delta_power_index[path]; + u8 swing_upper_bound = dm_info->default_ofdm_index + 10; + u8 swing_lower_bound = 0; + u8 max_tx_pwr_idx_offset = 0xf; + s8 agc_index = 0; + u8 swing_index = dm_info->default_ofdm_index; + + tx_pwr_idx_offset = min_t(u8, tx_pwr_idx_offset, max_tx_pwr_idx_offset); + + if (delta_pwr_idx >= 0) { + if (delta_pwr_idx <= tx_pwr_idx_offset) { + agc_index = delta_pwr_idx; + swing_index = dm_info->default_ofdm_index; + } else if (delta_pwr_idx > tx_pwr_idx_offset) { + agc_index = tx_pwr_idx_offset; + swing_index = dm_info->default_ofdm_index + + delta_pwr_idx - tx_pwr_idx_offset; + swing_index = min_t(u8, swing_index, swing_upper_bound); + } + } else { + if (dm_info->default_ofdm_index > abs(delta_pwr_idx)) + swing_index = + dm_info->default_ofdm_index + delta_pwr_idx; + else + swing_index = swing_lower_bound; + swing_index = max_t(u8, swing_index, swing_lower_bound); + + agc_index = 0; + } + + if (swing_index >= RTW_TXSCALE_SIZE) { + rtw_warn(rtwdev, "swing index overflow\n"); + swing_index = RTW_TXSCALE_SIZE - 1; + } + *txagc_idx = agc_index; + *swing_idx = swing_index; +} + +static void rtw8822b_pwrtrack_set_pwr(struct rtw_dev *rtwdev, u8 path, + u8 pwr_idx_offset) +{ + s8 txagc_idx; + u8 swing_idx; + u32 reg1, reg2; + + if (path == RF_PATH_A) { + reg1 = 0xc94; + reg2 = 0xc1c; + } else if (path == RF_PATH_B) { + reg1 = 0xe94; + reg2 = 0xe1c; + } else { + return; + } + + rtw8822b_txagc_swing_offset(rtwdev, path, pwr_idx_offset, + &txagc_idx, &swing_idx); + rtw_write32_mask(rtwdev, reg1, GENMASK(29, 25), txagc_idx); + rtw_write32_mask(rtwdev, reg2, GENMASK(31, 21), + rtw8822b_txscale_tbl[swing_idx]); +} + +static void rtw8822b_pwrtrack_set(struct rtw_dev *rtwdev, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 pwr_idx_offset, tx_pwr_idx; + u8 channel = rtwdev->hal.current_channel; + u8 band_width = rtwdev->hal.current_band_width; + u8 regd = rtwdev->regd.txpwr_regd; + u8 tx_rate = dm_info->tx_rate; + u8 max_pwr_idx = rtwdev->chip->max_power_index; + + tx_pwr_idx = rtw_phy_get_tx_power_index(rtwdev, path, tx_rate, + band_width, channel, regd); + + tx_pwr_idx = min_t(u8, tx_pwr_idx, max_pwr_idx); + + pwr_idx_offset = max_pwr_idx - tx_pwr_idx; + + rtw8822b_pwrtrack_set_pwr(rtwdev, path, pwr_idx_offset); +} + +static void rtw8822b_phy_pwrtrack_path(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 power_idx_cur, power_idx_last; + u8 delta; + + /* 8822B only has one thermal meter at PATH A */ + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + power_idx_last = dm_info->delta_power_index[path]; + power_idx_cur = rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, + path, RF_PATH_A, delta); + + /* if delta of power indexes are the same, just skip */ + if (power_idx_cur == power_idx_last) + return; + + dm_info->delta_power_index[path] = power_idx_cur; + rtw8822b_pwrtrack_set(rtwdev, path); +} + +static void rtw8822b_phy_pwrtrack(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_swing_table swing_table; + u8 thermal_value, path; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[RF_PATH_A] == 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); + + 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; + + for (path = 0; path < rtwdev->hal.rf_path_num; path++) + rtw8822b_phy_pwrtrack_path(rtwdev, &swing_table, path); + +iqk: + if (rtw_phy_pwrtrack_need_iqk(rtwdev)) + rtw8822b_do_iqk(rtwdev); +} + +static void rtw8822b_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; + } + + rtw8822b_phy_pwrtrack(rtwdev); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8822b_bf_config_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + +static void rtw8822b_bf_config_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_mu(rtwdev, bfee); +} + +static void rtw8822b_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (bfee->role == RTW_BFEE_SU) + rtw8822b_bf_config_bfee_su(rtwdev, vif, bfee, enable); + else if (bfee->role == RTW_BFEE_MU) + rtw8822b_bf_config_bfee_mu(rtwdev, vif, bfee, enable); + else + rtw_warn(rtwdev, "wrong bfee role\n"); +} + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, @@ -1754,6 +2042,7 @@ static struct rtw_intf_phy_para_table phy_para_table_8822b = { static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { [2] = RTW_DEF_RFE(8822b, 2, 2), + [3] = RTW_DEF_RFE(8822b, 3, 0), [5] = RTW_DEF_RFE(8822b, 5, 5), }; @@ -1801,6 +2090,10 @@ static struct rtw_chip_ops rtw8822b_ops = { .cfg_ldo25 = rtw8822b_cfg_ldo25, .false_alarm_statistics = rtw8822b_false_alarm_statistics, .phy_calibration = rtw8822b_phy_calibration, + .pwr_track = rtw8822b_pwr_track, + .config_bfee = rtw8822b_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, .coex_set_init = rtw8822b_coex_cfg_init, .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, @@ -1955,6 +2248,129 @@ static const struct coex_rf_para rf_para_rx_8822b[] = { static_assert(ARRAY_SIZE(rf_para_tx_8822b) == ARRAY_SIZE(rf_para_rx_8822b)); +static const u8 +rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, +}; + +static const u8 +rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, +}; + +static const u8 +rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, +}; + +static const u8 +rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static const u8 rtw8822b_pwrtrk_2gb_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2gb_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 11, 12, 12, 12, 13, 13 +}; + +static const u8 rtw8822b_pwrtrk_2ga_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2ga_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_b_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_b_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 11, 12, 12, 12, 13, 13 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_a_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 +}; + +static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_3], + .pwrtrk_2gb_n = rtw8822b_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8822b_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8822b_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8822b_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8822b_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8822b_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8822b_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8822b_pwrtrk_2g_cck_a_p, +}; + struct rtw_chip_info rtw8822b_hw_spec = { .ops = &rtw8822b_ops, .id = RTW_CHIP_TYPE_8822B, @@ -1977,6 +2393,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { .dig_min = 0x1c, .ht_supported = true, .vht_supported = true, + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), .sys_func_en = 0xDC, .pwr_on_seq = card_enable_flow_8822b, .pwr_off_seq = card_disable_flow_8822b, @@ -1992,6 +2409,10 @@ struct rtw_chip_info rtw8822b_hw_spec = { .rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl}, .rfe_defs = rtw8822b_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), + .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, + .iqk_threshold = 8, + .bfer_su_max_num = 2, + .bfer_mu_max_num = 1, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h index 0cb93d7d4cfd..6211f4b547b9 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h @@ -127,6 +127,18 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) #define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) #define REG_HTSTFWT 0x800 #define REG_RXPSEL 0x808 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c index 465f58411cab..b9010b111a13 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c @@ -11643,104 +11643,155 @@ static const u32 rtw8822b_bb[] = { RTW_DECL_TABLE_PHY_COND(rtw8822b_bb, rtw_phy_cfg_bb); -static const u32 rtw8822b_bb_pg_type2[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x40424446, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x38404244, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x30323436, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404244, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x30323436, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x38404244, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x30323436, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x42442628, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x34363840, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x26283032, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x40424446, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x38404244, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x30323436, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404244, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x30323436, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x38404244, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x30323436, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x42442628, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x34363840, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x26283032 +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type2[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x40424446, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x38404244, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x30323436, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404244, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x30323436, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x38404244, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x30323436, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x42442628, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x34363840, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x40424446, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x38404244, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x30323436, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404244, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x30323436, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x38404244, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x30323436, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x42442628, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x34363840, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x26283032, }, }; RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type2); -static const u32 rtw8822b_bb_pg_type5[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426 +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type3[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type3); + +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type5[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426, }, }; RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type5); @@ -20382,6 +20433,596 @@ static const u32 rtw8822b_rf_b[] = { RTW_DECL_TABLE_RF_RADIO(rtw8822b_rf_b, B); +static const struct rtw_txpwr_lmt_cfg_pair rtw8822b_txpwr_lmt_type0[] = { + { 0, 0, 0, 0, 1, 32, }, + { 2, 0, 0, 0, 1, 28, }, + { 1, 0, 0, 0, 1, 30, }, + { 0, 0, 0, 0, 2, 32, }, + { 2, 0, 0, 0, 2, 28, }, + { 1, 0, 0, 0, 2, 30, }, + { 0, 0, 0, 0, 3, 32, }, + { 2, 0, 0, 0, 3, 28, }, + { 1, 0, 0, 0, 3, 30, }, + { 0, 0, 0, 0, 4, 32, }, + { 2, 0, 0, 0, 4, 28, }, + { 1, 0, 0, 0, 4, 30, }, + { 0, 0, 0, 0, 5, 32, }, + { 2, 0, 0, 0, 5, 28, }, + { 1, 0, 0, 0, 5, 30, }, + { 0, 0, 0, 0, 6, 32, }, + { 2, 0, 0, 0, 6, 28, }, + { 1, 0, 0, 0, 6, 30, }, + { 0, 0, 0, 0, 7, 32, }, + { 2, 0, 0, 0, 7, 28, }, + { 1, 0, 0, 0, 7, 30, }, + { 0, 0, 0, 0, 8, 32, }, + { 2, 0, 0, 0, 8, 28, }, + { 1, 0, 0, 0, 8, 30, }, + { 0, 0, 0, 0, 9, 32, }, + { 2, 0, 0, 0, 9, 28, }, + { 1, 0, 0, 0, 9, 30, }, + { 0, 0, 0, 0, 10, 32, }, + { 2, 0, 0, 0, 10, 28, }, + { 1, 0, 0, 0, 10, 30, }, + { 0, 0, 0, 0, 11, 32, }, + { 2, 0, 0, 0, 11, 28, }, + { 1, 0, 0, 0, 11, 30, }, + { 0, 0, 0, 0, 12, 26, }, + { 2, 0, 0, 0, 12, 28, }, + { 1, 0, 0, 0, 12, 30, }, + { 0, 0, 0, 0, 13, 20, }, + { 2, 0, 0, 0, 13, 28, }, + { 1, 0, 0, 0, 13, 28, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 26, }, + { 2, 0, 0, 1, 1, 30, }, + { 1, 0, 0, 1, 1, 34, }, + { 0, 0, 0, 1, 2, 30, }, + { 2, 0, 0, 1, 2, 30, }, + { 1, 0, 0, 1, 2, 34, }, + { 0, 0, 0, 1, 3, 32, }, + { 2, 0, 0, 1, 3, 30, }, + { 1, 0, 0, 1, 3, 34, }, + { 0, 0, 0, 1, 4, 34, }, + { 2, 0, 0, 1, 4, 30, }, + { 1, 0, 0, 1, 4, 34, }, + { 0, 0, 0, 1, 5, 34, }, + { 2, 0, 0, 1, 5, 30, }, + { 1, 0, 0, 1, 5, 34, }, + { 0, 0, 0, 1, 6, 34, }, + { 2, 0, 0, 1, 6, 30, }, + { 1, 0, 0, 1, 6, 34, }, + { 0, 0, 0, 1, 7, 34, }, + { 2, 0, 0, 1, 7, 30, }, + { 1, 0, 0, 1, 7, 34, }, + { 0, 0, 0, 1, 8, 34, }, + { 2, 0, 0, 1, 8, 30, }, + { 1, 0, 0, 1, 8, 34, }, + { 0, 0, 0, 1, 9, 32, }, + { 2, 0, 0, 1, 9, 30, }, + { 1, 0, 0, 1, 9, 34, }, + { 0, 0, 0, 1, 10, 30, }, + { 2, 0, 0, 1, 10, 30, }, + { 1, 0, 0, 1, 10, 34, }, + { 0, 0, 0, 1, 11, 28, }, + { 2, 0, 0, 1, 11, 30, }, + { 1, 0, 0, 1, 11, 34, }, + { 0, 0, 0, 1, 12, 22, }, + { 2, 0, 0, 1, 12, 30, }, + { 1, 0, 0, 1, 12, 34, }, + { 0, 0, 0, 1, 13, 14, }, + { 2, 0, 0, 1, 13, 30, }, + { 1, 0, 0, 1, 13, 34, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 26, }, + { 2, 0, 0, 2, 1, 30, }, + { 1, 0, 0, 2, 1, 34, }, + { 0, 0, 0, 2, 2, 30, }, + { 2, 0, 0, 2, 2, 30, }, + { 1, 0, 0, 2, 2, 34, }, + { 0, 0, 0, 2, 3, 32, }, + { 2, 0, 0, 2, 3, 30, }, + { 1, 0, 0, 2, 3, 34, }, + { 0, 0, 0, 2, 4, 34, }, + { 2, 0, 0, 2, 4, 30, }, + { 1, 0, 0, 2, 4, 34, }, + { 0, 0, 0, 2, 5, 34, }, + { 2, 0, 0, 2, 5, 30, }, + { 1, 0, 0, 2, 5, 34, }, + { 0, 0, 0, 2, 6, 34, }, + { 2, 0, 0, 2, 6, 30, }, + { 1, 0, 0, 2, 6, 34, }, + { 0, 0, 0, 2, 7, 34, }, + { 2, 0, 0, 2, 7, 30, }, + { 1, 0, 0, 2, 7, 34, }, + { 0, 0, 0, 2, 8, 34, }, + { 2, 0, 0, 2, 8, 30, }, + { 1, 0, 0, 2, 8, 34, }, + { 0, 0, 0, 2, 9, 32, }, + { 2, 0, 0, 2, 9, 30, }, + { 1, 0, 0, 2, 9, 34, }, + { 0, 0, 0, 2, 10, 30, }, + { 2, 0, 0, 2, 10, 30, }, + { 1, 0, 0, 2, 10, 34, }, + { 0, 0, 0, 2, 11, 26, }, + { 2, 0, 0, 2, 11, 30, }, + { 1, 0, 0, 2, 11, 34, }, + { 0, 0, 0, 2, 12, 20, }, + { 2, 0, 0, 2, 12, 30, }, + { 1, 0, 0, 2, 12, 34, }, + { 0, 0, 0, 2, 13, 14, }, + { 2, 0, 0, 2, 13, 30, }, + { 1, 0, 0, 2, 13, 34, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 26, }, + { 2, 0, 0, 3, 1, 18, }, + { 1, 0, 0, 3, 1, 30, }, + { 0, 0, 0, 3, 2, 28, }, + { 2, 0, 0, 3, 2, 18, }, + { 1, 0, 0, 3, 2, 30, }, + { 0, 0, 0, 3, 3, 30, }, + { 2, 0, 0, 3, 3, 18, }, + { 1, 0, 0, 3, 3, 30, }, + { 0, 0, 0, 3, 4, 30, }, + { 2, 0, 0, 3, 4, 18, }, + { 1, 0, 0, 3, 4, 30, }, + { 0, 0, 0, 3, 5, 32, }, + { 2, 0, 0, 3, 5, 18, }, + { 1, 0, 0, 3, 5, 30, }, + { 0, 0, 0, 3, 6, 32, }, + { 2, 0, 0, 3, 6, 18, }, + { 1, 0, 0, 3, 6, 30, }, + { 0, 0, 0, 3, 7, 32, }, + { 2, 0, 0, 3, 7, 18, }, + { 1, 0, 0, 3, 7, 30, }, + { 0, 0, 0, 3, 8, 30, }, + { 2, 0, 0, 3, 8, 18, }, + { 1, 0, 0, 3, 8, 30, }, + { 0, 0, 0, 3, 9, 30, }, + { 2, 0, 0, 3, 9, 18, }, + { 1, 0, 0, 3, 9, 30, }, + { 0, 0, 0, 3, 10, 28, }, + { 2, 0, 0, 3, 10, 18, }, + { 1, 0, 0, 3, 10, 30, }, + { 0, 0, 0, 3, 11, 26, }, + { 2, 0, 0, 3, 11, 18, }, + { 1, 0, 0, 3, 11, 30, }, + { 0, 0, 0, 3, 12, 20, }, + { 2, 0, 0, 3, 12, 18, }, + { 1, 0, 0, 3, 12, 30, }, + { 0, 0, 0, 3, 13, 14, }, + { 2, 0, 0, 3, 13, 18, }, + { 1, 0, 0, 3, 13, 30, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 26, }, + { 2, 0, 1, 2, 3, 30, }, + { 1, 0, 1, 2, 3, 34, }, + { 0, 0, 1, 2, 4, 26, }, + { 2, 0, 1, 2, 4, 30, }, + { 1, 0, 1, 2, 4, 34, }, + { 0, 0, 1, 2, 5, 30, }, + { 2, 0, 1, 2, 5, 30, }, + { 1, 0, 1, 2, 5, 34, }, + { 0, 0, 1, 2, 6, 32, }, + { 2, 0, 1, 2, 6, 30, }, + { 1, 0, 1, 2, 6, 34, }, + { 0, 0, 1, 2, 7, 30, }, + { 2, 0, 1, 2, 7, 30, }, + { 1, 0, 1, 2, 7, 34, }, + { 0, 0, 1, 2, 8, 26, }, + { 2, 0, 1, 2, 8, 30, }, + { 1, 0, 1, 2, 8, 34, }, + { 0, 0, 1, 2, 9, 26, }, + { 2, 0, 1, 2, 9, 30, }, + { 1, 0, 1, 2, 9, 34, }, + { 0, 0, 1, 2, 10, 20, }, + { 2, 0, 1, 2, 10, 30, }, + { 1, 0, 1, 2, 10, 34, }, + { 0, 0, 1, 2, 11, 14, }, + { 2, 0, 1, 2, 11, 30, }, + { 1, 0, 1, 2, 11, 34, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 63, }, + { 1, 0, 1, 2, 12, 63, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 63, }, + { 1, 0, 1, 2, 13, 63, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 24, }, + { 2, 0, 1, 3, 3, 18, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 24, }, + { 2, 0, 1, 3, 4, 18, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 26, }, + { 2, 0, 1, 3, 5, 18, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 28, }, + { 2, 0, 1, 3, 6, 18, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 26, }, + { 2, 0, 1, 3, 7, 18, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 26, }, + { 2, 0, 1, 3, 8, 18, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 26, }, + { 2, 0, 1, 3, 9, 18, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 20, }, + { 2, 0, 1, 3, 10, 18, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 14, }, + { 2, 0, 1, 3, 11, 18, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 63, }, + { 1, 0, 1, 3, 12, 63, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 63, }, + { 1, 0, 1, 3, 13, 63, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 30, }, + { 2, 1, 0, 1, 36, 32, }, + { 1, 1, 0, 1, 36, 30, }, + { 0, 1, 0, 1, 40, 32, }, + { 2, 1, 0, 1, 40, 32, }, + { 1, 1, 0, 1, 40, 30, }, + { 0, 1, 0, 1, 44, 32, }, + { 2, 1, 0, 1, 44, 32, }, + { 1, 1, 0, 1, 44, 30, }, + { 0, 1, 0, 1, 48, 32, }, + { 2, 1, 0, 1, 48, 32, }, + { 1, 1, 0, 1, 48, 30, }, + { 0, 1, 0, 1, 52, 32, }, + { 2, 1, 0, 1, 52, 32, }, + { 1, 1, 0, 1, 52, 28, }, + { 0, 1, 0, 1, 56, 32, }, + { 2, 1, 0, 1, 56, 32, }, + { 1, 1, 0, 1, 56, 28, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 32, }, + { 1, 1, 0, 1, 60, 28, }, + { 0, 1, 0, 1, 64, 28, }, + { 2, 1, 0, 1, 64, 32, }, + { 1, 1, 0, 1, 64, 28, }, + { 0, 1, 0, 1, 100, 26, }, + { 2, 1, 0, 1, 100, 32, }, + { 1, 1, 0, 1, 100, 32, }, + { 0, 1, 0, 1, 104, 32, }, + { 2, 1, 0, 1, 104, 32, }, + { 1, 1, 0, 1, 104, 32, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 32, }, + { 1, 1, 0, 1, 108, 32, }, + { 0, 1, 0, 1, 112, 32, }, + { 2, 1, 0, 1, 112, 32, }, + { 1, 1, 0, 1, 112, 32, }, + { 0, 1, 0, 1, 116, 32, }, + { 2, 1, 0, 1, 116, 32, }, + { 1, 1, 0, 1, 116, 32, }, + { 0, 1, 0, 1, 120, 32, }, + { 2, 1, 0, 1, 120, 32, }, + { 1, 1, 0, 1, 120, 32, }, + { 0, 1, 0, 1, 124, 32, }, + { 2, 1, 0, 1, 124, 32, }, + { 1, 1, 0, 1, 124, 32, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 32, }, + { 1, 1, 0, 1, 128, 32, }, + { 0, 1, 0, 1, 132, 32, }, + { 2, 1, 0, 1, 132, 32, }, + { 1, 1, 0, 1, 132, 32, }, + { 0, 1, 0, 1, 136, 32, }, + { 2, 1, 0, 1, 136, 32, }, + { 1, 1, 0, 1, 136, 32, }, + { 0, 1, 0, 1, 140, 28, }, + { 2, 1, 0, 1, 140, 32, }, + { 1, 1, 0, 1, 140, 32, }, + { 0, 1, 0, 1, 144, 28, }, + { 2, 1, 0, 1, 144, 32, }, + { 1, 1, 0, 1, 144, 63, }, + { 0, 1, 0, 1, 149, 32, }, + { 2, 1, 0, 1, 149, 63, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 32, }, + { 2, 1, 0, 1, 153, 63, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 32, }, + { 2, 1, 0, 1, 157, 63, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 32, }, + { 2, 1, 0, 1, 161, 63, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 32, }, + { 2, 1, 0, 1, 165, 63, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 30, }, + { 2, 1, 0, 2, 36, 32, }, + { 1, 1, 0, 2, 36, 28, }, + { 0, 1, 0, 2, 40, 32, }, + { 2, 1, 0, 2, 40, 32, }, + { 1, 1, 0, 2, 40, 28, }, + { 0, 1, 0, 2, 44, 32, }, + { 2, 1, 0, 2, 44, 32, }, + { 1, 1, 0, 2, 44, 28, }, + { 0, 1, 0, 2, 48, 32, }, + { 2, 1, 0, 2, 48, 32, }, + { 1, 1, 0, 2, 48, 28, }, + { 0, 1, 0, 2, 52, 32, }, + { 2, 1, 0, 2, 52, 32, }, + { 1, 1, 0, 2, 52, 28, }, + { 0, 1, 0, 2, 56, 32, }, + { 2, 1, 0, 2, 56, 32, }, + { 1, 1, 0, 2, 56, 28, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 32, }, + { 1, 1, 0, 2, 60, 28, }, + { 0, 1, 0, 2, 64, 28, }, + { 2, 1, 0, 2, 64, 32, }, + { 1, 1, 0, 2, 64, 28, }, + { 0, 1, 0, 2, 100, 26, }, + { 2, 1, 0, 2, 100, 32, }, + { 1, 1, 0, 2, 100, 32, }, + { 0, 1, 0, 2, 104, 32, }, + { 2, 1, 0, 2, 104, 32, }, + { 1, 1, 0, 2, 104, 32, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 32, }, + { 1, 1, 0, 2, 108, 32, }, + { 0, 1, 0, 2, 112, 32, }, + { 2, 1, 0, 2, 112, 32, }, + { 1, 1, 0, 2, 112, 32, }, + { 0, 1, 0, 2, 116, 32, }, + { 2, 1, 0, 2, 116, 32, }, + { 1, 1, 0, 2, 116, 32, }, + { 0, 1, 0, 2, 120, 32, }, + { 2, 1, 0, 2, 120, 32, }, + { 1, 1, 0, 2, 120, 32, }, + { 0, 1, 0, 2, 124, 32, }, + { 2, 1, 0, 2, 124, 32, }, + { 1, 1, 0, 2, 124, 32, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 32, }, + { 1, 1, 0, 2, 128, 32, }, + { 0, 1, 0, 2, 132, 32, }, + { 2, 1, 0, 2, 132, 32, }, + { 1, 1, 0, 2, 132, 32, }, + { 0, 1, 0, 2, 136, 32, }, + { 2, 1, 0, 2, 136, 32, }, + { 1, 1, 0, 2, 136, 32, }, + { 0, 1, 0, 2, 140, 26, }, + { 2, 1, 0, 2, 140, 32, }, + { 1, 1, 0, 2, 140, 32, }, + { 0, 1, 0, 2, 144, 26, }, + { 2, 1, 0, 2, 144, 63, }, + { 1, 1, 0, 2, 144, 63, }, + { 0, 1, 0, 2, 149, 32, }, + { 2, 1, 0, 2, 149, 63, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 32, }, + { 2, 1, 0, 2, 153, 63, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 32, }, + { 2, 1, 0, 2, 157, 63, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 32, }, + { 2, 1, 0, 2, 161, 63, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 32, }, + { 2, 1, 0, 2, 165, 63, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 20, }, + { 1, 1, 0, 3, 36, 22, }, + { 0, 1, 0, 3, 40, 30, }, + { 2, 1, 0, 3, 40, 20, }, + { 1, 1, 0, 3, 40, 22, }, + { 0, 1, 0, 3, 44, 30, }, + { 2, 1, 0, 3, 44, 20, }, + { 1, 1, 0, 3, 44, 22, }, + { 0, 1, 0, 3, 48, 30, }, + { 2, 1, 0, 3, 48, 20, }, + { 1, 1, 0, 3, 48, 22, }, + { 0, 1, 0, 3, 52, 30, }, + { 2, 1, 0, 3, 52, 20, }, + { 1, 1, 0, 3, 52, 22, }, + { 0, 1, 0, 3, 56, 30, }, + { 2, 1, 0, 3, 56, 20, }, + { 1, 1, 0, 3, 56, 22, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 20, }, + { 1, 1, 0, 3, 60, 22, }, + { 0, 1, 0, 3, 64, 28, }, + { 2, 1, 0, 3, 64, 20, }, + { 1, 1, 0, 3, 64, 22, }, + { 0, 1, 0, 3, 100, 26, }, + { 2, 1, 0, 3, 100, 20, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 30, }, + { 2, 1, 0, 3, 104, 20, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 32, }, + { 2, 1, 0, 3, 108, 20, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 20, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 20, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 32, }, + { 2, 1, 0, 3, 120, 20, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 20, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 32, }, + { 2, 1, 0, 3, 128, 20, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 32, }, + { 2, 1, 0, 3, 132, 20, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 30, }, + { 2, 1, 0, 3, 136, 20, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 20, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 144, 26, }, + { 2, 1, 0, 3, 144, 63, }, + { 1, 1, 0, 3, 144, 63, }, + { 0, 1, 0, 3, 149, 32, }, + { 2, 1, 0, 3, 149, 63, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 32, }, + { 2, 1, 0, 3, 153, 63, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 32, }, + { 2, 1, 0, 3, 157, 63, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 32, }, + { 2, 1, 0, 3, 161, 63, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 32, }, + { 2, 1, 0, 3, 165, 63, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 22, }, + { 2, 1, 1, 2, 38, 30, }, + { 1, 1, 1, 2, 38, 30, }, + { 0, 1, 1, 2, 46, 30, }, + { 2, 1, 1, 2, 46, 30, }, + { 1, 1, 1, 2, 46, 30, }, + { 0, 1, 1, 2, 54, 30, }, + { 2, 1, 1, 2, 54, 30, }, + { 1, 1, 1, 2, 54, 30, }, + { 0, 1, 1, 2, 62, 24, }, + { 2, 1, 1, 2, 62, 30, }, + { 1, 1, 1, 2, 62, 30, }, + { 0, 1, 1, 2, 102, 24, }, + { 2, 1, 1, 2, 102, 30, }, + { 1, 1, 1, 2, 102, 30, }, + { 0, 1, 1, 2, 110, 30, }, + { 2, 1, 1, 2, 110, 30, }, + { 1, 1, 1, 2, 110, 30, }, + { 0, 1, 1, 2, 118, 30, }, + { 2, 1, 1, 2, 118, 30, }, + { 1, 1, 1, 2, 118, 30, }, + { 0, 1, 1, 2, 126, 30, }, + { 2, 1, 1, 2, 126, 30, }, + { 1, 1, 1, 2, 126, 30, }, + { 0, 1, 1, 2, 134, 30, }, + { 2, 1, 1, 2, 134, 30, }, + { 1, 1, 1, 2, 134, 30, }, + { 0, 1, 1, 2, 142, 30, }, + { 2, 1, 1, 2, 142, 63, }, + { 1, 1, 1, 2, 142, 63, }, + { 0, 1, 1, 2, 151, 30, }, + { 2, 1, 1, 2, 151, 63, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 30, }, + { 2, 1, 1, 2, 159, 63, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 20, }, + { 2, 1, 1, 3, 38, 20, }, + { 1, 1, 1, 3, 38, 22, }, + { 0, 1, 1, 3, 46, 30, }, + { 2, 1, 1, 3, 46, 20, }, + { 1, 1, 1, 3, 46, 22, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 20, }, + { 1, 1, 1, 3, 54, 22, }, + { 0, 1, 1, 3, 62, 22, }, + { 2, 1, 1, 3, 62, 20, }, + { 1, 1, 1, 3, 62, 22, }, + { 0, 1, 1, 3, 102, 22, }, + { 2, 1, 1, 3, 102, 20, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 20, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 30, }, + { 2, 1, 1, 3, 118, 20, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 30, }, + { 2, 1, 1, 3, 126, 20, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 20, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 142, 30, }, + { 2, 1, 1, 3, 142, 63, }, + { 1, 1, 1, 3, 142, 63, }, + { 0, 1, 1, 3, 151, 30, }, + { 2, 1, 1, 3, 151, 63, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 30, }, + { 2, 1, 1, 3, 159, 63, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 20, }, + { 2, 1, 2, 4, 42, 30, }, + { 1, 1, 2, 4, 42, 28, }, + { 0, 1, 2, 4, 58, 20, }, + { 2, 1, 2, 4, 58, 30, }, + { 1, 1, 2, 4, 58, 28, }, + { 0, 1, 2, 4, 106, 20, }, + { 2, 1, 2, 4, 106, 30, }, + { 1, 1, 2, 4, 106, 30, }, + { 0, 1, 2, 4, 122, 30, }, + { 2, 1, 2, 4, 122, 30, }, + { 1, 1, 2, 4, 122, 30, }, + { 0, 1, 2, 4, 138, 30, }, + { 2, 1, 2, 4, 138, 63, }, + { 1, 1, 2, 4, 138, 63, }, + { 0, 1, 2, 4, 155, 30, }, + { 2, 1, 2, 4, 155, 63, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 18, }, + { 2, 1, 2, 5, 42, 20, }, + { 1, 1, 2, 5, 42, 22, }, + { 0, 1, 2, 5, 58, 18, }, + { 2, 1, 2, 5, 58, 20, }, + { 1, 1, 2, 5, 58, 22, }, + { 0, 1, 2, 5, 106, 20, }, + { 2, 1, 2, 5, 106, 20, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 30, }, + { 2, 1, 2, 5, 122, 20, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 138, 30, }, + { 2, 1, 2, 5, 138, 63, }, + { 1, 1, 2, 5, 138, 63, }, + { 0, 1, 2, 5, 155, 30, }, + { 2, 1, 2, 5, 155, 63, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8822b_txpwr_lmt_type0); + static const struct rtw_txpwr_lmt_cfg_pair rtw8822b_txpwr_lmt_type2[] = { { 0, 0, 0, 0, 1, 32, }, { 2, 0, 0, 0, 1, 28, }, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h index d4c268889368..4140e1ccb7b1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h @@ -9,9 +9,11 @@ extern const struct rtw_table rtw8822b_mac_tbl; extern const struct rtw_table rtw8822b_agc_tbl; extern const struct rtw_table rtw8822b_bb_tbl; extern const struct rtw_table rtw8822b_bb_pg_type2_tbl; +extern const struct rtw_table rtw8822b_bb_pg_type3_tbl; extern const struct rtw_table rtw8822b_bb_pg_type5_tbl; extern const struct rtw_table rtw8822b_rf_a_tbl; extern const struct rtw_table rtw8822b_rf_b_tbl; +extern const struct rtw_table rtw8822b_txpwr_lmt_type0_tbl; extern const struct rtw_table rtw8822b_txpwr_lmt_type2_tbl; extern const struct rtw_table rtw8822b_txpwr_lmt_type5_tbl; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index c2f6cd76a658..174029836833 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -14,6 +14,7 @@ #include "reg.h" #include "debug.h" #include "util.h" +#include "bf.h" static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, u8 rx_path, bool is_tx2_path); @@ -40,6 +41,11 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) efuse->country_code[1] = map->country_code[1]; efuse->bt_setting = map->rf_bt_setting; efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[RF_PATH_A] = map->path_a_thermal; + efuse->thermal_meter[RF_PATH_B] = map->path_b_thermal; + efuse->thermal_meter_k = + (map->path_a_thermal + map->path_b_thermal) >> 1; + efuse->power_track_type = (map->tx_pwr_calibrate_rate >> 4) & 0xf; for (i = 0; i < 4; i++) efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; @@ -1000,6 +1006,21 @@ static void rtw8822c_rf_init(struct rtw_dev *rtwdev) rtw8822c_rf_x2_check(rtwdev); } +static void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 path; + + for (path = RF_PATH_A; path < RTW_RF_PATH_MAX; path++) { + dm_info->delta_power_index[path] = 0; + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->thermal_avg[path] = 0xff; + } + + dm_info->pwr_trk_triggered = false; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; @@ -1047,6 +1068,9 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) dm_info->cck_gi_l_bnd = ((cck_gi_l_bnd_msb << 4) | (cck_gi_l_bnd_lsb)); rtw8822c_rf_init(rtwdev); + rtw8822c_pwrtrack_init(rtwdev); + + rtw_bf_phy_init(rtwdev); } #define WLAN_TXQ_RPT_EN 0x1F @@ -1088,8 +1112,8 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) #define WLAN_AMPDU_MAX_TIME 0x70 #define WLAN_RTS_LEN_TH 0xFF #define WLAN_RTS_TX_TIME_TH 0x08 -#define WLAN_MAX_AGG_PKT_LIMIT 0x20 -#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x20 +#define WLAN_MAX_AGG_PKT_LIMIT 0x3f +#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x3f #define WLAN_PRE_TXCNT_TIME_TH 0x1E0 #define FAST_EDCA_VO_TH 0x06 #define FAST_EDCA_VI_TH 0x06 @@ -1112,6 +1136,7 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) #define WLAN_RTS_RATE_FB_RATE4_H 0x400003E0 #define WLAN_RTS_RATE_FB_RATE5 0x0600F015 #define WLAN_RTS_RATE_FB_RATE5_H 0x000000E0 +#define WLAN_MULTI_ADDR 0xFFFFFFFF #define WLAN_TX_FUNC_CFG1 0x30 #define WLAN_TX_FUNC_CFG2 0x30 @@ -1221,6 +1246,8 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_BCN_MAX_ERR, WLAN_BCN_MAX_ERR); /* WMAC configuration */ + rtw_write32(rtwdev, REG_MAR, WLAN_MULTI_ADDR); + rtw_write32(rtwdev, REG_MAR + 4, WLAN_MULTI_ADDR); rtw_write8(rtwdev, REG_BBPSF_CTRL + 2, WLAN_RESP_TXRATE); rtw_write8(rtwdev, REG_ACKTO, WLAN_ACK_TO); rtw_write8(rtwdev, REG_ACKTO_CCK, WLAN_ACK_TO_CCK); @@ -1284,11 +1311,11 @@ static void rtw8822c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) rf_reg18 &= ~(RF18_BAND_MASK | RF18_CHANNEL_MASK | RF18_RFSI_MASK | RF18_BW_MASK); - rf_reg18 |= (channel <= 14 ? RF18_BAND_2G : RF18_BAND_5G); + rf_reg18 |= (IS_CH_2G_BAND(channel) ? RF18_BAND_2G : RF18_BAND_5G); rf_reg18 |= (channel & RF18_CHANNEL_MASK); - if (channel > 144) + if (IS_CH_5G_BAND_4(channel)) rf_reg18 |= RF18_RFSI_GT_CH140; - else if (channel >= 80) + else if (IS_CH_5G_BAND_3(channel)) rf_reg18 |= RF18_RFSI_GE_CH80; switch (bw) { @@ -1338,7 +1365,7 @@ static void rtw8822c_toggle_igi(struct rtw_dev *rtwdev) static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 primary_ch_idx) { - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { rtw_write32_clr(rtwdev, REG_BGCTRL, BITS_RX_IQ_WEIGHT); rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x8); rtw_write32_set(rtwdev, REG_TXF4, BIT(20)); @@ -1403,7 +1430,7 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3); else rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x1); - } else if (channel > 35) { + } else if (IS_CH_5G_BAND(channel)) { rtw_write32_set(rtwdev, REG_CCKTXONLY, BIT_BB_CCK_CHECK_EN); rtw_write32_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); rtw_write32_set(rtwdev, REG_BGCTRL, BITS_RX_IQ_WEIGHT); @@ -1411,17 +1438,17 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x0); rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0x22); rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3); - if (channel >= 36 && channel <= 64) { + if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x1); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, 0x1); - } else if (channel >= 100 && channel <= 144) { + } else if (IS_CH_5G_BAND_3(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x2); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, 0x2); - } else if (channel >= 149) { + } else if (IS_CH_5G_BAND_4(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x3); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, @@ -1616,6 +1643,8 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, u8 gain_a, gain_b; s8 rx_power[RTW_RF_PATH_MAX]; s8 min_rx_power = -120; + u8 rssi; + int path; rx_power[RF_PATH_A] = GET_PHY_STAT_P0_PWDB_A(phy_status); rx_power[RF_PATH_B] = GET_PHY_STAT_P0_PWDB_B(phy_status); @@ -1638,6 +1667,11 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->rx_power[RF_PATH_A] = rx_power[RF_PATH_A]; pkt_stat->rx_power[RF_PATH_B] = rx_power[RF_PATH_B]; + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + } + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); pkt_stat->bw = RTW_CHANNEL_WIDTH_20; pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], @@ -1647,8 +1681,13 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; + s8 rx_evm; + u8 evm_dbm = 0; + u8 rssi; + int path; if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0) rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status); @@ -1669,6 +1708,34 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->signal_power = max3(pkt_stat->rx_power[RF_PATH_A], pkt_stat->rx_power[RF_PATH_B], min_rx_power); + + dm_info->curr_rx_rate = pkt_stat->rate; + + pkt_stat->rx_evm[RF_PATH_A] = GET_PHY_STAT_P1_RXEVM_A(phy_status); + pkt_stat->rx_evm[RF_PATH_B] = GET_PHY_STAT_P1_RXEVM_B(phy_status); + + pkt_stat->rx_snr[RF_PATH_A] = GET_PHY_STAT_P1_RXSNR_A(phy_status); + pkt_stat->rx_snr[RF_PATH_B] = GET_PHY_STAT_P1_RXSNR_B(phy_status); + + pkt_stat->cfo_tail[RF_PATH_A] = GET_PHY_STAT_P1_CFO_TAIL_A(phy_status); + pkt_stat->cfo_tail[RF_PATH_B] = GET_PHY_STAT_P1_CFO_TAIL_B(phy_status); + + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; + dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; + + rx_evm = pkt_stat->rx_evm[path]; + + if (rx_evm < 0) { + if (rx_evm == S8_MIN) + evm_dbm = 0; + else + evm_dbm = ((u8)-rx_evm >> 1); + } + dm_info->rx_evm_dbm[path] = evm_dbm; + } } static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, @@ -1704,7 +1771,8 @@ static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc); + pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && + GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); @@ -1822,6 +1890,7 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev) u32 cck_enable; u32 cck_fa_cnt; u32 crc32_cnt; + u32 cca32_cnt; u32 ofdm_fa_cnt; u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5; u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail, @@ -1866,6 +1935,13 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev) dm_info->vht_ok_cnt = crc32_cnt & 0xffff; dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16; + cca32_cnt = rtw_read32(rtwdev, 0x2c08); + dm_info->ofdm_cca_cnt = ((cca32_cnt & 0xffff0000) >> 16); + dm_info->cck_cca_cnt = cca32_cnt & 0xffff; + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 0); rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 2); rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 0); @@ -2053,6 +2129,57 @@ static void rtw8822c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) } } +static void rtw8822c_bf_enable_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + u8 csi_rsc = 0; + u32 tmp6dc; + + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + + tmp6dc = rtw_read32(rtwdev, REG_BBPSF_CTRL) | + BIT_WMAC_USE_NDPARATE | + (csi_rsc << 13); + if (vif->net_type == RTW_NET_AP_MODE) + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc | BIT(12)); + else + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc & ~BIT(12)); + + rtw_write32(rtwdev, REG_CSI_RRSR, 0x550); +} + +static void rtw8822c_bf_config_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw8822c_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + +static void rtw8822c_bf_config_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_mu(rtwdev, bfee); +} + +static void rtw8822c_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (bfee->role == RTW_BFEE_SU) + rtw8822c_bf_config_bfee_su(rtwdev, vif, bfee, enable); + else if (bfee->role == RTW_BFEE_MU) + rtw8822c_bf_config_bfee_mu(rtwdev, vif, bfee, enable); + else + rtw_warn(rtwdev, "wrong bfee role\n"); +} + struct dpk_cfg_pair { u32 addr; u32 bitmask; @@ -2603,9 +2730,9 @@ static bool rtw8822c_dpk_coef_iq_check(struct rtw_dev *rtwdev, { if (coef_i == 0x1000 || coef_i == 0x0fff || coef_q == 0x1000 || coef_q == 0x0fff) - return 1; - else - return 0; + return true; + + return false; } static u32 rtw8822c_dpk_coef_transfer(struct rtw_dev *rtwdev) @@ -2843,7 +2970,7 @@ static void rtw8822c_dpk_cal_gs(struct rtw_dev *rtwdev, u8 path) dpk_info->dpk_gs[path] = tmp_gs; } -void rtw8822c_dpk_cal_coef1(struct rtw_dev *rtwdev) +static void rtw8822c_dpk_cal_coef1(struct rtw_dev *rtwdev) { struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; u32 offset[DPK_RF_PATH_NUM] = {0, 0x58}; @@ -3084,7 +3211,7 @@ static void rtw8822c_phy_calibration(struct rtw_dev *rtwdev) rtw8822c_do_dpk(rtwdev); } -void rtw8822c_dpk_track(struct rtw_dev *rtwdev) +static void rtw8822c_dpk_track(struct rtw_dev *rtwdev) { struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; u8 path; @@ -3168,8 +3295,8 @@ rtw8822c_phy_cck_pd_set_reg(struct rtw_dev *rtwdev, static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - s8 pd_lvl[4] = {2, 4, 6, 8}; - s8 cs_lvl[4] = {2, 2, 2, 4}; + s8 pd_lvl[CCK_PD_LV_MAX] = {0, 2, 4, 6, 8}; + s8 cs_lvl[CCK_PD_LV_MAX] = {0, 2, 2, 2, 4}; u8 cur_lvl; u8 nrx, bw; @@ -3191,6 +3318,87 @@ static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) dm_info->cck_pd_lv[bw][nrx] = new_lvl; } +#define PWR_TRACK_MASK 0x7f +static void rtw8822c_pwrtrack_set(struct rtw_dev *rtwdev, u8 rf_path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + switch (rf_path) { + case RF_PATH_A: + rtw_write32_mask(rtwdev, 0x18a0, PWR_TRACK_MASK, + dm_info->delta_power_index[rf_path]); + break; + case RF_PATH_B: + rtw_write32_mask(rtwdev, 0x41a0, PWR_TRACK_MASK, + dm_info->delta_power_index[rf_path]); + break; + default: + break; + } +} + +static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 thermal_value, delta; + + if (rtwdev->efuse.thermal_meter[path] == 0xff) + return; + + thermal_value = rtw_read_rf(rtwdev, path, RF_T_METER, 0x7e); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, path); + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, path); + + dm_info->delta_power_index[path] = + rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, path, path, + delta); + + rtw8822c_pwrtrack_set(rtwdev, path); +} + +static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_swing_table swing_table; + u8 i; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + for (i = 0; i < rtwdev->hal.rf_path_num; i++) + rtw8822c_pwr_track_path(rtwdev, &swing_table, i); + + if (rtw_phy_pwrtrack_need_iqk(rtwdev)) + rtw8822c_do_iqk(rtwdev); +} + +static void rtw8822c_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, BIT(19), 0x01); + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, BIT(19), 0x00); + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, BIT(19), 0x01); + + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x01); + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x00); + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x01); + + dm_info->pwr_trk_triggered = true; + return; + } + + __rtw8822c_pwr_track(rtwdev); + dm_info->pwr_trk_triggered = false; +} + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, @@ -3571,6 +3779,10 @@ static struct rtw_chip_ops rtw8822c_ops = { .dpk_track = rtw8822c_dpk_track, .phy_calibration = rtw8822c_phy_calibration, .cck_pd_set = rtw8822c_phy_cck_pd_set, + .pwr_track = rtw8822c_pwr_track, + .config_bfee = rtw8822c_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, .coex_set_init = rtw8822c_coex_cfg_init, .coex_set_ant_switch = NULL, @@ -3725,6 +3937,129 @@ static const struct coex_rf_para rf_para_rx_8822c[] = { static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c)); +static const u8 +rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, +}; + +static const u8 +rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, +}; + +static const u8 +rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, +}; + +static const u8 +rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, +}; + +static const u8 rtw8822c_pwrtrk_2gb_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, + 9, 9, 10, 11, 12, 13, 14, 15, 15, 16, + 17, 18, 19, 20, 20, 21, 22, 23, 24, 25 +}; + +static const u8 rtw8822c_pwrtrk_2gb_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +}; + +static const u8 rtw8822c_pwrtrk_2ga_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, + 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, + 13, 14, 15, 15, 16, 17, 17, 18, 19, 19 +}; + +static const u8 rtw8822c_pwrtrk_2ga_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 25, 26, 27 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_b_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, + 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, + 17, 18, 19, 20, 21, 22, 23, 23, 24, 25 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_b_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_a_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, + 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 17, 18, 18, 19, 20, 21, 21, 22 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, + 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, + 18, 18, 19, 20, 21, 22, 23, 24, 24, 25 +}; + +static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_3], + .pwrtrk_2gb_n = rtw8822c_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8822c_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8822c_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8822c_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8822c_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8822c_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8822c_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8822c_pwrtrk_2g_cck_a_p, +}; + struct rtw_chip_info rtw8822c_hw_spec = { .ops = &rtw8822c_ops, .id = RTW_CHIP_TYPE_8822C, @@ -3747,6 +4082,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .dig_min = 0x20, .ht_supported = true, .vht_supported = true, + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG), .sys_func_en = 0xD8, .pwr_on_seq = card_enable_flow_8822c, .pwr_off_seq = card_disable_flow_8822c, @@ -3765,6 +4101,10 @@ struct rtw_chip_info rtw8822c_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs), .en_dis_dpd = true, .dpd_ratemask = DIS_DPD_RATEALL, + .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, + .iqk_threshold = 8, + .bfer_su_max_num = 2, + .bfer_mu_max_num = 1, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h index 438db74d8e7a..abd9f300bedd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h @@ -149,6 +149,18 @@ const struct rtw_table name ## _tbl = { \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) #define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) #define REG_ANAPARLDO_POW_MAC 0x0029 #define BIT_LDOE25_PON BIT(0) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c index e2dd4c766077..d102a2c27757 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c @@ -1762,53 +1762,53 @@ static const u32 rtw8822c_bb[] = { RTW_DECL_TABLE_PHY_COND(rtw8822c_bb, rtw_phy_cfg_bb); -static const u32 rtw8822c_bb_pg_type0[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x484c5054, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x484c5054, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044 +static const struct rtw_phy_pg_cfg_pair rtw8822c_bb_pg_type0[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x484c5054, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x484c5054, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, }, }; RTW_DECL_TABLE_BB_PG(rtw8822c_bb_pg_type0); diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 48b9ed49b79a..9b90339ab697 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -5,6 +5,7 @@ #include "main.h" #include "rx.h" #include "ps.h" +#include "debug.h" void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, struct sk_buff *skb) @@ -25,8 +26,6 @@ void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtwvif = (struct rtw_vif *)vif->drv_priv; rtwvif->stats.rx_unicast += skb->len; rtwvif->stats.rx_cnt++; - if (rtwvif->stats.rx_cnt > RTW_LPS_THRESHOLD) - rtw_leave_lps_irqsafe(rtwdev, rtwvif); } } } @@ -39,6 +38,60 @@ struct rtw_rx_addr_match_data { u8 *bssid; }; +static void rtw_rx_phy_stat(struct rtw_dev *rtwdev, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_hdr *hdr) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_pkt_count *cur_pkt_cnt = &dm_info->cur_pkt_count; + u8 rate_ss, rate_ss_evm, evm_id; + u8 i, idx; + + dm_info->curr_rx_rate = pkt_stat->rate; + + if (ieee80211_is_beacon(hdr->frame_control)) + cur_pkt_cnt->num_bcn_pkt++; + + switch (pkt_stat->rate) { + case DESC_RATE1M...DESC_RATE11M: + goto pkt_num; + case DESC_RATE6M...DESC_RATE54M: + rate_ss = 0; + rate_ss_evm = 1; + evm_id = RTW_EVM_OFDM; + break; + case DESC_RATEMCS0...DESC_RATEMCS7: + case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT1SS_MCS9: + rate_ss = 1; + rate_ss_evm = 1; + evm_id = RTW_EVM_1SS; + break; + case DESC_RATEMCS8...DESC_RATEMCS15: + case DESC_RATEVHT2SS_MCS0...DESC_RATEVHT2SS_MCS9: + rate_ss = 2; + rate_ss_evm = 2; + evm_id = RTW_EVM_2SS_A; + break; + default: + rtw_warn(rtwdev, "unknown pkt rate = %d\n", pkt_stat->rate); + return; + } + + for (i = 0; i < rate_ss_evm; i++) { + idx = evm_id + i; + ewma_evm_add(&dm_info->ewma_evm[idx], + dm_info->rx_evm_dbm[i]); + } + + for (i = 0; i < rtwdev->hal.rf_path_num; i++) { + idx = RTW_SNR_OFDM_A + 4 * rate_ss + i; + ewma_snr_add(&dm_info->ewma_snr[idx], + dm_info->rx_snr[i]); + } +pkt_num: + cur_pkt_cnt->num_qry_pkt[pkt_stat->rate]++; +} + static void rtw_rx_addr_match_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -50,14 +103,16 @@ static void rtw_rx_addr_match_iter(void *data, u8 *mac, struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat; u8 *bssid = iter_data->bssid; - if (ether_addr_equal(vif->bss_conf.bssid, bssid) && - (ether_addr_equal(vif->addr, hdr->addr1) || - ieee80211_is_beacon(hdr->frame_control))) - sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2, - vif->addr); - else + if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) return; + if (!(ether_addr_equal(vif->addr, hdr->addr1) || + ieee80211_is_beacon(hdr->frame_control))) + return; + + rtw_rx_phy_stat(rtwdev, pkt_stat, hdr); + sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2, + vif->addr); if (!sta) return; @@ -105,35 +160,17 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, else if (pkt_stat->rate >= DESC_RATEMCS0) rx_status->encoding = RX_ENC_HT; - if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT1SS_MCS9) { - rx_status->nss = 1; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT1SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT2SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT2SS_MCS9) { - rx_status->nss = 2; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT2SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT3SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT3SS_MCS9) { - rx_status->nss = 3; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT3SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT4SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT4SS_MCS9) { - rx_status->nss = 4; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT4SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEMCS0 && - pkt_stat->rate <= DESC_RATEMCS15) { - rx_status->rate_idx = pkt_stat->rate - DESC_RATEMCS0; - } else if (rx_status->band == NL80211_BAND_5GHZ && - pkt_stat->rate >= DESC_RATE6M && - pkt_stat->rate <= DESC_RATE54M) { + if (rx_status->band == NL80211_BAND_5GHZ && + pkt_stat->rate >= DESC_RATE6M && + pkt_stat->rate <= DESC_RATE54M) { rx_status->rate_idx = pkt_stat->rate - DESC_RATE6M; } else if (rx_status->band == NL80211_BAND_2GHZ && pkt_stat->rate >= DESC_RATE1M && pkt_stat->rate <= DESC_RATE54M) { rx_status->rate_idx = pkt_stat->rate - DESC_RATE1M; - } else { - rx_status->rate_idx = 0; + } else if (pkt_stat->rate >= DESC_RATEMCS0) { + rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx, + &rx_status->nss); } rx_status->flag |= RX_FLAG_MACTIME_START; diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h index 383f3b2babc1..3342e3761281 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.h +++ b/drivers/net/wireless/realtek/rtw88/rx.h @@ -5,6 +5,15 @@ #ifndef __RTW_RX_H_ #define __RTW_RX_H_ +enum rtw_rx_desc_enc { + RX_DESC_ENC_NONE = 0, + RX_DESC_ENC_WEP40 = 1, + RX_DESC_ENC_TKIP_WO_MIC = 2, + RX_DESC_ENC_TKIP_MIC = 3, + RX_DESC_ENC_AES = 4, + RX_DESC_ENC_WEP104 = 5, +}; + #define GET_RX_DESC_PHYST(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(26)) #define GET_RX_DESC_ICV_ERR(rxdesc) \ @@ -21,6 +30,8 @@ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(19, 16)) #define GET_RX_DESC_SHIFT(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(25, 24)) +#define GET_RX_DESC_ENC_TYPE(rxdesc) \ + le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(22, 20)) #define GET_RX_DESC_RX_RATE(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x03), GENMASK(6, 0)) #define GET_RX_DESC_MACID(rxdesc) \ diff --git a/drivers/net/wireless/realtek/rtw88/sec.c b/drivers/net/wireless/realtek/rtw88/sec.c index c594fc02804d..d0d7fbb10d58 100644 --- a/drivers/net/wireless/realtek/rtw88/sec.c +++ b/drivers/net/wireless/realtek/rtw88/sec.c @@ -96,6 +96,27 @@ void rtw_sec_clear_cam(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTW_SEC_CMD_REG, command); } +u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam) +{ + struct rtw_sec_desc *sec = &rtwdev->sec; + u8 offset = 0; + u8 count, n; + + if (!used_cam) + return 0; + + for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) { + n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset); + if (n == RTW_MAX_SEC_CAM_NUM) + break; + + used_cam[count] = n; + offset = n + 1; + } + + return count; +} + void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev) { struct rtw_sec_desc *sec = &rtwdev->sec; diff --git a/drivers/net/wireless/realtek/rtw88/sec.h b/drivers/net/wireless/realtek/rtw88/sec.h index 8c50a895c797..efcf45433999 100644 --- a/drivers/net/wireless/realtek/rtw88/sec.h +++ b/drivers/net/wireless/realtek/rtw88/sec.h @@ -34,6 +34,7 @@ void rtw_sec_write_cam(struct rtw_dev *rtwdev, void rtw_sec_clear_cam(struct rtw_dev *rtwdev, struct rtw_sec_desc *sec, u8 hw_key_idx); +u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam); void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 8eaa9809ca44..24c39c60c99a 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -27,8 +27,6 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtwvif = (struct rtw_vif *)vif->drv_priv; rtwvif->stats.tx_unicast += skb->len; rtwvif->stats.tx_cnt++; - if (rtwvif->stats.tx_cnt > RTW_LPS_THRESHOLD) - rtw_leave_lps_irqsafe(rtwdev, rtwvif); } } } @@ -58,6 +56,7 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) SET_TX_DESC_DATA_SHORT(txdesc, pkt_info->short_gi); SET_TX_DESC_SPE_RPT(txdesc, pkt_info->report); SET_TX_DESC_SW_DEFINE(txdesc, pkt_info->sn); + SET_TX_DESC_USE_RTS(txdesc, pkt_info->rts); } EXPORT_SYMBOL(rtw_tx_fill_tx_desc); @@ -260,6 +259,9 @@ static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, ampdu_density = get_tx_ampdu_density(sta); } + if (info->control.use_rts) + pkt_info->rts = true; + if (sta->vht_cap.vht_supported) rate = get_highest_vht_tx_rate(rtwdev, sta); else if (sta->ht_cap.ht_supported) @@ -365,3 +367,132 @@ void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, pkt_info->qsel = TX_DESC_QSEL_MGMT; pkt_info->ls = true; } + +void rtw_tx(struct rtw_dev *rtwdev, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct rtw_tx_pkt_info pkt_info = {0}; + + rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb); + if (rtw_hci_tx(rtwdev, &pkt_info, skb)) + goto out; + + return; + +out: + ieee80211_free_txskb(rtwdev->hw, skb); +} + +static void rtw_txq_check_agg(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq, + struct sk_buff *skb) +{ + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + struct ieee80211_tx_info *info; + struct rtw_sta_info *si; + + if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) { + info = IEEE80211_SKB_CB(skb); + info->flags |= IEEE80211_TX_CTL_AMPDU; + return; + } + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags)) + return; + + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return; + + if (!txq->sta) + return; + + si = (struct rtw_sta_info *)txq->sta->drv_priv; + set_bit(txq->tid, si->tid_ba); + + ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work); +} + +static bool rtw_txq_dequeue(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq) +{ + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + struct ieee80211_tx_control control; + struct sk_buff *skb; + + skb = ieee80211_tx_dequeue(rtwdev->hw, txq); + if (!skb) + return false; + + rtw_txq_check_agg(rtwdev, rtwtxq, skb); + + control.sta = txq->sta; + rtw_tx(rtwdev, &control, skb); + rtwtxq->last_push = jiffies; + + return true; +} + +static void rtw_txq_push(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq, + unsigned long frames) +{ + int i; + + rcu_read_lock(); + + for (i = 0; i < frames; i++) + if (!rtw_txq_dequeue(rtwdev, rtwtxq)) + break; + + rcu_read_unlock(); +} + +void rtw_tx_tasklet(unsigned long data) +{ + struct rtw_dev *rtwdev = (void *)data; + struct rtw_txq *rtwtxq, *tmp; + + spin_lock_bh(&rtwdev->txq_lock); + + list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + unsigned long frame_cnt; + unsigned long byte_cnt; + + ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + rtw_txq_push(rtwdev, rtwtxq, frame_cnt); + + list_del_init(&rtwtxq->list); + } + + spin_unlock_bh(&rtwdev->txq_lock); +} + +void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) +{ + struct rtw_txq *rtwtxq; + + if (!txq) + return; + + rtwtxq = (struct rtw_txq *)txq->drv_priv; + INIT_LIST_HEAD(&rtwtxq->list); +} + +void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) +{ + struct rtw_txq *rtwtxq; + + if (!txq) + return; + + rtwtxq = (struct rtw_txq *)txq->drv_priv; + spin_lock_bh(&rtwdev->txq_lock); + if (!list_empty(&rtwtxq->list)) + list_del_init(&rtwtxq->list); + spin_unlock_bh(&rtwdev->txq_lock); +} diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 8338dbf55576..9ca4f74a501b 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -35,6 +35,8 @@ le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, GENMASK(23, 12)) #define SET_TX_DESC_MAX_AGG_NUM(txdesc, value) \ le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(21, 17)) +#define SET_TX_DESC_USE_RTS(tx_desc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(12)) #define SET_TX_DESC_AMPDU_DENSITY(txdesc, value) \ le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, GENMASK(22, 20)) #define SET_TX_DESC_DATA_STBC(txdesc, value) \ @@ -75,6 +77,12 @@ enum rtw_tx_desc_queue_select { TX_DESC_QSEL_H2C = 19, }; +void rtw_tx(struct rtw_dev *rtwdev, + struct ieee80211_tx_control *control, + struct sk_buff *skb); +void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); +void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); +void rtw_tx_tasklet(unsigned long data); void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct ieee80211_tx_control *control, diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c index 212070c2baa8..10f1117c0cfb 100644 --- a/drivers/net/wireless/realtek/rtw88/util.c +++ b/drivers/net/wireless/realtek/rtw88/util.c @@ -70,3 +70,30 @@ void rtw_restore_reg(struct rtw_dev *rtwdev, } } } + +void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) +{ + if (rate <= DESC_RATE54M) + return; + + if (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT1SS_MCS9) { + *nss = 1; + *mcs = rate - DESC_RATEVHT1SS_MCS0; + } else if (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9) { + *nss = 2; + *mcs = rate - DESC_RATEVHT2SS_MCS0; + } else if (rate >= DESC_RATEVHT3SS_MCS0 && + rate <= DESC_RATEVHT3SS_MCS9) { + *nss = 3; + *mcs = rate - DESC_RATEVHT3SS_MCS0; + } else if (rate >= DESC_RATEVHT4SS_MCS0 && + rate <= DESC_RATEVHT4SS_MCS9) { + *nss = 4; + *mcs = rate - DESC_RATEVHT4SS_MCS0; + } else if (rate >= DESC_RATEMCS0 && + rate <= DESC_RATEMCS15) { + *mcs = rate - DESC_RATEMCS0; + } +} diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 6c7f26ef6476..9cc8a335d519 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1756,6 +1756,7 @@ static int rsi_send_beacon(struct rsi_common *common) skb_pull(skb, (64 - dword_align_bytes)); if (rsi_prepare_beacon(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare beacon\n"); + dev_kfree_skb(skb); return -EINVAL; } skb_queue_tail(&common->tx_queue[MGMT_BEACON_Q], skb); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 760eaffeebd6..53f41fc2cadf 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -785,10 +785,10 @@ static int rsi_probe(struct usb_interface *pfunction, rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__); - if (id && id->idProduct == RSI_USB_PID_9113) { + if (id->idProduct == RSI_USB_PID_9113) { rsi_dbg(INIT_ZONE, "%s: 9113 module detected\n", __func__); adapter->device_model = RSI_DEV_9113; - } else if (id && id->idProduct == RSI_USB_PID_9116) { + } else if (id->idProduct == RSI_USB_PID_9116) { rsi_dbg(INIT_ZONE, "%s: 9116 module detected\n", __func__); adapter->device_model = RSI_DEV_9116; } else { diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c index 6574e78e05ea..2a03dc533b6a 100644 --- a/drivers/net/wireless/st/cw1200/fwio.c +++ b/drivers/net/wireless/st/cw1200/fwio.c @@ -320,12 +320,12 @@ int cw1200_load_firmware(struct cw1200_common *priv) goto out; } - priv->hw_type = cw1200_get_hw_type(val32, &major_revision); - if (priv->hw_type < 0) { + ret = cw1200_get_hw_type(val32, &major_revision); + if (ret < 0) { pr_err("Can't deduce hardware type.\n"); - ret = -ENOTSUPP; goto out; } + priv->hw_type = ret; /* Set DPLL Reg value, and read back to confirm writes work */ ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 14133eedb3b6..12952b1c29df 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -79,10 +79,9 @@ static void cw1200_queue_register_post_gc(struct list_head *gc_list, struct cw1200_queue_item *item) { struct cw1200_queue_item *gc_item; - gc_item = kmalloc(sizeof(struct cw1200_queue_item), + gc_item = kmemdup(item, sizeof(struct cw1200_queue_item), GFP_ATOMIC); BUG_ON(!gc_item); - memcpy(gc_item, item, sizeof(struct cw1200_queue_item)); list_add_tail(&gc_item->head, gc_list); } diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index c46b044b7f7b..988581cc134b 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -120,8 +120,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, ++priv->scan.n_ssids; } - if (frame.skb) - dev_kfree_skb(frame.skb); + dev_kfree_skb(frame.skb); mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 547ad538d8b6..e994995d79ab 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -544,11 +544,6 @@ static int wlcore_irq_locked(struct wl1271 *wl) } while (!done && loopcount--) { - /* - * In order to avoid a race with the hardirq, clear the flag - * before acknowledging the chip. - */ - clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_atomic(); ret = wlcore_fw_status(wl, wl->fw_status); @@ -668,7 +663,7 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) disable_irq_nosync(wl->irq); pm_wakeup_event(wl->dev, 0); spin_unlock_irqrestore(&wl->wl_lock, flags); - return IRQ_HANDLED; + goto out_handled; } spin_unlock_irqrestore(&wl->wl_lock, flags); @@ -692,6 +687,11 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) mutex_unlock(&wl->mutex); +out_handled: + spin_lock_irqsave(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; } @@ -1434,7 +1434,7 @@ int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, field = &filter->fields[filter->num_fields]; - field->pattern = kzalloc(len, GFP_KERNEL); + field->pattern = kmemdup(pattern, len, GFP_KERNEL); if (!field->pattern) { wl1271_warning("Failed to allocate RX filter pattern"); return -ENOMEM; @@ -1445,7 +1445,6 @@ int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, field->offset = cpu_to_le16(offset); field->flags = flags; field->len = len; - memcpy(field->pattern, pattern, len); return 0; } |