diff options
author | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2021-07-27 12:48:17 +0200 |
---|---|---|
committer | Maarten Lankhorst <maarten.lankhorst@linux.intel.com> | 2021-07-27 12:48:17 +0200 |
commit | ca31fef11dc83e672415d5925a134749761329bd (patch) | |
tree | 8eb6a489e2d6dd117300f40ed8fc945a06bb6eee /drivers/net/wireless | |
parent | drm/plane: Move drm_plane_enable_fb_damage_clips into core (diff) | |
parent | efi: sysfb_efi: fix build when EFI is not set (diff) | |
download | linux-ca31fef11dc83e672415d5925a134749761329bd.tar.xz linux-ca31fef11dc83e672415d5925a134749761329bd.zip |
Backmerge remote-tracking branch 'drm/drm-next' into drm-misc-next
Required bump from v5.13-rc3 to v5.14-rc3, and to pick up sysfb compilation fixes.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Diffstat (limited to 'drivers/net/wireless')
233 files changed, 7325 insertions, 3614 deletions
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 869524852fba..ab8f77ae5e66 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -442,14 +442,7 @@ static int ath10k_ahb_resource_init(struct ath10k *ar) pdev = ar_ahb->pdev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ath10k_err(ar, "failed to get memory resource\n"); - ret = -ENXIO; - goto out; - } - - ar_ahb->mem = devm_ioremap_resource(&pdev->dev, res); + ar_ahb->mem = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ar_ahb->mem)) { ath10k_err(ar, "mem ioremap error\n"); ret = PTR_ERR(ar_ahb->mem); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 648ed36f845f..5aeff2d9f6cf 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -301,7 +301,7 @@ struct ath10k_fw_stats_pdev { s32 underrun; u32 hw_paused; s32 tx_abort; - s32 mpdus_requed; + s32 mpdus_requeued; u32 tx_ko; u32 data_rc; u32 self_triggers; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index fd052f6ed019..39378e3f9b2b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1105,7 +1105,7 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { "d_tx_ppdu_reaped", "d_tx_fifo_underrun", "d_tx_ppdu_abort", - "d_tx_mpdu_requed", + "d_tx_mpdu_requeued", "d_tx_excessive_retries", "d_tx_hw_rate", "d_tx_dropped_sw_retries", @@ -1205,7 +1205,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, data[i++] = pdev_stats->hw_reaped; data[i++] = pdev_stats->underrun; data[i++] = pdev_stats->tx_abort; - data[i++] = pdev_stats->mpdus_requed; + data[i++] = pdev_stats->mpdus_requeued; data[i++] = pdev_stats->tx_ko; data[i++] = pdev_stats->data_rc; data[i++] = pdev_stats->sw_retry_failure; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 956157946106..ec689e3ce48a 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -845,6 +845,7 @@ enum htt_security_types { #define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2 #define ATH10K_TXRX_NUM_EXT_TIDS 19 +#define ATH10K_TXRX_NON_QOS_TID 16 enum htt_security_flags { #define HTT_SECURITY_TYPE_MASK 0x7F @@ -1282,8 +1283,8 @@ struct htt_dbg_stats_wal_tx_stats { /* Num PPDUs cleaned up in TX abort */ __le32 tx_abort; - /* Num MPDUs requed by SW */ - __le32 mpdus_requed; + /* Num MPDUs requeued by SW */ + __le32 mpdus_requeued; /* excessive retries */ __le32 tx_ko; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 1a08156d5011..adbaeb67eedf 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1746,16 +1746,95 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu); } +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ieee80211_hdr *hdr; + u64 pn = 0; + u8 *ehdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control); + + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) { + pn = ehdr[0]; + pn |= (u64)ehdr[1] << 8; + pn |= (u64)ehdr[4] << 16; + pn |= (u64)ehdr[5] << 24; + pn |= (u64)ehdr[6] << 32; + pn |= (u64)ehdr[7] << 40; + } + return pn; +} + +static bool ath10k_htt_rx_h_frag_multicast_check(struct ath10k *ar, + struct sk_buff *skb, + u16 offset) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + return !is_multicast_ether_addr(hdr->addr1); +} + +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, + struct sk_buff *skb, + u16 peer_id, + u16 offset, + enum htt_rx_mpdu_encrypt_type enctype) +{ + struct ath10k_peer *peer; + union htt_rx_pn_t *last_pn, new_pn = {0}; + struct ieee80211_hdr *hdr; + u8 tid, frag_number; + u32 seq; + + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n"); + return false; + } + + hdr = (struct ieee80211_hdr *)(skb->data + offset); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = ieee80211_get_tid(hdr); + else + tid = ATH10K_TXRX_NON_QOS_TID; + + last_pn = &peer->frag_tids_last_pn[tid]; + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype); + frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + + if (frag_number == 0) { + last_pn->pn48 = new_pn.pn48; + peer->frag_tids_seq[tid] = seq; + } else { + if (seq != peer->frag_tids_seq[tid]) + return false; + + if (new_pn.pn48 != last_pn->pn48 + 1) + return false; + + last_pn->pn48 = new_pn.pn48; + } + + return true; +} + static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *status, bool fill_crypt_header, u8 *rx_hdr, - enum ath10k_pkt_rx_err *err) + enum ath10k_pkt_rx_err *err, + u16 peer_id, + bool frag) { struct sk_buff *first; struct sk_buff *last; - struct sk_buff *msdu; + struct sk_buff *msdu, *temp; struct htt_rx_desc *rxd; struct ieee80211_hdr *hdr; enum htt_rx_mpdu_encrypt_type enctype; @@ -1768,6 +1847,7 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, bool is_decrypted; bool is_mgmt; u32 attention; + bool frag_pn_check = true, multicast_check = true; if (skb_queue_empty(amsdu)) return; @@ -1866,7 +1946,37 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, } skb_queue_walk(amsdu, msdu) { + if (frag && !fill_crypt_header && is_decrypted && + enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) + frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar, + msdu, + peer_id, + 0, + enctype); + + if (frag) + multicast_check = ath10k_htt_rx_h_frag_multicast_check(ar, + msdu, + 0); + + if (!frag_pn_check || !multicast_check) { + /* Discard the fragment with invalid PN or multicast DA + */ + temp = msdu->prev; + __skb_unlink(msdu, amsdu); + dev_kfree_skb_any(msdu); + msdu = temp; + frag_pn_check = true; + multicast_check = true; + continue; + } + ath10k_htt_rx_h_csum_offload(msdu); + + if (frag && !fill_crypt_header && + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + status->flag &= ~RX_FLAG_MMIC_STRIPPED; + ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype, is_decrypted); @@ -1884,6 +1994,11 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, hdr = (void *)msdu->data; hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED); + + if (frag && !fill_crypt_header && + enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) + status->flag &= ~RX_FLAG_IV_STRIPPED & + ~RX_FLAG_MMIC_STRIPPED; } } @@ -1991,14 +2106,62 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, ath10k_unchain_msdu(amsdu, unchain_cnt); } +static bool ath10k_htt_rx_validate_amsdu(struct ath10k *ar, + struct sk_buff_head *amsdu) +{ + u8 *subframe_hdr; + struct sk_buff *first; + bool is_first, is_last; + struct htt_rx_desc *rxd; + struct ieee80211_hdr *hdr; + size_t hdr_len, crypto_len; + enum htt_rx_mpdu_encrypt_type enctype; + int bytes_aligned = ar->hw_params.decap_align_bytes; + + first = skb_peek(amsdu); + + rxd = (void *)first->data - sizeof(*rxd); + hdr = (void *)rxd->rx_hdr_status; + + is_first = !!(rxd->msdu_end.common.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); + is_last = !!(rxd->msdu_end.common.info0 & + __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); + + /* Return in case of non-aggregated msdu */ + if (is_first && is_last) + return true; + + /* First msdu flag is not set for the first msdu of the list */ + if (!is_first) + return false; + + enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0), + RX_MPDU_START_INFO0_ENCRYPT_TYPE); + + hdr_len = ieee80211_hdrlen(hdr->frame_control); + crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype); + + subframe_hdr = (u8 *)hdr + round_up(hdr_len, bytes_aligned) + + crypto_len; + + /* Validate if the amsdu has a proper first subframe. + * There are chances a single msdu can be received as amsdu when + * the unauthenticated amsdu flag of a QoS header + * gets flipped in non-SPP AMSDU's, in such cases the first + * subframe has llc/snap header in place of a valid da. + * return false if the da matches rfc1042 pattern + */ + if (ether_addr_equal(subframe_hdr, rfc1042_header)) + return false; + + return true; +} + static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *rx_status) { - /* FIXME: It might be a good idea to do some fuzzy-testing to drop - * invalid/dangerous frames. - */ - if (!rx_status->freq) { ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n"); return false; @@ -2009,6 +2172,11 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, return false; } + if (!ath10k_htt_rx_validate_amsdu(ar, amsdu)) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid amsdu received\n"); + return false; + } + return true; } @@ -2071,7 +2239,8 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter); - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0, + false); msdus_to_queue = skb_queue_len(&amsdu); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); @@ -2204,6 +2373,11 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, fw_desc = &rx->fw_desc; rx_desc_len = fw_desc->len; + if (fw_desc->u.bits.discard) { + ath10k_dbg(ar, ATH10K_DBG_HTT, "htt discard mpdu\n"); + goto err; + } + /* I have not yet seen any case where num_mpdu_ranges > 1. * qcacld does not seem handle that case either, so we introduce the * same limitiation here as well. @@ -2509,6 +2683,13 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, rx_desc = (struct htt_hl_rx_desc *)(skb->data + tot_hdr_len); rx_desc_info = __le32_to_cpu(rx_desc->info); + hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len); + + if (is_multicast_ether_addr(hdr->addr1)) { + /* Discard the fragment with multicast DA */ + goto err; + } + if (!MS(rx_desc_info, HTT_RX_DESC_HL_INFO_ENCRYPTED)) { spin_unlock_bh(&ar->data_lock); return ath10k_htt_rx_proc_rx_ind_hl(htt, &resp->rx_ind_hl, skb, @@ -2516,8 +2697,6 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, HTT_RX_NON_TKIP_MIC); } - hdr = (struct ieee80211_hdr *)((u8 *)rx_desc + rx_hl->fw_desc.len); - if (ieee80211_has_retry(hdr->frame_control)) goto err; @@ -3027,7 +3206,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL, - NULL); + NULL, peer_id, frag); ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5ce4f8d038b9..c272b290fa73 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5592,6 +5592,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (arvif->nohwcrypt && !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + ret = -EINVAL; ath10k_warn(ar, "cryptmode module param needed for sw crypto\n"); goto err; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index e7fde635e0ee..71878ab35b93 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3685,8 +3685,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev, 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)) + bus_params.chip_id)) { + ret = -ENODEV; goto err_unsupported; + } } } @@ -3697,11 +3699,15 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (bus_params.chip_id == 0xffffffff) + if (bus_params.chip_id == 0xffffffff) { + ret = -ENODEV; goto err_unsupported; + } - if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) - goto err_free_irq; + if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { + ret = -ENODEV; + goto err_unsupported; + } ret = ath10k_core_register(ar, &bus_params); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 862d0901c5b8..cf64898b9447 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -235,7 +235,6 @@ u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe); void ath10k_pci_hif_power_down(struct ath10k *ar); int ath10k_pci_alloc_pipes(struct ath10k *ar); void ath10k_pci_free_pipes(struct ath10k *ar); -void ath10k_pci_free_pipes(struct ath10k *ar); void ath10k_pci_rx_replenish_retry(struct timer_list *t); void ath10k_pci_ce_deinit(struct ath10k *ar); void ath10k_pci_init_napi(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index f2b6bf8f0d60..705b6295e466 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -1282,7 +1282,19 @@ struct fw_rx_desc_base { #define FW_RX_DESC_UDP (1 << 6) struct fw_rx_desc_hl { - u8 info0; + union { + struct { + u8 discard:1, + forward:1, + any_err:1, + dup_err:1, + reserved:1, + inspect:1, + extension:2; + } bits; + u8 info0; + } u; + u8 version; u8 len; u8 flags; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index d48b922215eb..b8a4bbfe10b8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2795,7 +2795,7 @@ void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) switch (ar->scan.state) { case ATH10K_SCAN_IDLE: case ATH10K_SCAN_STARTING: - ath10k_warn(ar, "received chan info event without a scan request, ignoring\n"); + ath10k_dbg(ar, ATH10K_DBG_WMI, "received chan info event without a scan request, ignoring\n"); goto exit; case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: @@ -2867,7 +2867,7 @@ void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, dst->hw_reaped = __le32_to_cpu(src->hw_reaped); dst->underrun = __le32_to_cpu(src->underrun); dst->tx_abort = __le32_to_cpu(src->tx_abort); - dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); + dst->mpdus_requeued = __le32_to_cpu(src->mpdus_requeued); dst->tx_ko = __le32_to_cpu(src->tx_ko); dst->data_rc = __le32_to_cpu(src->data_rc); dst->self_triggers = __le32_to_cpu(src->self_triggers); @@ -2895,7 +2895,7 @@ ath10k_wmi_10_4_pull_pdev_stats_tx(const struct wmi_10_4_pdev_stats_tx *src, dst->hw_reaped = __le32_to_cpu(src->hw_reaped); dst->underrun = __le32_to_cpu(src->underrun); dst->tx_abort = __le32_to_cpu(src->tx_abort); - dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed); + dst->mpdus_requeued = __le32_to_cpu(src->mpdus_requeued); dst->tx_ko = __le32_to_cpu(src->tx_ko); dst->data_rc = __le32_to_cpu(src->data_rc); dst->self_triggers = __le32_to_cpu(src->self_triggers); @@ -8270,7 +8270,7 @@ ath10k_wmi_fw_pdev_tx_stats_fill(const struct ath10k_fw_stats_pdev *pdev, len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "PPDUs cleaned", pdev->tx_abort); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDUs requed", pdev->mpdus_requed); + "MPDUs requeued", pdev->mpdus_requeued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "Excessive retries", pdev->tx_ko); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index d870f7067cb7..41c1a3d339c2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -4371,8 +4371,8 @@ struct wmi_pdev_stats_tx { /* Num PPDUs cleaned up in TX abort */ __le32 tx_abort; - /* Num MPDUs requed by SW */ - __le32 mpdus_requed; + /* Num MPDUs requeued by SW */ + __le32 mpdus_requeued; /* excessive retries */ __le32 tx_ko; @@ -4444,8 +4444,8 @@ struct wmi_10_4_pdev_stats_tx { /* Num PPDUs cleaned up in TX abort */ __le32 tx_abort; - /* Num MPDUs requed by SW */ - __le32 mpdus_requed; + /* Num MPDUs requeued by SW */ + __le32 mpdus_requeued; /* excessive retries */ __le32 tx_ko; @@ -7418,7 +7418,6 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar); struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_connect(struct ath10k *ar); -struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 77ce3347ab86..969bf1a590d9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -70,6 +70,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cold_boot_calib = true, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -110,6 +111,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cold_boot_calib = true, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, }, { .name = "qca6390 hw2.0", @@ -149,6 +151,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cold_boot_calib = false, .supports_suspend = true, .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, }, { .name = "qcn9074 hw1.0", @@ -186,6 +189,47 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .cold_boot_calib = false, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, + }, + { + .name = "wcn6855 hw2.0", + .hw_rev = ATH11K_HW_WCN6855_HW20, + .fw = { + .dir = "WCN6855/hw2.0", + .board_size = 256 * 1024, + .cal_size = 256 * 1024, + }, + .max_radios = 3, + .bdf_addr = 0x4B0C0000, + .hw_ops = &wcn6855_ops, + .ring_mask = &ath11k_hw_ring_mask_qca6390, + .internal_sleep_clock = true, + .regs = &wcn6855_regs, + .qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390, + .host_ce_config = ath11k_host_ce_config_qca6390, + .ce_count = 9, + .target_ce_config = ath11k_target_ce_config_wlan_qca6390, + .target_ce_count = 9, + .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, + .svc_to_ce_map_len = 14, + .single_pdev_only = true, + .rxdma1_enable = false, + .num_rxmda_per_pdev = 2, + .rx_mac_buf_ring = true, + .vdev_start_delay = true, + .htt_peer_map_v2 = false, + .tcl_0_only = true, + .spectral_fft_sz = 0, + + .interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP), + .supports_monitor = false, + .supports_shadow_regs = true, + .idle_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, }, }; @@ -488,7 +532,8 @@ static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab, if (len < ALIGN(ie_len, 4)) { ath11k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n", ie_id, ie_len, len); - return -EINVAL; + ret = -EINVAL; + goto err; } switch (ie_id) { diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 55af982deca7..018fb2385f2a 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -107,6 +107,7 @@ enum ath11k_hw_rev { ATH11K_HW_QCA6390_HW20, ATH11K_HW_IPQ6018_HW10, ATH11K_HW_QCN9074_HW10, + ATH11K_HW_WCN6855_HW20, }; enum ath11k_firmware_mode { @@ -795,8 +796,8 @@ struct ath11k_fw_stats_pdev { s32 underrun; /* Num PPDUs cleaned up in TX abort */ s32 tx_abort; - /* Num MPDUs requed by SW */ - s32 mpdus_requed; + /* Num MPDUs requeued by SW */ + s32 mpdus_requeued; /* excessive retries */ u32 tx_ko; /* data hw rate code */ diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index ec93f14e6d2a..9e0c90da99d3 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -89,7 +89,7 @@ static inline void htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf, len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_abort = %u", htt_stats_buf->tx_abort); len += HTT_DBG_OUT(buf + len, buf_len - len, "mpdu_requeued = %u", - htt_stats_buf->mpdu_requed); + htt_stats_buf->mpdu_requeued); len += HTT_DBG_OUT(buf + len, buf_len - len, "tx_xretry = %u", htt_stats_buf->tx_xretry); len += HTT_DBG_OUT(buf + len, buf_len - len, "data_rc = %u", diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 567a26d485a9..d428f52003a4 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -147,7 +147,7 @@ struct htt_tx_pdev_stats_cmn_tlv { u32 hw_flush; u32 hw_filt; u32 tx_abort; - u32 mpdu_requed; + u32 mpdu_requeued; u32 tx_xretry; u32 data_rc; u32 mpdu_dropped_xretry; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 04f6c4e0658b..b0c8f6290099 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -342,7 +342,6 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab) struct ath11k_dp *dp = &ab->dp; struct hal_srng *srng; int i, ret; - u32 ring_hash_map; ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring, HAL_SW2WBM_RELEASE, 0, 0, @@ -439,20 +438,9 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab) } /* When hash based routing of rx packet is enabled, 32 entries to map - * the hash values to the ring will be configured. Each hash entry uses - * three bits to map to a particular ring. The ring mapping will be - * 0:TCL, 1:SW1, 2:SW2, 3:SW3, 4:SW4, 5:Release, 6:FW and 7:Not used. + * the hash values to the ring will be configured. */ - ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | - HAL_HASH_ROUTING_RING_SW2 << 3 | - HAL_HASH_ROUTING_RING_SW3 << 6 | - HAL_HASH_ROUTING_RING_SW4 << 9 | - HAL_HASH_ROUTING_RING_SW1 << 12 | - HAL_HASH_ROUTING_RING_SW2 << 15 | - HAL_HASH_ROUTING_RING_SW3 << 18 | - HAL_HASH_ROUTING_RING_SW4 << 21; - - ath11k_hal_reo_hw_setup(ab, ring_hash_map); + ab->hw_params.hw_ops->reo_setup(ab); return 0; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 1d9aa1bb6b6e..603d2f93ac18 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -260,6 +260,16 @@ static void ath11k_dp_rxdesc_set_msdu_len(struct ath11k_base *ab, ab->hw_params.hw_ops->rx_desc_set_msdu_len(desc, len); } +static bool ath11k_dp_rx_h_attn_is_mcbc(struct ath11k_base *ab, + struct hal_rx_desc *desc) +{ + struct rx_attention *attn = ath11k_dp_rx_get_attention(ab, desc); + + return ath11k_dp_rx_h_msdu_end_first_msdu(ab, desc) && + (!!FIELD_GET(RX_ATTENTION_INFO1_MCAST_BCAST, + __le32_to_cpu(attn->info1))); +} + static void ath11k_dp_service_mon_ring(struct timer_list *t) { struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); @@ -852,6 +862,24 @@ static void ath11k_dp_rx_frags_cleanup(struct dp_rx_tid *rx_tid, bool rel_link_d __skb_queue_purge(&rx_tid->rx_frags); } +void ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer) +{ + struct dp_rx_tid *rx_tid; + int i; + + lockdep_assert_held(&ar->ab->base_lock); + + for (i = 0; i <= IEEE80211_NUM_TIDS; i++) { + rx_tid = &peer->rx_tid[i]; + + spin_unlock_bh(&ar->ab->base_lock); + del_timer_sync(&rx_tid->frag_timer); + spin_lock_bh(&ar->ab->base_lock); + + ath11k_dp_rx_frags_cleanup(rx_tid, true); + } +} + void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer) { struct dp_rx_tid *rx_tid; @@ -3450,6 +3478,7 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, u8 tid; int ret = 0; bool more_frags; + bool is_mcbc; rx_desc = (struct hal_rx_desc *)msdu->data; peer_id = ath11k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); @@ -3457,6 +3486,11 @@ static int ath11k_dp_rx_frag_h_mpdu(struct ath11k *ar, seqno = ath11k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); frag_no = ath11k_dp_rx_h_mpdu_start_frag_no(ar->ab, msdu); more_frags = ath11k_dp_rx_h_mpdu_start_more_frags(ar->ab, msdu); + is_mcbc = ath11k_dp_rx_h_attn_is_mcbc(ar->ab, rx_desc); + + /* Multicast/Broadcast fragments are not expected */ + if (is_mcbc) + return -EINVAL; if (!ath11k_dp_rx_h_mpdu_start_seq_ctrl_valid(ar->ab, rx_desc) || !ath11k_dp_rx_h_mpdu_start_fc_valid(ar->ab, rx_desc) || diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index bf399312b5ff..623da3bf9dc8 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -49,6 +49,7 @@ int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key); +void ath11k_peer_frags_flush(struct ath11k *ar, struct ath11k_peer *peer); void ath11k_peer_rx_tid_cleanup(struct ath11k *ar, struct ath11k_peer *peer); void ath11k_peer_rx_tid_delete(struct ath11k *ar, struct ath11k_peer *peer, u8 tid); diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 08e3c72d9237..eaa0edca5576 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -382,6 +382,16 @@ static void ath11k_hal_srng_src_hw_init(struct ath11k_base *ab, val = FIELD_PREP(HAL_REO1_RING_ID_ENTRY_SIZE, srng->entry_size); ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(ab), val); + if (srng->ring_id == HAL_SRNG_RING_ID_WBM_IDLE_LINK) { + ath11k_hif_write32(ab, reg_base, (u32)srng->ring_base_paddr); + val = FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB, + ((u64)srng->ring_base_paddr >> + HAL_ADDR_MSB_REG_SHIFT)) | + FIELD_PREP(HAL_TCL1_RING_BASE_MSB_RING_SIZE, + (srng->entry_size * srng->num_entries)); + ath11k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(ab), val); + } + /* interrupt setup */ /* NOTE: IPQ8074 v2 requires the interrupt timer threshold in the * unit of 8 usecs instead of 1 usec (as required by v1). diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 91d1428b8b94..35ed3a14e200 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -120,6 +120,7 @@ struct ath11k_base; #define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008 #define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c #define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010 +#define HAL_REO1_MISC_CTL 0x00000630 #define HAL_REO1_RING_BASE_LSB(ab) ab->hw_params.regs->hal_reo1_ring_base_lsb #define HAL_REO1_RING_BASE_MSB(ab) ab->hw_params.regs->hal_reo1_ring_base_msb #define HAL_REO1_RING_ID(ab) ab->hw_params.regs->hal_reo1_ring_id @@ -280,6 +281,7 @@ struct ath11k_base; #define HAL_REO1_GEN_ENABLE_FRAG_DST_RING GENMASK(25, 23) #define HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE BIT(2) #define HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE BIT(3) +#define HAL_REO1_MISC_CTL_FRAGMENT_DST_RING GENMASK(20, 17) /* CE ring bit field mask and shift */ #define HAL_CE_DST_R0_DEST_CTRL_MAX_LEN GENMASK(15, 0) @@ -906,7 +908,6 @@ void ath11k_hal_reo_qdesc_setup(void *vaddr, int tid, u32 ba_window_size, u32 start_seq, enum hal_pn_type type); void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab, struct hal_srng *srng); -void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map); void ath11k_hal_setup_link_idle_list(struct ath11k_base *ab, struct hal_wbm_idle_scatter_list *sbuf, u32 nsbufs, u32 tot_link_desc, diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index fac2396edf32..325055ca41ab 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -801,43 +801,6 @@ void ath11k_hal_reo_init_cmd_ring(struct ath11k_base *ab, } } -void ath11k_hal_reo_hw_setup(struct ath11k_base *ab, u32 ring_hash_map) -{ - u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; - u32 val; - - val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE); - - val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING; - val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING, - HAL_SRNG_RING_ID_REO2SW1) | - FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | - FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); - ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val); - - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab), - HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab), - HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab), - HAL_DEFAULT_REO_TIMEOUT_USEC); - ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab), - HAL_DEFAULT_REO_TIMEOUT_USEC); - - ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, - FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, - ring_hash_map)); - ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1, - FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, - ring_hash_map)); - ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, - FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, - ring_hash_map)); - ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, - FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, - ring_hash_map)); -} - static enum hal_rx_mon_status ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, struct hal_rx_mon_ppdu_info *ppdu_info, @@ -1128,12 +1091,9 @@ ath11k_hal_rx_parse_mon_status_tlv(struct ath11k_base *ab, break; } case HAL_RX_MPDU_START: { - struct hal_rx_mpdu_info *mpdu_info = - (struct hal_rx_mpdu_info *)tlv_data; u16 peer_id; - peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID, - __le32_to_cpu(mpdu_info->info0)); + peer_id = ab->hw_params.hw_ops->mpdu_info_get_peerid(tlv_data); if (peer_id) ppdu_info->peer_id = peer_id; break; diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h index d464a270c049..0f1f04b812b9 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.h +++ b/drivers/net/wireless/ath/ath11k/hal_rx.h @@ -254,12 +254,20 @@ struct hal_rx_phyrx_rssi_legacy_info { } __packed; #define HAL_RX_MPDU_INFO_INFO0_PEERID GENMASK(31, 16) +#define HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855 GENMASK(15, 0) + struct hal_rx_mpdu_info { __le32 rsvd0; __le32 info0; __le32 rsvd1[21]; } __packed; +struct hal_rx_mpdu_info_wcn6855 { + __le32 rsvd0[8]; + __le32 info0; + __le32 rsvd1[14]; +} __packed; + #define HAL_RX_PPDU_END_DURATION GENMASK(23, 0) struct hal_rx_ppdu_end_duration { __le32 rsvd0[9]; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 377ae8d5b58f..d9596903b0a5 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -10,6 +10,7 @@ #include "hw.h" #include "core.h" #include "ce.h" +#include "hif.h" /* Map from pdev index to hw mac index */ static u8 ath11k_hw_ipq8074_mac_from_pdev_id(int pdev_idx) @@ -45,6 +46,13 @@ static void ath11k_hw_qcn9074_tx_mesh_enable(struct ath11k_base *ab, true); } +static void ath11k_hw_wcn6855_tx_mesh_enable(struct ath11k_base *ab, + struct hal_tcl_data_cmd *tcl_cmd) +{ + tcl_cmd->info3 |= FIELD_PREP(HAL_QCN9074_TCL_DATA_CMD_INFO3_MESH_ENABLE, + true); +} + static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, struct target_resource_config *config) { @@ -91,6 +99,52 @@ static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab, config->num_keep_alive_pattern = 0; } +static void ath11k_hw_ipq8074_reo_setup(struct ath11k_base *ab) +{ + u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; + u32 val; + /* Each hash entry uses three bits to map to a particular ring. */ + u32 ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | + HAL_HASH_ROUTING_RING_SW2 << 3 | + HAL_HASH_ROUTING_RING_SW3 << 6 | + HAL_HASH_ROUTING_RING_SW4 << 9 | + HAL_HASH_ROUTING_RING_SW1 << 12 | + HAL_HASH_ROUTING_RING_SW2 << 15 | + HAL_HASH_ROUTING_RING_SW3 << 18 | + HAL_HASH_ROUTING_RING_SW4 << 21; + + val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE); + + val &= ~HAL_REO1_GEN_ENABLE_FRAG_DST_RING; + val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_FRAG_DST_RING, + HAL_SRNG_RING_ID_REO2SW1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); + ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val); + + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_0, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, + ring_hash_map)); + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_1, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, + ring_hash_map)); + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, + ring_hash_map)); + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, + FIELD_PREP(HAL_REO_DEST_RING_CTRL_HASH_RING_MAP, + ring_hash_map)); +} + static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, struct target_resource_config *config) { @@ -489,6 +543,228 @@ static u8 *ath11k_hw_qcn9074_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) return &desc->u.qcn9074.msdu_payload[0]; } +static bool ath11k_hw_wcn6855_rx_desc_get_first_msdu(struct hal_rx_desc *desc) +{ + return !!FIELD_GET(RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855, + __le32_to_cpu(desc->u.wcn6855.msdu_end.info2)); +} + +static bool ath11k_hw_wcn6855_rx_desc_get_last_msdu(struct hal_rx_desc *desc) +{ + return !!FIELD_GET(RX_MSDU_END_INFO2_LAST_MSDU_WCN6855, + __le32_to_cpu(desc->u.wcn6855.msdu_end.info2)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_END_INFO2_L3_HDR_PADDING, + __le32_to_cpu(desc->u.wcn6855.msdu_end.info2)); +} + +static u8 *ath11k_hw_wcn6855_rx_desc_get_hdr_status(struct hal_rx_desc *desc) +{ + return desc->u.wcn6855.hdr_status; +} + +static bool ath11k_hw_wcn6855_rx_desc_encrypt_valid(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1) & + RX_MPDU_START_INFO1_ENCRYPT_INFO_VALID; +} + +static u32 ath11k_hw_wcn6855_rx_desc_get_encrypt_type(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MPDU_START_INFO2_ENC_TYPE, + __le32_to_cpu(desc->u.wcn6855.mpdu_start.info2)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_decap_type(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO2_DECAP_FORMAT, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info2)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO2_MESH_CTRL_PRESENT, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info2)); +} + +static bool ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) +{ + return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_CTRL_VALID, + __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1)); +} + +static bool ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc) +{ + return !!FIELD_GET(RX_MPDU_START_INFO1_MPDU_FCTRL_VALID, + __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1)); +} + +static u16 ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MPDU_START_INFO1_MPDU_SEQ_NUM, + __le32_to_cpu(desc->u.wcn6855.mpdu_start.info1)); +} + +static u16 ath11k_hw_wcn6855_rx_desc_get_msdu_len(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO1_MSDU_LENGTH, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info1)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO3_SGI, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info3)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO3_RATE_MCS, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info3)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO3_RECV_BW, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info3)); +} + +static u32 ath11k_hw_wcn6855_rx_desc_get_msdu_freq(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.wcn6855.msdu_start.phy_meta_data); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO3_PKT_TYPE, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info3)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MSDU_START_INFO3_MIMO_SS_BITMAP, + __le32_to_cpu(desc->u.wcn6855.msdu_start.info3)); +} + +static u8 ath11k_hw_wcn6855_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) +{ + return FIELD_GET(RX_MPDU_START_INFO2_TID_WCN6855, + __le32_to_cpu(desc->u.wcn6855.mpdu_start.info2)); +} + +static u16 ath11k_hw_wcn6855_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.wcn6855.mpdu_start.sw_peer_id); +} + +static void ath11k_hw_wcn6855_rx_desc_copy_attn_end(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + memcpy((u8 *)&fdesc->u.wcn6855.msdu_end, (u8 *)&ldesc->u.wcn6855.msdu_end, + sizeof(struct rx_msdu_end_wcn6855)); + memcpy((u8 *)&fdesc->u.wcn6855.attention, (u8 *)&ldesc->u.wcn6855.attention, + sizeof(struct rx_attention)); + memcpy((u8 *)&fdesc->u.wcn6855.mpdu_end, (u8 *)&ldesc->u.wcn6855.mpdu_end, + sizeof(struct rx_mpdu_end)); +} + +static u32 ath11k_hw_wcn6855_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc) +{ + return FIELD_GET(HAL_TLV_HDR_TAG, + __le32_to_cpu(desc->u.wcn6855.mpdu_start_tag)); +} + +static u32 ath11k_hw_wcn6855_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.wcn6855.mpdu_start.phy_ppdu_id); +} + +static void ath11k_hw_wcn6855_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.wcn6855.msdu_start.info1); + + info &= ~RX_MSDU_START_INFO1_MSDU_LENGTH; + info |= FIELD_PREP(RX_MSDU_START_INFO1_MSDU_LENGTH, len); + + desc->u.wcn6855.msdu_start.info1 = __cpu_to_le32(info); +} + +static +struct rx_attention *ath11k_hw_wcn6855_rx_desc_get_attention(struct hal_rx_desc *desc) +{ + return &desc->u.wcn6855.attention; +} + +static u8 *ath11k_hw_wcn6855_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) +{ + return &desc->u.wcn6855.msdu_payload[0]; +} + +static void ath11k_hw_wcn6855_reo_setup(struct ath11k_base *ab) +{ + u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG; + u32 val; + /* Each hash entry uses four bits to map to a particular ring. */ + u32 ring_hash_map = HAL_HASH_ROUTING_RING_SW1 << 0 | + HAL_HASH_ROUTING_RING_SW2 << 4 | + HAL_HASH_ROUTING_RING_SW3 << 8 | + HAL_HASH_ROUTING_RING_SW4 << 12 | + HAL_HASH_ROUTING_RING_SW1 << 16 | + HAL_HASH_ROUTING_RING_SW2 << 20 | + HAL_HASH_ROUTING_RING_SW3 << 24 | + HAL_HASH_ROUTING_RING_SW4 << 28; + + val = ath11k_hif_read32(ab, reo_base + HAL_REO1_GEN_ENABLE); + val |= FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE, 1) | + FIELD_PREP(HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE, 1); + ath11k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val); + + val = ath11k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTL); + val &= ~HAL_REO1_MISC_CTL_FRAGMENT_DST_RING; + val |= FIELD_PREP(HAL_REO1_MISC_CTL_FRAGMENT_DST_RING, HAL_SRNG_RING_ID_REO2SW1); + ath11k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTL, val); + + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + ath11k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab), + HAL_DEFAULT_REO_TIMEOUT_USEC); + + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2, + ring_hash_map); + ath11k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_3, + ring_hash_map); +} + +static u16 ath11k_hw_ipq8074_mpdu_info_get_peerid(u8 *tlv_data) +{ + u16 peer_id = 0; + struct hal_rx_mpdu_info *mpdu_info = + (struct hal_rx_mpdu_info *)tlv_data; + + peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID, + __le32_to_cpu(mpdu_info->info0)); + + return peer_id; +} + +static u16 ath11k_hw_wcn6855_mpdu_info_get_peerid(u8 *tlv_data) +{ + u16 peer_id = 0; + struct hal_rx_mpdu_info_wcn6855 *mpdu_info = + (struct hal_rx_mpdu_info_wcn6855 *)tlv_data; + + peer_id = FIELD_GET(HAL_RX_MPDU_INFO_INFO0_PEERID_WCN6855, + __le32_to_cpu(mpdu_info->info0)); + return peer_id; +} + const struct ath11k_hw_ops ipq8074_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, .wmi_init_config = ath11k_init_wmi_config_ipq8074, @@ -521,6 +797,8 @@ const struct ath11k_hw_ops ipq8074_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, }; const struct ath11k_hw_ops ipq6018_ops = { @@ -555,6 +833,8 @@ const struct ath11k_hw_ops ipq6018_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, }; const struct ath11k_hw_ops qca6390_ops = { @@ -589,6 +869,8 @@ const struct ath11k_hw_ops qca6390_ops = { .rx_desc_set_msdu_len = ath11k_hw_ipq8074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_ipq8074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_ipq8074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, }; const struct ath11k_hw_ops qcn9074_ops = { @@ -623,6 +905,44 @@ const struct ath11k_hw_ops qcn9074_ops = { .rx_desc_set_msdu_len = ath11k_hw_qcn9074_rx_desc_set_msdu_len, .rx_desc_get_attention = ath11k_hw_qcn9074_rx_desc_get_attention, .rx_desc_get_msdu_payload = ath11k_hw_qcn9074_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_ipq8074_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, +}; + +const struct ath11k_hw_ops wcn6855_ops = { + .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, + .wmi_init_config = ath11k_init_wmi_config_qca6390, + .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_qca6390, + .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_qca6390, + .tx_mesh_enable = ath11k_hw_wcn6855_tx_mesh_enable, + .rx_desc_get_first_msdu = ath11k_hw_wcn6855_rx_desc_get_first_msdu, + .rx_desc_get_last_msdu = ath11k_hw_wcn6855_rx_desc_get_last_msdu, + .rx_desc_get_l3_pad_bytes = ath11k_hw_wcn6855_rx_desc_get_l3_pad_bytes, + .rx_desc_get_hdr_status = ath11k_hw_wcn6855_rx_desc_get_hdr_status, + .rx_desc_encrypt_valid = ath11k_hw_wcn6855_rx_desc_encrypt_valid, + .rx_desc_get_encrypt_type = ath11k_hw_wcn6855_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath11k_hw_wcn6855_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath11k_hw_wcn6855_rx_desc_get_mesh_ctl, + .rx_desc_get_mpdu_seq_ctl_vld = ath11k_hw_wcn6855_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath11k_hw_wcn6855_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_seq_no, + .rx_desc_get_msdu_len = ath11k_hw_wcn6855_rx_desc_get_msdu_len, + .rx_desc_get_msdu_sgi = ath11k_hw_wcn6855_rx_desc_get_msdu_sgi, + .rx_desc_get_msdu_rate_mcs = ath11k_hw_wcn6855_rx_desc_get_msdu_rate_mcs, + .rx_desc_get_msdu_rx_bw = ath11k_hw_wcn6855_rx_desc_get_msdu_rx_bw, + .rx_desc_get_msdu_freq = ath11k_hw_wcn6855_rx_desc_get_msdu_freq, + .rx_desc_get_msdu_pkt_type = ath11k_hw_wcn6855_rx_desc_get_msdu_pkt_type, + .rx_desc_get_msdu_nss = ath11k_hw_wcn6855_rx_desc_get_msdu_nss, + .rx_desc_get_mpdu_tid = ath11k_hw_wcn6855_rx_desc_get_mpdu_tid, + .rx_desc_get_mpdu_peer_id = ath11k_hw_wcn6855_rx_desc_get_mpdu_peer_id, + .rx_desc_copy_attn_end_tlv = ath11k_hw_wcn6855_rx_desc_copy_attn_end, + .rx_desc_get_mpdu_start_tag = ath11k_hw_wcn6855_rx_desc_get_mpdu_start_tag, + .rx_desc_get_mpdu_ppdu_id = ath11k_hw_wcn6855_rx_desc_get_mpdu_ppdu_id, + .rx_desc_set_msdu_len = ath11k_hw_wcn6855_rx_desc_set_msdu_len, + .rx_desc_get_attention = ath11k_hw_wcn6855_rx_desc_get_attention, + .rx_desc_get_msdu_payload = ath11k_hw_wcn6855_rx_desc_get_msdu_payload, + .reo_setup = ath11k_hw_wcn6855_reo_setup, + .mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid, }; #define ATH11K_TX_RING_MASK_0 0x1 @@ -1688,3 +2008,74 @@ const struct ath11k_hw_regs qcn9074_regs = { .pcie_qserdes_sysclk_en_sel = 0x01e0e0a8, .pcie_pcs_osc_dtct_config_base = 0x01e0f45c, }; + +const struct ath11k_hw_regs wcn6855_regs = { + /* SW2TCL(x) R0 ring configuration address */ + .hal_tcl1_ring_base_lsb = 0x00000690, + .hal_tcl1_ring_base_msb = 0x00000694, + .hal_tcl1_ring_id = 0x00000698, + .hal_tcl1_ring_misc = 0x000006a0, + .hal_tcl1_ring_tp_addr_lsb = 0x000006ac, + .hal_tcl1_ring_tp_addr_msb = 0x000006b0, + .hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006c0, + .hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006c4, + .hal_tcl1_ring_msi1_base_lsb = 0x000006d8, + .hal_tcl1_ring_msi1_base_msb = 0x000006dc, + .hal_tcl1_ring_msi1_data = 0x000006e0, + .hal_tcl2_ring_base_lsb = 0x000006e8, + .hal_tcl_ring_base_lsb = 0x00000798, + + /* TCL STATUS ring address */ + .hal_tcl_status_ring_base_lsb = 0x000008a0, + + /* REO2SW(x) R0 ring configuration address */ + .hal_reo1_ring_base_lsb = 0x00000244, + .hal_reo1_ring_base_msb = 0x00000248, + .hal_reo1_ring_id = 0x0000024c, + .hal_reo1_ring_misc = 0x00000254, + .hal_reo1_ring_hp_addr_lsb = 0x00000258, + .hal_reo1_ring_hp_addr_msb = 0x0000025c, + .hal_reo1_ring_producer_int_setup = 0x00000268, + .hal_reo1_ring_msi1_base_lsb = 0x0000028c, + .hal_reo1_ring_msi1_base_msb = 0x00000290, + .hal_reo1_ring_msi1_data = 0x00000294, + .hal_reo2_ring_base_lsb = 0x0000029c, + .hal_reo1_aging_thresh_ix_0 = 0x000005bc, + .hal_reo1_aging_thresh_ix_1 = 0x000005c0, + .hal_reo1_aging_thresh_ix_2 = 0x000005c4, + .hal_reo1_aging_thresh_ix_3 = 0x000005c8, + + /* REO2SW(x) R2 ring pointers (head/tail) address */ + .hal_reo1_ring_hp = 0x00003030, + .hal_reo1_ring_tp = 0x00003034, + .hal_reo2_ring_hp = 0x00003038, + + /* REO2TCL R0 ring configuration address */ + .hal_reo_tcl_ring_base_lsb = 0x00000454, + .hal_reo_tcl_ring_hp = 0x00003060, + + /* REO status address */ + .hal_reo_status_ring_base_lsb = 0x0000055c, + .hal_reo_status_hp = 0x00003078, + + /* WCSS relative address */ + .hal_seq_wcss_umac_ce0_src_reg = 0x1b80000, + .hal_seq_wcss_umac_ce0_dst_reg = 0x1b81000, + .hal_seq_wcss_umac_ce1_src_reg = 0x1b82000, + .hal_seq_wcss_umac_ce1_dst_reg = 0x1b83000, + + /* WBM Idle address */ + .hal_wbm_idle_link_ring_base_lsb = 0x00000870, + .hal_wbm_idle_link_ring_misc = 0x00000880, + + /* SW2WBM release address */ + .hal_wbm_release_ring_base_lsb = 0x000001e8, + + /* WBM2SW release address */ + .hal_wbm0_release_ring_base_lsb = 0x00000920, + .hal_wbm1_release_ring_base_lsb = 0x00000978, + + /* PCIe base address */ + .pcie_qserdes_sysclk_en_sel = 0x01e0c0ac, + .pcie_pcs_osc_dtct_config_base = 0x01e0c628, +}; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index c81a6328361d..62f5978b3005 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -162,6 +162,7 @@ struct ath11k_hw_params { bool cold_boot_calib; bool supports_suspend; u32 hal_desc_sz; + bool fix_l1ss; }; struct ath11k_hw_ops { @@ -199,12 +200,15 @@ struct ath11k_hw_ops { void (*rx_desc_set_msdu_len)(struct hal_rx_desc *desc, u16 len); struct rx_attention *(*rx_desc_get_attention)(struct hal_rx_desc *desc); u8 *(*rx_desc_get_msdu_payload)(struct hal_rx_desc *desc); + void (*reo_setup)(struct ath11k_base *ab); + u16 (*mpdu_info_get_peerid)(u8 *tlv_data); }; extern const struct ath11k_hw_ops ipq8074_ops; extern const struct ath11k_hw_ops ipq6018_ops; extern const struct ath11k_hw_ops qca6390_ops; extern const struct ath11k_hw_ops qcn9074_ops; +extern const struct ath11k_hw_ops wcn6855_ops; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074; extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390; @@ -318,5 +322,6 @@ struct ath11k_hw_regs { extern const struct ath11k_hw_regs ipq8074_regs; extern const struct ath11k_hw_regs qca6390_regs; extern const struct ath11k_hw_regs qcn9074_regs; +extern const struct ath11k_hw_regs wcn6855_regs; #endif diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4df425dd31a2..e9b3689331ec 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1314,10 +1314,16 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, arg->he_flag = true; - memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, - sizeof(arg->peer_he_cap_macinfo)); - memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, - sizeof(arg->peer_he_cap_phyinfo)); + memcpy_and_pad(&arg->peer_he_cap_macinfo, + sizeof(arg->peer_he_cap_macinfo), + he_cap->he_cap_elem.mac_cap_info, + sizeof(he_cap->he_cap_elem.mac_cap_info), + 0); + memcpy_and_pad(&arg->peer_he_cap_phyinfo, + sizeof(arg->peer_he_cap_phyinfo), + he_cap->he_cap_elem.phy_cap_info, + sizeof(he_cap->he_cap_elem.phy_cap_info), + 0); arg->peer_he_ops = vif->bss_conf.he_oper.params; /* the top most byte is used to indicate BSS color info */ @@ -2779,6 +2785,12 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, */ spin_lock_bh(&ab->base_lock); peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr); + + /* flush the fragments cache during key (re)install to + * ensure all frags in the new frag list belong to the same key. + */ + if (peer && cmd == SET_KEY) + ath11k_peer_frags_flush(ar, peer); spin_unlock_bh(&ab->base_lock); if (!peer) { @@ -5373,11 +5385,6 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, if (WARN_ON(!arvif->is_up)) continue; - ret = ath11k_mac_setup_bcn_tmpl(arvif); - if (ret) - ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n", - ret); - ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); if (ret) { ath11k_warn(ab, "failed to restart vdev %d: %d\n", @@ -5385,6 +5392,11 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, continue; } + ret = ath11k_mac_setup_bcn_tmpl(arvif); + if (ret) + ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n", + ret); + ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, arvif->bssid); if (ret) { diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 27b394d115e2..75cc2d80fde8 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -354,6 +354,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) ath11k_mhi_config = &ath11k_mhi_config_qcn9074; break; case ATH11K_HW_QCA6390_HW20: + case ATH11K_HW_WCN6855_HW20: ath11k_mhi_config = &ath11k_mhi_config_qca6390; break; default: diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 0f31eb566fb6..646ad79f309c 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -36,10 +36,12 @@ #define QCA6390_DEVICE_ID 0x1101 #define QCN9074_DEVICE_ID 0x1104 +#define WCN6855_DEVICE_ID 0x1103 static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, - /* TODO: add QCN9074_DEVICE_ID) once firmware issues are resolved */ + { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, + { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, {0} }; @@ -432,7 +434,8 @@ static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) ath11k_pci_enable_ltssm(ab); ath11k_pci_clear_all_intrs(ab); ath11k_pci_set_wlaon_pwr_ctrl(ab); - ath11k_pci_fix_l1ss(ab); + if (ab->hw_params.fix_l1ss) + ath11k_pci_fix_l1ss(ab); } ath11k_mhi_clear_vector(ab); @@ -1176,12 +1179,26 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .get_ce_msi_idx = ath11k_pci_get_ce_msi_idx, }; +static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor) +{ + u32 soc_hw_version; + + soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); + *major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, + soc_hw_version); + *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, + soc_hw_version); + + ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", + *major, *minor); +} + static int ath11k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_dev) { struct ath11k_base *ab; struct ath11k_pci *ab_pci; - u32 soc_hw_version, soc_hw_version_major, soc_hw_version_minor; + u32 soc_hw_version_major, soc_hw_version_minor; int ret; ab = ath11k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH11K_BUS_PCI, @@ -1209,15 +1226,8 @@ static int ath11k_pci_probe(struct pci_dev *pdev, switch (pci_dev->device) { case QCA6390_DEVICE_ID: - soc_hw_version = ath11k_pci_read32(ab, TCSR_SOC_HW_VERSION); - soc_hw_version_major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK, - soc_hw_version); - soc_hw_version_minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, - soc_hw_version); - - ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", - soc_hw_version_major, soc_hw_version_minor); - + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, + &soc_hw_version_minor); switch (soc_hw_version_major) { case 2: ab->hw_rev = ATH11K_HW_QCA6390_HW20; @@ -1235,6 +1245,21 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab->bus_params.static_window_map = true; ab->hw_rev = ATH11K_HW_QCN9074_HW10; break; + case WCN6855_DEVICE_ID: + ath11k_pci_read_hw_version(ab, &soc_hw_version_major, + &soc_hw_version_minor); + switch (soc_hw_version_major) { + case 2: + ab->hw_rev = ATH11K_HW_WCN6855_HW20; + break; + default: + dev_err(&pdev->dev, "Unsupported WCN6855 SOC hardware version: %d %d\n", + soc_hw_version_major, soc_hw_version_minor); + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } + ab_pci->msi_config = &ath11k_msi_config[0]; + break; default: dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n", pci_dev->device); diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h index 0cdb4a1f816e..79c50804d7dc 100644 --- a/drivers/net/wireless/ath/ath11k/rx_desc.h +++ b/drivers/net/wireless/ath/ath11k/rx_desc.h @@ -368,6 +368,7 @@ struct rx_attention { #define RX_MPDU_START_INFO2_BSSID_HIT BIT(9) #define RX_MPDU_START_INFO2_BSSID_NUM GENMASK(13, 10) #define RX_MPDU_START_INFO2_TID GENMASK(17, 14) +#define RX_MPDU_START_INFO2_TID_WCN6855 GENMASK(18, 15) #define RX_MPDU_START_INFO3_REO_DEST_IND GENMASK(4, 0) #define RX_MPDU_START_INFO3_FLOW_ID_TOEPLITZ BIT(7) @@ -546,6 +547,31 @@ struct rx_mpdu_start_qcn9074 { __le32 ht_ctrl; } __packed; +struct rx_mpdu_start_wcn6855 { + __le32 info3; + __le32 reo_queue_desc_lo; + __le32 info4; + __le32 pn[4]; + __le32 info2; + __le32 peer_meta_data; + __le16 info0; + __le16 phy_ppdu_id; + __le16 ast_index; + __le16 sw_peer_id; + __le32 info1; + __le32 info5; + __le32 info6; + __le16 frame_ctrl; + __le16 duration; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + __le16 qos_ctrl; + __le32 ht_ctrl; +} __packed; + /* rx_mpdu_start * * rxpcu_mpdu_filter_in_category @@ -804,6 +830,20 @@ struct rx_msdu_start_qcn9074 { __le16 vlan_stag_c1; } __packed; +struct rx_msdu_start_wcn6855 { + __le16 info0; + __le16 phy_ppdu_id; + __le32 info1; + __le32 info2; + __le32 toeplitz_hash; + __le32 flow_id_toeplitz; + __le32 info3; + __le32 ppdu_start_timestamp; + __le32 phy_meta_data; + __le16 vlan_ctag_ci; + __le16 vlan_stag_ci; +} __packed; + /* rx_msdu_start * * rxpcu_mpdu_filter_in_category @@ -988,7 +1028,9 @@ struct rx_msdu_start_qcn9074 { #define RX_MSDU_END_INFO2_REPORTED_MPDU_LEN GENMASK(13, 0) #define RX_MSDU_END_INFO2_FIRST_MSDU BIT(14) +#define RX_MSDU_END_INFO2_FIRST_MSDU_WCN6855 BIT(28) #define RX_MSDU_END_INFO2_LAST_MSDU BIT(15) +#define RX_MSDU_END_INFO2_LAST_MSDU_WCN6855 BIT(29) #define RX_MSDU_END_INFO2_SA_IDX_TIMEOUT BIT(16) #define RX_MSDU_END_INFO2_DA_IDX_TIMEOUT BIT(17) #define RX_MSDU_END_INFO2_MSDU_LIMIT_ERR BIT(18) @@ -1037,6 +1079,31 @@ struct rx_msdu_end_ipq8074 { __le16 sa_sw_peer_id; } __packed; +struct rx_msdu_end_wcn6855 { + __le16 info0; + __le16 phy_ppdu_id; + __le16 ip_hdr_cksum; + __le16 reported_mpdu_len; + __le32 info1; + __le32 ext_wapi_pn[2]; + __le32 info4; + __le32 ipv6_options_crc; + __le32 tcp_seq_num; + __le32 tcp_ack_num; + __le16 info3; + __le16 window_size; + __le32 info2; + __le16 sa_idx; + __le16 da_idx; + __le32 info5; + __le32 fse_metadata; + __le16 cce_metadata; + __le16 sa_sw_peer_id; + __le32 rule_indication[2]; + __le32 info6; + __le32 info7; +} __packed; + #define RX_MSDU_END_MPDU_LENGTH_INFO GENMASK(13, 0) #define RX_MSDU_END_INFO2_DA_OFFSET GENMASK(5, 0) @@ -1400,10 +1467,30 @@ struct hal_rx_desc_qcn9074 { u8 msdu_payload[0]; } __packed; +struct hal_rx_desc_wcn6855 { + __le32 msdu_end_tag; + struct rx_msdu_end_wcn6855 msdu_end; + __le32 rx_attn_tag; + struct rx_attention attention; + __le32 msdu_start_tag; + struct rx_msdu_start_wcn6855 msdu_start; + u8 rx_padding0[HAL_RX_DESC_PADDING0_BYTES]; + __le32 mpdu_start_tag; + struct rx_mpdu_start_wcn6855 mpdu_start; + __le32 mpdu_end_tag; + struct rx_mpdu_end mpdu_end; + u8 rx_padding1[HAL_RX_DESC_PADDING1_BYTES]; + __le32 hdr_status_tag; + __le32 phy_ppdu_id; + u8 hdr_status[HAL_RX_DESC_HDR_STATUS_LEN]; + u8 msdu_payload[0]; +} __packed; + struct hal_rx_desc { union { struct hal_rx_desc_ipq8074 ipq8074; struct hal_rx_desc_qcn9074 qcn9074; + struct hal_rx_desc_wcn6855 wcn6855; } u; } __packed; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 5ca2d80679b6..6c253eae9d06 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -5235,7 +5235,7 @@ ath11k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src, dst->hw_reaped = src->hw_reaped; dst->underrun = src->underrun; dst->tx_abort = src->tx_abort; - dst->mpdus_requed = src->mpdus_requed; + dst->mpdus_requeued = src->mpdus_requeued; dst->tx_ko = src->tx_ko; dst->data_rc = src->data_rc; dst->self_triggers = src->self_triggers; @@ -5505,7 +5505,7 @@ ath11k_wmi_fw_pdev_tx_stats_fill(const struct ath11k_fw_stats_pdev *pdev, len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "PPDUs cleaned", pdev->tx_abort); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDUs requed", pdev->mpdus_requed); + "MPDUs requeued", pdev->mpdus_requeued); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", "Excessive retries", pdev->tx_ko); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 3ade1ddd35c9..d35c47e0b19d 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -4171,8 +4171,8 @@ struct wmi_pdev_stats_tx { /* Num PPDUs cleaned up in TX abort */ s32 tx_abort; - /* Num MPDUs requed by SW */ - s32 mpdus_requed; + /* Num MPDUs requeued by SW */ + s32 mpdus_requeued; /* excessive retries */ u32 tx_ko; diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index f2db7cf16566..3f4ce4e9c532 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -855,7 +855,7 @@ ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) } /** - * at5k_hw_stop_rx_pcu() - Stop RX engine + * ath5k_hw_stop_rx_pcu() - Stop RX engine * @ah: The &struct ath5k_hw * * Stops RX engine on PCU diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 29527e8dcced..fefdc6753acd 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3303,8 +3303,8 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (ret < 0) return ret; } else { - ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, - MATCHED_SSID_FILTER, 0); + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + MATCHED_SSID_FILTER, 0); if (ret < 0) return ret; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 76b538942a79..5184a0aacfe2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -522,6 +522,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); rxs->enc_flags |= (rxsp->status4 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0; + rxs->enc_flags |= + (rxsp->status4 & AR_STBC) ? (1 << RX_ENC_FLAG_STBC_SHIFT) : 0; rxs->bw = (rxsp->status4 & AR_2040) ? RATE_INFO_BW_40 : RATE_INFO_BW_20; rxs->evm0 = rxsp->status6; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 45f6402478b5..139831539da3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -307,6 +307,11 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) hchan = ah->curchan; } + if (!hchan) { + fastcc = false; + hchan = ath9k_cmn_get_channel(sc->hw, ah, &sc->cur_chan->chandef); + } + if (!ath_prepare_reset(sc)) fastcc = false; @@ -2649,7 +2654,7 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 duration) + struct ieee80211_prep_tx_info *info) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index b2d760873992..ba9bea79381c 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -16,13 +16,11 @@ config CARL9170 config CARL9170_LEDS bool "SoftLED Support" - depends on CARL9170 - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS default y + depends on CARL9170 + depends on MAC80211_LEDS help - This option is necessary, if you want your device' LEDs to blink + This option is necessary, if you want your device's LEDs to blink. Say Y, unless you need the LEDs for firmware debugging. diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index eae9abf540a7..b53ebb3ac9a2 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -24,7 +24,7 @@ #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) /** - * ath_hw_set_bssid_mask - filter out bssids we listen + * ath_hw_setbssidmask - filter out bssids we listen * * @common: the ath_common struct for the device. * diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 63079231e48e..8e1dbfda6538 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -800,7 +800,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, (char *)ctl_skb->skb->data, ctl_skb->skb->len); /* Move the head of the ring to the next empty descriptor */ - ch->head_blk_ctl = ctl_skb->next; + ch->head_blk_ctl = ctl_skb->next; /* Commit all previous writes and set descriptors to VALID */ wmb(); diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 65ef893f2736..455143c4164e 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -3464,8 +3464,12 @@ struct wcn36xx_hal_rem_bcn_filter_req { #define WCN36XX_HAL_OFFLOAD_DISABLE 0 #define WCN36XX_HAL_OFFLOAD_ENABLE 1 #define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE 0x2 +#define WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE 0x4 +#define WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE \ + (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_MCAST_FILTER_ENABLE) #define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE \ - (HAL_OFFLOAD_ENABLE|HAL_OFFLOAD_BCAST_FILTER_ENABLE) + (WCN36XX_HAL_OFFLOAD_ENABLE | WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE) +#define WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX 0x02 struct wcn36xx_hal_ns_offload_params { u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; @@ -3487,10 +3491,10 @@ struct wcn36xx_hal_ns_offload_params { /* slot index for this offload */ u32 slot_index; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_host_offload_req { - u8 offload_Type; + u8 offload_type; /* enable or disable */ u8 enable; @@ -3499,13 +3503,13 @@ struct wcn36xx_hal_host_offload_req { u8 host_ipv4_addr[4]; u8 host_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN]; } u; -}; +} __packed; struct wcn36xx_hal_host_offload_req_msg { struct wcn36xx_hal_msg_header header; struct wcn36xx_hal_host_offload_req host_offload_params; struct wcn36xx_hal_ns_offload_params ns_offload_params; -}; +} __packed; /* Packet Types. */ #define WCN36XX_HAL_KEEP_ALIVE_NULL_PKT 1 @@ -4901,7 +4905,7 @@ struct wcn36xx_hal_gtk_offload_req_msg { u64 key_replay_counter; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_gtk_offload_rsp_msg { struct wcn36xx_hal_msg_header header; @@ -4915,7 +4919,7 @@ struct wcn36xx_hal_gtk_offload_rsp_msg { struct wcn36xx_hal_gtk_offload_get_info_req_msg { struct wcn36xx_hal_msg_header header; u8 bss_index; -}; +} __packed; struct wcn36xx_hal_gtk_offload_get_info_rsp_msg { struct wcn36xx_hal_msg_header header; @@ -4939,7 +4943,7 @@ struct wcn36xx_hal_gtk_offload_get_info_rsp_msg { u32 igtk_rekey_count; u8 bss_index; -}; +} __packed; struct dhcp_info { /* Indicates the device mode which indicates about the DHCP activity */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index afb4877eaad8..d202f2128df2 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -25,6 +25,7 @@ #include <linux/rpmsg.h> #include <linux/soc/qcom/smem_state.h> #include <linux/soc/qcom/wcnss_ctrl.h> +#include <net/ipv6.h> #include "wcn36xx.h" #include "testmode.h" @@ -172,7 +173,9 @@ static struct ieee80211_supported_band wcn_band_5ghz = { #ifdef CONFIG_PM static const struct wiphy_wowlan_support wowlan_support = { - .flags = WIPHY_WOWLAN_ANY + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY }; #endif @@ -293,23 +296,16 @@ static int wcn36xx_start(struct ieee80211_hw *hw) goto out_free_dxe_pool; } - wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); - if (!wcn->hal_buf) { - wcn36xx_err("Failed to allocate smd buf\n"); - ret = -ENOMEM; - goto out_free_dxe_ctl; - } - ret = wcn36xx_smd_load_nv(wcn); if (ret) { wcn36xx_err("Failed to push NV to chip\n"); - goto out_free_smd_buf; + goto out_free_dxe_ctl; } ret = wcn36xx_smd_start(wcn); if (ret) { wcn36xx_err("Failed to start chip\n"); - goto out_free_smd_buf; + goto out_free_dxe_ctl; } if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) { @@ -336,8 +332,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw) out_smd_stop: wcn36xx_smd_stop(wcn); -out_free_smd_buf: - kfree(wcn->hal_buf); out_free_dxe_ctl: wcn36xx_dxe_free_ctl_blks(wcn); out_free_dxe_pool: @@ -372,8 +366,6 @@ static void wcn36xx_stop(struct ieee80211_hw *hw) wcn36xx_dxe_free_mem_pools(wcn); wcn36xx_dxe_free_ctl_blks(wcn); - - kfree(wcn->hal_buf); } static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable) @@ -1088,28 +1080,91 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw, #ifdef CONFIG_PM +static struct ieee80211_vif *wcn36xx_get_first_assoc_vif(struct wcn36xx *wcn) +{ + struct wcn36xx_vif *vif_priv = NULL; + struct ieee80211_vif *vif = NULL; + + list_for_each_entry(vif_priv, &wcn->vif_list, list) { + if (vif_priv->sta_assoc) { + vif = wcn36xx_priv_to_vif(vif_priv); + break; + } + } + return vif; +} + static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow) { struct wcn36xx *wcn = hw->priv; + struct ieee80211_vif *vif = NULL; + int ret = 0; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n"); - flush_workqueue(wcn->hal_ind_wq); - wcn36xx_smd_set_power_params(wcn, true); - return 0; + mutex_lock(&wcn->conf_mutex); + + vif = wcn36xx_get_first_assoc_vif(wcn); + if (vif) { + ret = wcn36xx_smd_arp_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_ipv6_ns_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_gtk_offload(wcn, vif, true); + if (ret) + goto out; + ret = wcn36xx_smd_set_power_params(wcn, true); + if (ret) + goto out; + ret = wcn36xx_smd_wlan_host_suspend_ind(wcn); + } +out: + mutex_unlock(&wcn->conf_mutex); + return ret; } static int wcn36xx_resume(struct ieee80211_hw *hw) { struct wcn36xx *wcn = hw->priv; + struct ieee80211_vif *vif = NULL; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n"); - flush_workqueue(wcn->hal_ind_wq); - wcn36xx_smd_set_power_params(wcn, false); + mutex_lock(&wcn->conf_mutex); + vif = wcn36xx_get_first_assoc_vif(wcn); + if (vif) { + wcn36xx_smd_host_resume(wcn); + wcn36xx_smd_set_power_params(wcn, false); + wcn36xx_smd_gtk_offload_get_info(wcn, vif); + wcn36xx_smd_gtk_offload(wcn, vif, false); + wcn36xx_smd_ipv6_ns_offload(wcn, vif, false); + wcn36xx_smd_arp_offload(wcn, vif, false); + } + mutex_unlock(&wcn->conf_mutex); + return 0; } +static void wcn36xx_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct wcn36xx *wcn = hw->priv; + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + + mutex_lock(&wcn->conf_mutex); + + memcpy(vif_priv->rekey_data.kek, data->kek, NL80211_KEK_LEN); + memcpy(vif_priv->rekey_data.kck, data->kck, NL80211_KCK_LEN); + vif_priv->rekey_data.replay_ctr = + cpu_to_le64(be64_to_cpup((__be64 *)data->replay_ctr)); + vif_priv->rekey_data.valid = true; + + mutex_unlock(&wcn->conf_mutex); +} + #endif static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, @@ -1176,6 +1231,34 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, return ret; } +#if IS_ENABLED(CONFIG_IPV6) +static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct inet6_dev *idev) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct inet6_ifaddr *ifa; + int idx = 0; + + memset(vif_priv->tentative_addrs, 0, sizeof(vif_priv->tentative_addrs)); + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + vif_priv->target_ipv6_addrs[idx] = ifa->addr; + if (ifa->flags & IFA_F_TENTATIVE) + __set_bit(idx, vif_priv->tentative_addrs); + idx++; + if (idx >= WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX) + break; + wcn36xx_dbg(WCN36XX_DBG_MAC, "%pI6 %s\n", &ifa->addr, + (ifa->flags & IFA_F_TENTATIVE) ? "tentative" : NULL); + } + read_unlock_bh(&idev->lock); + + vif_priv->num_target_ipv6_addrs = idx; +} +#endif + static const struct ieee80211_ops wcn36xx_ops = { .start = wcn36xx_start, .stop = wcn36xx_stop, @@ -1184,6 +1267,7 @@ static const struct ieee80211_ops wcn36xx_ops = { #ifdef CONFIG_PM .suspend = wcn36xx_suspend, .resume = wcn36xx_resume, + .set_rekey_data = wcn36xx_set_rekey_data, #endif .config = wcn36xx_config, .prepare_multicast = wcn36xx_prepare_multicast, @@ -1199,6 +1283,9 @@ static const struct ieee80211_ops wcn36xx_ops = { .sta_add = wcn36xx_sta_add, .sta_remove = wcn36xx_sta_remove, .ampdu_action = wcn36xx_ampdu_action, +#if IS_ENABLED(CONFIG_IPV6) + .ipv6_addr_change = wcn36xx_ipv6_addr_change, +#endif CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) }; @@ -1401,6 +1488,12 @@ static int wcn36xx_probe(struct platform_device *pdev) mutex_init(&wcn->hal_mutex); mutex_init(&wcn->scan_lock); + wcn->hal_buf = devm_kmalloc(wcn->dev, WCN36XX_HAL_BUF_SIZE, GFP_KERNEL); + if (!wcn->hal_buf) { + ret = -ENOMEM; + goto out_wq; + } + ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32)); if (ret < 0) { wcn36xx_err("failed to set DMA mask: %d\n", ret); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index d0c3a1557e8d..0e3be17d8cea 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -445,22 +445,12 @@ out: return ret; } -static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr, - enum wcn36xx_hal_host_msg_type msg_type, - size_t msg_size) -{ - memset(hdr, 0, msg_size + sizeof(*hdr)); - hdr->msg_type = msg_type; - hdr->msg_version = WCN36XX_HAL_MSG_VERSION0; - hdr->len = msg_size + sizeof(*hdr); -} - #define __INIT_HAL_MSG(msg_body, type, version) \ do { \ - memset(&msg_body, 0, sizeof(msg_body)); \ - msg_body.header.msg_type = type; \ - msg_body.header.msg_version = version; \ - msg_body.header.len = sizeof(msg_body); \ + memset(&(msg_body), 0, sizeof(msg_body)); \ + (msg_body).header.msg_type = type; \ + (msg_body).header.msg_version = version; \ + (msg_body).header.len = sizeof(msg_body); \ } while (0) \ #define INIT_HAL_MSG(msg_body, type) \ @@ -2729,8 +2719,7 @@ int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *) wcn->hal_buf; - init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ, - sizeof(msg_body->mc_addr_list)); + INIT_HAL_MSG(*msg_body, WCN36XX_HAL_8023_MULTICAST_LIST_REQ); /* An empty list means all mc traffic will be received */ if (fp) @@ -2756,6 +2745,269 @@ out: return ret; } +int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_host_offload_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); + msg_body.host_offload_params.offload_type = + WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD; + if (enable) { + msg_body.host_offload_params.enable = + WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE; + memcpy(&msg_body.host_offload_params.u, + &vif->bss_conf.arp_addr_list[0], sizeof(__be32)); + } + msg_body.ns_offload_params.bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +#if IS_ENABLED(CONFIG_IPV6) +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_host_offload_req_msg msg_body; + struct wcn36xx_hal_ns_offload_params *ns_params; + struct wcn36xx_hal_host_offload_req *ho_params; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_OFFLOAD_REQ); + ho_params = &msg_body.host_offload_params; + ns_params = &msg_body.ns_offload_params; + + ho_params->offload_type = WCN36XX_HAL_IPV6_NS_OFFLOAD; + if (enable) { + ho_params->enable = + WCN36XX_HAL_OFFLOAD_NS_AND_MCAST_FILTER_ENABLE; + if (vif_priv->num_target_ipv6_addrs) { + memcpy(&ho_params->u, + &vif_priv->target_ipv6_addrs[0].in6_u, + sizeof(struct in6_addr)); + memcpy(&ns_params->target_ipv6_addr1, + &vif_priv->target_ipv6_addrs[0].in6_u, + sizeof(struct in6_addr)); + ns_params->target_ipv6_addr1_valid = 1; + } + if (vif_priv->num_target_ipv6_addrs > 1) { + memcpy(&ns_params->target_ipv6_addr2, + &vif_priv->target_ipv6_addrs[1].in6_u, + sizeof(struct in6_addr)); + ns_params->target_ipv6_addr2_valid = 1; + } + } + memcpy(&ns_params->self_addr, vif->addr, ETH_ALEN); + ns_params->bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} +#else +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + return 0; +} +#endif + +int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_REQ); + + if (enable) { + memcpy(&msg_body.kek, vif_priv->rekey_data.kek, NL80211_KEK_LEN); + memcpy(&msg_body.kck, vif_priv->rekey_data.kck, NL80211_KCK_LEN); + msg_body.key_replay_counter = + le64_to_cpu(vif_priv->rekey_data.replay_ctr); + msg_body.bss_index = vif_priv->bss_index; + } else { + msg_body.flags = WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE; + } + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending host_offload_arp failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("host_offload_arp failed err=%d\n", ret); + goto out; + } +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +static int wcn36xx_smd_gtk_offload_get_info_rsp(struct wcn36xx *wcn, + struct ieee80211_vif *vif) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *rsp; + __be64 replay_ctr; + + if (wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len)) + return -EIO; + + rsp = (struct wcn36xx_hal_gtk_offload_get_info_rsp_msg *)wcn->hal_buf; + + if (rsp->bss_index != vif_priv->bss_index) { + wcn36xx_err("gtk_offload_info invalid response bss index %d\n", + rsp->bss_index); + return -ENOENT; + } + + if (vif_priv->rekey_data.replay_ctr != cpu_to_le64(rsp->key_replay_counter)) { + replay_ctr = cpu_to_be64(rsp->key_replay_counter); + vif_priv->rekey_data.replay_ctr = + cpu_to_le64(rsp->key_replay_counter); + ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, + (void *)&replay_ctr, GFP_KERNEL); + wcn36xx_dbg(WCN36XX_DBG_HAL, + "GTK replay counter increment %llu\n", + rsp->key_replay_counter); + } + + wcn36xx_dbg(WCN36XX_DBG_HAL, + "gtk offload info status %d last_rekey_status %d " + "replay_counter %llu total_rekey_count %d gtk_rekey_count %d " + "igtk_rekey_count %d bss_index %d\n", + rsp->status, rsp->last_rekey_status, + rsp->key_replay_counter, rsp->total_rekey_count, + rsp->gtk_rekey_count, rsp->igtk_rekey_count, + rsp->bss_index); + + return 0; +} + +int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn, + struct ieee80211_vif *vif) +{ + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); + struct wcn36xx_hal_gtk_offload_get_info_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ); + + msg_body.bss_index = vif_priv->bss_index; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending gtk_offload_get_info failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("gtk_offload_get_info failed err=%d\n", ret); + goto out; + } + ret = wcn36xx_smd_gtk_offload_get_info_rsp(wcn, vif); +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_wlan_host_suspend_ind_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_SUSPEND_IND); + msg_body.configured_mcst_bcst_filter_setting = 0; + msg_body.active_session_count = 1; + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = rpmsg_send(wcn->smd_channel, wcn->hal_buf, msg_body.header.len); + + mutex_unlock(&wcn->hal_mutex); + + return ret; +} + +int wcn36xx_smd_host_resume(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_wlan_host_resume_req_msg msg_body; + struct wcn36xx_hal_host_resume_rsp_msg *rsp; + int ret; + + mutex_lock(&wcn->hal_mutex); + + INIT_HAL_MSG(msg_body, WCN36XX_HAL_HOST_RESUME_REQ); + msg_body.configured_mcst_bcst_filter_setting = 0; + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending wlan_host_resume failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("wlan_host_resume err=%d\n", ret); + goto out; + } + + rsp = (struct wcn36xx_hal_host_resume_rsp_msg *)wcn->hal_buf; + if (rsp->status) + wcn36xx_warn("wlan_host_resume status=%d\n", rsp->status); + +out: + mutex_unlock(&wcn->hal_mutex); + + return ret; +} + int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, void *buf, int len, void *priv, u32 addr) { @@ -2804,6 +3056,10 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_8023_MULTICAST_LIST_RSP: case WCN36XX_HAL_START_SCAN_OFFLOAD_RSP: case WCN36XX_HAL_STOP_SCAN_OFFLOAD_RSP: + case WCN36XX_HAL_HOST_OFFLOAD_RSP: + case WCN36XX_HAL_GTK_OFFLOAD_RSP: + case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP: + case WCN36XX_HAL_HOST_RESUME_RSP: memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 462860572e1f..d8bded03945d 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -146,4 +146,21 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn, struct ieee80211_vif *vif, struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp); + +int wcn36xx_smd_arp_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_ipv6_ns_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_gtk_offload(struct wcn36xx *wcn, struct ieee80211_vif *vif, + bool enable); + +int wcn36xx_smd_gtk_offload_get_info(struct wcn36xx *wcn, + struct ieee80211_vif *vif); + +int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn); + +int wcn36xx_smd_host_resume(struct wcn36xx *wcn); + #endif /* _SMD_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 71fa9992b118..6121d8a5641a 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -18,6 +18,7 @@ #define _WCN36XX_H_ #include <linux/completion.h> +#include <linux/in6.h> #include <linux/printk.h> #include <linux/spinlock.h> #include <net/mac80211.h> @@ -136,6 +137,19 @@ struct wcn36xx_vif { u8 self_dpu_desc_index; u8 self_ucast_dpu_sign; +#if IS_ENABLED(CONFIG_IPV6) + /* IPv6 addresses for WoWLAN */ + struct in6_addr target_ipv6_addrs[WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX]; + unsigned long tentative_addrs[BITS_TO_LONGS(WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)]; + int num_target_ipv6_addrs; +#endif + /* WoWLAN GTK rekey data */ + struct { + u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN]; + __le64 replay_ctr; + bool valid; + } rekey_data; + struct list_head sta_list; }; diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 6746fd206d2a..1ff2679963f0 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -2842,9 +2842,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil) wil->radio_wdev = wil->main_ndev->ieee80211_ptr; mutex_unlock(&wil->vif_mutex); if (p2p_wdev) { - wiphy_lock(wil->wiphy); cfg80211_unregister_wdev(p2p_wdev); - wiphy_unlock(wil->wiphy); kfree(p2p_wdev); } } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index d13d081fdcc6..67172385a5d6 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -9,7 +9,7 @@ #include "wil6210.h" #include "trace.h" -/** +/* * Theory of operation: * * There is ISR pseudo-cause register, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 02ad44997e87..2dc8406736f4 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -224,7 +224,7 @@ struct auth_no_hdr { u8 led_polarity = LED_POLARITY_LOW_ACTIVE; /** - * return AHB address for given firmware internal (linker) address + * wmi_addr_remap - return AHB address for given firmware internal (linker) address * @x: internal address * If address have no valid AHB mapping, return 0 */ @@ -242,7 +242,7 @@ static u32 wmi_addr_remap(u32 x) } /** - * find fw_mapping entry by section name + * wil_find_fw_mapping - find fw_mapping entry by section name * @section: section name * * Return pointer to section or NULL if not found @@ -260,7 +260,7 @@ struct fw_map *wil_find_fw_mapping(const char *section) } /** - * Check address validity for WMI buffer; remap if needed + * wmi_buffer_block - Check address validity for WMI buffer; remap if needed * @wil: driver data * @ptr_: internal (linker) fw/ucode address * @size: if non zero, validate the block does not diff --git a/drivers/net/wireless/broadcom/b43/debugfs.c b/drivers/net/wireless/broadcom/b43/debugfs.c index 89a25aefb327..efa98444e3fb 100644 --- a/drivers/net/wireless/broadcom/b43/debugfs.c +++ b/drivers/net/wireless/broadcom/b43/debugfs.c @@ -643,24 +643,14 @@ bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature) return enabled; } -static void b43_remove_dynamic_debug(struct b43_wldev *dev) -{ - struct b43_dfsentry *e = dev->dfsentry; - int i; - - for (i = 0; i < __B43_NR_DYNDBG; i++) - debugfs_remove(e->dyn_debug_dentries[i]); -} - static void b43_add_dynamic_debug(struct b43_wldev *dev) { struct b43_dfsentry *e = dev->dfsentry; #define add_dyn_dbg(name, id, initstate) do { \ e->dyn_debug[id] = (initstate); \ - e->dyn_debug_dentries[id] = \ - debugfs_create_bool(name, 0600, e->subdir, \ - &(e->dyn_debug[id])); \ + debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ } while (0) add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, false); @@ -713,10 +703,9 @@ void b43_debugfs_add_device(struct b43_wldev *dev) #define ADD_FILE(name, mode) \ do { \ - e->file_##name.dentry = \ - debugfs_create_file(__stringify(name), \ - mode, e->subdir, dev, \ - &fops_##name.fops); \ + debugfs_create_file(__stringify(name), \ + mode, e->subdir, dev, \ + &fops_##name.fops); \ } while (0) @@ -746,19 +735,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) e = dev->dfsentry; if (!e) return; - b43_remove_dynamic_debug(dev); - - debugfs_remove(e->file_shm16read.dentry); - debugfs_remove(e->file_shm16write.dentry); - debugfs_remove(e->file_shm32read.dentry); - debugfs_remove(e->file_shm32write.dentry); - debugfs_remove(e->file_mmio16read.dentry); - debugfs_remove(e->file_mmio16write.dentry); - debugfs_remove(e->file_mmio32read.dentry); - debugfs_remove(e->file_mmio32write.dentry); - debugfs_remove(e->file_txstat.dentry); - debugfs_remove(e->file_restart.dentry); - debugfs_remove(e->file_loctls.dentry); debugfs_remove(e->subdir); kfree(e->txstatlog.log); diff --git a/drivers/net/wireless/broadcom/b43/debugfs.h b/drivers/net/wireless/broadcom/b43/debugfs.h index 0bf437c86c67..6f6b500b8881 100644 --- a/drivers/net/wireless/broadcom/b43/debugfs.h +++ b/drivers/net/wireless/broadcom/b43/debugfs.h @@ -32,7 +32,6 @@ struct b43_txstatus_log { }; struct b43_dfs_file { - struct dentry *dentry; char *buffer; size_t data_len; }; @@ -70,8 +69,6 @@ struct b43_dfsentry { /* Enabled/Disabled list for the dynamic debugging features. */ bool dyn_debug[__B43_NR_DYNDBG]; - /* Dentries for the dynamic debugging entries. */ - struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG]; }; bool b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature); diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c index 665b737fbb0d..cf3ccf4ddfe7 100644 --- a/drivers/net/wireless/broadcom/b43/phy_n.c +++ b/drivers/net/wireless/broadcom/b43/phy_n.c @@ -4592,58 +4592,11 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; - u8 channel = dev->phy.channel; - int tone[2] = { 57, 58 }; - u32 noise[2] = { 0x3FF, 0x3FF }; - B43_WARN_ON(dev->phy.rev < 3); if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 1); - if (nphy->gband_spurwar_en) { - /* TODO: N PHY Adjust Analog Pfbw (7) */ - if (channel == 11 && b43_is_40mhz(dev)) { - ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/ - } else { - ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ - } - /* TODO: N PHY Adjust CRS Min Power (0x1E) */ - } - - if (nphy->aband_spurwar_en) { - if (channel == 54) { - tone[0] = 0x20; - noise[0] = 0x25F; - } else if (channel == 38 || channel == 102 || channel == 118) { - if (0 /* FIXME */) { - tone[0] = 0x20; - noise[0] = 0x21F; - } else { - tone[0] = 0; - noise[0] = 0; - } - } else if (channel == 134) { - tone[0] = 0x20; - noise[0] = 0x21F; - } else if (channel == 151) { - tone[0] = 0x10; - noise[0] = 0x23F; - } else if (channel == 153 || channel == 161) { - tone[0] = 0x30; - noise[0] = 0x23F; - } else { - tone[0] = 0; - noise[0] = 0; - } - - if (!tone[0] && !noise[0]) { - ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/ - } else { - ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/ - } - } - if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 0); } diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.c b/drivers/net/wireless/broadcom/b43legacy/debugfs.c index e7e4293c01f2..6b0e8d117061 100644 --- a/drivers/net/wireless/broadcom/b43legacy/debugfs.c +++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.c @@ -336,24 +336,14 @@ int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature) return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]); } -static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev) -{ - struct b43legacy_dfsentry *e = dev->dfsentry; - int i; - - for (i = 0; i < __B43legacy_NR_DYNDBG; i++) - debugfs_remove(e->dyn_debug_dentries[i]); -} - static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev) { struct b43legacy_dfsentry *e = dev->dfsentry; #define add_dyn_dbg(name, id, initstate) do { \ e->dyn_debug[id] = (initstate); \ - e->dyn_debug_dentries[id] = \ - debugfs_create_bool(name, 0600, e->subdir, \ - &(e->dyn_debug[id])); \ + debugfs_create_bool(name, 0600, e->subdir, \ + &(e->dyn_debug[id])); \ } while (0) add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, false); @@ -396,11 +386,9 @@ void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) #define ADD_FILE(name, mode) \ do { \ - e->file_##name.dentry = \ - debugfs_create_file(__stringify(name), \ - mode, e->subdir, dev, \ - &fops_##name.fops); \ - e->file_##name.dentry = NULL; \ + debugfs_create_file(__stringify(name), mode, \ + e->subdir, dev, \ + &fops_##name.fops); \ } while (0) @@ -424,13 +412,6 @@ void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) e = dev->dfsentry; if (!e) return; - b43legacy_remove_dynamic_debug(dev); - - debugfs_remove(e->file_tsf.dentry); - debugfs_remove(e->file_ucode_regs.dentry); - debugfs_remove(e->file_shm.dentry); - debugfs_remove(e->file_txstat.dentry); - debugfs_remove(e->file_restart.dentry); debugfs_remove(e->subdir); kfree(e->txstatlog.log); diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.h b/drivers/net/wireless/broadcom/b43legacy/debugfs.h index 7a37764406b1..924130880dfe 100644 --- a/drivers/net/wireless/broadcom/b43legacy/debugfs.h +++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.h @@ -28,7 +28,6 @@ struct b43legacy_txstatus_log { }; struct b43legacy_dfs_file { - struct dentry *dentry; char *buffer; size_t data_len; }; @@ -49,8 +48,6 @@ struct b43legacy_dfsentry { /* Enabled/Disabled list for the dynamic debugging features. */ bool dyn_debug[__B43legacy_NR_DYNDBG]; - /* Dentries for the dynamic debugging entries. */ - struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG]; }; int b43legacy_debug(struct b43legacy_wldev *dev, diff --git a/drivers/net/wireless/broadcom/b43legacy/dma.c b/drivers/net/wireless/broadcom/b43legacy/dma.c index 7e2f70c4207c..6869f2bf1bae 100644 --- a/drivers/net/wireless/broadcom/b43legacy/dma.c +++ b/drivers/net/wireless/broadcom/b43legacy/dma.c @@ -213,19 +213,6 @@ return dev->dma.tx_ring1; return ring; } -/* Bcm4301-ring to mac80211-queue mapping */ -static inline int txring_to_priority(struct b43legacy_dmaring *ring) -{ - static const u8 idx_to_prio[] = - { 3, 2, 1, 0, 4, 5, }; - -/*FIXME: have only one queue, for now */ -return 0; - - return idx_to_prio[ring->index]; -} - - static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, int controller_idx) { diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index f64ebff68308..eec3af9c3745 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -391,7 +391,7 @@ void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf) * registers, we should take care of register overflows. * In theory, the whole tsf read process should be atomic. * We try to be atomic here, by restaring the read process, - * if any of the high registers changed (overflew). + * if any of the high registers changed (overflowed). */ if (dev->dev->id.revision >= 3) { u32 low; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index f4405d7861b6..cedba56fc448 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -2767,8 +2767,9 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, struct brcmf_sta_info_le sta_info_le; u32 sta_flags; u32 is_tdls_peer; - s32 total_rssi; - s32 count_rssi; + s32 total_rssi_avg = 0; + s32 total_rssi = 0; + s32 count_rssi = 0; int rssi; u32 i; @@ -2834,25 +2835,27 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES); sinfo->rx_bytes = le64_to_cpu(sta_info_le.rx_tot_bytes); } - total_rssi = 0; - count_rssi = 0; for (i = 0; i < BRCMF_ANT_MAX; i++) { - if (sta_info_le.rssi[i]) { - sinfo->chain_signal_avg[count_rssi] = - sta_info_le.rssi[i]; - sinfo->chain_signal[count_rssi] = - sta_info_le.rssi[i]; - total_rssi += sta_info_le.rssi[i]; - count_rssi++; - } + if (sta_info_le.rssi[i] == 0 || + sta_info_le.rx_lastpkt_rssi[i] == 0) + continue; + sinfo->chains |= BIT(count_rssi); + sinfo->chain_signal[count_rssi] = + sta_info_le.rx_lastpkt_rssi[i]; + sinfo->chain_signal_avg[count_rssi] = + sta_info_le.rssi[i]; + total_rssi += sta_info_le.rx_lastpkt_rssi[i]; + total_rssi_avg += sta_info_le.rssi[i]; + count_rssi++; } if (count_rssi) { - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); - sinfo->chains = count_rssi; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); - total_rssi /= count_rssi; - sinfo->signal = total_rssi; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); + sinfo->filled |= + BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); + sinfo->signal = total_rssi / count_rssi; + sinfo->signal_avg = total_rssi_avg / count_rssi; } else if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) { memset(&scb_val, 0, sizeof(scb_val)); @@ -2892,8 +2895,13 @@ brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, &cfg->assoclist, sizeof(cfg->assoclist)); if (err) { - bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST unsupported, err=%d\n", - err); + /* GET_ASSOCLIST unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "BRCMF_C_GET_ASSOCLIST unsupported\n"); + else + bphy_err(drvr, "BRCMF_C_GET_ASSOCLIST failed, err=%d\n", + err); + cfg->assoclist.count = 0; return -EOPNOTSUPP; } @@ -6848,7 +6856,12 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) err = brcmf_fil_iovar_int_get(ifp, "rxchain", &rxchain); if (err) { - bphy_err(drvr, "rxchain error (%d)\n", err); + /* rxchain unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "rxchain unsupported\n"); + else + bphy_err(drvr, "rxchain error (%d)\n", err); + nchain = 1; } else { for (nchain = 0; rxchain; nchain++) @@ -7442,18 +7455,23 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], s32 found_index; int i; - country_codes = drvr->settings->country_codes; - if (!country_codes) { - brcmf_dbg(TRACE, "No country codes configured for device\n"); - return -EINVAL; - } - if ((alpha2[0] == ccreq->country_abbrev[0]) && (alpha2[1] == ccreq->country_abbrev[1])) { brcmf_dbg(TRACE, "Country code already set\n"); return -EAGAIN; } + country_codes = drvr->settings->country_codes; + if (!country_codes) { + brcmf_dbg(TRACE, "No country codes configured for device, using ISO3166 code and 0 rev\n"); + memset(ccreq, 0, sizeof(*ccreq)); + ccreq->country_abbrev[0] = alpha2[0]; + ccreq->country_abbrev[1] = alpha2[1]; + ccreq->ccode[0] = alpha2[0]; + ccreq->ccode[1] = alpha2[1]; + return 0; + } + found_index = -1; for (i = 0; i < country_codes->table_size; i++) { cc = &country_codes->table[i]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index cee1682d2333..db5f8535fdb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -188,9 +188,14 @@ static void _brcmf_set_multicast_list(struct work_struct *work) /*Finally, pick up the PROMISC flag */ cmd_value = (ndev->flags & IFF_PROMISC) ? true : false; err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value); - if (err < 0) - bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, %d\n", - err); + if (err < 0) { + /* PROMISC unsupported by firmware of older chips */ + if (err == -EBADE) + bphy_info_once(drvr, "BRCMF_C_SET_PROMISC unsupported\n"); + else + bphy_err(drvr, "Setting BRCMF_C_SET_PROMISC failed, err=%d\n", + err); + } brcmf_configure_arp_nd_offload(ifp, !cmd_value); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index 44ba6f389fa9..9bb5f709d41a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -60,6 +60,10 @@ void __brcmf_err(struct brcmf_bus *bus, const char *func, const char *fmt, ...); ##__VA_ARGS__); \ } while (0) +#define bphy_info_once(drvr, fmt, ...) \ + wiphy_info_once((drvr)->wiphy, "%s: " fmt, __func__, \ + ##__VA_ARGS__) + #if defined(DEBUG) || defined(CONFIG_BRCM_TRACING) /* For debug/tracing purposes treat info messages as errors */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index 46c66415b4a6..e290dec9c53d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -32,6 +32,13 @@ static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ BRCMF_FW_DEFAULT_PATH fw_base; \ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin") +/* Firmware and Country Local Matrix files */ +#define BRCMF_FW_CLM_DEF(fw_name, fw_base) \ +static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ + BRCMF_FW_DEFAULT_PATH fw_base; \ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin"); \ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".clm_blob") + #define BRCMF_FW_ENTRY(chipid, mask, name) \ { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index a7554265f95f..2f7bc3a70c65 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -12,12 +12,59 @@ #include "common.h" #include "of.h" +static int brcmf_of_get_country_codes(struct device *dev, + struct brcmf_mp_device *settings) +{ + struct device_node *np = dev->of_node; + struct brcmfmac_pd_cc_entry *cce; + struct brcmfmac_pd_cc *cc; + int count; + int i; + + count = of_property_count_strings(np, "brcm,ccode-map"); + if (count < 0) { + /* The property is optional, so return success if it doesn't + * exist. Otherwise propagate the error code. + */ + return (count == -EINVAL) ? 0 : count; + } + + cc = devm_kzalloc(dev, sizeof(*cc) + count * sizeof(*cce), GFP_KERNEL); + if (!cc) + return -ENOMEM; + + cc->table_size = count; + + for (i = 0; i < count; i++) { + const char *map; + + cce = &cc->table[i]; + + if (of_property_read_string_index(np, "brcm,ccode-map", + i, &map)) + continue; + + /* String format e.g. US-Q2-86 */ + if (sscanf(map, "%2c-%2c-%d", cce->iso3166, cce->cc, + &cce->rev) != 3) + brcmf_err("failed to read country map %s\n", map); + else + brcmf_dbg(INFO, "%s-%s-%d\n", cce->iso3166, cce->cc, + cce->rev); + } + + settings->country_codes = cc; + + return 0; +} + void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; struct device_node *root, *np = dev->of_node; int irq; + int err; u32 irqf; u32 val; @@ -43,8 +90,14 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, of_node_put(root); } - if (!np || bus_type != BRCMF_BUSTYPE_SDIO || - !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) + return; + + err = brcmf_of_get_country_codes(dev, settings); + if (err) + brcmf_err("failed to get OF country code map (err=%d)\n", err); + + if (bus_type != BRCMF_BUSTYPE_SDIO) return; if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 34cd8a7401fe..9ac0d8c73d5a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2037,7 +2037,7 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, } /** - * Change a P2P Role. + * brcmf_p2p_ifchange - Change a P2P Role. * @cfg: driver private data for cfg80211 interface. * @if_type: interface type. * Returns 0 if success. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 143a705b5cb3..c49dd0c36ae4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -48,8 +48,8 @@ enum brcmf_pcie_state { BRCMF_FW_DEF(43602, "brcmfmac43602-pcie"); BRCMF_FW_DEF(4350, "brcmfmac4350-pcie"); BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie"); -BRCMF_FW_DEF(4356, "brcmfmac4356-pcie"); -BRCMF_FW_DEF(43570, "brcmfmac43570-pcie"); +BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-pcie"); +BRCMF_FW_CLM_DEF(43570, "brcmfmac43570-pcie"); BRCMF_FW_DEF(4358, "brcmfmac4358-pcie"); BRCMF_FW_DEF(4359, "brcmfmac4359-pcie"); BRCMF_FW_DEF(4364, "brcmfmac4364-pcie"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 16ed325795a8..97ee9e2e2e35 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -616,18 +616,18 @@ BRCMF_FW_DEF(43362, "brcmfmac43362-sdio"); BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ -BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); -BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); +BRCMF_FW_CLM_DEF(43430A1, "brcmfmac43430-sdio"); +BRCMF_FW_CLM_DEF(43455, "brcmfmac43455-sdio"); BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); -BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); -BRCMF_FW_DEF(4356, "brcmfmac4356-sdio"); +BRCMF_FW_CLM_DEF(4354, "brcmfmac4354-sdio"); +BRCMF_FW_CLM_DEF(4356, "brcmfmac4356-sdio"); BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); -BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); -BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); +BRCMF_FW_CLM_DEF(4373, "brcmfmac4373-sdio"); +BRCMF_FW_CLM_DEF(43012, "brcmfmac43012-sdio"); /* firmware config files */ -MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-sdio.*.txt"); -MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcm/brcmfmac*-pcie.*.txt"); +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.txt"); +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.*.txt"); static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), @@ -1291,7 +1291,7 @@ static void brcmf_sdio_free_glom(struct brcmf_sdio *bus) } } -/** +/* * brcmfmac sdio bus specific header * This is the lowest layer header wrapped on the packets transmitted between * host and WiFi dongle which contains information needed for SDIO core and @@ -4162,7 +4162,6 @@ static int brcmf_sdio_bus_reset(struct device *dev) if (ret) { brcmf_err("Failed to probe after sdio device reset: ret %d\n", ret); - brcmf_sdiod_remove(sdiodev); } return ret; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c index 53365977bfd6..2084b506a450 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/aiutils.c @@ -531,9 +531,6 @@ void ai_detach(struct si_pub *sih) sii = container_of(sih, struct si_info, pub); - if (sii == NULL) - return; - kfree(sii); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 39f3af2d0439..eadac0f5590f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1220,6 +1220,7 @@ static int brcms_bcma_probe(struct bcma_device *pdev) { struct brcms_info *wl; struct ieee80211_hw *hw; + int ret; dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n", pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class, @@ -1244,11 +1245,16 @@ static int brcms_bcma_probe(struct bcma_device *pdev) wl = brcms_attach(pdev); if (!wl) { pr_err("%s: brcms_attach failed!\n", __func__); - return -ENODEV; + ret = -ENODEV; + goto err_free_ieee80211; } brcms_led_register(wl); return 0; + +err_free_ieee80211: + ieee80211_free_hw(hw); + return ret; } static int brcms_suspend(struct bcma_device *pdev) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 763e0ec583d7..26de1bd7fee9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -6607,7 +6607,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); - memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN); + memcpy(&rts->ra, &h->addr1, ETH_ALEN); + memcpy(&rts->ta, &h->addr2, ETH_ALEN); } /* mainrate diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h index aa4ab53bf634..af86c7fc5112 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/stf.h @@ -29,7 +29,6 @@ void brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band); void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force); bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val); -void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc); u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec); u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec); diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 23fbddd0c1f8..47eb89b773cf 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -5356,7 +5356,7 @@ struct ipw2100_wep_key { #define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10] /** - * Set a the wep key + * ipw2100_set_key() - Set a the wep key * * @priv: struct to work on * @idx: index of the key we want to set diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 14b0db28143b..d86918d162aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -16,9 +16,10 @@ iwlwifi-objs += iwl-trans.o iwlwifi-objs += queue/tx.o iwlwifi-objs += fw/img.o fw/notif-wait.o -iwlwifi-objs += fw/dbg.o fw/pnvm.o +iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o +iwlwifi-$(CONFIG_EFI) += fw/uefi.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index c2315dea9a23..7f1faa9d97b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -9,7 +9,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 63 +#define IWL_22000_UCODE_API_MAX 64 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -47,6 +47,7 @@ #define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" #define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" #define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-" +#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-" #define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-" #define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-" #define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-" @@ -93,6 +94,8 @@ IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode" #define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \ IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode" #define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ @@ -389,6 +392,7 @@ const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; +const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; const char iwl_ax200_killer_1650w_name[] = @@ -724,6 +728,13 @@ const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { + .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, .uhb_supported = true, @@ -797,6 +808,7 @@ MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index df1297358379..871533beff30 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -171,8 +171,12 @@ const char iwl9260_killer_1550_name[] = "Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz"; const char iwl9560_killer_1550i_name[] = "Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)"; +const char iwl9560_killer_1550i_160_name[] = + "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz"; const char iwl9560_killer_1550s_name[] = "Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)"; +const char iwl9560_killer_1550s_160_name[] = + "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz"; const struct iwl_cfg iwl9260_2ac_cfg = { .fw_name_pre = IWL9260_FW_PRE, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e31bba836c6f..34933f133a0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -163,6 +163,27 @@ int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, } IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); +/* + * Evaluate a DSM with no arguments and a u32 return value, + */ +int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value) +{ + int ret; + u64 val; + + ret = iwl_acpi_get_dsm_integer(dev, rev, func, + guid, &val, sizeof(u32)); + + if (ret < 0) + return ret; + + /* cast val (u64) to be u32 */ + *value = (u32)val; + return 0; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); + union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, int *tbl_rev) @@ -696,68 +717,37 @@ int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_sar_geo_init); -static u32 iwl_acpi_eval_dsm_func(struct device *dev, enum iwl_dsm_funcs_rev_0 eval_func) -{ - union acpi_object *obj; - u32 ret; - - obj = iwl_acpi_get_dsm_object(dev, 0, - eval_func, NULL, - &iwl_guid); - - if (IS_ERR(obj)) { - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM func '%d': Got Error in obj = %ld\n", - eval_func, - PTR_ERR(obj)); - return 0; - } - - if (obj->type != ACPI_TYPE_INTEGER) { - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM func '%d' did not return a valid object, type=%d\n", - eval_func, - obj->type); - ret = 0; - goto out; - } - - ret = obj->integer.value; - IWL_DEBUG_DEV_RADIO(dev, - "ACPI: DSM method evaluated: func='%d', ret=%d\n", - eval_func, - ret); -out: - ACPI_FREE(obj); - return ret; -} - __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) { - u32 ret; + int ret; + u8 value; __le32 config_bitmap = 0; /* ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' */ - ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_ENABLE_INDONESIA_5G2); + ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, + DSM_FUNC_ENABLE_INDONESIA_5G2, + &iwl_guid, &value); - if (ret == DSM_VALUE_INDONESIA_ENABLE) + if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) config_bitmap |= cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); /* ** Evaluate func 'DSM_FUNC_DISABLE_SRD' */ - ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_DISABLE_SRD); - - if (ret == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - - else if (ret == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, + DSM_FUNC_DISABLE_SRD, + &iwl_guid, &value); + if (!ret) { + if (value == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (value == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } return config_bitmap; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index d16e6ec08c9f..b858e998999c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -78,6 +78,7 @@ enum iwl_dsm_funcs_rev_0 { DSM_FUNC_DISABLE_SRD = 1, DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, DSM_FUNC_11AX_ENABLEMENT = 6, + DSM_FUNC_ENABLE_UNII4_CHAN = 7 }; enum iwl_dsm_values_srd { @@ -116,6 +117,9 @@ void *iwl_acpi_get_object(struct device *dev, acpi_string method); int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, const guid_t *guid, u8 *value); +int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value); + union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, int *tbl_rev); @@ -182,6 +186,12 @@ static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, return -ENOENT; } +static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, + const guid_t *guid, u32 *value) +{ + return -ENOENT; +} + static inline union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index c625d319142e..ce060c3dfd7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -535,11 +535,6 @@ enum iwl_legacy_cmds { OFFLOADS_QUERY_CMD = 0xd5, /** - * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config - */ - REMOTE_WAKE_CONFIG_CMD = 0xd6, - - /** * @D0I3_END_CMD: End D0i3/D3 state, no command data */ D0I3_END_CMD = 0xed, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 758639084e0c..b2e7ef3ddc88 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -159,6 +159,22 @@ struct iwl_proto_offload_cmd_v3_large { struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L]; } __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_3 */ +/** + * struct iwl_proto_offload_cmd_v4 - ARP/NS offload configuration + * @sta_id: station id + * @common: common/IPv4 configuration + * @num_valid_ipv6_addrs: number of valid IPv6 addresses + * @targ_addrs: target IPv6 addresses + * @ns_config: NS offload configurations + */ +struct iwl_proto_offload_cmd_v4 { + __le32 sta_id; + struct iwl_proto_offload_cmd_common common; + __le32 num_valid_ipv6_addrs; + struct iwl_targ_addr targ_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L]; + struct iwl_ns_config ns_config[IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L]; +} __packed; /* PROT_OFFLOAD_CONFIG_CMD_DB_S_VER_4 */ + /* * WOWLAN_PATTERNS */ @@ -302,13 +318,23 @@ struct iwl_wowlan_patterns_cmd { /** * @n_patterns: number of patterns */ - __le32 n_patterns; + u8 n_patterns; + + /** + * @n_patterns: sta_id + */ + u8 sta_id; + + /** + * @reserved: reserved for alignment + */ + __le16 reserved; /** * @patterns: the patterns, array length in @n_patterns */ struct iwl_wowlan_pattern_v2 patterns[]; -} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_2 */ +} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_3 */ enum iwl_wowlan_wakeup_filters { IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0), @@ -339,9 +365,10 @@ enum iwl_wowlan_flags { }; /** - * struct iwl_wowlan_config_cmd - WoWLAN configuration + * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6) * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters - * @non_qos_seq: non-QoS sequence counter to use next + * @non_qos_seq: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 6. * @qos_seq: QoS sequence counters to use next * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down * @is_11n_connection: indicates HT connection @@ -456,6 +483,23 @@ struct iwl_wowlan_kek_kck_material_cmd_v3 { __le32 bigtk_cipher; } __packed; /* KEK_KCK_MATERIAL_API_S_VER_3 */ +struct iwl_wowlan_kek_kck_material_cmd_v4 { + __le32 sta_id; + u8 kck[IWL_KCK_MAX_SIZE]; + u8 kek[IWL_KEK_MAX_SIZE]; + __le16 kck_len; + __le16 kek_len; + __le64 replay_ctr; + __le32 akm; + __le32 gtk_cipher; + __le32 igtk_cipher; + __le32 bigtk_cipher; +} __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */ + +struct iwl_wowlan_get_status_cmd { + __le32 sta_id; +} __packed; /* WOWLAN_GET_STATUSES_CMD_API_S_VER_1 */ + #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 enum iwl_wowlan_rekey_status { @@ -604,12 +648,13 @@ struct iwl_wowlan_status_v7 { } __packed; /* WOWLAN_STATUSES_API_S_VER_7 */ /** - * struct iwl_wowlan_status_v9 - WoWLAN status (version 9) + * struct iwl_wowlan_status_v9 - WoWLAN status (versions 9 and 10) * @gtk: GTK data * @igtk: IGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next + * @non_qos_seq_ctr: non-QoS sequence counter to use next. + * Reserved if the struct has version >= 10. * @qos_seq_ctr: QoS sequence counters to use next * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys @@ -638,7 +683,7 @@ struct iwl_wowlan_status_v9 { u8 tid_tear_down; u8 reserved[3]; u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_API_S_VER_9 */ +} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */ /** * struct iwl_wowlan_status - WoWLAN status @@ -683,55 +728,6 @@ static inline u8 iwlmvm_wowlan_gtk_idx(struct iwl_wowlan_gtk_status *gtk) return gtk->key_flags & IWL_WOWLAN_GTK_IDX_MASK; } -#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64 -#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128 -#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048 - -struct iwl_tcp_packet_info { - __le16 tcp_pseudo_header_checksum; - __le16 tcp_payload_length; -} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */ - -struct iwl_tcp_packet { - struct iwl_tcp_packet_info info; - u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; - u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN]; -} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ - -struct iwl_remote_wake_packet { - struct iwl_tcp_packet_info info; - u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8]; - u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN]; -} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */ - -struct iwl_wowlan_remote_wake_config { - __le32 connection_max_time; /* unused */ - /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */ - u8 max_syn_retries; - u8 max_data_retries; - u8 tcp_syn_ack_timeout; - u8 tcp_ack_timeout; - - struct iwl_tcp_packet syn_tx; - struct iwl_tcp_packet synack_rx; - struct iwl_tcp_packet keepalive_ack_rx; - struct iwl_tcp_packet fin_tx; - - struct iwl_remote_wake_packet keepalive_tx; - struct iwl_remote_wake_packet wake_rx; - - /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */ - u8 sequence_number_offset; - u8 sequence_number_length; - u8 token_offset; - u8 token_length; - /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */ - __le32 initial_sequence_number; - __le16 keepalive_interval; - __le16 num_tokens; - u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS]; -} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */ - /* TODO: NetDetect API */ #endif /* __iwl_fw_api_d3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index d299bba3aa54..985b0dc5b52a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -64,6 +64,12 @@ enum iwl_data_path_subcmd_ids { RX_NO_DATA_NOTIF = 0xF5, /** + * @THERMAL_DUAL_CHAIN_DISABLE_REQ: firmware request for SMPS mode, + * &struct iwl_thermal_dual_chain_request + */ + THERMAL_DUAL_CHAIN_REQUEST = 0xF6, + + /** * @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif */ TLC_MNG_UPDATE_NOTIF = 0xF7, @@ -169,4 +175,24 @@ struct iwl_datapath_monitor_notif { u8 reserved[3]; } __packed; /* MONITOR_NTF_API_S_VER_1 */ +/** + * enum iwl_thermal_dual_chain_req_events - firmware SMPS request event + * @THERMAL_DUAL_CHAIN_REQ_ENABLE: (re-)enable dual-chain operation + * (subject to other constraints) + * @THERMAL_DUAL_CHAIN_REQ_DISABLE: disable dual-chain operation + * (static SMPS) + */ +enum iwl_thermal_dual_chain_req_events { + THERMAL_DUAL_CHAIN_REQ_ENABLE, + THERMAL_DUAL_CHAIN_REQ_DISABLE, +}; /* THERMAL_DUAL_CHAIN_DISABLE_STATE_API_E_VER_1 */ + +/** + * struct iwl_thermal_dual_chain_request - SMPS request + * @event: the type of request, see &enum iwl_thermal_dual_chain_req_events + */ +struct iwl_thermal_dual_chain_request { + __le32 event; +} __packed; /* THERMAL_DUAL_CHAIN_DISABLE_REQ_NTFY_API_S_VER_1 */ + #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 996d5cc5bd9a..5a2d9a1f7e73 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #ifndef __iwl_fw_dbg_tlv_h__ #define __iwl_fw_dbg_tlv_h__ @@ -11,6 +11,7 @@ #define IWL_FW_INI_MAX_NAME 32 #define IWL_FW_INI_MAX_CFG_NAME 64 #define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 +#define IWL_FW_INI_REGION_V2_MASK 0x0000FFFF /** * struct iwl_fw_ini_hcmd diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index dc8f2777e944..cf48c6fa8f65 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -453,6 +453,25 @@ struct iwl_lari_config_change_cmd_v3 { } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_3 */ /** + * struct iwl_lari_config_change_cmd_v4 - change LARI configuration + * @config_bitmap: Bitmap of the config commands. Each bit will trigger a + * different predefined FW config operation. + * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. + * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits + * per country, one to indicate whether to override and the other to + * indicate the value to use. + * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits + * per country, one to indicate whether to override and the other to + * indicate allow/disallow unii4 channels. + */ +struct iwl_lari_config_change_cmd_v4 { + __le32 config_bitmap; + __le32 oem_uhb_allow_bitmap; + __le32 oem_11ax_allow_bitmap; + __le32 oem_unii4_allow_bitmap; +} __packed; /* LARI_CHANGE_CONF_CMD_S_VER_4 */ + +/** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete * @status: PNVM image loading status */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index cc4e18ca9566..df7c55e06f54 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1933,6 +1933,13 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, u32 num_of_ranges, i, size; void *range; + /* + * The higher part of the ID in version 2 is irrelevant for + * us, so mask it out. + */ + if (le32_to_cpu(reg->hdr.version) == 2) + id &= IWL_FW_INI_REGION_V2_MASK; + if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || !ops->fill_range) return 0; @@ -1957,7 +1964,7 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data); header = (void *)tlv->data; - header->region_id = reg->id; + header->region_id = cpu_to_le32(id); header->num_of_ranges = cpu_to_le32(num_of_ranges); header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME); memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME); @@ -2752,44 +2759,6 @@ void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt) } IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync); -#define FSEQ_REG(x) { .addr = (x), .str = #x, } - -void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt) -{ - struct iwl_trans *trans = fwrt->trans; - int i; - struct { - u32 addr; - const char *str; - } fseq_regs[] = { - FSEQ_REG(FSEQ_ERROR_CODE), - FSEQ_REG(FSEQ_TOP_INIT_VERSION), - FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), - FSEQ_REG(FSEQ_OTP_VERSION), - FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), - FSEQ_REG(FSEQ_ALIVE_TOKEN), - FSEQ_REG(FSEQ_CNVI_ID), - FSEQ_REG(FSEQ_CNVR_ID), - FSEQ_REG(CNVI_AUX_MISC_CHIP), - FSEQ_REG(CNVR_AUX_MISC_CHIP), - FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), - FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), - }; - - if (!iwl_trans_grab_nic_access(trans)) - return; - - IWL_ERR(fwrt, "Fseq Registers:\n"); - - for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) - IWL_ERR(fwrt, "0x%08X | %s\n", - iwl_read_prph_no_grab(trans, fseq_regs[i].addr), - fseq_regs[i].str); - - iwl_trans_release_nic_access(trans); -} -IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs); - static int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend) { struct iwl_dbg_suspend_resume_cmd cmd = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 49fa2f5f8c7e..c0e84ef84f5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2019 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -321,4 +321,6 @@ static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt, fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor); } } + +void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c new file mode 100644 index 000000000000..a1842205e86a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015-2017 Intel Deutschland GmbH + */ +#include <linux/devcoredump.h> +#include "iwl-drv.h" +#include "runtime.h" +#include "dbg.h" +#include "debugfs.h" +#include "iwl-io.h" +#include "iwl-prph.h" +#include "iwl-csr.h" + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table_v1 { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: + * rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: + * host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: + * enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: + * time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: + * wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on + * (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the + * compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */; + +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 trm_hw_status0; /* TRM HW status */ + u32 trm_hw_status1; /* TRM HW status */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 fw_rev_type; /* firmware revision type */ + u32 major; /* uCode version major */ + u32 minor; /* uCode version minor */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: + * rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: + * host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: + * enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: + * time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: + * wico interrupt */ + u32 last_cmd_id; /* last HCMD id handled by the firmware */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on + * (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the + * compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; + +/* + * UMAC error struct - relevant starting from family 8000 chip. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_umac_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 data3; /* error-specific data */ + u32 umac_major; + u32 umac_minor; + u32 frame_pointer; /* core register 27*/ + u32 stack_pointer; /* core register 28 */ + u32 cmd_header; /* latest host cmd sent to UMAC */ + u32 nic_isr_pref; /* ISR status register */ +} __packed; + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_umac_error_event_table table = {}; + u32 base = fwrt->trans->dbg.umac_error_event_table; + + if (!base && + !(fwrt->trans->dbg.error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_UMAC)) + return; + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (table.valid) + fwrt->dump.umac_err_id = table.error_id; + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", + fwrt->trans->status, table.valid); + } + + IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, + iwl_fw_lookup_assert_desc(table.error_id)); + IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1); + IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major); + IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor); + IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer); + IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer); + IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header); + IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref); +} + +static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_error_event_table table = {}; + u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num]; + + if (fwrt->cur_fw_img == IWL_UCODE_INIT) { + if (!base) + base = fwrt->fw->init_errlog_ptr; + } else { + if (!base) + base = fwrt->fw->inst_errlog_ptr; + } + + if (base < 0x400000) { + IWL_ERR(fwrt, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (fwrt->cur_fw_img == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + /* check if there is a HW error */ + val = iwl_trans_read_mem32(trans, base); + if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { + int err; + + IWL_ERR(trans, "HW error, resetting before reading\n"); + + /* reset the device */ + iwl_trans_sw_reset(trans); + + err = iwl_finish_nic_init(trans, trans->trans_cfg); + if (err) + return; + } + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (table.valid) + fwrt->dump.lmac_err_id[lmac_num] = table.error_id; + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", + fwrt->trans->status, table.valid); + } + + /* Do not change this output - scripts rely on it */ + + IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version); + + IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, + iwl_fw_lookup_assert_desc(table.error_id)); + IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); + IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); + IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time); + IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low); + IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi); + IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1); + IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2); + IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type); + IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major); + IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor); + IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver); + IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver); + IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd); + IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0); + IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1); + IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2); + IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3); + IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4); + IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id); + IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event); + IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control); + IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration); + IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); + IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); + IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); + IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp); + IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler); +} + +/* + * TCM error struct. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_tcm_error_event_table { + u32 valid; + u32 error_id; + u32 blink2; + u32 ilink1; + u32 ilink2; + u32 data1, data2, data3; + u32 logpc; + u32 frame_pointer; + u32 stack_pointer; + u32 msgid; + u32 isr; + u32 hw_status[5]; + u32 sw_status[1]; + u32 reserved[4]; +} __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */ + +static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + struct iwl_tcm_error_event_table table = {}; + u32 base = fwrt->trans->dbg.tcm_error_event_table; + int i; + + if (!base || + !(fwrt->trans->dbg.error_event_table_tlv_status & + IWL_ERROR_EVENT_TABLE_TCM)) + return; + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + IWL_ERR(fwrt, "TCM status:\n"); + IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); + IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2); + IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1); + IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); + IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); + IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); + IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3); + IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc); + IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer); + IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer); + IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid); + IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr); + for (i = 0; i < ARRAY_SIZE(table.hw_status); i++) + IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n", + table.hw_status[i], i); + for (i = 0; i < ARRAY_SIZE(table.sw_status); i++) + IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n", + table.sw_status[i], i); +} + +static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + u32 error, data1; + + if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { + error = UMAG_SB_CPU_2_STATUS; + data1 = UMAG_SB_CPU_1_STATUS; + } else if (fwrt->trans->trans_cfg->device_family >= + IWL_DEVICE_FAMILY_8000) { + error = SB_CPU_2_STATUS; + data1 = SB_CPU_1_STATUS; + } else { + return; + } + + error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); + + IWL_ERR(trans, "IML/ROM dump:\n"); + + if (error & 0xFFFF0000) + IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); + + IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error); + IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n", + iwl_read_umac_prph(trans, data1)); + + if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) + IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", + iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); +} + +#define FSEQ_REG(x) { .addr = (x), .str = #x, } + +static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_trans *trans = fwrt->trans; + int i; + struct { + u32 addr; + const char *str; + } fseq_regs[] = { + FSEQ_REG(FSEQ_ERROR_CODE), + FSEQ_REG(FSEQ_TOP_INIT_VERSION), + FSEQ_REG(FSEQ_CNVIO_INIT_VERSION), + FSEQ_REG(FSEQ_OTP_VERSION), + FSEQ_REG(FSEQ_TOP_CONTENT_VERSION), + FSEQ_REG(FSEQ_ALIVE_TOKEN), + FSEQ_REG(FSEQ_CNVI_ID), + FSEQ_REG(FSEQ_CNVR_ID), + FSEQ_REG(CNVI_AUX_MISC_CHIP), + FSEQ_REG(CNVR_AUX_MISC_CHIP), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), + FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), + }; + + if (!iwl_trans_grab_nic_access(trans)) + return; + + IWL_ERR(fwrt, "Fseq Registers:\n"); + + for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) + IWL_ERR(fwrt, "0x%08X | %s\n", + iwl_read_prph_no_grab(trans, fseq_regs[i].addr), + fseq_regs[i].str); + + iwl_trans_release_nic_access(trans); +} + +void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) +{ + if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) { + IWL_ERR(fwrt, + "DEVICE_ENABLED bit is not set. Aborting dump.\n"); + return; + } + + iwl_fwrt_dump_lmac_error_log(fwrt, 0); + if (fwrt->trans->dbg.lmac_error_event_table[1]) + iwl_fwrt_dump_lmac_error_log(fwrt, 1); + iwl_fwrt_dump_umac_error_log(fwrt); + iwl_fwrt_dump_tcm_error_log(fwrt); + iwl_fwrt_dump_iml_error_log(fwrt); + iwl_fwrt_dump_fseq_regs(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index f9c5cf538ad1..9a8c7b7a0816 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2008-2014, 2018-2020 Intel Corporation + * Copyright (C) 2008-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -52,7 +52,8 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_INIT_DATA = 4, IWL_UCODE_TLV_BOOT = 5, IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ - IWL_UCODE_TLV_PAN = 7, + IWL_UCODE_TLV_PAN = 7, /* deprecated -- only used in DVM */ + IWL_UCODE_TLV_MEM_DESC = 7, /* replaces PAN in non-DVM */ IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8, IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9, IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10, @@ -97,6 +98,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_PNVM_VERSION = 62, IWL_UCODE_TLV_PNVM_SKU = 64, + IWL_UCODE_TLV_TCM_DEBUG_ADDRS = 65, IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0, @@ -277,10 +279,11 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, - NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 + /* sparse says it cannot increment the previous enum member */ +#define NUM_IWL_UCODE_TLV_API 128 +#else + NUM_IWL_UCODE_TLV_API #endif }; @@ -411,6 +414,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PROTECTED_TWT = (__force iwl_ucode_tlv_capa_t)56, IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE = (__force iwl_ucode_tlv_capa_t)57, IWL_UCODE_TLV_CAPA_PASSIVE_6GHZ_SCAN = (__force iwl_ucode_tlv_capa_t)58, + IWL_UCODE_TLV_CAPA_BROADCAST_TWT = (__force iwl_ucode_tlv_capa_t)60, /* set 2 */ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, @@ -446,10 +450,11 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100, IWL_UCODE_TLV_CAPA_RFIM_SUPPORT = (__force iwl_ucode_tlv_capa_t)102, - NUM_IWL_UCODE_TLV_CAPA #ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ - = 128 + /* sparse says it cannot increment the previous enum member */ +#define NUM_IWL_UCODE_TLV_CAPA 128 +#else + NUM_IWL_UCODE_TLV_CAPA #endif }; @@ -946,6 +951,10 @@ struct iwl_fw_cmd_version { u8 notif_ver; } __packed; +struct iwl_fw_tcm_error_addr { + __le32 addr; +}; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */ + static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv, size_t fixed_size, size_t var_size) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 40f2109a097f..2403490cbc26 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -10,7 +10,7 @@ #include "fw/api/commands.h" #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" -#include <linux/efi.h> +#include "fw/uefi.h" struct iwl_pnvm_section { __le32 offset; @@ -220,83 +220,6 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, return -ENOENT; } -#if defined(CONFIG_EFI) - -#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ - 0xb2, 0xec, 0xf5, 0xa3, \ - 0x59, 0x4f, 0x4a, 0xea) - -#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" - -#define IWL_HARDCODED_PNVM_SIZE 4096 - -struct pnvm_sku_package { - u8 rev; - u8 reserved1[3]; - u32 total_size; - u8 n_skus; - u8 reserved2[11]; - u8 data[]; -}; - -static int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - struct efivar_entry *pnvm_efivar; - struct pnvm_sku_package *package; - unsigned long package_size; - int err; - - pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); - if (!pnvm_efivar) - return -ENOMEM; - - memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME, - sizeof(IWL_UEFI_OEM_PNVM_NAME)); - pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; - - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_PNVM_SIZE; - - package = kmalloc(package_size, GFP_KERNEL); - if (!package) { - err = -ENOMEM; - goto out; - } - - err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package); - if (err) { - IWL_DEBUG_FW(trans, - "PNVM UEFI variable not found %d (len %lu)\n", - err, package_size); - goto out; - } - - IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size); - - *data = kmemdup(package->data, *len, GFP_KERNEL); - if (!*data) - err = -ENOMEM; - *len = package_size - sizeof(*package); - -out: - kfree(package); - kfree(pnvm_efivar); - - return err; -} -#else /* CONFIG_EFI */ -static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - return -EOPNOTSUPP; -} -#endif /* CONFIG_EFI */ - static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) { const struct firmware *pnvm; @@ -335,6 +258,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, { u8 *data; size_t len; + struct pnvm_sku_package *package; struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, PNVM_INIT_COMPLETE_NTFY) }; @@ -356,9 +280,19 @@ int iwl_pnvm_load(struct iwl_trans *trans, } /* First attempt to get the PNVM from BIOS */ - ret = iwl_pnvm_get_from_efi(trans, &data, &len); - if (!ret) - goto parse; + package = iwl_uefi_get_pnvm(trans, &len); + if (!IS_ERR_OR_NULL(package)) { + data = kmemdup(package->data, len, GFP_KERNEL); + + /* free package regardless of whether kmemdup succeeded */ + kfree(package); + + if (data) { + /* we need only the data size */ + len -= sizeof(*package); + goto parse; + } + } /* If it's not available, try from the filesystem */ ret = iwl_pnvm_get_from_fs(trans, &data, &len); @@ -379,6 +313,30 @@ parse: kfree(data); skip_parse: + data = NULL; + /* now try to get the reduce power table, if not loaded yet */ + if (!trans->reduce_power_loaded) { + data = iwl_uefi_get_reduced_power(trans, &len); + if (IS_ERR_OR_NULL(data)) { + /* + * Pretend we've loaded it - at least we've tried and + * couldn't load it at all, so there's no point in + * trying again over and over. + */ + trans->reduce_power_loaded = true; + + goto skip_reduce_power; + } + } + + ret = iwl_trans_set_reduce_power(trans, data, len); + if (ret) + IWL_DEBUG_FW(trans, + "Failed to set reduce power table %d\n", + ret); + kfree(data); + +skip_reduce_power: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index e4f91bce222d..61d3d4e0b7d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /****************************************************************************** * - * Copyright(c) 2020 Intel Corporation + * Copyright(c) 2020-2021 Intel Corporation * *****************************************************************************/ @@ -10,7 +10,7 @@ #include "fw/notif-wait.h" -#define MVM_UCODE_PNVM_TIMEOUT (HZ / 10) +#define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c new file mode 100644 index 000000000000..a7c79d814aa4 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright(c) 2021 Intel Corporation + */ + +#include "iwl-drv.h" +#include "pnvm.h" +#include "iwl-prph.h" +#include "iwl-io.h" + +#include "fw/uefi.h" +#include "fw/api/alive.h" +#include <linux/efi.h> + +#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ + 0xb2, 0xec, 0xf5, 0xa3, \ + 0x59, 0x4f, 0x4a, 0xea) + +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + struct efivar_entry *pnvm_efivar; + void *data; + unsigned long package_size; + int err; + + *len = 0; + + pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); + if (!pnvm_efivar) + return ERR_PTR(-ENOMEM); + + memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME, + sizeof(IWL_UEFI_OEM_PNVM_NAME)); + pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* + * TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_PNVM_SIZE; + + data = kmalloc(package_size, GFP_KERNEL); + if (!data) { + data = ERR_PTR(-ENOMEM); + goto out; + } + + err = efivar_entry_get(pnvm_efivar, NULL, &package_size, data); + if (err) { + IWL_DEBUG_FW(trans, + "PNVM UEFI variable not found %d (len %zd)\n", + err, package_size); + kfree(data); + data = ERR_PTR(err); + goto out; + } + + IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %zd\n", package_size); + *len = package_size; + +out: + kfree(pnvm_efivar); + + return data; +} + +static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, + const u8 *data, size_t len) +{ + struct iwl_ucode_tlv *tlv; + u8 *reduce_power_data = NULL, *tmp; + u32 size = 0; + + IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n"); + + while (len >= sizeof(*tlv)) { + u32 tlv_len, tlv_type; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) { + IWL_ERR(trans, "invalid TLV len: %zd/%u\n", + len, tlv_len); + reduce_power_data = ERR_PTR(-EINVAL); + goto out; + } + + data += sizeof(*tlv); + + switch (tlv_type) { + case IWL_UCODE_TLV_MEM_DESC: { + IWL_DEBUG_FW(trans, + "Got IWL_UCODE_TLV_MEM_DESC len %d\n", + tlv_len); + + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); + + tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL); + if (!tmp) { + IWL_DEBUG_FW(trans, + "Couldn't allocate (more) reduce_power_data\n"); + + reduce_power_data = ERR_PTR(-ENOMEM); + goto out; + } + + reduce_power_data = tmp; + + memcpy(reduce_power_data + size, data, tlv_len); + + size += tlv_len; + + break; + } + case IWL_UCODE_TLV_PNVM_SKU: + IWL_DEBUG_FW(trans, + "New REDUCE_POWER section started, stop parsing.\n"); + goto done; + default: + IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", + tlv_type, tlv_len); + break; + } + + len -= ALIGN(tlv_len, 4); + data += ALIGN(tlv_len, 4); + } + +done: + if (!size) { + IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); + reduce_power_data = ERR_PTR(-ENOENT); + goto out; + } + + IWL_INFO(trans, "loaded REDUCE_POWER\n"); + +out: + return reduce_power_data; +} + +static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len) +{ + struct iwl_ucode_tlv *tlv; + void *sec_data; + + IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); + + while (len >= sizeof(*tlv)) { + u32 tlv_len, tlv_type; + + len -= sizeof(*tlv); + tlv = (void *)data; + + tlv_len = le32_to_cpu(tlv->length); + tlv_type = le32_to_cpu(tlv->type); + + if (len < tlv_len) { + IWL_ERR(trans, "invalid TLV len: %zd/%u\n", + len, tlv_len); + return ERR_PTR(-EINVAL); + } + + if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { + struct iwl_sku_id *sku_id = + (void *)(data + sizeof(*tlv)); + + IWL_DEBUG_FW(trans, + "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", + tlv_len); + IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", + le32_to_cpu(sku_id->data[0]), + le32_to_cpu(sku_id->data[1]), + le32_to_cpu(sku_id->data[2])); + + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + len -= ALIGN(tlv_len, 4); + + if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && + trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && + trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { + sec_data = iwl_uefi_reduce_power_section(trans, + data, + len); + if (!IS_ERR(sec_data)) + return sec_data; + } else { + IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); + } + } else { + data += sizeof(*tlv) + ALIGN(tlv_len, 4); + len -= ALIGN(tlv_len, 4); + } + } + + return ERR_PTR(-ENOENT); +} + +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +{ + struct efivar_entry *reduce_power_efivar; + struct pnvm_sku_package *package; + void *data = NULL; + unsigned long package_size; + int err; + + *len = 0; + + reduce_power_efivar = kzalloc(sizeof(*reduce_power_efivar), GFP_KERNEL); + if (!reduce_power_efivar) + return ERR_PTR(-ENOMEM); + + memcpy(&reduce_power_efivar->var.VariableName, IWL_UEFI_REDUCED_POWER_NAME, + sizeof(IWL_UEFI_REDUCED_POWER_NAME)); + reduce_power_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; + + /* + * TODO: we hardcode a maximum length here, because reading + * from the UEFI is not working. To implement this properly, + * we have to call efivar_entry_size(). + */ + package_size = IWL_HARDCODED_REDUCE_POWER_SIZE; + + package = kmalloc(package_size, GFP_KERNEL); + if (!package) { + package = ERR_PTR(-ENOMEM); + goto out; + } + + err = efivar_entry_get(reduce_power_efivar, NULL, &package_size, package); + if (err) { + IWL_DEBUG_FW(trans, + "Reduced Power UEFI variable not found %d (len %lu)\n", + err, package_size); + kfree(package); + data = ERR_PTR(err); + goto out; + } + + IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", + package_size); + *len = package_size; + + IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", + package->rev, package->total_size, package->n_skus); + + data = iwl_uefi_reduce_power_parse(trans, package->data, + *len - sizeof(*package)); + + kfree(package); + +out: + kfree(reduce_power_efivar); + + return data; +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h new file mode 100644 index 000000000000..45d0b36d79b5 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright(c) 2021 Intel Corporation + */ + + +#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" +#define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" + +/* + * TODO: we have these hardcoded values that the caller must pass, + * because reading from the UEFI is not working. To implement this + * properly, we have to change iwl_pnvm_get_from_uefi() to call + * efivar_entry_size() and return the value to the caller instead. + */ +#define IWL_HARDCODED_PNVM_SIZE 4096 +#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 + +struct pnvm_sku_package { + u8 rev; + u32 total_size; + u8 n_skus; + u32 reserved[2]; + u8 data[]; +} __packed; + +#ifdef CONFIG_EFI +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +#else /* CONFIG_EFI */ +static inline +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline +void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +{ + return ERR_PTR(-EOPNOTSUPP); +} +#endif /* CONFIG_EFI */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index b35ffdfdf14b..bf6ee56d4d96 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -426,6 +426,7 @@ struct iwl_cfg { #define IWL_CFG_RF_TYPE_HR1 0x10C #define IWL_CFG_RF_TYPE_GF 0x10D #define IWL_CFG_RF_TYPE_MR 0x110 +#define IWL_CFG_RF_TYPE_FM 0x112 #define IWL_CFG_RF_ID_TH 0x1 #define IWL_CFG_RF_ID_TH1 0x1 @@ -505,8 +506,11 @@ extern const char iwl_ax201_killer_1650s_name[]; extern const char iwl_ax201_killer_1650i_name[]; extern const char iwl_ax210_killer_1675w_name[]; extern const char iwl_ax210_killer_1675x_name[]; +extern const char iwl9560_killer_1550i_160_name[]; +extern const char iwl9560_killer_1550s_160_name[]; extern const char iwl_ax211_name[]; extern const char iwl_ax221_name[]; +extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; @@ -586,7 +590,6 @@ extern const struct iwl_cfg iwl_qu_b0_hr_b0; extern const struct iwl_cfg iwl_qu_c0_hr_b0; extern const struct iwl_cfg iwl_ax200_cfg_cc; extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; -extern const struct iwl_cfg iwl_ax201_cfg_qu_hr; extern const struct iwl_cfg iwl_ax201_cfg_qu_c0_hr_b0; extern const struct iwl_cfg iwl_ax201_cfg_quz_hr; extern const struct iwl_cfg iwl_ax1650i_cfg_quz_hr; @@ -613,6 +616,7 @@ extern const struct iwl_cfg iwl_cfg_ma_a0_hr_b0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf_a0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0; extern const struct iwl_cfg iwl_cfg_ma_a0_mr_a0; +extern const struct iwl_cfg iwl_cfg_ma_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_snj_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 2be605cc6fbf..e1fec23ac07f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018, 2020 Intel Corporation + * Copyright (C) 2018, 2020-2021 Intel Corporation */ #ifndef __iwl_context_info_file_gen3_h__ #define __iwl_context_info_file_gen3_h__ @@ -128,6 +128,17 @@ struct iwl_prph_scratch_rbd_cfg { } __packed; /* PERIPH_SCRATCH_RBD_CFG_S */ /* + * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table + * @base_addr: reduce power table address + * @size: table size in dwords + */ +struct iwl_prph_scratch_uefi_cfg { + __le64 base_addr; + __le32 size; + __le32 reserved; +} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */ + +/* * struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config * @version: version information of context info and HW * @control: control flags of FH configurations @@ -141,6 +152,7 @@ struct iwl_prph_scratch_ctrl_cfg { struct iwl_prph_scratch_pnvm_cfg pnvm_cfg; struct iwl_prph_scratch_hwm_cfg hwm_cfg; struct iwl_prph_scratch_rbd_cfg rbd_cfg; + struct iwl_prph_scratch_uefi_cfg reduce_power_cfg; } __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */ /* @@ -151,7 +163,7 @@ struct iwl_prph_scratch_ctrl_cfg { */ struct iwl_prph_scratch { struct iwl_prph_scratch_ctrl_cfg ctrl_cfg; - __le32 reserved[16]; + __le32 reserved[12]; struct iwl_context_info_dram dram; } __packed; /* PERIPH_SCRATCH_S */ @@ -245,9 +257,11 @@ struct iwl_context_info_gen3 { int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, const struct fw_img *fw); -void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans); +void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const void *data, u32 len); +int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len); #endif /* __iwl_context_info_file_gen3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index db312abd2e09..47e5a17c0f48 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -325,9 +325,6 @@ enum { #define CSR_HW_RF_ID_TYPE_GF (0x0010D000) #define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000) -/* HW_RF CHIP ID */ -#define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF) - /* HW_RF CHIP STEP */ #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 4cd8c39cc3e9..0ddd255a8cc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -57,7 +57,7 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_BUF_ALLOC] = {.min_ver = 1, .max_ver = 1,}, [IWL_DBG_TLV_TYPE_HCMD] = {.min_ver = 1, .max_ver = 1,}, - [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 1,}, + [IWL_DBG_TLV_TYPE_REGION] = {.min_ver = 1, .max_ver = 2,}, [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, }; @@ -178,9 +178,20 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, u32 type = le32_to_cpu(reg->type); u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); + /* + * The higher part of the ID in version 2 is irrelevant for + * us, so mask it out. + */ + if (le32_to_cpu(reg->hdr.version) == 2) + id &= IWL_FW_INI_REGION_V2_MASK; + if (le32_to_cpu(tlv->length) < sizeof(*reg)) return -EINVAL; + /* for safe use of a string from FW, limit it to IWL_FW_INI_MAX_NAME */ + IWL_DEBUG_FW(trans, "WRT: parsing region: %.*s\n", + IWL_FW_INI_MAX_NAME, reg->name); + if (id >= IWL_FW_INI_MAX_REGION_ID) { IWL_ERR(trans, "WRT: Invalid region id %u\n", id); return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 884750bf7840..977dce686bdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1117,6 +1117,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_ERROR_EVENT_TABLE_LMAC1; break; } + case IWL_UCODE_TLV_TCM_DEBUG_ADDRS: { + struct iwl_fw_tcm_error_addr *ptr = (void *)tlv_data; + + if (tlv_len != sizeof(*ptr)) + goto invalid_tlv_len; + drv->trans->dbg.tcm_error_event_table = + le32_to_cpu(ptr->addr) & ~FW_ADDR_CACHE_CONTROL; + drv->trans->dbg.error_event_table_tlv_status |= + IWL_ERROR_EVENT_TABLE_TCM; + break; + } case IWL_UCODE_TLV_TYPE_DEBUG_INFO: case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION: case IWL_UCODE_TLV_TYPE_HCMD: diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index fc75d049046d..850648ebd61c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -549,8 +549,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL, .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, @@ -579,25 +578,20 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, - .phy_cap_info[5] = - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, .phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1, + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = - IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, @@ -632,19 +626,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { .mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, - .mac_cap_info[2] = - IEEE80211_HE_MAC_CAP2_BSR, .mac_cap_info[3] = - IEEE80211_HE_MAC_CAP3_OMI_CONTROL | - IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, - .mac_cap_info[4] = - IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, - .mac_cap_info[5] = - IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, + IEEE80211_HE_MAC_CAP3_OMI_CONTROL, .phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G, .phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, .phy_cap_info[2] = @@ -654,27 +640,14 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = { IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, - .phy_cap_info[4] = - IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, - .phy_cap_info[5] = - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, .phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, .phy_cap_info[7] = - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1, + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, }, /* @@ -745,12 +718,72 @@ static void iwl_init_he_6ghz_capa(struct iwl_trans *trans, iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa); } +static void +iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, + struct ieee80211_supported_band *sband, + struct ieee80211_sband_iftype_data *iftype_data, + u8 tx_chains, u8 rx_chains, + const struct iwl_fw *fw) +{ + bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); + + /* Advertise an A-MPDU exponent extension based on + * operating band + */ + if (sband->band != NL80211_BAND_2GHZ) + iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1; + else + iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; + + if (is_ap && iwlwifi_mod_params.nvm_file) + iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + if ((tx_chains & rx_chains) == ANT_AB) { + iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; + if (!is_ap) + iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_MAX_NC_2; + } else if (!is_ap) { + /* If not 2x2, we need to indicate 1x1 in the + * Midamble RX Max NSTS - but not for AP mode + */ + iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &= + ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; + iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= + ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; + iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_MAX_NC_1; + } + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case IWL_CFG_RF_TYPE_GF: + case IWL_CFG_RF_TYPE_MR: + iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + if (!is_ap) + iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + break; + } + + if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) + iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |= + IEEE80211_HE_MAC_CAP2_BCAST_TWT; +} + static void iwl_init_he_hw_capab(struct iwl_trans *trans, struct iwl_nvm_data *data, struct ieee80211_supported_band *sband, - u8 tx_chains, u8 rx_chains) + u8 tx_chains, u8 rx_chains, + const struct iwl_fw *fw) { struct ieee80211_sband_iftype_data *iftype_data; + int i; /* should only initialize once */ if (WARN_ON(sband->iftype_data)) @@ -777,26 +810,18 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, sband->iftype_data = iftype_data; sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa); - /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ - if ((tx_chains & rx_chains) != ANT_AB) { - int i; - - for (i = 0; i < sband->n_iftype_data; i++) { - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[1] &= - ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[2] &= - ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; - iftype_data[i].he_cap.he_cap_elem.phy_cap_info[7] &= - ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; - } - } + for (i = 0; i < sband->n_iftype_data; i++) + iwl_nvm_fixup_sband_iftd(trans, sband, &iftype_data[i], + tx_chains, rx_chains, fw); + iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); } static void iwl_init_sbands(struct iwl_trans *trans, struct iwl_nvm_data *data, const void *nvm_ch_flags, u8 tx_chains, - u8 rx_chains, u32 sbands_flags, bool v4) + u8 rx_chains, u32 sbands_flags, bool v4, + const struct iwl_fw *fw) { struct device *dev = trans->dev; const struct iwl_cfg *cfg = trans->cfg; @@ -816,7 +841,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, tx_chains, rx_chains); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); sband = &data->bands[NL80211_BAND_5GHZ]; sband->band = NL80211_BAND_5GHZ; @@ -831,7 +857,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, tx_chains, rx_chains); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); /* 6GHz band. */ sband = &data->bands[NL80211_BAND_6GHZ]; @@ -843,7 +870,8 @@ static void iwl_init_sbands(struct iwl_trans *trans, NL80211_BAND_6GHZ); if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) - iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); else sband->n_channels = 0; if (n_channels != n_used) @@ -1154,7 +1182,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ; iwl_init_sbands(trans, data, ch_section, tx_chains, rx_chains, - sbands_flags, false); + sbands_flags, false, fw); data->calib_version = 255; return data; @@ -1661,7 +1689,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, channel_profile, nvm->valid_tx_ant & fw->valid_tx_ant, nvm->valid_rx_ant & fw->valid_rx_ant, - sbands_flags, v4); + sbands_flags, v4, fw); iwl_free_resp(&hcmd); return nvm; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 3ce77e4eb7e3..9a9e714bf9af 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -412,6 +412,8 @@ enum { #define UREG_DOORBELL_TO_ISR6_RESUME BIT(19) #define UREG_DOORBELL_TO_ISR6_PNVM BIT(20) +#define CNVI_MBOX_C 0xA3400C + #define FSEQ_ERROR_CODE 0xA340C8 #define FSEQ_TOP_INIT_VERSION 0xA34038 #define FSEQ_CNVIO_INIT_VERSION 0xA3403C diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index bf569f856ad8..0199d7a5a648 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -193,6 +193,7 @@ enum iwl_error_event_table_status { IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0), IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1), IWL_ERROR_EVENT_TABLE_UMAC = BIT(2), + IWL_ERROR_EVENT_TABLE_TCM = BIT(3), }; /** @@ -589,6 +590,8 @@ struct iwl_trans_ops { void (*debugfs_cleanup)(struct iwl_trans *trans); void (*sync_nmi)(struct iwl_trans *trans); int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len); + int (*set_reduce_power)(struct iwl_trans *trans, + const void *data, u32 len); void (*interrupts)(struct iwl_trans *trans, bool enable); }; @@ -706,6 +709,7 @@ struct iwl_self_init_dram { * @trigger_tlv: array of pointers to triggers TLVs for debug * @lmac_error_event_table: addrs of lmacs error tables * @umac_error_event_table: addr of umac error table + * @tcm_error_event_table: address of TCM error table * @error_event_table_tlv_status: bitmap that indicates what error table * 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 @@ -732,6 +736,7 @@ struct iwl_trans_debug { u32 lmac_error_event_table[2]; u32 umac_error_event_table; + u32 tcm_error_event_table; unsigned int error_event_table_tlv_status; enum iwl_ini_cfg_state internal_ini_cfg; @@ -957,6 +962,7 @@ struct iwl_trans { bool pm_support; bool ltr_enabled; u8 pnvm_loaded:1; + u8 reduce_power_loaded:1; const struct iwl_hcmd_arr *command_groups; int command_groups_size; @@ -1420,6 +1426,20 @@ static inline int iwl_trans_set_pnvm(struct iwl_trans *trans, return 0; } +static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len) +{ + if (trans->ops->set_reduce_power) { + int ret = trans->ops->set_reduce_power(trans, data, len); + + if (ret) + return ret; + } + + trans->reduce_power_loaded = true; + return 0; +} + static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) { return trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 2e28cf299ef4..6a259d867d90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -104,7 +104,7 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_tkip_params_cmd *tkip; - struct iwl_wowlan_kek_kck_material_cmd_v3 *kek_kck_cmd; + struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; bool error, use_rsc_tsc, use_tkip, configure_keys; int wep_key_idx; }; @@ -393,14 +393,19 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, } static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, struct cfg80211_wowlan *wowlan) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_patterns_cmd *pattern_cmd; struct iwl_host_cmd cmd = { .id = WOWLAN_PATTERNS, .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; int i, err; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_PATTERNS, + IWL_FW_CMD_VER_UNKNOWN); if (!wowlan->n_patterns) return 0; @@ -408,11 +413,13 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, cmd.len[0] = sizeof(*pattern_cmd) + wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2); - pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); + pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL); if (!pattern_cmd) return -ENOMEM; - pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); + pattern_cmd->n_patterns = wowlan->n_patterns; + if (ver >= 3) + pattern_cmd->sta_id = mvmvif->ap_sta_id; for (i = 0; i < wowlan->n_patterns; i++) { int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); @@ -636,7 +643,6 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct ieee80211_sta *ap_sta) { - int ret; struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ @@ -646,12 +652,16 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; - /* Query the last used seqno and set it */ - ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - if (ret < 0) - return ret; + if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_CONFIGURATION, 0) < 6) { + /* Query the last used seqno and set it */ + int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + if (ret < 0) + return ret; + + wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + } iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); @@ -706,7 +716,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 cmd_flags) { - struct iwl_wowlan_kek_kck_material_cmd_v3 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -715,7 +726,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, - .kek_kck_cmd = &kek_kck_cmd, + .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -809,13 +820,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_ALWAYS_LONG_GROUP, WOWLAN_KEK_KCK_MATERIAL, IWL_FW_CMD_VER_UNKNOWN); - if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && + if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 && cmd_ver != IWL_FW_CMD_VER_UNKNOWN)) return -EINVAL; - if (cmd_ver == 3) - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); - else - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, mvmvif->rekey_data.kck_len); @@ -825,6 +832,21 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len); kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm); + kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id); + + if (cmd_ver == 4) { + cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); + } else { + if (cmd_ver == 3) + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); + else + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); + /* skip the sta_id at the beginning */ + _kek_kck_cmd = (void *) + ((u8 *)_kek_kck_cmd) + sizeof(kek_kck_cmd.sta_id); + } IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n", mvmvif->rekey_data.akm); @@ -832,7 +854,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, cmd_flags, cmd_size, - &kek_kck_cmd); + _kek_kck_cmd); if (ret) goto out; } @@ -884,7 +906,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE)) - ret = iwl_mvm_send_patterns(mvm, wowlan); + ret = iwl_mvm_send_patterns(mvm, vif, wowlan); else ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) @@ -1534,9 +1556,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, } out: - mvmvif->seqno_valid = true; - /* +0x10 because the set API expects next-to-use, not last-used */ - mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0) < 10) { + mvmvif->seqno_valid = true; + /* +0x10 because the set API expects next-to-use, not last-used */ + mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + } return true; } @@ -1587,15 +1612,27 @@ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) iwl_mvm_parse_wowlan_status_common(v9) -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) +static struct iwl_wowlan_status * +iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) { struct iwl_wowlan_status *status; + struct iwl_wowlan_get_status_cmd get_status_cmd = { + .sta_id = cpu_to_le32(sta_id), + }; struct iwl_host_cmd cmd = { .id = WOWLAN_GET_STATUSES, .flags = CMD_WANT_SKB, + .data = { &get_status_cmd, }, + .len = { sizeof(get_status_cmd), }, }; int ret, len; u8 notif_ver; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) + cmd.len[0] = 0; lockdep_assert_held(&mvm->mutex); @@ -1608,8 +1645,11 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) len = iwl_rx_packet_payload_len(cmd.resp_pkt); /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - WOWLAN_GET_STATUSES, 7); + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0); + if (!notif_ver) + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 7); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { @@ -1654,7 +1694,7 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) status->gtk[0] = v7->gtk[0]; status->igtk[0] = v7->igtk[0]; - } else if (notif_ver == 9) { + } else if (notif_ver == 9 || notif_ver == 10) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; status = iwl_mvm_parse_wowlan_status_common_v9(mvm, @@ -1680,29 +1720,37 @@ out_free_resp: } static struct iwl_wowlan_status * -iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm) +iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id) { - int ret; - - /* only for tracing for now */ - ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + OFFLOADS_QUERY_CMD, + IWL_FW_CMD_VER_UNKNOWN); + __le32 station_id = cpu_to_le32(sta_id); + u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0; + + if (!mvm->net_detect) { + /* only for tracing for now */ + int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, + cmd_size, &station_id); + if (ret) + IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + } - return iwl_mvm_send_wowlan_get_status(mvm); + return iwl_mvm_send_wowlan_get_status(mvm, sta_id); } /* releases the MVM mutex */ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_status_data status; struct iwl_wowlan_status *fw_status; int i; bool keep; struct iwl_mvm_sta *mvm_ap_sta; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id); if (IS_ERR_OR_NULL(fw_status)) goto out_unlock; @@ -1880,7 +1928,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, u32 reasons = 0; int i, n_matches, ret; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA); if (!IS_ERR_OR_NULL(fw_status)) { reasons = le32_to_cpu(fw_status->wakeup_reasons); kfree(fw_status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 38d0bfb649cc..7d9faeffd154 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -460,7 +460,7 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, int pos = 0; mutex_lock(&mvm->mutex); - iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL); mutex_unlock(&mvm->mutex); do_div(curr_os, NSEC_PER_USEC); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 63d65018d098..95f883aba148 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1023,7 +1023,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, mvm->fw_restart++; /* take the return value to make compiler happy - it will fail anyway */ - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(LONG_GROUP, REPLY_ERROR), + 0, 0, NULL); mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index a456b8a0ae58..59cef0d89a6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include <linux/etherdevice.h> #include <linux/math64.h> @@ -430,6 +430,10 @@ iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, FTM_PUT_FLAG(TB); else if (peer->ftm.non_trigger_based) FTM_PUT_FLAG(NON_TB); + + if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) && + peer->ftm.lmr_feedback) + FTM_PUT_FLAG(LMR_FEEDBACK); } static int @@ -879,7 +883,8 @@ static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) u32 curr_gp2, diff; u64 now_from_boot_ns; - iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, + &now_from_boot_ns, NULL); if (curr_gp2 >= gp2_ts) diff = curr_gp2 - gp2_ts; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 8aa5f1a2c58c..38fd5886af2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1139,19 +1139,34 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { - int cmd_ret; - struct iwl_lari_config_change_cmd_v3 cmd = {}; + int ret; + u32 value; + struct iwl_lari_config_change_cmd_v4 cmd = {}; cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT, + &iwl_guid, &value); + if (!ret) + cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); /* apply more config masks here */ - if (cmd.config_bitmap) { + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, + DSM_FUNC_ENABLE_UNII4_CHAN, + &iwl_guid, &value); + if (!ret) + cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); + + if (cmd.config_bitmap || + cmd.oem_11ax_allow_bitmap || + cmd.oem_unii4_allow_bitmap) { size_t cmd_size; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE, 1); - if (cmd_ver == 3) + if (cmd_ver == 4) + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); + else if (cmd_ver == 3) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); else if (cmd_ver == 2) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); @@ -1159,16 +1174,21 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x\n", - le32_to_cpu(cmd.config_bitmap)); - cmd_ret = iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), - 0, cmd_size, &cmd); - if (cmd_ret < 0) + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd.config_bitmap), + le32_to_cpu(cmd.oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(mvm, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd.oem_unii4_allow_bitmap), + cmd_ver); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + 0, cmd_size, &cmd); + if (ret < 0) IWL_DEBUG_RADIO(mvm, "Failed to send LARI_CONFIG_CHANGE (%d)\n", - cmd_ret); + ret); } } #else /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 607d5d564928..70ebecb73c24 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3306,14 +3306,14 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw, static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 req_duration) + struct ieee80211_prep_tx_info *info) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS; - if (req_duration > duration) - duration = req_duration; + if (info->duration > duration) + duration = info->duration; mutex_lock(&mvm->mutex); /* Try really hard to protect the session and hear a beacon @@ -3800,6 +3800,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct cfg80211_chan_def chandef; struct iwl_mvm_phy_ctxt *phy_ctxt; + bool band_change_removal; int ret, i; IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, @@ -3880,19 +3881,30 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); /* - * Change the PHY context configuration as it is currently referenced - * only by the P2P Device MAC + * Check if the remain-on-channel is on a different band and that + * requires context removal, see iwl_mvm_phy_ctxt_changed(). If + * so, we'll need to release and then re-configure here, since we + * must not remove a PHY context that's part of a binding. */ - if (mvmvif->phy_ctxt->ref == 1) { + band_change_removal = + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && + mvmvif->phy_ctxt->channel->band != chandef.chan->band; + + if (mvmvif->phy_ctxt->ref == 1 && !band_change_removal) { + /* + * Change the PHY context configuration as it is currently + * referenced only by the P2P Device MAC (and we can modify it) + */ ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, &chandef, 1, 1); if (ret) goto out_unlock; } else { /* - * The PHY context is shared with other MACs. Need to remove the - * P2P Device from the binding, allocate an new PHY context and - * create a new binding + * The PHY context is shared with other MACs (or we're trying to + * switch bands), so remove the P2P Device from the binding, + * allocate an new PHY context and create a new binding. */ phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); if (!phy_ctxt) { @@ -4211,7 +4223,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif = NULL; lockdep_assert_held(&mvm->mutex); - iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); switch (vif->type) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 4d9d4d6892fc..b50942f28bb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -16,6 +16,8 @@ #include <linux/thermal.h> #endif +#include <linux/ktime.h> + #include "iwl-op-mode.h" #include "iwl-trans.h" #include "fw/notif-wait.h" @@ -195,6 +197,7 @@ enum iwl_mvm_smps_type_request { IWL_MVM_SMPS_REQ_BT_COEX, IWL_MVM_SMPS_REQ_TT, IWL_MVM_SMPS_REQ_PROT, + IWL_MVM_SMPS_REQ_FW, NUM_IWL_MVM_SMPS_REQ, }; @@ -991,6 +994,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + bool fw_static_smps_request; + unsigned long bt_coex_last_tcm_ts; struct iwl_mvm_tcm tcm; @@ -1447,10 +1452,16 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac); -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); + +static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) +{ + iwl_fwrt_dump_error_logs(&mvm->fwrt); +} + u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime); +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2, + u64 *boottime, ktime_t *realtime); u32 iwl_mvm_get_systime(struct iwl_mvm *mvm); /* Tx / Host Commands */ @@ -1769,7 +1780,6 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); extern const struct file_operations iwl_dbgfs_d3_test_ops; -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm); #ifdef CONFIG_PM void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -1827,7 +1837,9 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, enum ieee80211_smps_mode smps_request); -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm); +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt); +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif); /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 1cc90e61367b..41880517e8bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2012-2014, 2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -36,7 +36,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_v1 v1; struct iwl_proto_offload_cmd_v2 v2; struct iwl_proto_offload_cmd_v3_small v3s; - struct iwl_proto_offload_cmd_v3_large v3l; + struct iwl_proto_offload_cmd_v4 v4; } cmd = {}; struct iwl_host_cmd hcmd = { .id = PROT_OFFLOAD_CONFIG_CMD, @@ -47,6 +47,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_common *common; u32 enabled = 0, size; u32 capa_flags = mvm->fw->ucode_capa.flags; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + PROT_OFFLOAD_CONFIG_CMD, 0); + #if IS_ENABLED(CONFIG_IPV6) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; @@ -72,9 +75,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, addrs = cmd.v3s.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; } else { - nsc = cmd.v3l.ns_config; + nsc = cmd.v4.ns_config; n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; - addrs = cmd.v3l.targ_addrs; + addrs = cmd.v4.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; } @@ -116,7 +119,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); else - cmd.v3l.num_valid_ipv6_addrs = + cmd.v4.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { bool found = false; @@ -171,8 +174,17 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, common = &cmd.v3s.common; size = sizeof(cmd.v3s); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - common = &cmd.v3l.common; - size = sizeof(cmd.v3l); + common = &cmd.v4.common; + size = sizeof(cmd.v4); + if (ver < 4) { + /* + * This basically uses iwl_proto_offload_cmd_v3_large + * which doesn't have the sta_id parameter before the + * common part. + */ + size -= sizeof(cmd.v4.sta_id); + hcmd.data[0] = common; + } } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { common = &cmd.v2.common; size = sizeof(cmd.v2); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ebed82c590e5..20e8d343a950 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -210,6 +210,39 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, ieee80211_disconnect(vif, true); } +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, + mvm->fw_static_smps_request ? + IEEE80211_SMPS_STATIC : + IEEE80211_SMPS_AUTOMATIC); +} + +static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + iwl_mvm_apply_fw_smps_request(vif); +} + +static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_thermal_dual_chain_request *req = (void *)pkt->data; + + /* + * We could pass it to the iterator data, but also need to remember + * it for new interfaces that are added while in this state. + */ + mvm->fw_static_smps_request = + req->event == cpu_to_le32(THERMAL_DUAL_CHAIN_REQ_DISABLE); + ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_intf_dual_chain_req, NULL); +} + /** * enum iwl_rx_handler_context context for Rx handler * @RX_HANDLER_SYNC : this means that it will be called in the Rx path @@ -358,6 +391,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_datapath_monitor_notif), + + RX_HANDLER_GRP(DATA_PATH_GROUP, THERMAL_DUAL_CHAIN_REQUEST, + iwl_mvm_rx_thermal_dual_chain_req, + RX_HANDLER_ASYNC_LOCKED, + struct iwl_thermal_dual_chain_request), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -445,7 +483,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(D3_CONFIG_CMD), HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), HCMD_NAME(OFFLOADS_QUERY_CMD), - HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), @@ -503,6 +540,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(MONITOR_NOTIF), + HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 0fd51f6aa206..035336a9e755 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -76,6 +76,7 @@ static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, } static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, __le32 *rxchain_info, u8 chains_static, u8 chains_dynamic) @@ -93,11 +94,22 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * between the two antennas is sufficiently different to impact * performance. */ - if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) { + if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm, ctxt)) { idle_cnt = 2; active_cnt = 2; } + /* + * If the firmware requested it, then we know that it supports + * getting zero for the values to indicate "use one, but pick + * which one yourself", which means it can dynamically pick one + * that e.g. has better RSSI. + */ + if (mvm->fw_static_smps_request && active_cnt == 1 && idle_cnt == 1) { + idle_cnt = 0; + active_cnt = 0; + } + *rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); *rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); @@ -113,6 +125,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd_v1 *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -123,7 +136,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &tail->rxchain_info, chains_static, chains_dynamic); tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); @@ -133,6 +146,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -143,7 +157,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, chains_static, chains_dynamic); } @@ -170,7 +184,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); @@ -186,7 +200,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data_v1(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 8e26422ca326..c0babb8d5b5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -2001,8 +2001,10 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb; u8 channel, energy_a, energy_b; struct iwl_mvm_rx_phy_data phy_data = { + .info_type = le32_get_bits(desc->phy_info[1], + IWL_RX_PHY_DATA1_INFO_TYPE_MASK), .d0 = desc->phy_info[0], - .info_type = IWL_RX_PHY_INFO_TYPE_NONE, + .d1 = desc->phy_info[1], }; if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc))) @@ -2015,10 +2017,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS; channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS; - phy_data.info_type = - le32_get_bits(desc->phy_info[1], - IWL_RX_PHY_DATA1_INFO_TYPE_MASK); - /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 5a0696c44f6d..0368b7101222 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -2327,9 +2327,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; @@ -2362,9 +2362,9 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f618368eda83..9c45a64c5009 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3794,8 +3794,12 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, mvm_sta->disable_tx = disable; - /* Tell mac80211 to start/stop queuing tx for this station */ - ieee80211_sta_block_awake(mvm->hw, sta, disable); + /* + * If sta PS state is handled by mac80211, tell it to start/stop + * queuing tx for this station. + */ + if (!ieee80211_hw_check(mvm->hw, AP_LINK_PS)) + ieee80211_sta_block_awake(mvm->hw, sta, disable); iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 83342a6a6d5b..d3307a11fcac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -31,6 +31,13 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, return; list_del(&te_data->list); + + /* + * the list is only used for AUX ROC events so make sure it is always + * initialized + */ + INIT_LIST_HEAD(&te_data->list); + te_data->running = false; te_data->uid = 0; te_data->id = TE_MAX; @@ -310,6 +317,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, + !te_data->vif->bss_conf.assoc ? + "Not associated and the time event is over already..." : "No beacon heard and the time event is over already..."); break; default: @@ -607,14 +616,15 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, } static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif) + struct iwl_mvm_vif *mvmvif, + u32 id) { 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), - .conf_id = cpu_to_le32(mvmvif->time_event_data.id), + .conf_id = cpu_to_le32(id), }; int ret; @@ -632,6 +642,12 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, { u32 id; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); + enum nl80211_iftype iftype; + + if (!te_data->vif) + return false; + + iftype = te_data->vif->type; /* * It is possible that by the time we got to this point the time @@ -656,8 +672,8 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ - iwl_mvm_cancel_session_protection(mvm, mvmvif); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + iwl_mvm_cancel_session_protection(mvm, mvmvif, id); + if (iftype == NL80211_IFTYPE_P2P_DEVICE) { set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); iwl_mvm_roc_finished(mvm); } @@ -738,11 +754,6 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_ERR(mvm, "Couldn't remove the time event\n"); } -/* - * 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) { @@ -756,7 +767,15 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, id = te_data->id; spin_unlock_bh(&mvm->time_event_lock); - if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + if (id != SESSION_PROTECT_CONF_ASSOC) { + IWL_DEBUG_TE(mvm, + "don't remove session protection id=%u\n", + id); + return; + } + } else if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { IWL_DEBUG_TE(mvm, "don't remove TE with id=%u (not session protection)\n", id); @@ -808,6 +827,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, vif, + !vif->bss_conf.assoc ? + "Not associated and the session protection is over already..." : "No beacon heard and the session protection is over already..."); spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, te_data); @@ -981,7 +1002,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - iwl_mvm_cancel_session_protection(mvm, mvmvif); + iwl_mvm_cancel_session_protection(mvm, mvmvif, + mvmvif->time_event_data.id); set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, @@ -1141,6 +1163,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); te_data->duration = le32_to_cpu(cmd.duration_tu); + te_data->vif = vif; spin_unlock_bh(&mvm->time_event_lock); IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 1ad621d13ad3..0a13c2bda2ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1032,6 +1032,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_INVALID_STA)) return -1; + if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->he_cap.has_he) + return -1; + if (unlikely(ieee80211_is_probe_resp(fc))) iwl_mvm_probe_resp_set_noa(mvm, skb); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index c566be99a4c7..4a3d2971a98b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -238,316 +238,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) return last_idx; } -/* - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_error_event_table_v1 { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 pc; /* program counter */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 gp3; /* GP3 timer register */ - u32 ucode_ver; /* uCode version */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */; - -struct iwl_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 trm_hw_status0; /* TRM HW status */ - u32 trm_hw_status1; /* TRM HW status */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 fw_rev_type; /* firmware revision type */ - u32 major; /* uCode version major */ - u32 minor; /* uCode version minor */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 last_cmd_id; /* last HCMD id handled by the firmware */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; - -/* - * UMAC error struct - relevant starting from family 8000 chip. - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_umac_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 umac_major; - u32 umac_minor; - u32 frame_pointer; /* core register 27*/ - u32 stack_pointer; /* core register 28 */ - u32 cmd_header; /* latest host cmd sent to UMAC */ - u32 nic_isr_pref; /* ISR status register */ -} __packed; - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_umac_error_event_table table = {}; - u32 base = mvm->trans->dbg.umac_error_event_table; - - if (!base && - !(mvm->trans->dbg.error_event_table_tlv_status & - IWL_ERROR_EVENT_TABLE_UMAC)) - return; - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.umac_err_id = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); - IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major); - IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor); - IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer); - IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer); - IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header); - IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); -} - -static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_error_event_table table = {}; - u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num]; - - if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) { - if (!base) - base = mvm->fw->init_errlog_ptr; - } else { - if (!base) - base = mvm->fw->inst_errlog_ptr; - } - - if (base < 0x400000) { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - /* check if there is a HW error */ - val = iwl_trans_read_mem32(trans, base); - if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { - int err; - - IWL_ERR(trans, "HW error, resetting before reading\n"); - - /* reset the device */ - iwl_trans_sw_reset(trans); - - err = iwl_finish_nic_init(trans, trans->trans_cfg); - if (err) - return; - } - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - /* Do not change this output - scripts rely on it */ - - IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); - - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); - IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); - IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type); - IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major); - IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor); - IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd); - IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0); - IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1); - IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); - IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); - IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); - IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id); - IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); - IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); - IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); - IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); - IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); - IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); - IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); - IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); -} - -static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - u32 error, data1; - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { - error = UMAG_SB_CPU_2_STATUS; - data1 = UMAG_SB_CPU_1_STATUS; - } else if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_8000) { - error = SB_CPU_2_STATUS; - data1 = SB_CPU_1_STATUS; - } else { - return; - } - - error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); - - IWL_ERR(trans, "IML/ROM dump:\n"); - - if (error & 0xFFFF0000) - IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); - - IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error); - IWL_ERR(mvm, "0x%08X | IML/ROM data1\n", - iwl_read_umac_prph(trans, data1)); - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) - IWL_ERR(mvm, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", - iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); -} - -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) -{ - if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { - IWL_ERR(mvm, - "DEVICE_ENABLED bit is not set. Aborting dump.\n"); - return; - } - - iwl_mvm_dump_lmac_error_log(mvm, 0); - - if (mvm->trans->dbg.lmac_error_event_table[1]) - iwl_mvm_dump_lmac_error_log(mvm, 1); - - iwl_mvm_dump_umac_error_log(mvm); - - iwl_mvm_dump_iml_error_log(mvm); - - iwl_fw_error_print_fseq_regs(&mvm->fwrt); -} - int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn) { @@ -621,7 +311,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request) { struct iwl_mvm_vif *mvmvif; - enum ieee80211_smps_mode smps_mode; + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; int i; lockdep_assert_held(&mvm->mutex); @@ -630,10 +320,8 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return; - if (vif->type == NL80211_IFTYPE_AP) - smps_mode = IEEE80211_SMPS_OFF; - else - smps_mode = IEEE80211_SMPS_AUTOMATIC; + if (vif->type != NL80211_IFTYPE_STATION) + return; mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; @@ -683,23 +371,37 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm) mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan; } +struct iwl_mvm_diversity_iter_data { + struct iwl_mvm_phy_ctxt *ctxt; + bool result; +}; + static void iwl_mvm_diversity_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool *result = _data; + struct iwl_mvm_diversity_iter_data *data = _data; int i; + if (mvmvif->phy_ctxt != data->ctxt) + return; + for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC || - mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) - *result = false; + mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { + data->result = false; + break; + } } } -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt) { - bool result = true; + struct iwl_mvm_diversity_iter_data data = { + .ctxt = ctxt, + .result = true, + }; lockdep_assert_held(&mvm->mutex); @@ -711,9 +413,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_diversity_iter, &result); + iwl_mvm_diversity_iter, &data); - return result; + return data.result; } void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm, @@ -1398,7 +1100,8 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm) return iwl_read_prph(mvm->trans, reg_addr); } -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, + u32 *gp2, u64 *boottime, ktime_t *realtime) { bool ps_disabled; @@ -1412,7 +1115,11 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) } *gp2 = iwl_mvm_get_systime(mvm); - *boottime = ktime_get_boottime_ns(); + + if (clock_type == CLOCK_BOOTTIME && boottime) + *boottime = ktime_get_boottime_ns(); + else if (clock_type == CLOCK_REALTIME && realtime) + *realtime = ktime_get_real(); if (!ps_disabled) { mvm->ps_disabled = ps_disabled; 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 cecc32e7dbe8..239a722cd79d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -79,7 +79,6 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, struct iwl_prph_scratch *prph_scratch; struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl; struct iwl_prph_info *prph_info; - void *iml_img; u32 control_flags = 0; int ret; int cmdq_size = max_t(u32, IWL_CMD_QUEUE_SIZE, @@ -138,8 +137,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, /* Allocate prph information * currently we don't assign to the prph info anything, but it would get - * assigned later */ - prph_info = dma_alloc_coherent(trans->dev, sizeof(*prph_info), + * assigned later + * + * We also use the second half of this page to give the device some + * dummy TR/CR tail pointers - which shouldn't be necessary as we don't + * use this, but the hardware still reads/writes there and we can't let + * it go do that with a NULL pointer. + */ + BUILD_BUG_ON(sizeof(*prph_info) > PAGE_SIZE / 2); + prph_info = dma_alloc_coherent(trans->dev, PAGE_SIZE, &trans_pcie->prph_info_dma_addr, GFP_KERNEL); if (!prph_info) { @@ -166,13 +172,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, ctxt_info_gen3->cr_head_idx_arr_base_addr = cpu_to_le64(trans_pcie->rxq->rb_stts_dma); ctxt_info_gen3->tr_tail_idx_arr_base_addr = - cpu_to_le64(trans_pcie->rxq->tr_tail_dma); + cpu_to_le64(trans_pcie->prph_info_dma_addr + PAGE_SIZE / 2); ctxt_info_gen3->cr_tail_idx_arr_base_addr = - cpu_to_le64(trans_pcie->rxq->cr_tail_dma); - ctxt_info_gen3->cr_idx_arr_size = - cpu_to_le16(IWL_NUM_OF_COMPLETION_RINGS); - ctxt_info_gen3->tr_idx_arr_size = - cpu_to_le16(IWL_NUM_OF_TRANSFER_RINGS); + cpu_to_le64(trans_pcie->prph_info_dma_addr + 3 * PAGE_SIZE / 4); ctxt_info_gen3->mtr_base_addr = cpu_to_le64(trans->txqs.txq[trans->txqs.cmd.q_id]->dma_addr); ctxt_info_gen3->mcr_base_addr = @@ -187,14 +189,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, trans_pcie->prph_scratch = prph_scratch; /* Allocate IML */ - iml_img = dma_alloc_coherent(trans->dev, trans->iml_len, - &trans_pcie->iml_dma_addr, GFP_KERNEL); - if (!iml_img) { + trans_pcie->iml = dma_alloc_coherent(trans->dev, trans->iml_len, + &trans_pcie->iml_dma_addr, + GFP_KERNEL); + if (!trans_pcie->iml) { ret = -ENOMEM; goto err_free_ctxt_info; } - memcpy(iml_img, trans->iml, trans->iml_len); + memcpy(trans_pcie->iml, trans->iml, trans->iml_len); iwl_enable_fw_load_int_ctx_info(trans); @@ -216,10 +219,8 @@ err_free_ctxt_info: trans_pcie->ctxt_info_dma_addr); trans_pcie->ctxt_info_gen3 = NULL; err_free_prph_info: - dma_free_coherent(trans->dev, - sizeof(*prph_info), - prph_info, - trans_pcie->prph_info_dma_addr); + dma_free_coherent(trans->dev, PAGE_SIZE, prph_info, + trans_pcie->prph_info_dma_addr); err_free_prph_scratch: dma_free_coherent(trans->dev, @@ -230,29 +231,40 @@ err_free_prph_scratch: } -void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans) +void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + if (trans_pcie->iml) { + dma_free_coherent(trans->dev, trans->iml_len, trans_pcie->iml, + trans_pcie->iml_dma_addr); + trans_pcie->iml_dma_addr = 0; + trans_pcie->iml = NULL; + } + + iwl_pcie_ctxt_info_free_fw_img(trans); + + if (alive) + return; + if (!trans_pcie->ctxt_info_gen3) return; + /* ctxt_info_gen3 and prph_scratch are still needed for PNVM load */ dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info_gen3), trans_pcie->ctxt_info_gen3, trans_pcie->ctxt_info_dma_addr); trans_pcie->ctxt_info_dma_addr = 0; trans_pcie->ctxt_info_gen3 = NULL; - iwl_pcie_ctxt_info_free_fw_img(trans); - dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_scratch), trans_pcie->prph_scratch, trans_pcie->prph_scratch_dma_addr); trans_pcie->prph_scratch_dma_addr = 0; trans_pcie->prph_scratch = NULL; - dma_free_coherent(trans->dev, sizeof(*trans_pcie->prph_info), - trans_pcie->prph_info, + /* this is needed for the entire lifetime */ + dma_free_coherent(trans->dev, PAGE_SIZE, trans_pcie->prph_info, trans_pcie->prph_info_dma_addr); trans_pcie->prph_info_dma_addr = 0; trans_pcie->prph_info = NULL; @@ -290,3 +302,37 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, return 0; } + +int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const void *data, u32 len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + int ret; + + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return 0; + + /* only allocate the DRAM if not allocated yet */ + if (!trans->reduce_power_loaded) { + if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size)) + return -EBUSY; + + ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len, + &trans_pcie->reduce_power_dram); + if (ret < 0) { + IWL_DEBUG_FW(trans, + "Failed to allocate reduce power DMA %d.\n", + ret); + return ret; + } + } + + prph_sc_ctrl->reduce_power_cfg.base_addr = + cpu_to_le64(trans_pcie->reduce_power_dram.physical); + prph_sc_ctrl->reduce_power_cfg.size = + cpu_to_le32(trans_pcie->reduce_power_dram.size); + + return 0; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d94bd8d732e9..16baee3d52ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -532,6 +532,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x31DC, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name), IWL_DEV_INFO(0xA370, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_name), IWL_DEV_INFO(0xA370, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name), + IWL_DEV_INFO(0x51F0, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_160_name), + IWL_DEV_INFO(0x51F0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name), IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), @@ -1030,6 +1032,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_mr_a0, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, + iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, @@ -1209,14 +1216,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (cfg == &iwlax210_2ax_cfg_so_hr_a0) { if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_TY) { iwl_trans->cfg = &iwlax210_2ax_cfg_ty_gf_a0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) { iwl_trans->cfg = &iwlax210_2ax_cfg_so_jf_b0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF)) { iwl_trans->cfg = &iwlax211_2ax_cfg_so_gf_a0; - } else if (CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id) == - CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_GF4)) { + } else if (CSR_HW_RFID_TYPE(iwl_trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4)) { iwl_trans->cfg = &iwlax411_2ax_cfg_so_gf4_a0; } } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 76a512cd2e5c..cc550f6ef957 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2003-2015, 2018-2020 Intel Corporation + * Copyright (C) 2003-2015, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -109,12 +109,8 @@ struct iwl_rx_completion_desc { * Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices. * In AX210 devices it is a pointer to a list of iwl_rx_transfer_desc's * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) - * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd) - * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd) - * @tr_tail: driver's pointer to the transmission ring tail buffer - * @tr_tail_dma: physical address of the buffer for the transmission ring tail - * @cr_tail: driver's pointer to the completion ring tail buffer - * @cr_tail_dma: physical address of the buffer for the completion ring tail + * @used_bd: driver's pointer to buffer of used receive buffer descriptors (rbd) + * @used_bd_dma: physical address of buffer of used receive buffer descriptors (rbd) * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -142,10 +138,6 @@ struct iwl_rxq { struct iwl_rx_completion_desc *cd; }; dma_addr_t used_bd_dma; - __le16 *tr_tail; - dma_addr_t tr_tail_dma; - __le16 *cr_tail; - dma_addr_t cr_tail_dma; u32 read; u32 write; u32 free_count; @@ -279,6 +271,8 @@ struct cont_rec { * Context information addresses will be taken from here. * This is driver's local copy for keeping track of size and * count for allocating and freeing the memory. + * @iml: image loader image virtual address + * @iml_dma_addr: image loader image DMA address * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @kw: keep warm address @@ -317,6 +311,7 @@ struct cont_rec { * @alloc_page_lock: spinlock for the page allocator * @alloc_page: allocated page to still use parts of * @alloc_page_used: how much of the allocated page was already used (bytes) + * @rf_name: name/version of the CRF, if any */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -329,6 +324,7 @@ struct iwl_trans_pcie { }; struct iwl_prph_info *prph_info; struct iwl_prph_scratch *prph_scratch; + void *iml; dma_addr_t ctxt_info_dma_addr; dma_addr_t prph_info_dma_addr; dma_addr_t prph_scratch_dma_addr; @@ -353,6 +349,7 @@ struct iwl_trans_pcie { struct iwl_dma_ptr kw; struct iwl_dram_data pnvm_dram; + struct iwl_dram_data reduce_power_dram; struct iwl_txq *txq_memory; @@ -409,6 +406,8 @@ struct iwl_trans_pcie { bool fw_reset_handshake; bool fw_reset_done; wait_queue_head_t fw_reset_waitq; + + char rf_name[32]; }; static inline struct iwl_trans_pcie * @@ -530,9 +529,6 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } -#define IWL_NUM_OF_COMPLETION_RINGS 31 -#define IWL_NUM_OF_TRANSFER_RINGS 527 - static inline int iwl_pcie_get_num_sections(const struct fw_img *fw, int start) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index fb8491412be4..4f6f4b2720f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -663,7 +663,6 @@ static int iwl_pcie_free_bd_size(struct iwl_trans *trans, bool use_rx_td) static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, struct iwl_rxq *rxq) { - struct device *dev = trans->dev; bool use_rx_td = (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210); int free_size = iwl_pcie_free_bd_size(trans, use_rx_td); @@ -685,21 +684,6 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, rxq->used_bd, rxq->used_bd_dma); rxq->used_bd_dma = 0; rxq->used_bd = NULL; - - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - return; - - if (rxq->tr_tail) - dma_free_coherent(dev, sizeof(__le16), - rxq->tr_tail, rxq->tr_tail_dma); - rxq->tr_tail_dma = 0; - rxq->tr_tail = NULL; - - if (rxq->cr_tail) - dma_free_coherent(dev, sizeof(__le16), - rxq->cr_tail, rxq->cr_tail_dma); - rxq->cr_tail_dma = 0; - rxq->cr_tail = NULL; } static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, @@ -744,21 +728,6 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, rxq->rb_stts_dma = trans_pcie->base_rb_stts_dma + rxq->id * rb_stts_size; - if (!use_rx_td) - return 0; - - /* Allocate the driver's pointer to TR tail */ - rxq->tr_tail = dma_alloc_coherent(dev, sizeof(__le16), - &rxq->tr_tail_dma, GFP_KERNEL); - if (!rxq->tr_tail) - goto err; - - /* Allocate the driver's pointer to CR tail */ - rxq->cr_tail = dma_alloc_coherent(dev, sizeof(__le16), - &rxq->cr_tail_dma, GFP_KERNEL); - if (!rxq->cr_tail) - goto err; - return 0; err: @@ -1590,9 +1559,6 @@ restart: out: /* Backtrack one entry */ rxq->read = i; - /* update cr tail with the rxq read pointer */ - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - *rxq->cr_tail = cpu_to_le16(r); spin_unlock(&rxq->lock); /* diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 1bcd36e9e008..a34009357227 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -149,7 +149,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) iwl_pcie_ctxt_info_free_paging(trans); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - iwl_pcie_ctxt_info_gen3_free(trans); + iwl_pcie_ctxt_info_gen3_free(trans, false); else iwl_pcie_ctxt_info_free(trans); @@ -240,6 +240,75 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) return 0; } +static void iwl_pcie_get_rf_name(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + char *buf = trans_pcie->rf_name; + size_t buflen = sizeof(trans_pcie->rf_name); + size_t pos; + u32 version; + + if (buf[0]) + return; + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF): + pos = scnprintf(buf, buflen, "JF"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF): + pos = scnprintf(buf, buflen, "GF"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4): + pos = scnprintf(buf, buflen, "GF4"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR): + pos = scnprintf(buf, buflen, "HR"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1): + pos = scnprintf(buf, buflen, "HR1"); + break; + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB): + pos = scnprintf(buf, buflen, "HRCDB"); + break; + default: + return; + } + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR): + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1): + case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB): + version = iwl_read_prph(trans, CNVI_MBOX_C); + switch (version) { + case 0x20000: + pos += scnprintf(buf + pos, buflen - pos, " B3"); + break; + case 0x120000: + pos += scnprintf(buf + pos, buflen - pos, " B5"); + break; + default: + pos += scnprintf(buf + pos, buflen - pos, + " (0x%x)", version); + break; + } + break; + default: + break; + } + + pos += scnprintf(buf + pos, buflen - pos, ", rfid=0x%x", + trans->hw_rf_id); + + IWL_INFO(trans, "Detected RF %s\n", buf); + + /* + * also add a \n for debugfs - need to do it after printing + * since our IWL_INFO machinery wants to see a static \n at + * the end of the string + */ + pos += scnprintf(buf + pos, buflen - pos, "\n"); +} + void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -254,7 +323,10 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) /* now that we got alive we can free the fw image & the context info. * paging memory cannot be freed included since FW will still use it */ - iwl_pcie_ctxt_info_free(trans); + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + iwl_pcie_ctxt_info_gen3_free(trans, true); + else + iwl_pcie_ctxt_info_free(trans); /* * Re-enable all the interrupts, including the RF-Kill one, now that @@ -263,6 +335,8 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_enable_interrupts(trans); mutex_lock(&trans_pcie->mutex); iwl_pcie_check_hw_rf_kill(trans); + + iwl_pcie_get_rf_name(trans); mutex_unlock(&trans_pcie->mutex); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 239bc177a3e5..bee6b4574226 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1648,7 +1648,7 @@ static void iwl_pcie_irq_set_affinity(struct iwl_trans *trans) if (ret) IWL_ERR(trans_pcie->trans, "Failed to set affinity mask for IRQ %d\n", - i); + trans_pcie->msix_entries[i].vector); } } @@ -1943,6 +1943,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) trans_pcie->pnvm_dram.block, trans_pcie->pnvm_dram.physical); + if (trans_pcie->reduce_power_dram.size) + dma_free_coherent(trans->dev, + trans_pcie->reduce_power_dram.size, + trans_pcie->reduce_power_dram.block, + trans_pcie->reduce_power_dram.physical); + mutex_destroy(&trans_pcie->mutex); iwl_trans_free(trans); } @@ -2848,11 +2854,28 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, return bytes_copied; } +static ssize_t iwl_dbgfs_rf_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->rf_name[0]) + return -ENODEV; + + return simple_read_from_buffer(user_buf, count, ppos, + trans_pcie->rf_name, + strlen(trans_pcie->rf_name)); +} + DEBUGFS_READ_WRITE_FILE_OPS(interrupt); DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(rfkill); +DEBUGFS_READ_FILE_OPS(rf); + static const struct file_operations iwl_dbgfs_tx_queue_ops = { .owner = THIS_MODULE, .open = iwl_dbgfs_tx_queue_open, @@ -2879,6 +2902,7 @@ void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(fh_reg, dir, 0400); DEBUGFS_ADD_FILE(rfkill, dir, 0600); DEBUGFS_ADD_FILE(monitor_data, dir, 0400); + DEBUGFS_ADD_FILE(rf, dir, 0400); } static void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans) @@ -3400,6 +3424,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, .set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm, + .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power, #ifdef CONFIG_IWLWIFI_DEBUGFS .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, #endif @@ -3413,6 +3438,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans *trans; int ret, addr_size; const struct iwl_trans_ops *ops = &trans_ops_pcie_gen2; + void __iomem * const *table; if (!cfg_trans->gen2) ops = &trans_ops_pcie; @@ -3485,9 +3511,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, goto out_no_pci; } - trans_pcie->hw_base = pcim_iomap_table(pdev)[0]; - if (!trans_pcie->hw_base) { + table = pcim_iomap_table(pdev); + if (!table) { dev_err(&pdev->dev, "pcim_iomap_table failed\n"); + ret = -ENOMEM; + goto out_no_pci; + } + + trans_pcie->hw_base = table[0]; + if (!trans_pcie->hw_base) { + dev_err(&pdev->dev, "couldn't find IO mem in first BAR\n"); ret = -ENODEV; goto out_no_pci; } diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c index 2c7adb4be100..0aea35c9c11c 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.c +++ b/drivers/net/wireless/intersil/orinoco/hw.c @@ -988,15 +988,18 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) * tsc must be NULL or up to 8 bytes */ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, const u8 *rsc, - size_t rsc_len, const u8 *tsc, size_t tsc_len) + int set_tx, const u8 *key, size_t key_len, + const u8 *rsc, size_t rsc_len, + const u8 *tsc, size_t tsc_len) { struct { __le16 idx; u8 rsc[ORINOCO_SEQ_LEN]; - u8 key[TKIP_KEYLEN]; - u8 tx_mic[MIC_KEYLEN]; - u8 rx_mic[MIC_KEYLEN]; + struct { + u8 key[TKIP_KEYLEN]; + u8 tx_mic[MIC_KEYLEN]; + u8 rx_mic[MIC_KEYLEN]; + } tkip; u8 tsc[ORINOCO_SEQ_LEN]; } __packed buf; struct hermes *hw = &priv->hw; @@ -1011,8 +1014,9 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, key_idx |= 0x8000; buf.idx = cpu_to_le16(key_idx); - memcpy(buf.key, key, - sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic)); + if (key_len != sizeof(buf.tkip)) + return -EINVAL; + memcpy(&buf.tkip, key, sizeof(buf.tkip)); if (rsc_len > sizeof(buf.rsc)) rsc_len = sizeof(buf.rsc); diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h index 466d1ede76f1..da5804dbdf34 100644 --- a/drivers/net/wireless/intersil/orinoco/hw.h +++ b/drivers/net/wireless/intersil/orinoco/hw.h @@ -38,8 +38,9 @@ int __orinoco_hw_set_wap(struct orinoco_private *priv); int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv); int __orinoco_hw_setup_enc(struct orinoco_private *priv); int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, - int set_tx, const u8 *key, const u8 *rsc, - size_t rsc_len, const u8 *tsc, size_t tsc_len); + int set_tx, const u8 *key, size_t key_len, + const u8 *rsc, size_t rsc_len, + const u8 *tsc, size_t tsc_len); int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx); int __orinoco_hw_set_multicast_list(struct orinoco_private *priv, struct net_device *dev, diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c index 7b6c4ae8ddb3..4a01260027bc 100644 --- a/drivers/net/wireless/intersil/orinoco/wext.c +++ b/drivers/net/wireless/intersil/orinoco/wext.c @@ -791,7 +791,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, err = __orinoco_hw_set_tkip_key(priv, idx, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, - priv->keys[idx].key, + priv->keys[idx].key, priv->keys[idx].key_len, tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); if (err) printk(KERN_ERR "%s: Error %d setting TKIP key" diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 51ce767eaf88..ffa894f7312a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -626,6 +626,7 @@ struct mac80211_hwsim_data { u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; struct mac_address addresses[2]; + struct ieee80211_chanctx_conf *chanctx; int channels, idx; bool use_chanctx; bool destroy_on_close; @@ -1257,7 +1258,8 @@ static inline u16 trans_tx_rate_flags_ieee2hwsim(struct ieee80211_tx_rate *rate) static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, struct sk_buff *my_skb, - int dst_portid) + int dst_portid, + struct ieee80211_channel *channel) { struct sk_buff *skb; struct mac80211_hwsim_data *data = hw->priv; @@ -1312,7 +1314,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags)) goto nla_put_failure; - if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq)) + if (nla_put_u32(skb, HWSIM_ATTR_FREQ, channel->center_freq)) goto nla_put_failure; /* We get the tx control (rate and retries) info*/ @@ -1659,7 +1661,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, _portid = READ_ONCE(data->wmediumd); if (_portid || hwsim_virtio_enabled) - return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); + return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel); /* NO wmediumd detected, perfect medium simulation */ data->tx_pkts++; @@ -1693,8 +1695,13 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw) static void mac80211_hwsim_stop(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; + data->started = false; hrtimer_cancel(&data->beacon_timer); + + while (!skb_queue_empty(&data->pending)) + ieee80211_free_txskb(hw, skb_dequeue(&data->pending)); + wiphy_dbg(hw->wiphy, "%s\n", __func__); } @@ -1770,8 +1777,10 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, mac80211_hwsim_monitor_rx(hw, skb, chan); if (_pid || hwsim_virtio_enabled) - return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid, chan); + data->tx_pkts++; + data->tx_bytes += skb->len; mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); dev_kfree_skb(skb); } @@ -2509,6 +2518,11 @@ static int mac80211_hwsim_croc(struct ieee80211_hw *hw, static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = ctx; + mutex_unlock(&hwsim->mutex); hwsim_set_chanctx_magic(ctx); wiphy_dbg(hw->wiphy, "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", @@ -2520,6 +2534,11 @@ static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = NULL; + mutex_unlock(&hwsim->mutex); wiphy_dbg(hw->wiphy, "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", ctx->def.chan->center_freq, ctx->def.width, @@ -2532,6 +2551,11 @@ static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct mac80211_hwsim_data *hwsim = hw->priv; + + mutex_lock(&hwsim->mutex); + hwsim->chanctx = ctx; + mutex_unlock(&hwsim->mutex); hwsim_check_chanctx_magic(ctx); wiphy_dbg(hw->wiphy, "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n", @@ -3124,6 +3148,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, hw->wiphy->max_remain_on_channel_duration = 1000; data->if_combination.radar_detect_widths = 0; data->if_combination.num_different_channels = data->channels; + data->chanctx = NULL; } else { data->if_combination.num_different_channels = 1; data->if_combination.radar_detect_widths = @@ -3633,6 +3658,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, int frame_data_len; void *frame_data; struct sk_buff *skb = NULL; + struct ieee80211_channel *channel = NULL; if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || !info->attrs[HWSIM_ATTR_FRAME] || @@ -3659,6 +3685,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (!data2) goto out; + if (data2->use_chanctx) { + if (data2->tmp_chan) + channel = data2->tmp_chan; + else if (data2->chanctx) + channel = data2->chanctx->def.chan; + } else { + channel = data2->channel; + } + if (!channel) + goto out; + if (!hwsim_virtio_enabled) { if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup) @@ -3670,7 +3707,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, /* check if radio is configured properly */ - if (data2->idle || !data2->started) + if ((data2->idle && !data2->tmp_chan) || !data2->started) goto out; /* A frame is received from user space */ @@ -3683,18 +3720,16 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, mutex_lock(&data2->mutex); rx_status.freq = nla_get_u32(info->attrs[HWSIM_ATTR_FREQ]); - if (rx_status.freq != data2->channel->center_freq && - (!data2->tmp_chan || - rx_status.freq != data2->tmp_chan->center_freq)) { + if (rx_status.freq != channel->center_freq) { mutex_unlock(&data2->mutex); goto out; } mutex_unlock(&data2->mutex); } else { - rx_status.freq = data2->channel->center_freq; + rx_status.freq = channel->center_freq; } - rx_status.band = data2->channel->band; + rx_status.band = channel->band; rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); @@ -3791,11 +3826,6 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) return -EINVAL; } - if (param.channels > CFG80211_MAX_NUM_DIFFERENT_CHANNELS) { - GENL_SET_ERR_MSG(info, "too many channels specified"); - return -EINVAL; - } - if (info->attrs[HWSIM_ATTR_NO_VIF]) param.no_vif = true; diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c index ee4cf3437e28..64fc5e410864 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -941,7 +941,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) wdev->netdev = dev; priv->dev = dev; - dev->netdev_ops = &lbs_netdev_ops; + dev->netdev_ops = &lbs_netdev_ops; dev->watchdog_timeo = 5 * HZ; dev->ethtool_ops = &lbs_ethtool_ops; dev->flags |= IFF_BROADCAST | IFF_MULTICAST; diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index c68814841583..6cbba84989b8 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -151,13 +151,13 @@ static uint16_t lbs_mesh_get_channel(struct lbs_private *priv) */ /** - * lbs_anycast_get - Get function for sysfs attribute anycast_mask + * anycast_mask_show - Get function for sysfs attribute anycast_mask * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t lbs_anycast_get(struct device *dev, - struct device_attribute *attr, char * buf) +static ssize_t anycast_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_access mesh_access; @@ -173,14 +173,15 @@ static ssize_t lbs_anycast_get(struct device *dev, } /** - * lbs_anycast_set - Set function for sysfs attribute anycast_mask + * anycast_mask_store - Set function for sysfs attribute anycast_mask * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t lbs_anycast_set(struct device *dev, - struct device_attribute *attr, const char * buf, size_t count) +static ssize_t anycast_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_access mesh_access; @@ -199,13 +200,13 @@ static ssize_t lbs_anycast_set(struct device *dev, } /** - * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit + * prb_rsp_limit_show - Get function for sysfs attribute prb_rsp_limit * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t lbs_prb_rsp_limit_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t prb_rsp_limit_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_access mesh_access; @@ -225,14 +226,15 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, } /** - * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit + * prb_rsp_limit_store - Set function for sysfs attribute prb_rsp_limit * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t lbs_prb_rsp_limit_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t prb_rsp_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_access mesh_access; @@ -259,27 +261,28 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, } /** - * lbs_mesh_get - Get function for sysfs attribute mesh + * lbs_mesh_show - Get function for sysfs attribute mesh * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t lbs_mesh_get(struct device *dev, - struct device_attribute *attr, char * buf) +static ssize_t lbs_mesh_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); } /** - * lbs_mesh_set - Set function for sysfs attribute mesh + * lbs_mesh_store - Set function for sysfs attribute mesh * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t lbs_mesh_set(struct device *dev, - struct device_attribute *attr, const char * buf, size_t count) +static ssize_t lbs_mesh_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; int enable; @@ -301,20 +304,19 @@ static ssize_t lbs_mesh_set(struct device *dev, * lbs_mesh attribute to be exported per ethX interface * through sysfs (/sys/class/net/ethX/lbs_mesh) */ -static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); +static DEVICE_ATTR_RW(lbs_mesh); /* * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) */ -static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); +static DEVICE_ATTR_RW(anycast_mask); /* * prb_rsp_limit attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/prb_rsp_limit) */ -static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, - lbs_prb_rsp_limit_set); +static DEVICE_ATTR_RW(prb_rsp_limit); static struct attribute *lbs_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, @@ -351,13 +353,13 @@ static int mesh_get_default_parameters(struct device *dev, } /** - * bootflag_get - Get function for sysfs attribute bootflag + * bootflag_show - Get function for sysfs attribute bootflag * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t bootflag_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t bootflag_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -371,14 +373,14 @@ static ssize_t bootflag_get(struct device *dev, } /** - * bootflag_set - Set function for sysfs attribute bootflag + * bootflag_store - Set function for sysfs attribute bootflag * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd; @@ -401,13 +403,13 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, } /** - * boottime_get - Get function for sysfs attribute boottime + * boottime_show - Get function for sysfs attribute boottime * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t boottime_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t boottime_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -421,14 +423,15 @@ static ssize_t boottime_get(struct device *dev, } /** - * boottime_set - Set function for sysfs attribute boottime + * boottime_store - Set function for sysfs attribute boottime * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t boottime_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t boottime_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd; @@ -460,13 +463,13 @@ static ssize_t boottime_set(struct device *dev, } /** - * channel_get - Get function for sysfs attribute channel + * channel_show - Get function for sysfs attribute channel * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t channel_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t channel_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -480,14 +483,14 @@ static ssize_t channel_get(struct device *dev, } /** - * channel_set - Set function for sysfs attribute channel + * channel_store - Set function for sysfs attribute channel * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t channel_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t channel_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd; @@ -510,13 +513,13 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, } /** - * mesh_id_get - Get function for sysfs attribute mesh_id + * mesh_id_show - Get function for sysfs attribute mesh_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -539,14 +542,14 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, } /** - * mesh_id_set - Set function for sysfs attribute mesh_id + * mesh_id_store - Set function for sysfs attribute mesh_id * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; @@ -585,13 +588,14 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, } /** - * protocol_id_get - Get function for sysfs attribute protocol_id + * protocol_id_show - Get function for sysfs attribute protocol_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t protocol_id_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t protocol_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -605,14 +609,15 @@ static ssize_t protocol_id_get(struct device *dev, } /** - * protocol_id_set - Set function for sysfs attribute protocol_id + * protocol_id_store - Set function for sysfs attribute protocol_id * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t protocol_id_set(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t protocol_id_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; @@ -646,13 +651,13 @@ static ssize_t protocol_id_set(struct device *dev, } /** - * metric_id_get - Get function for sysfs attribute metric_id + * metric_id_show - Get function for sysfs attribute metric_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t metric_id_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t metric_id_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -666,14 +671,15 @@ static ssize_t metric_id_get(struct device *dev, } /** - * metric_id_set - Set function for sysfs attribute metric_id + * metric_id_store - Set function for sysfs attribute metric_id * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t metric_id_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; @@ -707,13 +713,13 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, } /** - * capability_get - Get function for sysfs attribute capability + * capability_show - Get function for sysfs attribute capability * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned */ -static ssize_t capability_get(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t capability_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; @@ -727,14 +733,15 @@ static ssize_t capability_get(struct device *dev, } /** - * capability_set - Set function for sysfs attribute capability + * capability_store - Set function for sysfs attribute capability * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer */ -static ssize_t capability_set(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t capability_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; @@ -768,13 +775,13 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, } -static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); -static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); -static DEVICE_ATTR(channel, 0644, channel_get, channel_set); -static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); -static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); -static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); -static DEVICE_ATTR(capability, 0644, capability_get, capability_set); +static DEVICE_ATTR_RW(bootflag); +static DEVICE_ATTR_RW(boottime); +static DEVICE_ATTR_RW(channel); +static DEVICE_ATTR_RW(mesh_id); +static DEVICE_ATTR_RW(protocol_id); +static DEVICE_ATTR_RW(metric_id); +static DEVICE_ATTR_RW(capability); static struct attribute *boot_opts_attrs[] = { &dev_attr_bootflag.attr, diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index a92916dc81a9..fe0a69e804d8 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -48,7 +48,7 @@ static int if_usb_submit_rx_urb(struct if_usb_card *cardp); static int if_usb_reset_device(struct lbtf_private *priv); /** - * if_usb_wrike_bulk_callback - call back to handle URB status + * if_usb_write_bulk_callback - call back to handle URB status * * @urb: pointer to urb structure */ diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 470d669c7f14..2ff23ab259ab 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -995,6 +995,11 @@ struct host_cmd_ds_802_11_key_material { struct mwifiex_ie_type_key_param_set key_param_set; } __packed; +struct host_cmd_ds_802_11_key_material_wep { + __le16 action; + struct mwifiex_ie_type_key_param_set key_param_set[NUM_WEP_KEYS]; +} __packed; + struct host_cmd_ds_gen { __le16 command; __le16 size; @@ -2347,6 +2352,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_wmm_get_status get_wmm_status; struct host_cmd_ds_802_11_key_material key_material; struct host_cmd_ds_802_11_key_material_v2 key_material_v2; + struct host_cmd_ds_802_11_key_material_wep key_material_wep; struct host_cmd_ds_version_ext verext; struct host_cmd_ds_mgmt_frame_reg reg_mask; struct host_cmd_ds_remain_on_chan roc_cfg; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 529dfd8b7ae8..17399d4aa129 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1445,11 +1445,18 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) if (!priv) continue; rtnl_lock(); - wiphy_lock(adapter->wiphy); if (priv->netdev && - priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) + priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { + /* + * Close the netdev now, because if we do it later, the + * netdev notifiers will need to acquire the wiphy lock + * again --> deadlock. + */ + dev_close(priv->wdev.netdev); + wiphy_lock(adapter->wiphy); mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); - wiphy_unlock(adapter->wiphy); + wiphy_unlock(adapter->wiphy); + } rtnl_unlock(); } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 94228b316df1..46517515ba72 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1231,7 +1231,7 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - u32 tmp; + u32 *cookie; card->sleep_cookie_vbase = dma_alloc_coherent(&card->dev->dev, sizeof(u32), @@ -1242,13 +1242,11 @@ static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) "dma_alloc_coherent failed!\n"); return -ENOMEM; } + cookie = (u32 *)card->sleep_cookie_vbase; /* Init val of Sleep Cookie */ - tmp = FW_AWAKE_COOKIE; - put_unaligned(tmp, card->sleep_cookie_vbase); + *cookie = FW_AWAKE_COOKIE; - mwifiex_dbg(adapter, INFO, - "alloc_scook: sleep cookie=0x%x\n", - get_unaligned(card->sleep_cookie_vbase)); + mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", *cookie); return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index d3a968ef21ef..48ea00da1fc9 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -840,14 +840,15 @@ mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv, } if (!enc_key) { - memset(&key_material->key_param_set, 0, - (NUM_WEP_KEYS * - sizeof(struct mwifiex_ie_type_key_param_set))); + struct host_cmd_ds_802_11_key_material_wep *key_material_wep = + (struct host_cmd_ds_802_11_key_material_wep *)key_material; + memset(key_material_wep->key_param_set, 0, + sizeof(key_material_wep->key_param_set)); ret = mwifiex_set_keyparamset_wep(priv, - &key_material->key_param_set, + &key_material_wep->key_param_set[0], &key_param_len); cmd->size = cpu_to_le16(key_param_len + - sizeof(key_material->action) + S_DS_GEN); + sizeof(key_material_wep->action) + S_DS_GEN); return ret; } else memset(&key_material->key_param_set, 0, diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 84b32a5f01ee..3bf6571f4149 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -4552,7 +4552,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, else rates = sta->supp_rates[NL80211_BAND_5GHZ] << 5; legacy_rate_mask_to_array(p->legacy_rates, rates); - memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); + memcpy(p->ht_rates, &sta->ht_cap.mcs, 16); p->interop = 1; p->amsdu_enabled = 0; @@ -5034,7 +5034,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ap_legacy_rates = ap->supp_rates[NL80211_BAND_5GHZ] << 5; } - memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); + memcpy(ap_mcs_rates, &ap->ht_cap.mcs, 16); rcu_read_unlock(); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 72b1cc0ecfda..5e1c1506a4c6 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -191,6 +191,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, q->entry[idx].txwi = txwi; q->entry[idx].skb = skb; + q->entry[idx].wcid = 0xffff; return idx; } @@ -349,6 +350,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { + struct ieee80211_tx_status status = { + .sta = sta, + }; struct mt76_tx_info tx_info = { .skb = skb, }; @@ -360,11 +364,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, u8 *txwi; t = mt76_get_txwi(dev); - if (!t) { - hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_free_txskb(hw, skb); - return -ENOMEM; - } + if (!t) + goto free_skb; + txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; @@ -427,8 +429,13 @@ free: } #endif - dev_kfree_skb(tx_info.skb); mt76_put_txwi(dev, t); + +free_skb: + status.skb = tx_info.skb; + hw = mt76_tx_status_get_hw(dev, tx_info.skb); + ieee80211_tx_status_ext(hw, &status); + return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 977acab0360a..d03aedc3286b 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -83,6 +83,22 @@ static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { { .throughput = 300 * 1024, .blink_time = 50 }, }; +struct ieee80211_rate mt76_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(11, 60), + OFDM_RATE(15, 90), + OFDM_RATE(10, 120), + OFDM_RATE(14, 180), + OFDM_RATE(9, 240), + OFDM_RATE(13, 360), + OFDM_RATE(8, 480), + OFDM_RATE(12, 540), +}; +EXPORT_SYMBOL_GPL(mt76_rates); + static int mt76_led_init(struct mt76_dev *dev) { struct device_node *np = dev->dev->of_node; @@ -315,17 +331,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - - wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_ADHOC); } struct mt76_phy * @@ -346,6 +351,17 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, phy->hw = hw; phy->priv = hw->priv + phy_size; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC); + return phy; } EXPORT_SYMBOL_GPL(mt76_alloc_phy); @@ -428,6 +444,17 @@ mt76_alloc_device(struct device *pdev, unsigned int size, mutex_init(&dev->mcu.mutex); dev->tx_worker.fn = mt76_tx_worker; + hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_ADHOC); + spin_lock_init(&dev->token_lock); idr_init(&dev->token); @@ -514,10 +541,36 @@ EXPORT_SYMBOL_GPL(mt76_free_device); static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) { struct sk_buff *skb = phy->rx_amsdu[q].head; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_dev *dev = phy->dev; phy->rx_amsdu[q].head = NULL; phy->rx_amsdu[q].tail = NULL; + + /* + * Validate if the amsdu has a proper first subframe. + * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU + * flag of the QoS header gets flipped. In such cases, the first + * subframe has a LLC/SNAP header in the location of the destination + * address. + */ + if (skb_shinfo(skb)->frag_list) { + int offset = 0; + + if (!(status->flag & RX_FLAG_8023)) { + offset = ieee80211_get_hdrlen_from_skb(skb); + + if ((status->flag & + (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == + RX_FLAG_DECRYPTED) + offset += 8; + } + + if (ether_addr_equal(skb->data + offset, rfc1042_header)) { + dev_kfree_skb(skb); + return; + } + } __skb_queue_tail(&dev->rx_skb[q], skb); } @@ -606,20 +659,19 @@ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) } EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); -void mt76_update_survey(struct mt76_dev *dev) +void mt76_update_survey(struct mt76_phy *phy) { + struct mt76_dev *dev = phy->dev; ktime_t cur_time; if (dev->drv->update_survey) - dev->drv->update_survey(dev); + dev->drv->update_survey(phy); cur_time = ktime_get_boottime(); - mt76_update_survey_active_time(&dev->phy, cur_time); - if (dev->phy2) - mt76_update_survey_active_time(dev->phy2, cur_time); + mt76_update_survey_active_time(phy, cur_time); if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - struct mt76_channel_state *state = dev->phy.chan_state; + struct mt76_channel_state *state = phy->chan_state; spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; @@ -638,7 +690,7 @@ void mt76_set_channel(struct mt76_phy *phy) int timeout = HZ / 5; wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); - mt76_update_survey(dev); + mt76_update_survey(phy); phy->chandef = *chandef; phy->chan_state = mt76_channel_state(phy, chandef->chan); @@ -663,7 +715,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, mutex_lock(&dev->mutex); if (idx == 0 && dev->drv->update_survey) - mt76_update_survey(dev); + mt76_update_survey(phy); sband = &phy->sband_2g; if (idx >= sband->sband.n_channels) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 36ede65919f8..25c5ceef5257 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -87,6 +87,22 @@ enum mt76_rxq_id { __MT_RXQ_MAX }; +enum mt76_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_TKIP, + MT_CIPHER_TKIP_NO_MIC, + MT_CIPHER_AES_CCMP, + MT_CIPHER_WEP104, + MT_CIPHER_BIP_CMAC_128, + MT_CIPHER_WEP128, + MT_CIPHER_WAPI, + MT_CIPHER_CCMP_CCX, + MT_CIPHER_CCMP_256, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, +}; + struct mt76_queue_buf { dma_addr_t addr; u16 len; @@ -320,6 +336,7 @@ enum { struct mt76_hw_cap { bool has_2ghz; bool has_5ghz; + bool has_6ghz; }; #define MT_DRV_TXWI_NO_FREE BIT(0) @@ -336,7 +353,7 @@ struct mt76_driver_ops { u16 token_size; u8 mcs_rates; - void (*update_survey)(struct mt76_dev *dev); + void (*update_survey)(struct mt76_phy *phy); int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, @@ -738,6 +755,21 @@ enum mt76_phy_type { MT_PHY_TYPE_HE_MU, }; +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ +} + +extern struct ieee80211_rate mt76_rates[12]; + #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) @@ -1031,7 +1063,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); bool mt76_has_tx_pending(struct mt76_phy *phy); void mt76_set_channel(struct mt76_phy *phy); -void mt76_update_survey(struct mt76_dev *dev); +void mt76_update_survey(struct mt76_phy *phy); void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); @@ -1056,7 +1088,14 @@ struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev, struct sk_buff_head *list); void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, struct sk_buff_head *list); -void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb); +void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb, + struct list_head *free_list); +static inline void +mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb) +{ + __mt76_tx_complete_skb(dev, wcid, skb, NULL); +} + void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush); int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1253,4 +1292,15 @@ mt76_token_put(struct mt76_dev *dev, int token) return txwi; } + +static inline int +mt76_get_next_pkt_id(struct mt76_wcid *wcid) +{ + wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; + if (wcid->packet_id == MT_PACKET_ID_NO_ACK || + wcid->packet_id == MT_PACKET_ID_NO_SKB) + wcid->packet_id = MT_PACKET_ID_FIRST; + + return wcid->packet_id; +} #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index e1b2cfa56074..031d39a48a55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -304,34 +304,6 @@ mt7603_init_hardware(struct mt7603_dev *dev) return 0; } -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7603_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -569,8 +541,8 @@ int mt7603_register_device(struct mt7603_dev *dev) wiphy->reg_notifier = mt7603_regd_notifier; - ret = mt76_register_device(&dev->mt76, true, mt7603_rates, - ARRAY_SIZE(mt7603_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index fbceb07c5f37..3972c56136a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -550,14 +550,27 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; @@ -831,7 +844,7 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; } -static enum mt7603_cipher_type +static enum mt76_cipher_type mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); @@ -863,7 +876,7 @@ mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, struct ieee80211_key_conf *key) { - enum mt7603_cipher_type cipher; + enum mt76_cipher_type cipher; u32 addr = mt7603_wtbl3_addr(wcid); u8 key_data[32]; int key_len = sizeof(key_data); @@ -1213,7 +1226,7 @@ mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7603_fill_txs(dev, sta, info, txs_data)) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } @@ -1584,12 +1597,12 @@ trigger: return true; } -void mt7603_update_channel(struct mt76_dev *mdev) +void mt7603_update_channel(struct mt76_phy *mphy) { - struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); + struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); struct mt76_channel_state *state; - state = mdev->phy.chan_state; + state = mphy->chan_state; state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } @@ -1806,7 +1819,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); dev->mphy.mac_work_count++; - mt76_update_survey(&dev->mt76); + mt76_update_survey(&dev->mphy); mt7603_edcca_check(dev); for (i = 0, idx = 0; i < 2; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 1df5b9fed2bb..0fd46d907638 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -256,7 +256,7 @@ void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t); -void mt7603_update_channel(struct mt76_dev *mdev); +void mt7603_update_channel(struct mt76_phy *mphy); void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val); void mt7603_cca_stats_reset(struct mt7603_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index 6741e6907194..3b901090b29c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -765,16 +765,4 @@ enum { #define MT_WTBL1_OR (MT_WTBL1_BASE + 0x2300) #define MT_WTBL1_OR_PSM_WRITE BIT(31) -enum mt7603_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_TKIP, - MT_CIPHER_TKIP_NO_MIC, - MT_CIPHER_AES_CCMP, - MT_CIPHER_WEP104, - MT_CIPHER_BIP_CMAC_128, - MT_CIPHER_WEP128, - MT_CIPHER_WAPI, -}; - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index e8fc4a7ae9bc..83f9861ff522 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 676bb22726d6..cb4659771fd9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -75,7 +75,7 @@ mt7615_pm_set(void *data, u64 val) if (!mt7615_wait_for_mcu_init(dev)) return 0; - if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) + if (!mt7615_firmware_offload(dev) || mt76_is_usb(&dev->mt76)) return -EOPNOTSUPP; if (val == pm->enable) @@ -319,24 +319,6 @@ mt7615_radio_read(struct seq_file *s, void *data) return 0; } -static int mt7615_read_temperature(struct seq_file *s, void *data) -{ - struct mt7615_dev *dev = dev_get_drvdata(s->private); - int temp; - - if (!mt7615_wait_for_mcu_init(dev)) - return 0; - - /* cpu */ - mt7615_mutex_acquire(dev); - temp = mt7615_mcu_get_temperature(dev, 0); - mt7615_mutex_release(dev); - - seq_printf(s, "Temperature: %d\n", temp); - - return 0; -} - static int mt7615_queues_acq(struct seq_file *s, void *data) { @@ -566,8 +548,6 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_file("reset_test", 0200, dir, dev, &fops_reset_test); - debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, - mt7615_read_temperature); debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr); debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 8004ae5c16a9..00aefea1bf61 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -81,7 +81,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) if (napi_complete(napi)) mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev)); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } @@ -99,7 +99,7 @@ static int mt7615_poll_rx(struct napi_struct *napi, int budget) return 0; } done = mt76_dma_rx_poll(napi, budget); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } @@ -222,14 +222,9 @@ void mt7615_dma_start(struct mt7615_dev *dev) int mt7615_dma_init(struct mt7615_dev *dev) { int rx_ring_size = MT7615_RX_RING_SIZE; - int rx_buf_size = MT_RX_BUF_SIZE; u32 mask; int ret; - /* Increase buffer size to receive large VHT MPDUs */ - if (dev->mphy.cap.has_5ghz) - rx_buf_size *= 2; - mt76_dma_attach(&dev->mt76); mt76_wr(dev, MT_WPDMA_GLO_CFG, @@ -270,7 +265,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) /* init rx queues */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, - MT7615_RX_MCU_RING_SIZE, rx_buf_size, + MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; @@ -279,7 +274,7 @@ int mt7615_dma_init(struct mt7615_dev *dev) rx_ring_size /= 2; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, - rx_ring_size, rx_buf_size, MT_RX_RING_BASE); + rx_ring_size, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 86341d1f82f3..2f1ac644e018 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -8,11 +8,61 @@ */ #include <linux/etherdevice.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "eeprom.h" +static ssize_t mt7615_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7615_dev *mdev = dev_get_drvdata(dev); + int temperature; + + if (!mt7615_wait_for_mcu_init(mdev)) + return 0; + + mt7615_mutex_acquire(mdev); + temperature = mt7615_mcu_get_temperature(mdev); + mt7615_mutex_release(mdev); + + if (temperature < 0) + return temperature; + + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); +} + +static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7615_thermal_show_temp, + NULL, 0); + +static struct attribute *mt7615_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7615_hwmon); + +int mt7615_thermal_init(struct mt7615_dev *dev) +{ + struct wiphy *wiphy = mt76_hw(dev)->wiphy; + struct device *hwmon; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, + wiphy_name(wiphy), dev, + mt7615_hwmon_groups); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7615_thermal_init); + static void mt7615_phy_init(struct mt7615_dev *dev) { @@ -174,35 +224,6 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) } EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init); -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -struct ieee80211_rate mt7615_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; -EXPORT_SYMBOL_GPL(mt7615_rates); - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -362,7 +383,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->max_sched_scan_plan_interval = - MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; + MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; @@ -472,8 +493,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) for (i = 0; i <= MT_TXQ_PSD ; i++) mphy->q_tx[i] = dev->mphy.q_tx[i]; - ret = mt76_register_phy(mphy, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + ret = mt76_register_phy(mphy, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (ret) ieee80211_free_hw(mphy->hw); @@ -510,7 +531,6 @@ void mt7615_init_device(struct mt7615_dev *dev) mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); spin_lock_init(&dev->pm.txq_lock); - set_bit(MT76_STATE_PM, &dev->mphy.state); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f81a17d56008..ff3f85e4087c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -20,7 +20,7 @@ #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) static const struct mt7615_dfs_radar_spec etsi_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [5] = { 1, 0, 6, 32, 28, 0, 17, 990, 5010, 1, 1 }, [6] = { 1, 0, 9, 32, 28, 0, 27, 615, 5010, 1, 1 }, @@ -34,7 +34,7 @@ static const struct mt7615_dfs_radar_spec etsi_radar_specs = { }; static const struct mt7615_dfs_radar_spec fcc_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 9, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, @@ -45,7 +45,7 @@ static const struct mt7615_dfs_radar_spec fcc_radar_specs = { }; static const struct mt7615_dfs_radar_spec jp_radar_specs = { - .pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 }, + .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, @@ -57,6 +57,33 @@ static const struct mt7615_dfs_radar_spec jp_radar_specs = { }, }; +static enum mt76_cipher_type +mt7615_mac_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, u8 idx, bool unicast) { @@ -313,14 +340,27 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) @@ -1062,7 +1102,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); - mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */ + mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0); sta->rate_set_tsf |= rd.rateset; @@ -1078,7 +1118,7 @@ EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; @@ -1118,7 +1158,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, static int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, int keyidx, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; @@ -1157,7 +1197,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, static void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt7615_cipher_type cipher, u16 cipher_mask, + enum mt76_cipher_type cipher, u16 cipher_mask, enum set_key_cmd cmd) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); @@ -1183,7 +1223,7 @@ int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { - enum mt7615_cipher_type cipher; + enum mt76_cipher_type cipher; u16 cipher_mask = wcid->cipher; int err; @@ -1235,22 +1275,20 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, int first_idx = 0, last_idx; int i, idx, count; bool fixed_rate, ack_timeout; - bool probe, ampdu, cck = false; + bool ampdu, cck = false; bool rs_idx; u32 rate_set_tsf; u32 final_rate, final_rate_flags, final_nss, txs; - fixed_rate = info->status.rates[0].count; - probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); - txs = le32_to_cpu(txs_data[1]); - ampdu = !fixed_rate && (txs & MT_TXS1_AMPDU); + ampdu = txs & MT_TXS1_AMPDU; txs = le32_to_cpu(txs_data[3]); count = FIELD_GET(MT_TXS3_TX_COUNT, txs); last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs); txs = le32_to_cpu(txs_data[0]); + fixed_rate = txs & MT_TXS0_FIXED_RATE; final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; @@ -1272,7 +1310,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY); - if (fixed_rate && !probe) { + if (fixed_rate) { info->status.rates[0].count = count; i = 0; goto out; @@ -1391,7 +1429,7 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7615_fill_txs(dev, sta, info, txs_data)) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } @@ -1821,43 +1859,41 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -static void __mt7615_update_channel(struct mt7615_dev *dev) +static void mt7615_update_survey(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; + ktime_t cur_time; + + /* MT7615 can only update both phys simultaneously + * since some reisters are shared across bands. + */ mt7615_phy_update_channel(&mdev->phy, 0); if (mdev->phy2) mt7615_phy_update_channel(mdev->phy2, 1); + cur_time = ktime_get_boottime(); + + mt76_update_survey_active_time(&mdev->phy, cur_time); + if (mdev->phy2) + mt76_update_survey_active_time(mdev->phy2, cur_time); + /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } -void mt7615_update_channel(struct mt76_dev *mdev) +void mt7615_update_channel(struct mt76_phy *mphy) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76); if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) return; - __mt7615_update_channel(dev); + mt7615_update_survey(dev); mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7615_update_channel); -static void mt7615_update_survey(struct mt7615_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - ktime_t cur_time; - - __mt7615_update_channel(dev); - cur_time = ktime_get_boottime(); - - mt76_update_survey_active_time(&mdev->phy, cur_time); - if (mdev->phy2) - mt76_update_survey_active_time(mdev->phy2, cur_time); -} - static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) { @@ -1906,14 +1942,26 @@ void mt7615_pm_wake_work(struct work_struct *work) mphy = dev->phy.mt76; if (!mt7615_mcu_set_drv_ctrl(dev)) { + struct mt76_dev *mdev = &dev->mt76; int i; - mt76_for_each_q_rx(&dev->mt76, i) - napi_schedule(&dev->mt76.napi[i]); - mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); - ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, - MT7615_WATCHDOG_TIME); + if (mt76_is_sdio(mdev)) { + mt76_worker_schedule(&mdev->sdio.txrx_worker); + } else { + mt76_for_each_q_rx(mdev, i) + napi_schedule(&mdev->napi[i]); + mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); + mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM], + false); + } + + if (test_bit(MT76_STATE_RUNNING, &mphy->state)) { + unsigned long timeout; + + timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, + timeout); + } } ieee80211_wake_queues(mphy->hw); @@ -1948,6 +1996,7 @@ void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; struct mt76_phy *mphy; + unsigned long timeout; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); @@ -1966,8 +2015,9 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mutex_release(phy->dev); mt76_tx_status_check(mphy->dev, NULL, false); - ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, - MT7615_WATCHDOG_TIME); + + timeout = mt7615_get_macwork_timeout(phy->dev); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout); } void mt7615_tx_token_put(struct mt7615_dev *dev) @@ -2048,14 +2098,12 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) { const struct mt7615_dfs_radar_spec *radar_specs; struct mt7615_dev *dev = phy->dev; - int err, i; + int err, i, lpn = 500; switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs; - err = mt7615_mcu_set_fcc5_lpn(dev, 8); - if (err < 0) - return err; + lpn = 8; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs; @@ -2067,6 +2115,11 @@ mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) return -EINVAL; } + /* avoid FCC radar detection in non-FCC region */ + err = mt7615_mcu_set_fcc5_lpn(dev, lpn); + if (err < 0) + return err; + for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { err = mt7615_mcu_set_radar_th(dev, i, &radar_specs->radar_pattern[i]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 6bf9da040196..46f283eb8d0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -383,48 +383,6 @@ struct mt7615_dfs_radar_spec { struct mt7615_dfs_pattern radar_pattern[16]; }; -enum mt7615_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_TKIP, - MT_CIPHER_TKIP_NO_MIC, - MT_CIPHER_AES_CCMP, - MT_CIPHER_WEP104, - MT_CIPHER_BIP_CMAC_128, - MT_CIPHER_WEP128, - MT_CIPHER_WAPI, - MT_CIPHER_CCMP_256 = 10, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, -}; - -static inline enum mt7615_cipher_type -mt7615_mac_get_cipher(int cipher) -{ - switch (cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; - case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; - case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; - case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; - default: - return MT_CIPHER_NONE; - } -} - static inline struct mt7615_txp_common * mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 39733b351ac4..dada43d6d879 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -28,6 +28,7 @@ static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); + unsigned long timeout; bool running; int ret; @@ -78,8 +79,8 @@ static int mt7615_start(struct ieee80211_hw *hw) set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); if (!running) mt7615_mac_reset_counters(dev); @@ -240,8 +241,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, } ret = mt7615_mcu_add_dev_info(phy, vif, true); - if (ret) - goto out; out: mt7615_mutex_release(dev); @@ -352,10 +351,12 @@ out: mt7615_mutex_release(dev); mt76_worker_schedule(&dev->mt76.tx_worker); - if (!mt76_testmode_enabled(phy->mt76)) + if (!mt76_testmode_enabled(phy->mt76)) { + unsigned long timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(phy->mt76->hw, - &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + &phy->mt76->mac_work, timeout); + } return ret; } @@ -695,7 +696,7 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, msta->n_rates = i; if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) { mt7615_mac_set_rates(phy, msta, NULL, msta->rates); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(phy->mt76, &dev->pm); } spin_unlock_bh(&dev->mt76.lock); } @@ -711,7 +712,7 @@ void mt7615_tx_worker(struct mt76_worker *w) } mt76_tx_worker_run(&dev->mt76); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7615_tx(struct ieee80211_hw *hw, @@ -741,7 +742,7 @@ static void mt7615_tx(struct ieee80211_hw *hw, if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(mphy, &dev->pm); return; } @@ -881,7 +882,8 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mt7615_mutex_acquire(dev); - mt76_set(dev, reg, MT_LPON_TCR_MODE); /* TSF read */ + /* TSF read */ + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1); @@ -911,7 +913,33 @@ mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); /* TSF software overwrite */ - mt76_set(dev, reg, MT_LPON_TCR_WRITE); + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_WRITE); + + mt7615_mutex_release(dev); +} + +static void +mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + s64 timestamp) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 idx = mvif->mt76.omac_idx; + u32 reg; + + idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; + reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); + + mt7615_mutex_acquire(dev); + + mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); + /* TSF software adjust*/ + mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_ADJUST); mt7615_mutex_release(dev); } @@ -1162,7 +1190,7 @@ static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw, else clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); - mt7615_mcu_sta_update_hdr_trans(dev, vif, sta); + mt7615_mcu_set_sta_decap_offload(dev, vif, sta); } #ifdef CONFIG_PM @@ -1200,6 +1228,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = mt7615_hw_dev(hw); + unsigned long timeout; bool running; mt7615_mutex_acquire(dev); @@ -1223,8 +1252,8 @@ static int mt7615_resume(struct ieee80211_hw *hw) mt76_connac_mcu_set_suspend_iter, phy->mt76); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, - MT7615_WATCHDOG_TIME); + timeout = mt7615_get_macwork_timeout(dev); + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); mt7615_mutex_release(dev); @@ -1278,6 +1307,7 @@ const struct ieee80211_ops mt7615_ops = { .get_stats = mt7615_get_stats, .get_tsf = mt7615_get_tsf, .set_tsf = mt7615_set_tsf, + .offset_tsf = mt7615_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7615_set_antenna, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index aa42af9ebfd6..f8a09692d3e4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -411,6 +411,9 @@ mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb) c = (struct mt7615_mcu_csa_notify *)skb->data; + if (c->omac_idx > EXT_BSSID_MAX) + return; + if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx)) mphy = dev->mt76.phy2; @@ -427,6 +430,10 @@ mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) r = (struct mt7615_mcu_rdd_report *)skb->data; + if (!dev->radar_pattern.n_pulses && !r->long_detected && + !r->constant_prf_detected && !r->staggered_prf_detected) + return; + if (r->band_idx && dev->mt76.phy2) mphy = dev->mt76.phy2; @@ -1021,9 +1028,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (IS_ERR(sskb)) return PTR_ERR(sskb); - mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable); + mt76_connac_mcu_sta_basic_tlv(sskb, vif, sta, enable, true); if (enable && sta) - mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0); + mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, + MT76_STA_INFO_STATE_ASSOC); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_RESET_AND_SET, NULL, @@ -1037,8 +1045,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, if (sta) mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta, NULL, wtbl_hdr); - mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, &msta->wcid, NULL, - wtbl_hdr); + mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid, + NULL, wtbl_hdr); } cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE; @@ -1058,6 +1066,26 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); } +static int +mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct sk_buff *skb = NULL; + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, + WTBL_SET, NULL, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, &msta->wcid, NULL, + wtbl_hdr); + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, + true); +} + static const struct mt7615_mcu_ops wtbl_update_ops = { .add_beacon_offload = mt7615_mcu_add_beacon_offload, .set_pm_state = mt7615_mcu_ctrl_pm_state, @@ -1068,6 +1096,7 @@ static const struct mt7615_mcu_ops wtbl_update_ops = { .sta_add = mt7615_mcu_wtbl_sta_add, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans, }; static int @@ -1120,18 +1149,21 @@ mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev, static int __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable, int cmd) + struct ieee80211_sta *sta, bool enable, int cmd, + bool offload_fw) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, + .offload_fw = offload_fw, .enable = enable, + .newly = true, .cmd = cmd, }; info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; - return mt76_connac_mcu_add_sta_cmd(phy, &info); + return mt76_connac_mcu_sta_cmd(phy, &info); } static int @@ -1139,7 +1171,19 @@ mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, - MCU_EXT_CMD_STA_REC_UPDATE); + MCU_EXT_CMD_STA_REC_UPDATE, false); +} + +static int +mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + + return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, + vif, &msta->wcid, + MCU_EXT_CMD_STA_REC_UPDATE); } static const struct mt7615_mcu_ops sta_update_ops = { @@ -1152,27 +1196,9 @@ static const struct mt7615_mcu_ops sta_update_ops = { .sta_add = mt7615_mcu_add_sta, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans, }; -int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; - struct wtbl_req_hdr *wtbl_hdr; - struct sk_buff *skb = NULL; - - wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, - WTBL_SET, NULL, &skb); - if (IS_ERR(wtbl_hdr)) - return PTR_ERR(wtbl_hdr); - - mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, &msta->wcid, NULL, wtbl_hdr); - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE, - true); -} - static int mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) { @@ -1280,7 +1306,7 @@ mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, - MCU_UNI_CMD_STA_REC_UPDATE); + MCU_UNI_CMD_STA_REC_UPDATE, true); } static int @@ -1338,6 +1364,18 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, MCU_UNI_CMD_STA_REC_UPDATE, true); } +static int +mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + + return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, + vif, &msta->wcid, + MCU_UNI_CMD_STA_REC_UPDATE); +} + static const struct mt7615_mcu_ops uni_update_ops = { .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload, .set_pm_state = mt7615_mcu_uni_ctrl_pm_state, @@ -1348,6 +1386,7 @@ static const struct mt7615_mcu_ops uni_update_ops = { .sta_add = mt7615_mcu_uni_add_sta, .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, + .set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans, }; int mt7615_mcu_restart(struct mt76_dev *dev) @@ -2322,14 +2361,12 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } -int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) +int mt7615_mcu_get_temperature(struct mt7615_dev *dev) { struct { u8 action; u8 rsv[3]; - } req = { - .action = index, - }; + } req = {}; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req, sizeof(req), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 202ea235415e..71719c787511 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -229,7 +229,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, GFP_KERNEL); if (!bus_ops) { ret = -ENOMEM; - goto error; + goto err_free_dev; } bus_ops->rr = mt7615_rr; @@ -242,17 +242,20 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto error; + goto err_free_dev; if (is_mt7663(mdev)) mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); ret = mt7615_register_device(dev); if (ret) - goto error; + goto err_free_irq; return 0; -error: + +err_free_irq: + devm_free_irq(pdev, irq, dev); +err_free_dev: mt76_free_device(&dev->mt76); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 989f05ed4377..d0c64a9b09cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -20,7 +20,6 @@ MT7615_MAX_INTERFACES) #define MT7615_PM_TIMEOUT (HZ / 12) -#define MT7615_WATCHDOG_TIME (HZ / 10) #define MT7615_HW_SCAN_TIMEOUT (HZ / 10) #define MT7615_RESET_TIMEOUT (30 * HZ) #define MT7615_RATE_RETRY 2 @@ -202,6 +201,7 @@ struct mt7615_phy { #define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__) #define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev)) #define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev)) +#define mt7615_mcu_set_sta_decap_offload(dev, ...) (dev)->mcu_ops->set_sta_decap_offload((dev), __VA_ARGS__) struct mt7615_mcu_ops { int (*add_tx_ba)(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, @@ -221,6 +221,9 @@ struct mt7615_mcu_ops { int (*set_pm_state)(struct mt7615_dev *dev, int band, int state); int (*set_drv_ctrl)(struct mt7615_dev *dev); int (*set_fw_ctrl)(struct mt7615_dev *dev); + int (*set_sta_decap_offload)(struct mt7615_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); }; struct mt7615_dev { @@ -356,6 +359,7 @@ static inline int mt7622_wmac_init(struct mt7615_dev *dev) } #endif +int mt7615_thermal_init(struct mt7615_dev *dev); int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); @@ -456,6 +460,12 @@ static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev) return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx); } +static inline unsigned long +mt7615_get_macwork_timeout(struct mt7615_dev *dev) +{ + return dev->pm.enable ? HZ / 3 : HZ / 10; +} + void mt7615_dma_reset(struct mt7615_dev *dev); void mt7615_scan_work(struct work_struct *work); void mt7615_roc_work(struct work_struct *work); @@ -466,7 +476,7 @@ int mt7615_set_channel(struct mt7615_phy *phy); void mt7615_init_work(struct mt7615_dev *dev); int mt7615_mcu_restart(struct mt76_dev *dev); -void mt7615_update_channel(struct mt76_dev *mdev); +void mt7615_update_channel(struct mt76_phy *mphy); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); @@ -494,7 +504,7 @@ u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg); int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); -int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); +int mt7615_mcu_get_temperature(struct mt7615_dev *dev); int mt7615_mcu_set_tx_power(struct mt7615_phy *phy); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, @@ -518,9 +528,6 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7615_mac_work(struct work_struct *work); void mt7615_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); -int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev); int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val); int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index ec8ec1a2033f..a2465b49ecd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -98,7 +98,7 @@ mt7615_led_set_config(struct led_classdev *led_cdev, addr = mt7615_reg_map(dev, MT_LED_CTRL); mt76_wr(dev, addr, val); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static int @@ -147,8 +147,12 @@ int mt7615_register_device(struct mt7615_dev *dev) if (ret) return ret; - ret = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); + if (ret) + return ret; + + ret = mt7615_thermal_init(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index d7cbef752f9f..da87c02a73eb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -131,20 +131,21 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; int pid, id; u8 *txwi = (u8 *)txwi_ptr; struct mt76_txwi_cache *t; + struct mt7615_sta *msta; void *txp; + msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if (!wcid) wcid = &dev->mt76.global_wcid; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2) @@ -267,6 +268,7 @@ void mt7615_mac_reset_work(struct work_struct *work) struct mt7615_phy *phy2; struct mt76_phy *ext_phy; struct mt7615_dev *dev; + unsigned long timeout; dev = container_of(work, struct mt7615_dev, reset_work); ext_phy = dev->mt76.phy2; @@ -344,11 +346,11 @@ void mt7615_mac_reset_work(struct work_struct *work) mt7615_mutex_release(dev); + timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, - MT7615_WATCHDOG_TIME); + timeout); if (phy2) ieee80211_queue_delayed_work(ext_phy->hw, - &phy2->mt76->mac_work, - MT7615_WATCHDOG_TIME); + &phy2->mt76->mac_work, timeout); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 63c081bb04d0..6712ad9faeaa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -463,7 +463,9 @@ enum mt7615_reg_base { #define MT_LPON_TCR0(_n) MT_LPON(0x010 + ((_n) * 4)) #define MT_LPON_TCR2(_n) MT_LPON(0x0f8 + ((_n) - 2) * 4) #define MT_LPON_TCR_MODE GENMASK(1, 0) +#define MT_LPON_TCR_READ GENMASK(1, 0) #define MT_LPON_TCR_WRITE BIT(0) +#define MT_LPON_TCR_ADJUST BIT(1) #define MT_LPON_UTTR0 MT_LPON(0x018) #define MT_LPON_UTTR1 MT_LPON(0x01c) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h index 05180971de84..03877d89e152 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +/* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. * * Author: Sean Wang <sean.wang@mediatek.com> diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index 17fe4187d1de..45c1cd3b9f49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -51,16 +51,14 @@ mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, return ret; } -static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) +static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; u32 status; int ret; - if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) - goto out; - sdio_claim_host(func); sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); @@ -69,29 +67,45 @@ static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); if (ret < 0) { dev_err(dev->mt76.dev, "Cannot get ownership from device"); - set_bit(MT76_STATE_PM, &mphy->state); - sdio_release_host(func); + } else { + clear_bit(MT76_STATE_PM, &mphy->state); - return ret; + pm->stats.last_wake_event = jiffies; + pm->stats.doze_time += pm->stats.last_wake_event - + pm->stats.last_doze_event; } - sdio_release_host(func); -out: - dev->pm.last_activity = jiffies; + return ret; +} - return 0; +static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + int ret = 0; + + mutex_lock(&dev->pm.mutex); + + if (test_bit(MT76_STATE_PM, &mphy->state)) + ret = __mt7663s_mcu_drv_pmctrl(dev); + + mutex_unlock(&dev->pm.mutex); + + return ret; } static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int ret = 0; u32 status; - int ret; - if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) - return 0; + mutex_lock(&pm->mutex); + + if (mt76_connac_skip_fw_pmctrl(mphy, pm)) + goto out; sdio_claim_host(func); @@ -102,9 +116,15 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev) if (ret < 0) { dev_err(dev->mt76.dev, "Cannot set ownership to device"); clear_bit(MT76_STATE_PM, &mphy->state); + } else { + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; } sdio_release_host(func); +out: + mutex_unlock(&pm->mutex); return ret; } @@ -123,7 +143,7 @@ int mt7663s_mcu_init(struct mt7615_dev *dev) struct mt7615_mcu_ops *mcu_ops; int ret; - ret = mt7663s_mcu_drv_pmctrl(dev); + ret = __mt7663s_mcu_drv_pmctrl(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c index 4393dd21ebbb..04f4c89b7499 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c @@ -283,9 +283,15 @@ void mt7663s_txrx_worker(struct mt76_worker *w) { struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, txrx_worker); - struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); + struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); int i, nframes, ret; + if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { + queue_work(mdev->wq, &dev->pm.wake_work); + return; + } + /* disable interrupt */ sdio_claim_host(sdio->func); sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); @@ -295,16 +301,16 @@ void mt7663s_txrx_worker(struct mt76_worker *w) /* tx */ for (i = 0; i <= MT_TXQ_PSD; i++) { - ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]); + ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]); if (ret > 0) nframes += ret; } - ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); + ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]); if (ret > 0) nframes += ret; /* rx */ - ret = mt7663s_rx_handler(dev); + ret = mt7663s_rx_handler(mdev); if (ret > 0) nframes += ret; } while (nframes > 0); @@ -312,6 +318,8 @@ void mt7663s_txrx_worker(struct mt76_worker *w) /* enable interrupt */ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); sdio_release_host(sdio->func); + + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } void mt7663s_sdio_irq(struct sdio_func *func) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index be9a69fe1b38..f13d1b418742 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -31,7 +31,6 @@ int mt7622_wmac_init(struct mt7615_dev *dev) static int mt7622_wmac_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); void __iomem *mem_base; int irq; @@ -39,7 +38,7 @@ static int mt7622_wmac_probe(struct platform_device *pdev) if (irq < 0) return irq; - mem_base = devm_ioremap_resource(&pdev->dev, res); + mem_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(mem_base)) return PTR_ERR(mem_base); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index c55698f9c49a..028ff432d811 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -55,10 +55,7 @@ int mt7663u_mcu_init(struct mt7615_dev *dev) dev->mt76.mcu_ops = &mt7663u_mcu_ops, - /* usb does not support runtime-pm */ - clear_bit(MT76_STATE_PM, &dev->mphy.state); mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); - if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { mt7615_mcu_restart(&dev->mt76); if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index f8d3673c2cae..996d48cca18a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -123,7 +123,7 @@ static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); - mt76_set(dev, addr, MT_LPON_TCR_MODE); /* TSF read */ + mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ val = mt76_rr(dev, MT_LPON_UTTR0); sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; @@ -191,14 +191,15 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info) { - struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct sk_buff *skb = tx_info->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt7615_sta *msta; int pad; + msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && - !msta->rate_probe) { + msta && !msta->rate_probe) { /* request to configure sampling rate */ spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], @@ -323,8 +324,8 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) hw->max_tx_fragments = 1; } - err = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); + err = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 6c889b90fd12..f49d97d0a1c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -7,12 +7,13 @@ #include "mt76.h" #define MT76_CONNAC_SCAN_IE_LEN 600 -#define MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL 10 +#define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10 +#define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX #define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 #define MT76_CONNAC_MAX_SCAN_MATCH 16 #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) -#define MT76_CONNAC_COREDUMP_SZ (128 * 1024) +#define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, @@ -45,6 +46,8 @@ enum { struct mt76_connac_pm { bool enable; + bool ds_enable; + bool suspended; spinlock_t txq_lock; struct { @@ -116,19 +119,27 @@ out: } static inline void -mt76_connac_pm_unref(struct mt76_connac_pm *pm) +mt76_connac_pm_unref(struct mt76_phy *phy, struct mt76_connac_pm *pm) { spin_lock_bh(&pm->wake.lock); - pm->wake.count--; + pm->last_activity = jiffies; + if (--pm->wake.count == 0 && + test_bit(MT76_STATE_MCU_RUNNING, &phy->state)) + mt76_connac_power_save_sched(phy, pm); + spin_unlock_bh(&pm->wake.lock); } static inline bool mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm) { + struct mt76_dev *dev = phy->dev; bool ret; + if (dev->token_count) + return true; + spin_lock_bh(&pm->wake.lock); ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state); spin_unlock_bh(&pm->wake.lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 6f180c92d413..af43bcb54578 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -10,13 +10,16 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) if (!pm->enable) return 0; - if (!mt76_is_mmio(dev)) + if (mt76_is_usb(dev)) return 0; cancel_delayed_work_sync(&pm->ps_work); if (!test_bit(MT76_STATE_PM, &phy->state)) return 0; + if (pm->suspended) + return 0; + queue_work(dev->wq, &pm->wake_work); if (!wait_event_timeout(pm->wait, !test_bit(MT76_STATE_PM, &phy->state), @@ -34,12 +37,15 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy, { struct mt76_dev *dev = phy->dev; - if (!mt76_is_mmio(dev)) + if (mt76_is_usb(dev)) return; if (!pm->enable) return; + if (pm->suspended) + return; + pm->last_activity = jiffies; if (!test_bit(MT76_STATE_PM, &phy->state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index fe0ab5e5ff81..5c3a81e5f559 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req); void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - bool enable) + bool enable, bool newly) { struct sta_rec_basic *basic; struct tlv *tlv; @@ -316,7 +316,8 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); if (enable) { - basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + if (newly) + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); basic->conn_state = CONN_STATE_PORT_SECURE; } else { basic->conn_state = CONN_STATE_DISCONNECT; @@ -393,6 +394,7 @@ mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, } void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct mt76_wcid *wcid, void *sta_wtbl, void *wtbl_tlv) { @@ -404,9 +406,46 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, wtbl_tlv, sta_wtbl); htr = (struct wtbl_hdr_trans *)tlv; htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); + + if (vif->type == NL80211_IFTYPE_STATION) + htr->to_ds = true; + else + htr->from_ds = true; + + if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { + htr->to_ds = true; + htr->from_ds = true; + } } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv); +int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, int cmd) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct wtbl_req_hdr *wtbl_hdr; + struct tlv *sta_wtbl; + struct sk_buff *skb; + + skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, + sizeof(struct tlv)); + + wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET, + sta_wtbl, &skb); + if (IS_ERR(wtbl_hdr)) + return PTR_ERR(wtbl_hdr); + + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, sta_wtbl, wtbl_hdr); + + return mt76_mcu_skb_send_msg(dev, skb, cmd, true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_update_hdr_trans); + void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, @@ -671,7 +710,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, - u8 rcpi) + u8 rcpi, u8 sta_state) { struct cfg80211_chan_def *chandef = &mphy->chandef; enum nl80211_band band = chandef->chan->band; @@ -721,6 +760,10 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, sta); phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); phy->rcpi = rcpi; + phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, + sta->ht_cap.ampdu_factor) | + FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, + sta->ht_cap.ampdu_density); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; @@ -732,7 +775,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); state = (struct sta_rec_state *)tlv; - state->state = 2; + state->state = sta_state; if (sta->vht_cap.vht_supported) { state->vht_opmode = sta->bandwidth; @@ -824,8 +867,8 @@ void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv); -int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, - struct mt76_sta_cmd_info *info) +int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info) { struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv; struct mt76_dev *dev = phy->dev; @@ -837,10 +880,13 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, info->enable); - if (info->enable && info->sta) - mt76_connac_mcu_sta_tlv(phy, skb, info->sta, info->vif, - info->rcpi); + if (info->sta || !info->offload_fw) + mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, + info->enable, info->newly); + if (info->sta && info->enable) + mt76_connac_mcu_sta_tlv(phy, skb, info->sta, + info->vif, info->rcpi, + info->state); sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); @@ -855,6 +901,8 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif, info->sta, sta_wtbl, wtbl_hdr); + mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid, + sta_wtbl, wtbl_hdr); if (info->sta) mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta, sta_wtbl, wtbl_hdr); @@ -862,7 +910,7 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } -EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_sta_cmd); +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_cmd); void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_ampdu_params *params, @@ -891,8 +939,10 @@ void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, ba->rst_ba_sb = 1; } - if (is_mt7921(dev)) + if (is_mt7921(dev)) { + ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0; return; + } if (enable && tx) { u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; @@ -1267,6 +1317,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, u8 pad[3]; } __packed hdr; struct bss_info_uni_he he; + struct bss_info_uni_bss_color bss_color; } he_req = { .hdr = { .bss_idx = mvif->idx, @@ -1275,8 +1326,21 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, .tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC), .len = cpu_to_le16(sizeof(struct bss_info_uni_he)), }, + .bss_color = { + .tag = cpu_to_le16(UNI_BSS_INFO_BSS_COLOR), + .len = cpu_to_le16(sizeof(struct bss_info_uni_bss_color)), + .enable = 0, + .bss_color = 0, + }, }; + if (enable) { + he_req.bss_color.enable = + vif->bss_conf.he_bss_color.enabled; + he_req.bss_color.bss_color = + vif->bss_conf.he_bss_color.color; + } + mt76_connac_mcu_uni_bss_he_tlv(phy, vif, (struct tlv *)&he_req.he); err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE, @@ -1459,14 +1523,16 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, req->version = 1; req->seq_num = mvif->scan_seq_num | ext_phy << 7; - if (is_mt7663(phy->dev) && - (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) { - get_random_mask_addr(req->mt7663.random_mac, sreq->mac_addr, - sreq->mac_addr_mask); + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac + : req->mt7921.random_mac; + req->scan_func = 1; - } else if (is_mt7921(phy->dev)) { - req->mt7921.bss_idx = mvif->idx; + get_random_mask_addr(addr, sreq->mac_addr, + sreq->mac_addr_mask); } + if (is_mt7921(phy->dev)) + req->mt7921.bss_idx = mvif->idx; req->ssids_num = sreq->n_ssids; for (i = 0; i < req->ssids_num; i++) { @@ -1552,6 +1618,26 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable) } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep); +int mt76_connac_sta_state_dp(struct mt76_dev *dev, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + if ((old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) || + (old_state == IEEE80211_STA_NONE && + new_state == IEEE80211_STA_NOTEXIST)) + mt76_connac_mcu_set_deep_sleep(dev, true); + + if ((old_state == IEEE80211_STA_NOTEXIST && + new_state == IEEE80211_STA_NONE) || + (old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC)) + mt76_connac_mcu_set_deep_sleep(dev, false); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp); + void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, struct mt76_connac_coredump *coredump) { @@ -1566,6 +1652,60 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event); +int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy) +{ + struct mt76_connac_cap_hdr { + __le16 n_element; + u8 rsv[2]; + } __packed * hdr; + struct sk_buff *skb; + int ret, i; + + ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CMD_GET_NIC_CAPAB, NULL, + 0, true, &skb); + if (ret) + return ret; + + hdr = (struct mt76_connac_cap_hdr *)skb->data; + if (skb->len < sizeof(*hdr)) { + ret = -EINVAL; + goto out; + } + + skb_pull(skb, sizeof(*hdr)); + + for (i = 0; i < le16_to_cpu(hdr->n_element); i++) { + struct tlv_hdr { + __le32 type; + __le32 len; + } __packed * tlv = (struct tlv_hdr *)skb->data; + int len; + + if (skb->len < sizeof(*tlv)) + break; + + skb_pull(skb, sizeof(*tlv)); + + len = le32_to_cpu(tlv->len); + if (skb->len < len) + break; + + switch (le32_to_cpu(tlv->type)) { + case MT_NIC_CAP_6G: + phy->cap.has_6ghz = skb->data[0]; + break; + default: + break; + } + skb_pull(skb, len); + } +out: + dev_kfree_skb(skb); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_get_nic_capability); + static void mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, struct mt76_power_limits *limits, @@ -1628,12 +1768,15 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, 142, 144, 149, 151, 153, 155, 157, 159, 161, 165 }; + int i, n_chan, batch_size, idx = 0, tx_power, last_ch; struct mt76_connac_sku_tlv sku_tlbv; - int i, n_chan, batch_size, idx = 0; struct mt76_power_limits limits; const u8 *ch_list; sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; + tx_power = 2 * phy->hw->conf.power_level; + if (!tx_power) + tx_power = 127; if (band == NL80211_BAND_2GHZ) { n_chan = ARRAY_SIZE(chan_list_2ghz); @@ -1644,39 +1787,48 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, } batch_size = DIV_ROUND_UP(n_chan, batch_len); + if (!phy->cap.has_5ghz) + last_ch = chan_list_2ghz[n_chan - 1]; + else + last_ch = chan_list_5ghz[n_chan - 1]; + for (i = 0; i < batch_size; i++) { - bool last_msg = i == batch_size - 1; - int num_ch = last_msg ? n_chan % batch_len : batch_len; struct mt76_connac_tx_power_limit_tlv tx_power_tlv = { .band = band == NL80211_BAND_2GHZ ? 1 : 2, - .n_chan = num_ch, - .last_msg = last_msg, }; + int j, err, msg_len, num_ch; struct sk_buff *skb; - int j, err, msg_len; + num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv); skb = mt76_mcu_msg_alloc(dev, NULL, msg_len); if (!skb) return -ENOMEM; + skb_reserve(skb, sizeof(tx_power_tlv)); + BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2)); memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2)); + tx_power_tlv.n_chan = num_ch; - skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv)); for (j = 0; j < num_ch; j++, idx++) { struct ieee80211_channel chan = { .hw_value = ch_list[idx], .band = band, }; - mt76_get_rate_power_limits(phy, &chan, &limits, 127); + mt76_get_rate_power_limits(phy, &chan, &limits, + tx_power); + tx_power_tlv.last_msg = ch_list[idx] == last_ch; sku_tlbv.channel = ch_list[idx]; + mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit, &limits, band); skb_put_data(skb, &sku_tlbv, sku_len); } + __skb_push(skb, sizeof(tx_power_tlv)); + memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv)); err = mt76_mcu_skb_send_msg(dev, skb, MCU_CMD_SET_RATE_TX_POWER, false); @@ -1691,11 +1843,20 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy) { int err; - err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ); - if (err < 0) - return err; + if (phy->cap.has_2ghz) { + err = mt76_connac_mcu_rate_txpower_band(phy, + NL80211_BAND_2GHZ); + if (err < 0) + return err; + } + if (phy->cap.has_5ghz) { + err = mt76_connac_mcu_rate_txpower_band(phy, + NL80211_BAND_5GHZ); + if (err < 0) + return err; + } - return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ); + return 0; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower); @@ -1935,7 +2096,7 @@ mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev, ptlv->index = index; memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); - memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8); + memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_SUSPEND, true); } @@ -1970,14 +2131,17 @@ mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, }; if (wowlan->magic_pkt) - req.wow_ctrl_tlv.trigger |= BIT(0); + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC; if (wowlan->disconnect) - req.wow_ctrl_tlv.trigger |= BIT(2); + req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT | + UNI_WOW_DETECT_TYPE_BCN_LOST); if (wowlan->nd_config) { mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config); - req.wow_ctrl_tlv.trigger |= BIT(5); + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT; mt76_connac_mcu_sched_scan_enable(phy, vif, suspend); } + if (wowlan->n_patterns) + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP; if (mt76_is_mmio(dev)) req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index a1096861d04a..1c73beb22677 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -559,6 +559,7 @@ enum { MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, + MCU_CMD_GET_NIC_CAPAB = MCU_CE_PREFIX | 0x8a, MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca, @@ -575,6 +576,7 @@ enum { enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RLM = 2, + UNI_BSS_INFO_BSS_COLOR = 4, UNI_BSS_INFO_HE_BASIC = 5, UNI_BSS_INFO_BCN_CONTENT = 7, UNI_BSS_INFO_QBSS = 15, @@ -591,6 +593,36 @@ enum { }; enum { + MT_NIC_CAP_TX_RESOURCE, + MT_NIC_CAP_TX_EFUSE_ADDR, + MT_NIC_CAP_COEX, + MT_NIC_CAP_SINGLE_SKU, + MT_NIC_CAP_CSUM_OFFLOAD, + MT_NIC_CAP_HW_VER, + MT_NIC_CAP_SW_VER, + MT_NIC_CAP_MAC_ADDR, + MT_NIC_CAP_PHY, + MT_NIC_CAP_MAC, + MT_NIC_CAP_FRAME_BUF, + MT_NIC_CAP_BEAM_FORM, + MT_NIC_CAP_LOCATION, + MT_NIC_CAP_MUMIMO, + MT_NIC_CAP_BUFFER_MODE_INFO, + MT_NIC_CAP_HW_ADIE_VERSION = 0x14, + MT_NIC_CAP_ANTSWP = 0x16, + MT_NIC_CAP_WFDMA_REALLOC, + MT_NIC_CAP_6G, +}; + +#define UNI_WOW_DETECT_TYPE_MAGIC BIT(0) +#define UNI_WOW_DETECT_TYPE_ANY BIT(1) +#define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2) +#define UNI_WOW_DETECT_TYPE_GTK_REKEY_FAIL BIT(3) +#define UNI_WOW_DETECT_TYPE_BCN_LOST BIT(4) +#define UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT BIT(5) +#define UNI_WOW_DETECT_TYPE_BITMAP BIT(6) + +enum { UNI_SUSPEND_MODE_SETTING, UNI_SUSPEND_WOW_CTRL, UNI_SUSPEND_WOW_GPIO_PARAM, @@ -762,7 +794,7 @@ struct mt76_connac_sched_scan_req { u8 intervals_num; u8 scan_func; /* MT7663: BIT(0) eable random mac address */ struct mt76_connac_mcu_scan_channel channels[64]; - __le16 intervals[MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL]; + __le16 intervals[MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL]; union { struct { u8 random_mac[ETH_ALEN]; @@ -770,7 +802,9 @@ struct mt76_connac_sched_scan_req { } mt7663; struct { u8 bss_idx; - u8 pad2[63]; + u8 pad2[19]; + u8 random_mac[ETH_ALEN]; + u8 pad3[38]; } mt7921; }; } __packed; @@ -781,6 +815,14 @@ struct mt76_connac_sched_scan_done { __le16 pad; } __packed; +struct bss_info_uni_bss_color { + __le16 tag; + __le16 len; + u8 enable; + u8 bss_color; + u8 rsv[2]; +} __packed; + struct bss_info_uni_he { __le16 tag; __le16 len; @@ -885,15 +927,24 @@ struct mt76_connac_suspend_tlv { u8 pad[5]; } __packed; +enum mt76_sta_info_state { + MT76_STA_INFO_STATE_NONE, + MT76_STA_INFO_STATE_AUTH, + MT76_STA_INFO_STATE_ASSOC +}; + struct mt76_sta_cmd_info { struct ieee80211_sta *sta; struct mt76_wcid *wcid; struct ieee80211_vif *vif; + bool offload_fw; bool enable; + bool newly; int cmd; u8 rcpi; + u8 state; }; #define MT_SKU_POWER_LIMIT 161 @@ -963,18 +1014,23 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable); + struct ieee80211_sta *sta, bool enable, + bool newly); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct mt76_wcid *wcid, void *sta_wtbl, void *wtbl_tlv); +int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, + struct ieee80211_vif *vif, + struct mt76_wcid *wcid, int cmd); void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif, - u8 rcpi); + u8 rcpi, u8 state); void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); @@ -996,8 +1052,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_wcid *wcid, bool enable); -int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy, - struct mt76_sta_cmd_info *info); +int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info); void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band); @@ -1008,6 +1064,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, int mt76_connac_mcu_start_patch(struct mt76_dev *dev); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); +int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy); int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); @@ -1028,6 +1085,9 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend); void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); +int mt76_connac_sta_state_dp(struct mt76_dev *dev, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state); int mt76_connac_mcu_chip_config(struct mt76_dev *dev); int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable); void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index dd66fd12a2e6..cea24213186c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -68,7 +68,7 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) nic_conf1 &= 0xff00; if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) - dev_err(dev->mt76.dev, + dev_dbg(dev->mt76.dev, "driver does not support HW RF ctrl\n"); if (!mt76x02_field_valid(nic_conf0 >> 8)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 5847f943e8da..b795e7245c07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -87,7 +87,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .reconfig_complete = mt76x02_reconfig_complete, }; -static int mt76x0e_register_device(struct mt76x02_dev *dev) +static int mt76x0e_init_hardware(struct mt76x02_dev *dev, bool resume) { int err; @@ -100,9 +100,11 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) if (err < 0) return err; - err = mt76x02_dma_init(dev); - if (err < 0) - return err; + if (!resume) { + err = mt76x02_dma_init(dev); + if (err < 0) + return err; + } err = mt76x0_init_hardware(dev); if (err < 0) @@ -123,6 +125,17 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); + return 0; +} + +static int mt76x0e_register_device(struct mt76x02_dev *dev) +{ + int err; + + err = mt76x0e_init_hardware(dev, false); + if (err < 0) + return err; + err = mt76x0_register_device(dev); if (err < 0) return err; @@ -167,6 +180,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; + mt76_pci_disable_aspm(pdev); + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x0e_ops, &drv_ops); if (!mdev) @@ -220,6 +235,60 @@ mt76x0e_remove(struct pci_dev *pdev) mt76_free_device(mdev); } +#ifdef CONFIG_PM +static int mt76x0e_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + int i; + + mt76_worker_disable(&mdev->tx_worker); + for (i = 0; i < ARRAY_SIZE(mdev->phy.q_tx); i++) + mt76_queue_tx_cleanup(dev, mdev->phy.q_tx[i], true); + for (i = 0; i < ARRAY_SIZE(mdev->q_mcu); i++) + mt76_queue_tx_cleanup(dev, mdev->q_mcu[i], true); + napi_disable(&mdev->tx_napi); + + mt76_for_each_q_rx(mdev, i) + napi_disable(&mdev->napi[i]); + + mt76x02_dma_disable(dev); + mt76x02_mcu_cleanup(dev); + mt76x0_chip_onoff(dev, false, false); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + pci_save_state(pdev); + + return pci_set_power_state(pdev, pci_choose_state(pdev, state)); +} + +static int mt76x0e_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + int err, i; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + mt76_worker_enable(&mdev->tx_worker); + + mt76_for_each_q_rx(mdev, i) { + mt76_queue_rx_reset(dev, i); + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + return mt76x0e_init_hardware(dev, true); +} +#endif /* CONFIG_PM */ + static const struct pci_device_id mt76x0e_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7610) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7630) }, @@ -237,6 +306,10 @@ static struct pci_driver mt76x0e_driver = { .id_table = mt76x0e_device_table, .probe = mt76x0e_probe, .remove = mt76x0e_remove, +#ifdef CONFIG_PM + .suspend = mt76x0e_suspend, + .resume = mt76x0e_resume, +#endif /* CONFIG_PM */ }; module_pci_driver(mt76x0e_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 0da37867cb64..c32e6dc68773 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -34,24 +34,24 @@ mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); if (!key) - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; if (key->keylen > 32) - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; memcpy(key_data, key->key, key->keylen); switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MT76X02_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MT76X02_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MT76X02_CIPHER_TKIP; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MT76X02_CIPHER_AES_CCMP; default: - return MT_CIPHER_NONE; + return MT76X02_CIPHER_NONE; } } @@ -63,7 +63,7 @@ int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, u32 val; cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) + if (cipher == MT76X02_CIPHER_NONE && key) return -EOPNOTSUPP; val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); @@ -91,10 +91,10 @@ void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx, eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4); pn = (u64)eiv << 16; - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MT76X02_CIPHER_TKIP) { pn |= (iv >> 16) & 0xff; pn |= (iv & 0xff) << 8; - } else if (cipher >= MT_CIPHER_AES_CCMP) { + } else if (cipher >= MT76X02_CIPHER_AES_CCMP) { pn |= iv & 0xffff; } else { return; @@ -112,7 +112,7 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, u64 pn; cipher = mt76x02_mac_get_key_info(key, key_data); - if (cipher == MT_CIPHER_NONE && key) + if (cipher == MT76X02_CIPHER_NONE && key) return -EOPNOTSUPP; mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); @@ -126,16 +126,16 @@ int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, pn = atomic64_read(&key->tx_pn); iv_data[3] = key->keyidx << 6; - if (cipher >= MT_CIPHER_TKIP) { + if (cipher >= MT76X02_CIPHER_TKIP) { iv_data[3] |= 0x20; put_unaligned_le32(pn >> 16, &iv_data[4]); } - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MT76X02_CIPHER_TKIP) { iv_data[0] = (pn >> 8) & 0xff; iv_data[1] = (iv_data[0] | 0x20) & 0x7f; iv_data[2] = pn & 0xff; - } else if (cipher >= MT_CIPHER_AES_CCMP) { + } else if (cipher >= MT76X02_CIPHER_AES_CCMP) { put_unaligned_le16((pn & 0xffff), &iv_data[0]); } } @@ -1022,12 +1022,12 @@ void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]); } -void mt76x02_update_channel(struct mt76_dev *mdev) +void mt76x02_update_channel(struct mt76_phy *mphy) { - struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76); struct mt76_channel_state *state; - state = mdev->phy.chan_state; + state = mphy->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); spin_lock_bh(&dev->mt76.cc_lock); @@ -1169,7 +1169,7 @@ void mt76x02_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); - mt76_update_survey(&dev->mt76); + mt76_update_survey(&dev->mphy); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 0cfbaca50210..5dc6c834111e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -195,7 +195,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, struct ieee80211_sta *sta, int len); void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq); void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); -void mt76x02_update_channel(struct mt76_dev *mdev); +void mt76x02_update_channel(struct mt76_phy *mphy); void mt76x02_mac_work(struct work_struct *work); void mt76x02_mac_cc_reset(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index 3e722276b5c2..fa7872ac22bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -692,15 +692,15 @@ struct mt76_wcid_key { } __packed __aligned(4); enum mt76x02_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CKIP40, - MT_CIPHER_CKIP104, - MT_CIPHER_CKIP128, - MT_CIPHER_WAPI, + MT76X02_CIPHER_NONE, + MT76X02_CIPHER_WEP40, + MT76X02_CIPHER_WEP104, + MT76X02_CIPHER_TKIP, + MT76X02_CIPHER_AES_CCMP, + MT76X02_CIPHER_CKIP40, + MT76X02_CIPHER_CKIP104, + MT76X02_CIPHER_CKIP128, + MT76X02_CIPHER_WAPI, }; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 02db5d66735d..ccdbab341271 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -7,24 +7,18 @@ #include <linux/module.h> #include "mt76x02.h" -#define CCK_RATE(_idx, _rate) { \ +#define MT76x02_CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ } -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - struct ieee80211_rate mt76x02_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), + MT76x02_CCK_RATE(0, 10), + MT76x02_CCK_RATE(1, 20), + MT76x02_CCK_RATE(2, 55), + MT76x02_CCK_RATE(3, 110), OFDM_RATE(0, 60), OFDM_RATE(1, 90), OFDM_RATE(2, 120), diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile index 40c8061787e9..80e49244348e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7915E) += mt7915e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 6a8ddeeecbe9..64048243e34b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -3,6 +3,7 @@ #include "mt7915.h" #include "eeprom.h" +#include "mcu.h" /** global debugfs **/ @@ -16,7 +17,7 @@ mt7915_implicit_txbf_set(void *data, u64 val) dev->ibf = !!val; - return mt7915_mcu_set_txbf_type(dev); + return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static int @@ -147,6 +148,9 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) { struct mt7915_dev *dev = s->private; bool ext_phy = phy != &dev->phy; + static const char * const bw[] = { + "BW20", "BW40", "BW80", "BW160" + }; int cnt; if (!phy) @@ -164,11 +168,16 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) seq_puts(s, "Tx Beamformer Rx feedback statistics: "); cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy)); - seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n", + seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld, ", FIELD_GET(MT_ETBF_RX_FB_ALL, cnt), FIELD_GET(MT_ETBF_RX_FB_HE, cnt), FIELD_GET(MT_ETBF_RX_FB_VHT, cnt), FIELD_GET(MT_ETBF_RX_FB_HT, cnt)); + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy)); + seq_printf(s, "%s, NC: %ld, NR: %ld\n", + bw[FIELD_GET(MT_ETBF_RX_FB_BW, cnt)], + FIELD_GET(MT_ETBF_RX_FB_NC, cnt), + FIELD_GET(MT_ETBF_RX_FB_NR, cnt)); /* Tx Beamformee Rx NDPA & Tx feedback report */ cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy)); @@ -204,7 +213,7 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file); /* Tx amsdu info */ - seq_puts(file, "Tx MSDU stat:\n"); + seq_puts(file, "Tx MSDU statistics:\n"); for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) { stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); n += stat[i]; @@ -224,18 +233,6 @@ mt7915_tx_stats_show(struct seq_file *file, void *data) DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats); -static int mt7915_read_temperature(struct seq_file *s, void *data) -{ - struct mt7915_dev *dev = dev_get_drvdata(s->private); - int temp; - - /* cpu */ - temp = mt7915_mcu_get_temperature(dev, 0); - seq_printf(s, "Temperature: %d\n", temp); - - return 0; -} - static int mt7915_queues_acq(struct seq_file *s, void *data) { @@ -307,54 +304,23 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy) "RU26", "RU52", "RU106", "RU242/SU20", "RU484/SU40", "RU996/SU80", "RU2x996/SU160" }; - struct mt7915_dev *dev = dev_get_drvdata(s->private); - bool ext_phy = phy != &dev->phy; - u32 reg_base; - int i, idx = 0; + s8 txpower[MT7915_SKU_RATE_NUM], *buf; + int i; if (!phy) return; - reg_base = MT_TMAC_FP0R0(ext_phy); - seq_printf(s, "\nBand %d\n", ext_phy); + seq_printf(s, "\nBand %d\n", phy != &phy->dev->phy); - for (i = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { - u8 cnt, mcs_num = mt7915_sku_group_len[i]; - s8 txpower[12]; - int j; + mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); + for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { + u8 mcs_num = mt7915_sku_group_len[i]; - if (i == SKU_HT_BW20 || i == SKU_HT_BW40) { - mcs_num = 8; - } else if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) { + if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) mcs_num = 10; - } else if (i == SKU_HE_RU26) { - reg_base = MT_TMAC_FP0R18(ext_phy); - idx = 0; - } - - for (j = 0, cnt = 0; j < DIV_ROUND_UP(mcs_num, 4); j++) { - u32 val; - - if (i == SKU_VHT_BW160 && idx == 60) { - reg_base = MT_TMAC_FP0R15(ext_phy); - idx = 0; - } - - val = mt76_rr(dev, reg_base + (idx / 4) * 4); - - if (idx && idx % 4) - val >>= (idx % 4) * 8; - - while (val > 0 && cnt < mcs_num) { - s8 pwr = FIELD_GET(MT_TMAC_FP_MASK, val); - - txpower[cnt++] = pwr; - val >>= 8; - idx++; - } - } - mt76_seq_puts_array(s, sku_group_name[i], txpower, mcs_num); + mt76_seq_puts_array(s, sku_group_name[i], buf, mcs_num); + buf += mt7915_sku_group_len[i]; } } @@ -390,8 +356,6 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) debugfs_create_file("radar_trigger", 0200, dir, dev, &fops_radar_trigger); debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger); - debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, - mt7915_read_temperature); debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, mt7915_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 11d0b760abd7..9182568f95c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -19,39 +19,6 @@ int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc) return 0; } -void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - __le32 *rxd = (__le32 *)skb->data; - enum rx_pkt_type type; - - type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); - - switch (type) { - case PKT_TYPE_TXRX_NOTIFY: - mt7915_mac_tx_free(dev, skb); - break; - case PKT_TYPE_RX_EVENT: - mt7915_mcu_rx_event(dev, skb); - break; -#ifdef CONFIG_NL80211_TESTMODE - case PKT_TYPE_TXRXV: - mt7915_mac_fill_rx_vector(dev, skb); - break; -#endif - case PKT_TYPE_NORMAL: - if (!mt7915_mac_fill_rx(dev, skb)) { - mt76_rx(&dev->mt76, q, skb); - return; - } - fallthrough; - default: - dev_kfree_skb(skb); - break; - } -} - static void mt7915_tx_cleanup(struct mt7915_dev *dev) { @@ -112,8 +79,6 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev) int mt7915_dma_init(struct mt7915_dev *dev) { - /* Increase buffer size to receive large VHT/HE MPDUs */ - int rx_buf_size = MT_RX_BUF_SIZE * 2; u32 hif1_ofs = 0; int ret; @@ -177,28 +142,28 @@ int mt7915_dma_init(struct mt7915_dev *dev) /* event from WM */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; /* event from WA */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; /* rx data queue */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT7915_RXQ_BAND0, MT7915_RX_RING_SIZE, - rx_buf_size, MT_RX_DATA_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); if (ret) return ret; if (dev->dbdc_support) { ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT], MT7915_RXQ_BAND1, MT7915_RX_RING_SIZE, - rx_buf_size, + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE + hif1_ofs); if (ret) return ret; @@ -207,7 +172,7 @@ int mt7915_dma_init(struct mt7915_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT_WA], MT7915_RXQ_MCU_WA_EXT, MT7915_RX_MCU_RING_SIZE, - rx_buf_size, + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE + hif1_ofs); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 8ededf2e5279..ee3d64434821 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -4,22 +4,12 @@ #include "mt7915.h" #include "eeprom.h" -static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset) -{ - u8 *data = dev->mt76.eeprom.data; - - if (data[offset] == 0xff && !dev->flash_mode) - mt7915_mcu_get_eeprom(dev, offset); - - return data[offset]; -} - static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) { struct mt76_dev *mdev = &dev->mt76; - u32 val; + u8 *eeprom = mdev->eeprom.data; + u32 val = eeprom[MT_EE_DO_PRE_CAL]; - val = mt7915_eeprom_read(dev, MT_EE_DO_PRE_CAL); if (val != (MT_EE_WIFI_CAL_DPD | MT_EE_WIFI_CAL_GROUP)) return 0; @@ -43,7 +33,13 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) dev->flash_mode = true; ret = mt7915_eeprom_load_precal(dev); } else { - memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE); + u32 block_num, i; + + block_num = DIV_ROUND_UP(MT7915_EEPROM_SIZE, + MT7915_EEPROM_BLOCK_SIZE); + for (i = 0; i < block_num; i++) + mt7915_mcu_get_eeprom(dev, + i * MT7915_EEPROM_BLOCK_SIZE); } return ret; @@ -52,10 +48,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) static int mt7915_check_eeprom(struct mt7915_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; - u16 val; - - mt7915_eeprom_read(dev, MT_EE_CHIP_ID); - val = get_unaligned_le16(eeprom); + u16 val = get_unaligned_le16(eeprom); switch (val) { case 0x7915: @@ -69,9 +62,10 @@ void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; + u8 *eeprom = dev->mt76.eeprom.data; u32 val; - val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy); + val = eeprom[MT_EE_WIFI_CONF + ext_phy]; val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support) val = ext_phy ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; @@ -143,6 +137,7 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx) { + u8 *eeprom = dev->mt76.eeprom.data; int index, target_power; bool tssi_on; @@ -153,18 +148,18 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, if (chan->band == NL80211_BAND_2GHZ) { index = MT_EE_TX0_POWER_2G + chain_idx * 3; - target_power = mt7915_eeprom_read(dev, index); + target_power = eeprom[index]; if (!tssi_on) - target_power += mt7915_eeprom_read(dev, index + 1); + target_power += eeprom[index + 1]; } else { int group = mt7915_get_channel_group(chan->hw_value); index = MT_EE_TX0_POWER_5G + chain_idx * 12; - target_power = mt7915_eeprom_read(dev, index + group); + target_power = eeprom[index + group]; if (!tssi_on) - target_power += mt7915_eeprom_read(dev, index + 8); + target_power += eeprom[index + 8]; } return target_power; @@ -172,13 +167,14 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band) { + u8 *eeprom = dev->mt76.eeprom.data; u32 val; s8 delta; if (band == NL80211_BAND_2GHZ) - val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_2G); + val = eeprom[MT_EE_RATE_DELTA_2G]; else - val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_5G); + val = eeprom[MT_EE_RATE_DELTA_5G]; if (!(val & MT_EE_RATE_DELTA_EN)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 033fb592bdf0..a43389a41800 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -33,7 +33,7 @@ enum mt7915_eeprom_field { #define MT_EE_WIFI_CAL_GROUP BIT(0) #define MT_EE_WIFI_CAL_DPD GENMASK(2, 1) #define MT_EE_CAL_UNIT 1024 -#define MT_EE_CAL_GROUP_SIZE (44 * MT_EE_CAL_UNIT) +#define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16) #define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT) #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) @@ -99,12 +99,15 @@ static inline bool mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) { u8 *eep = dev->mt76.eeprom.data; + u8 val = eep[MT_EE_WIFI_CONF + 7]; - /* TODO: DBDC */ - if (band == NL80211_BAND_5GHZ) - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_5G; + if (band == NL80211_BAND_2GHZ) + return val & MT_EE_WIFI_CONF7_TSSI0_2G; + + if (dev->dbdc_support) + return val & MT_EE_WIFI_CONF7_TSSI1_5G; else - return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_2G; + return val & MT_EE_WIFI_CONF7_TSSI0_5G; } extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 822f3aa6bb8b..4798d6344305 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -2,39 +2,14 @@ /* Copyright (C) 2020 MediaTek Inc. */ #include <linux/etherdevice.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/thermal.h> #include "mt7915.h" #include "mac.h" #include "mcu.h" #include "eeprom.h" -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7915_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, @@ -67,6 +42,117 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static ssize_t mt7915_thermal_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7915_phy *phy = dev_get_drvdata(dev); + int temperature; + + temperature = mt7915_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); +} + +static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp, + NULL, 0); + +static struct attribute *mt7915_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7915_hwmon); + +static int +mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7915_THERMAL_THROTTLE_MAX; + + return 0; +} + +static int +mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7915_phy *phy = cdev->devdata; + + *state = phy->throttle_state; + + return 0; +} + +static int +mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7915_phy *phy = cdev->devdata; + int ret; + + if (state > MT7915_THERMAL_THROTTLE_MAX) + return -EINVAL; + + if (state == phy->throttle_state) + return 0; + + ret = mt7915_mcu_set_thermal_throttling(phy, state); + if (ret) + return ret; + + phy->throttle_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7915_thermal_ops = { + .get_max_state = mt7915_thermal_get_max_throttle_state, + .get_cur_state = mt7915_thermal_get_cur_throttle_state, + .set_cur_state = mt7915_thermal_set_cur_throttle_state, +}; + +static void mt7915_unregister_thermal(struct mt7915_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + + if (!phy->cdev) + return; + + sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + thermal_cooling_device_unregister(phy->cdev); +} + +static int mt7915_thermal_init(struct mt7915_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct thermal_cooling_device *cdev; + struct device *hwmon; + + cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy, + &mt7915_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + "cooling_device") < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, + wiphy_name(wiphy), phy, + mt7915_hwmon_groups); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} + static void mt7915_init_txpower(struct mt7915_dev *dev, struct ieee80211_supported_band *sband) @@ -201,7 +287,6 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536); @@ -228,20 +313,19 @@ static int mt7915_txbf_init(struct mt7915_dev *dev) { int ret; - if (dev->dbdc_support) { - ret = mt7915_mcu_set_txbf_module(dev); + ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE); if (ret) return ret; } /* trigger sounding packets */ - ret = mt7915_mcu_set_txbf_sounding(dev); + ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON); if (ret) return ret; /* enable eBF */ - return mt7915_mcu_set_txbf_type(dev); + return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static int mt7915_register_ext_phy(struct mt7915_dev *dev) @@ -281,8 +365,12 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev) if (ret) goto error; - ret = mt76_register_phy(mphy, true, mt7915_rates, - ARRAY_SIZE(mt7915_rates)); + ret = mt76_register_phy(mphy, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); + if (ret) + goto error; + + ret = mt7915_thermal_init(phy); if (ret) goto error; @@ -480,6 +568,9 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, if (nss < 2) return; + /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ + elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; + if (vif != NL80211_IFTYPE_AP) return; @@ -493,9 +584,6 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap, c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] |= c; - - /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ - elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; } static void @@ -579,8 +667,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, switch (i) { case NL80211_IFTYPE_AP: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_RES; he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= @@ -594,8 +680,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; break; case NL80211_IFTYPE_STATION: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_REQ; he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; @@ -690,6 +774,7 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev) if (!phy) return; + mt7915_unregister_thermal(phy); mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); } @@ -731,8 +816,12 @@ int mt7915_register_device(struct mt7915_dev *dev) dev->mt76.test_ops = &mt7915_testmode_ops; #endif - ret = mt76_register_device(&dev->mt76, true, mt7915_rates, - ARRAY_SIZE(mt7915_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); + if (ret) + return ret; + + ret = mt7915_thermal_init(&dev->phy); if (ret) return ret; @@ -748,10 +837,12 @@ int mt7915_register_device(struct mt7915_dev *dev) void mt7915_unregister_device(struct mt7915_dev *dev) { mt7915_unregister_ext_phy(dev); + mt7915_unregister_thermal(&dev->phy); mt76_unregister_device(&dev->mt76); mt7915_mcu_exit(dev); mt7915_tx_token_put(dev); mt7915_dma_cleanup(dev); + tasklet_disable(&dev->irq_tasklet); mt76_free_device(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 7a9759fb79d8..2462704094b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -307,7 +307,8 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, } } -int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) +static int +mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -412,14 +413,27 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) @@ -610,9 +624,10 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return 0; } -#ifdef CONFIG_NL80211_TESTMODE -void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) +static void +mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) { +#ifdef CONFIG_NL80211_TESTMODE struct mt7915_phy *phy = &dev->phy; __le32 *rxd = (__le32 *)skb->data; __le32 *rxv_hdr = rxd + 2; @@ -650,10 +665,10 @@ void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) phy->test.last_freq_offset = foe; phy->test.last_snr = snr; +#endif dev_kfree_skb(skb); } -#endif static void mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, @@ -885,7 +900,7 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi, } void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, + struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, bool beacon) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -944,7 +959,12 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, txwi[3] = cpu_to_le32(val); txwi[4] = 0; - txwi[5] = 0; + + val = FIELD_PREP(MT_TXD5_PID, pid); + if (pid >= MT_PACKET_ID_FIRST) + val |= MT_TXD5_TX_STATUS_HOST; + txwi[5] = cpu_to_le32(val); + txwi[6] = 0; txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; @@ -984,11 +1004,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; - struct mt76_tx_cb *cb = mt76_tx_skb_cb(tx_info->skb); struct mt76_txwi_cache *t; struct mt7915_txp *txp; int id, i, nbuf = tx_info->nbuf - 1; u8 *txwi = (u8 *)txwi_ptr; + int pid; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; @@ -996,10 +1016,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; - mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - false); + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - cb->wcid = wcid->idx; + mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, + false); txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { @@ -1071,54 +1091,7 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) } static void -mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 stat, - struct list_head *free_list) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_status status = { - .sta = sta, - .info = info, - .skb = skb, - .free_list = free_list, - }; - struct ieee80211_hw *hw; - - if (sta) { - struct mt7915_sta *msta; - - msta = (struct mt7915_sta *)sta->drv_priv; - status.rate = &msta->stats.tx_rate; - } - -#ifdef CONFIG_NL80211_TESTMODE - if (mt76_is_testmode_skb(mdev, skb, &hw)) { - struct mt7915_phy *phy = mt7915_hw_phy(hw); - struct ieee80211_vif *vif = phy->monitor_vif; - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - - mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb); - return; - } -#endif - - hw = mt76_tx_status_get_hw(mdev, skb); - - if (info->flags & IEEE80211_TX_CTL_AMPDU) - info->flags |= IEEE80211_TX_STAT_AMPDU; - - if (stat) - ieee80211_tx_info_clear_status(info); - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - - info->status.tx_time = 0; - ieee80211_tx_status_ext(hw, &status); -} - -void mt7915_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *t) +mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { struct mt7915_txp *txp; int i; @@ -1129,7 +1102,39 @@ void mt7915_txp_skb_unmap(struct mt76_dev *dev, le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); } -void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) +static void +mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t, + struct ieee80211_sta *sta, struct list_head *free_list) +{ + struct mt76_dev *mdev = &dev->mt76; + struct mt76_wcid *wcid; + __le32 *txwi; + u16 wcid_idx; + + mt7915_txp_skb_unmap(mdev, t); + if (!t->skb) + goto out; + + txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); + if (sta) { + wcid = (struct mt76_wcid *)sta->drv_priv; + wcid_idx = wcid->idx; + + if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7915_tx_check_aggr(sta, txwi); + } else { + wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1])); + } + + __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); + +out: + t->skb = NULL; + mt76_put_txwi(mdev, t); +} + +static void +mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data; struct mt76_dev *mdev = &dev->mt76; @@ -1194,28 +1199,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) if (!txwi) continue; - mt7915_txp_skb_unmap(mdev, txwi); - if (txwi->skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb); - void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi); - - if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7915_tx_check_aggr(sta, txwi_ptr); - - if (sta && !info->tx_time_est) { - struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; - int pending; - - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } - - mt7915_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list); - txwi->skb = NULL; - } - - mt76_put_txwi(mdev, txwi); + mt7915_txwi_free(dev, txwi, sta, &free_list); } mt7915_mac_sta_poll(dev); @@ -1233,6 +1217,120 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb) } } +static bool +mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid, + __le32 *txs_data) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct sk_buff_head list; + struct sk_buff *skb; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out; + + info = IEEE80211_SKB_CB(skb); + if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK))) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + mt76_tx_status_skb_done(mdev, skb, &list); + +out: + mt76_tx_status_unlock(mdev, &list); + + return !!skb; +} + +static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) +{ + struct mt7915_sta *msta = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + u16 wcidx; + u32 txs; + u8 pid; + + txs = le32_to_cpu(txs_data[0]); + if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) + return; + + txs = le32_to_cpu(txs_data[2]); + wcidx = FIELD_GET(MT_TXS2_WCID, txs); + + txs = le32_to_cpu(txs_data[3]); + pid = FIELD_GET(MT_TXS3_PID, txs); + + if (pid < MT_PACKET_ID_FIRST) + return; + + if (wcidx >= MT7915_WTBL_SIZE) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + if (!wcid) + goto out; + + mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data); + + if (!wcid->sta) + goto out; + + msta = container_of(wcid, struct mt7915_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + +out: + rcu_read_unlock(); +} + +void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + __le32 *end = (__le32 *)&skb->data[skb->len]; + enum rx_pkt_type type; + + type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0])); + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + mt7915_mac_tx_free(dev, skb); + break; + case PKT_TYPE_RX_EVENT: + mt7915_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXRXV: + mt7915_mac_fill_rx_vector(dev, skb); + break; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) + mt7915_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; + case PKT_TYPE_NORMAL: + if (!mt7915_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + fallthrough; + default: + dev_kfree_skb(skb); + break; + } +} + void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { struct mt7915_dev *dev; @@ -1254,15 +1352,8 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) e->skb = t ? t->skb : NULL; } - if (e->skb) { - struct mt76_tx_cb *cb = mt76_tx_skb_cb(e->skb); - struct mt76_wcid *wcid; - - wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]); - - mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0, - NULL); - } + if (e->skb) + mt76_tx_complete_skb(mdev, e->wcid, e->skb); } void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) @@ -1296,14 +1387,10 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy) memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2); /* reset airtime counters */ - mt76_rr(dev, MT_MIB_SDR9(ext_phy)); - mt76_rr(dev, MT_MIB_SDR36(ext_phy)); - mt76_rr(dev, MT_MIB_SDR37(ext_phy)); - - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(ext_phy), - MT_WF_RMAC_MIB_RXTIME_CLR); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(ext_phy), MT_WF_RMAC_MIB_RXTIME_CLR); + + mt7915_mcu_get_chan_mib_info(phy, true); } void mt7915_mac_set_timing(struct mt7915_phy *phy) @@ -1397,53 +1484,24 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) return sum / n; } -static void -mt7915_phy_update_channel(struct mt76_phy *mphy, int idx) +void mt7915_update_channel(struct mt76_phy *mphy) { - struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76); struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; - struct mt76_channel_state *state; - u64 busy_time, tx_time, rx_time, obss_time; + struct mt76_channel_state *state = mphy->chan_state; + bool ext_phy = phy != &phy->dev->phy; int nf; - busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), - MT_MIB_SDR9_BUSY_MASK); - tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), - MT_MIB_SDR36_TXTIME_MASK); - rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), - MT_MIB_SDR37_RXTIME_MASK); - obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), - MT_MIB_OBSSTIME_MASK); + mt7915_mcu_get_chan_mib_info(phy, false); - nf = mt7915_phy_get_nf(phy, idx); + nf = mt7915_phy_get_nf(phy, ext_phy); if (!phy->noise) phy->noise = nf << 4; else if (nf) phy->noise += nf - (phy->noise >> 4); - state = mphy->chan_state; - state->cc_busy += busy_time; - state->cc_tx += tx_time; - state->cc_rx += rx_time + obss_time; - state->cc_bss_rx += rx_time; state->noise = -(phy->noise >> 4); } -void mt7915_update_channel(struct mt76_dev *mdev) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - - mt7915_phy_update_channel(&mdev->phy, 0); - if (mdev->phy2) - mt7915_phy_update_channel(mdev->phy2, 1); - - /* reset obss airtime */ - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); - if (mdev->phy2) - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(1), - MT_WF_RMAC_MIB_RXTIME_CLR); -} - static bool mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) { @@ -1530,14 +1588,18 @@ mt7915_dma_reset(struct mt7915_dev *dev) mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_set(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN); + MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); if (dev->hif2) { mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, (MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN)); mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, (MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN)); + MT_WFDMA1_GLO_CFG_RX_DMA_EN | + MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA1_GLO_CFG_OMIT_RX_INFO)); } } @@ -1548,14 +1610,7 @@ void mt7915_tx_token_put(struct mt7915_dev *dev) spin_lock_bh(&dev->mt76.token_lock); idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7915_txp_skb_unmap(&dev->mt76, txwi); - if (txwi->skb) { - struct ieee80211_hw *hw; - - hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb); - ieee80211_free_txskb(hw, txwi->skb); - } - mt76_put_txwi(&dev->mt76, txwi); + mt7915_txwi_free(dev, txwi, NULL, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); @@ -1588,11 +1643,6 @@ void mt7915_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &phy2->mt76->state); cancel_delayed_work_sync(&phy2->mt76->mac_work); } - /* lock/unlock all queues to ensure that no tx is pending */ - mt76_txq_schedule_all(&dev->mphy); - if (ext_phy) - mt76_txq_schedule_all(ext_phy); - mt76_worker_disable(&dev->mt76.tx_worker); napi_disable(&dev->mt76.napi[0]); napi_disable(&dev->mt76.napi[1]); @@ -1618,10 +1668,6 @@ void mt7915_mac_reset_work(struct work_struct *work) if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); - mt76_worker_enable(&dev->mt76.tx_worker); - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - napi_enable(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[0]); @@ -1630,14 +1676,20 @@ void mt7915_mac_reset_work(struct work_struct *work) napi_enable(&dev->mt76.napi[2]); napi_schedule(&dev->mt76.napi[2]); + tasklet_schedule(&dev->irq_tasklet); + + mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); + mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); + + mt76_worker_enable(&dev->mt76.tx_worker); + + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) ieee80211_wake_queues(ext_phy->hw); - mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); - mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); - mutex_unlock(&dev->mt76.mutex); mt7915_update_beacons(dev); @@ -1651,7 +1703,7 @@ void mt7915_mac_reset_work(struct work_struct *work) } static void -mt7915_mac_update_mib_stats(struct mt7915_phy *phy) +mt7915_mac_update_stats(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; @@ -1733,8 +1785,10 @@ void mt7915_mac_sta_rc_work(struct work_struct *work) if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | IEEE80211_RC_NSS_CHANGED | - IEEE80211_RC_BW_CHANGED)) + IEEE80211_RC_BW_CHANGED)) { + mt7915_mcu_add_he(dev, vif, sta); mt7915_mcu_add_rate_ctrl(dev, vif, sta); + } if (changed & IEEE80211_RC_SMPS_CHANGED) mt7915_mcu_add_smps(dev, vif, sta); @@ -1756,11 +1810,11 @@ void mt7915_mac_work(struct work_struct *work) mutex_lock(&mphy->dev->mutex); - mt76_update_survey(mphy->dev); + mt76_update_survey(mphy); if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; - mt7915_mac_update_mib_stats(phy); + mt7915_mac_update_stats(phy); } if (++phy->sta_work_count == 10) { @@ -1770,6 +1824,8 @@ void mt7915_mac_work(struct work_struct *work) mutex_unlock(&mphy->dev->mutex); + mt76_tx_status_check(mphy->dev, NULL, false); + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7915_WATCHDOG_TIME); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index 0f929fb53027..eb1885f4bd8e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -304,6 +304,62 @@ struct mt7915_tx_free { /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) +#define MT_TXS0_FIXED_RATE BIT(31) +#define MT_TXS0_BW GENMASK(30, 29) +#define MT_TXS0_TID GENMASK(28, 26) +#define MT_TXS0_AMPDU BIT(25) +#define MT_TXS0_TXS_FORMAT GENMASK(24, 23) +#define MT_TXS0_BA_ERROR BIT(22) +#define MT_TXS0_PS_FLAG BIT(21) +#define MT_TXS0_TXOP_TIMEOUT BIT(20) +#define MT_TXS0_BIP_ERROR BIT(19) + +#define MT_TXS0_QUEUE_TIMEOUT BIT(18) +#define MT_TXS0_RTS_TIMEOUT BIT(17) +#define MT_TXS0_ACK_TIMEOUT BIT(16) +#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) + +#define MT_TXS0_TX_STATUS_HOST BIT(15) +#define MT_TXS0_TX_STATUS_MCU BIT(14) +#define MT_TXS0_TX_RATE GENMASK(13, 0) + +#define MT_TXS1_SEQNO GENMASK(31, 20) +#define MT_TXS1_RESP_RATE GENMASK(19, 16) +#define MT_TXS1_RXV_SEQNO GENMASK(15, 8) +#define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) + +#define MT_TXS2_BF_STATUS GENMASK(31, 30) +#define MT_TXS2_LAST_TX_RATE GENMASK(29, 27) +#define MT_TXS2_SHARED_ANTENNA BIT(26) +#define MT_TXS2_WCID GENMASK(25, 16) +#define MT_TXS2_TX_DELAY GENMASK(15, 0) + +#define MT_TXS3_PID GENMASK(31, 24) +#define MT_TXS3_ANT_ID GENMASK(23, 0) + +#define MT_TXS4_TIMESTAMP GENMASK(31, 0) + +#define MT_TXS5_F0_FINAL_MPDU BIT(31) +#define MT_TXS5_F0_QOS BIT(30) +#define MT_TXS5_F0_TX_COUNT GENMASK(29, 25) +#define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0) +#define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24) +#define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0) + +#define MT_TXS6_F0_NOISE_3 GENMASK(31, 24) +#define MT_TXS6_F0_NOISE_2 GENMASK(23, 16) +#define MT_TXS6_F0_NOISE_1 GENMASK(15, 8) +#define MT_TXS6_F0_NOISE_0 GENMASK(7, 0) +#define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24) +#define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0) + +#define MT_TXS7_F0_RCPI_3 GENMASK(31, 24) +#define MT_TXS7_F0_RCPI_2 GENMASK(23, 16) +#define MT_TXS7_F0_RCPI_1 GENMASK(15, 8) +#define MT_TXS7_F0_RCPI_0 GENMASK(7, 0) +#define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24) +#define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0) + struct mt7915_dfs_pulse { u32 max_width; /* us */ int max_pwr; /* dbm */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index e5bd687546b6..c25f8da590dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -139,12 +139,6 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask) if (type != NL80211_IFTYPE_STATION) break; - /* next, try to find a free repeater entry for the sta */ - i = get_free_idx(mask >> REPEATER_BSSID_START, 0, - REPEATER_BSSID_MAX - REPEATER_BSSID_START); - if (i) - return i + 32 - 1; - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; @@ -172,6 +166,22 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask) return -1; } +static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + int i; + + for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { + mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); + memset(mvif->bitrate_mask.control[i].ht_mcs, GENMASK(7, 0), + sizeof(mvif->bitrate_mask.control[i].ht_mcs)); + memset(mvif->bitrate_mask.control[i].vht_mcs, GENMASK(15, 0), + sizeof(mvif->bitrate_mask.control[i].vht_mcs)); + memset(mvif->bitrate_mask.control[i].he_mcs, GENMASK(15, 0), + sizeof(mvif->bitrate_mask.control[i].he_mcs)); + } +} + static int mt7915_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -241,6 +251,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, vif->offload_flags = 0; vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + mt7915_init_bitrate_mask(vif); + out: mutex_unlock(&dev->mt76.mutex); @@ -798,7 +810,8 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; /* TSF software read */ - mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE); + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); @@ -827,7 +840,34 @@ mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); /* TSF software overwrite */ - mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE); + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_WRITE); + + mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + s64 timestamp) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = mt7915_hw_dev(hw); + struct mt7915_phy *phy = mt7915_hw_phy(hw); + bool band = phy != &dev->phy; + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + u16 n; + + mutex_lock(&dev->mt76.mutex); + + n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx; + mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); + /* TSF software adjust*/ + mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, + MT_LPON_TCR_SW_ADJUST); mutex_unlock(&dev->mt76.mutex); } @@ -911,17 +951,15 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } -static void -mt7915_sta_rc_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - u32 changed) +static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) { - struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = msta->vif->phy->dev; + struct ieee80211_hw *hw = msta->vif->phy->mt76->hw; + u32 *changed = data; spin_lock_bh(&dev->sta_poll_lock); - msta->stats.changed |= changed; + msta->stats.changed |= *changed; if (list_empty(&msta->rc_list)) list_add_tail(&msta->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->sta_poll_lock); @@ -929,6 +967,39 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &dev->rc_work); } +static void mt7915_sta_rc_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + u32 changed) +{ + mt7915_sta_rc_work(&changed, sta); +} + +static int +mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + enum nl80211_band band = mvif->phy->mt76->chandef.chan->band; + u32 changed; + + if (mask->control[band].gi == NL80211_TXRATE_FORCE_LGI) + return -EINVAL; + + changed = IEEE80211_RC_SUPP_RATES_CHANGED; + mvif->bitrate_mask = *mask; + + /* Update firmware rate control to add a boundary on top of table + * to limit the rate selection for each peer, so when set bitrates + * vht-mcs-5 1:9, which actually means nss = 1 mcs = 0~9. This only + * applies to data frames as for the other mgmt, mcast, bcast still + * use legacy rates as it is. + */ + ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed); + + return 0; +} + static void mt7915_sta_set_4addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -987,9 +1058,11 @@ const struct ieee80211_ops mt7915_ops = { .get_stats = mt7915_get_stats, .get_tsf = mt7915_get_tsf, .set_tsf = mt7915_set_tsf, + .offset_tsf = mt7915_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, + .set_bitrate_mask = mt7915_set_bitrate_mask, .set_coverage_class = mt7915_set_coverage_class, .sta_statistics = mt7915_sta_statistics, .sta_set_4addr = mt7915_sta_set_4addr, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b3f14ff67c5a..863aa18b3024 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -88,28 +88,28 @@ struct mt7915_fw_region { #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) -static enum mt7915_cipher_type +static enum mcu_cipher_type mt7915_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; + return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; + return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; + return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; + return MCU_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; + return MCU_CIPHER_WAPI; default: return MT_CIPHER_NONE; } @@ -147,10 +147,10 @@ mt7915_get_he_phy_cap(struct mt7915_phy *phy, struct ieee80211_vif *vif) } static u8 -mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +mt7915_get_phy_mode(struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - enum nl80211_band band = mphy->chandef.chan->band; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + enum nl80211_band band = mvif->phy->mt76->chandef.chan->band; struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; const struct ieee80211_sta_he_cap *he_cap; @@ -163,7 +163,7 @@ mt7915_get_phy_mode(struct mt76_phy *mphy, struct ieee80211_vif *vif, } else { struct ieee80211_supported_band *sband; - sband = mphy->hw->wiphy->bands[band]; + sband = mvif->phy->mt76->hw->wiphy->bands[band]; ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; @@ -209,6 +209,112 @@ mt7915_mcu_get_sta_nss(u16 mcs_map) return nss - 1; } +static void +mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, + const u16 *mask) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct cfg80211_chan_def *chandef = &msta->vif->phy->mt76->chandef; + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + u16 mcs_map; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_80P80: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80p80); + break; + case NL80211_CHAN_WIDTH_160: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_160); + break; + default: + mcs_map = le16_to_cpu(sta->he_cap.he_mcs_nss_supp.rx_mcs_80); + break; + } + + for (nss = 0; nss < max_nss; nss++) { + int mcs; + + switch ((mcs_map >> (2 * nss)) & 0x3) { + case IEEE80211_HE_MCS_SUPPORT_0_11: + mcs = GENMASK(11, 0); + break; + case IEEE80211_HE_MCS_SUPPORT_0_9: + mcs = GENMASK(9, 0); + break; + case IEEE80211_HE_MCS_SUPPORT_0_7: + mcs = GENMASK(7, 0); + break; + default: + mcs = 0; + } + + mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1; + + switch (mcs) { + case 0 ... 7: + mcs = IEEE80211_HE_MCS_SUPPORT_0_7; + break; + case 8 ... 9: + mcs = IEEE80211_HE_MCS_SUPPORT_0_9; + break; + case 10 ... 11: + mcs = IEEE80211_HE_MCS_SUPPORT_0_11; + break; + default: + mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; + break; + } + mcs_map &= ~(0x3 << (nss * 2)); + mcs_map |= mcs << (nss * 2); + + /* only support 2ss on 160MHz */ + if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160)) + break; + } + + *he_mcs = cpu_to_le16(mcs_map); +} + +static void +mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, + const u16 *mask) +{ + u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + u16 mcs; + + for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) { + switch (mcs_map & 0x3) { + case IEEE80211_VHT_MCS_SUPPORT_0_9: + mcs = GENMASK(9, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_8: + mcs = GENMASK(8, 0); + break; + case IEEE80211_VHT_MCS_SUPPORT_0_7: + mcs = GENMASK(7, 0); + break; + default: + mcs = 0; + } + + vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]); + + /* only support 2ss on 160MHz */ + if (nss > 1 && (sta->bandwidth == IEEE80211_STA_RX_BW_160)) + break; + } +} + +static void +mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, + const u8 *mask) +{ + int nss, max_nss = sta->rx_nss > 3 ? 4 : sta->rx_nss; + + for (nss = 0; nss < max_nss; nss++) + ht_mcs[nss] = sta->ht_cap.mcs.rx_mask[nss] & mask[nss]; +} + static int mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) @@ -350,6 +456,24 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) } static void +mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7915_mcu_thermal_notify *t; + struct mt7915_phy *phy; + + t = (struct mt7915_mcu_thermal_notify *)skb->data; + if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) + return; + + if (t->ctrl.band_idx && dev->mt76.phy2) + mphy = dev->mt76.phy2; + + phy = (struct mt7915_phy *)mphy->priv; + phy->throttle_state = t->ctrl.duty.duty_cycle; +} + +static void mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; @@ -469,6 +593,7 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) u16 attempts = le16_to_cpu(ra->attempts); u16 curr = le16_to_cpu(ra->curr_rate); u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct ieee80211_tx_status status = {}; struct mt76_phy *mphy = &dev->mphy; struct mt7915_sta_stats *stats; struct mt7915_sta *msta; @@ -500,6 +625,13 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) stats->per = 1000 * (attempts - success) / attempts; } + + status.sta = wcid_to_sta(wcid); + if (!status.sta) + return; + + status.rate = &stats->tx_rate; + ieee80211_tx_status_ext(mphy->hw, &status); } static void @@ -531,6 +663,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; switch (rxd->ext_eid) { + case MCU_EXT_EVENT_THERMAL_PROTECT: + mt7915_mcu_rx_thermal_notify(dev, skb); + break; case MCU_EXT_EVENT_RDD_REPORT: mt7915_mcu_rx_radar_detected(dev, skb); break; @@ -733,7 +868,7 @@ mt7915_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); bss->dtim_period = vif->bss_conf.dtim_period; - bss->phy_mode = mt7915_get_phy_mode(phy->mt76, vif, NULL); + bss->phy_mode = mt7915_get_phy_mode(vif, NULL); } else { memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN); } @@ -1072,14 +1207,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); - if (cipher == MT_CIPHER_BIP_CMAC_128) { - sec_key->cipher_id = MT_CIPHER_AES_CCMP; + if (cipher == MCU_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MCU_CIPHER_AES_CCMP; sec_key->key_id = bip->keyidx; sec_key->key_len = 16; memcpy(sec_key->key, bip->key, 16); sec_key = &sec->key[1]; - sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); @@ -1091,14 +1226,14 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb, sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MCU_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(sec_key->key + 16, key->key + 24, 8); memcpy(sec_key->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ - if (cipher == MT_CIPHER_AES_CCMP) { + if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(bip->key, key->key, key->keylen); bip->keyidx = key->keyidx; } @@ -1336,8 +1471,11 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, static void mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; + enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; + const u16 *mcs_mask = msta->vif->bitrate_mask.control[band].he_mcs; struct sta_rec_he *he; struct tlv *tlv; u32 cap = 0; @@ -1428,15 +1566,18 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - he->max_nss_mcs[CMD_HE_MCS_BW8080] = - he_cap->he_mcs_nss_supp.rx_mcs_80p80; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW8080], + mcs_mask); - he->max_nss_mcs[CMD_HE_MCS_BW160] = - he_cap->he_mcs_nss_supp.rx_mcs_160; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW160], + mcs_mask); fallthrough; default: - he->max_nss_mcs[CMD_HE_MCS_BW80] = - he_cap->he_mcs_nss_supp.rx_mcs_80; + mt7915_mcu_set_sta_he_mcs(sta, + &he->max_nss_mcs[CMD_HE_MCS_BW80], + mcs_mask); break; } @@ -1544,27 +1685,18 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); } -static int -mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static void +mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct sk_buff *skb; - int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_muru); - - if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) - return 0; - - skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); + struct sta_rec_vht *vht; + struct tlv *tlv; - /* starec muru */ - mt7915_mcu_sta_muru_tlv(skb, sta); + tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_EXT_CMD(STA_REC_UPDATE), true); + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); + vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; } static void @@ -1616,17 +1748,6 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, mt7915_mcu_sta_amsdu_tlv(skb, sta); } - /* starec vht */ - if (sta->vht_cap.vht_supported) { - struct sta_rec_vht *vht; - - tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); - vht = (struct sta_rec_vht *)tlv; - vht->vht_cap = cpu_to_le32(sta->vht_cap.cap); - vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map; - vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map; - } - /* starec he */ if (sta->he_cap.has_he) mt7915_mcu_sta_he_tlv(skb, sta); @@ -2016,26 +2137,21 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif, vc = mt7915_get_he_phy_cap(phy, vif); ve = &vc->he_cap_elem; - ebfee = !!((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) && + ebfee = !!(HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) && HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4])); - ebf = !!((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) || - HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) && + ebf = !!(HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) && HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4])); } else if (sta->vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc; struct ieee80211_sta_vht_cap *vc; - u32 cr, ce; pc = &sta->vht_cap; vc = &phy->mt76->sband_5g.sband.vht_cap; - cr = IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | - IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; - ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; - ebfee = !!((pc->cap & cr) && (vc->cap & ce)); - ebf = !!((vc->cap & cr) && (pc->cap & ce)); + ebfee = !!((pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && + (vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); + ebf = !!((vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) && + (pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); } /* must keep each tag independent */ @@ -2079,57 +2195,47 @@ static void mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; - struct mt76_phy *mphy = &dev->mphy; - enum nl80211_band band; + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; + struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; + enum nl80211_band band = chandef->chan->band; struct sta_rec_ra *ra; struct tlv *tlv; - u32 supp_rate, n_rates, cap = sta->wme ? STA_CAP_WMM : 0; - u8 i, nss = sta->rx_nss, mcs = 0; + u32 supp_rate = sta->supp_rates[band]; + u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt7915_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); ra = (struct sta_rec_ra *)tlv; - if (msta->wcid.ext_phy && dev->mt76.phy2) - mphy = dev->mt76.phy2; - - band = mphy->chandef.chan->band; - supp_rate = sta->supp_rates[band]; - n_rates = hweight32(supp_rate); - ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt7915_get_phy_mode(mphy, vif, sta); - ra->channel = mphy->chandef.chan->hw_value; + ra->phy_mode = mt7915_get_phy_mode(vif, sta); + ra->channel = chandef->chan->hw_value; ra->bw = sta->bandwidth; - ra->rate_len = n_rates; ra->phy.bw = sta->bandwidth; - if (n_rates) { + if (supp_rate) { + supp_rate &= mask->control[band].legacy; + ra->rate_len = hweight32(supp_rate); + if (band == NL80211_BAND_2GHZ) { ra->supp_mode = MODE_CCK; ra->supp_cck_rate = supp_rate & GENMASK(3, 0); - ra->phy.type = MT_PHY_TYPE_CCK; - if (n_rates > 4) { + if (ra->rate_len > 4) { ra->supp_mode |= MODE_OFDM; ra->supp_ofdm_rate = supp_rate >> 4; - ra->phy.type = MT_PHY_TYPE_OFDM; } } else { ra->supp_mode = MODE_OFDM; ra->supp_ofdm_rate = supp_rate; - ra->phy.type = MT_PHY_TYPE_OFDM; } } if (sta->ht_cap.ht_supported) { - for (i = 0; i < nss; i++) - ra->ht_mcs[i] = sta->ht_cap.mcs.rx_mask[i]; + const u8 *mcs_mask = mask->control[band].ht_mcs; - ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; ra->supp_mode |= MODE_HT; - mcs = hweight32(le32_to_cpu(ra->supp_ht_mcs)) - 1; ra->af = sta->ht_cap.ampdu_factor; ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); @@ -2144,13 +2250,16 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_RX_STBC; if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) cap |= STA_CAP_LDPC; + + mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask); + ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; } if (sta->vht_cap.vht_supported) { - u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); - u16 vht_mcs; - u8 af, mcs_prev; + const u16 *mcs_mask = mask->control[band].vht_mcs; + u8 af; + ra->supp_mode |= MODE_VHT; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->vht_cap.cap); ra->af = max_t(u8, ra->af, af); @@ -2167,33 +2276,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) cap |= STA_CAP_VHT_LDPC; - ra->supp_mode |= MODE_VHT; - for (mcs = 0, i = 0; i < nss; i++, mcs_map >>= 2) { - switch (mcs_map & 0x3) { - case IEEE80211_VHT_MCS_SUPPORT_0_9: - vht_mcs = GENMASK(9, 0); - break; - case IEEE80211_VHT_MCS_SUPPORT_0_8: - vht_mcs = GENMASK(8, 0); - break; - case IEEE80211_VHT_MCS_SUPPORT_0_7: - vht_mcs = GENMASK(7, 0); - break; - default: - vht_mcs = 0; - } - - ra->supp_vht_mcs[i] = cpu_to_le16(vht_mcs); - - mcs_prev = hweight16(vht_mcs) - 1; - if (mcs_prev > mcs) - mcs = mcs_prev; - - /* only support 2ss on 160MHz */ - if (i > 1 && (ra->bw == CMD_CBW_160MHZ || - ra->bw == CMD_CBW_8080MHZ)) - break; - } + mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask); } if (sta->he_cap.has_he) { @@ -2201,28 +2284,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_HE; } - ra->sta_status = cpu_to_le32(cap); - - switch (BIT(fls(ra->supp_mode) - 1)) { - case MODE_VHT: - ra->phy.type = MT_PHY_TYPE_VHT; - ra->phy.mcs = mcs; - ra->phy.nss = nss; - ra->phy.stbc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC); - ra->phy.ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - ra->phy.sgi = - !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); - break; - case MODE_HT: - ra->phy.type = MT_PHY_TYPE_HT; - ra->phy.mcs = mcs; - ra->phy.ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING; - ra->phy.stbc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC); - ra->phy.sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); - break; - default: - break; - } + ra->sta_cap = cpu_to_le32(cap); } int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -2243,6 +2305,87 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD(STA_REC_UPDATE), true); } +int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + int len; + + if (!sta->he_cap.has_he) + return 0; + + len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_he); + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_he_tlv(skb, sta); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); +} + +static int +mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ +#define MT_STA_BSS_GROUP 1 + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct { + __le32 action; + u8 wlan_idx_lo; + u8 status; + u8 wlan_idx_hi; + u8 rsv0[5]; + __le32 val; + u8 rsv1[8]; + } __packed req = { + .action = cpu_to_le32(MT_STA_BSS_GROUP), + .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), + .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), + .val = cpu_to_le32(mvif->idx % 16), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + int ret; + + if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + return 0; + + ret = mt7915_mcu_add_group(dev, vif, sta); + if (ret) + return ret; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* wait until TxBF and MU ready to update stare vht */ + + /* starec muru */ + mt7915_mcu_sta_muru_tlv(skb, sta); + /* starec vht */ + mt7915_mcu_sta_vht_tlv(skb, sta); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(STA_REC_UPDATE), true); +} + int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { @@ -2253,17 +2396,14 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, /* must keep the order */ ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); - if (ret) + if (ret || !enable) return ret; ret = mt7915_mcu_add_mu(dev, vif, sta); if (ret) return ret; - if (enable) - return mt7915_mcu_add_rate_ctrl(dev, vif, sta); - - return 0; + return mt7915_mcu_add_rate_ctrl(dev, vif, sta); } int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -2432,7 +2572,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb, cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4); buf = (u8 *)tlv + sizeof(*cont); - mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, + mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL, true); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } @@ -3307,7 +3447,8 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) { struct mt7915_mcu_eeprom_info req = { - .addr = cpu_to_le32(round_down(offset, 16)), + .addr = cpu_to_le32(round_down(offset, + MT7915_EEPROM_BLOCK_SIZE)), }; struct mt7915_mcu_eeprom_info *res; struct sk_buff *skb; @@ -3321,7 +3462,7 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) res = (struct mt7915_mcu_eeprom_info *)skb->data; buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); - memcpy(buf, res->data, 16); + memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); dev_kfree_skb(skb); return 0; @@ -3440,8 +3581,9 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - u16 total = 2, idx, center_freq = chandef->center_freq1; + u16 total = 2, center_freq = chandef->center_freq1; u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data; + int idx; if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD)) return 0; @@ -3469,22 +3611,128 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) return 0; } -int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index) +int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) +{ + /* strict order */ + static const enum mt7915_chan_mib_offs offs[] = { + MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME + }; + struct mt76_channel_state *state = phy->mt76->chan_state; + struct mt76_channel_state *state_ts = &phy->state_ts; + struct mt7915_dev *dev = phy->dev; + struct mt7915_mcu_mib *res, req[4]; + struct sk_buff *skb; + int i, ret; + + for (i = 0; i < 4; i++) { + req[i].band = cpu_to_le32(phy != &dev->phy); + req[i].offs = cpu_to_le32(offs[i]); + } + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), + req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (struct mt7915_mcu_mib *)(skb->data + 20); + + if (chan_switch) + goto out; + +#define __res_u64(s) le64_to_cpu(res[s].data) + state->cc_busy += __res_u64(0) - state_ts->cc_busy; + state->cc_tx += __res_u64(1) - state_ts->cc_tx; + state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; + state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; + +out: + state_ts->cc_busy = __res_u64(0); + state_ts->cc_tx = __res_u64(1); + state_ts->cc_bss_rx = __res_u64(2); + state_ts->cc_rx = __res_u64(2) + __res_u64(3); +#undef __res_u64 + + dev_kfree_skb(skb); + + return 0; +} + +int mt7915_mcu_get_temperature(struct mt7915_phy *phy) { + struct mt7915_dev *dev = phy->dev; struct { u8 ctrl_id; u8 action; - u8 band; + u8 dbdc_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, - .action = index, + .dbdc_idx = phy != &dev->phy, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, sizeof(req), true); } +int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_thermal_ctrl ctrl; + + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; + } __packed req = { + .ctrl = { + .band_idx = phy != &dev->phy, + }, + }; + int level; + +#define TRIGGER_TEMPERATURE 122 +#define RESTORE_TEMPERATURE 116 +#define SUSTAIN_PERIOD 10 + + if (!state) { + req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE; + goto out; + } + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + int ret; + + req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG; + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state = state * 4 / 5; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), + &req, sizeof(req.ctrl), false); + if (ret) + return ret; + } + + /* currently use fixed values for throttling, and would be better + * to implement thermal zone for dynamic trip in the long run. + */ + + /* set high-temperature trigger threshold */ + req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE; + req.trigger_temp = cpu_to_le32(TRIGGER_TEMPERATURE); + req.restore_temp = cpu_to_le32(RESTORE_TEMPERATURE); + req.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + +out: + req.ctrl.type.protect_type = 1; + req.ctrl.type.trigger_type = 1; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), + &req, sizeof(req), false); +} + int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) { struct { @@ -3505,7 +3753,6 @@ int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx) int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) { -#define MT7915_SKU_RATE_NUM 161 struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_hw *hw = mphy->hw; @@ -3555,6 +3802,39 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) sizeof(req), true); } +int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) +{ +#define RATE_POWER_INFO 2 + struct mt7915_dev *dev = phy->dev; + struct { + u8 format_id; + u8 category; + u8 band; + u8 _rsv; + } __packed req = { + .format_id = 7, + .category = RATE_POWER_INFO, + .band = phy != &dev->phy, + }; + s8 res[MT7915_SKU_RATE_NUM][2]; + struct sk_buff *skb; + int ret, i; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + memcpy(res, skb->data + 4, sizeof(res)); + for (i = 0; i < len; i++) + txpower[i] = res[i][req.band]; + + dev_kfree_skb(skb); + + return 0; +} + int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, u8 en) { @@ -3613,57 +3893,50 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) &req, sizeof(req), false); } -int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev) -{ -#define MT_BF_MODULE_UPDATE 25 - struct { - u8 action; - u8 bf_num; - u8 bf_bitmap; - u8 bf_sel[8]; - u8 rsv[8]; - } __packed req = { - .action = MT_BF_MODULE_UPDATE, - .bf_num = 2, - .bf_bitmap = GENMASK(1, 0), - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, - sizeof(req), true); -} - -int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev) +int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) { -#define MT_BF_TYPE_UPDATE 20 struct { u8 action; - bool ebf; - bool ibf; - u8 rsv; + union { + struct { + u8 snd_mode; + u8 sta_num; + u8 rsv; + u8 wlan_idx[4]; + __le32 snd_period; /* ms */ + } __packed snd; + struct { + bool ebf; + bool ibf; + u8 rsv; + } __packed type; + struct { + u8 bf_num; + u8 bf_bitmap; + u8 bf_sel[8]; + u8 rsv[5]; + } __packed mod; + }; } __packed req = { - .action = MT_BF_TYPE_UPDATE, - .ebf = true, - .ibf = dev->ibf, + .action = action, }; - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, - sizeof(req), true); -} - -int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev) -{ -#define MT_BF_PROCESSING 4 - struct { - u8 action; - u8 snd_mode; - u8 sta_num; - u8 rsv; - u8 wlan_idx[4]; - __le32 snd_period; /* ms */ - } __packed req = { - .action = true, - .snd_mode = MT_BF_PROCESSING, - }; +#define MT_BF_PROCESSING 4 + switch (action) { + case MT_BF_SOUNDING_ON: + req.snd.snd_mode = MT_BF_PROCESSING; + break; + case MT_BF_TYPE_UPDATE: + req.type.ebf = true; + req.type.ibf = dev->ibf; + break; + case MT_BF_MODULE_UPDATE: + req.mod.bf_num = 2; + req.mod.bf_bitmap = GENMASK(1, 0); + break; + default: + return -EINVAL; + } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, sizeof(req), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 42582a66e42d..edd3ba3a0c2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -68,6 +68,29 @@ struct mt7915_mcu_rxd { u8 s2d_index; }; +struct mt7915_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7915_mcu_thermal_notify { + struct mt7915_mcu_rxd rxd; + + struct mt7915_mcu_thermal_ctrl ctrl; + __le32 temperature; + u8 rsv[8]; +} __packed; + struct mt7915_mcu_csa_notify { struct mt7915_mcu_rxd rxd; @@ -193,6 +216,19 @@ struct mt7915_mcu_phy_rx_info { #define MT_RA_RATE_DCM_EN BIT(4) #define MT_RA_RATE_BW GENMASK(14, 13) +struct mt7915_mcu_mib { + __le32 band; + __le32 offs; + __le64 data; +} __packed; + +enum mt7915_chan_mib_offs { + MIB_BUSY_TIME = 14, + MIB_TX_TIME = 81, + MIB_RX_TIME, + MIB_OBSS_AIRTIME = 86 +}; + struct edca { u8 queue; u8 set; @@ -262,6 +298,7 @@ enum { MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, MCU_EXT_CMD_TXBF_ACTION = 0x1e, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, + MCU_EXT_CMD_THERMAL_PROT = 0x23, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, MCU_EXT_CMD_EDCA_UPDATE = 0x27, @@ -277,6 +314,7 @@ enum { MCU_EXT_CMD_MUAR_UPDATE = 0x48, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, + MCU_EXT_CMD_GET_MIB_INFO = 0x5a, MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_SCS_CTRL = 0x82, @@ -919,7 +957,7 @@ struct sta_rec_ra { u8 op_vht_rx_nss; u8 op_vht_rx_nss_type; - __le32 sta_status; + __le32 sta_cap; struct ra_phy phy; } __packed; @@ -1034,18 +1072,17 @@ enum { STA_REC_MAX_NUM }; -enum mt7915_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_WEP128, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CCMP_256, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, - MT_CIPHER_WAPI, - MT_CIPHER_BIP_CMAC_128, +enum mcu_cipher_type { + MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_WEP104, + MCU_CIPHER_WEP128, + MCU_CIPHER_TKIP, + MCU_CIPHER_AES_CCMP, + MCU_CIPHER_CCMP_256, + MCU_CIPHER_GCMP, + MCU_CIPHER_GCMP_256, + MCU_CIPHER_WAPI, + MCU_CIPHER_BIP_CMAC_128, }; enum { @@ -1067,10 +1104,27 @@ enum { }; enum { + THERMAL_PROTECT_PARAMETER_CTRL, + THERMAL_PROTECT_BASIC_INFO, + THERMAL_PROTECT_ENABLE, + THERMAL_PROTECT_DISABLE, + THERMAL_PROTECT_DUTY_CONFIG, + THERMAL_PROTECT_MECH_INFO, + THERMAL_PROTECT_DUTY_INFO, + THERMAL_PROTECT_STATE_ACT, +}; + +enum { MT_EBF = BIT(0), /* explicit beamforming */ MT_IBF = BIT(1) /* implicit beamforming */ }; +enum { + MT_BF_SOUNDING_ON = 1, + MT_BF_TYPE_UPDATE = 20, + MT_BF_MODULE_UPDATE = 25 +}; + #define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 4ea8972d4e2f..3f613fae6218 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -9,7 +9,7 @@ #include "../mt76.h" #include "regs.h" -#define MT7915_MAX_INTERFACES 32 +#define MT7915_MAX_INTERFACES 19 #define MT7915_MAX_WMM_SETS 4 #define MT7915_WTBL_SIZE 288 #define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1) @@ -31,6 +31,7 @@ #define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" #define MT7915_EEPROM_SIZE 3584 +#define MT7915_EEPROM_BLOCK_SIZE 16 #define MT7915_TOKEN_SIZE 8192 #define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ @@ -38,6 +39,10 @@ #define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */ #define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */ +#define MT7915_THERMAL_THROTTLE_MAX 100 + +#define MT7915_SKU_RATE_NUM 161 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -100,6 +105,7 @@ struct mt7915_vif { struct mt7915_phy *phy; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; + struct cfg80211_bitrate_mask bitrate_mask; }; struct mib_stats { @@ -126,6 +132,9 @@ struct mt7915_phy { struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 throttle_state; + u32 rxfilter; u64 omac_mask; @@ -141,6 +150,7 @@ struct mt7915_phy { u32 ampdu_ref; struct mib_stats mib; + struct mt76_channel_state state_ts; struct list_head stats_list; u8 sta_work_count; @@ -169,6 +179,7 @@ struct mt7915_dev { struct mt7915_hif *hif2; const struct mt76_bus_ops *bus_ops; + struct tasklet_struct irq_tasklet; struct mt7915_phy phy; u16 chainmask; @@ -322,6 +333,8 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); int mt7915_set_channel(struct mt7915_phy *phy); @@ -342,9 +355,8 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val); int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); -int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev); -int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev); -int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev); +int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len); +int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse); @@ -352,7 +364,9 @@ int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, const struct mt7915_dfs_pattern *pattern); int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev); int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy); -int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index); +int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch); +int mt7915_mcu_get_temperature(struct mt7915_phy *phy); +int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state); int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx); int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); @@ -374,9 +388,11 @@ void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) { if (dev->hif2) - mt7915_dual_hif_set_irq_mask(dev, true, 0, mask); + mt7915_dual_hif_set_irq_mask(dev, false, 0, mask); else - mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); + mt76_set_irq_mask(&dev->mt76, 0, 0, mask); + + tasklet_schedule(&dev->irq_tasklet); } static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) @@ -392,12 +408,9 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, - struct sk_buff *skb, struct mt76_wcid *wcid, + struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, bool beacon); void mt7915_mac_set_timing(struct mt7915_phy *phy); -int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb); -void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb); -void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb); int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -417,13 +430,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); void mt7915_stats_work(struct work_struct *work); -void mt7915_txp_skb_unmap(struct mt76_dev *dev, - struct mt76_txwi_cache *txwi); int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy); void mt7915_set_stream_he_caps(struct mt7915_phy *phy); void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy); -void mt7915_update_channel(struct mt76_dev *mdev); +void mt7915_update_channel(struct mt76_phy *mphy); int mt7915_init_debugfs(struct mt7915_dev *dev); #ifdef CONFIG_MAC80211_DEBUGFS void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 643f171884cf..340b364da5f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -94,11 +94,15 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) } /* TODO: support 2/4/6/8 MSI-X vectors */ -static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +static void mt7915_irq_tasklet(struct tasklet_struct *t) { - struct mt7915_dev *dev = dev_instance; + struct mt7915_dev *dev = from_tasklet(dev, t, irq_tasklet); u32 intr, intr1, mask; + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); @@ -111,9 +115,6 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) intr |= intr1; } - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) - return IRQ_NONE; - trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask = intr & MT_INT_RX_DONE_ALL; @@ -150,6 +151,20 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) wake_up(&dev->reset_wait); } } +} + +static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) +{ + struct mt7915_dev *dev = dev_instance; + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return IRQ_NONE; + + tasklet_schedule(&dev->irq_tasklet); return IRQ_HANDLED; } @@ -240,6 +255,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev, if (ret) return ret; + mt76_pci_disable_aspm(pdev); + if (id->device == 0x7916) return mt7915_pci_hif2_probe(pdev); @@ -250,10 +267,18 @@ static int mt7915_pci_probe(struct pci_dev *pdev, dev = container_of(mdev, struct mt7915_dev, mt76); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free; + ret = mt7915_mmio_init(mdev, pcim_iomap_table(pdev)[0], pdev->irq); if (ret) goto error; + tasklet_setup(&dev->irq_tasklet, mt7915_irq_tasklet); + + mt76_wr(dev, MT_INT_MASK_CSR, 0); + /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); @@ -266,10 +291,14 @@ static int mt7915_pci_probe(struct pci_dev *pdev, ret = mt7915_register_device(dev); if (ret) - goto error; + goto free_irq; return 0; +free_irq: + devm_free_irq(mdev->dev, pdev->irq, dev); error: + pci_free_irq_vectors(pdev); +free: mt76_free_device(&dev->mt76); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index efe0f2904c66..a213b5cb82f8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -82,11 +82,6 @@ #define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) #define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) -#define MT_TMAC_FP0R0(_band) MT_WF_TMAC(_band, 0x020) -#define MT_TMAC_FP0R15(_band) MT_WF_TMAC(_band, 0x080) -#define MT_TMAC_FP0R18(_band) MT_WF_TMAC(_band, 0x270) -#define MT_TMAC_FP_MASK GENMASK(7, 0) - #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) #define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00) @@ -104,6 +99,11 @@ #define MT_ETBF_TX_FB_CPL GENMASK(31, 16) #define MT_ETBF_TX_FB_TRI GENMASK(15, 0) +#define MT_ETBF_RX_FB_CONT(_band) MT_WF_ETBF(_band, 0x068) +#define MT_ETBF_RX_FB_BW GENMASK(7, 6) +#define MT_ETBF_RX_FB_NC GENMASK(5, 3) +#define MT_ETBF_RX_FB_NR GENMASK(2, 0) + #define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x0f0) #define MT_ETBF_TX_IBF_CNT GENMASK(31, 16) #define MT_ETBF_TX_EBF_CNT GENMASK(15, 0) @@ -124,6 +124,8 @@ #define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) #define MT_LPON_TCR_SW_MODE GENMASK(1, 0) #define MT_LPON_TCR_SW_WRITE BIT(0) +#define MT_LPON_TCR_SW_ADJUST BIT(1) +#define MT_LPON_TCR_SW_READ GENMASK(1, 0) /* MIB: band 0(0x24800), band 1(0xa4800) */ #define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800) @@ -132,20 +134,9 @@ #define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) -#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c) -#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) - -#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) -#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) - #define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) -#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) -#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) -#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) -#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) - #define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) #define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) @@ -158,9 +149,6 @@ #define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) -#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) -#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) - #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2)) #define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2)) @@ -258,14 +246,10 @@ #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) -#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) +#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) #define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) -#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) -#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) -#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) - /* WFDMA0 */ #define MT_WFDMA0_BASE 0xd4000 #define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index f9d81e36ef09..b220b334906b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -464,10 +464,17 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) static void mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) { - if (en) + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); + + if (en) { + struct mt7915_dev *dev = phy->dev; + mt7915_tm_update_channel(phy); - mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); + /* read-clear */ + mt76_rr(dev, MT_MIB_SDR3(phy != &dev->phy)); + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); + } } static int @@ -690,7 +697,11 @@ static int mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { struct mt7915_phy *phy = mphy->priv; + struct mt7915_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + enum mt76_rxq_id q; void *rx, *rssi; + u16 fcs_err; int i; rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); @@ -735,6 +746,12 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) nla_nest_end(msg, rx); + fcs_err = mt76_get_field(dev, MT_MIB_SDR3(ext_phy), + MT_MIB_SDR3_FCS_ERR_MASK); + q = ext_phy ? MT_RXQ_EXT : MT_RXQ_MAIN; + mphy->test.rx_stats.packets[q] += fcs_err; + mphy->test.rx_stats.fcs_error[q] += fcs_err; + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h index 8f8533ef9859..397a6b5532bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +/* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_TESTMODE_H diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index e531666f9fb4..0ebb59966a08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -1,4 +1,4 @@ -#SPDX-License-Identifier: ISC +# SPDX-License-Identifier: ISC obj-$(CONFIG_MT7921E) += mt7921e.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index 6ee423dd4027..77468bdae460 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -184,7 +184,10 @@ mt7921_txpwr(struct seq_file *s, void *data) struct mt7921_txpwr txpwr; int ret; + mt7921_mutex_acquire(dev); ret = mt7921_get_txpwr_info(dev, &txpwr); + mt7921_mutex_release(dev); + if (ret) return ret; @@ -247,6 +250,9 @@ mt7921_pm_set(void *data, u64 val) ieee80211_iterate_active_interfaces(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_pm_interface_iter, mphy->priv); + + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); + mt7921_mutex_release(dev); return 0; @@ -265,6 +271,36 @@ mt7921_pm_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n"); static int +mt7921_deep_sleep_set(void *data, u64 val) +{ + struct mt7921_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; + bool enable = !!val; + + mt7921_mutex_acquire(dev); + if (pm->ds_enable != enable) { + mt76_connac_mcu_set_deep_sleep(&dev->mt76, enable); + pm->ds_enable = enable; + } + mt7921_mutex_release(dev); + + return 0; +} + +static int +mt7921_deep_sleep_get(void *data, u64 *val) +{ + struct mt7921_dev *dev = data; + + *val = dev->pm.ds_enable; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7921_deep_sleep_get, + mt7921_deep_sleep_set, "%lld\n"); + +static int mt7921_pm_stats(struct seq_file *s, void *data) { struct mt7921_dev *dev = dev_get_drvdata(s->private); @@ -355,6 +391,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev) debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset); debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir, mt7921_pm_stats); + debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c index 71e664ee7652..7d7d43a5422f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c @@ -74,7 +74,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget) mt7921_tx_cleanup(dev); if (napi_complete(napi)) mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } @@ -92,7 +92,7 @@ static int mt7921_poll_rx(struct napi_struct *napi, int budget) return 0; } done = mt76_dma_rx_poll(napi, budget); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } @@ -313,9 +313,9 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force) int mt7921_wfsys_reset(struct mt7921_dev *dev) { - mt76_set(dev, 0x70002600, BIT(0)); - msleep(200); - mt76_clear(dev, 0x70002600, BIT(0)); + mt76_clear(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); + msleep(50); + mt76_set(dev, MT_WFSYS_SW_RST_B, WFSYS_SW_RST_B); if (!__mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B, WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500)) @@ -380,9 +380,7 @@ int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev) int mt7921_dma_init(struct mt7921_dev *dev) { - /* Increase buffer size to receive large VHT/HE MPDUs */ struct mt76_bus_ops *bus_ops; - int rx_buf_size = MT_RX_BUF_SIZE * 2; int ret; dev->bus_ops = dev->mt76.bus; @@ -402,6 +400,10 @@ int mt7921_dma_init(struct mt7921_dev *dev) if (ret) return ret; + ret = mt7921_wfsys_reset(dev); + if (ret) + return ret; + /* init tx queue */ ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE); @@ -426,7 +428,7 @@ int mt7921_dma_init(struct mt7921_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7921_RXQ_MCU_WM, MT7921_RX_MCU_RING_SIZE, - rx_buf_size, MT_RX_EVENT_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; @@ -434,14 +436,14 @@ int mt7921_dma_init(struct mt7921_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7921_RXQ_MCU_WM, MT7921_RX_MCU_RING_SIZE, - rx_buf_size, MT_WFDMA0(0x540)); + MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); if (ret) return ret; /* rx data */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE, - rx_buf_size, MT_RX_DATA_RING_BASE); + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index fe28bf4050c4..a9ce10b98827 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -7,34 +7,6 @@ #include "mcu.h" #include "eeprom.h" -#define CCK_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \ -} - -#define OFDM_RATE(_idx, _rate) { \ - .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ -} - -static struct ieee80211_rate mt7921_rates[] = { - CCK_RATE(0, 10), - CCK_RATE(1, 20), - CCK_RATE(2, 55), - CCK_RATE(3, 110), - OFDM_RATE(11, 60), - OFDM_RATE(15, 90), - OFDM_RATE(10, 120), - OFDM_RATE(14, 180), - OFDM_RATE(9, 240), - OFDM_RATE(13, 360), - OFDM_RATE(8, 480), - OFDM_RATE(12, 540), -}; - static const struct ieee80211_iface_limit if_limits[] = { { .max = MT7921_MAX_INTERFACES, @@ -73,11 +45,13 @@ static void mt7921_init_wiphy(struct ieee80211_hw *hw) { struct mt7921_phy *phy = mt7921_hw_phy(hw); + struct mt7921_dev *dev = phy->dev; struct wiphy *wiphy = hw->wiphy; hw->queues = 4; - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; - hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_rx_aggregation_subframes = 64; + hw->max_tx_aggregation_subframes = 128; + hw->netdev_features = NETIF_F_RXCSUM; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; @@ -88,11 +62,13 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) hw->vif_data_size = sizeof(struct mt7921_vif); wiphy->iface_combinations = if_comb; + wiphy->flags &= ~WIPHY_FLAG_IBSS_RSN; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; wiphy->max_sched_scan_plan_interval = - MT76_CONNAC_MAX_SCHED_SCAN_INTERVAL; + MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; @@ -100,46 +76,33 @@ mt7921_init_wiphy(struct ieee80211_hw *hw) wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->reg_notifier = mt7921_regd_notifier; - wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + if (dev->pm.enable) + ieee80211_hw_set(hw, CONNECTION_MONITOR); + hw->max_tx_fragments = 4; } static void mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) { - u32 mask, set; - mt76_rmw_field(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); mt76_set(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); - mask = MT_MDP_RCFR0_MCU_RX_MGMT | - MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | - MT_MDP_RCFR0_MCU_RX_CTL_BAR; - set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); - mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); - - mask = MT_MDP_RCFR1_MCU_RX_BYPASS | - MT_MDP_RCFR1_RX_DROPPED_UCAST | - MT_MDP_RCFR1_RX_DROPPED_MCAST; - set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | - FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); - mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); - mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN); @@ -148,14 +111,15 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band) mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); } -void mt7921_mac_init(struct mt7921_dev *dev) +int mt7921_mac_init(struct mt7921_dev *dev) { int i; mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); - /* disable hardware de-agg */ - mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); - mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); + /* enable hardware de-agg */ + mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); + /* enable hardware rx header translation */ + mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); for (i = 0; i < MT7921_WTBL_SIZE; i++) mt7921_mac_wtbl_update(dev, i, @@ -163,7 +127,7 @@ void mt7921_mac_init(struct mt7921_dev *dev) for (i = 0; i < 2; i++) mt7921_mac_init_band(dev, i); - mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); + return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); } static int mt7921_init_hardware(struct mt7921_dev *dev) @@ -203,9 +167,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev) dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - mt7921_mac_init(dev); - - return 0; + return mt7921_mac_init(dev); } int mt7921_register_device(struct mt7921_dev *dev) @@ -224,7 +186,6 @@ int mt7921_register_device(struct mt7921_dev *dev) mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); spin_lock_init(&dev->pm.txq_lock); - set_bit(MT76_STATE_PM, &dev->mphy.state); INIT_LIST_HEAD(&dev->phy.stats_list); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); @@ -239,6 +200,8 @@ int mt7921_register_device(struct mt7921_dev *dev) dev->pm.idle_timeout = MT7921_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; + dev->pm.enable = true; + dev->pm.ds_enable = true; ret = mt7921_init_hardware(dev); if (ret) @@ -253,19 +216,33 @@ int mt7921_register_device(struct mt7921_dev *dev) IEEE80211_HT_CAP_MAX_AMSDU; dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; mt76_set_stream_caps(&dev->mphy, true); mt7921_set_stream_he_caps(&dev->phy); - ret = mt76_register_device(&dev->mt76, true, mt7921_rates, - ARRAY_SIZE(mt7921_rates)); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, + ARRAY_SIZE(mt76_rates)); + if (ret) + return ret; + + ret = mt7921_init_debugfs(dev); if (ret) return ret; - return mt7921_init_debugfs(dev); + ret = mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); + if (ret) + return ret; + + dev->hw_init_done = true; + + return 0; } void mt7921_unregister_device(struct mt7921_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 214bd1859792..7fe2e3a50428 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -308,21 +308,24 @@ mt7921_mac_assoc_rssi(struct mt7921_dev *dev, struct sk_buff *skb) int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) { + u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + bool hdr_trans, unicast, insert_ccmp_hdr = false; + u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info; + __le32 *rxv = NULL, *rxd = (__le32 *)skb->data; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7921_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; - __le32 *rxd = (__le32 *)skb->data; - __le32 *rxv = NULL; - u32 mode = 0; + u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); - bool unicast, insert_ccmp_hdr = false; - u8 remove_pad; + u32 rxd4 = le32_to_cpu(rxd[4]); + u16 seq_ctrl = 0; + __le16 fc = 0; + u32 mode = 0; int i, idx; - u8 chfreq; memset(status, 0, sizeof(*status)); @@ -332,9 +335,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; + if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) + return -EINVAL; + chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; status->wcid = mt7921_rx_get_wcid(dev, idx, unicast); if (status->wcid) { @@ -357,6 +364,9 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (!sband->channels) return -EINVAL; + if ((rxd0 & csum_mask) == csum_mask) + skb->ip_summed = CHECKSUM_UNNECESSARY; + if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; @@ -377,6 +387,13 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) rxd += 6; if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + u32 v0 = le32_to_cpu(rxd[0]); + u32 v2 = le32_to_cpu(rxd[2]); + + fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); + seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); + qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); + rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; @@ -386,14 +403,27 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { - status->iv[0] = data[5]; - status->iv[1] = data[4]; - status->iv[2] = data[3]; - status->iv[3] = data[2]; - status->iv[4] = data[1]; - status->iv[5] = data[0]; - - insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) @@ -444,16 +474,19 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); - status->signal = status->chain_signal[0]; - - for (i = 1; i < hweight8(mphy->antenna_mask); i++) { - if (!(status->chains & BIT(i))) + status->signal = -128; + for (i = 0; i < hweight8(mphy->antenna_mask); i++) { + if (!(status->chains & BIT(i)) || + status->chain_signal[i] >= 0) continue; status->signal = max(status->signal, status->chain_signal[i]); } + if (status->signal == -128) + status->flag |= RX_FLAG_NO_SIGNAL_VAL; + stbc = FIELD_GET(MT_PRXV_STBC, v0); gi = FIELD_GET(MT_PRXV_SGI, v0); cck = false; @@ -540,10 +573,35 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); - if (insert_ccmp_hdr) { - u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); + status->amsdu = !!amsdu_info; + if (status->amsdu) { + status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; + status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; + if (!hdr_trans) { + memmove(skb->data + 2, skb->data, + ieee80211_get_hdrlen_from_skb(skb)); + skb_pull(skb, 2); + } + } + + if (!hdr_trans) { + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + + mt76_insert_ccmp_hdr(skb, key_id); + } - mt76_insert_ccmp_hdr(skb, key_id); + hdr = mt76_skb_get_hdr(skb); + fc = hdr->frame_control; + if (ieee80211_is_data_qos(fc)) { + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); + qos_ctl = *ieee80211_get_qos_ctl(hdr); + } + } else { + status->flag &= ~(RX_FLAG_RADIOTAP_HE | + RX_FLAG_RADIOTAP_HE_MU); + status->flag |= RX_FLAG_8023; } mt7921_mac_assoc_rssi(dev, skb); @@ -551,14 +609,12 @@ int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb) if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) mt7921_mac_decode_he_radiotap(skb, status, rxv, mode); - hdr = mt76_skb_get_hdr(skb); - if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) + if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; - status->aggr = unicast && - !ieee80211_is_qos_nullfunc(hdr->frame_control); - status->qos_ctl = *ieee80211_get_qos_ctl(hdr); - status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); + status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); + status->qos_ctl = qos_ctl; return 0; } @@ -676,6 +732,23 @@ mt7921_mac_write_txwi_80211(struct mt7921_dev *dev, __le32 *txwi, txwi[7] |= cpu_to_le32(val); } +static void mt7921_update_txs(struct mt76_wcid *wcid, __le32 *txwi) +{ + struct mt7921_sta *msta = container_of(wcid, struct mt7921_sta, wcid); + u32 pid, frame_type = FIELD_GET(MT_TXD2_FRAME_TYPE, txwi[2]); + + if (!(frame_type & (IEEE80211_FTYPE_DATA >> 2))) + return; + + if (time_is_after_eq_jiffies(msta->next_txs_ts)) + return; + + msta->next_txs_ts = jiffies + msecs_to_jiffies(250); + pid = mt76_get_next_pkt_id(wcid); + txwi[5] |= cpu_to_le32(MT_TXD5_TX_STATUS_MCU | + FIELD_PREP(MT_TXD5_PID, pid)); +} + void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, bool beacon) @@ -752,6 +825,8 @@ void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } + + mt7921_update_txs(wcid, txwi); } static void @@ -1154,18 +1229,18 @@ mt7921_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -void mt7921_update_channel(struct mt76_dev *mdev) +void mt7921_update_channel(struct mt76_phy *mphy) { - struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_dev *dev = container_of(mphy->dev, struct mt7921_dev, mt76); - if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) + if (mt76_connac_pm_wake(mphy, &dev->pm)) return; - mt7921_phy_update_channel(&mdev->phy, 0); + mt7921_phy_update_channel(mphy, 0); /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); - mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + mt76_connac_power_save_sched(mphy, &dev->pm); } void mt7921_tx_token_put(struct mt7921_dev *dev) @@ -1196,7 +1271,8 @@ mt7921_vif_connect_iter(void *priv, u8 *mac, struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; struct mt7921_dev *dev = mvif->phy->dev; - ieee80211_disconnect(vif, true); + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_disconnect(vif, true); mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); mt7921_mcu_set_tx(dev, vif); @@ -1212,6 +1288,7 @@ mt7921_mac_reset(struct mt7921_dev *dev) mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); skb_queue_purge(&dev->mt76.mcu.res_q); @@ -1227,56 +1304,64 @@ mt7921_mac_reset(struct mt7921_dev *dev) mt7921_tx_token_put(dev); idr_init(&dev->mt76.token); - err = mt7921_wpdma_reset(dev, true); - if (err) - return err; + mt7921_wpdma_reset(dev, true); mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } - napi_enable(&dev->mt76.tx_napi); - napi_schedule(&dev->mt76.tx_napi); - mt76_worker_enable(&dev->mt76.tx_worker); - clear_bit(MT76_MCU_RESET, &dev->mphy.state); - clear_bit(MT76_STATE_PM, &dev->mphy.state); - mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); + mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, + MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | + MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); err = mt7921_run_firmware(dev); if (err) - return err; + goto out; err = mt7921_mcu_set_eeprom(dev); if (err) - return err; + goto out; - mt7921_mac_init(dev); - return __mt7921_start(&dev->phy); + err = mt7921_mac_init(dev); + if (err) + goto out; + + err = __mt7921_start(&dev->phy); +out: + clear_bit(MT76_RESET, &dev->mphy.state); + + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); + mt76_worker_enable(&dev->mt76.tx_worker); + + return err; } /* system error recovery */ void mt7921_mac_reset_work(struct work_struct *work) { - struct ieee80211_hw *hw; - struct mt7921_dev *dev; + struct mt7921_dev *dev = container_of(work, struct mt7921_dev, + reset_work); + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_connac_pm *pm = &dev->pm; int i; - dev = container_of(work, struct mt7921_dev, reset_work); - hw = mt76_hw(dev); - dev_err(dev->mt76.dev, "chip reset\n"); + dev->hw_full_reset = true; ieee80211_stop_queues(hw); cancel_delayed_work_sync(&dev->mphy.mac_work); - cancel_delayed_work_sync(&dev->pm.ps_work); - cancel_work_sync(&dev->pm.wake_work); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { + __mt7921_mcu_drv_pmctrl(dev); + if (!mt7921_mac_reset(dev)) break; } @@ -1293,16 +1378,24 @@ void mt7921_mac_reset_work(struct work_struct *work) ieee80211_scan_completed(dev->mphy.hw, &info); } + dev->hw_full_reset = false; ieee80211_wake_queues(hw); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_vif_connect_iter, NULL); + mt76_connac_power_save_sched(&dev->mt76.phy, pm); } void mt7921_reset(struct mt76_dev *mdev) { struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + if (!dev->hw_init_done) + return; + + if (dev->hw_full_reset) + return; + queue_work(dev->mt76.wq, &dev->reset_work); } @@ -1337,30 +1430,6 @@ mt7921_mac_update_mib_stats(struct mt7921_phy *phy) } } -static void -mt7921_mac_sta_stats_work(struct mt7921_phy *phy) -{ - struct mt7921_dev *dev = phy->dev; - struct mt7921_sta *msta; - LIST_HEAD(list); - - spin_lock_bh(&dev->sta_poll_lock); - list_splice_init(&phy->stats_list, &list); - - while (!list_empty(&list)) { - msta = list_first_entry(&list, struct mt7921_sta, stats_list); - list_del_init(&msta->stats_list); - spin_unlock_bh(&dev->sta_poll_lock); - - /* query wtbl info to report tx rate for further devices */ - mt7921_get_wtbl_info(dev, msta->wcid.idx); - - spin_lock_bh(&dev->sta_poll_lock); - } - - spin_unlock_bh(&dev->sta_poll_lock); -} - void mt7921_mac_work(struct work_struct *work) { struct mt7921_phy *phy; @@ -1372,16 +1441,12 @@ void mt7921_mac_work(struct work_struct *work) mt7921_mutex_acquire(phy->dev); - mt76_update_survey(mphy->dev); + mt76_update_survey(mphy); if (++mphy->mac_work_count == 2) { mphy->mac_work_count = 0; mt7921_mac_update_mib_stats(phy); } - if (++phy->sta_work_count == 4) { - phy->sta_work_count = 0; - mt7921_mac_sta_stats_work(phy); - } mt7921_mutex_release(phy->dev); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, @@ -1404,8 +1469,9 @@ void mt7921_pm_wake_work(struct work_struct *work) napi_schedule(&dev->mt76.napi[i]); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt7921_tx_cleanup(dev); - ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, - MT7921_WATCHDOG_TIME); + if (test_bit(MT76_STATE_RUNNING, &mphy->state)) + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, + MT7921_WATCHDOG_TIME); } ieee80211_wake_queues(mphy->hw); @@ -1416,13 +1482,15 @@ void mt7921_pm_power_save_work(struct work_struct *work) { struct mt7921_dev *dev; unsigned long delta; + struct mt76_phy *mphy; dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev, pm.ps_work.work); + mphy = dev->phy.mt76; delta = dev->pm.idle_timeout; - if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) || - test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state)) + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) goto out; if (time_is_after_jiffies(dev->pm.last_activity + delta)) { @@ -1430,8 +1498,10 @@ void mt7921_pm_power_save_work(struct work_struct *work) goto out; } - if (!mt7921_mcu_fw_pmctrl(dev)) + if (!mt7921_mcu_fw_pmctrl(dev)) { + cancel_delayed_work_sync(&mphy->mac_work); return; + } out: queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } @@ -1493,7 +1563,7 @@ void mt7921_coredump_work(struct work_struct *work) break; skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); - if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { + if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { dev_kfree_skb(skb); continue; } @@ -1503,7 +1573,10 @@ void mt7921_coredump_work(struct work_struct *work) dev_kfree_skb(skb); } - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, - GFP_KERNEL); + + if (dump) + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); + mt7921_reset(&dev->mt76); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h index 109c8849d106..3af67fac213d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.h @@ -88,6 +88,9 @@ enum rx_pkt_type { /* RXD DW4 */ #define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) +#define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) +#define MT_RXD4_MID_AMSDU_FRAME BIT(1) +#define MT_RXD4_LAST_AMSDU_FRAME BIT(0) #define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) #define MT_RXD4_NORMAL_CLS BIT(10) #define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) @@ -97,6 +100,17 @@ enum rx_pkt_type { #define MT_RXD3_NORMAL_PF_MODE BIT(29) #define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) +/* RXD GROUP4 */ +#define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) +#define MT_RXD6_TA_LO GENMASK(31, 16) + +#define MT_RXD7_TA_HI GENMASK(31, 0) + +#define MT_RXD8_SEQ_CTRL GENMASK(15, 0) +#define MT_RXD8_QOS_CTL GENMASK(31, 16) + +#define MT_RXD9_HT_CONTROL GENMASK(31, 0) + /* P-RXV DW0 */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_DCM BIT(4) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index f4c27aa41048..63ec140c9c37 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -74,19 +74,19 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; else if (band == NL80211_BAND_5GHZ) he_cap_elem->phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; switch (i) { case NL80211_IFTYPE_STATION: - he_cap_elem->mac_cap_info[0] |= - IEEE80211_HE_MAC_CAP0_TWT_REQ; he_cap_elem->mac_cap_info[1] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; @@ -103,7 +103,15 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + he_cap_elem->phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; @@ -224,54 +232,6 @@ static void mt7921_stop(struct ieee80211_hw *hw) mt7921_mutex_release(dev); } -static inline int get_free_idx(u32 mask, u8 start, u8 end) -{ - return ffs(~mask & GENMASK(end, start)); -} - -static int get_omac_idx(enum nl80211_iftype type, u64 mask) -{ - int i; - - switch (type) { - case NL80211_IFTYPE_STATION: - /* prefer hw bssid slot 1-3 */ - i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); - if (i) - return i - 1; - - /* next, try to find a free repeater entry for the sta */ - i = get_free_idx(mask >> REPEATER_BSSID_START, 0, - REPEATER_BSSID_MAX - REPEATER_BSSID_START); - if (i) - return i + 32 - 1; - - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); - if (i) - return i - 1; - - if (~mask & BIT(HW_BSSID_0)) - return HW_BSSID_0; - - break; - case NL80211_IFTYPE_MONITOR: - /* ap uses hw bssid 0 and ext bssid */ - if (~mask & BIT(HW_BSSID_0)) - return HW_BSSID_0; - - i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); - if (i) - return i - 1; - - break; - default: - WARN_ON(1); - break; - } - - return -1; -} - static int mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -293,12 +253,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw, goto out; } - idx = get_omac_idx(vif->type, phy->omac_mask); - if (idx < 0) { - ret = -ENOSPC; - goto out; - } - mvif->mt76.omac_idx = idx; + mvif->mt76.omac_idx = mvif->mt76.idx; mvif->phy = phy; mvif->mt76.band_idx = 0; mvif->mt76.wmm_idx = mvif->mt76.idx % MT7921_MAX_WMM_SETS; @@ -370,7 +325,7 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw, spin_unlock_bh(&dev->sta_poll_lock); } -int mt7921_set_channel(struct mt7921_phy *phy) +static int mt7921_set_channel(struct mt7921_phy *phy) { struct mt7921_dev *dev = phy->dev; int ret; @@ -430,6 +385,11 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; wcid_keyidx = &wcid->hw_key_idx2; break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (!mvif->wep_sta) + return -EOPNOTSUPP; + break; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: @@ -437,8 +397,6 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: default: return -EOPNOTSUPP; } @@ -456,6 +414,12 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, cmd == SET_KEY ? key : NULL); err = mt7921_mcu_add_key(dev, vif, msta, key, cmd); + if (err) + goto out; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || + key->cipher == WLAN_CIPHER_SUITE_WEP40) + err = mt7921_mcu_add_key(dev, vif, mvif->wep_sta, key, cmd); out: mt7921_mutex_release(dev); @@ -478,6 +442,9 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed) mt7921_mutex_acquire(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + mt76_connac_mcu_set_rate_txpower(phy->mt76); + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); @@ -623,7 +590,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, mt7921_mcu_uni_bss_ps(dev, vif); if (changed & BSS_CHANGED_ASSOC) { - mt7921_mcu_sta_add(dev, NULL, vif, true); + mt7921_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_ASSOC); mt7921_bss_bcnft_apply(dev, vif, info->assoc); } @@ -662,14 +630,14 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (ret) return ret; - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, - true); + if (vif->type == NL80211_IFTYPE_STATION) + mvif->wep_sta = msta; mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - ret = mt7921_mcu_sta_add(dev, sta, vif, true); + ret = mt7921_mcu_sta_update(dev, sta, vif, true, + MT76_STA_INFO_STATE_NONE); if (ret) return ret; @@ -678,6 +646,27 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, return 0; } +void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + + mt7921_mutex_acquire(dev); + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, + true); + + mt7921_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); + + mt7921_mutex_release(dev); +} + void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -687,13 +676,14 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); - mt7921_mcu_sta_add(dev, sta, vif, false); + mt7921_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); mt7921_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->type == NL80211_IFTYPE_STATION) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + mvif->wep_sta = NULL; ewma_rssi_init(&mvif->rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, @@ -721,7 +711,7 @@ void mt7921_tx_worker(struct mt76_worker *w) } mt76_txq_schedule_all(&dev->mphy); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7921_tx(struct ieee80211_hw *hw, @@ -751,7 +741,7 @@ static void mt7921_tx(struct ieee80211_hw *hw, if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); - mt76_connac_pm_unref(&dev->pm); + mt76_connac_pm_unref(mphy, &dev->pm); return; } @@ -832,20 +822,21 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return ret; } -static int -mt7921_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static int mt7921_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) { - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, - IEEE80211_STA_NONE); -} + struct mt7921_dev *dev = mt7921_hw_dev(hw); -static int -mt7921_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, - IEEE80211_STA_NOTEXIST); + if (dev->pm.ds_enable) { + mt7921_mutex_acquire(dev); + mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state); + mt7921_mutex_release(dev); + } + + return mt76_sta_state(hw, vif, sta, old_state, new_state); } static int @@ -1164,6 +1155,23 @@ static void mt7921_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, HZ / 2); } +static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool enabled) +{ + struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv; + struct mt7921_dev *dev = mt7921_hw_dev(hw); + + if (enabled) + set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + else + clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + + mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, + MCU_UNI_CMD_STA_REC_UPDATE); +} + const struct ieee80211_ops mt7921_ops = { .tx = mt7921_tx, .start = mt7921_start, @@ -1174,10 +1182,10 @@ const struct ieee80211_ops mt7921_ops = { .conf_tx = mt7921_conf_tx, .configure_filter = mt7921_configure_filter, .bss_info_changed = mt7921_bss_info_changed, - .sta_add = mt7921_sta_add, - .sta_remove = mt7921_sta_remove, + .sta_state = mt7921_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, + .sta_set_decap_offload = mt7921_sta_set_decap_offload, .ampdu_action = mt7921_ampdu_action, .set_rts_threshold = mt7921_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 5f3d56d570a5..cd690c64f65b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -88,28 +88,28 @@ struct mt7921_fw_region { #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id) -static enum mt7921_cipher_type +static enum mcu_cipher_type mt7921_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; + return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; + return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: - return MT_CIPHER_TKIP; + return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: - return MT_CIPHER_BIP_CMAC_128; + return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; + return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; + return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; + return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; + return MCU_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; + return MCU_CIPHER_WAPI; default: return MT_CIPHER_NONE; } @@ -399,40 +399,6 @@ mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy, } static void -mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb, - u16 wlan_idx) -{ - struct mt7921_mcu_wlan_info_event *wtbl_info = - (struct mt7921_mcu_wlan_info_event *)(skb->data); - struct rate_info rate = {}; - u8 curr_idx = wtbl_info->rate_info.rate_idx; - u16 curr = le16_to_cpu(wtbl_info->rate_info.rate[curr_idx]); - struct mt7921_mcu_peer_cap peer = wtbl_info->peer_cap; - struct mt76_phy *mphy = &dev->mphy; - struct mt7921_sta_stats *stats; - struct mt7921_sta *msta; - struct mt76_wcid *wcid; - - if (wlan_idx >= MT76_N_WCIDS) - return; - - rcu_read_lock(); - - wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); - if (!wcid) - goto out; - - msta = container_of(wcid, struct mt7921_sta, wcid); - stats = &msta->stats; - - /* current rate */ - mt7921_mcu_tx_rate_parse(mphy, &peer, &rate, curr); - stats->tx_rate = rate; -out: - rcu_read_unlock(); -} - -static void mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; @@ -447,22 +413,33 @@ mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void -mt7921_mcu_beacon_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) +mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_connac_beacon_loss_event *event = priv; + + if (mvif->idx != event->bss_idx) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) + return; + + ieee80211_connection_loss(vif); +} + +static void +mt7921_mcu_connection_loss_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt76_connac_beacon_loss_event *event; - struct mt76_phy *mphy; - u8 band_idx = 0; /* DBDC support */ + struct mt76_phy *mphy = &dev->mt76.phy; skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; - if (band_idx && dev->mt76.phy2) - mphy = dev->mt76.phy2; - else - mphy = &dev->mt76.phy; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, - mt76_connac_mcu_beacon_loss_iter, event); + mt7921_mcu_connection_loss_iter, event); } static void @@ -521,13 +498,56 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb) } static void +mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb) +{ + struct mt7921_mcu_tx_done_event *event; + struct mt7921_sta *msta; + struct mt7921_phy *mphy = &dev->phy; + struct mt7921_mcu_peer_cap peer; + struct ieee80211_sta *sta; + LIST_HEAD(list); + + skb_pull(skb, sizeof(struct mt7921_mcu_rxd)); + event = (struct mt7921_mcu_tx_done_event *)skb->data; + + spin_lock_bh(&dev->sta_poll_lock); + list_splice_init(&mphy->stats_list, &list); + + while (!list_empty(&list)) { + msta = list_first_entry(&list, struct mt7921_sta, stats_list); + list_del_init(&msta->stats_list); + + if (msta->wcid.idx != event->wlan_idx) + continue; + + spin_unlock_bh(&dev->sta_poll_lock); + + sta = wcid_to_sta(&msta->wcid); + + /* peer config based on IEEE SPEC */ + memset(&peer, 0x0, sizeof(peer)); + peer.bw = event->bw; + peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); + peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); + mt7921_mcu_tx_rate_parse(mphy->mt76, &peer, + &msta->stats.tx_rate, event->tx_rate); + + spin_lock_bh(&dev->sta_poll_lock); + break; + } + spin_unlock_bh(&dev->sta_poll_lock); +} + +static void mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) { struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_BSS_BEACON_LOSS: - mt7921_mcu_beacon_loss_event(dev, skb); + mt7921_mcu_connection_loss_event(dev, skb); break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: @@ -546,6 +566,9 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb) case MCU_EVENT_LP_INFO: mt7921_mcu_low_power_event(dev, skb); break; + case MCU_EVENT_TX_DONE: + mt7921_mcu_tx_done_event(dev, skb); + break; default: break; } @@ -566,6 +589,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb) rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || + rxd->eid == MCU_EVENT_TX_DONE || rxd->eid == MCU_EVENT_DBG_MSG || rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_LP_INFO || @@ -601,14 +625,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); - if (cipher == MT_CIPHER_BIP_CMAC_128) { - sec_key->cipher_id = MT_CIPHER_AES_CCMP; + if (cipher == MCU_CIPHER_BIP_CMAC_128) { + sec_key->cipher_id = MCU_CIPHER_AES_CCMP; sec_key->key_id = bip->keyidx; sec_key->key_len = 16; memcpy(sec_key->key, bip->key, 16); sec_key = &sec->key[1]; - sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128; + sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); @@ -620,14 +644,14 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb, sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MT_CIPHER_TKIP) { + if (cipher == MCU_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(sec_key->key + 16, key->key + 24, 8); memcpy(sec_key->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ - if (cipher == MT_CIPHER_AES_CCMP) { + if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(bip->key, key->key, key->keylen); bip->keyidx = key->keyidx; } @@ -907,7 +931,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); if (ret) { dev_dbg(dev->mt76.dev, "Firmware is already download\n"); - return -EIO; + goto fw_loaded; } ret = mt7921_load_patch(dev); @@ -925,14 +949,13 @@ static int mt7921_load_firmware(struct mt7921_dev *dev) return -EIO; } +fw_loaded: mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); #ifdef CONFIG_PM dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; #endif /* CONFIG_PM */ - clear_bit(MT76_STATE_PM, &dev->mphy.state); - dev_err(dev->mt76.dev, "Firmware init done\n"); return 0; @@ -966,7 +989,7 @@ int mt7921_run_firmware(struct mt7921_dev *dev) set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt7921_mcu_fw_log_2_host(dev, 1); - return 0; + return mt76_connac_mcu_get_nic_capability(&dev->mphy); } int mt7921_mcu_init(struct mt7921_dev *dev) @@ -1133,26 +1156,6 @@ int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset) return 0; } -u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx) -{ - struct mt7921_mcu_wlan_info wtbl_info = { - .wlan_idx = cpu_to_le32(wlan_idx), - }; - struct sk_buff *skb; - int ret; - - ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL, - &wtbl_info, sizeof(wtbl_info), true, - &skb); - if (ret) - return ret; - - mt7921_mcu_tx_rate_report(dev, skb, wlan_idx); - dev_kfree_skb(skb); - - return 0; -} - int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; @@ -1265,8 +1268,9 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, sizeof(req), false); } -int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, bool enable) +int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state) { struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; int rssi = -ewma_rssi_read(&mvif->rssi); @@ -1275,27 +1279,25 @@ int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD_STA_REC_UPDATE, + .state = state, + .offload_fw = true, .rcpi = to_rcpi(rssi), }; struct mt7921_sta *msta; msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL; info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; - return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info); + return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); } -int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int i, err = 0; - mutex_lock(&pm->mutex); - - if (!test_bit(MT76_STATE_PM, &mphy->state)) - goto out; - for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL, @@ -1316,6 +1318,22 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) pm->stats.doze_time += pm->stats.last_wake_event - pm->stats.last_doze_event; out: + return err; +} + +int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + int err = 0; + + mutex_lock(&pm->mutex); + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + err = __mt7921_mcu_drv_pmctrl(dev); +out: mutex_unlock(&pm->mutex); if (err) @@ -1365,6 +1383,7 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7921_phy *phy = priv; struct mt7921_dev *dev = phy->dev; + struct ieee80211_hw *hw = mt76_hw(dev); int ret; if (dev->pm.enable) @@ -1377,9 +1396,11 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) if (dev->pm.enable) { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } else { vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index 49823d0a3d0a..d76cf8f8dfdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -81,6 +81,7 @@ enum { MCU_EVENT_REG_ACCESS = 0x05, MCU_EVENT_LP_INFO = 0x07, MCU_EVENT_SCAN_DONE = 0x0d, + MCU_EVENT_TX_DONE = 0x0f, MCU_EVENT_BSS_ABSENCE = 0x11, MCU_EVENT_BSS_BEACON_LOSS = 0x13, MCU_EVENT_CH_PRIVILEGE = 0x18, @@ -197,18 +198,17 @@ struct sta_rec_sec { struct sec_key key[2]; } __packed; -enum mt7921_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_WEP104, - MT_CIPHER_WEP128, - MT_CIPHER_TKIP, - MT_CIPHER_AES_CCMP, - MT_CIPHER_CCMP_256, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, - MT_CIPHER_WAPI, - MT_CIPHER_BIP_CMAC_128, +enum mcu_cipher_type { + MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_WEP104, + MCU_CIPHER_WEP128, + MCU_CIPHER_TKIP, + MCU_CIPHER_AES_CCMP, + MCU_CIPHER_CCMP_256, + MCU_CIPHER_GCMP, + MCU_CIPHER_GCMP_256, + MCU_CIPHER_WAPI, + MCU_CIPHER_BIP_CMAC_128, }; enum { @@ -254,86 +254,6 @@ struct mt7921_mcu_reg_event { __le32 val; } __packed; -struct mt7921_mcu_tx_config { - u8 peer_addr[ETH_ALEN]; - u8 sw; - u8 dis_rx_hdr_tran; - - u8 aad_om; - u8 pfmu_idx; - __le16 partial_aid; - - u8 ibf; - u8 ebf; - u8 is_ht; - u8 is_vht; - - u8 mesh; - u8 baf_en; - u8 cf_ack; - u8 rdg_ba; - - u8 rdg; - u8 pm; - u8 rts; - u8 smps; - - u8 txop_ps; - u8 not_update_ipsm; - u8 skip_tx; - u8 ldpc; - - u8 qos; - u8 from_ds; - u8 to_ds; - u8 dyn_bw; - - u8 amdsu_cross_lg; - u8 check_per; - u8 gid_63; - u8 he; - - u8 vht_ibf; - u8 vht_ebf; - u8 vht_ldpc; - u8 he_ldpc; -} __packed; - -struct mt7921_mcu_sec_config { - u8 wpi_flag; - u8 rv; - u8 ikv; - u8 rkv; - - u8 rcid; - u8 rca1; - u8 rca2; - u8 even_pn; - - u8 key_id; - u8 muar_idx; - u8 cipher_suit; - u8 rsv[1]; -} __packed; - -struct mt7921_mcu_key_config { - u8 key[32]; -} __packed; - -struct mt7921_mcu_rate_info { - u8 mpdu_fail; - u8 mpdu_tx; - u8 rate_idx; - u8 rsv[1]; - __le16 rate[8]; -} __packed; - -struct mt7921_mcu_ba_config { - u8 ba_en; - u8 rsv[3]; - __le32 ba_winsize; -} __packed; - struct mt7921_mcu_ant_id_config { u8 ant_id[4]; } __packed; @@ -357,41 +277,6 @@ struct mt7921_mcu_peer_cap { u8 rsv[1]; } __packed; -struct mt7921_mcu_rx_cnt { - u8 rx_rcpi[4]; - u8 rx_cc[4]; - u8 rx_cc_sel; - u8 ce_rmsd; - u8 rsv[2]; -} __packed; - -struct mt7921_mcu_tx_cnt { - __le16 rate1_cnt; - __le16 rate1_fail_cnt; - __le16 rate2_cnt; - __le16 rate3_cnt; - __le16 cur_bw_tx_cnt; - __le16 cur_bw_tx_fail_cnt; - __le16 other_bw_tx_cnt; - __le16 other_bw_tx_fail_cnt; -} __packed; - -struct mt7921_mcu_wlan_info_event { - struct mt7921_mcu_tx_config tx_config; - struct mt7921_mcu_sec_config sec_config; - struct mt7921_mcu_key_config key_config; - struct mt7921_mcu_rate_info rate_info; - struct mt7921_mcu_ba_config ba_config; - struct mt7921_mcu_peer_cap peer_cap; - struct mt7921_mcu_rx_cnt rx_cnt; - struct mt7921_mcu_tx_cnt tx_cnt; -} __packed; - -struct mt7921_mcu_wlan_info { - __le32 wlan_idx; - struct mt7921_mcu_wlan_info_event event; -} __packed; - struct mt7921_txpwr_req { u8 ver; u8 action; @@ -407,4 +292,31 @@ struct mt7921_txpwr_event { struct mt7921_txpwr txpwr; } __packed; +struct mt7921_mcu_tx_done_event { + u8 pid; + u8 status; + u16 seq; + + u8 wlan_idx; + u8 tx_cnt; + u16 tx_rate; + + u8 flag; + u8 tid; + u8 rsp_rate; + u8 mcs; + + u8 bw; + u8 tx_pwr; + u8 reason; + u8 rsv0[1]; + + u32 delay; + u32 timestamp; + u32 applied_flag; + + u8 txs[28]; + + u8 rsv1[32]; +} __packed; #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 59862ea4951c..2d8bd6bfc820 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -92,6 +92,8 @@ struct mt7921_sta { unsigned long ampdu_state; struct mt7921_sta_key_conf bip; + + unsigned long next_txs_ts; }; DECLARE_EWMA(rssi, 10, 8); @@ -100,6 +102,8 @@ struct mt7921_vif { struct mt76_vif mt76; /* must be first */ struct mt7921_sta sta; + struct mt7921_sta *wep_sta; + struct mt7921_phy *phy; struct ewma_rssi rssi; @@ -156,6 +160,8 @@ struct mt7921_dev { u16 chainmask; struct work_struct reset_work; + bool hw_full_reset:1; + bool hw_init_done:1; struct list_head sta_poll_list; spinlock_t sta_poll_lock; @@ -256,9 +262,9 @@ int mt7921_mcu_init(struct mt7921_dev *dev); int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif, struct mt7921_sta *msta, struct ieee80211_key_conf *key, enum set_key_cmd cmd); -int mt7921_set_channel(struct mt7921_phy *phy); -int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, bool enable); +int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state); int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd); int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif); int mt7921_mcu_set_eeprom(struct mt7921_dev *dev); @@ -318,7 +324,7 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev) return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } -void mt7921_mac_init(struct mt7921_dev *dev); +int mt7921_mac_init(struct mt7921_dev *dev); bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask); void mt7921_mac_reset_counters(struct mt7921_phy *phy); void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, @@ -330,6 +336,8 @@ void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb); void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb); int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7921_mac_work(struct work_struct *work); @@ -352,7 +360,7 @@ void mt7921_stats_work(struct work_struct *work); void mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); void mt7921_set_stream_he_caps(struct mt7921_phy *phy); -void mt7921_update_channel(struct mt76_dev *mdev); +void mt7921_update_channel(struct mt76_phy *mphy); int mt7921_init_debugfs(struct mt7921_dev *dev); int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, @@ -362,12 +370,12 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, struct ieee80211_ampdu_params *params, bool enable); void mt7921_scan_work(struct work_struct *work); -u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u32 wlan_idx); int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif); int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, bool enable); +int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); void mt7921_pm_wake_work(struct work_struct *work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index fa02d934f0bf..c3905bcab360 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -106,6 +106,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .rx_poll_complete = mt7921_rx_poll_complete, .sta_ps = mt7921_sta_ps, .sta_add = mt7921_mac_sta_add, + .sta_assoc = mt7921_mac_sta_assoc, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt7921_update_channel, }; @@ -188,22 +189,29 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; bool hif_suspend; int i, err; - err = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + pm->suspended = true; + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + err = mt7921_mcu_drv_pmctrl(dev); if (err < 0) - return err; + goto restore_suspend; hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state); if (hif_suspend) { err = mt76_connac_mcu_set_hif_suspend(mdev, true); if (err) - return err; + goto restore_suspend; } - if (!dev->pm.enable) - mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); + /* always enable deep sleep during suspend to reduce + * power consumption + */ + mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); napi_disable(&mdev->tx_napi); mt76_worker_disable(&mdev->tx_worker); @@ -231,27 +239,30 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state) err = mt7921_mcu_fw_pmctrl(dev); if (err) - goto restore; + goto restore_napi; pci_save_state(pdev); err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); if (err) - goto restore; + goto restore_napi; return 0; -restore: +restore_napi: mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); - if (!dev->pm.enable) + if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); if (hif_suspend) mt76_connac_mcu_set_hif_suspend(mdev, false); +restore_suspend: + pm->suspended = false; + return err; } @@ -259,8 +270,10 @@ static int mt7921_pci_resume(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; int i, err; + pm->suspended = false; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; @@ -291,7 +304,8 @@ static int mt7921_pci_resume(struct pci_dev *pdev) napi_enable(&mdev->tx_napi); napi_schedule(&mdev->tx_napi); - if (!dev->pm.enable) + /* restore previous ds setting */ + if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state)) diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index a18d2896ee1f..783a15635ec5 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -184,9 +184,6 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) if (!q->queued) wake_up(&dev->tx_wait); - if (!mcu) - mt76_txq_schedule(&dev->phy, q->qid); - return nframes; } @@ -195,19 +192,28 @@ static void mt76s_status_worker(struct mt76_worker *w) struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, status_worker); struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); + bool resched = false; int i, nframes; do { + int ndata_frames = 0; + nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]); for (i = 0; i <= MT_TXQ_PSD; i++) - nframes += mt76s_process_tx_queue(dev, - dev->phy.q_tx[i]); + ndata_frames += mt76s_process_tx_queue(dev, + dev->phy.q_tx[i]); + nframes += ndata_frames; + if (ndata_frames > 0) + resched = true; if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) queue_work(dev->wq, &dev->sdio.stat_work); } while (nframes > 0); + + if (resched) + mt76_worker_schedule(&dev->sdio.txrx_worker); } static void mt76s_tx_status_data(struct work_struct *work) @@ -256,6 +262,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, q->entry[q->head].skb = tx_info.skb; q->entry[q->head].buf_sz = len; + q->entry[q->head].wcid = 0xffff; smp_wmb(); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c index 001d0ba5f73e..f73ffbd6e622 100644 --- a/drivers/net/wireless/mediatek/mt76/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -88,17 +88,8 @@ static void mt76_testmode_free_skb(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; - struct sk_buff *skb = td->tx_skb; - - if (!skb) - return; - if (skb_has_frag_list(skb)) { - kfree_skb_list(skb_shinfo(skb)->frag_list); - skb_shinfo(skb)->frag_list = NULL; - } - - dev_kfree_skb(skb); + dev_kfree_skb(td->tx_skb); td->tx_skb = NULL; } @@ -158,19 +149,18 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) frag_len = MT_TXP_MAX_LEN; frag = alloc_skb(frag_len, GFP_KERNEL); - if (!frag) + if (!frag) { + mt76_testmode_free_skb(phy); + dev_kfree_skb(head); return -ENOMEM; + } __skb_put_zero(frag, frag_len); head->len += frag->len; head->data_len += frag->len; - if (*frag_tail) { - (*frag_tail)->next = frag; - frag_tail = &frag; - } else { - *frag_tail = frag; - } + *frag_tail = frag; + frag_tail = &(*frag_tail)->next; } mt76_testmode_free_skb(phy); @@ -531,6 +521,14 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) u64 rx_fcs_error = 0; int i; + if (dev->test_ops->dump_stats) { + int ret; + + ret = dev->test_ops->dump_stats(phy, msg); + if (ret) + return ret; + } + for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) { rx_packets += td->rx_stats.packets[i]; rx_fcs_error += td->rx_stats.fcs_error[i]; @@ -545,9 +543,6 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) MT76_TM_STATS_ATTR_PAD)) return -EMSGSIZE; - if (dev->test_ops->dump_stats) - return dev->test_ops->dump_stats(phy, msg); - return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 53ea8de82df0..f0f7a913eaab 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -54,11 +54,23 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) spin_unlock_bh(&dev->status_list.lock); + rcu_read_lock(); while ((skb = __skb_dequeue(list)) != NULL) { + struct ieee80211_tx_status status = { + .skb = skb, + .info = IEEE80211_SKB_CB(skb), + }; + struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->wcid[cb->wcid]); + if (wcid) + status.sta = wcid_to_sta(wcid); + hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_tx_status(hw, skb); + ieee80211_tx_status_ext(hw, &status); } - + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_tx_status_unlock); @@ -80,7 +92,7 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, /* Tx status can be unreliable. if it fails, mark the frame as ACKed */ if (flags & MT_TX_CB_TXS_FAILED) { - ieee80211_tx_info_clear_status(info); + info->status.rates[0].count = 0; info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; } @@ -117,12 +129,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, spin_lock_bh(&dev->status_list.lock); memset(cb, 0, sizeof(*cb)); - wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK; - if (wcid->packet_id == MT_PACKET_ID_NO_ACK || - wcid->packet_id == MT_PACKET_ID_NO_SKB) - wcid->packet_id = MT_PACKET_ID_FIRST; - - pid = wcid->packet_id; + pid = mt76_get_next_pkt_id(wcid); cb->wcid = wcid->idx; cb->pktid = pid; cb->jiffies = jiffies; @@ -173,36 +180,37 @@ mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush) EXPORT_SYMBOL_GPL(mt76_tx_status_check); static void -mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) +mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, + struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct mt76_wcid *wcid; int pending; - if (info->tx_time_est) - return; - - if (wcid_idx >= ARRAY_SIZE(dev->wcid)) + if (!wcid || info->tx_time_est) return; - rcu_read_lock(); - - wcid = rcu_dereference(dev->wcid[wcid_idx]); - if (wcid) { - pending = atomic_dec_return(&wcid->non_aql_packets); - if (pending < 0) - atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); - } - - rcu_read_unlock(); + pending = atomic_dec_return(&wcid->non_aql_packets); + if (pending < 0) + atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); } -void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb) +void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, + struct list_head *free_list) { + struct ieee80211_tx_status status = { + .skb = skb, + .free_list = free_list, + }; + struct mt76_wcid *wcid = NULL; struct ieee80211_hw *hw; struct sk_buff_head list; - mt76_tx_check_non_aql(dev, wcid_idx, skb); + rcu_read_lock(); + + if (wcid_idx < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[wcid_idx]); + + mt76_tx_check_non_aql(dev, wcid, skb); #ifdef CONFIG_NL80211_TESTMODE if (mt76_is_testmode_skb(dev, skb, &hw)) { @@ -214,21 +222,25 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk wake_up(&dev->tx_wait); dev_kfree_skb_any(skb); - return; + goto out; } #endif if (!skb->prev) { hw = mt76_tx_status_get_hw(dev, skb); - ieee80211_free_txskb(hw, skb); - return; + status.sta = wcid_to_sta(wcid); + ieee80211_tx_status_ext(hw, &status); + goto out; } mt76_tx_status_lock(dev, &list); __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list); mt76_tx_status_unlock(dev, &list); + +out: + rcu_read_unlock(); } -EXPORT_SYMBOL_GPL(mt76_tx_complete_skb); +EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb); static int __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, @@ -244,11 +256,15 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, non_aql = !info->tx_time_est; idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta); - if (idx < 0 || !sta || !non_aql) + if (idx < 0 || !sta) return idx; wcid = (struct mt76_wcid *)sta->drv_priv; q->entry[idx].wcid = wcid->idx; + + if (!non_aql) + return idx; + pending = atomic_inc_return(&wcid->non_aql_packets); if (stop && pending >= MT_MAX_NON_AQL_PKT) *stop = true; @@ -285,7 +301,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, skb_set_queue_mapping(skb, qid); } - if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) + if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 30bc54e98c58..1e9f60bb811a 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -925,6 +925,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, q->head = (q->head + 1) % q->ndesc; q->entry[idx].skb = tx_info.skb; + q->entry[idx].wcid = 0xffff; q->queued++; return idx; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 6bcc4a13ae6c..cc772045d526 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -26,6 +26,7 @@ static const struct usb_device_id mt7601u_device_table[] = { { USB_DEVICE(0x2717, 0x4106) }, { USB_DEVICE(0x2955, 0x0001) }, { USB_DEVICE(0x2955, 0x1001) }, + { USB_DEVICE(0x2955, 0x1003) }, { USB_DEVICE(0x2a5f, 0x1000) }, { USB_DEVICE(0x7392, 0x7710) }, { 0, } diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 1472e9843896..8e9aaf03a6fa 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -164,7 +164,7 @@ static int wilc_bus_probe(struct spi_device *spi) wilc->bus_data = spi_priv; wilc->dev_irq_num = spi->irq; - wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk"); + wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc"); if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) { kfree(spi_priv); return -EPROBE_DEFER; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 5264b0a1f098..deddb0afd312 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -1037,7 +1037,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi, * FIXME: if we do not find matching entry, we tell that frame was * posted without any retries. We need to find a way to fix that * and provide retry count. - */ + */ if (unlikely((aggr == 1 && ampdu == 0 && real_mcs != mcs)) || !match) { rt2800_rate_from_status(skbdesc, status, rt2x00dev->curr_band); mcs = real_mcs; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index d4d389e8f1b4..fb1d31b2d52a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -446,8 +446,9 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, * Beacons and probe responses require the tsf timestamp * to be inserted into the frame. */ - if (ieee80211_is_beacon(hdr->frame_control) || - ieee80211_is_probe_resp(hdr->frame_control)) + if ((ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) && + !(tx_info->flags & IEEE80211_TX_CTL_INJECTED)) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); if ((tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) && diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index d1a566cc0c9e..01735776345a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -853,15 +853,10 @@ struct rtl8192eu_efuse { u8 usb_optional_function; u8 res9[2]; u8 mac_addr[ETH_ALEN]; /* 0xd7 */ - u8 res10[2]; - u8 vendor_name[7]; - u8 res11[2]; - u8 device_name[0x0b]; /* 0xe8 */ - u8 res12[2]; - u8 serial[0x0b]; /* 0xf5 */ - u8 res13[0x30]; + u8 device_info[80]; + u8 res11[3]; u8 unknown[0x0d]; /* 0x130 */ - u8 res14[0xc3]; + u8 res12[0xc3]; }; struct rtl8xxxu_reg8val { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index cfe2dfdae928..b06508d0cdf8 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -554,9 +554,43 @@ rtl8192e_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) } } +static void rtl8192eu_log_next_device_info(struct rtl8xxxu_priv *priv, + char *record_name, + char *device_info, + unsigned int *record_offset) +{ + char *record = device_info + *record_offset; + + /* A record is [ total length | 0x03 | value ] */ + unsigned char l = record[0]; + + /* + * The whole device info section seems to be 80 characters, make sure + * we don't read further. + */ + if (*record_offset + l > 80) { + dev_warn(&priv->udev->dev, + "invalid record length %d while parsing \"%s\" at offset %u.\n", + l, record_name, *record_offset); + return; + } + + if (l >= 2) { + char value[80]; + + memcpy(value, &record[2], l - 2); + value[l - 2] = '\0'; + dev_info(&priv->udev->dev, "%s: %s\n", record_name, value); + *record_offset = *record_offset + l; + } else { + dev_info(&priv->udev->dev, "%s not available.\n", record_name); + } +} + static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) { struct rtl8192eu_efuse *efuse = &priv->efuse_wifi.efuse8192eu; + unsigned int record_offset; int i; if (efuse->rtl_id != cpu_to_le16(0x8129)) @@ -604,12 +638,25 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv) priv->has_xtalk = 1; priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f; - dev_info(&priv->udev->dev, "Vendor: %.7s\n", efuse->vendor_name); - dev_info(&priv->udev->dev, "Product: %.11s\n", efuse->device_name); - if (memchr_inv(efuse->serial, 0xff, 11)) - dev_info(&priv->udev->dev, "Serial: %.11s\n", efuse->serial); - else - dev_info(&priv->udev->dev, "Serial not available.\n"); + /* + * device_info section seems to be laid out as records + * [ total length | 0x03 | value ] so: + * - vendor length + 2 + * - 0x03 + * - vendor string (not null terminated) + * - product length + 2 + * - 0x03 + * - product string (not null terminated) + * Then there is one or 2 0x00 on all the 4 devices I own or found + * dumped online. + * As previous version of the code handled an optional serial + * string, I now assume there may be a third record if the + * length is not 0. + */ + record_offset = 0; + rtl8192eu_log_next_device_info(priv, "Vendor", efuse->device_info, &record_offset); + rtl8192eu_log_next_device_info(priv, "Product", efuse->device_info, &record_offset); + rtl8192eu_log_next_device_info(priv, "Serial", efuse->device_info, &record_offset); if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) { unsigned char *raw = priv->efuse_wifi.raw; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9ff09cf7eb62..ac1061caacd6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5554,6 +5554,11 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) urb_len = skb->len; pkt_cnt = 0; + if (urb_len < sizeof(struct rtl8xxxu_rxdesc16)) { + kfree_skb(skb); + return RX_TYPE_ERROR; + } + do { rx_desc = (struct rtl8xxxu_rxdesc16 *)skb->data; _rx_desc_le = (__le32 *)skb->data; @@ -5581,7 +5586,7 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) * at least cover the rx descriptor */ if (pkt_cnt > 1 && - urb_len > (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16))) + urb_len >= (pkt_offset + sizeof(struct rtl8xxxu_rxdesc16))) next_skb = skb_clone(skb, GFP_ATOMIC); rx_status = IEEE80211_SKB_RXCB(skb); @@ -5627,7 +5632,9 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) pkt_cnt--; urb_len -= pkt_offset; - } while (skb && urb_len > 0 && pkt_cnt > 0); + next_skb = NULL; + } while (skb && pkt_cnt > 0 && + urb_len >= sizeof(struct rtl8xxxu_rxdesc16)); return RX_TYPE_DATA_PKT; } diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index 447caa4aad32..c5b8df58d4a2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -1721,10 +1721,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); coex_dm->ps_tdma_du_adj_type = 14; - } else if (max_interval == 3) { - btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, true, 15); - coex_dm->ps_tdma_du_adj_type = 15; } else { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); @@ -1739,10 +1735,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); coex_dm->ps_tdma_du_adj_type = 10; - } else if (max_interval == 3) { - btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, true, 11); - coex_dm->ps_tdma_du_adj_type = 11; } else { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); @@ -1759,10 +1751,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); coex_dm->ps_tdma_du_adj_type = 6; - } else if (max_interval == 3) { - btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, true, 7); - coex_dm->ps_tdma_du_adj_type = 7; } else { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 7); @@ -1777,10 +1765,6 @@ static void btc8821a2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); coex_dm->ps_tdma_du_adj_type = 2; - } else if (max_interval == 3) { - btc8821a2ant_ps_tdma(btcoexist, - NORMAL_EXEC, true, 3); - coex_dm->ps_tdma_du_adj_type = 3; } else { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); @@ -2810,6 +2794,7 @@ static void btc8821a2ant_action_a2dp(struct btc_coexist *btcoexist) 0x4); } + /* preserve identical branches for further fine-tuning */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); @@ -2944,6 +2929,7 @@ static void btc8821a2ant_action_pan_edr(struct btc_coexist *btcoexist) 0x4); } + /* preserve identical branches for further fine-tuning */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26); @@ -3132,6 +3118,7 @@ static void btc8821a2ant_action_pan_edr_hid(struct btc_coexist *btcoexist) btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* preserve identical branches for further fine-tuning */ if (wifi_bw == BTC_WIFI_BW_LEGACY) { /* for HID at 11b/g mode */ btc8821a2ant_coex_table(btcoexist, NORMAL_EXEC, 0x55ff55ff, @@ -3321,6 +3308,7 @@ static void btc8821a2ant_action_hid_a2dp(struct btc_coexist *btcoexist) 0x4); } + /* preserve identical branches for further fine-tuning */ if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { btc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); diff --git a/drivers/net/wireless/realtek/rtlwifi/cam.c b/drivers/net/wireless/realtek/rtlwifi/cam.c index 7aa28da39409..7a0355dc6bab 100644 --- a/drivers/net/wireless/realtek/rtlwifi/cam.c +++ b/drivers/net/wireless/realtek/rtlwifi/cam.c @@ -167,7 +167,7 @@ void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index) u32 ul_command; u32 ul_content; - u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES]; + u32 ul_enc_algo; switch (rtlpriv->sec.pairwise_enc_algorithm) { case WEP40_ENCRYPTION: diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c index 8d2c6d8d32d9..4ff0d4118193 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c @@ -112,7 +112,7 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) } /** - * writeLLT - LLT table write access + * rtl92c_llt_write - LLT table write access * @hw: Pointer to the ieee80211_hw structure. * @address: LLT logical address. * @data: LLT data content @@ -144,7 +144,7 @@ bool rtl92c_llt_write(struct ieee80211_hw *hw, u32 address, u32 data) } /** - * rtl92c_init_LLT_table - Init LLT table + * rtl92c_init_llt_table - Init LLT table * @hw: Pointer to the ieee80211_hw structure. * @boundary: Page boundary. * diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 68ec009ea157..76dd881ef9bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -2574,7 +2574,7 @@ static void _rtl92d_phy_lc_calibrate_sw(struct ieee80211_hw *hw, bool is2t) RTPRINT(rtlpriv, FINIT, INIT_IQK, "path-B / 2.4G LCK\n"); } - memset(&curvecount_val[0], 0, CV_CURVE_CNT * 2); + memset(curvecount_val, 0, sizeof(curvecount_val)); /* Set LC calibration off */ rtl_set_rfreg(hw, (enum radio_path)index, RF_CHNLBW, 0x08000, 0x0); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index 38034102aacb..e474b4ec17f3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -513,7 +513,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc8, /* 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 */ + /* For firmware download we only need to set LINIP */ set_tx_desc_linip(pdesc, tcb_desc->last_inipkt); /* 92SE must set as 1 for firmware download HW DMA error */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index f8a1de6e9849..c98f2216734f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -915,7 +915,7 @@ int rtl8723e_hw_init(struct ieee80211_hw *hw) struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - bool rtstatus = true; + bool rtstatus; int err; u8 tmp_u1b; unsigned long flags; diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index cedbf3825848..2551e228b581 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -591,8 +591,10 @@ void rtw_coex_info_response(struct rtw_dev *rtwdev, struct sk_buff *skb) struct rtw_coex *coex = &rtwdev->coex; u8 *payload = get_payload_from_coex_resp(skb); - if (payload[0] != COEX_RESP_ACK_BY_WL_FW) + if (payload[0] != COEX_RESP_ACK_BY_WL_FW) { + dev_kfree_skb_any(skb); return; + } skb_queue_tail(&coex->queue, skb); wake_up(&coex->wait); @@ -630,20 +632,16 @@ static bool rtw_coex_get_bt_scan_type(struct rtw_dev *rtwdev, u8 *scan_type) struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SCAN_TYPE; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *scan_type = GET_COEX_RESP_BT_SCAN_TYPE(payload); dev_kfree_skb_any(skb); - ret = true; - -out: - return ret; + return true; } static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, @@ -651,19 +649,15 @@ static bool rtw_coex_set_lna_constrain_level(struct rtw_dev *rtwdev, { struct rtw_coex_info_req req = {0}; struct sk_buff *skb; - bool ret = false; req.op_code = BT_MP_INFO_OP_LNA_CONSTRAINT; req.para1 = lna_constrain_level; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; dev_kfree_skb_any(skb); - ret = true; - -out: - return ret; + return true; } #define case_BTSTATUS(src) \ @@ -3523,6 +3517,7 @@ static bool rtw_coex_get_bt_reg(struct rtw_dev *rtwdev, payload = get_payload_from_coex_resp(skb); *val = GET_COEX_RESP_BT_REG_VAL(payload); + dev_kfree_skb_any(skb); return true; } @@ -3533,19 +3528,17 @@ static bool rtw_coex_get_bt_patch_version(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_PATCH_VER; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *patch_version = GET_COEX_RESP_BT_PATCH_VER(payload); - ret = true; + dev_kfree_skb_any(skb); -out: - return ret; + return true; } static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, @@ -3554,19 +3547,17 @@ static bool rtw_coex_get_bt_supported_version(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SUPP_VER; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *supported_version = GET_COEX_RESP_BT_SUPP_VER(payload); - ret = true; + dev_kfree_skb_any(skb); -out: - return ret; + return true; } static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, @@ -3575,19 +3566,17 @@ static bool rtw_coex_get_bt_supported_feature(struct rtw_dev *rtwdev, struct rtw_coex_info_req req = {0}; struct sk_buff *skb; u8 *payload; - bool ret = false; req.op_code = BT_MP_INFO_OP_SUPP_FEAT; skb = rtw_coex_info_request(rtwdev, &req); if (!skb) - goto out; + return false; payload = get_payload_from_coex_resp(skb); *supported_feature = GET_COEX_RESP_BT_SUPP_FEAT(payload); - ret = true; + dev_kfree_skb_any(skb); -out: - return ret; + return true; } struct rtw_coex_sta_stat_iter_data { diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 18ab472ea46c..dfd52cff5d02 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -11,6 +11,7 @@ #include "debug.h" #include "phy.h" #include "reg.h" +#include "ps.h" #ifdef CONFIG_RTW88_DEBUGFS @@ -847,7 +848,13 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp, if (!input) return -EINVAL; + if (test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) + return -EINPROGRESS; + + mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); rtw_write8(rtwdev, REG_HRCV_MSG, 1); + mutex_unlock(&rtwdev->mutex); return count; } diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index c8efd1900a34..0dd3f9a88c8d 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -20,6 +20,7 @@ enum rtw_debug_mask { RTW_DBG_BF = 0x00000800, RTW_DBG_WOW = 0x00001000, RTW_DBG_CFO = 0x00002000, + RTW_DBG_PATH_DIV = 0x00004000, RTW_DBG_ALL = 0xffffffff }; diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index ea2cd4db1d3c..3bfa5ecc0053 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -127,6 +127,62 @@ static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); } +struct rtw_beacon_filter_iter_data { + struct rtw_dev *rtwdev; + u8 *payload; +}; + +static void rtw_fw_bcn_filter_notify_vif_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct rtw_beacon_filter_iter_data *iter_data = data; + struct rtw_dev *rtwdev = iter_data->rtwdev; + u8 *payload = iter_data->payload; + u8 type = GET_BCN_FILTER_NOTIFY_TYPE(payload); + u8 event = GET_BCN_FILTER_NOTIFY_EVENT(payload); + s8 sig = (s8)GET_BCN_FILTER_NOTIFY_RSSI(payload); + + switch (type) { + case BCN_FILTER_NOTIFY_SIGNAL_CHANGE: + event = event ? NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH : + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + ieee80211_cqm_rssi_notify(vif, event, sig, GFP_KERNEL); + break; + case BCN_FILTER_CONNECTION_LOSS: + ieee80211_connection_loss(vif); + break; + case BCN_FILTER_CONNECTED: + rtwdev->beacon_loss = false; + break; + case BCN_FILTER_NOTIFY_BEACON_LOSS: + rtwdev->beacon_loss = true; + rtw_leave_lps(rtwdev); + break; + } +} + +static void rtw_fw_bcn_filter_notify(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_beacon_filter_iter_data dev_iter_data; + + dev_iter_data.rtwdev = rtwdev; + dev_iter_data.payload = payload; + rtw_iterate_vifs(rtwdev, rtw_fw_bcn_filter_notify_vif_iter, + &dev_iter_data); +} + +static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->scan_density = payload[0]; + + rtw_dbg(rtwdev, RTW_DBG_FW, "scan.density = %x\n", + dm_info->scan_density); +} + void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; @@ -152,6 +208,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) case C2H_WLAN_INFO: rtw_coex_wl_fwdbginfo_notify(rtwdev, c2h->payload, len); break; + case C2H_BCN_FILTER_NOTIFY: + rtw_fw_bcn_filter_notify(rtwdev, c2h->payload, len); + break; case C2H_HALMAC: rtw_fw_c2h_cmd_handle_ext(rtwdev, skb); break; @@ -186,6 +245,12 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, break; case C2H_WLAN_RFON: complete(&rtwdev->lps_leave_check); + dev_kfree_skb_any(skb); + break; + case C2H_SCAN_RESULT: + complete(&rtwdev->fw_scan_density); + rtw_fw_scan_result(rtwdev, c2h->payload, len); + dev_kfree_skb_any(skb); break; default: /* pass offset for further operation */ @@ -527,6 +592,45 @@ void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev) rtw_fw_send_h2c_command(rtwdev, h2c_pkt); } +void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, + struct ieee80211_vif *vif) +{ + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); + static const u8 rssi_min = 0, rssi_max = 100, rssi_offset = 100; + struct rtw_sta_info *si = + sta ? (struct rtw_sta_info *)sta->drv_priv : NULL; + s32 threshold = bss_conf->cqm_rssi_thold + rssi_offset; + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !si) + return; + + if (!connect) { + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1); + SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); + + return; + } + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P0); + ether_addr_copy(&h2c_pkt[1], bss_conf->bssid); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); + + memset(h2c_pkt, 0, sizeof(h2c_pkt)); + threshold = clamp_t(s32, threshold, rssi_min, rssi_max); + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_BCN_FILTER_OFFLOAD_P1); + SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, connect); + SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, + BCN_FILTER_OFFLOAD_MODE_DEFAULT); + SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, (u8)threshold); + SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, BCN_LOSS_CNT); + SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, si->mac_id); + SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, bss_conf->cqm_rssi_hyst); + SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, bss_conf->beacon_int); + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} + void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -1613,3 +1717,13 @@ void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable) rtw_fw_send_h2c_packet(rtwdev, h2c_pkt); } + +void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start) +{ + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_SCAN); + SET_SCAN_START(h2c_pkt, start); + + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 7c5b1d75e26f..a8a7162fbe64 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -24,6 +24,14 @@ #define DLFW_BLK_SIZE_LEGACY 4 #define FW_START_ADDR_LEGACY 0x1000 +#define BCN_LOSS_CNT 10 +#define BCN_FILTER_NOTIFY_SIGNAL_CHANGE 0 +#define BCN_FILTER_CONNECTION_LOSS 1 +#define BCN_FILTER_CONNECTED 2 +#define BCN_FILTER_NOTIFY_BEACON_LOSS 3 + +#define SCAN_NOTIFY_TIMEOUT msecs_to_jiffies(10) + enum rtw_c2h_cmd_id { C2H_CCX_TX_RPT = 0x03, C2H_BT_INFO = 0x09, @@ -32,6 +40,8 @@ enum rtw_c2h_cmd_id { C2H_HW_FEATURE_REPORT = 0x19, C2H_WLAN_INFO = 0x27, C2H_WLAN_RFON = 0x32, + C2H_BCN_FILTER_NOTIFY = 0x36, + C2H_SCAN_RESULT = 0x38, C2H_HW_FEATURE_DUMP = 0xfd, C2H_HALMAC = 0xff, }; @@ -78,9 +88,20 @@ enum rtw_fw_feature { FW_FEATURE_LPS_C2H = BIT(1), FW_FEATURE_LCLK = BIT(2), FW_FEATURE_PG = BIT(3), + FW_FEATURE_BCN_FILTER = BIT(5), + FW_FEATURE_NOTIFY_SCAN = BIT(6), FW_FEATURE_MAX = BIT(31), }; +enum rtw_beacon_filter_offload_mode { + BCN_FILTER_OFFLOAD_MODE_0 = 0, + BCN_FILTER_OFFLOAD_MODE_1, + BCN_FILTER_OFFLOAD_MODE_2, + BCN_FILTER_OFFLOAD_MODE_3, + + BCN_FILTER_OFFLOAD_MODE_DEFAULT = BCN_FILTER_OFFLOAD_MODE_1, +}; + struct rtw_coex_info_req { u8 seq; u8 op_code; @@ -237,6 +258,10 @@ struct rtw_fw_hdr_legacy { #define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) #define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) +#define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf) +#define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10) +#define GET_BCN_FILTER_NOTIFY_RSSI(c2h_payload) (c2h_payload[2] - 100) + /* PKT H2C */ #define H2C_PKT_CMD_ID 0xFF #define H2C_PKT_CATEGORY 0x01 @@ -345,7 +370,10 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_LPS_PG_INFO 0x2b #define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RSSI_MONITOR 0x42 +#define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56 +#define H2C_CMD_BCN_FILTER_OFFLOAD_P1 0x57 #define H2C_CMD_WL_PHY_INFO 0x58 +#define H2C_CMD_SCAN 0x59 #define H2C_CMD_COEX_TDMA_TYPE 0x60 #define H2C_CMD_QUERY_BT_INFO 0x61 @@ -381,6 +409,23 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8)) #define SET_WL_PHY_INFO_RX_EVM(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(23, 16)) +#define SET_BCN_FILTER_OFFLOAD_P1_MACID(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8)) +#define SET_BCN_FILTER_OFFLOAD_P1_ENABLE(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(16)) +#define SET_BCN_FILTER_OFFLOAD_P1_HYST(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(20, 17)) +#define SET_BCN_FILTER_OFFLOAD_P1_OFFLOAD_MODE(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 21)) +#define SET_BCN_FILTER_OFFLOAD_P1_THRESHOLD(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24)) +#define SET_BCN_FILTER_OFFLOAD_P1_BCN_LOSS_CNT(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(3, 0)) +#define SET_BCN_FILTER_OFFLOAD_P1_BCN_INTERVAL(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(13, 4)) + +#define SET_SCAN_START(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) #define SET_PWR_MODE_SET_MODE(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(14, 8)) @@ -554,6 +599,12 @@ static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb) return (struct rtw_c2h_cmd *)(skb->data + pkt_offset); } +static inline bool rtw_fw_feature_check(struct rtw_fw_state *fw, + enum rtw_fw_feature feature) +{ + return !!(fw->feature & feature); +} + void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, struct sk_buff *skb); void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb); @@ -577,6 +628,8 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); void rtw_fw_media_status_report(struct rtw_dev *rtwdev, u8 mac_id, bool conn); void rtw_fw_update_wl_phy_info(struct rtw_dev *rtwdev); +void rtw_fw_beacon_filter_config(struct rtw_dev *rtwdev, bool connect, + struct ieee80211_vif *vif); int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, u8 *buf, u32 size); void rtw_remove_rsvd_page(struct rtw_dev *rtwdev, @@ -607,5 +660,5 @@ void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c); void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev); int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size, u32 *buffer); - +void rtw_fw_scan_notify(struct rtw_dev *rtwdev, bool start); #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 333df6b38113..6f5629852416 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -153,6 +153,9 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, u8 port = 0; u8 bcn_ctrl = 0; + if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER)) + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; rtwvif->port = port; rtwvif->stats.tx_unicast = 0; rtwvif->stats.rx_unicast = 0; @@ -399,6 +402,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT_EN_BCNQ_DL); } + if (changed & BSS_CHANGED_CQM) + rtw_fw_beacon_filter_config(rtwdev, true, vif); if (changed & BSS_CHANGED_MU_GROUPS) rtw_chip_set_gid_table(rtwdev, vif, conf); @@ -450,6 +455,7 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; + rtw_fw_beacon_filter_config(rtwdev, false, vif); mutex_lock(&rtwdev->mutex); rtw_sta_remove(rtwdev, sta, true); mutex_unlock(&rtwdev->mutex); @@ -599,6 +605,7 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, rtw_vif_port_config(rtwdev, rtwvif, config); rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); + rtw_core_fw_scan_notify(rtwdev, true); set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); set_bit(RTW_FLAG_SCANNING, rtwdev->flags); @@ -618,6 +625,8 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); + rtw_core_fw_scan_notify(rtwdev, false); + ether_addr_copy(rtwvif->mac_addr, vif->addr); config |= PORT_SET_MAC_ADDR; rtw_vif_port_config(rtwdev, rtwvif, config); @@ -629,7 +638,7 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 duration) + struct ieee80211_prep_tx_info *info) { struct rtw_dev *rtwdev = hw->priv; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f3a3a86fa9b5..c6364837e83b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2,6 +2,8 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include <linux/devcoredump.h> + #include "main.h" #include "regd.h" #include "fw.h" @@ -239,7 +241,8 @@ static void rtw_watch_dog_work(struct work_struct *work) * get that vif and check if device is having traffic more than the * threshold. */ - if (rtwdev->ps_enabled && data.rtwvif && !ps_active) + if (rtwdev->ps_enabled && data.rtwvif && !ps_active && + !rtwdev->beacon_loss) rtw_enter_lps(rtwdev, data.rtwvif->port); rtwdev->watch_dog_cnt++; @@ -292,6 +295,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, rtw_fw_media_status_report(rtwdev, si->mac_id, true); rtwdev->sta_cnt++; + rtwdev->beacon_loss = false; rtw_info(rtwdev, "sta %pM joined with macid %d\n", sta->addr, si->mac_id); @@ -318,59 +322,131 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, sta->addr, si->mac_id); } -static bool rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) +struct rtw_fwcd_hdr { + u32 item; + u32 size; + u32 padding1; + u32 padding2; +} __packed; + +static int rtw_fwcd_prep(struct rtw_dev *rtwdev) +{ + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + const struct rtw_fwcd_segs *segs = chip->fwcd_segs; + u32 prep_size = chip->fw_rxff_size + sizeof(struct rtw_fwcd_hdr); + u8 i; + + if (segs) { + prep_size += segs->num * sizeof(struct rtw_fwcd_hdr); + + for (i = 0; i < segs->num; i++) + prep_size += segs->segs[i]; + } + + desc->data = vmalloc(prep_size); + if (!desc->data) + return -ENOMEM; + + desc->size = prep_size; + desc->next = desc->data; + + return 0; +} + +static u8 *rtw_fwcd_next(struct rtw_dev *rtwdev, u32 item, u32 size) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + struct rtw_fwcd_hdr *hdr; + u8 *next; + + if (!desc->data) { + rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared successfully\n"); + return NULL; + } + + next = desc->next + sizeof(struct rtw_fwcd_hdr); + if (next - desc->data + size > desc->size) { + rtw_dbg(rtwdev, RTW_DBG_FW, "fwcd isn't prepared enough\n"); + return NULL; + } + + hdr = (struct rtw_fwcd_hdr *)(desc->next); + hdr->item = item; + hdr->size = size; + hdr->padding1 = 0x01234567; + hdr->padding2 = 0x89abcdef; + desc->next = next + size; + + return next; +} + +static void rtw_fwcd_dump(struct rtw_dev *rtwdev) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + + rtw_dbg(rtwdev, RTW_DBG_FW, "dump fwcd\n"); + + /* Data will be freed after lifetime of device coredump. After calling + * dev_coredump, data is supposed to be handled by the device coredump + * framework. Note that a new dump will be discarded if a previous one + * hasn't been released yet. + */ + dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); +} + +static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) +{ + struct rtw_fwcd_desc *desc = &rtwdev->fw.fwcd_desc; + + if (free_self) { + rtw_dbg(rtwdev, RTW_DBG_FW, "free fwcd by self\n"); + vfree(desc->data); + } + + desc->data = NULL; + desc->next = NULL; +} + +static int rtw_fw_dump_crash_log(struct rtw_dev *rtwdev) { u32 size = rtwdev->chip->fw_rxff_size; u32 *buf; u8 seq; - bool ret = true; - buf = vmalloc(size); + buf = (u32 *)rtw_fwcd_next(rtwdev, RTW_FWCD_TLV, size); if (!buf) - goto exit; + return -ENOMEM; if (rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, size, buf)) { rtw_dbg(rtwdev, RTW_DBG_FW, "dump fw fifo fail\n"); - goto free_buf; + return -EINVAL; } if (GET_FW_DUMP_LEN(buf) == 0) { rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's length is 0\n"); - goto free_buf; + return -EINVAL; } seq = GET_FW_DUMP_SEQ(buf); - if (seq > 0 && seq != (rtwdev->fw.prev_dump_seq + 1)) { + if (seq > 0) { rtw_dbg(rtwdev, RTW_DBG_FW, "fw crash dump's seq is wrong: %d\n", seq); - goto free_buf; - } - - print_hex_dump(KERN_ERR, "rtw88 fw dump: ", DUMP_PREFIX_OFFSET, 16, 1, - buf, size, true); - - if (GET_FW_DUMP_MORE(buf) == 1) { - rtwdev->fw.prev_dump_seq = seq; - ret = false; + return -EINVAL; } -free_buf: - vfree(buf); -exit: - rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); - - return ret; + return 0; } int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, - const char *prefix_str) + u32 fwcd_item) { u32 rxff = rtwdev->chip->fw_rxff_size; u32 dump_size, done_size = 0; u8 *buf; int ret; - buf = vzalloc(size); + buf = rtw_fwcd_next(rtwdev, fwcd_item, size); if (!buf) return -ENOMEM; @@ -383,7 +459,7 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, rtw_err(rtwdev, "ddma fw 0x%x [+0x%x] to fw fifo fail\n", ocp_src, done_size); - goto exit; + return ret; } ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RXBUF_FW, 0, @@ -392,24 +468,18 @@ int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, rtw_err(rtwdev, "dump fw 0x%x [+0x%x] from fw fifo fail\n", ocp_src, done_size); - goto exit; + return ret; } size -= dump_size; done_size += dump_size; } - print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 1, - buf, done_size, true); - -exit: - vfree(buf); - return ret; + return 0; } EXPORT_SYMBOL(rtw_dump_fw); -int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, - const char *prefix_str) +int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size) { u8 *buf; u32 i; @@ -419,17 +489,13 @@ int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, return -EINVAL; } - buf = vzalloc(size); + buf = rtw_fwcd_next(rtwdev, RTW_FWCD_REG, size); if (!buf) return -ENOMEM; for (i = 0; i < size; i += 4) *(u32 *)(buf + i) = rtw_read32(rtwdev, addr + i); - print_hex_dump(KERN_ERR, prefix_str, DUMP_PREFIX_OFFSET, 16, 4, buf, - size, true); - - vfree(buf); return 0; } EXPORT_SYMBOL(rtw_dump_reg); @@ -487,20 +553,24 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev) static void __fw_recovery_work(struct rtw_dev *rtwdev) { - - /* rtw_fw_dump_crash_log() returns false indicates that there are - * still more log to dump. Driver set 0x1cf[7:0] = 0x1 to tell firmware - * to dump the remaining part of the log, and firmware will trigger an - * IMR_C2HCMD interrupt to inform driver the log is ready. - */ - if (!rtw_fw_dump_crash_log(rtwdev)) { - rtw_write8(rtwdev, REG_HRCV_MSG, 1); - return; - } - rtwdev->fw.prev_dump_seq = 0; + int ret = 0; set_bit(RTW_FLAG_RESTARTING, rtwdev->flags); - rtw_chip_dump_fw_crash(rtwdev); + + ret = rtw_fwcd_prep(rtwdev); + if (ret) + goto free; + ret = rtw_fw_dump_crash_log(rtwdev); + if (ret) + goto free; + ret = rtw_chip_dump_fw_crash(rtwdev); + if (ret) + goto free; + + rtw_fwcd_dump(rtwdev); +free: + rtw_fwcd_free(rtwdev, !!ret); + rtw_write8(rtwdev, REG_MCU_TST_CFG, 0); WARN(1, "firmware crash, start reset and recover\n"); @@ -1109,11 +1179,11 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, return LPS_DEEP_MODE_NONE; if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) && - (fw->feature & FW_FEATURE_PG)) + rtw_fw_feature_check(fw, FW_FEATURE_PG)) return LPS_DEEP_MODE_PG; if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) && - (fw->feature & FW_FEATURE_LCLK)) + rtw_fw_feature_check(fw, FW_FEATURE_LCLK)) return LPS_DEEP_MODE_LCLK; return LPS_DEEP_MODE_NONE; @@ -1183,6 +1253,22 @@ err: return ret; } +void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) +{ + if (!rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_NOTIFY_SCAN)) + return; + + if (start) { + rtw_fw_scan_notify(rtwdev, true); + } else { + reinit_completion(&rtwdev->fw_scan_density); + rtw_fw_scan_notify(rtwdev, false); + if (!wait_for_completion_timeout(&rtwdev->fw_scan_density, + SCAN_NOTIFY_TIMEOUT)) + rtw_warn(rtwdev, "firmware failed to report density after scan\n"); + } +} + int rtw_core_start(struct rtw_dev *rtwdev) { int ret; @@ -1761,6 +1847,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) init_waitqueue_head(&rtwdev->coex.wait); init_completion(&rtwdev->lps_leave_check); + init_completion(&rtwdev->fw_scan_density); rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; @@ -1812,6 +1899,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) destroy_workqueue(rtwdev->tx_wq); spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); skb_queue_purge(&rtwdev->tx_report.queue); + skb_queue_purge(&rtwdev->coex.queue); spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); list_for_each_entry_safe(rsvd_pkt, tmp, &rtwdev->rsvd_page_list, diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index dc3744847ba9..e5af375b3dd0 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -806,7 +806,7 @@ struct rtw_regulatory { struct rtw_chip_ops { int (*mac_init)(struct rtw_dev *rtwdev); - void (*dump_fw_crash)(struct rtw_dev *rtwdev); + int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); void (*phy_set_param)(struct rtw_dev *rtwdev); @@ -841,6 +841,10 @@ struct rtw_chip_ops { u8 fixrate_en, u8 *new_rate); void (*cfo_init)(struct rtw_dev *rtwdev); void (*cfo_track)(struct rtw_dev *rtwdev); + void (*config_tx_path)(struct rtw_dev *rtwdev, u8 tx_path, + enum rtw_bb_path tx_path_1ss, + enum rtw_bb_path tx_path_cck, + bool is_tx2_path); /* for coex */ void (*coex_set_init)(struct rtw_dev *rtwdev); @@ -1108,6 +1112,15 @@ enum rtw_fw_fifo_sel { RTW_FW_FIFO_MAX, }; +enum rtw_fwcd_item { + RTW_FWCD_TLV, + RTW_FWCD_REG, + RTW_FWCD_ROM, + RTW_FWCD_IMEM, + RTW_FWCD_DMEM, + RTW_FWCD_EMEM, +}; + /* hardware configuration for each IC */ struct rtw_chip_info { struct rtw_chip_ops *ops; @@ -1136,7 +1149,11 @@ struct rtw_chip_info { u8 max_power_index; u16 fw_fifo_addr[RTW_FW_FIFO_MAX]; + const struct rtw_fwcd_segs *fwcd_segs; + + u8 default_1ss_tx_path; + bool path_div_supported; bool ht_supported; bool vht_supported; u8 lps_deep_mode_supported; @@ -1614,6 +1631,8 @@ struct rtw_dm_info { struct rtw_iqk_info iqk; struct rtw_gapk_info gapk; bool is_bt_iqk_timeout; + + u8 scan_density; }; struct rtw_efuse { @@ -1717,6 +1736,17 @@ struct rtw_fifo_conf { const struct rtw_rqpn *rqpn; }; +struct rtw_fwcd_desc { + u32 size; + u8 *next; + u8 *data; +}; + +struct rtw_fwcd_segs { + const u32 *segs; + u8 num; +}; + #define FW_CD_TYPE 0xffff #define FW_CD_LEN 4 #define FW_CD_VAL 0xaabbccdd @@ -1724,11 +1754,11 @@ struct rtw_fw_state { const struct firmware *firmware; struct rtw_dev *rtwdev; struct completion completion; + struct rtw_fwcd_desc fwcd_desc; u16 version; u8 sub_version; u8 sub_index; u16 h2c_version; - u8 prev_dump_seq; u32 feature; }; @@ -1781,6 +1811,14 @@ struct rtw_hal { [DESC_RATE_MAX]; }; +struct rtw_path_div { + enum rtw_bb_path current_tx_path; + u32 path_a_sum; + u32 path_b_sum; + u16 path_a_cnt; + u16 path_b_cnt; +}; + struct rtw_dev { struct ieee80211_hw *hw; struct device *dev; @@ -1837,6 +1875,7 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; bool ps_enabled; + bool beacon_loss; struct completion lps_leave_check; struct dentry *debugfs; @@ -1848,11 +1887,13 @@ struct rtw_dev { DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS); u8 mp_mode; + struct rtw_path_div dm_path_div; struct rtw_fw_state wow_fw; struct rtw_wow_param wow; bool need_rfk; + struct completion fw_scan_density; /* hci related data, must be last */ u8 priv[] __aligned(sizeof(void *)); @@ -1923,10 +1964,12 @@ static inline void rtw_release_macid(struct rtw_dev *rtwdev, u8 mac_id) clear_bit(mac_id, rtwdev->mac_id_map); } -static inline void rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev) +static inline int rtw_chip_dump_fw_crash(struct rtw_dev *rtwdev) { if (rtwdev->chip->ops->dump_fw_crash) - rtwdev->chip->ops->dump_fw_crash(rtwdev); + return rtwdev->chip->ops->dump_fw_crash(rtwdev); + + return 0; } void rtw_get_channel_params(struct cfg80211_chan_def *chandef, @@ -1958,9 +2001,9 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, bool fw_exist); void rtw_fw_recovery(struct rtw_dev *rtwdev); +void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start); int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, - const char *prefix_str); -int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size, - const char *prefix_str); + u32 fwcd_item); +int rtw_dump_reg(struct rtw_dev *rtwdev, const u32 addr, const u32 size); #endif diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index f59a4c462e3b..e7d17ab8f113 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -2,6 +2,7 @@ /* Copyright(c) 2018-2019 Realtek Corporation */ +#include <linux/dmi.h> #include <linux/module.h> #include <linux/pci.h> #include "main.h" @@ -1673,6 +1674,36 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) netif_napi_del(&rtwpci->napi); } +enum rtw88_quirk_dis_pci_caps { + QUIRK_DIS_PCI_CAP_MSI, + QUIRK_DIS_PCI_CAP_ASPM, +}; + +static int disable_pci_caps(const struct dmi_system_id *dmi) +{ + uintptr_t dis_caps = (uintptr_t)dmi->driver_data; + + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_MSI)) + rtw_disable_msi = true; + if (dis_caps & BIT(QUIRK_DIS_PCI_CAP_ASPM)) + rtw_pci_disable_aspm = true; + + return 1; +} + +static const struct dmi_system_id rtw88_pci_quirks[] = { + { + .callback = disable_pci_caps, + .ident = "Protempo Ltd L116HTN6SPW", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Protempo Ltd"), + DMI_MATCH(DMI_PRODUCT_NAME, "L116HTN6SPW"), + }, + .driver_data = (void *)BIT(QUIRK_DIS_PCI_CAP_ASPM), + }, + {} +}; + int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1723,6 +1754,7 @@ int rtw_pci_probe(struct pci_dev *pdev, goto err_destroy_pci; } + dmi_check_system(rtw88_pci_quirks); rtw_pci_phy_cfg(rtwdev); ret = rtw_register_hw(rtwdev, hw); diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 8146acaf1893..569dd3cfde35 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -127,6 +127,17 @@ static void rtw_phy_cfo_init(struct rtw_dev *rtwdev) chip->ops->cfo_init(rtwdev); } +static void rtw_phy_tx_path_div_init(struct rtw_dev *rtwdev) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + + path_div->current_tx_path = rtwdev->chip->default_1ss_tx_path; + path_div->path_a_cnt = 0; + path_div->path_a_sum = 0; + path_div->path_b_cnt = 0; + path_div->path_b_sum = 0; +} + void rtw_phy_init(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -149,6 +160,7 @@ void rtw_phy_init(struct rtw_dev *rtwdev) dm_info->iqk.done = false; rtw_phy_cfo_init(rtwdev); + rtw_phy_tx_path_div_init(rtwdev); } EXPORT_SYMBOL(rtw_phy_init); @@ -695,6 +707,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) rtw_phy_dig(rtwdev); rtw_phy_cck_pd(rtwdev); rtw_phy_ra_track(rtwdev); + rtw_phy_tx_path_diversity(rtwdev); rtw_phy_cfo_track(rtwdev); rtw_phy_dpk_track(rtwdev); rtw_phy_pwr_track(rtwdev); @@ -2315,3 +2328,71 @@ bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) return false; } EXPORT_SYMBOL(rtw_phy_pwrtrack_need_iqk); + +static void rtw_phy_set_tx_path_by_reg(struct rtw_dev *rtwdev, + enum rtw_bb_path tx_path_sel_1ss) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + enum rtw_bb_path tx_path_sel_cck = tx_path_sel_1ss; + struct rtw_chip_info *chip = rtwdev->chip; + + if (tx_path_sel_1ss == path_div->current_tx_path) + return; + + path_div->current_tx_path = tx_path_sel_1ss; + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "Switch TX path=%s\n", + tx_path_sel_1ss == BB_PATH_A ? "A" : "B"); + chip->ops->config_tx_path(rtwdev, rtwdev->hal.antenna_tx, + tx_path_sel_1ss, tx_path_sel_cck, false); +} + +static void rtw_phy_tx_path_div_select(struct rtw_dev *rtwdev) +{ + struct rtw_path_div *path_div = &rtwdev->dm_path_div; + enum rtw_bb_path path = path_div->current_tx_path; + s32 rssi_a = 0, rssi_b = 0; + + if (path_div->path_a_cnt) + rssi_a = path_div->path_a_sum / path_div->path_a_cnt; + else + rssi_a = 0; + if (path_div->path_b_cnt) + rssi_b = path_div->path_b_sum / path_div->path_b_cnt; + else + rssi_b = 0; + + if (rssi_a != rssi_b) + path = (rssi_a > rssi_b) ? BB_PATH_A : BB_PATH_B; + + path_div->path_a_cnt = 0; + path_div->path_a_sum = 0; + path_div->path_b_cnt = 0; + path_div->path_b_sum = 0; + rtw_phy_set_tx_path_by_reg(rtwdev, path); +} + +static void rtw_phy_tx_path_diversity_2ss(struct rtw_dev *rtwdev) +{ + if (rtwdev->hal.antenna_rx != BB_PATH_AB) { + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, + "[Return] tx_Path_en=%d, rx_Path_en=%d\n", + rtwdev->hal.antenna_tx, rtwdev->hal.antenna_rx); + return; + } + if (rtwdev->sta_cnt == 0) { + rtw_dbg(rtwdev, RTW_DBG_PATH_DIV, "No Link\n"); + return; + } + + rtw_phy_tx_path_div_select(rtwdev); +} + +void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev) +{ + struct rtw_chip_info *chip = rtwdev->chip; + + if (!chip->path_div_supported) + return; + + rtw_phy_tx_path_diversity_2ss(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index 0b6f2fc8193c..112ed125970a 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -61,6 +61,7 @@ void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, struct rtw_swing_table *swing_table); void rtw_phy_parsing_cfo(struct rtw_dev *rtwdev, struct rtw_rx_pkt_stat *pkt_stat); +void rtw_phy_tx_path_diversity(struct rtw_dev *rtwdev); struct rtw_txpwr_lmt_cfg_pair { u8 regd; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 3bead34c3d10..3f0ac33156d6 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -152,7 +152,7 @@ static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev) else fw = &rtwdev->fw; - if (fw->feature & FW_FEATURE_LPS_C2H) + if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H)) ret = __rtw_fw_leave_lps_check_c2h(rtwdev); else ret = __rtw_fw_leave_lps_check_reg(rtwdev); @@ -172,7 +172,7 @@ static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev) else fw = &rtwdev->fw; - if (fw->feature & FW_FEATURE_LPS_C2H) + if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H)) reinit_completion(&rtwdev->lps_leave_check); } diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 6cb593cc33c2..8bf3cd3a3678 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -17,7 +17,6 @@ #include "util.h" #include "bf.h" #include "efuse.h" -#include "coex.h" #define IQK_DONE_8822C 0xaa @@ -80,6 +79,13 @@ static void rtw8822c_header_file_init(struct rtw_dev *rtwdev, bool pre) rtw_write32_set(rtwdev, REG_ENCCK, BIT_CCK_OFDM_BLK_EN); } +static void rtw8822c_bb_reset(struct rtw_dev *rtwdev) +{ + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); + rtw_write16_clr(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_BB_RSTB); +} + static void rtw8822c_dac_backup_reg(struct rtw_dev *rtwdev, struct rtw_backup_info *backup, struct rtw_backup_info *backup_rf) @@ -2103,13 +2109,51 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev) return 0; } -static void rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev) +#define FWCD_SIZE_REG_8822C 0x2000 +#define FWCD_SIZE_DMEM_8822C 0x10000 +#define FWCD_SIZE_IMEM_8822C 0x10000 +#define FWCD_SIZE_EMEM_8822C 0x20000 +#define FWCD_SIZE_ROM_8822C 0x10000 + +static const u32 __fwcd_segs_8822c[] = { + FWCD_SIZE_REG_8822C, + FWCD_SIZE_DMEM_8822C, + FWCD_SIZE_IMEM_8822C, + FWCD_SIZE_EMEM_8822C, + FWCD_SIZE_ROM_8822C, +}; + +static const struct rtw_fwcd_segs rtw8822c_fwcd_segs = { + .segs = __fwcd_segs_8822c, + .num = ARRAY_SIZE(__fwcd_segs_8822c), +}; + +static int rtw8822c_dump_fw_crash(struct rtw_dev *rtwdev) { - rtw_dump_reg(rtwdev, 0x0, 0x2000, "rtw8822c reg_"); - rtw_dump_fw(rtwdev, OCPBASE_DMEM_88XX, 0x10000, "rtw8822c DMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_IMEM_88XX, 0x10000, "rtw8822c IMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_EMEM_88XX, 0x20000, "rtw8822c EMEM_"); - rtw_dump_fw(rtwdev, OCPBASE_ROM_88XX, 0x10000, "rtw8822c ROM_"); +#define __dump_fw_8822c(_dev, _mem) \ + rtw_dump_fw(_dev, OCPBASE_ ## _mem ## _88XX, \ + FWCD_SIZE_ ## _mem ## _8822C, RTW_FWCD_ ## _mem) + int ret; + + ret = rtw_dump_reg(rtwdev, 0x0, FWCD_SIZE_REG_8822C); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, DMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, IMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, EMEM); + if (ret) + return ret; + ret = __dump_fw_8822c(rtwdev, ROM); + if (ret) + return ret; + + return 0; + +#undef __dump_fw_8822c } static void rtw8822c_rstb_3wire(struct rtw_dev *rtwdev, bool enable) @@ -2424,10 +2468,11 @@ static void rtw8822c_config_cck_tx_path(struct rtw_dev *rtwdev, u8 tx_path, else rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x8); } + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path, - bool is_tx2_path) + enum rtw_bb_path tx_path_sel_1ss) { if (tx_path == BB_PATH_A) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x11); @@ -2436,21 +2481,28 @@ static void rtw8822c_config_ofdm_tx_path(struct rtw_dev *rtwdev, u8 tx_path, rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x12); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xff, 0x0); } else { - if (is_tx2_path) { + if (tx_path_sel_1ss == BB_PATH_AB) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x33); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0404); - } else { + } else if (tx_path_sel_1ss == BB_PATH_B) { + rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x32); + rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400); + } else if (tx_path_sel_1ss == BB_PATH_A) { rtw_write32_mask(rtwdev, REG_ANTMAP0, 0xff, 0x31); rtw_write32_mask(rtwdev, REG_TXLGMAP, 0xffff, 0x0400); } } + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_tx_path(struct rtw_dev *rtwdev, u8 tx_path, + enum rtw_bb_path tx_path_sel_1ss, + enum rtw_bb_path tx_path_cck, bool is_tx2_path) { - rtw8822c_config_cck_tx_path(rtwdev, tx_path, is_tx2_path); - rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, is_tx2_path); + rtw8822c_config_cck_tx_path(rtwdev, tx_path_cck, is_tx2_path); + rtw8822c_config_ofdm_tx_path(rtwdev, tx_path, tx_path_sel_1ss); + rtw8822c_bb_reset(rtwdev); } static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, @@ -2466,7 +2518,8 @@ static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, rtw_write32_mask(rtwdev, REG_ORITXCODE2, MASK20BITS, 0x11111); rtw8822c_config_rx_path(rtwdev, rx_path); - rtw8822c_config_tx_path(rtwdev, tx_path, is_tx2_path); + rtw8822c_config_tx_path(rtwdev, tx_path, BB_PATH_A, BB_PATH_A, + is_tx2_path); rtw8822c_toggle_igi(rtwdev); } @@ -2517,6 +2570,7 @@ 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_path_div *p_div = &rtwdev->dm_path_div; struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; @@ -2559,6 +2613,13 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *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; + if (path == RF_PATH_A) { + p_div->path_a_sum += rssi; + p_div->path_a_cnt++; + } else if (path == RF_PATH_B) { + p_div->path_b_sum += rssi; + p_div->path_b_cnt++; + } dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; @@ -4371,26 +4432,28 @@ static void rtw8822c_pwrtrack_set(struct rtw_dev *rtwdev, u8 rf_path) } } -static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev, - struct rtw_swing_table *swing_table, - u8 path) +static void rtw8822c_pwr_track_stats(struct rtw_dev *rtwdev, u8 path) { - struct rtw_dm_info *dm_info = &rtwdev->dm_info; - u8 thermal_value, delta; + u8 thermal_value; 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); +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 delta; + 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); } @@ -4401,12 +4464,12 @@ static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev) rtw_phy_config_swing_table(rtwdev, &swing_table); + for (i = 0; i < rtwdev->hal.rf_path_num; i++) + rtw8822c_pwr_track_stats(rtwdev, i); if (rtw_phy_pwrtrack_need_lck(rtwdev)) rtw8822c_do_lck(rtwdev); - for (i = 0; i < rtwdev->hal.rf_path_num; i++) rtw8822c_pwr_track_path(rtwdev, &swing_table, i); - } static void rtw8822c_pwr_track(struct rtw_dev *rtwdev) @@ -4851,6 +4914,7 @@ static struct rtw_chip_ops rtw8822c_ops = { .cfg_csi_rate = rtw_bf_cfg_csi_rate, .cfo_init = rtw8822c_cfo_init, .cfo_track = rtw8822c_cfo_track, + .config_tx_path = rtw8822c_config_tx_path, .coex_set_init = rtw8822c_coex_cfg_init, .coex_set_ant_switch = NULL, @@ -5192,6 +5256,8 @@ struct rtw_chip_info rtw8822c_hw_spec = { .band = RTW_BAND_2G | RTW_BAND_5G, .page_size = 128, .dig_min = 0x20, + .default_1ss_tx_path = BB_PATH_A, + .path_div_supported = true, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG), @@ -5259,6 +5325,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .coex_info_hw_regs = coex_info_hw_regs_8822c, .fw_fifo_addr = {0x780, 0x700, 0x780, 0x660, 0x650, 0x680}, + .fwcd_segs = &rtw8822c_fwcd_segs, }; EXPORT_SYMBOL(rtw8822c_hw_spec); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c index 822f3da91f1b..f9e3d0779c59 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c @@ -16812,53 +16812,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x00010E46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00030246, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -18762,53 +18762,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -18957,53 +18957,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19152,53 +19152,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19347,53 +19347,53 @@ static const u32 rtw8822c_rf_a[] = { 0x92000002, 0x00000000, 0x40000000, 0x00000000, 0x03F, 0x0000EA46, 0x93000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x93000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x94000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000001, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000002, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000003, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000004, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000005, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000006, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000015, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0x95000016, 0x00000000, 0x40000000, 0x00000000, - 0x03F, 0x00031E46, + 0x03F, 0x0003D646, 0xA0000000, 0x00000000, 0x03F, 0x00002A46, 0xB0000000, 0x00000000, @@ -19610,21 +19610,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19633,21 +19633,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19656,21 +19656,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19679,21 +19679,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19702,21 +19702,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19725,21 +19725,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19748,21 +19748,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19771,21 +19771,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19794,21 +19794,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19817,21 +19817,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19840,21 +19840,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19863,21 +19863,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19886,21 +19886,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19909,21 +19909,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19932,21 +19932,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19955,21 +19955,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -19978,21 +19978,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20001,21 +20001,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20024,21 +20024,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20047,21 +20047,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20070,21 +20070,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20093,21 +20093,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20116,21 +20116,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -20139,21 +20139,21 @@ static const u32 rtw8822c_rf_a[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x000008C8, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x000008CB, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x000008CE, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x000008D1, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x000008D4, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000DD1, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0xA0000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000487, @@ -38484,21 +38484,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38507,21 +38507,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38530,21 +38530,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38553,21 +38553,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38576,21 +38576,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38599,21 +38599,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38622,21 +38622,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x93000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38645,21 +38645,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38668,21 +38668,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38691,21 +38691,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38714,21 +38714,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38737,21 +38737,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38760,21 +38760,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38783,21 +38783,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38806,21 +38806,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x94000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38829,21 +38829,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000001, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38852,21 +38852,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000002, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38875,21 +38875,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000003, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38898,21 +38898,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000004, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38921,21 +38921,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000005, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38944,21 +38944,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000006, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38967,21 +38967,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000015, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -38990,21 +38990,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0x95000016, 0x00000000, 0x40000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000467, @@ -39013,21 +39013,21 @@ static const u32 rtw8822c_rf_b[] = { 0x033, 0x00000062, 0x03F, 0x00000908, 0x033, 0x00000063, - 0x03F, 0x00000D09, + 0x03F, 0x00000CC6, 0x033, 0x00000064, - 0x03F, 0x00000D49, + 0x03F, 0x00000CC9, 0x033, 0x00000065, - 0x03F, 0x00000D8A, + 0x03F, 0x00000CCC, 0x033, 0x00000066, - 0x03F, 0x00000DEB, + 0x03F, 0x00000CCF, 0x033, 0x00000067, - 0x03F, 0x00000DEE, + 0x03F, 0x00000CD2, 0x033, 0x00000068, - 0x03F, 0x00000DF1, + 0x03F, 0x00000CD5, 0x033, 0x00000069, - 0x03F, 0x00000DF4, + 0x03F, 0x00000DD4, 0x033, 0x0000006A, - 0x03F, 0x00000DF7, + 0x03F, 0x00000DD7, 0xA0000000, 0x00000000, 0x033, 0x00000060, 0x03F, 0x00000487, diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9fe77556858e..63ce2443f136 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -1036,14 +1036,11 @@ static bool is_associated(struct usbnet *usbdev) { struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); u8 bssid[ETH_ALEN]; - int ret; if (!priv->radio_on) return false; - ret = get_bssid(usbdev, bssid); - - return (ret == 0 && !is_zero_ether_addr(bssid)); + return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid)); } static int disassociate(struct usbnet *usbdev, bool reset_ssid) diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index ce9892152f4d..99b21a2c8386 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -203,7 +203,7 @@ int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE); if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && - (common->secinfo.security_enable)) { + info->control.hw_key) { if (rsi_is_cipher_wep(common)) ieee80211_size += 4; else @@ -470,9 +470,9 @@ int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) } if (common->band == NL80211_BAND_2GHZ) - bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1); + bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_1); else - bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6); + bcn_frm->rate_info |= cpu_to_le16(RSI_RATE_6); if (mac_bcn->data[tim_offset + 2] == 0) bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON); diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 16025300cddb..b66975f54567 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -837,6 +837,23 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, common->cqm_info.rssi_hyst); } + if (changed & BSS_CHANGED_BEACON_INT) { + rsi_dbg(INFO_ZONE, "%s: Changed Beacon interval: %d\n", + __func__, bss_conf->beacon_int); + if (common->beacon_interval != bss->beacon_int) { + common->beacon_interval = bss->beacon_int; + if (vif->type == NL80211_IFTYPE_AP) { + struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; + + rsi_set_vap_capabilities(common, RSI_OPMODE_AP, + vif->addr, vif_info->vap_id, + VAP_UPDATE); + } + } + adapter->ps_info.listen_interval = + bss->beacon_int * adapter->ps_info.num_bcns_per_lis_int; + } + if ((changed & BSS_CHANGED_BEACON_ENABLED) && ((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_P2P_GO))) { @@ -1028,7 +1045,6 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, mutex_lock(&common->mutex); switch (cmd) { case SET_KEY: - secinfo->security_enable = true; status = rsi_hal_key_config(hw, vif, key, sta); if (status) { mutex_unlock(&common->mutex); @@ -1047,8 +1063,6 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, break; case DISABLE_KEY: - if (vif->type == NL80211_IFTYPE_STATION) - secinfo->security_enable = false; rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); memset(key, 0, sizeof(struct ieee80211_key_conf)); status = rsi_hal_key_config(hw, vif, key, sta); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 33c76d39a8e9..891fd5f0fa76 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1547,8 +1547,8 @@ static int rsi_eeprom_read(struct rsi_common *common) } /** - * This function sends a frame to block/unblock - * data queues in the firmware + * rsi_send_block_unblock_frame() - This function sends a frame to block/unblock + * data queues in the firmware * * @common: Pointer to the driver private structure. * @block_event: Event block if true, unblock if false @@ -1803,8 +1803,7 @@ int rsi_send_wowlan_request(struct rsi_common *common, u16 flags, RSI_WIFI_MGMT_Q); cmd_frame->desc.desc_dword0.frame_type = WOWLAN_CONFIG_PARAMS; cmd_frame->host_sleep_status = sleep_status; - if (common->secinfo.security_enable && - common->secinfo.gtk_cipher) + if (common->secinfo.gtk_cipher) flags |= RSI_WOW_GTK_REKEY; if (sleep_status) cmd_frame->wow_flags = flags; diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index a1065e5a92b4..0f535850a383 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -151,7 +151,6 @@ enum edca_queue { }; struct security_info { - bool security_enable; u32 ptk_cipher; u32 gtk_cipher; }; diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c index b65ec14136c7..4c30b5772ce0 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c +++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c @@ -53,6 +53,7 @@ static const struct sdio_device_id cw1200_sdio_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) }, { /* end: all zeroes */ }, }; +MODULE_DEVICE_TABLE(sdio, cw1200_sdio_ids); /* hwbus_ops implemetation */ diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index 988581cc134b..1f856fbbc0ea 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -75,30 +75,27 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) return -EINVAL; - /* will be unlocked in cw1200_scan_work() */ - down(&priv->scan.lock); - mutex_lock(&priv->conf_mutex); - frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, req->ie_len); - if (!frame.skb) { - mutex_unlock(&priv->conf_mutex); - up(&priv->scan.lock); + if (!frame.skb) return -ENOMEM; - } if (req->ie_len) skb_put_data(frame.skb, req->ie, req->ie_len); + /* will be unlocked in cw1200_scan_work() */ + down(&priv->scan.lock); + mutex_lock(&priv->conf_mutex); + ret = wsm_set_template_frame(priv, &frame); if (!ret) { /* Host want to be the probe responder. */ ret = wsm_set_probe_responder(priv, true); } if (ret) { - dev_kfree_skb(frame.skb); mutex_unlock(&priv->conf_mutex); up(&priv->scan.lock); + dev_kfree_skb(frame.skb); return ret; } @@ -120,8 +117,8 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, ++priv->scan.n_ssids; } - dev_kfree_skb(frame.skb); mutex_unlock(&priv->conf_mutex); + dev_kfree_skb(frame.skb); queue_work(priv->workqueue, &priv->scan.work); return 0; } diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index 498c8db2eb48..c3be81dc7970 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -12,7 +12,7 @@ #include "acx.h" /** - * send command to firmware + * wl1251_cmd_send - Send command to firmware * * @wl: wl struct * @id: command id @@ -59,7 +59,7 @@ out: } /** - * send test command to firmware + * wl1251_cmd_test - Send test command to firmware * * @wl: wl struct * @buf: buffer containing the command, with all headers, must work with dma @@ -100,7 +100,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) } /** - * read acx from firmware + * wl1251_cmd_interrogate - Read acx from firmware * * @wl: wl struct * @id: acx id @@ -138,7 +138,7 @@ out: } /** - * write acx value to firmware + * wl1251_cmd_configure - Write acx value to firmware * * @wl: wl struct * @id: acx id @@ -454,9 +454,12 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, cmd->channels[i].channel = channels[i]->hw_value; } - cmd->params.ssid_len = ssid_len; - if (ssid) - memcpy(cmd->params.ssid, ssid, ssid_len); + if (ssid) { + int len = clamp_val(ssid_len, 0, IEEE80211_MAX_SSID_LEN); + + cmd->params.ssid_len = len; + memcpy(cmd->params.ssid, ssid, len); + } ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); if (ret < 0) { diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 9d7dbfe7fe0c..c6da0cfb4afb 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1503,6 +1503,13 @@ static int wl12xx_get_fuse_mac(struct wl1271 *wl) u32 mac1, mac2; int ret; + /* Device may be in ELP from the bootloader or kexec */ + ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + if (ret < 0) + goto out; + + usleep_range(500000, 700000); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); if (ret < 0) goto out; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 32a2e27cc561..8b798b5fcaf5 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -821,7 +821,7 @@ out: /** - * send test command to firmware + * wl1271_cmd_test - send test command to firmware * * @wl: wl struct * @buf: buffer containing the command, with all headers, must work with dma @@ -850,7 +850,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) EXPORT_SYMBOL_GPL(wl1271_cmd_test); /** - * read acx from firmware + * wl1271_cmd_interrogate - read acx from firmware * * @wl: wl struct * @id: acx id @@ -879,7 +879,7 @@ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, } /** - * write acx value to firmware + * wlcore_cmd_configure_failsafe - write acx value to firmware * * @wl: wl struct * @id: acx id diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index a68bbadae043..46ab69eab26a 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -29,18 +29,20 @@ int wlcore_event_fw_logger(struct wl1271 *wl) u8 *buffer; u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS; u32 addr = WL18XX_LOGGER_SDIO_BUFF_ADDR; - u32 end_buff_addr = WL18XX_LOGGER_SDIO_BUFF_ADDR + - WL18XX_LOGGER_BUFF_OFFSET; + u32 addr_ptr; + u32 buff_start_ptr; + u32 buff_read_ptr; + u32 buff_end_ptr; u32 available_len; u32 actual_len; - u32 clear_addr; + u32 clear_ptr; size_t len; u32 start_loc; buffer = kzalloc(WL18XX_LOGGER_SDIO_BUFF_MAX, GFP_KERNEL); if (!buffer) { wl1271_error("Fail to allocate fw logger memory"); - fw_log.actual_buff_size = cpu_to_le32(0); + actual_len = 0; goto out; } @@ -49,51 +51,58 @@ int wlcore_event_fw_logger(struct wl1271 *wl) if (ret < 0) { wl1271_error("Fail to read logger buffer, error_id = %d", ret); - fw_log.actual_buff_size = cpu_to_le32(0); + actual_len = 0; goto free_out; } memcpy(&fw_log, buffer, sizeof(fw_log)); - if (le32_to_cpu(fw_log.actual_buff_size) == 0) + actual_len = le32_to_cpu(fw_log.actual_buff_size); + if (actual_len == 0) goto free_out; - actual_len = le32_to_cpu(fw_log.actual_buff_size); - start_loc = (le32_to_cpu(fw_log.buff_read_ptr) - - internal_fw_addrbase) - addr; - end_buff_addr += le32_to_cpu(fw_log.max_buff_size); - available_len = end_buff_addr - - (le32_to_cpu(fw_log.buff_read_ptr) - - internal_fw_addrbase); - actual_len = min(actual_len, available_len); - len = actual_len; + /* Calculate the internal pointer to the fwlog structure */ + addr_ptr = internal_fw_addrbase + addr; + + /* Calculate the internal pointers to the start and end of log buffer */ + buff_start_ptr = addr_ptr + WL18XX_LOGGER_BUFF_OFFSET; + buff_end_ptr = buff_start_ptr + le32_to_cpu(fw_log.max_buff_size); + /* Read the read pointer and validate it */ + buff_read_ptr = le32_to_cpu(fw_log.buff_read_ptr); + if (buff_read_ptr < buff_start_ptr || + buff_read_ptr >= buff_end_ptr) { + wl1271_error("buffer read pointer out of bounds: %x not in (%x-%x)\n", + buff_read_ptr, buff_start_ptr, buff_end_ptr); + goto free_out; + } + + start_loc = buff_read_ptr - addr_ptr; + available_len = buff_end_ptr - buff_read_ptr; + + /* Copy initial part up to the end of ring buffer */ + len = min(actual_len, available_len); wl12xx_copy_fwlog(wl, &buffer[start_loc], len); - clear_addr = addr + start_loc + le32_to_cpu(fw_log.actual_buff_size) + - internal_fw_addrbase; + clear_ptr = addr_ptr + start_loc + actual_len; + if (clear_ptr == buff_end_ptr) + clear_ptr = buff_start_ptr; - len = le32_to_cpu(fw_log.actual_buff_size) - len; + /* Copy any remaining part from beginning of ring buffer */ + len = actual_len - len; if (len) { wl12xx_copy_fwlog(wl, &buffer[WL18XX_LOGGER_BUFF_OFFSET], len); - clear_addr = addr + WL18XX_LOGGER_BUFF_OFFSET + len + - internal_fw_addrbase; - } - - /* double check that clear address and write pointer are the same */ - if (clear_addr != le32_to_cpu(fw_log.buff_write_ptr)) { - wl1271_error("Calculate of clear addr Clear = %x, write = %x", - clear_addr, le32_to_cpu(fw_log.buff_write_ptr)); + clear_ptr = addr_ptr + WL18XX_LOGGER_BUFF_OFFSET + len; } - /* indicate FW about Clear buffer */ + /* Update the read pointer */ ret = wlcore_write32(wl, addr + WL18XX_LOGGER_READ_POINT_OFFSET, - fw_log.buff_write_ptr); + clear_ptr); free_out: kfree(buffer); out: - return le32_to_cpu(fw_log.actual_buff_size); + return actual_len; } EXPORT_SYMBOL_GPL(wlcore_event_fw_logger); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 8509b989940c..5669f17b395f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3242,8 +3242,8 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, * the firmware filters so that all multicast packets are passed * This is mandatory for MDNS based discovery protocols */ - if (wlvif->bss_type == BSS_TYPE_AP_BSS) { - if (*total & FIF_ALLMULTI) { + if (wlvif->bss_type == BSS_TYPE_AP_BSS) { + if (*total & FIF_ALLMULTI) { ret = wl1271_acx_group_address_tbl(wl, wlvif, false, NULL, 0); @@ -6784,7 +6784,7 @@ int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) if (pdev_data->family && pdev_data->family->nvs_name) { nvs_name = pdev_data->family->nvs_name; - ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, nvs_name, &pdev->dev, GFP_KERNEL, wl, wlcore_nvs_cb); if (ret < 0) { diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 5cf0379b88b6..35b535c125b6 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -12,9 +12,9 @@ #include "debug.h" #include "sysfs.h" -static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t bt_coex_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; @@ -30,9 +30,9 @@ static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, } -static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t bt_coex_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct wl1271 *wl = dev_get_drvdata(dev); unsigned long res; @@ -71,13 +71,11 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, return count; } -static DEVICE_ATTR(bt_coex_state, 0644, - wl1271_sysfs_show_bt_coex_state, - wl1271_sysfs_store_bt_coex_state); +static DEVICE_ATTR_RW(bt_coex_state); -static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t hw_pg_ver_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct wl1271 *wl = dev_get_drvdata(dev); ssize_t len; @@ -94,7 +92,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, return len; } -static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL); +static DEVICE_ATTR_RO(hw_pg_ver); static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 5c4cd0e1adeb..a7ceef10bf6a 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -1544,14 +1544,14 @@ static int __init usb_init(void) zd_workqueue = create_singlethread_workqueue(driver.name); if (zd_workqueue == NULL) { - printk(KERN_ERR "%s couldn't create workqueue\n", driver.name); + pr_err("%s couldn't create workqueue\n", driver.name); return -ENOMEM; } r = usb_register(&driver); if (r) { destroy_workqueue(zd_workqueue); - printk(KERN_ERR "%s usb_register() failed. Error number %d\n", + pr_err("%s usb_register() failed. Error number %d\n", driver.name, r); return r; } |