Johannes Berg says: ==================== A fairly big set of changes all over, notably with: - cfg80211: new APIs for NAN (Neighbor Aware Networking, aka Wi-Fi Aware) so less work must be in firmware - mt76: - mt7996/mt7925 MLO fixes/improvements - mt7996 NPU support (HW eth/wifi traffic offload) - iwlwifi: UNII-9 and continuing UHR work * tag 'wireless-next-2026-03-26' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (230 commits) wifi: mac80211: ignore reserved bits in reconfiguration status wifi: cfg80211: allow protected action frame TX for NAN wifi: ieee80211: Add some missing NAN definitions wifi: nl80211: Add a notification to notify NAN channel evacuation wifi: nl80211: add NL80211_CMD_NAN_ULW_UPDATE notification wifi: nl80211: allow reporting spurious NAN Data frames wifi: cfg80211: allow ToDS=0/FromDS=0 data frames on NAN data interfaces wifi: nl80211: define an API for configuring the NAN peer's schedule wifi: nl80211: add support for NAN stations wifi: cfg80211: separately store HT, VHT and HE capabilities for NAN wifi: cfg80211: add support for NAN data interface wifi: cfg80211: make sure NAN chandefs are valid wifi: cfg80211: Add an API to configure local NAN schedule wifi: mac80211: cleanup error path of ieee80211_do_open wifi: mac80211: extract channel logic from link logic wifi: iwlwifi: mld: set RX_FLAG_RADIOTAP_TLV_AT_END generically wifi: iwlwifi: reduce the number of prints upon firmware crash wifi: iwlwifi: fix the description of SESSION_PROTECTION_CMD wifi: iwlwifi: mld: introduce iwl_mld_vif_fw_id_valid wifi: iwlwifi: mld: block EMLSR during TDLS connections ... ====================
Unified · Split
| @@ -1016,7 +1016,6 @@ static int ath10k_usb_probe(struct usb_interface *interface, · 1015 unmodified lines | |||
| 1016 | 1016 | ||
| 1017 | netif_napi_add(ar->napi_dev, &ar->napi, ath10k_usb_napi_poll); | 1017 | netif_napi_add(ar->napi_dev, &ar->napi, ath10k_usb_napi_poll); |
| 1018 | 1018 | ||
| 1019 | usb_get_dev(dev); | ||
| 1020 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); | 1019 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); |
| 1021 | product_id = le16_to_cpu(dev->descriptor.idProduct); | 1020 | product_id = le16_to_cpu(dev->descriptor.idProduct); |
| 1022 | 1021 | ||
| @@ -1055,12 +1054,10 @@ err_usb_destroy: · 32 unmodified lines | |||
| 1055 | err: | 1054 | err: |
| 1056 | ath10k_core_destroy(ar); | 1055 | ath10k_core_destroy(ar); |
| 1057 | 1056 | ||
| 1058 | usb_put_dev(dev); | ||
| 1059 | |||
| 1060 | return ret; | 1057 | return ret; |
| 1061 | } | 1058 | } |
| 1062 | 1059 | ||
| 1063 | static void ath10k_usb_remove(struct usb_interface *interface) | 1060 | static void ath10k_usb_disconnect(struct usb_interface *interface) |
| 1064 | { | 1061 | { |
| 1065 | struct ath10k_usb *ar_usb; | 1062 | struct ath10k_usb *ar_usb; |
| 1066 | 1063 | ||
| @@ -1071,7 +1068,6 @@ static void ath10k_usb_remove(struct usb_interface *interface) · 4 unmodified lines | |||
| 1071 | ath10k_core_unregister(ar_usb->ar); | 1068 | ath10k_core_unregister(ar_usb->ar); |
| 1072 | netif_napi_del(&ar_usb->ar->napi); | 1069 | netif_napi_del(&ar_usb->ar->napi); |
| 1073 | ath10k_usb_destroy(ar_usb->ar); | 1070 | ath10k_usb_destroy(ar_usb->ar); |
| 1074 | usb_put_dev(interface_to_usbdev(interface)); | ||
| 1075 | ath10k_core_destroy(ar_usb->ar); | 1071 | ath10k_core_destroy(ar_usb->ar); |
| 1076 | } | 1072 | } |
| 1077 | 1073 | ||
| @@ -1117,7 +1113,7 @@ static struct usb_driver ath10k_usb_driver = { · 39 unmodified lines | |||
| 1117 | .probe = ath10k_usb_probe, | 1113 | .probe = ath10k_usb_probe, |
| 1118 | .suspend = ath10k_usb_pm_suspend, | 1114 | .suspend = ath10k_usb_pm_suspend, |
| 1119 | .resume = ath10k_usb_pm_resume, | 1115 | .resume = ath10k_usb_pm_resume, |
| 1120 | .disconnect = ath10k_usb_remove, | 1116 | .disconnect = ath10k_usb_disconnect, |
| 1121 | .id_table = ath10k_usb_ids, | 1117 | .id_table = ath10k_usb_ids, |
| 1122 | .supports_autosuspend = true, | 1118 | .supports_autosuspend = true, |
| 1123 | .disable_hub_initiated_lpm = 1, | 1119 | .disable_hub_initiated_lpm = 1, |
| @@ -21,8 +21,8 @@ · 20 unmodified lines | |||
| 21 | #define ATH12K_ROOTPD_READY_TIMEOUT (5 * HZ) | 21 | #define ATH12K_ROOTPD_READY_TIMEOUT (5 * HZ) |
| 22 | #define ATH12K_RPROC_AFTER_POWERUP QCOM_SSR_AFTER_POWERUP | 22 | #define ATH12K_RPROC_AFTER_POWERUP QCOM_SSR_AFTER_POWERUP |
| 23 | #define ATH12K_AHB_FW_PREFIX "q6_fw" | 23 | #define ATH12K_AHB_FW_PREFIX "q6_fw" |
| 24 | #define ATH12K_AHB_FW_SUFFIX ".mdt" | 24 | #define ATH12K_AHB_FW_SUFFIX ".mbn" |
| 25 | #define ATH12K_AHB_FW2 "iu_fw.mdt" | 25 | #define ATH12K_AHB_FW2 "iu_fw.mbn" |
| 26 | #define ATH12K_AHB_UPD_SWID 0x12 | 26 | #define ATH12K_AHB_UPD_SWID 0x12 |
| 27 | #define ATH12K_USERPD_SPAWN_TIMEOUT (5 * HZ) | 27 | #define ATH12K_USERPD_SPAWN_TIMEOUT (5 * HZ) |
| 28 | #define ATH12K_USERPD_READY_TIMEOUT (10 * HZ) | 28 | #define ATH12K_USERPD_READY_TIMEOUT (10 * HZ) |
| @@ -523,7 +523,7 @@ struct ath12k_sta { · 522 unmodified lines | |||
| 523 | u16 links_map; | 523 | u16 links_map; |
| 524 | u8 assoc_link_id; | 524 | u8 assoc_link_id; |
| 525 | u16 ml_peer_id; | 525 | u16 ml_peer_id; |
| 526 | u8 num_peer; | 526 | u16 free_logical_link_idx_map; |
| 527 | 527 | ||
| 528 | enum ieee80211_sta_state state; | 528 | enum ieee80211_sta_state state; |
| 529 | }; | 529 | }; |
| @@ -205,16 +205,9 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev, · 204 unmodified lines | |||
| 205 | if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) | 205 | if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) |
| 206 | return; | 206 | return; |
| 207 | 207 | ||
| 208 | if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { | 208 | if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) |
| 209 | is_ampdu = | 209 | is_ampdu = |
| 210 | HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); | 210 | HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); |
| 211 | tx_retry_failed = | ||
| 212 | __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - | ||
| 213 | __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); | ||
| 214 | tx_retry_count = | ||
| 215 | HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + | ||
| 216 | HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); | ||
| 217 | } | ||
| 218 | 211 | ||
| 219 | if (usr_stats->tlv_flags & | 212 | if (usr_stats->tlv_flags & |
| 220 | BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { | 213 | BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { |
| @@ -223,10 +216,19 @@ ath12k_update_per_peer_tx_stats(struct ath12k_pdev_dp *dp_pdev, · 2 unmodified lines | |||
| 223 | HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M); | 216 | HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M); |
| 224 | tid = le32_get_bits(usr_stats->ack_ba.info, | 217 | tid = le32_get_bits(usr_stats->ack_ba.info, |
| 225 | HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM); | 218 | HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM); |
| 226 | } | ||
| 227 | 219 | ||
| 228 | if (common->fes_duration_us) | 220 | if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { |
| 229 | tx_duration = le32_to_cpu(common->fes_duration_us); | 221 | tx_retry_failed = |
| 222 | __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - | ||
| 223 | __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); | ||
| 224 | tx_retry_count = | ||
| 225 | HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + | ||
| 226 | HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); | ||
| 227 | } | ||
| 228 | |||
| 229 | if (common->fes_duration_us) | ||
| 230 | tx_duration = le32_to_cpu(common->fes_duration_us); | ||
| 231 | } | ||
| 230 | 232 | ||
| 231 | user_rate = &usr_stats->rate; | 233 | user_rate = &usr_stats->rate; |
| 232 | flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); | 234 | flags = HTT_USR_RATE_PREAMBLE(user_rate->rate_flags); |
| @@ -268,21 +268,28 @@ enum hal_rx_reception_type { · 267 unmodified lines | |||
| 268 | }; | 268 | }; |
| 269 | 269 | ||
| 270 | enum hal_rx_legacy_rate { | 270 | enum hal_rx_legacy_rate { |
| 271 | HAL_RX_LEGACY_RATE_1_MBPS, | 271 | HAL_RX_LEGACY_RATE_LP_1_MBPS, |
| 272 | HAL_RX_LEGACY_RATE_2_MBPS, | 272 | HAL_RX_LEGACY_RATE_LP_2_MBPS, |
| 273 | HAL_RX_LEGACY_RATE_5_5_MBPS, | 273 | HAL_RX_LEGACY_RATE_LP_5_5_MBPS, |
| 274 | HAL_RX_LEGACY_RATE_6_MBPS, | 274 | HAL_RX_LEGACY_RATE_LP_11_MBPS, |
| 275 | HAL_RX_LEGACY_RATE_9_MBPS, | 275 | HAL_RX_LEGACY_RATE_SP_2_MBPS, |
| 276 | HAL_RX_LEGACY_RATE_11_MBPS, | 276 | HAL_RX_LEGACY_RATE_SP_5_5_MBPS, |
| 277 | HAL_RX_LEGACY_RATE_12_MBPS, | 277 | HAL_RX_LEGACY_RATE_SP_11_MBPS, |
| 278 | HAL_RX_LEGACY_RATE_18_MBPS, | ||
| 279 | HAL_RX_LEGACY_RATE_24_MBPS, | ||
| 280 | HAL_RX_LEGACY_RATE_36_MBPS, | ||
| 281 | HAL_RX_LEGACY_RATE_48_MBPS, | ||
| 282 | HAL_RX_LEGACY_RATE_54_MBPS, | ||
| 283 | HAL_RX_LEGACY_RATE_INVALID, | 278 | HAL_RX_LEGACY_RATE_INVALID, |
| 284 | }; | 279 | }; |
| 285 | 280 | ||
| 281 | enum hal_rx_legacy_rates_ofdm { | ||
| 282 | HAL_RX_LEGACY_RATE_OFDM_48_MBPS, | ||
| 283 | HAL_RX_LEGACY_RATE_OFDM_24_MBPS, | ||
| 284 | HAL_RX_LEGACY_RATE_OFDM_12_MBPS, | ||
| 285 | HAL_RX_LEGACY_RATE_OFDM_6_MBPS, | ||
| 286 | HAL_RX_LEGACY_RATE_OFDM_54_MBPS, | ||
| 287 | HAL_RX_LEGACY_RATE_OFDM_36_MBPS, | ||
| 288 | HAL_RX_LEGACY_RATE_OFDM_18_MBPS, | ||
| 289 | HAL_RX_LEGACY_RATE_OFDM_9_MBPS, | ||
| 290 | HAL_RX_LEGACY_RATE_OFDM_INVALID, | ||
| 291 | }; | ||
| 292 | |||
| 286 | enum hal_ring_type { | 293 | enum hal_ring_type { |
| 287 | HAL_REO_DST, | 294 | HAL_REO_DST, |
| 288 | HAL_REO_EXCEPTION, | 295 | HAL_REO_EXCEPTION, |
| @@ -164,30 +164,31 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = { · 163 unmodified lines | |||
| 164 | CHAN6G(233, 7115, 0), | 164 | CHAN6G(233, 7115, 0), |
| 165 | }; | 165 | }; |
| 166 | 166 | ||
| 167 | #define ATH12K_MAC_RATE_A_M(bps, code) \ | ||
| 168 | { .bitrate = (bps), .hw_value = (code),\ | ||
| 169 | .flags = IEEE80211_RATE_MANDATORY_A } | ||
| 170 | |||
| 171 | #define ATH12K_MAC_RATE_B(bps, code, code_short) \ | ||
| 172 | { .bitrate = (bps), .hw_value = (code), .hw_value_short = (code_short),\ | ||
| 173 | .flags = IEEE80211_RATE_SHORT_PREAMBLE } | ||
| 174 | |||
| 167 | static struct ieee80211_rate ath12k_legacy_rates[] = { | 175 | static struct ieee80211_rate ath12k_legacy_rates[] = { |
| 168 | { .bitrate = 10, | 176 | { .bitrate = 10, |
| 169 | .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, | 177 | .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, |
| 170 | { .bitrate = 20, | 178 | ATH12K_MAC_RATE_B(20, ATH12K_HW_RATE_CCK_LP_2M, |
| 171 | .hw_value = ATH12K_HW_RATE_CCK_LP_2M, | 179 | ATH12K_HW_RATE_CCK_SP_2M), |
| 172 | .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M, | 180 | ATH12K_MAC_RATE_B(55, ATH12K_HW_RATE_CCK_LP_5_5M, |
| 173 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 181 | ATH12K_HW_RATE_CCK_SP_5_5M), |
| 174 | { .bitrate = 55, | 182 | ATH12K_MAC_RATE_B(110, ATH12K_HW_RATE_CCK_LP_11M, |
| 175 | .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M, | 183 | ATH12K_HW_RATE_CCK_SP_11M), |
| 176 | .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M, | 184 | ATH12K_MAC_RATE_A_M(60, ATH12K_HW_RATE_OFDM_6M), |
| 177 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 185 | ATH12K_MAC_RATE_A_M(90, ATH12K_HW_RATE_OFDM_9M), |
| 178 | { .bitrate = 110, | 186 | ATH12K_MAC_RATE_A_M(120, ATH12K_HW_RATE_OFDM_12M), |
| 179 | .hw_value = ATH12K_HW_RATE_CCK_LP_11M, | 187 | ATH12K_MAC_RATE_A_M(180, ATH12K_HW_RATE_OFDM_18M), |
| 180 | .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M, | 188 | ATH12K_MAC_RATE_A_M(240, ATH12K_HW_RATE_OFDM_24M), |
| 181 | .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | 189 | ATH12K_MAC_RATE_A_M(360, ATH12K_HW_RATE_OFDM_36M), |
| 182 | 190 | ATH12K_MAC_RATE_A_M(480, ATH12K_HW_RATE_OFDM_48M), | |
| 183 | { .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M }, | 191 | ATH12K_MAC_RATE_A_M(540, ATH12K_HW_RATE_OFDM_54M), |
| 184 | { .bitrate = 90, .hw_value = ATH12K_HW_RATE_OFDM_9M }, | ||
| 185 | { .bitrate = 120, .hw_value = ATH12K_HW_RATE_OFDM_12M }, | ||
| 186 | { .bitrate = 180, .hw_value = ATH12K_HW_RATE_OFDM_18M }, | ||
| 187 | { .bitrate = 240, .hw_value = ATH12K_HW_RATE_OFDM_24M }, | ||
| 188 | { .bitrate = 360, .hw_value = ATH12K_HW_RATE_OFDM_36M }, | ||
| 189 | { .bitrate = 480, .hw_value = ATH12K_HW_RATE_OFDM_48M }, | ||
| 190 | { .bitrate = 540, .hw_value = ATH12K_HW_RATE_OFDM_54M }, | ||
| 191 | }; | 192 | }; |
| 192 | 193 | ||
| 193 | static const int | 194 | static const int |
| @@ -732,11 +733,17 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, · 538 unmodified lines | |||
| 732 | if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck) | 733 | if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck) |
| 733 | continue; | 734 | continue; |
| 734 | 735 | ||
| 735 | if (rate->hw_value == hw_rate) | 736 | /* To handle 802.11a PPDU type */ |
| 737 | if ((!cck) && (rate->hw_value == hw_rate) && | ||
| 738 | (rate->flags & IEEE80211_RATE_MANDATORY_A)) | ||
| 736 | return i; | 739 | return i; |
| 740 | /* To handle 802.11b short PPDU type */ | ||
| 737 | else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && | 741 | else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && |
| 738 | rate->hw_value_short == hw_rate) | 742 | rate->hw_value_short == hw_rate) |
| 739 | return i; | 743 | return i; |
| 744 | /* To handle 802.11b long PPDU type */ | ||
| 745 | else if (rate->hw_value == hw_rate) | ||
| 746 | return i; | ||
| 740 | } | 747 | } |
| 741 | 748 | ||
| 742 | return 0; | 749 | return 0; |
| @@ -6786,6 +6793,8 @@ static void ath12k_mac_free_unassign_link_sta(struct ath12k_hw *ah, · 6043 unmodified lines | |||
| 6786 | return; | 6793 | return; |
| 6787 | 6794 | ||
| 6788 | ahsta->links_map &= ~BIT(link_id); | 6795 | ahsta->links_map &= ~BIT(link_id); |
| 6796 | ahsta->free_logical_link_idx_map |= BIT(arsta->link_idx); | ||
| 6797 | |||
| 6789 | rcu_assign_pointer(ahsta->link[link_id], NULL); | 6798 | rcu_assign_pointer(ahsta->link[link_id], NULL); |
| 6790 | synchronize_rcu(); | 6799 | synchronize_rcu(); |
| 6791 | 6800 | ||
| @@ -7104,6 +7113,7 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, · 312 unmodified lines | |||
| 7104 | struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta); | 7113 | struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta); |
| 7105 | struct ieee80211_link_sta *link_sta; | 7114 | struct ieee80211_link_sta *link_sta; |
| 7106 | struct ath12k_link_vif *arvif; | 7115 | struct ath12k_link_vif *arvif; |
| 7116 | int link_idx; | ||
| 7107 | 7117 | ||
| 7108 | lockdep_assert_wiphy(ah->hw->wiphy); | 7118 | lockdep_assert_wiphy(ah->hw->wiphy); |
| 7109 | 7119 | ||
| @@ -7122,8 +7132,16 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, · 12 unmodified lines | |||
| 7122 | 7132 | ||
| 7123 | ether_addr_copy(arsta->addr, link_sta->addr); | 7133 | ether_addr_copy(arsta->addr, link_sta->addr); |
| 7124 | 7134 | ||
| 7125 | /* logical index of the link sta in order of creation */ | 7135 | if (!ahsta->free_logical_link_idx_map) |
| 7126 | arsta->link_idx = ahsta->num_peer++; | 7136 | return -ENOSPC; |
| 7137 | |||
| 7138 | /* | ||
| 7139 | * Allocate a logical link index by selecting the first available bit | ||
| 7140 | * from the free logical index map | ||
| 7141 | */ | ||
| 7142 | link_idx = __ffs(ahsta->free_logical_link_idx_map); | ||
| 7143 | ahsta->free_logical_link_idx_map &= ~BIT(link_idx); | ||
| 7144 | arsta->link_idx = link_idx; | ||
| 7127 | 7145 | ||
| 7128 | arsta->link_id = link_id; | 7146 | arsta->link_id = link_id; |
| 7129 | ahsta->links_map |= BIT(arsta->link_id); | 7147 | ahsta->links_map |= BIT(arsta->link_id); |
| @@ -7632,6 +7650,7 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, · 502 unmodified lines | |||
| 7632 | if (old_state == IEEE80211_STA_NOTEXIST && | 7650 | if (old_state == IEEE80211_STA_NOTEXIST && |
| 7633 | new_state == IEEE80211_STA_NONE) { | 7651 | new_state == IEEE80211_STA_NONE) { |
| 7634 | memset(ahsta, 0, sizeof(*ahsta)); | 7652 | memset(ahsta, 0, sizeof(*ahsta)); |
| 7653 | ahsta->free_logical_link_idx_map = U16_MAX; | ||
| 7635 | 7654 | ||
| 7636 | arsta = &ahsta->deflink; | 7655 | arsta = &ahsta->deflink; |
| 7637 | 7656 | ||
| @@ -405,6 +405,42 @@ ath12k_wifi7_dp_mon_hal_rx_parse_user_info(const struct hal_receive_user_info *r · 404 unmodified lines | |||
| 405 | } | 405 | } |
| 406 | } | 406 | } |
| 407 | 407 | ||
| 408 | static __always_inline u8 | ||
| 409 | ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(u8 rate) | ||
| 410 | { | ||
| 411 | u8 ath12k_rate; | ||
| 412 | |||
| 413 | /* Map hal_rx_legacy_rate to ath12k_hw_rate_cck */ | ||
| 414 | switch (rate) { | ||
| 415 | case HAL_RX_LEGACY_RATE_LP_1_MBPS: | ||
| 416 | ath12k_rate = ATH12K_HW_RATE_CCK_LP_1M; | ||
| 417 | break; | ||
| 418 | case HAL_RX_LEGACY_RATE_LP_2_MBPS: | ||
| 419 | ath12k_rate = ATH12K_HW_RATE_CCK_LP_2M; | ||
| 420 | break; | ||
| 421 | case HAL_RX_LEGACY_RATE_LP_5_5_MBPS: | ||
| 422 | ath12k_rate = ATH12K_HW_RATE_CCK_LP_5_5M; | ||
| 423 | break; | ||
| 424 | case HAL_RX_LEGACY_RATE_LP_11_MBPS: | ||
| 425 | ath12k_rate = ATH12K_HW_RATE_CCK_LP_11M; | ||
| 426 | break; | ||
| 427 | case HAL_RX_LEGACY_RATE_SP_2_MBPS: | ||
| 428 | ath12k_rate = ATH12K_HW_RATE_CCK_SP_2M; | ||
| 429 | break; | ||
| 430 | case HAL_RX_LEGACY_RATE_SP_5_5_MBPS: | ||
| 431 | ath12k_rate = ATH12K_HW_RATE_CCK_SP_5_5M; | ||
| 432 | break; | ||
| 433 | case HAL_RX_LEGACY_RATE_SP_11_MBPS: | ||
| 434 | ath12k_rate = ATH12K_HW_RATE_CCK_SP_11M; | ||
| 435 | break; | ||
| 436 | default: | ||
| 437 | ath12k_rate = rate; | ||
| 438 | break; | ||
| 439 | } | ||
| 440 | |||
| 441 | return ath12k_rate; | ||
| 442 | } | ||
| 443 | |||
| 408 | static void | 444 | static void |
| 409 | ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, | 445 | ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, |
| 410 | struct hal_rx_mon_ppdu_info *ppdu_info) | 446 | struct hal_rx_mon_ppdu_info *ppdu_info) |
| @@ -415,25 +451,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, · 4 unmodified lines | |||
| 415 | rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE); | 451 | rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE); |
| 416 | switch (rate) { | 452 | switch (rate) { |
| 417 | case 1: | 453 | case 1: |
| 418 | rate = HAL_RX_LEGACY_RATE_1_MBPS; | 454 | rate = HAL_RX_LEGACY_RATE_LP_1_MBPS; |
| 419 | break; | 455 | break; |
| 420 | case 2: | 456 | case 2: |
| 421 | case 5: | 457 | rate = HAL_RX_LEGACY_RATE_LP_2_MBPS; |
| 422 | rate = HAL_RX_LEGACY_RATE_2_MBPS; | ||
| 423 | break; | 458 | break; |
| 424 | case 3: | 459 | case 3: |
| 425 | case 6: | 460 | rate = HAL_RX_LEGACY_RATE_LP_5_5_MBPS; |
| 426 | rate = HAL_RX_LEGACY_RATE_5_5_MBPS; | ||
| 427 | break; | 461 | break; |
| 428 | case 4: | 462 | case 4: |
| 463 | rate = HAL_RX_LEGACY_RATE_LP_11_MBPS; | ||
| 464 | break; | ||
| 465 | case 5: | ||
| 466 | rate = HAL_RX_LEGACY_RATE_SP_2_MBPS; | ||
| 467 | break; | ||
| 468 | case 6: | ||
| 469 | rate = HAL_RX_LEGACY_RATE_SP_5_5_MBPS; | ||
| 470 | break; | ||
| 429 | case 7: | 471 | case 7: |
| 430 | rate = HAL_RX_LEGACY_RATE_11_MBPS; | 472 | rate = HAL_RX_LEGACY_RATE_SP_11_MBPS; |
| 431 | break; | 473 | break; |
| 432 | default: | 474 | default: |
| 433 | rate = HAL_RX_LEGACY_RATE_INVALID; | 475 | rate = HAL_RX_LEGACY_RATE_INVALID; |
| 476 | break; | ||
| 434 | } | 477 | } |
| 435 | 478 | ||
| 436 | ppdu_info->rate = rate; | 479 | ppdu_info->rate = ath12k_wifi7_hal_mon_map_legacy_rate_to_hw_rate(rate); |
| 437 | ppdu_info->cck_flag = 1; | 480 | ppdu_info->cck_flag = 1; |
| 438 | } | 481 | } |
| 439 | 482 | ||
| @@ -447,31 +490,32 @@ ath12k_wifi7_dp_mon_parse_l_sig_a(const struct hal_rx_lsig_a_info *lsiga, · 7 unmodified lines | |||
| 447 | rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE); | 490 | rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE); |
| 448 | switch (rate) { | 491 | switch (rate) { |
| 449 | case 8: | 492 | case 8: |
| 450 | rate = HAL_RX_LEGACY_RATE_48_MBPS; | 493 | rate = HAL_RX_LEGACY_RATE_OFDM_48_MBPS; |
| 451 | break; | 494 | break; |
| 452 | case 9: | 495 | case 9: |
| 453 | rate = HAL_RX_LEGACY_RATE_24_MBPS; | 496 | rate = HAL_RX_LEGACY_RATE_OFDM_24_MBPS; |
| 454 | break; | 497 | break; |
| 455 | case 10: | 498 | case 10: |
| 456 | rate = HAL_RX_LEGACY_RATE_12_MBPS; | 499 | rate = HAL_RX_LEGACY_RATE_OFDM_12_MBPS; |
| 457 | break; | 500 | break; |
| 458 | case 11: | 501 | case 11: |
| 459 | rate = HAL_RX_LEGACY_RATE_6_MBPS; | 502 | rate = HAL_RX_LEGACY_RATE_OFDM_6_MBPS; |
| 460 | break; | 503 | break; |
| 461 | case 12: | 504 | case 12: |
| 462 | rate = HAL_RX_LEGACY_RATE_54_MBPS; | 505 | rate = HAL_RX_LEGACY_RATE_OFDM_54_MBPS; |
| 463 | break; | 506 | break; |
| 464 | case 13: | 507 | case 13: |
| 465 | rate = HAL_RX_LEGACY_RATE_36_MBPS; | 508 | rate = HAL_RX_LEGACY_RATE_OFDM_36_MBPS; |
| 466 | break; | 509 | break; |
| 467 | case 14: | 510 | case 14: |
| 468 | rate = HAL_RX_LEGACY_RATE_18_MBPS; | 511 | rate = HAL_RX_LEGACY_RATE_OFDM_18_MBPS; |
| 469 | break; | 512 | break; |
| 470 | case 15: | 513 | case 15: |
| 471 | rate = HAL_RX_LEGACY_RATE_9_MBPS; | 514 | rate = HAL_RX_LEGACY_RATE_OFDM_9_MBPS; |
| 472 | break; | 515 | break; |
| 473 | default: | 516 | default: |
| 474 | rate = HAL_RX_LEGACY_RATE_INVALID; | 517 | rate = HAL_RX_LEGACY_RATE_OFDM_INVALID; |
| 518 | break; | ||
| 475 | } | 519 | } |
| 476 | 520 | ||
| 477 | ppdu_info->rate = rate; | 521 | ppdu_info->rate = rate; |
| @@ -10017,50 +10017,46 @@ static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab, · 10016 unmodified lines | |||
| 10017 | 10017 | ||
| 10018 | static int | 10018 | static int |
| 10019 | ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, | 10019 | ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, |
| 10020 | struct wmi_unit_test_cmd ut_cmd, | 10020 | const struct wmi_unit_test_arg *ut) |
| 10021 | u32 *test_args) | ||
| 10022 | { | 10021 | { |
| 10023 | struct ath12k_wmi_pdev *wmi = ar->wmi; | 10022 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
| 10024 | struct wmi_unit_test_cmd *cmd; | 10023 | struct wmi_unit_test_cmd *cmd; |
| 10024 | int buf_len, arg_len; | ||
| 10025 | struct sk_buff *skb; | 10025 | struct sk_buff *skb; |
| 10026 | struct wmi_tlv *tlv; | 10026 | struct wmi_tlv *tlv; |
| 10027 | __le32 *ut_cmd_args; | ||
| 10027 | void *ptr; | 10028 | void *ptr; |
| 10028 | u32 *ut_cmd_args; | ||
| 10029 | int buf_len, arg_len; | ||
| 10030 | int ret; | 10029 | int ret; |
| 10031 | int i; | 10030 | int i; |
| 10032 | 10031 | ||
| 10033 | arg_len = sizeof(u32) * le32_to_cpu(ut_cmd.num_args); | 10032 | arg_len = sizeof(*ut_cmd_args) * ut->num_args; |
| 10034 | buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE; | 10033 | buf_len = sizeof(*cmd) + arg_len + TLV_HDR_SIZE; |
| 10035 | 10034 | ||
| 10036 | skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len); | 10035 | skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len); |
| 10037 | if (!skb) | 10036 | if (!skb) |
| 10038 | return -ENOMEM; | 10037 | return -ENOMEM; |
| 10039 | 10038 | ||
| 10040 | cmd = (struct wmi_unit_test_cmd *)skb->data; | 10039 | ptr = skb->data; |
| 10040 | cmd = ptr; | ||
| 10041 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_UNIT_TEST_CMD, | 10041 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_UNIT_TEST_CMD, |
| 10042 | sizeof(ut_cmd)); | 10042 | sizeof(*cmd)); |
| 10043 | 10043 | cmd->vdev_id = cpu_to_le32(ut->vdev_id); | |
| 10044 | cmd->vdev_id = ut_cmd.vdev_id; | 10044 | cmd->module_id = cpu_to_le32(ut->module_id); |
| 10045 | cmd->module_id = ut_cmd.module_id; | 10045 | cmd->num_args = cpu_to_le32(ut->num_args); |
| 10046 | cmd->num_args = ut_cmd.num_args; | 10046 | cmd->diag_token = cpu_to_le32(ut->diag_token); |
| 10047 | cmd->diag_token = ut_cmd.diag_token; | ||
| 10048 | |||
| 10049 | ptr = skb->data + sizeof(ut_cmd); | ||
| 10050 | 10047 | ||
| 10048 | ptr += sizeof(*cmd); | ||
| 10051 | tlv = ptr; | 10049 | tlv = ptr; |
| 10052 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, arg_len); | 10050 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, arg_len); |
| 10053 | 10051 | ||
| 10054 | ptr += TLV_HDR_SIZE; | 10052 | ptr += TLV_HDR_SIZE; |
| 10055 | |||
| 10056 | ut_cmd_args = ptr; | 10053 | ut_cmd_args = ptr; |
| 10057 | for (i = 0; i < le32_to_cpu(ut_cmd.num_args); i++) | 10054 | for (i = 0; i < ut->num_args; i++) |
| 10058 | ut_cmd_args[i] = test_args[i]; | 10055 | ut_cmd_args[i] = cpu_to_le32(ut->args[i]); |
| 10059 | 10056 | ||
| 10060 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, | 10057 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
| 10061 | "WMI unit test : module %d vdev %d n_args %d token %d\n", | 10058 | "WMI unit test : module %d vdev %d n_args %d token %d\n", |
| 10062 | cmd->module_id, cmd->vdev_id, cmd->num_args, | 10059 | ut->module_id, ut->vdev_id, ut->num_args, ut->diag_token); |
| 10063 | cmd->diag_token); | ||
| 10064 | 10060 | ||
| 10065 | ret = ath12k_wmi_cmd_send(wmi, skb, WMI_UNIT_TEST_CMDID); | 10061 | ret = ath12k_wmi_cmd_send(wmi, skb, WMI_UNIT_TEST_CMDID); |
| 10066 | 10062 | ||
| @@ -10076,8 +10072,7 @@ ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, · 9 unmodified lines | |||
| 10076 | int ath12k_wmi_simulate_radar(struct ath12k *ar) | 10072 | int ath12k_wmi_simulate_radar(struct ath12k *ar) |
| 10077 | { | 10073 | { |
| 10078 | struct ath12k_link_vif *arvif; | 10074 | struct ath12k_link_vif *arvif; |
| 10079 | u32 dfs_args[DFS_MAX_TEST_ARGS]; | 10075 | struct wmi_unit_test_arg wmi_ut = {}; |
| 10080 | struct wmi_unit_test_cmd wmi_ut; | ||
| 10081 | bool arvif_found = false; | 10076 | bool arvif_found = false; |
| 10082 | 10077 | ||
| 10083 | list_for_each_entry(arvif, &ar->arvifs, list) { | 10078 | list_for_each_entry(arvif, &ar->arvifs, list) { |
| @@ -10090,22 +10085,23 @@ int ath12k_wmi_simulate_radar(struct ath12k *ar) · 6 unmodified lines | |||
| 10090 | if (!arvif_found) | 10085 | if (!arvif_found) |
| 10091 | return -EINVAL; | 10086 | return -EINVAL; |
| 10092 | 10087 | ||
| 10093 | dfs_args[DFS_TEST_CMDID] = 0; | 10088 | wmi_ut.args[DFS_TEST_CMDID] = 0; |
| 10094 | dfs_args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id; | 10089 | wmi_ut.args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id; |
| 10095 | /* Currently we could pass segment_id(b0 - b1), chirp(b2) | 10090 | /* |
| 10091 | * Currently we could pass segment_id(b0 - b1), chirp(b2) | ||
| 10096 | * freq offset (b3 - b10) to unit test. For simulation | 10092 | * freq offset (b3 - b10) to unit test. For simulation |
| 10097 | * purpose this can be set to 0 which is valid. | 10093 | * purpose this can be set to 0 which is valid. |
| 10098 | */ | 10094 | */ |
| 10099 | dfs_args[DFS_TEST_RADAR_PARAM] = 0; | 10095 | wmi_ut.args[DFS_TEST_RADAR_PARAM] = 0; |
| 10100 | 10096 | ||
| 10101 | wmi_ut.vdev_id = cpu_to_le32(arvif->vdev_id); | 10097 | wmi_ut.vdev_id = arvif->vdev_id; |
| 10102 | wmi_ut.module_id = cpu_to_le32(DFS_UNIT_TEST_MODULE); | 10098 | wmi_ut.module_id = DFS_UNIT_TEST_MODULE; |
| 10103 | wmi_ut.num_args = cpu_to_le32(DFS_MAX_TEST_ARGS); | 10099 | wmi_ut.num_args = DFS_MAX_TEST_ARGS; |
| 10104 | wmi_ut.diag_token = cpu_to_le32(DFS_UNIT_TEST_TOKEN); | 10100 | wmi_ut.diag_token = DFS_UNIT_TEST_TOKEN; |
| 10105 | 10101 | ||
| 10106 | ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Triggering Radar Simulation\n"); | 10102 | ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Triggering Radar Simulation\n"); |
| 10107 | 10103 | ||
| 10108 | return ath12k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args); | 10104 | return ath12k_wmi_send_unit_test_cmd(ar, &wmi_ut); |
| 10109 | } | 10105 | } |
| 10110 | 10106 | ||
| 10111 | int ath12k_wmi_send_tpc_stats_request(struct ath12k *ar, | 10107 | int ath12k_wmi_send_tpc_stats_request(struct ath12k *ar, |
| @@ -4193,7 +4193,6 @@ struct wmi_addba_clear_resp_cmd { · 4192 unmodified lines | |||
| 4193 | struct ath12k_wmi_mac_addr_params peer_macaddr; | 4193 | struct ath12k_wmi_mac_addr_params peer_macaddr; |
| 4194 | } __packed; | 4194 | } __packed; |
| 4195 | 4195 | ||
| 4196 | #define DFS_PHYERR_UNIT_TEST_CMD 0 | ||
| 4197 | #define DFS_UNIT_TEST_MODULE 0x2b | 4196 | #define DFS_UNIT_TEST_MODULE 0x2b |
| 4198 | #define DFS_UNIT_TEST_TOKEN 0xAA | 4197 | #define DFS_UNIT_TEST_TOKEN 0xAA |
| 4199 | 4198 | ||
| @@ -4204,10 +4203,15 @@ enum dfs_test_args_idx { · 4 unmodified lines | |||
| 4204 | DFS_MAX_TEST_ARGS, | 4203 | DFS_MAX_TEST_ARGS, |
| 4205 | }; | 4204 | }; |
| 4206 | 4205 | ||
| 4207 | struct wmi_dfs_unit_test_arg { | 4206 | /* update if another test command requires more */ |
| 4208 | u32 cmd_id; | 4207 | #define WMI_UNIT_TEST_ARGS_MAX DFS_MAX_TEST_ARGS |
| 4209 | u32 pdev_id; | 4208 | |
| 4210 | u32 radar_param; | 4209 | struct wmi_unit_test_arg { |
| 4210 | u32 vdev_id; | ||
| 4211 | u32 module_id; | ||
| 4212 | u32 diag_token; | ||
| 4213 | u32 num_args; | ||
| 4214 | u32 args[WMI_UNIT_TEST_ARGS_MAX]; | ||
| 4211 | }; | 4215 | }; |
| 4212 | 4216 | ||
| 4213 | struct wmi_unit_test_cmd { | 4217 | struct wmi_unit_test_cmd { |
| @@ -1124,8 +1124,6 @@ static int ath6kl_usb_probe(struct usb_interface *interface, · 1123 unmodified lines | |||
| 1124 | int vendor_id, product_id; | 1124 | int vendor_id, product_id; |
| 1125 | int ret = 0; | 1125 | int ret = 0; |
| 1126 | 1126 | ||
| 1127 | usb_get_dev(dev); | ||
| 1128 | |||
| 1129 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); | 1127 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); |
| 1130 | product_id = le16_to_cpu(dev->descriptor.idProduct); | 1128 | product_id = le16_to_cpu(dev->descriptor.idProduct); |
| 1131 | 1129 | ||
| @@ -1143,11 +1141,8 @@ static int ath6kl_usb_probe(struct usb_interface *interface, · 11 unmodified lines | |||
| 1143 | ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n"); | 1141 | ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n"); |
| 1144 | 1142 | ||
| 1145 | ar_usb = ath6kl_usb_create(interface); | 1143 | ar_usb = ath6kl_usb_create(interface); |
| 1146 | 1144 | if (ar_usb == NULL) | |
| 1147 | if (ar_usb == NULL) { | 1145 | return -ENOMEM; |
| 1148 | ret = -ENOMEM; | ||
| 1149 | goto err_usb_put; | ||
| 1150 | } | ||
| 1151 | 1146 | ||
| 1152 | ar = ath6kl_core_create(&ar_usb->udev->dev); | 1147 | ar = ath6kl_core_create(&ar_usb->udev->dev); |
| 1153 | if (ar == NULL) { | 1148 | if (ar == NULL) { |
| @@ -1176,15 +1171,12 @@ err_core_free: · 22 unmodified lines | |||
| 1176 | ath6kl_core_destroy(ar); | 1171 | ath6kl_core_destroy(ar); |
| 1177 | err_usb_destroy: | 1172 | err_usb_destroy: |
| 1178 | ath6kl_usb_destroy(ar_usb); | 1173 | ath6kl_usb_destroy(ar_usb); |
| 1179 | err_usb_put: | ||
| 1180 | usb_put_dev(dev); | ||
| 1181 | 1174 | ||
| 1182 | return ret; | 1175 | return ret; |
| 1183 | } | 1176 | } |
| 1184 | 1177 | ||
| 1185 | static void ath6kl_usb_remove(struct usb_interface *interface) | 1178 | static void ath6kl_usb_disconnect(struct usb_interface *interface) |
| 1186 | { | 1179 | { |
| 1187 | usb_put_dev(interface_to_usbdev(interface)); | ||
| 1188 | ath6kl_usb_device_detached(interface); | 1180 | ath6kl_usb_device_detached(interface); |
| 1189 | } | 1181 | } |
| 1190 | 1182 | ||
| @@ -1235,7 +1227,7 @@ static struct usb_driver ath6kl_usb_driver = { · 44 unmodified lines | |||
| 1235 | .probe = ath6kl_usb_probe, | 1227 | .probe = ath6kl_usb_probe, |
| 1236 | .suspend = ath6kl_usb_pm_suspend, | 1228 | .suspend = ath6kl_usb_pm_suspend, |
| 1237 | .resume = ath6kl_usb_pm_resume, | 1229 | .resume = ath6kl_usb_pm_resume, |
| 1238 | .disconnect = ath6kl_usb_remove, | 1230 | .disconnect = ath6kl_usb_disconnect, |
| 1239 | .id_table = ath6kl_usb_ids, | 1231 | .id_table = ath6kl_usb_ids, |
| 1240 | .supports_autosuspend = true, | 1232 | .supports_autosuspend = true, |
| 1241 | .disable_hub_initiated_lpm = 1, | 1233 | .disable_hub_initiated_lpm = 1, |
| @@ -1630,16 +1630,6 @@ enum wmi_roam_mode { · 1629 unmodified lines | |||
| 1630 | WMI_LOCK_BSS_MODE = 3, /* Lock to the current BSS */ | 1630 | WMI_LOCK_BSS_MODE = 3, /* Lock to the current BSS */ |
| 1631 | }; | 1631 | }; |
| 1632 | 1632 | ||
| 1633 | struct bss_bias { | ||
| 1634 | u8 bssid[ETH_ALEN]; | ||
| 1635 | s8 bias; | ||
| 1636 | } __packed; | ||
| 1637 | |||
| 1638 | struct bss_bias_info { | ||
| 1639 | u8 num_bss; | ||
| 1640 | struct bss_bias bss_bias[]; | ||
| 1641 | } __packed; | ||
| 1642 | |||
| 1643 | struct low_rssi_scan_params { | 1633 | struct low_rssi_scan_params { |
| 1644 | __le16 lrssi_scan_period; | 1634 | __le16 lrssi_scan_period; |
| 1645 | a_sle16 lrssi_scan_threshold; | 1635 | a_sle16 lrssi_scan_threshold; |
| @@ -1652,7 +1642,6 @@ struct roam_ctrl_cmd { · 6 unmodified lines | |||
| 1652 | union { | 1642 | union { |
| 1653 | u8 bssid[ETH_ALEN]; /* WMI_FORCE_ROAM */ | 1643 | u8 bssid[ETH_ALEN]; /* WMI_FORCE_ROAM */ |
| 1654 | u8 roam_mode; /* WMI_SET_ROAM_MODE */ | 1644 | u8 roam_mode; /* WMI_SET_ROAM_MODE */ |
| 1655 | struct bss_bias_info bss; /* WMI_SET_HOST_BIAS */ | ||
| 1656 | struct low_rssi_scan_params params; /* WMI_SET_LRSSI_SCAN_PARAMS | 1645 | struct low_rssi_scan_params params; /* WMI_SET_LRSSI_SCAN_PARAMS |
| 1657 | */ | 1646 | */ |
| 1658 | } __packed info; | 1647 | } __packed info; |
| @@ -1382,8 +1382,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, · 1381 unmodified lines | |||
| 1382 | goto err_alloc; | 1382 | goto err_alloc; |
| 1383 | } | 1383 | } |
| 1384 | 1384 | ||
| 1385 | usb_get_dev(udev); | ||
| 1386 | |||
| 1387 | hif_dev->udev = udev; | 1385 | hif_dev->udev = udev; |
| 1388 | hif_dev->interface = interface; | 1386 | hif_dev->interface = interface; |
| 1389 | hif_dev->usb_device_id = id; | 1387 | hif_dev->usb_device_id = id; |
| @@ -1403,7 +1401,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, · 13 unmodified lines | |||
| 1403 | err_fw_req: | 1401 | err_fw_req: |
| 1404 | usb_set_intfdata(interface, NULL); | 1402 | usb_set_intfdata(interface, NULL); |
| 1405 | kfree(hif_dev); | 1403 | kfree(hif_dev); |
| 1406 | usb_put_dev(udev); | ||
| 1407 | err_alloc: | 1404 | err_alloc: |
| 1408 | return ret; | 1405 | return ret; |
| 1409 | } | 1406 | } |
| @@ -1451,7 +1448,6 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) · 41 unmodified lines | |||
| 1451 | 1448 | ||
| 1452 | kfree(hif_dev); | 1449 | kfree(hif_dev); |
| 1453 | dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n"); | 1450 | dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n"); |
| 1454 | usb_put_dev(udev); | ||
| 1455 | } | 1451 | } |
| 1456 | 1452 | ||
| 1457 | #ifdef CONFIG_PM | 1453 | #ifdef CONFIG_PM |
| @@ -837,18 +837,19 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, · 836 unmodified lines | |||
| 837 | struct b43_dmaring *ring; | 837 | struct b43_dmaring *ring; |
| 838 | int i, err; | 838 | int i, err; |
| 839 | dma_addr_t dma_test; | 839 | dma_addr_t dma_test; |
| 840 | size_t nr_slots; | ||
| 840 | 841 | ||
| 841 | ring = kzalloc_obj(*ring); | 842 | if (for_tx) |
| 843 | nr_slots = B43_TXRING_SLOTS; | ||
| 844 | else | ||
| 845 | nr_slots = B43_RXRING_SLOTS; | ||
| 846 | |||
| 847 | ring = kzalloc_flex(*ring, meta, nr_slots); | ||
| 842 | if (!ring) | 848 | if (!ring) |
| 843 | goto out; | 849 | goto out; |
| 844 | 850 | ||
| 845 | ring->nr_slots = B43_RXRING_SLOTS; | 851 | ring->nr_slots = nr_slots; |
| 846 | if (for_tx) | ||
| 847 | ring->nr_slots = B43_TXRING_SLOTS; | ||
| 848 | 852 | ||
| 849 | ring->meta = kzalloc_objs(struct b43_dmadesc_meta, ring->nr_slots); | ||
| 850 | if (!ring->meta) | ||
| 851 | goto err_kfree_ring; | ||
| 852 | for (i = 0; i < ring->nr_slots; i++) | 853 | for (i = 0; i < ring->nr_slots; i++) |
| 853 | ring->meta->skb = B43_DMA_PTR_POISON; | 854 | ring->meta->skb = B43_DMA_PTR_POISON; |
| 854 | 855 | ||
| @@ -943,8 +944,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, · 88 unmodified lines | |||
| 943 | err_kfree_txhdr_cache: | 944 | err_kfree_txhdr_cache: |
| 944 | kfree(ring->txhdr_cache); | 945 | kfree(ring->txhdr_cache); |
| 945 | err_kfree_meta: | 946 | err_kfree_meta: |
| 946 | kfree(ring->meta); | ||
| 947 | err_kfree_ring: | ||
| 948 | kfree(ring); | 947 | kfree(ring); |
| 949 | ring = NULL; | 948 | ring = NULL; |
| 950 | goto out; | 949 | goto out; |
| @@ -1004,7 +1003,6 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring, · 53 unmodified lines | |||
| 1004 | free_ringmemory(ring); | 1003 | free_ringmemory(ring); |
| 1005 | 1004 | ||
| 1006 | kfree(ring->txhdr_cache); | 1005 | kfree(ring->txhdr_cache); |
| 1007 | kfree(ring->meta); | ||
| 1008 | kfree(ring); | 1006 | kfree(ring); |
| 1009 | } | 1007 | } |
| 1010 | 1008 | ||
| @@ -228,8 +228,6 @@ struct b43_dmaring { · 227 unmodified lines | |||
| 228 | const struct b43_dma_ops *ops; | 228 | const struct b43_dma_ops *ops; |
| 229 | /* Kernel virtual base address of the ring memory. */ | 229 | /* Kernel virtual base address of the ring memory. */ |
| 230 | void *descbase; | 230 | void *descbase; |
| 231 | /* Meta data about all descriptors. */ | ||
| 232 | struct b43_dmadesc_meta *meta; | ||
| 233 | /* Cache of TX headers for each TX frame. | 231 | /* Cache of TX headers for each TX frame. |
| 234 | * This is to avoid an allocation on each TX. | 232 | * This is to avoid an allocation on each TX. |
| 235 | * This is NULL for an RX ring. | 233 | * This is NULL for an RX ring. |
| @@ -273,6 +271,8 @@ struct b43_dmaring { · 37 unmodified lines | |||
| 273 | /* Statistics: Total number of TX plus all retries. */ | 271 | /* Statistics: Total number of TX plus all retries. */ |
| 274 | u64 nr_total_packet_tries; | 272 | u64 nr_total_packet_tries; |
| 275 | #endif /* CONFIG_B43_DEBUG */ | 273 | #endif /* CONFIG_B43_DEBUG */ |
| 274 | /* Meta data about all descriptors. */ | ||
| 275 | struct b43_dmadesc_meta meta[] __counted_by(nr_slots); | ||
| 276 | }; | 276 | }; |
| 277 | 277 | ||
| 278 | static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) | 278 | static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include "fw/api/txq.h" | 10 | #include "fw/api/txq.h" |
| 11 | 11 | ||
| 12 | /* Highest firmware core release supported */ | 12 | /* Highest firmware core release supported */ |
| 13 | #define IWL_BZ_UCODE_CORE_MAX 101 | 13 | #define IWL_BZ_UCODE_CORE_MAX 102 |
| 14 | 14 | ||
| 15 | /* Lowest firmware API version supported */ | 15 | /* Lowest firmware API version supported */ |
| 16 | #define IWL_BZ_UCODE_API_MIN 100 | 16 | #define IWL_BZ_UCODE_API_MIN 100 |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include "fw/api/txq.h" | 9 | #include "fw/api/txq.h" |
| 10 | 10 | ||
| 11 | /* Highest firmware core release supported */ | 11 | /* Highest firmware core release supported */ |
| 12 | #define IWL_DR_UCODE_CORE_MAX 101 | 12 | #define IWL_DR_UCODE_CORE_MAX 102 |
| 13 | 13 | ||
| 14 | /* Lowest firmware API version supported */ | 14 | /* Lowest firmware API version supported */ |
| 15 | #define IWL_DR_UCODE_API_MIN 100 | 15 | #define IWL_DR_UCODE_API_MIN 100 |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include "fw/api/txq.h" | 10 | #include "fw/api/txq.h" |
| 11 | 11 | ||
| 12 | /* Highest firmware core release supported */ | 12 | /* Highest firmware core release supported */ |
| 13 | #define IWL_SC_UCODE_CORE_MAX 101 | 13 | #define IWL_SC_UCODE_CORE_MAX 102 |
| 14 | 14 | ||
| 15 | /* Lowest firmware API version supported */ | 15 | /* Lowest firmware API version supported */ |
| 16 | #define IWL_SC_UCODE_API_MIN 100 | 16 | #define IWL_SC_UCODE_API_MIN 100 |
| @@ -504,7 +504,8 @@ iwl_acpi_parse_chains_table(union acpi_object *table, · 503 unmodified lines | |||
| 504 | u8 num_chains, u8 num_sub_bands) | 504 | u8 num_chains, u8 num_sub_bands) |
| 505 | { | 505 | { |
| 506 | for (u8 chain = 0; chain < num_chains; chain++) { | 506 | for (u8 chain = 0; chain < num_chains; chain++) { |
| 507 | for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM; | 507 | for (u8 subband = 0; |
| 508 | subband < ARRAY_SIZE(chains[chain].subbands); | ||
| 508 | subband++) { | 509 | subband++) { |
| 509 | /* if we don't have the values, use the default */ | 510 | /* if we don't have the values, use the default */ |
| 510 | if (subband >= num_sub_bands) { | 511 | if (subband >= num_sub_bands) { |
| @@ -534,7 +535,23 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) · 23 unmodified lines | |||
| 534 | if (IS_ERR(data)) | 535 | if (IS_ERR(data)) |
| 535 | return PTR_ERR(data); | 536 | return PTR_ERR(data); |
| 536 | 537 | ||
| 537 | /* start by trying to read revision 2 */ | 538 | /* start by trying to read revision 3 */ |
| 539 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | ||
| 540 | ACPI_WRDS_WIFI_DATA_SIZE_REV3, | ||
| 541 | &tbl_rev); | ||
| 542 | if (!IS_ERR(wifi_pkg)) { | ||
| 543 | if (tbl_rev != 3) { | ||
| 544 | ret = -EINVAL; | ||
| 545 | goto out_free; | ||
| 546 | } | ||
| 547 | |||
| 548 | num_chains = ACPI_SAR_NUM_CHAINS_REV2; | ||
| 549 | num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3; | ||
| 550 | |||
| 551 | goto read_table; | ||
| 552 | } | ||
| 553 | |||
| 554 | /* then try revision 2 */ | ||
| 538 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | 555 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 539 | ACPI_WRDS_WIFI_DATA_SIZE_REV2, | 556 | ACPI_WRDS_WIFI_DATA_SIZE_REV2, |
| 540 | &tbl_rev); | 557 | &tbl_rev); |
| @@ -591,6 +608,13 @@ read_table: · 50 unmodified lines | |||
| 591 | goto out_free; | 608 | goto out_free; |
| 592 | } | 609 | } |
| 593 | 610 | ||
| 611 | if (WARN_ON(num_chains * num_sub_bands > | ||
| 612 | ARRAY_SIZE(fwrt->sar_profiles[0].chains) * | ||
| 613 | ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) { | ||
| 614 | ret = -EINVAL; | ||
| 615 | goto out_free; | ||
| 616 | } | ||
| 617 | |||
| 594 | IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); | 618 | IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); |
| 595 | 619 | ||
| 596 | flags = wifi_pkg->package.elements[1].integer.value; | 620 | flags = wifi_pkg->package.elements[1].integer.value; |
| @@ -624,7 +648,22 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) · 27 unmodified lines | |||
| 624 | if (IS_ERR(data)) | 648 | if (IS_ERR(data)) |
| 625 | return PTR_ERR(data); | 649 | return PTR_ERR(data); |
| 626 | 650 | ||
| 627 | /* start by trying to read revision 2 */ | 651 | /* start by trying to read revision 3 */ |
| 652 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | ||
| 653 | ACPI_EWRD_WIFI_DATA_SIZE_REV3, | ||
| 654 | &tbl_rev); | ||
| 655 | if (!IS_ERR(wifi_pkg)) { | ||
| 656 | if (tbl_rev != 3) { | ||
| 657 | ret = -EINVAL; | ||
| 658 | goto out_free; | ||
| 659 | } | ||
| 660 | |||
| 661 | num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3; | ||
| 662 | |||
| 663 | goto read_table; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* then try revision 2 */ | ||
| 628 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | 667 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 629 | ACPI_EWRD_WIFI_DATA_SIZE_REV2, | 668 | ACPI_EWRD_WIFI_DATA_SIZE_REV2, |
| 630 | &tbl_rev); | 669 | &tbl_rev); |
| @@ -679,6 +718,13 @@ read_table: · 48 unmodified lines | |||
| 679 | goto out_free; | 718 | goto out_free; |
| 680 | } | 719 | } |
| 681 | 720 | ||
| 721 | if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands > | ||
| 722 | ARRAY_SIZE(fwrt->sar_profiles[0].chains) * | ||
| 723 | ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) { | ||
| 724 | ret = -EINVAL; | ||
| 725 | goto out_free; | ||
| 726 | } | ||
| 727 | |||
| 682 | enabled = !!(wifi_pkg->package.elements[1].integer.value); | 728 | enabled = !!(wifi_pkg->package.elements[1].integer.value); |
| 683 | n_profiles = wifi_pkg->package.elements[2].integer.value; | 729 | n_profiles = wifi_pkg->package.elements[2].integer.value; |
| 684 | 730 | ||
| @@ -721,6 +767,13 @@ read_table: · 36 unmodified lines | |||
| 721 | if (tbl_rev < 2) | 767 | if (tbl_rev < 2) |
| 722 | goto set_enabled; | 768 | goto set_enabled; |
| 723 | 769 | ||
| 770 | if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * 2 * num_sub_bands > | ||
| 771 | ARRAY_SIZE(fwrt->sar_profiles[0].chains) * | ||
| 772 | ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) { | ||
| 773 | ret = -EINVAL; | ||
| 774 | goto out_free; | ||
| 775 | } | ||
| 776 | |||
| 724 | /* parse cdb chains for all profiles */ | 777 | /* parse cdb chains for all profiles */ |
| 725 | for (i = 0; i < n_profiles; i++) { | 778 | for (i = 0; i < n_profiles; i++) { |
| 726 | struct iwl_sar_profile_chain *chains; | 779 | struct iwl_sar_profile_chain *chains; |
| @@ -759,6 +812,12 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) · 32 unmodified lines | |||
| 759 | u8 profiles; | 812 | u8 profiles; |
| 760 | u8 min_profiles; | 813 | u8 min_profiles; |
| 761 | } rev_data[] = { | 814 | } rev_data[] = { |
| 815 | { | ||
| 816 | .revisions = BIT(4), | ||
| 817 | .bands = ACPI_GEO_NUM_BANDS_REV4, | ||
| 818 | .profiles = ACPI_NUM_GEO_PROFILES_REV3, | ||
| 819 | .min_profiles = BIOS_GEO_MIN_PROFILE_NUM, | ||
| 820 | }, | ||
| 762 | { | 821 | { |
| 763 | .revisions = BIT(3), | 822 | .revisions = BIT(3), |
| 764 | .bands = ACPI_GEO_NUM_BANDS_REV2, | 823 | .bands = ACPI_GEO_NUM_BANDS_REV2, |
| @@ -812,6 +871,18 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) · 47 unmodified lines | |||
| 812 | num_bands = rev_data[idx].bands; | 871 | num_bands = rev_data[idx].bands; |
| 813 | num_profiles = rev_data[idx].profiles; | 872 | num_profiles = rev_data[idx].profiles; |
| 814 | 873 | ||
| 874 | if (WARN_ON(num_profiles > | ||
| 875 | ARRAY_SIZE(fwrt->geo_profiles))) { | ||
| 876 | ret = -EINVAL; | ||
| 877 | goto out_free; | ||
| 878 | } | ||
| 879 | |||
| 880 | if (WARN_ON(num_bands > | ||
| 881 | ARRAY_SIZE(fwrt->geo_profiles[0].bands))) { | ||
| 882 | ret = -EINVAL; | ||
| 883 | goto out_free; | ||
| 884 | } | ||
| 885 | |||
| 815 | if (rev_data[idx].min_profiles) { | 886 | if (rev_data[idx].min_profiles) { |
| 816 | /* read header that says # of profiles */ | 887 | /* read header that says # of profiles */ |
| 817 | union acpi_object *entry; | 888 | union acpi_object *entry; |
| @@ -851,18 +922,20 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) · 33 unmodified lines | |||
| 851 | 922 | ||
| 852 | read_table: | 923 | read_table: |
| 853 | fwrt->geo_rev = tbl_rev; | 924 | fwrt->geo_rev = tbl_rev; |
| 925 | |||
| 854 | for (i = 0; i < num_profiles; i++) { | 926 | for (i = 0; i < num_profiles; i++) { |
| 855 | for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) { | 927 | struct iwl_geo_profile *prof = &fwrt->geo_profiles[i]; |
| 928 | |||
| 929 | for (j = 0; j < ARRAY_SIZE(prof->bands); j++) { | ||
| 856 | union acpi_object *entry; | 930 | union acpi_object *entry; |
| 857 | 931 | ||
| 858 | /* | 932 | /* |
| 859 | * num_bands is either 2 or 3, if it's only 2 then | 933 | * num_bands is either 2 or 3 or 4, if it's lower |
| 860 | * fill the third band (6 GHz) with the values from | 934 | * than 4, fill the third band (6 GHz) with the values |
| 861 | * 5 GHz (second band) | 935 | * from 5 GHz (second band) |
| 862 | */ | 936 | */ |
| 863 | if (j >= num_bands) { | 937 | if (j >= num_bands) { |
| 864 | fwrt->geo_profiles[i].bands[j].max = | 938 | prof->bands[j].max = prof->bands[1].max; |
| 865 | fwrt->geo_profiles[i].bands[1].max; | ||
| 866 | } else { | 939 | } else { |
| 867 | entry = &wifi_pkg->package.elements[entry_idx]; | 940 | entry = &wifi_pkg->package.elements[entry_idx]; |
| 868 | entry_idx++; | 941 | entry_idx++; |
| @@ -872,15 +945,17 @@ read_table: · 3 unmodified lines | |||
| 872 | goto out_free; | 945 | goto out_free; |
| 873 | } | 946 | } |
| 874 | 947 | ||
| 875 | fwrt->geo_profiles[i].bands[j].max = | 948 | prof->bands[j].max = |
| 876 | entry->integer.value; | 949 | entry->integer.value; |
| 877 | } | 950 | } |
| 878 | 951 | ||
| 879 | for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) { | 952 | for (k = 0; |
| 953 | k < ARRAY_SIZE(prof->bands[0].chains); | ||
| 954 | k++) { | ||
| 880 | /* same here as above */ | 955 | /* same here as above */ |
| 881 | if (j >= num_bands) { | 956 | if (j >= num_bands) { |
| 882 | fwrt->geo_profiles[i].bands[j].chains[k] = | 957 | prof->bands[j].chains[k] = |
| 883 | fwrt->geo_profiles[i].bands[1].chains[k]; | 958 | prof->bands[1].chains[k]; |
| 884 | } else { | 959 | } else { |
| 885 | entry = &wifi_pkg->package.elements[entry_idx]; | 960 | entry = &wifi_pkg->package.elements[entry_idx]; |
| 886 | entry_idx++; | 961 | entry_idx++; |
| @@ -890,7 +965,7 @@ read_table: · 3 unmodified lines | |||
| 890 | goto out_free; | 965 | goto out_free; |
| 891 | } | 966 | } |
| 892 | 967 | ||
| 893 | fwrt->geo_profiles[i].bands[j].chains[k] = | 968 | prof->bands[j].chains[k] = |
| 894 | entry->integer.value; | 969 | entry->integer.value; |
| 895 | } | 970 | } |
| 896 | } | 971 | } |
| @@ -898,6 +973,7 @@ read_table: · 1 unmodified line | |||
| 898 | } | 973 | } |
| 899 | 974 | ||
| 900 | fwrt->geo_num_profiles = num_profiles; | 975 | fwrt->geo_num_profiles = num_profiles; |
| 976 | fwrt->geo_bios_source = BIOS_SOURCE_ACPI; | ||
| 901 | fwrt->geo_enabled = true; | 977 | fwrt->geo_enabled = true; |
| 902 | ret = 0; | 978 | ret = 0; |
| 903 | out_free: | 979 | out_free: |
| @@ -915,6 +991,22 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) · 11 unmodified lines | |||
| 915 | if (IS_ERR(data)) | 991 | if (IS_ERR(data)) |
| 916 | return PTR_ERR(data); | 992 | return PTR_ERR(data); |
| 917 | 993 | ||
| 994 | /* try to read ppag table rev 5 */ | ||
| 995 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | ||
| 996 | ACPI_PPAG_WIFI_DATA_SIZE_V3, &tbl_rev); | ||
| 997 | if (!IS_ERR(wifi_pkg)) { | ||
| 998 | if (tbl_rev == 5) { | ||
| 999 | num_sub_bands = IWL_NUM_SUB_BANDS_V3; | ||
| 1000 | IWL_DEBUG_RADIO(fwrt, | ||
| 1001 | "Reading PPAG table (tbl_rev=%d)\n", | ||
| 1002 | tbl_rev); | ||
| 1003 | goto read_table; | ||
| 1004 | } else { | ||
| 1005 | ret = -EINVAL; | ||
| 1006 | goto out_free; | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | |||
| 918 | /* try to read ppag table rev 1 to 4 (all have the same data size) */ | 1010 | /* try to read ppag table rev 1 to 4 (all have the same data size) */ |
| 919 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, | 1011 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 920 | ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); | 1012 | ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); |
| @@ -950,6 +1042,15 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) · 29 unmodified lines | |||
| 950 | goto out_free; | 1042 | goto out_free; |
| 951 | 1043 | ||
| 952 | read_table: | 1044 | read_table: |
| 1045 | if (WARN_ON_ONCE(num_sub_bands > | ||
| 1046 | ARRAY_SIZE(fwrt->ppag_chains[0].subbands))) { | ||
| 1047 | ret = -EINVAL; | ||
| 1048 | goto out_free; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | BUILD_BUG_ON(ACPI_PPAG_NUM_CHAINS > | ||
| 1052 | ARRAY_SIZE(fwrt->ppag_chains)); | ||
| 1053 | |||
| 953 | fwrt->ppag_bios_rev = tbl_rev; | 1054 | fwrt->ppag_bios_rev = tbl_rev; |
| 954 | flags = &wifi_pkg->package.elements[1]; | 1055 | flags = &wifi_pkg->package.elements[1]; |
| 955 | 1056 | ||
| @@ -966,7 +1067,7 @@ read_table: · 10 unmodified lines | |||
| 966 | * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the | 1067 | * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the |
| 967 | * following sub-bands to High-Band (5GHz). | 1068 | * following sub-bands to High-Band (5GHz). |
| 968 | */ | 1069 | */ |
| 969 | for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { | 1070 | for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) { |
| 970 | for (j = 0; j < num_sub_bands; j++) { | 1071 | for (j = 0; j < num_sub_bands; j++) { |
| 971 | union acpi_object *ent; | 1072 | union acpi_object *ent; |
| 972 | 1073 | ||
| @@ -980,6 +1081,7 @@ read_table: · 7 unmodified lines | |||
| 980 | } | 1081 | } |
| 981 | } | 1082 | } |
| 982 | 1083 | ||
| 1084 | iwl_bios_print_ppag(fwrt, num_sub_bands); | ||
| 983 | fwrt->ppag_bios_source = BIOS_SOURCE_ACPI; | 1085 | fwrt->ppag_bios_source = BIOS_SOURCE_ACPI; |
| 984 | ret = 0; | 1086 | ret = 0; |
| 985 | 1087 | ||
| @@ -8,11 +8,6 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/acpi.h> | 9 | #include <linux/acpi.h> |
| 10 | #include "fw/regulatory.h" | 10 | #include "fw/regulatory.h" |
| 11 | #include "fw/api/commands.h" | ||
| 12 | #include "fw/api/power.h" | ||
| 13 | #include "fw/api/phy.h" | ||
| 14 | #include "fw/api/nvm-reg.h" | ||
| 15 | #include "fw/api/config.h" | ||
| 16 | #include "fw/img.h" | 11 | #include "fw/img.h" |
| 17 | #include "iwl-trans.h" | 12 | #include "iwl-trans.h" |
| 18 | 13 | ||
| @@ -44,6 +39,7 @@ · 25 unmodified lines | |||
| 44 | #define ACPI_SAR_NUM_SUB_BANDS_REV0 5 | 39 | #define ACPI_SAR_NUM_SUB_BANDS_REV0 5 |
| 45 | #define ACPI_SAR_NUM_SUB_BANDS_REV1 11 | 40 | #define ACPI_SAR_NUM_SUB_BANDS_REV1 11 |
| 46 | #define ACPI_SAR_NUM_SUB_BANDS_REV2 11 | 41 | #define ACPI_SAR_NUM_SUB_BANDS_REV2 11 |
| 42 | #define ACPI_SAR_NUM_SUB_BANDS_REV3 12 | ||
| 47 | 43 | ||
| 48 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ | 44 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ |
| 49 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) | 45 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) |
| @@ -51,6 +47,8 @@ · 1 unmodified line | |||
| 51 | ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) | 47 | ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) |
| 52 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ | 48 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ |
| 53 | ACPI_SAR_NUM_SUB_BANDS_REV2 + 2) | 49 | ACPI_SAR_NUM_SUB_BANDS_REV2 + 2) |
| 50 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV3 (ACPI_SAR_NUM_CHAINS_REV2 * \ | ||
| 51 | ACPI_SAR_NUM_SUB_BANDS_REV3 + 2) | ||
| 54 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \ | 52 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \ |
| 55 | ACPI_SAR_NUM_CHAINS_REV0 * \ | 53 | ACPI_SAR_NUM_CHAINS_REV0 * \ |
| 56 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) | 54 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) |
| @@ -60,11 +58,15 @@ · 3 unmodified lines | |||
| 60 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ | 58 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ |
| 61 | ACPI_SAR_NUM_CHAINS_REV2 * \ | 59 | ACPI_SAR_NUM_CHAINS_REV2 * \ |
| 62 | ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) | 60 | ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) |
| 61 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV3 ((ACPI_SAR_PROFILE_NUM - 1) * \ | ||
| 62 | ACPI_SAR_NUM_CHAINS_REV2 * \ | ||
| 63 | ACPI_SAR_NUM_SUB_BANDS_REV3 + 3) | ||
| 63 | #define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ | 64 | #define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ |
| 64 | 65 | ||
| 65 | /* revision 0 and 1 are identical, except for the semantics in the FW */ | 66 | /* revision 0 and 1 are identical, except for the semantics in the FW */ |
| 66 | #define ACPI_GEO_NUM_BANDS_REV0 2 | 67 | #define ACPI_GEO_NUM_BANDS_REV0 2 |
| 67 | #define ACPI_GEO_NUM_BANDS_REV2 3 | 68 | #define ACPI_GEO_NUM_BANDS_REV2 3 |
| 69 | #define ACPI_GEO_NUM_BANDS_REV4 4 | ||
| 68 | 70 | ||
| 69 | #define ACPI_WRDD_WIFI_DATA_SIZE 2 | 71 | #define ACPI_WRDD_WIFI_DATA_SIZE 2 |
| 70 | #define ACPI_SPLC_WIFI_DATA_SIZE 2 | 72 | #define ACPI_SPLC_WIFI_DATA_SIZE 2 |
| @@ -96,10 +98,18 @@ · 25 unmodified lines | |||
| 96 | */ | 98 | */ |
| 97 | #define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX) | 99 | #define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX) |
| 98 | 100 | ||
| 99 | #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \ | 101 | #define ACPI_PPAG_NUM_CHAINS 2 |
| 100 | IWL_NUM_SUB_BANDS_V1) + 2) | 102 | #define ACPI_PPAG_NUM_BANDS_V1 5 |
| 101 | #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ | 103 | #define ACPI_PPAG_NUM_BANDS_V2 11 |
| 102 | IWL_NUM_SUB_BANDS_V2) + 2) | 104 | #define ACPI_PPAG_NUM_BANDS_V3 12 |
| 105 | #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((ACPI_PPAG_NUM_CHAINS * \ | ||
| 106 | ACPI_PPAG_NUM_BANDS_V1) + 2) | ||
| 107 | #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((ACPI_PPAG_NUM_CHAINS * \ | ||
| 108 | ACPI_PPAG_NUM_BANDS_V2) + 2) | ||
| 109 | |||
| 110 | /* used for ACPI PPAG table rev 5 */ | ||
| 111 | #define ACPI_PPAG_WIFI_DATA_SIZE_V3 ((ACPI_PPAG_NUM_CHAINS * \ | ||
| 112 | ACPI_PPAG_NUM_BANDS_V3) + 2) | ||
| 103 | 113 | ||
| 104 | #define IWL_SAR_ENABLE_MSK BIT(0) | 114 | #define IWL_SAR_ENABLE_MSK BIT(0) |
| 105 | #define IWL_REDUCE_POWER_FLAGS_POS 1 | 115 | #define IWL_REDUCE_POWER_FLAGS_POS 1 |
| @@ -56,7 +56,8 @@ enum iwl_data_path_subcmd_ids { · 55 unmodified lines | |||
| 56 | RFH_QUEUE_CONFIG_CMD = 0xD, | 56 | RFH_QUEUE_CONFIG_CMD = 0xD, |
| 57 | 57 | ||
| 58 | /** | 58 | /** |
| 59 | * @TLC_MNG_CONFIG_CMD: &struct iwl_tlc_config_cmd_v4 | 59 | * @TLC_MNG_CONFIG_CMD: &struct iwl_tlc_config_cmd_v4 or |
| 60 | * &struct iwl_tlc_config_cmd_v5 or &struct iwl_tlc_config_cmd. | ||
| 60 | */ | 61 | */ |
| 61 | TLC_MNG_CONFIG_CMD = 0xF, | 62 | TLC_MNG_CONFIG_CMD = 0xF, |
| 62 | 63 | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ | 1 | /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2012-2014, 2018-2019, 2021-2025 Intel Corporation | 3 | * Copyright (C) 2012-2014, 2018-2019, 2021-2026 Intel Corporation |
| 4 | * Copyright (C) 2013-2015 Intel Mobile Communications GmbH | 4 | * Copyright (C) 2013-2015 Intel Mobile Communications GmbH |
| 5 | * Copyright (C) 2016-2017 Intel Deutschland GmbH | 5 | * Copyright (C) 2016-2017 Intel Deutschland GmbH |
| 6 | */ | 6 | */ |
| @@ -26,7 +26,7 @@ enum iwl_mac_conf_subcmd_ids { · 19 unmodified lines | |||
| 26 | */ | 26 | */ |
| 27 | MISSED_VAP_NOTIF = 0xFA, | 27 | MISSED_VAP_NOTIF = 0xFA, |
| 28 | /** | 28 | /** |
| 29 | * @SESSION_PROTECTION_CMD: &struct iwl_mvm_session_prot_cmd | 29 | * @SESSION_PROTECTION_CMD: &struct iwl_session_prot_cmd |
| 30 | */ | 30 | */ |
| 31 | SESSION_PROTECTION_CMD = 0x5, | 31 | SESSION_PROTECTION_CMD = 0x5, |
| 32 | /** | 32 | /** |
| @@ -34,7 +34,8 @@ enum iwl_mac_conf_subcmd_ids { · 1 unmodified line | |||
| 34 | */ | 34 | */ |
| 35 | CANCEL_CHANNEL_SWITCH_CMD = 0x6, | 35 | CANCEL_CHANNEL_SWITCH_CMD = 0x6, |
| 36 | /** | 36 | /** |
| 37 | * @MAC_CONFIG_CMD: &struct iwl_mac_config_cmd | 37 | * @MAC_CONFIG_CMD: &struct iwl_mac_config_cmd_v3 or |
| 38 | * &struct iwl_mac_config_cmd | ||
| 38 | */ | 39 | */ |
| 39 | MAC_CONFIG_CMD = 0x8, | 40 | MAC_CONFIG_CMD = 0x8, |
| 40 | /** | 41 | /** |
| @@ -42,7 +43,8 @@ enum iwl_mac_conf_subcmd_ids { · 1 unmodified line | |||
| 42 | */ | 43 | */ |
| 43 | LINK_CONFIG_CMD = 0x9, | 44 | LINK_CONFIG_CMD = 0x9, |
| 44 | /** | 45 | /** |
| 45 | * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd | 46 | * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd_v1, |
| 47 | * &struct iwl_sta_cfg_cmd_v2, or &struct iwl_sta_cfg_cmd | ||
| 46 | */ | 48 | */ |
| 47 | STA_CONFIG_CMD = 0xA, | 49 | STA_CONFIG_CMD = 0xA, |
| 48 | /** | 50 | /** |
| @@ -356,7 +358,7 @@ struct iwl_mac_wifi_gen_support { · 307 unmodified lines | |||
| 356 | } __packed; | 358 | } __packed; |
| 357 | 359 | ||
| 358 | /** | 360 | /** |
| 359 | * struct iwl_mac_config_cmd - command structure to configure MAC contexts in | 361 | * struct iwl_mac_config_cmd_v3 - command structure to configure MAC contexts in |
| 360 | * MLD API for versions 2 and 3 | 362 | * MLD API for versions 2 and 3 |
| 361 | * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) | 363 | * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) |
| 362 | * | 364 | * |
| @@ -375,7 +377,7 @@ struct iwl_mac_wifi_gen_support { · 12 unmodified lines | |||
| 375 | * @client: client mac data | 377 | * @client: client mac data |
| 376 | * @p2p_dev: mac data for p2p device | 378 | * @p2p_dev: mac data for p2p device |
| 377 | */ | 379 | */ |
| 378 | struct iwl_mac_config_cmd { | 380 | struct iwl_mac_config_cmd_v3 { |
| 379 | __le32 id_and_color; | 381 | __le32 id_and_color; |
| 380 | __le32 action; | 382 | __le32 action; |
| 381 | /* MAC_CONTEXT_TYPE_API_E */ | 383 | /* MAC_CONTEXT_TYPE_API_E */ |
| @@ -393,7 +395,62 @@ struct iwl_mac_config_cmd { · 11 unmodified lines | |||
| 393 | struct iwl_mac_client_data client; | 395 | struct iwl_mac_client_data client; |
| 394 | struct iwl_mac_p2p_dev_data p2p_dev; | 396 | struct iwl_mac_p2p_dev_data p2p_dev; |
| 395 | }; | 397 | }; |
| 396 | } __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_2_VER_3 */ | 398 | } __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_2, _VER_3 */ |
| 399 | |||
| 400 | /** | ||
| 401 | * struct iwl_mac_nan_data - NAN specific MAC data | ||
| 402 | * @ndi_addrs: extra NDI addresses being used | ||
| 403 | * @ndi_addrs_count: number of extra NDI addresses | ||
| 404 | */ | ||
| 405 | struct iwl_mac_nan_data { | ||
| 406 | struct { | ||
| 407 | u8 addr[ETH_ALEN]; | ||
| 408 | __le16 reserved; | ||
| 409 | } __packed ndi_addrs[2]; | ||
| 410 | __le32 ndi_addrs_count; | ||
| 411 | } __packed; /* MAC_CONTEXT_CONFIG_NAN_DATA_API_S_VER_1 */ | ||
| 412 | |||
| 413 | /** | ||
| 414 | * struct iwl_mac_config_cmd - command structure to configure MAC contexts in | ||
| 415 | * MLD API for versions 4 | ||
| 416 | * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) | ||
| 417 | * | ||
| 418 | * @id_and_color: ID and color of the MAC | ||
| 419 | * @action: action to perform, see &enum iwl_ctxt_action | ||
| 420 | * @mac_type: one of &enum iwl_mac_types | ||
| 421 | * @local_mld_addr: mld address | ||
| 422 | * @reserved_for_local_mld_addr: reserved | ||
| 423 | * @filter_flags: combination of &enum iwl_mac_config_filter_flags | ||
| 424 | * @wifi_gen_v2: he/eht parameters as in cmd version 2 | ||
| 425 | * @wifi_gen: he/eht/uhr parameters as in cmd version 3 | ||
| 426 | * @nic_not_ack_enabled: mark that the NIC doesn't support receiving | ||
| 427 | * ACK-enabled AGG, (i.e. both BACK and non-BACK frames in single AGG). | ||
| 428 | * If the NIC is not ACK_ENABLED it may use the EOF-bit in first non-0 | ||
| 429 | * len delim to determine if AGG or single. | ||
| 430 | * @client: client mac data | ||
| 431 | * @p2p_dev: mac data for p2p device | ||
| 432 | * @nan: NAN specific data (NAN data interface addresses) | ||
| 433 | */ | ||
| 434 | struct iwl_mac_config_cmd { | ||
| 435 | __le32 id_and_color; | ||
| 436 | __le32 action; | ||
| 437 | /* MAC_CONTEXT_TYPE_API_E */ | ||
| 438 | __le32 mac_type; | ||
| 439 | u8 local_mld_addr[6]; | ||
| 440 | __le16 reserved_for_local_mld_addr; | ||
| 441 | __le32 filter_flags; | ||
| 442 | union { | ||
| 443 | struct iwl_mac_wifi_gen_support_v2 wifi_gen_v2; | ||
| 444 | struct iwl_mac_wifi_gen_support wifi_gen; | ||
| 445 | }; | ||
| 446 | __le32 nic_not_ack_enabled; | ||
| 447 | /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_3 */ | ||
| 448 | union { | ||
| 449 | struct iwl_mac_client_data client; | ||
| 450 | struct iwl_mac_p2p_dev_data p2p_dev; | ||
| 451 | struct iwl_mac_nan_data nan; | ||
| 452 | }; | ||
| 453 | } __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_4 */ | ||
| 397 | 454 | ||
| 398 | /** | 455 | /** |
| 399 | * enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being | 456 | * enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being |
| @@ -652,6 +709,7 @@ struct iwl_link_config_cmd { · 252 unmodified lines | |||
| 652 | */ | 709 | */ |
| 653 | #define IWL_FW_MAX_ACTIVE_LINKS_NUM 2 | 710 | #define IWL_FW_MAX_ACTIVE_LINKS_NUM 2 |
| 654 | #define IWL_FW_MAX_LINK_ID 3 | 711 | #define IWL_FW_MAX_LINK_ID 3 |
| 712 | #define IWL_FW_MAX_LINKS IWL_FW_MAX_LINK_ID + 1 | ||
| 655 | 713 | ||
| 656 | /** | 714 | /** |
| 657 | * enum iwl_fw_sta_type - FW station types | 715 | * enum iwl_fw_sta_type - FW station types |
| @@ -662,6 +720,13 @@ struct iwl_link_config_cmd { · 4 unmodified lines | |||
| 662 | * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be | 720 | * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be |
| 663 | * suspended / resumed at the right timing depending on the clients' | 721 | * suspended / resumed at the right timing depending on the clients' |
| 664 | * power save state and the DTIM timing | 722 | * power save state and the DTIM timing |
| 723 | * @STATION_TYPE_NAN_PEER_NMI: NAN management peer station type. A station | ||
| 724 | * of this type can have any number of links (even none) set in the | ||
| 725 | * link_mask. (Supported since version 3.) | ||
| 726 | * @STATION_TYPE_NAN_PEER_NDI: NAN data peer station type. A station | ||
| 727 | * of this type can have any number of links (even none) set in the | ||
| 728 | * link_mask. (Supported since version 3.) | ||
| 729 | * @STATION_TYPE_MAX: maximum number of FW station types | ||
| 665 | * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type | 730 | * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type |
| 666 | * for the aux sta, so this type is only for driver - internal use. | 731 | * for the aux sta, so this type is only for driver - internal use. |
| 667 | */ | 732 | */ |
| @@ -669,8 +734,11 @@ enum iwl_fw_sta_type { · 1 unmodified line | |||
| 669 | STATION_TYPE_PEER, | 734 | STATION_TYPE_PEER, |
| 670 | STATION_TYPE_BCAST_MGMT, | 735 | STATION_TYPE_BCAST_MGMT, |
| 671 | STATION_TYPE_MCAST, | 736 | STATION_TYPE_MCAST, |
| 672 | STATION_TYPE_AUX, | 737 | STATION_TYPE_NAN_PEER_NMI, |
| 673 | }; /* STATION_TYPE_E_VER_1 */ | 738 | STATION_TYPE_NAN_PEER_NDI, |
| 739 | STATION_TYPE_MAX, | ||
| 740 | STATION_TYPE_AUX = STATION_TYPE_MAX /* this doesn't exist in FW */ | ||
| 741 | }; /* STATION_TYPE_E_VER_1, _VER_2 */ | ||
| 674 | 742 | ||
| 675 | /** | 743 | /** |
| 676 | * struct iwl_sta_cfg_cmd_v1 - cmd structure to add a peer sta to the uCode's | 744 | * struct iwl_sta_cfg_cmd_v1 - cmd structure to add a peer sta to the uCode's |
| @@ -729,7 +797,7 @@ struct iwl_sta_cfg_cmd_v1 { · 52 unmodified lines | |||
| 729 | } __packed; /* STA_CMD_API_S_VER_1 */ | 797 | } __packed; /* STA_CMD_API_S_VER_1 */ |
| 730 | 798 | ||
| 731 | /** | 799 | /** |
| 732 | * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's | 800 | * struct iwl_sta_cfg_cmd_v2 - cmd structure to add a peer sta to the uCode's |
| 733 | * station table | 801 | * station table |
| 734 | * ( STA_CONFIG_CMD = 0xA ) | 802 | * ( STA_CONFIG_CMD = 0xA ) |
| 735 | * | 803 | * |
| @@ -769,7 +837,7 @@ struct iwl_sta_cfg_cmd_v1 { · 33 unmodified lines | |||
| 769 | * @mic_compute_pad_delay: MIC compute time padding | 837 | * @mic_compute_pad_delay: MIC compute time padding |
| 770 | * @reserved: Reserved for alignment | 838 | * @reserved: Reserved for alignment |
| 771 | */ | 839 | */ |
| 772 | struct iwl_sta_cfg_cmd { | 840 | struct iwl_sta_cfg_cmd_v2 { |
| 773 | __le32 sta_id; | 841 | __le32 sta_id; |
| 774 | __le32 link_id; | 842 | __le32 link_id; |
| 775 | u8 peer_mld_address[ETH_ALEN]; | 843 | u8 peer_mld_address[ETH_ALEN]; |
| @@ -799,6 +867,83 @@ struct iwl_sta_cfg_cmd { · 23 unmodified lines | |||
| 799 | u8 reserved[2]; | 867 | u8 reserved[2]; |
| 800 | } __packed; /* STA_CMD_API_S_VER_2 */ | 868 | } __packed; /* STA_CMD_API_S_VER_2 */ |
| 801 | 869 | ||
| 870 | /** | ||
| 871 | * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's | ||
| 872 | * station table | ||
| 873 | * ( STA_CONFIG_CMD = 0xA ) | ||
| 874 | * | ||
| 875 | * @sta_id: index of station in uCode's station table | ||
| 876 | * @link_mask: bitmap of link FW IDs used with this STA | ||
| 877 | * @peer_mld_address: the peers mld address | ||
| 878 | * @reserved_for_peer_mld_address: reserved | ||
| 879 | * @peer_link_address: the address of the link that is used to communicate | ||
| 880 | * with this sta | ||
| 881 | * @reserved_for_peer_link_address: reserved | ||
| 882 | * @station_type: type of this station. See &enum iwl_fw_sta_type | ||
| 883 | * @assoc_id: for GO only | ||
| 884 | * @beamform_flags: beam forming controls | ||
| 885 | * @mfp: indicates whether the STA uses management frame protection or not. | ||
| 886 | * @mimo: indicates whether the sta uses mimo or not | ||
| 887 | * @mimo_protection: indicates whether the sta uses mimo protection or not | ||
| 888 | * @ack_enabled: indicates that the AP supports receiving ACK- | ||
| 889 | * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG | ||
| 890 | * @trig_rnd_alloc: indicates that trigger based random allocation | ||
| 891 | * is enabled according to UORA element existence | ||
| 892 | * @tx_ampdu_spacing: minimum A-MPDU spacing: | ||
| 893 | * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density | ||
| 894 | * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K, | ||
| 895 | * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K. | ||
| 896 | * @sp_length: the size of the SP in actual number of frames | ||
| 897 | * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver | ||
| 898 | * enabled ACs. | ||
| 899 | * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY | ||
| 900 | * capa | ||
| 901 | * @htc_flags: which features are supported in HTC | ||
| 902 | * @use_ldpc_x2_cw: Indicates whether to use LDPC with double CW | ||
| 903 | * @use_icf: Indicates whether to use ICF instead of RTS | ||
| 904 | * @dps_pad_time: DPS (Dynamic Power Save) padding delay resolution to ensure | ||
| 905 | * proper timing alignment | ||
| 906 | * @dps_trans_delay: DPS minimal time that takes the peer to return to low power | ||
| 907 | * @dps_enabled: flag indicating whether or not DPS is enabled | ||
| 908 | * @mic_prep_pad_delay: MIC prep time padding | ||
| 909 | * @mic_compute_pad_delay: MIC compute time padding | ||
| 910 | * @nmi_sta_id: for an NDI peer STA, the NMI peer STA ID it relates to | ||
| 911 | * @ndi_local_addr: for an NDI peer STA, the local NDI interface MAC address | ||
| 912 | * @reserved: Reserved for alignment | ||
| 913 | */ | ||
| 914 | struct iwl_sta_cfg_cmd { | ||
| 915 | __le32 sta_id; | ||
| 916 | __le32 link_mask; | ||
| 917 | u8 peer_mld_address[ETH_ALEN]; | ||
| 918 | __le16 reserved_for_peer_mld_address; | ||
| 919 | u8 peer_link_address[ETH_ALEN]; | ||
| 920 | __le16 reserved_for_peer_link_address; | ||
| 921 | __le32 station_type; | ||
| 922 | __le32 assoc_id; | ||
| 923 | __le32 beamform_flags; | ||
| 924 | __le32 mfp; | ||
| 925 | __le32 mimo; | ||
| 926 | __le32 mimo_protection; | ||
| 927 | __le32 ack_enabled; | ||
| 928 | __le32 trig_rnd_alloc; | ||
| 929 | __le32 tx_ampdu_spacing; | ||
| 930 | __le32 tx_ampdu_max_size; | ||
| 931 | __le32 sp_length; | ||
| 932 | __le32 uapsd_acs; | ||
| 933 | struct iwl_he_pkt_ext_v2 pkt_ext; | ||
| 934 | __le32 htc_flags; | ||
| 935 | u8 use_ldpc_x2_cw; | ||
| 936 | u8 use_icf; | ||
| 937 | u8 dps_pad_time; | ||
| 938 | u8 dps_trans_delay; | ||
| 939 | u8 dps_enabled; | ||
| 940 | u8 mic_prep_pad_delay; | ||
| 941 | u8 mic_compute_pad_delay; | ||
| 942 | u8 nmi_sta_id; | ||
| 943 | u8 ndi_local_addr[ETH_ALEN]; | ||
| 944 | u8 reserved[2]; | ||
| 945 | } __packed; /* STA_CMD_API_S_VER_3 */ | ||
| 946 | |||
| 802 | /** | 947 | /** |
| 803 | * struct iwl_aux_sta_cmd - command for AUX STA configuration | 948 | * struct iwl_aux_sta_cmd - command for AUX STA configuration |
| 804 | * ( AUX_STA_CMD = 0xB ) | 949 | * ( AUX_STA_CMD = 0xB ) |
| @@ -57,8 +57,7 @@ enum iwl_mac_protection_flags { · 56 unmodified lines | |||
| 57 | * @FW_MAC_TYPE_P2P_DEVICE: P2P Device | 57 | * @FW_MAC_TYPE_P2P_DEVICE: P2P Device |
| 58 | * @FW_MAC_TYPE_P2P_STA: P2P client | 58 | * @FW_MAC_TYPE_P2P_STA: P2P client |
| 59 | * @FW_MAC_TYPE_GO: P2P GO | 59 | * @FW_MAC_TYPE_GO: P2P GO |
| 60 | * @FW_MAC_TYPE_TEST: ? | 60 | * @FW_MAC_TYPE_NAN: NAN (since version 4) |
| 61 | * @FW_MAC_TYPE_MAX: highest support MAC type | ||
| 62 | */ | 61 | */ |
| 63 | enum iwl_mac_types { | 62 | enum iwl_mac_types { |
| 64 | FW_MAC_TYPE_FIRST = 1, | 63 | FW_MAC_TYPE_FIRST = 1, |
| @@ -70,8 +69,7 @@ enum iwl_mac_types { · 5 unmodified lines | |||
| 70 | FW_MAC_TYPE_P2P_DEVICE, | 69 | FW_MAC_TYPE_P2P_DEVICE, |
| 71 | FW_MAC_TYPE_P2P_STA, | 70 | FW_MAC_TYPE_P2P_STA, |
| 72 | FW_MAC_TYPE_GO, | 71 | FW_MAC_TYPE_GO, |
| 73 | FW_MAC_TYPE_TEST, | 72 | FW_MAC_TYPE_NAN, |
| 74 | FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST | ||
| 75 | }; /* MAC_CONTEXT_TYPE_API_E_VER_1 */ | 73 | }; /* MAC_CONTEXT_TYPE_API_E_VER_1 */ |
| 76 | 74 | ||
| 77 | /** | 75 | /** |
| @@ -204,7 +204,7 @@ struct iwl_nvm_get_info_phy { · 203 unmodified lines | |||
| 204 | } __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ | 204 | } __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ |
| 205 | 205 | ||
| 206 | #define IWL_NUM_CHANNELS_V1 51 | 206 | #define IWL_NUM_CHANNELS_V1 51 |
| 207 | #define IWL_NUM_CHANNELS 110 | 207 | #define IWL_NUM_CHANNELS_V2 110 |
| 208 | 208 | ||
| 209 | /** | 209 | /** |
| 210 | * struct iwl_nvm_get_info_regulatory_v1 - regulatory information | 210 | * struct iwl_nvm_get_info_regulatory_v1 - regulatory information |
| @@ -227,7 +227,7 @@ struct iwl_nvm_get_info_regulatory_v1 { · 16 unmodified lines | |||
| 227 | struct iwl_nvm_get_info_regulatory { | 227 | struct iwl_nvm_get_info_regulatory { |
| 228 | __le32 lar_enabled; | 228 | __le32 lar_enabled; |
| 229 | __le32 n_channels; | 229 | __le32 n_channels; |
| 230 | __le32 channel_profile[IWL_NUM_CHANNELS]; | 230 | __le32 channel_profile[IWL_NUM_CHANNELS_V2]; |
| 231 | } __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_2 */ | 231 | } __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_2 */ |
| 232 | 232 | ||
| 233 | /** | 233 | /** |
| @@ -701,13 +701,23 @@ struct iwl_pnvm_init_complete_ntfy { · 467 unmodified lines | |||
| 701 | #define UATS_TABLE_COL_SIZE 13 | 701 | #define UATS_TABLE_COL_SIZE 13 |
| 702 | 702 | ||
| 703 | /** | 703 | /** |
| 704 | * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD | 704 | * struct iwl_mcc_allowed_ap_type_cmd_v1 - struct for MCC_ALLOWED_AP_TYPE_CMD |
| 705 | * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) | 705 | * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) |
| 706 | * @reserved: reserved | 706 | * @reserved: reserved |
| 707 | */ | 707 | */ |
| 708 | struct iwl_mcc_allowed_ap_type_cmd { | 708 | struct iwl_mcc_allowed_ap_type_cmd_v1 { |
| 709 | u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; | 709 | u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; |
| 710 | __le16 reserved; | 710 | __le16 reserved; |
| 711 | } __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */ | 711 | } __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */ |
| 712 | 712 | ||
| 713 | /** | ||
| 714 | * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD | ||
| 715 | * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) | ||
| 716 | * @mcc_to_ap_type_unii9_map: mapping an MCC to UNII-9 AP type support allowed | ||
| 717 | */ | ||
| 718 | struct iwl_mcc_allowed_ap_type_cmd { | ||
| 719 | u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; | ||
| 720 | u8 mcc_to_ap_type_unii9_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; | ||
| 721 | } __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_2 */ | ||
| 722 | |||
| 713 | #endif /* __iwl_fw_api_nvm_reg_h__ */ | 723 | #endif /* __iwl_fw_api_nvm_reg_h__ */ |
| @@ -269,6 +269,7 @@ enum iwl_dev_tx_power_cmd_mode { · 268 unmodified lines | |||
| 269 | #define IWL_NUM_CHAIN_LIMITS 2 | 269 | #define IWL_NUM_CHAIN_LIMITS 2 |
| 270 | #define IWL_NUM_SUB_BANDS_V1 5 | 270 | #define IWL_NUM_SUB_BANDS_V1 5 |
| 271 | #define IWL_NUM_SUB_BANDS_V2 11 | 271 | #define IWL_NUM_SUB_BANDS_V2 11 |
| 272 | #define IWL_NUM_SUB_BANDS_V3 12 | ||
| 272 | 273 | ||
| 273 | /** | 274 | /** |
| 274 | * struct iwl_dev_tx_power_common - Common part of the TX power reduction cmd | 275 | * struct iwl_dev_tx_power_common - Common part of the TX power reduction cmd |
| @@ -425,24 +426,38 @@ struct iwl_dev_tx_power_cmd_v10 { · 150 unmodified lines | |||
| 425 | __le32 flags; | 426 | __le32 flags; |
| 426 | } __packed; /* TX_REDUCED_POWER_API_S_VER_10 */ | 427 | } __packed; /* TX_REDUCED_POWER_API_S_VER_10 */ |
| 427 | 428 | ||
| 429 | struct iwl_dev_tx_power_cmd_v11 { | ||
| 430 | __le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3]; | ||
| 431 | u8 per_chain_restriction_changed; | ||
| 432 | u8 reserved; | ||
| 433 | __le32 timer_period; | ||
| 434 | __le32 flags; | ||
| 435 | } __packed; /* TX_REDUCED_POWER_API_S_VER_11 */ | ||
| 436 | |||
| 428 | /* | 437 | /* |
| 429 | * struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion) | 438 | * struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion) |
| 430 | * @common: common part of the command | 439 | * @common: common part of the command |
| 431 | * @v9: version 9 part of the command | 440 | * @v9: version 9 part of the command |
| 432 | * @v10: version 10 part of the command | 441 | * @v10: version 10 part of the command |
| 442 | * @v11: version 11 part of the command | ||
| 433 | */ | 443 | */ |
| 434 | struct iwl_dev_tx_power_cmd { | 444 | struct iwl_dev_tx_power_cmd { |
| 435 | struct iwl_dev_tx_power_common common; | 445 | struct iwl_dev_tx_power_common common; |
| 436 | union { | 446 | union { |
| 437 | struct iwl_dev_tx_power_cmd_v9 v9; | 447 | struct iwl_dev_tx_power_cmd_v9 v9; |
| 438 | struct iwl_dev_tx_power_cmd_v10 v10; | 448 | struct iwl_dev_tx_power_cmd_v10 v10; |
| 449 | struct iwl_dev_tx_power_cmd_v11 v11; | ||
| 439 | }; | 450 | }; |
| 440 | } __packed; /* TX_REDUCED_POWER_API_S_VER_9_VER10 */ | 451 | } __packed; /* TX_REDUCED_POWER_API_S_VER_9 |
| 452 | * TX_REDUCED_POWER_API_S_VER_10 | ||
| 453 | * TX_REDUCED_POWER_API_S_VER_11 | ||
| 454 | */ | ||
| 441 | 455 | ||
| 442 | #define IWL_NUM_GEO_PROFILES 3 | 456 | #define IWL_NUM_GEO_PROFILES 3 |
| 443 | #define IWL_NUM_GEO_PROFILES_V3 8 | 457 | #define IWL_NUM_GEO_PROFILES_V3 8 |
| 444 | #define IWL_NUM_BANDS_PER_CHAIN_V1 2 | 458 | #define IWL_NUM_BANDS_PER_CHAIN_V1 2 |
| 445 | #define IWL_NUM_BANDS_PER_CHAIN_V2 3 | 459 | #define IWL_NUM_BANDS_PER_CHAIN_V2 3 |
| 460 | #define IWL_NUM_BANDS_PER_CHAIN_V6 4 | ||
| 446 | 461 | ||
| 447 | /** | 462 | /** |
| 448 | * enum iwl_geo_per_chain_offset_operation - type of operation | 463 | * enum iwl_geo_per_chain_offset_operation - type of operation |
| @@ -524,12 +539,25 @@ struct iwl_geo_tx_power_profiles_cmd_v5 { · 75 unmodified lines | |||
| 524 | __le32 table_revision; | 539 | __le32 table_revision; |
| 525 | } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_5 */ | 540 | } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_5 */ |
| 526 | 541 | ||
| 542 | /** | ||
| 543 | * struct iwl_geo_tx_power_profiles_cmd_v6 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. | ||
| 544 | * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation | ||
| 545 | * @table: offset profile per band. | ||
| 546 | * @bios_hdr: describes the revision and the source of the BIOS | ||
| 547 | */ | ||
| 548 | struct iwl_geo_tx_power_profiles_cmd_v6 { | ||
| 549 | __le32 ops; | ||
| 550 | struct iwl_per_chain_offset table[IWL_NUM_GEO_PROFILES_V3][IWL_NUM_BANDS_PER_CHAIN_V6]; | ||
| 551 | struct iwl_bios_config_hdr bios_hdr; | ||
| 552 | } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_6 */ | ||
| 553 | |||
| 527 | union iwl_geo_tx_power_profiles_cmd { | 554 | union iwl_geo_tx_power_profiles_cmd { |
| 528 | struct iwl_geo_tx_power_profiles_cmd_v1 v1; | 555 | struct iwl_geo_tx_power_profiles_cmd_v1 v1; |
| 529 | struct iwl_geo_tx_power_profiles_cmd_v2 v2; | 556 | struct iwl_geo_tx_power_profiles_cmd_v2 v2; |
| 530 | struct iwl_geo_tx_power_profiles_cmd_v3 v3; | 557 | struct iwl_geo_tx_power_profiles_cmd_v3 v3; |
| 531 | struct iwl_geo_tx_power_profiles_cmd_v4 v4; | 558 | struct iwl_geo_tx_power_profiles_cmd_v4 v4; |
| 532 | struct iwl_geo_tx_power_profiles_cmd_v5 v5; | 559 | struct iwl_geo_tx_power_profiles_cmd_v5 v5; |
| 560 | struct iwl_geo_tx_power_profiles_cmd_v6 v6; | ||
| 533 | }; | 561 | }; |
| 534 | 562 | ||
| 535 | /** | 563 | /** |
| @@ -573,6 +601,7 @@ enum iwl_ppag_flags { · 37 unmodified lines | |||
| 573 | * @v1: command version 1 structure. | 601 | * @v1: command version 1 structure. |
| 574 | * @v5: command version 5 structure. | 602 | * @v5: command version 5 structure. |
| 575 | * @v7: command version 7 structure. | 603 | * @v7: command version 7 structure. |
| 604 | * @v8: command version 8 structure. | ||
| 576 | * @v1.flags: values from &enum iwl_ppag_flags | 605 | * @v1.flags: values from &enum iwl_ppag_flags |
| 577 | * @v1.gain: table of antenna gain values per chain and sub-band | 606 | * @v1.gain: table of antenna gain values per chain and sub-band |
| 578 | * @v1.reserved: reserved | 607 | * @v1.reserved: reserved |
| @@ -581,6 +610,8 @@ enum iwl_ppag_flags { · 2 unmodified lines | |||
| 581 | * @v7.ppag_config_info: see @struct bios_value_u32 | 610 | * @v7.ppag_config_info: see @struct bios_value_u32 |
| 582 | * @v7.gain: table of antenna gain values per chain and sub-band | 611 | * @v7.gain: table of antenna gain values per chain and sub-band |
| 583 | * @v7.reserved: reserved | 612 | * @v7.reserved: reserved |
| 613 | * @v8.ppag_config_info: see @struct bios_value_u32 | ||
| 614 | * @v8.gain: table of antenna gain values per chain and sub-band | ||
| 584 | */ | 615 | */ |
| 585 | union iwl_ppag_table_cmd { | 616 | union iwl_ppag_table_cmd { |
| 586 | struct { | 617 | struct { |
| @@ -598,6 +629,10 @@ union iwl_ppag_table_cmd { · 11 unmodified lines | |||
| 598 | s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; | 629 | s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; |
| 599 | s8 reserved[2]; | 630 | s8 reserved[2]; |
| 600 | } __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ | 631 | } __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ |
| 632 | struct { | ||
| 633 | struct bios_value_u32 ppag_config_info; | ||
| 634 | s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3]; | ||
| 635 | } __packed v8; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_8 */ | ||
| 601 | } __packed; | 636 | } __packed; |
| 602 | 637 | ||
| 603 | #define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) | 638 | #define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) |
| @@ -985,6 +985,7 @@ struct iwl_scan_probe_params_v4 { · 984 unmodified lines | |||
| 985 | } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ | 985 | } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ |
| 986 | 986 | ||
| 987 | #define SCAN_MAX_NUM_CHANS_V3 67 | 987 | #define SCAN_MAX_NUM_CHANS_V3 67 |
| 988 | #define SCAN_MAX_NUM_CHANS_V4 68 | ||
| 988 | 989 | ||
| 989 | /** | 990 | /** |
| 990 | * struct iwl_scan_channel_params_v4 - channel params | 991 | * struct iwl_scan_channel_params_v4 - channel params |
| @@ -1027,6 +1028,24 @@ struct iwl_scan_channel_params_v7 { · 36 unmodified lines | |||
| 1027 | struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; | 1028 | struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; |
| 1028 | } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ | 1029 | } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */ |
| 1029 | 1030 | ||
| 1031 | /** | ||
| 1032 | * struct iwl_scan_channel_params_v8 - channel params | ||
| 1033 | * @flags: channel flags &enum iwl_scan_channel_flags | ||
| 1034 | * @count: num of channels in scan request | ||
| 1035 | * @n_aps_override: override the number of APs the FW uses to calculate dwell | ||
| 1036 | * time when adaptive dwell is used. | ||
| 1037 | * Channel k will use n_aps_override[i] when BIT(20 + i) is set in | ||
| 1038 | * channel_config[k].flags | ||
| 1039 | * @channel_config: array of explicit channel configurations | ||
| 1040 | * for 2.4Ghz and 5.2Ghz bands | ||
| 1041 | */ | ||
| 1042 | struct iwl_scan_channel_params_v8 { | ||
| 1043 | u8 flags; | ||
| 1044 | u8 count; | ||
| 1045 | u8 n_aps_override[2]; | ||
| 1046 | struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V4]; | ||
| 1047 | } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_8 */ | ||
| 1048 | |||
| 1030 | /** | 1049 | /** |
| 1031 | * struct iwl_scan_general_params_v11 - channel params | 1050 | * struct iwl_scan_general_params_v11 - channel params |
| 1032 | * @flags: &enum iwl_umac_scan_general_flags_v2 | 1051 | * @flags: &enum iwl_umac_scan_general_flags_v2 |
| @@ -1109,6 +1128,20 @@ struct iwl_scan_req_params_v17 { · 76 unmodified lines | |||
| 1109 | struct iwl_scan_probe_params_v4 probe_params; | 1128 | struct iwl_scan_probe_params_v4 probe_params; |
| 1110 | } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */ | 1129 | } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */ |
| 1111 | 1130 | ||
| 1131 | /** | ||
| 1132 | * struct iwl_scan_req_params_v18 - scan request parameters (v18) | ||
| 1133 | * @general_params: &struct iwl_scan_general_params_v11 | ||
| 1134 | * @channel_params: &struct iwl_scan_channel_params_v8 | ||
| 1135 | * @periodic_params: &struct iwl_scan_periodic_parms_v1 | ||
| 1136 | * @probe_params: &struct iwl_scan_probe_params_v4 | ||
| 1137 | */ | ||
| 1138 | struct iwl_scan_req_params_v18 { | ||
| 1139 | struct iwl_scan_general_params_v11 general_params; | ||
| 1140 | struct iwl_scan_channel_params_v8 channel_params; | ||
| 1141 | struct iwl_scan_periodic_parms_v1 periodic_params; | ||
| 1142 | struct iwl_scan_probe_params_v4 probe_params; | ||
| 1143 | } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_18 */ | ||
| 1144 | |||
| 1112 | /** | 1145 | /** |
| 1113 | * struct iwl_scan_req_umac_v12 - scan request command (v12) | 1146 | * struct iwl_scan_req_umac_v12 - scan request command (v12) |
| 1114 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | 1147 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets |
| @@ -1133,6 +1166,18 @@ struct iwl_scan_req_umac_v17 { · 18 unmodified lines | |||
| 1133 | struct iwl_scan_req_params_v17 scan_params; | 1166 | struct iwl_scan_req_params_v17 scan_params; |
| 1134 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */ | 1167 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */ |
| 1135 | 1168 | ||
| 1169 | /** | ||
| 1170 | * struct iwl_scan_req_umac_v18 - scan request command (v18) | ||
| 1171 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
| 1172 | * @ooc_priority: out of channel priority - &enum iwl_scan_priority | ||
| 1173 | * @scan_params: scan parameters | ||
| 1174 | */ | ||
| 1175 | struct iwl_scan_req_umac_v18 { | ||
| 1176 | __le32 uid; | ||
| 1177 | __le32 ooc_priority; | ||
| 1178 | struct iwl_scan_req_params_v18 scan_params; | ||
| 1179 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_18 */ | ||
| 1180 | |||
| 1136 | /** | 1181 | /** |
| 1137 | * struct iwl_umac_scan_abort - scan abort command | 1182 | * struct iwl_umac_scan_abort - scan abort command |
| 1138 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | 1183 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets |
| @@ -598,7 +598,6 @@ struct iwl_stats_ntfy_per_sta { · 597 unmodified lines | |||
| 598 | } __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ | 598 | } __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ |
| 599 | 599 | ||
| 600 | #define IWL_STATS_MAX_PHY_OPERATIONAL 3 | 600 | #define IWL_STATS_MAX_PHY_OPERATIONAL 3 |
| 601 | #define IWL_STATS_MAX_FW_LINKS (IWL_FW_MAX_LINK_ID + 1) | ||
| 602 | 601 | ||
| 603 | /** | 602 | /** |
| 604 | * struct iwl_system_statistics_notif_oper - statistics notification | 603 | * struct iwl_system_statistics_notif_oper - statistics notification |
| @@ -610,7 +609,7 @@ struct iwl_stats_ntfy_per_sta { · 5 unmodified lines | |||
| 610 | */ | 609 | */ |
| 611 | struct iwl_system_statistics_notif_oper { | 610 | struct iwl_system_statistics_notif_oper { |
| 612 | __le32 time_stamp; | 611 | __le32 time_stamp; |
| 613 | struct iwl_stats_ntfy_per_link per_link[IWL_STATS_MAX_FW_LINKS]; | 612 | struct iwl_stats_ntfy_per_link per_link[IWL_FW_MAX_LINKS]; |
| 614 | struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; | 613 | struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; |
| 615 | struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; | 614 | struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; |
| 616 | } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */ | 615 | } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */ |
| @@ -624,7 +623,7 @@ struct iwl_system_statistics_notif_oper { · 7 unmodified lines | |||
| 624 | */ | 623 | */ |
| 625 | struct iwl_system_statistics_part1_notif_oper { | 624 | struct iwl_system_statistics_part1_notif_oper { |
| 626 | __le32 time_stamp; | 625 | __le32 time_stamp; |
| 627 | struct iwl_stats_ntfy_part1_per_link per_link[IWL_STATS_MAX_FW_LINKS]; | 626 | struct iwl_stats_ntfy_part1_per_link per_link[IWL_FW_MAX_LINKS]; |
| 628 | __le32 per_phy_crc_error_stats[IWL_STATS_MAX_PHY_OPERATIONAL]; | 627 | __le32 per_phy_crc_error_stats[IWL_STATS_MAX_PHY_OPERATIONAL]; |
| 629 | } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */ | 628 | } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */ |
| 630 | 629 | ||
| @@ -2933,7 +2933,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, · 2932 unmodified lines | |||
| 2933 | IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", | 2933 | IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", |
| 2934 | le32_to_cpu(desc->trig_desc.type)); | 2934 | le32_to_cpu(desc->trig_desc.type)); |
| 2935 | 2935 | ||
| 2936 | queue_delayed_work(system_unbound_wq, &wk_data->wk, | 2936 | queue_delayed_work(system_dfl_wq, &wk_data->wk, |
| 2937 | usecs_to_jiffies(delay)); | 2937 | usecs_to_jiffies(delay)); |
| 2938 | 2938 | ||
| 2939 | return 0; | 2939 | return 0; |
| @@ -3236,7 +3236,7 @@ int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, · 296 unmodified lines | |||
| 3236 | if (sync) | 3236 | if (sync) |
| 3237 | iwl_fw_dbg_collect_sync(fwrt, idx); | 3237 | iwl_fw_dbg_collect_sync(fwrt, idx); |
| 3238 | else | 3238 | else |
| 3239 | queue_delayed_work(system_unbound_wq, | 3239 | queue_delayed_work(system_dfl_wq, |
| 3240 | &fwrt->dump.wks[idx].wk, | 3240 | &fwrt->dump.wks[idx].wk, |
| 3241 | usecs_to_jiffies(delay)); | 3241 | usecs_to_jiffies(delay)); |
| 3242 | 3242 | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2012-2014, 2018-2025 Intel Corporation | 3 | * Copyright (C) 2012-2014, 2018-2026 Intel Corporation |
| 4 | * Copyright (C) 2013-2014 Intel Mobile Communications GmbH | 4 | * Copyright (C) 2013-2014 Intel Mobile Communications GmbH |
| 5 | * Copyright (C) 2015-2017 Intel Deutschland GmbH | 5 | * Copyright (C) 2015-2017 Intel Deutschland GmbH |
| 6 | */ | 6 | */ |
| @@ -128,19 +128,11 @@ static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) · 121 unmodified lines | |||
| 128 | 128 | ||
| 129 | IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, | 129 | IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, |
| 130 | iwl_fw_lookup_assert_desc(table.error_id)); | 130 | iwl_fw_lookup_assert_desc(table.error_id)); |
| 131 | IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1); | ||
| 132 | IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2); | ||
| 133 | IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1); | ||
| 134 | IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); | 131 | IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); |
| 135 | IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); | 132 | IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); |
| 136 | IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); | 133 | IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); |
| 137 | IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3); | 134 | IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3); |
| 138 | IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major); | ||
| 139 | IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor); | ||
| 140 | IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer); | ||
| 141 | IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer); | ||
| 142 | IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header); | 135 | IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header); |
| 143 | IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref); | ||
| 144 | } | 136 | } |
| 145 | 137 | ||
| 146 | static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num) | 138 | static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num) |
| @@ -200,39 +192,10 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu · 53 unmodified lines | |||
| 200 | 192 | ||
| 201 | IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, | 193 | IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, |
| 202 | iwl_fw_lookup_assert_desc(table.error_id)); | 194 | iwl_fw_lookup_assert_desc(table.error_id)); |
| 203 | IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); | ||
| 204 | IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); | ||
| 205 | IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2); | ||
| 206 | IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1); | ||
| 207 | IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); | 195 | IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); |
| 208 | IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); | 196 | IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); |
| 209 | IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); | 197 | IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); |
| 210 | IWL_ERR(fwrt, "0x%08X | data3\n", table.data3); | 198 | IWL_ERR(fwrt, "0x%08X | data3\n", table.data3); |
| 211 | IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time); | ||
| 212 | IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low); | ||
| 213 | IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi); | ||
| 214 | IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1); | ||
| 215 | IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2); | ||
| 216 | IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type); | ||
| 217 | IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major); | ||
| 218 | IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor); | ||
| 219 | IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver); | ||
| 220 | IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver); | ||
| 221 | IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd); | ||
| 222 | IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0); | ||
| 223 | IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1); | ||
| 224 | IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2); | ||
| 225 | IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3); | ||
| 226 | IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4); | ||
| 227 | IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id); | ||
| 228 | IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event); | ||
| 229 | IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control); | ||
| 230 | IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration); | ||
| 231 | IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); | ||
| 232 | IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); | ||
| 233 | IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); | ||
| 234 | IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp); | ||
| 235 | IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler); | ||
| 236 | } | 199 | } |
| 237 | 200 | ||
| 238 | /* | 201 | /* |
| @@ -264,7 +227,6 @@ static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx) · 25 unmodified lines | |||
| 264 | struct iwl_trans *trans = fwrt->trans; | 227 | struct iwl_trans *trans = fwrt->trans; |
| 265 | struct iwl_tcm_error_event_table table = {}; | 228 | struct iwl_tcm_error_event_table table = {}; |
| 266 | u32 base = fwrt->trans->dbg.tcm_error_event_table[idx]; | 229 | u32 base = fwrt->trans->dbg.tcm_error_event_table[idx]; |
| 267 | int i; | ||
| 268 | u32 flag = idx ? IWL_ERROR_EVENT_TABLE_TCM2 : | 230 | u32 flag = idx ? IWL_ERROR_EVENT_TABLE_TCM2 : |
| 269 | IWL_ERROR_EVENT_TABLE_TCM1; | 231 | IWL_ERROR_EVENT_TABLE_TCM1; |
| 270 | 232 | ||
| @@ -275,23 +237,10 @@ static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx) · 4 unmodified lines | |||
| 275 | 237 | ||
| 276 | IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); | 238 | IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); |
| 277 | IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); | 239 | IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); |
| 278 | IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2); | ||
| 279 | IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1); | ||
| 280 | IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); | 240 | IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); |
| 281 | IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); | 241 | IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); |
| 282 | IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); | 242 | IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); |
| 283 | IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3); | 243 | IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3); |
| 284 | IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc); | ||
| 285 | IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer); | ||
| 286 | IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer); | ||
| 287 | IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid); | ||
| 288 | IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr); | ||
| 289 | for (i = 0; i < ARRAY_SIZE(table.hw_status); i++) | ||
| 290 | IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n", | ||
| 291 | table.hw_status[i], i); | ||
| 292 | for (i = 0; i < ARRAY_SIZE(table.sw_status); i++) | ||
| 293 | IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n", | ||
| 294 | table.sw_status[i], i); | ||
| 295 | } | 244 | } |
| 296 | 245 | ||
| 297 | /* | 246 | /* |
| @@ -338,26 +287,10 @@ static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx) · 40 unmodified lines | |||
| 338 | 287 | ||
| 339 | IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); | 288 | IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); |
| 340 | IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); | 289 | IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); |
| 341 | IWL_ERR(fwrt, "0x%08X | rcm branchlink2\n", table.blink2); | ||
| 342 | IWL_ERR(fwrt, "0x%08X | rcm interruptlink1\n", table.ilink1); | ||
| 343 | IWL_ERR(fwrt, "0x%08X | rcm interruptlink2\n", table.ilink2); | 290 | IWL_ERR(fwrt, "0x%08X | rcm interruptlink2\n", table.ilink2); |
| 344 | IWL_ERR(fwrt, "0x%08X | rcm data1\n", table.data1); | 291 | IWL_ERR(fwrt, "0x%08X | rcm data1\n", table.data1); |
| 345 | IWL_ERR(fwrt, "0x%08X | rcm data2\n", table.data2); | 292 | IWL_ERR(fwrt, "0x%08X | rcm data2\n", table.data2); |
| 346 | IWL_ERR(fwrt, "0x%08X | rcm data3\n", table.data3); | 293 | IWL_ERR(fwrt, "0x%08X | rcm data3\n", table.data3); |
| 347 | IWL_ERR(fwrt, "0x%08X | rcm log PC\n", table.logpc); | ||
| 348 | IWL_ERR(fwrt, "0x%08X | rcm frame pointer\n", table.frame_pointer); | ||
| 349 | IWL_ERR(fwrt, "0x%08X | rcm stack pointer\n", table.stack_pointer); | ||
| 350 | IWL_ERR(fwrt, "0x%08X | rcm msg ID\n", table.msgid); | ||
| 351 | IWL_ERR(fwrt, "0x%08X | rcm ISR status\n", table.isr); | ||
| 352 | IWL_ERR(fwrt, "0x%08X | frame HW status\n", table.frame_hw_status); | ||
| 353 | IWL_ERR(fwrt, "0x%08X | LMAC-to-RCM request mbox\n", | ||
| 354 | table.mbx_lmac_to_rcm_req); | ||
| 355 | IWL_ERR(fwrt, "0x%08X | RCM-to-LMAC request mbox\n", | ||
| 356 | table.mbx_rcm_to_lmac_req); | ||
| 357 | IWL_ERR(fwrt, "0x%08X | MAC header control\n", table.mh_ctl); | ||
| 358 | IWL_ERR(fwrt, "0x%08X | MAC header addr1 low\n", table.mh_addr1_lo); | ||
| 359 | IWL_ERR(fwrt, "0x%08X | MAC header info\n", table.mh_info); | ||
| 360 | IWL_ERR(fwrt, "0x%08X | MAC header error\n", table.mh_err); | ||
| 361 | } | 294 | } |
| 362 | 295 | ||
| 363 | static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) | 296 | static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) |
| @@ -103,6 +103,7 @@ enum iwl_ucode_tlv_type { · 102 unmodified lines | |||
| 103 | IWL_UCODE_TLV_D3_KEK_KCK_ADDR = 67, | 103 | IWL_UCODE_TLV_D3_KEK_KCK_ADDR = 67, |
| 104 | IWL_UCODE_TLV_CURRENT_PC = 68, | 104 | IWL_UCODE_TLV_CURRENT_PC = 68, |
| 105 | IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72, | 105 | IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72, |
| 106 | IWL_UCODE_TLV_CMD_BIOS_TABLE = 73, | ||
| 106 | 107 | ||
| 107 | /* contains sub-sections like PNVM file does (did) */ | 108 | /* contains sub-sections like PNVM file does (did) */ |
| 108 | IWL_UCODE_TLV_PNVM_DATA = 74, | 109 | IWL_UCODE_TLV_PNVM_DATA = 74, |
| @@ -1040,6 +1041,20 @@ struct iwl_fw_cmd_version { · 931 unmodified lines | |||
| 1040 | u8 notif_ver; | 1041 | u8 notif_ver; |
| 1041 | } __packed; | 1042 | } __packed; |
| 1042 | 1043 | ||
| 1044 | /** | ||
| 1045 | * struct iwl_fw_cmd_bios_table - firmware command BIOS revision entry | ||
| 1046 | * @cmd: command ID | ||
| 1047 | * @group: group ID | ||
| 1048 | * @max_acpi_revision: max supported ACPI revision of command. | ||
| 1049 | * @max_uefi_revision: max supported UEFI revision of command. | ||
| 1050 | */ | ||
| 1051 | struct iwl_fw_cmd_bios_table { | ||
| 1052 | u8 cmd; | ||
| 1053 | u8 group; | ||
| 1054 | u8 max_acpi_revision; | ||
| 1055 | u8 max_uefi_revision; | ||
| 1056 | } __packed; | ||
| 1057 | |||
| 1043 | struct iwl_fw_tcm_error_addr { | 1058 | struct iwl_fw_tcm_error_addr { |
| 1044 | __le32 addr; | 1059 | __le32 addr; |
| 1045 | }; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */ | 1060 | }; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */ |
| @@ -1,11 +1,41 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | /* | 2 | /* |
| 3 | * Copyright(c) 2019 - 2021 Intel Corporation | 3 | * Copyright(c) 2019 - 2021 Intel Corporation |
| 4 | * Copyright(c) 2024 Intel Corporation | 4 | * Copyright(c) 2024 - 2025 Intel Corporation |
| 5 | */ | 5 | */ |
| 6 | #include <fw/api/commands.h> | 6 | #include <fw/api/commands.h> |
| 7 | #include "img.h" | 7 | #include "img.h" |
| 8 | 8 | ||
| 9 | u8 iwl_fw_lookup_cmd_bios_supported_revision(const struct iwl_fw *fw, | ||
| 10 | enum bios_source table_source, | ||
| 11 | u32 cmd_id, u8 def) | ||
| 12 | { | ||
| 13 | const struct iwl_fw_cmd_bios_table *entry; | ||
| 14 | /* prior to LONG_GROUP, we never used this CMD version API */ | ||
| 15 | u8 grp = iwl_cmd_groupid(cmd_id) ?: LONG_GROUP; | ||
| 16 | u8 cmd = iwl_cmd_opcode(cmd_id); | ||
| 17 | |||
| 18 | if (table_source != BIOS_SOURCE_ACPI && | ||
| 19 | table_source != BIOS_SOURCE_UEFI) | ||
| 20 | return def; | ||
| 21 | |||
| 22 | if (!fw->ucode_capa.cmd_bios_tables || | ||
| 23 | !fw->ucode_capa.n_cmd_bios_tables) | ||
| 24 | return def; | ||
| 25 | |||
| 26 | entry = fw->ucode_capa.cmd_bios_tables; | ||
| 27 | for (int i = 0; i < fw->ucode_capa.n_cmd_bios_tables; i++, entry++) { | ||
| 28 | if (entry->group == grp && entry->cmd == cmd) { | ||
| 29 | if (table_source == BIOS_SOURCE_ACPI) | ||
| 30 | return entry->max_acpi_revision; | ||
| 31 | return entry->max_uefi_revision; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | return def; | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL_GPL(iwl_fw_lookup_cmd_bios_supported_revision); | ||
| 38 | |||
| 9 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def) | 39 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def) |
| 10 | { | 40 | { |
| 11 | const struct iwl_fw_cmd_version *entry; | 41 | const struct iwl_fw_cmd_version *entry; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 10 | 10 | ||
| 11 | #include "api/dbg-tlv.h" | 11 | #include "api/dbg-tlv.h" |
| 12 | #include "api/nvm-reg.h" | ||
| 12 | 13 | ||
| 13 | #include "file.h" | 14 | #include "file.h" |
| 14 | #include "error-dump.h" | 15 | #include "error-dump.h" |
| @@ -57,6 +58,9 @@ struct iwl_ucode_capabilities { · 42 unmodified lines | |||
| 57 | 58 | ||
| 58 | const struct iwl_fw_cmd_version *cmd_versions; | 59 | const struct iwl_fw_cmd_version *cmd_versions; |
| 59 | u32 n_cmd_versions; | 60 | u32 n_cmd_versions; |
| 61 | |||
| 62 | const struct iwl_fw_cmd_bios_table *cmd_bios_tables; | ||
| 63 | u32 n_cmd_bios_tables; | ||
| 60 | }; | 64 | }; |
| 61 | 65 | ||
| 62 | static inline bool | 66 | static inline bool |
| @@ -274,6 +278,10 @@ iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type) · 211 unmodified lines | |||
| 274 | return &fw->img[ucode_type]; | 278 | return &fw->img[ucode_type]; |
| 275 | } | 279 | } |
| 276 | 280 | ||
| 281 | u8 iwl_fw_lookup_cmd_bios_supported_revision(const struct iwl_fw *fw, | ||
| 282 | enum bios_source table_source, | ||
| 283 | u32 cmd_id, u8 def); | ||
| 284 | |||
| 277 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def); | 285 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def); |
| 278 | 286 | ||
| 279 | u8 iwl_fw_lookup_notif_ver(const struct iwl_fw *fw, u8 grp, u8 cmd, u8 def); | 287 | u8 iwl_fw_lookup_notif_ver(const struct iwl_fw *fw, u8 grp, u8 cmd, u8 def); |
| @@ -241,6 +241,10 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, · 240 unmodified lines | |||
| 241 | int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; | 241 | int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; |
| 242 | int i, j; | 242 | int i, j; |
| 243 | 243 | ||
| 244 | if (WARN_ON_ONCE(n_subbands > | ||
| 245 | ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) | ||
| 246 | return -EINVAL; | ||
| 247 | |||
| 244 | for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { | 248 | for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { |
| 245 | struct iwl_sar_profile *prof; | 249 | struct iwl_sar_profile *prof; |
| 246 | 250 | ||
| @@ -300,132 +304,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, · 53 unmodified lines | |||
| 300 | } | 304 | } |
| 301 | IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); | 305 | IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); |
| 302 | 306 | ||
| 303 | static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, | ||
| 304 | int subband) | ||
| 305 | { | ||
| 306 | s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband]; | ||
| 307 | |||
| 308 | if ((subband == 0 && | ||
| 309 | (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) || | ||
| 310 | (subband != 0 && | ||
| 311 | (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) { | ||
| 312 | IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val); | ||
| 313 | return false; | ||
| 314 | } | ||
| 315 | return true; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* Utility function for iwlmvm and iwlxvt */ | ||
| 319 | int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, | ||
| 320 | union iwl_ppag_table_cmd *cmd, int *cmd_size) | ||
| 321 | { | ||
| 322 | u8 cmd_ver; | ||
| 323 | int i, j, num_sub_bands; | ||
| 324 | s8 *gain; | ||
| 325 | bool send_ppag_always; | ||
| 326 | |||
| 327 | /* many firmware images for JF lie about this */ | ||
| 328 | if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) == | ||
| 329 | CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) | ||
| 330 | return -EOPNOTSUPP; | ||
| 331 | |||
| 332 | if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { | ||
| 333 | IWL_DEBUG_RADIO(fwrt, | ||
| 334 | "PPAG capability not supported by FW, command not sent.\n"); | ||
| 335 | return -EINVAL; | ||
| 336 | } | ||
| 337 | |||
| 338 | cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, | ||
| 339 | WIDE_ID(PHY_OPS_GROUP, | ||
| 340 | PER_PLATFORM_ANT_GAIN_CMD), 1); | ||
| 341 | /* | ||
| 342 | * Starting from ver 4, driver needs to send the PPAG CMD regardless | ||
| 343 | * if PPAG is enabled/disabled or valid/invalid. | ||
| 344 | */ | ||
| 345 | send_ppag_always = cmd_ver > 3; | ||
| 346 | |||
| 347 | /* Don't send PPAG if it is disabled */ | ||
| 348 | if (!send_ppag_always && !fwrt->ppag_flags) { | ||
| 349 | IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); | ||
| 350 | return -EINVAL; | ||
| 351 | } | ||
| 352 | |||
| 353 | IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); | ||
| 354 | if (cmd_ver == 1) { | ||
| 355 | num_sub_bands = IWL_NUM_SUB_BANDS_V1; | ||
| 356 | gain = cmd->v1.gain[0]; | ||
| 357 | *cmd_size = sizeof(cmd->v1); | ||
| 358 | cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK); | ||
| 359 | if (fwrt->ppag_bios_rev >= 1) { | ||
| 360 | /* in this case FW supports revision 0 */ | ||
| 361 | IWL_DEBUG_RADIO(fwrt, | ||
| 362 | "PPAG table rev is %d, send truncated table\n", | ||
| 363 | fwrt->ppag_bios_rev); | ||
| 364 | } | ||
| 365 | } else if (cmd_ver == 5) { | ||
| 366 | num_sub_bands = IWL_NUM_SUB_BANDS_V2; | ||
| 367 | gain = cmd->v5.gain[0]; | ||
| 368 | *cmd_size = sizeof(cmd->v5); | ||
| 369 | cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK); | ||
| 370 | if (fwrt->ppag_bios_rev == 0) { | ||
| 371 | /* in this case FW supports revisions 1,2 or 3 */ | ||
| 372 | IWL_DEBUG_RADIO(fwrt, | ||
| 373 | "PPAG table rev is 0, send padded table\n"); | ||
| 374 | } | ||
| 375 | } else if (cmd_ver == 7) { | ||
| 376 | num_sub_bands = IWL_NUM_SUB_BANDS_V2; | ||
| 377 | gain = cmd->v7.gain[0]; | ||
| 378 | *cmd_size = sizeof(cmd->v7); | ||
| 379 | cmd->v7.ppag_config_info.hdr.table_source = | ||
| 380 | fwrt->ppag_bios_source; | ||
| 381 | cmd->v7.ppag_config_info.hdr.table_revision = | ||
| 382 | fwrt->ppag_bios_rev; | ||
| 383 | cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); | ||
| 384 | } else { | ||
| 385 | IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); | ||
| 386 | return -EINVAL; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* ppag mode */ | ||
| 390 | IWL_DEBUG_RADIO(fwrt, | ||
| 391 | "PPAG MODE bits were read from bios: %d\n", | ||
| 392 | fwrt->ppag_flags); | ||
| 393 | |||
| 394 | if (cmd_ver == 1 && | ||
| 395 | !fw_has_capa(&fwrt->fw->ucode_capa, | ||
| 396 | IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { | ||
| 397 | cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); | ||
| 398 | IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); | ||
| 399 | } else { | ||
| 400 | IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); | ||
| 401 | } | ||
| 402 | |||
| 403 | /* The 'flags' field is the same in v1 and v5 so we can just | ||
| 404 | * use v1 to access it. | ||
| 405 | */ | ||
| 406 | IWL_DEBUG_RADIO(fwrt, | ||
| 407 | "PPAG MODE bits going to be sent: %d\n", | ||
| 408 | (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) : | ||
| 409 | le32_to_cpu(cmd->v7.ppag_config_info.value)); | ||
| 410 | |||
| 411 | for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { | ||
| 412 | for (j = 0; j < num_sub_bands; j++) { | ||
| 413 | if (!send_ppag_always && | ||
| 414 | !iwl_ppag_value_valid(fwrt, i, j)) | ||
| 415 | return -EINVAL; | ||
| 416 | |||
| 417 | gain[i * num_sub_bands + j] = | ||
| 418 | fwrt->ppag_chains[i].subbands[j]; | ||
| 419 | IWL_DEBUG_RADIO(fwrt, | ||
| 420 | "PPAG table: chain[%d] band[%d]: gain = %d\n", | ||
| 421 | i, j, gain[i * num_sub_bands + j]); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | IWL_EXPORT_SYMBOL(iwl_fill_ppag_table); | ||
| 428 | |||
| 429 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) | 307 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) |
| 430 | { | 308 | { |
| 431 | if (!dmi_check_system(dmi_ppag_approved_list)) { | 309 | if (!dmi_check_system(dmi_ppag_approved_list)) { |
| @@ -440,6 +318,27 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) · 8 unmodified lines | |||
| 440 | } | 318 | } |
| 441 | IWL_EXPORT_SYMBOL(iwl_is_ppag_approved); | 319 | IWL_EXPORT_SYMBOL(iwl_is_ppag_approved); |
| 442 | 320 | ||
| 321 | /* Print the PPAG table as read from BIOS */ | ||
| 322 | void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands) | ||
| 323 | { | ||
| 324 | int i, j; | ||
| 325 | |||
| 326 | IWL_DEBUG_RADIO(fwrt, "PPAG table as read from BIOS:\n"); | ||
| 327 | IWL_DEBUG_RADIO(fwrt, "PPAG revision = %d\n", fwrt->ppag_bios_rev); | ||
| 328 | IWL_DEBUG_RADIO(fwrt, "PPAG flags = 0x%x\n", fwrt->ppag_flags); | ||
| 329 | |||
| 330 | if (WARN_ON_ONCE(n_subbands > | ||
| 331 | ARRAY_SIZE(fwrt->ppag_chains[0].subbands))) | ||
| 332 | return; | ||
| 333 | |||
| 334 | for (i = 0; i < ARRAY_SIZE(fwrt->ppag_chains); i++) | ||
| 335 | for (j = 0; j < n_subbands; j++) | ||
| 336 | IWL_DEBUG_RADIO(fwrt, | ||
| 337 | "ppag_chains[%d].subbands[%d] = %d\n", | ||
| 338 | i, j, | ||
| 339 | fwrt->ppag_chains[i].subbands[j]); | ||
| 340 | } | ||
| 341 | |||
| 443 | bool iwl_is_tas_approved(void) | 342 | bool iwl_is_tas_approved(void) |
| 444 | { | 343 | { |
| 445 | return dmi_check_system(dmi_tas_approved_list); | 344 | return dmi_check_system(dmi_tas_approved_list); |
| @@ -21,10 +21,11 @@ · 20 unmodified lines | |||
| 21 | */ | 21 | */ |
| 22 | #define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 | 22 | #define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 |
| 23 | #define BIOS_SAR_NUM_CHAINS 2 | 23 | #define BIOS_SAR_NUM_CHAINS 2 |
| 24 | #define BIOS_SAR_MAX_SUB_BANDS_NUM 11 | 24 | #define BIOS_SAR_MAX_SUB_BANDS_NUM 12 |
| 25 | #define BIOS_PPAG_MAX_SUB_BANDS_NUM 12 | ||
| 25 | 26 | ||
| 26 | #define BIOS_GEO_NUM_CHAINS 2 | 27 | #define BIOS_GEO_NUM_CHAINS 2 |
| 27 | #define BIOS_GEO_MAX_NUM_BANDS 3 | 28 | #define BIOS_GEO_MAX_NUM_BANDS 4 |
| 28 | #define BIOS_GEO_MAX_PROFILE_NUM 8 | 29 | #define BIOS_GEO_MAX_PROFILE_NUM 8 |
| 29 | #define BIOS_GEO_MIN_PROFILE_NUM 3 | 30 | #define BIOS_GEO_MIN_PROFILE_NUM 3 |
| 30 | 31 | ||
| @@ -100,7 +101,7 @@ struct iwl_geo_profile { · 69 unmodified lines | |||
| 100 | 101 | ||
| 101 | /* Same thing as with SAR, all revisions fit in revision 2 */ | 102 | /* Same thing as with SAR, all revisions fit in revision 2 */ |
| 102 | struct iwl_ppag_chain { | 103 | struct iwl_ppag_chain { |
| 103 | s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; | 104 | s8 subbands[BIOS_PPAG_MAX_SUB_BANDS_NUM]; |
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| 106 | struct iwl_tas_data { | 107 | struct iwl_tas_data { |
| @@ -180,6 +181,9 @@ enum iwl_dsm_masks_reg { · 73 unmodified lines | |||
| 180 | 181 | ||
| 181 | struct iwl_fw_runtime; | 182 | struct iwl_fw_runtime; |
| 182 | 183 | ||
| 184 | /* Print the PPAG table as read from BIOS */ | ||
| 185 | void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands); | ||
| 186 | |||
| 183 | bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); | 187 | bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); |
| 184 | 188 | ||
| 185 | int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, | 189 | int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, |
| @@ -190,10 +194,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, · 4 unmodified lines | |||
| 190 | __le16 *per_chain, u32 n_tables, u32 n_subbands, | 194 | __le16 *per_chain, u32 n_tables, u32 n_subbands, |
| 191 | int prof_a, int prof_b); | 195 | int prof_a, int prof_b); |
| 192 | 196 | ||
| 193 | int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, | ||
| 194 | union iwl_ppag_table_cmd *cmd, | ||
| 195 | int *cmd_size); | ||
| 196 | |||
| 197 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); | 197 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); |
| 198 | 198 | ||
| 199 | bool iwl_is_tas_approved(void); | 199 | bool iwl_is_tas_approved(void); |
| @@ -106,13 +106,14 @@ struct iwl_txf_iter_data { · 105 unmodified lines | |||
| 106 | * @cur_fw_img: current firmware image, must be maintained by | 106 | * @cur_fw_img: current firmware image, must be maintained by |
| 107 | * the driver by calling &iwl_fw_set_current_image() | 107 | * the driver by calling &iwl_fw_set_current_image() |
| 108 | * @dump: debug dump data | 108 | * @dump: debug dump data |
| 109 | * @uats_table: AP type table | 109 | * @ap_type_cmd: AP type tables (for enablement on 6 GHz) |
| 110 | * @uats_valid: is AP type table valid | 110 | * @ap_type_cmd_valid: if &ap_type_cmd is valid |
| 111 | * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: | 111 | * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: |
| 112 | * 0: Unlocked, 1 and 2: Locked. | 112 | * 0: Unlocked, 1 and 2: Locked. |
| 113 | * Only read the UEFI variables if locked. | 113 | * Only read the UEFI variables if locked. |
| 114 | * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables | 114 | * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables |
| 115 | * @geo_profiles: geographic profiles as read from WGDS BIOS table | 115 | * @geo_profiles: geographic profiles as read from WGDS BIOS table |
| 116 | * @geo_bios_source: see &enum bios_source | ||
| 116 | * @phy_filters: specific phy filters as read from WPFC BIOS table | 117 | * @phy_filters: specific phy filters as read from WPFC BIOS table |
| 117 | * @ppag_bios_rev: PPAG BIOS revision | 118 | * @ppag_bios_rev: PPAG BIOS revision |
| 118 | * @ppag_bios_source: see &enum bios_source | 119 | * @ppag_bios_source: see &enum bios_source |
| @@ -204,6 +205,7 @@ struct iwl_fw_runtime { · 85 unmodified lines | |||
| 204 | u8 sar_chain_b_profile; | 205 | u8 sar_chain_b_profile; |
| 205 | u8 reduced_power_flags; | 206 | u8 reduced_power_flags; |
| 206 | struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; | 207 | struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; |
| 208 | enum bios_source geo_bios_source; | ||
| 207 | u32 geo_rev; | 209 | u32 geo_rev; |
| 208 | u32 geo_num_profiles; | 210 | u32 geo_num_profiles; |
| 209 | bool geo_enabled; | 211 | bool geo_enabled; |
| @@ -213,8 +215,8 @@ struct iwl_fw_runtime { · 3 unmodified lines | |||
| 213 | u8 ppag_bios_source; | 215 | u8 ppag_bios_source; |
| 214 | struct iwl_sar_offset_mapping_cmd sgom_table; | 216 | struct iwl_sar_offset_mapping_cmd sgom_table; |
| 215 | bool sgom_enabled; | 217 | bool sgom_enabled; |
| 216 | struct iwl_mcc_allowed_ap_type_cmd uats_table; | 218 | struct iwl_mcc_allowed_ap_type_cmd ap_type_cmd; |
| 217 | bool uats_valid; | 219 | bool ap_type_cmd_valid; |
| 218 | u8 uefi_tables_lock_status; | 220 | u8 uefi_tables_lock_status; |
| 219 | struct iwl_phy_specific_cfg phy_filters; | 221 | struct iwl_phy_specific_cfg phy_filters; |
| 220 | enum bios_source dsm_source; | 222 | enum bios_source dsm_source; |
| @@ -402,11 +402,11 @@ static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, · 401 unmodified lines | |||
| 402 | if (uats_data->revision != 1) | 402 | if (uats_data->revision != 1) |
| 403 | return -EINVAL; | 403 | return -EINVAL; |
| 404 | 404 | ||
| 405 | memcpy(fwrt->uats_table.mcc_to_ap_type_map, | 405 | memcpy(fwrt->ap_type_cmd.mcc_to_ap_type_map, |
| 406 | uats_data->mcc_to_ap_type_map, | 406 | uats_data->mcc_to_ap_type_map, |
| 407 | sizeof(fwrt->uats_table.mcc_to_ap_type_map)); | 407 | sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_map)); |
| 408 | 408 | ||
| 409 | fwrt->uats_valid = true; | 409 | fwrt->ap_type_cmd_valid = true; |
| 410 | 410 | ||
| 411 | return 0; | 411 | return 0; |
| 412 | } | 412 | } |
| @@ -429,12 +429,61 @@ void iwl_uefi_get_uats_table(struct iwl_trans *trans, · 16 unmodified lines | |||
| 429 | } | 429 | } |
| 430 | IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); | 430 | IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); |
| 431 | 431 | ||
| 432 | void iwl_uefi_get_uneb_table(struct iwl_trans *trans, | ||
| 433 | struct iwl_fw_runtime *fwrt) | ||
| 434 | { | ||
| 435 | struct uefi_cnv_wlan_uneb_data *data; | ||
| 436 | |||
| 437 | data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UNEB_NAME, | ||
| 438 | "UNEB", sizeof(*data), NULL); | ||
| 439 | if (IS_ERR(data)) | ||
| 440 | return; | ||
| 441 | |||
| 442 | if (data->revision != 1) { | ||
| 443 | IWL_DEBUG_RADIO(fwrt, | ||
| 444 | "Cannot read UNEB table. rev is invalid\n"); | ||
| 445 | goto out; | ||
| 446 | } | ||
| 447 | |||
| 448 | BUILD_BUG_ON(sizeof(data->mcc_to_ap_type_map) != | ||
| 449 | sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map)); | ||
| 450 | |||
| 451 | memcpy(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map, | ||
| 452 | data->mcc_to_ap_type_map, | ||
| 453 | sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_unii9_map)); | ||
| 454 | |||
| 455 | fwrt->ap_type_cmd_valid = true; | ||
| 456 | |||
| 457 | out: | ||
| 458 | kfree(data); | ||
| 459 | } | ||
| 460 | IWL_EXPORT_SYMBOL(iwl_uefi_get_uneb_table); | ||
| 461 | |||
| 432 | static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, | 462 | static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, |
| 433 | struct uefi_sar_profile *uefi_sar_prof, | 463 | const u8 *vals, u8 prof_index, |
| 434 | u8 prof_index, bool enabled) | 464 | u8 num_subbands, bool enabled) |
| 435 | { | 465 | { |
| 436 | memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, | 466 | struct iwl_sar_profile *sar_prof = &fwrt->sar_profiles[prof_index]; |
| 437 | sizeof(struct uefi_sar_profile)); | 467 | |
| 468 | /* | ||
| 469 | * Make sure fwrt has enough room to hold the data | ||
| 470 | * coming from the UEFI table | ||
| 471 | */ | ||
| 472 | if (WARN_ON(ARRAY_SIZE(sar_prof->chains) * | ||
| 473 | ARRAY_SIZE(sar_prof->chains[0].subbands) < | ||
| 474 | UEFI_SAR_MAX_CHAINS_PER_PROFILE * num_subbands)) | ||
| 475 | return; | ||
| 476 | |||
| 477 | BUILD_BUG_ON(ARRAY_SIZE(sar_prof->chains) != | ||
| 478 | UEFI_SAR_MAX_CHAINS_PER_PROFILE); | ||
| 479 | |||
| 480 | for (int chain = 0; | ||
| 481 | chain < UEFI_SAR_MAX_CHAINS_PER_PROFILE; | ||
| 482 | chain++) { | ||
| 483 | for (int subband = 0; subband < num_subbands; subband++) | ||
| 484 | sar_prof->chains[chain].subbands[subband] = | ||
| 485 | vals[chain * num_subbands + subband]; | ||
| 486 | } | ||
| 438 | 487 | ||
| 439 | fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; | 488 | fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; |
| 440 | } | 489 | } |
| @@ -442,24 +491,46 @@ static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, · 1 unmodified line | |||
| 442 | int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) | 491 | int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) |
| 443 | { | 492 | { |
| 444 | struct uefi_cnv_var_wrds *data; | 493 | struct uefi_cnv_var_wrds *data; |
| 494 | unsigned long size; | ||
| 495 | unsigned long expected_size; | ||
| 496 | int num_subbands; | ||
| 445 | int ret = 0; | 497 | int ret = 0; |
| 446 | 498 | ||
| 447 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, | 499 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, |
| 448 | "WRDS", sizeof(*data), NULL); | 500 | "WRDS", |
| 501 | UEFI_SAR_WRDS_TABLE_SIZE_REV2, | ||
| 502 | &size); | ||
| 503 | |||
| 449 | if (IS_ERR(data)) | 504 | if (IS_ERR(data)) |
| 450 | return -EINVAL; | 505 | return -EINVAL; |
| 451 | 506 | ||
| 452 | if (data->revision != IWL_UEFI_WRDS_REVISION) { | 507 | switch (data->revision) { |
| 453 | ret = -EINVAL; | 508 | case 2: |
| 454 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", | 509 | expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV2; |
| 510 | num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; | ||
| 511 | break; | ||
| 512 | case 3: | ||
| 513 | expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV3; | ||
| 514 | num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; | ||
| 515 | break; | ||
| 516 | default: | ||
| 517 | IWL_DEBUG_RADIO(fwrt, | ||
| 518 | "Unsupported UEFI WRDS revision:%d\n", | ||
| 455 | data->revision); | 519 | data->revision); |
| 520 | ret = -EINVAL; | ||
| 521 | goto out; | ||
| 522 | } | ||
| 523 | |||
| 524 | if (size != expected_size) { | ||
| 525 | ret = -EINVAL; | ||
| 456 | goto out; | 526 | goto out; |
| 457 | } | 527 | } |
| 458 | 528 | ||
| 459 | /* The profile from WRDS is officially profile 1, but goes | 529 | /* The profile from WRDS is officially profile 1, but goes |
| 460 | * into sar_profiles[0] (because we don't have a profile 0). | 530 | * into sar_profiles[0] (because we don't have a profile 0). |
| 461 | */ | 531 | */ |
| 462 | iwl_uefi_set_sar_profile(fwrt, &data->sar_profile, 0, data->mode); | 532 | iwl_uefi_set_sar_profile(fwrt, data->vals, 0, |
| 533 | num_subbands, data->mode); | ||
| 463 | out: | 534 | out: |
| 464 | kfree(data); | 535 | kfree(data); |
| 465 | return ret; | 536 | return ret; |
| @@ -468,21 +539,40 @@ out: · 2 unmodified lines | |||
| 468 | int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) | 539 | int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) |
| 469 | { | 540 | { |
| 470 | struct uefi_cnv_var_ewrd *data; | 541 | struct uefi_cnv_var_ewrd *data; |
| 542 | unsigned long expected_size; | ||
| 471 | int i, ret = 0; | 543 | int i, ret = 0; |
| 544 | unsigned long size; | ||
| 545 | int num_subbands; | ||
| 546 | int profile_size; | ||
| 472 | 547 | ||
| 473 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, | 548 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, |
| 474 | "EWRD", sizeof(*data), NULL); | 549 | "EWRD", |
| 550 | UEFI_SAR_EWRD_TABLE_SIZE_REV2, | ||
| 551 | &size); | ||
| 475 | if (IS_ERR(data)) | 552 | if (IS_ERR(data)) |
| 476 | return -EINVAL; | 553 | return -EINVAL; |
| 477 | 554 | ||
| 478 | if (data->revision != IWL_UEFI_EWRD_REVISION) { | 555 | switch (data->revision) { |
| 479 | ret = -EINVAL; | 556 | case 2: |
| 480 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", | 557 | expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV2; |
| 558 | num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; | ||
| 559 | profile_size = UEFI_SAR_PROFILE_SIZE_REV2; | ||
| 560 | break; | ||
| 561 | case 3: | ||
| 562 | expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV3; | ||
| 563 | num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; | ||
| 564 | profile_size = UEFI_SAR_PROFILE_SIZE_REV3; | ||
| 565 | break; | ||
| 566 | default: | ||
| 567 | IWL_DEBUG_RADIO(fwrt, | ||
| 568 | "Unsupported UEFI EWRD revision:%d\n", | ||
| 481 | data->revision); | 569 | data->revision); |
| 570 | ret = -EINVAL; | ||
| 482 | goto out; | 571 | goto out; |
| 483 | } | 572 | } |
| 484 | 573 | ||
| 485 | if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { | 574 | if (size != expected_size || |
| 575 | data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { | ||
| 486 | ret = -EINVAL; | 576 | ret = -EINVAL; |
| 487 | goto out; | 577 | goto out; |
| 488 | } | 578 | } |
| @@ -492,8 +582,8 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) · 3 unmodified lines | |||
| 492 | * save them in sar_profiles[1-3] (because we don't | 582 | * save them in sar_profiles[1-3] (because we don't |
| 493 | * have profile 0). So in the array we start from 1. | 583 | * have profile 0). So in the array we start from 1. |
| 494 | */ | 584 | */ |
| 495 | iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, | 585 | iwl_uefi_set_sar_profile(fwrt, &data->vals[i * profile_size], |
| 496 | data->mode); | 586 | i + 1, num_subbands, data->mode); |
| 497 | 587 | ||
| 498 | out: | 588 | out: |
| 499 | kfree(data); | 589 | kfree(data); |
| @@ -503,20 +593,39 @@ out: · 3 unmodified lines | |||
| 503 | int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) | 593 | int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) |
| 504 | { | 594 | { |
| 505 | struct uefi_cnv_var_wgds *data; | 595 | struct uefi_cnv_var_wgds *data; |
| 506 | int i, ret = 0; | 596 | unsigned long expected_size; |
| 597 | unsigned long size; | ||
| 598 | int profile_size; | ||
| 599 | int n_subbands; | ||
| 600 | int ret = 0; | ||
| 507 | 601 | ||
| 508 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, | 602 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, |
| 509 | "WGDS", sizeof(*data), NULL); | 603 | "WGDS", UEFI_WGDS_TABLE_SIZE_REV3, |
| 604 | &size); | ||
| 510 | if (IS_ERR(data)) | 605 | if (IS_ERR(data)) |
| 511 | return -EINVAL; | 606 | return -EINVAL; |
| 512 | 607 | ||
| 513 | if (data->revision != IWL_UEFI_WGDS_REVISION) { | 608 | switch (data->revision) { |
| 609 | case 3: | ||
| 610 | expected_size = UEFI_WGDS_TABLE_SIZE_REV3; | ||
| 611 | n_subbands = UEFI_GEO_NUM_BANDS_REV3; | ||
| 612 | break; | ||
| 613 | case 4: | ||
| 614 | expected_size = UEFI_WGDS_TABLE_SIZE_REV4; | ||
| 615 | n_subbands = UEFI_GEO_NUM_BANDS_REV4; | ||
| 616 | break; | ||
| 617 | default: | ||
| 514 | ret = -EINVAL; | 618 | ret = -EINVAL; |
| 515 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", | 619 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", |
| 516 | data->revision); | 620 | data->revision); |
| 517 | goto out; | 621 | goto out; |
| 518 | } | 622 | } |
| 519 | 623 | ||
| 624 | if (size != expected_size) { | ||
| 625 | ret = -EINVAL; | ||
| 626 | goto out; | ||
| 627 | } | ||
| 628 | |||
| 520 | if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || | 629 | if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || |
| 521 | data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { | 630 | data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { |
| 522 | ret = -EINVAL; | 631 | ret = -EINVAL; |
| @@ -525,10 +634,31 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) · 2 unmodified lines | |||
| 525 | goto out; | 634 | goto out; |
| 526 | } | 635 | } |
| 527 | 636 | ||
| 637 | if (WARN_ON(BIOS_GEO_MAX_PROFILE_NUM > | ||
| 638 | ARRAY_SIZE(fwrt->geo_profiles) || | ||
| 639 | n_subbands > ARRAY_SIZE(fwrt->geo_profiles[0].bands) || | ||
| 640 | BIOS_GEO_NUM_CHAINS > | ||
| 641 | ARRAY_SIZE(fwrt->geo_profiles[0].bands[0].chains))) { | ||
| 642 | ret = -EINVAL; | ||
| 643 | goto out; | ||
| 644 | } | ||
| 645 | |||
| 528 | fwrt->geo_rev = data->revision; | 646 | fwrt->geo_rev = data->revision; |
| 529 | for (i = 0; i < data->num_profiles; i++) | 647 | fwrt->geo_bios_source = BIOS_SOURCE_UEFI; |
| 530 | memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], | 648 | profile_size = 3 * n_subbands; |
| 531 | sizeof(struct iwl_geo_profile)); | 649 | for (int prof = 0; prof < data->num_profiles; prof++) { |
| 650 | const u8 *val = &data->vals[profile_size * prof]; | ||
| 651 | struct iwl_geo_profile *geo_prof = &fwrt->geo_profiles[prof]; | ||
| 652 | |||
| 653 | for (int subband = 0; subband < n_subbands; subband++) { | ||
| 654 | geo_prof->bands[subband].max = *val++; | ||
| 655 | |||
| 656 | for (int chain = 0; | ||
| 657 | chain < BIOS_GEO_NUM_CHAINS; | ||
| 658 | chain++) | ||
| 659 | geo_prof->bands[subband].chains[chain] = *val++; | ||
| 660 | } | ||
| 661 | } | ||
| 532 | 662 | ||
| 533 | fwrt->geo_num_profiles = data->num_profiles; | 663 | fwrt->geo_num_profiles = data->num_profiles; |
| 534 | fwrt->geo_enabled = true; | 664 | fwrt->geo_enabled = true; |
| @@ -540,28 +670,66 @@ out: · 5 unmodified lines | |||
| 540 | int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) | 670 | int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) |
| 541 | { | 671 | { |
| 542 | struct uefi_cnv_var_ppag *data; | 672 | struct uefi_cnv_var_ppag *data; |
| 673 | int n_subbands; | ||
| 674 | u32 valid_rev; | ||
| 543 | int ret = 0; | 675 | int ret = 0; |
| 544 | 676 | ||
| 545 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, | 677 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, |
| 546 | "PPAG", sizeof(*data), NULL); | 678 | "PPAG", UEFI_PPAG_DATA_SIZE_V5, |
| 547 | if (IS_ERR(data)) | 679 | NULL); |
| 548 | return -EINVAL; | 680 | if (!IS_ERR(data)) { |
| 681 | n_subbands = UEFI_PPAG_SUB_BANDS_NUM_REV5; | ||
| 682 | valid_rev = BIT(5); | ||
| 683 | |||
| 684 | goto parse_table; | ||
| 685 | } | ||
| 686 | |||
| 687 | data = iwl_uefi_get_verified_variable(fwrt->trans, | ||
| 688 | IWL_UEFI_PPAG_NAME, | ||
| 689 | "PPAG", | ||
| 690 | UEFI_PPAG_DATA_SIZE_V4, | ||
| 691 | NULL); | ||
| 692 | if (!IS_ERR(data)) { | ||
| 693 | n_subbands = UEFI_PPAG_SUB_BANDS_NUM_REV4; | ||
| 694 | /* revisions 1-4 have all the same size */ | ||
| 695 | valid_rev = BIT(1) | BIT(2) | BIT(3) | BIT(4); | ||
| 696 | |||
| 697 | goto parse_table; | ||
| 698 | } | ||
| 549 | 699 | ||
| 550 | if (data->revision < IWL_UEFI_MIN_PPAG_REV || | 700 | return -EINVAL; |
| 551 | data->revision > IWL_UEFI_MAX_PPAG_REV) { | 701 | |
| 702 | parse_table: | ||
| 703 | if (!(BIT(data->revision) & valid_rev)) { | ||
| 552 | ret = -EINVAL; | 704 | ret = -EINVAL; |
| 553 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n", | 705 | IWL_DEBUG_RADIO(fwrt, |
| 706 | "Unsupported UEFI PPAG revision:%d\n", | ||
| 554 | data->revision); | 707 | data->revision); |
| 555 | goto out; | 708 | goto out; |
| 556 | } | 709 | } |
| 557 | 710 | ||
| 711 | /* | ||
| 712 | * Make sure fwrt has enough room to hold | ||
| 713 | * data coming from the UEFI table | ||
| 714 | */ | ||
| 715 | if (WARN_ON(ARRAY_SIZE(fwrt->ppag_chains) * | ||
| 716 | ARRAY_SIZE(fwrt->ppag_chains[0].subbands) < | ||
| 717 | UEFI_PPAG_NUM_CHAINS * n_subbands)) { | ||
| 718 | ret = -EINVAL; | ||
| 719 | goto out; | ||
| 720 | } | ||
| 721 | |||
| 558 | fwrt->ppag_bios_rev = data->revision; | 722 | fwrt->ppag_bios_rev = data->revision; |
| 559 | fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, | 723 | fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, |
| 560 | fwrt->ppag_bios_rev); | 724 | fwrt->ppag_bios_rev); |
| 561 | 725 | ||
| 562 | BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); | 726 | for (int chain = 0; chain < UEFI_PPAG_NUM_CHAINS; chain++) { |
| 563 | memcpy(&fwrt->ppag_chains, &data->ppag_chains, | 727 | for (int subband = 0; subband < n_subbands; subband++) |
| 564 | sizeof(data->ppag_chains)); | 728 | fwrt->ppag_chains[chain].subbands[subband] = |
| 729 | data->vals[chain * n_subbands + subband]; | ||
| 730 | } | ||
| 731 | |||
| 732 | iwl_bios_print_ppag(fwrt, n_subbands); | ||
| 565 | fwrt->ppag_bios_source = BIOS_SOURCE_UEFI; | 733 | fwrt->ppag_bios_source = BIOS_SOURCE_UEFI; |
| 566 | out: | 734 | out: |
| 567 | kfree(data); | 735 | kfree(data); |
| @@ -25,16 +25,12 @@ · 24 unmodified lines | |||
| 25 | #define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing" | 25 | #define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing" |
| 26 | #define IWL_UEFI_DSBR_NAME L"UefiCnvCommonDSBR" | 26 | #define IWL_UEFI_DSBR_NAME L"UefiCnvCommonDSBR" |
| 27 | #define IWL_UEFI_WPFC_NAME L"WPFC" | 27 | #define IWL_UEFI_WPFC_NAME L"WPFC" |
| 28 | #define IWL_UEFI_UNEB_NAME L"CnvUefiWlanUNEB" | ||
| 28 | 29 | ||
| 29 | 30 | ||
| 30 | #define IWL_SGOM_MAP_SIZE 339 | 31 | #define IWL_SGOM_MAP_SIZE 339 |
| 31 | #define IWL_UATS_MAP_SIZE 339 | 32 | #define IWL_UATS_MAP_SIZE 339 |
| 32 | 33 | ||
| 33 | #define IWL_UEFI_WRDS_REVISION 2 | ||
| 34 | #define IWL_UEFI_EWRD_REVISION 2 | ||
| 35 | #define IWL_UEFI_WGDS_REVISION 3 | ||
| 36 | #define IWL_UEFI_MIN_PPAG_REV 1 | ||
| 37 | #define IWL_UEFI_MAX_PPAG_REV 4 | ||
| 38 | #define IWL_UEFI_MIN_WTAS_REVISION 1 | 34 | #define IWL_UEFI_MIN_WTAS_REVISION 1 |
| 39 | #define IWL_UEFI_MAX_WTAS_REVISION 2 | 35 | #define IWL_UEFI_MAX_WTAS_REVISION 2 |
| 40 | #define IWL_UEFI_SPLC_REVISION 0 | 36 | #define IWL_UEFI_SPLC_REVISION 0 |
| @@ -63,6 +59,9 @@ struct uefi_cnv_wlan_uats_data { · 22 unmodified lines | |||
| 63 | u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; | 59 | u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; |
| 64 | } __packed; | 60 | } __packed; |
| 65 | 61 | ||
| 62 | /* UNEB's layout is identical to UATS's */ | ||
| 63 | #define uefi_cnv_wlan_uneb_data uefi_cnv_wlan_uats_data | ||
| 64 | |||
| 66 | struct uefi_cnv_common_step_data { | 65 | struct uefi_cnv_common_step_data { |
| 67 | u8 revision; | 66 | u8 revision; |
| 68 | u8 step_mode; | 67 | u8 step_mode; |
| @@ -72,68 +71,135 @@ struct uefi_cnv_common_step_data { · 3 unmodified lines | |||
| 72 | u8 radio2; | 71 | u8 radio2; |
| 73 | } __packed; | 72 | } __packed; |
| 74 | 73 | ||
| 75 | /* | 74 | #define UEFI_PPAG_SUB_BANDS_NUM_REV4 11 |
| 76 | * struct uefi_sar_profile - a SAR profile as defined in UEFI | 75 | #define UEFI_PPAG_SUB_BANDS_NUM_REV5 12 |
| 77 | * | 76 | #define UEFI_PPAG_NUM_CHAINS 2 |
| 78 | * @chains: a per-chain table of SAR values | ||
| 79 | */ | ||
| 80 | struct uefi_sar_profile { | ||
| 81 | struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE]; | ||
| 82 | } __packed; | ||
| 83 | 77 | ||
| 84 | /* | 78 | #define UEFI_SAR_SUB_BANDS_NUM_REV2 11 |
| 79 | #define UEFI_SAR_SUB_BANDS_NUM_REV3 12 | ||
| 80 | |||
| 81 | #define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4 | ||
| 82 | |||
| 83 | #define UEFI_GEO_NUM_BANDS_REV3 3 | ||
| 84 | #define UEFI_GEO_NUM_BANDS_REV4 4 | ||
| 85 | |||
| 86 | /** | ||
| 85 | * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI | 87 | * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI |
| 86 | * | 88 | * |
| 87 | * @revision: the revision of the table | 89 | * @revision: the revision of the table |
| 88 | * @mode: is WRDS enbaled/disabled | 90 | * @mode: is WRDS enbaled/disabled |
| 89 | * @sar_profile: sar profile #1 | 91 | * @vals: values for sar profile #1 as an array: |
| 92 | * vals[chain * num_of_subbands + subband] will return the right value. | ||
| 93 | * num_of_subbands depends on the revision. For revision 3, it is | ||
| 94 | * %UEFI_SAR_SUB_BANDS_NUM_REV3, for earlier revision, it is | ||
| 95 | * %UEFI_SAR_SUB_BANDS_NUM_REV2. | ||
| 96 | * The max number of chains is currently 2 | ||
| 90 | */ | 97 | */ |
| 91 | struct uefi_cnv_var_wrds { | 98 | struct uefi_cnv_var_wrds { |
| 92 | u8 revision; | 99 | u8 revision; |
| 93 | u32 mode; | 100 | u32 mode; |
| 94 | struct uefi_sar_profile sar_profile; | 101 | u8 vals[]; |
| 95 | } __packed; | 102 | } __packed; |
| 96 | 103 | ||
| 97 | /* | 104 | #define UEFI_SAR_PROFILE_SIZE_REV2 \ |
| 105 | (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \ | ||
| 106 | UEFI_SAR_SUB_BANDS_NUM_REV2) | ||
| 107 | |||
| 108 | #define UEFI_SAR_PROFILE_SIZE_REV3 \ | ||
| 109 | (sizeof(u8) * UEFI_SAR_MAX_CHAINS_PER_PROFILE * \ | ||
| 110 | UEFI_SAR_SUB_BANDS_NUM_REV3) | ||
| 111 | |||
| 112 | #define UEFI_SAR_WRDS_TABLE_SIZE_REV2 \ | ||
| 113 | (offsetof(struct uefi_cnv_var_wrds, vals) + \ | ||
| 114 | UEFI_SAR_PROFILE_SIZE_REV2) | ||
| 115 | |||
| 116 | #define UEFI_SAR_WRDS_TABLE_SIZE_REV3 \ | ||
| 117 | (offsetof(struct uefi_cnv_var_wrds, vals) + \ | ||
| 118 | UEFI_SAR_PROFILE_SIZE_REV3) | ||
| 119 | |||
| 120 | /** | ||
| 98 | * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI | 121 | * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI |
| 99 | * @revision: the revision of the table | 122 | * @revision: the revision of the table |
| 100 | * @mode: is WRDS enbaled/disabled | 123 | * @mode: is WRDS enbaled/disabled |
| 101 | * @num_profiles: how many additional profiles we have in this table (0-3) | 124 | * @num_profiles: how many additional profiles we have in this table (0-3) |
| 102 | * @sar_profiles: the additional SAR profiles (#2-#4) | 125 | * @vals: the additional SAR profiles (#2-#4) as an array of SAR profiles. |
| 126 | * A SAR profile is defined the &struct uefi_cnv_var_wrds::vals. The size | ||
| 127 | * of each profile depends on the number of subbands which depends on the | ||
| 128 | * revision. This is explained in &struct uefi_cnv_var_wrds. | ||
| 103 | */ | 129 | */ |
| 104 | struct uefi_cnv_var_ewrd { | 130 | struct uefi_cnv_var_ewrd { |
| 105 | u8 revision; | 131 | u8 revision; |
| 106 | u32 mode; | 132 | u32 mode; |
| 107 | u32 num_profiles; | 133 | u32 num_profiles; |
| 108 | struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1]; | 134 | u8 vals[]; |
| 109 | } __packed; | 135 | } __packed; |
| 110 | 136 | ||
| 111 | /* | 137 | #define UEFI_SAR_EWRD_TABLE_SIZE_REV2 \ |
| 138 | (offsetof(struct uefi_cnv_var_ewrd, vals) + \ | ||
| 139 | UEFI_SAR_PROFILE_SIZE_REV2 * (BIOS_SAR_MAX_PROFILE_NUM - 1)) | ||
| 140 | |||
| 141 | #define UEFI_SAR_EWRD_TABLE_SIZE_REV3 \ | ||
| 142 | (offsetof(struct uefi_cnv_var_ewrd, vals) + \ | ||
| 143 | UEFI_SAR_PROFILE_SIZE_REV3 * (BIOS_SAR_MAX_PROFILE_NUM - 1)) | ||
| 144 | |||
| 145 | /** | ||
| 112 | * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI | 146 | * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI |
| 113 | * @revision: the revision of the table | 147 | * @revision: the revision of the table |
| 114 | * @num_profiles: the number of geo profiles we have in the table. | 148 | * @num_profiles: the number of geo profiles we have in the table. |
| 115 | * The first 3 are mandatory, and can have up to 8. | 149 | * The first 3 are mandatory, and can have up to 8. |
| 116 | * @geo_profiles: a per-profile table of the offsets to add to SAR values. | 150 | * @vals: a per-profile table of the offsets to add to SAR values. This is an |
| 151 | * array of profiles, each profile is an array of | ||
| 152 | * &struct iwl_geo_profile_band, one for each subband. | ||
| 153 | * There are %UEFI_GEO_NUM_BANDS_REV3 or %UEFI_GEO_NUM_BANDS_REV4 subbands | ||
| 154 | * depending on the revision. | ||
| 117 | */ | 155 | */ |
| 118 | struct uefi_cnv_var_wgds { | 156 | struct uefi_cnv_var_wgds { |
| 119 | u8 revision; | 157 | u8 revision; |
| 120 | u8 num_profiles; | 158 | u8 num_profiles; |
| 121 | struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; | 159 | u8 vals[]; |
| 122 | } __packed; | 160 | } __packed; |
| 123 | 161 | ||
| 124 | /* | 162 | /* struct iwl_geo_profile_band is 3 bytes-long, but since it is not packed, |
| 163 | * we can't use sizeof() | ||
| 164 | */ | ||
| 165 | #define UEFI_WGDS_PROFILE_SIZE_REV3 (sizeof(u8) * 3 * UEFI_GEO_NUM_BANDS_REV3) | ||
| 166 | |||
| 167 | #define UEFI_WGDS_PROFILE_SIZE_REV4 (sizeof(u8) * 3 * UEFI_GEO_NUM_BANDS_REV4) | ||
| 168 | |||
| 169 | #define UEFI_WGDS_TABLE_SIZE_REV3 \ | ||
| 170 | (offsetof(struct uefi_cnv_var_wgds, vals) + \ | ||
| 171 | UEFI_WGDS_PROFILE_SIZE_REV3 * BIOS_GEO_MAX_PROFILE_NUM) | ||
| 172 | |||
| 173 | #define UEFI_WGDS_TABLE_SIZE_REV4 \ | ||
| 174 | (offsetof(struct uefi_cnv_var_wgds, vals) + \ | ||
| 175 | UEFI_WGDS_PROFILE_SIZE_REV4 * BIOS_GEO_MAX_PROFILE_NUM) | ||
| 176 | |||
| 177 | /** | ||
| 125 | * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI | 178 | * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI |
| 126 | * @revision: the revision of the table | 179 | * @revision: the revision of the table |
| 127 | * @ppag_modes: values from &enum iwl_ppag_flags | 180 | * @ppag_modes: values from &enum iwl_ppag_flags |
| 128 | * @ppag_chains: the PPAG values per chain and band | 181 | * @vals: the PPAG values per chain and band as an array. |
| 182 | * vals[chain * num_of_subbands + subband] will return the right value. | ||
| 183 | * num_of_subbands depends on the revision. For revision 5, it is | ||
| 184 | * %UEFI_PPAG_SUB_BANDS_NUM_REV5, for earlier revision it is | ||
| 185 | * %UEFI_PPAG_SUB_BANDS_NUM_REV4. | ||
| 186 | * the max number of chains is currently 2 | ||
| 129 | */ | 187 | */ |
| 130 | struct uefi_cnv_var_ppag { | 188 | struct uefi_cnv_var_ppag { |
| 131 | u8 revision; | 189 | u8 revision; |
| 132 | u32 ppag_modes; | 190 | u32 ppag_modes; |
| 133 | struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; | 191 | s8 vals[]; |
| 134 | } __packed; | 192 | } __packed; |
| 135 | 193 | ||
| 136 | /* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI | 194 | #define UEFI_PPAG_DATA_SIZE_V4 \ |
| 195 | (offsetof(struct uefi_cnv_var_ppag, vals) + \ | ||
| 196 | sizeof(s8) * UEFI_PPAG_NUM_CHAINS * UEFI_PPAG_SUB_BANDS_NUM_REV4) | ||
| 197 | #define UEFI_PPAG_DATA_SIZE_V5 \ | ||
| 198 | (offsetof(struct uefi_cnv_var_ppag, vals) + \ | ||
| 199 | sizeof(s8) * UEFI_PPAG_NUM_CHAINS * UEFI_PPAG_SUB_BANDS_NUM_REV5) | ||
| 200 | |||
| 201 | /** | ||
| 202 | * struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI | ||
| 137 | * @revision: the revision of the table | 203 | * @revision: the revision of the table |
| 138 | * @tas_selection: different options of TAS enablement. | 204 | * @tas_selection: different options of TAS enablement. |
| 139 | * @black_list_size: the number of defined entried in the black list | 205 | * @black_list_size: the number of defined entried in the black list |
| @@ -146,7 +212,8 @@ struct uefi_cnv_var_wtas { · 6 unmodified lines | |||
| 146 | u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; | 212 | u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; |
| 147 | } __packed; | 213 | } __packed; |
| 148 | 214 | ||
| 149 | /* struct uefi_cnv_var_splc - SPLC tabled as defined in UEFI | 215 | /** |
| 216 | * struct uefi_cnv_var_splc - SPLC tabled as defined in UEFI | ||
| 150 | * @revision: the revision of the table | 217 | * @revision: the revision of the table |
| 151 | * @default_pwr_limit: The default maximum power per device | 218 | * @default_pwr_limit: The default maximum power per device |
| 152 | */ | 219 | */ |
| @@ -155,7 +222,8 @@ struct uefi_cnv_var_splc { · 2 unmodified lines | |||
| 155 | u32 default_pwr_limit; | 222 | u32 default_pwr_limit; |
| 156 | } __packed; | 223 | } __packed; |
| 157 | 224 | ||
| 158 | /* struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI | 225 | /** |
| 226 | * struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI | ||
| 159 | * @revision: the revision of the table | 227 | * @revision: the revision of the table |
| 160 | * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code | 228 | * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code |
| 161 | */ | 229 | */ |
| @@ -164,7 +232,8 @@ struct uefi_cnv_var_wrdd { · 2 unmodified lines | |||
| 164 | u32 mcc; | 232 | u32 mcc; |
| 165 | } __packed; | 233 | } __packed; |
| 166 | 234 | ||
| 167 | /* struct uefi_cnv_var_eckv - ECKV table as defined in UEFI | 235 | /** |
| 236 | * struct uefi_cnv_var_eckv - ECKV table as defined in UEFI | ||
| 168 | * @revision: the revision of the table | 237 | * @revision: the revision of the table |
| 169 | * @ext_clock_valid: indicates if external 32KHz clock is valid | 238 | * @ext_clock_valid: indicates if external 32KHz clock is valid |
| 170 | */ | 239 | */ |
| @@ -175,7 +244,8 @@ struct uefi_cnv_var_eckv { · 4 unmodified lines | |||
| 175 | 244 | ||
| 176 | #define UEFI_MAX_DSM_FUNCS 32 | 245 | #define UEFI_MAX_DSM_FUNCS 32 |
| 177 | 246 | ||
| 178 | /* struct uefi_cnv_var_general_cfg - DSM-like table as defined in UEFI | 247 | /** |
| 248 | * struct uefi_cnv_var_general_cfg - DSM-like table as defined in UEFI | ||
| 179 | * @revision: the revision of the table | 249 | * @revision: the revision of the table |
| 180 | * @functions: payload of the different DSM functions | 250 | * @functions: payload of the different DSM functions |
| 181 | */ | 251 | */ |
| @@ -185,7 +255,9 @@ struct uefi_cnv_var_general_cfg { · 3 unmodified lines | |||
| 185 | } __packed; | 255 | } __packed; |
| 186 | 256 | ||
| 187 | #define IWL_UEFI_WBEM_REV0_MASK (BIT(0) | BIT(1)) | 257 | #define IWL_UEFI_WBEM_REV0_MASK (BIT(0) | BIT(1)) |
| 188 | /* struct uefi_cnv_wlan_wbem_data - Bandwidth enablement per MCC as defined | 258 | |
| 259 | /** | ||
| 260 | * struct uefi_cnv_wlan_wbem_data - Bandwidth enablement per MCC as defined | ||
| 189 | * in UEFI | 261 | * in UEFI |
| 190 | * @revision: the revision of the table | 262 | * @revision: the revision of the table |
| 191 | * @wbem_320mhz_per_mcc: enablement of 320MHz bandwidth per MCC | 263 | * @wbem_320mhz_per_mcc: enablement of 320MHz bandwidth per MCC |
| @@ -274,6 +346,8 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, · 82 unmodified lines | |||
| 274 | void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); | 346 | void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); |
| 275 | void iwl_uefi_get_uats_table(struct iwl_trans *trans, | 347 | void iwl_uefi_get_uats_table(struct iwl_trans *trans, |
| 276 | struct iwl_fw_runtime *fwrt); | 348 | struct iwl_fw_runtime *fwrt); |
| 349 | void iwl_uefi_get_uneb_table(struct iwl_trans *trans, | ||
| 350 | struct iwl_fw_runtime *fwrt); | ||
| 277 | int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt); | 351 | int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt); |
| 278 | int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value); | 352 | int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value); |
| 279 | int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt); | 353 | int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt); |
| @@ -373,6 +447,11 @@ iwl_uefi_get_uats_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) · 93 unmodified lines | |||
| 373 | { | 447 | { |
| 374 | } | 448 | } |
| 375 | 449 | ||
| 450 | static inline void | ||
| 451 | iwl_uefi_get_uneb_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) | ||
| 452 | { | ||
| 453 | } | ||
| 454 | |||
| 376 | static inline | 455 | static inline |
| 377 | int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) | 456 | int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) |
| 378 | { | 457 | { |
| @@ -85,7 +85,6 @@ enum iwl_nvm_type { · 84 unmodified lines | |||
| 85 | #define IWL_WATCHDOG_DISABLED 0 | 85 | #define IWL_WATCHDOG_DISABLED 0 |
| 86 | #define IWL_DEF_WD_TIMEOUT 2500 | 86 | #define IWL_DEF_WD_TIMEOUT 2500 |
| 87 | #define IWL_LONG_WD_TIMEOUT 10000 | 87 | #define IWL_LONG_WD_TIMEOUT 10000 |
| 88 | #define IWL_MAX_WD_TIMEOUT 120000 | ||
| 89 | 88 | ||
| 90 | #define IWL_DEFAULT_MAX_TX_POWER 22 | 89 | #define IWL_DEFAULT_MAX_TX_POWER 22 |
| 91 | #define IWL_TX_CSUM_NETIF_FLAGS (NETIF_F_IPV6_CSUM | NETIF_F_IP_CSUM |\ | 90 | #define IWL_TX_CSUM_NETIF_FLAGS (NETIF_F_IPV6_CSUM | NETIF_F_IP_CSUM |\ |
| @@ -133,6 +133,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) · 132 unmodified lines | |||
| 133 | kfree(drv->fw.dbg.mem_tlv); | 133 | kfree(drv->fw.dbg.mem_tlv); |
| 134 | kfree(drv->fw.iml); | 134 | kfree(drv->fw.iml); |
| 135 | kfree(drv->fw.ucode_capa.cmd_versions); | 135 | kfree(drv->fw.ucode_capa.cmd_versions); |
| 136 | kfree(drv->fw.ucode_capa.cmd_bios_tables); | ||
| 136 | kfree(drv->fw.phy_integration_ver); | 137 | kfree(drv->fw.phy_integration_ver); |
| 137 | kfree(drv->trans->dbg.pc_data); | 138 | kfree(drv->trans->dbg.pc_data); |
| 138 | drv->trans->dbg.pc_data = NULL; | 139 | drv->trans->dbg.pc_data = NULL; |
| @@ -1314,7 +1315,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, · 1175 unmodified lines | |||
| 1314 | if (tlv_len != sizeof(u32)) | 1315 | if (tlv_len != sizeof(u32)) |
| 1315 | goto invalid_tlv_len; | 1316 | goto invalid_tlv_len; |
| 1316 | if (le32_to_cpup((const __le32 *)tlv_data) > | 1317 | if (le32_to_cpup((const __le32 *)tlv_data) > |
| 1317 | IWL_FW_MAX_LINK_ID + 1) { | 1318 | IWL_FW_MAX_LINKS) { |
| 1318 | IWL_ERR(drv, | 1319 | IWL_ERR(drv, |
| 1319 | "%d is an invalid number of links\n", | 1320 | "%d is an invalid number of links\n", |
| 1320 | le32_to_cpup((const __le32 *)tlv_data)); | 1321 | le32_to_cpup((const __le32 *)tlv_data)); |
| @@ -1426,6 +1427,26 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, · 105 unmodified lines | |||
| 1426 | return -ENOMEM; | 1427 | return -ENOMEM; |
| 1427 | drv->fw.pnvm_size = tlv_len; | 1428 | drv->fw.pnvm_size = tlv_len; |
| 1428 | break; | 1429 | break; |
| 1430 | case IWL_UCODE_TLV_CMD_BIOS_TABLE: | ||
| 1431 | if (tlv_len % sizeof(struct iwl_fw_cmd_bios_table)) { | ||
| 1432 | IWL_ERR(drv, | ||
| 1433 | "Invalid length for command bios table: %u\n", | ||
| 1434 | tlv_len); | ||
| 1435 | return -EINVAL; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | if (capa->cmd_bios_tables) { | ||
| 1439 | IWL_ERR(drv, "Duplicate TLV type 0x%02X detected\n", | ||
| 1440 | tlv_type); | ||
| 1441 | return -EINVAL; | ||
| 1442 | } | ||
| 1443 | capa->cmd_bios_tables = kmemdup(tlv_data, tlv_len, | ||
| 1444 | GFP_KERNEL); | ||
| 1445 | if (!capa->cmd_bios_tables) | ||
| 1446 | return -ENOMEM; | ||
| 1447 | capa->n_cmd_bios_tables = | ||
| 1448 | tlv_len / sizeof(struct iwl_fw_cmd_bios_table); | ||
| 1449 | break; | ||
| 1429 | default: | 1450 | default: |
| 1430 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); | 1451 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
| 1431 | break; | 1452 | break; |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | |||
| 23 | #include "fw/api/commands.h" | 23 | #include "fw/api/commands.h" |
| 24 | #include "fw/api/cmdhdr.h" | 24 | #include "fw/api/cmdhdr.h" |
| 25 | #include "fw/img.h" | 25 | #include "fw/img.h" |
| 26 | #include "fw/dbg.h" | ||
| 27 | |||
| 26 | #include "mei/iwl-mei.h" | 28 | #include "mei/iwl-mei.h" |
| 27 | 29 | ||
| 28 | /* NVM offsets (in words) definitions */ | 30 | /* NVM offsets (in words) definitions */ |
| @@ -1702,6 +1704,11 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans, · 1673 unmodified lines | |||
| 1702 | band); | 1704 | band); |
| 1703 | new_rule = false; | 1705 | new_rule = false; |
| 1704 | 1706 | ||
| 1707 | if (IWL_FW_CHECK(trans, !center_freq, | ||
| 1708 | "Invalid channel %d (idx %d) in NVM\n", | ||
| 1709 | nvm_chan[ch_idx], ch_idx)) | ||
| 1710 | continue; | ||
| 1711 | |||
| 1705 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | 1712 | if (!(ch_flags & NVM_CHANNEL_VALID)) { |
| 1706 | iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, | 1713 | iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, |
| 1707 | nvm_chan[ch_idx], ch_flags); | 1714 | nvm_chan[ch_idx], ch_flags); |
| @@ -2031,7 +2038,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, · 323 unmodified lines | |||
| 2031 | if (empty_otp) | 2038 | if (empty_otp) |
| 2032 | IWL_INFO(trans, "OTP is empty\n"); | 2039 | IWL_INFO(trans, "OTP is empty\n"); |
| 2033 | 2040 | ||
| 2034 | nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS); | 2041 | nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V2); |
| 2035 | if (!nvm) { | 2042 | if (!nvm) { |
| 2036 | ret = -ENOMEM; | 2043 | ret = -ENOMEM; |
| 2037 | goto out; | 2044 | goto out; |
| @@ -138,7 +138,7 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) · 137 unmodified lines | |||
| 138 | IWL_RESET_MODE_FUNC_RESET, | 138 | IWL_RESET_MODE_FUNC_RESET, |
| 139 | IWL_RESET_MODE_PROD_RESET, | 139 | IWL_RESET_MODE_PROD_RESET, |
| 140 | }; | 140 | }; |
| 141 | static const enum iwl_reset_mode escalation_list_sc[] = { | 141 | static const enum iwl_reset_mode escalation_list_top[] = { |
| 142 | IWL_RESET_MODE_SW_RESET, | 142 | IWL_RESET_MODE_SW_RESET, |
| 143 | IWL_RESET_MODE_REPROBE, | 143 | IWL_RESET_MODE_REPROBE, |
| 144 | IWL_RESET_MODE_REPROBE, | 144 | IWL_RESET_MODE_REPROBE, |
| @@ -159,14 +159,14 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) · 14 unmodified lines | |||
| 159 | 159 | ||
| 160 | if (trans->request_top_reset) { | 160 | if (trans->request_top_reset) { |
| 161 | trans->request_top_reset = 0; | 161 | trans->request_top_reset = 0; |
| 162 | if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) | 162 | if (iwl_trans_is_top_reset_supported(trans)) |
| 163 | return IWL_RESET_MODE_TOP_RESET; | 163 | return IWL_RESET_MODE_TOP_RESET; |
| 164 | return IWL_RESET_MODE_PROD_RESET; | 164 | return IWL_RESET_MODE_PROD_RESET; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { | 167 | if (iwl_trans_is_top_reset_supported(trans)) { |
| 168 | escalation_list = escalation_list_sc; | 168 | escalation_list = escalation_list_top; |
| 169 | escalation_list_size = ARRAY_SIZE(escalation_list_sc); | 169 | escalation_list_size = ARRAY_SIZE(escalation_list_top); |
| 170 | } else { | 170 | } else { |
| 171 | escalation_list = escalation_list_old; | 171 | escalation_list = escalation_list_old; |
| 172 | escalation_list_size = ARRAY_SIZE(escalation_list_old); | 172 | escalation_list_size = ARRAY_SIZE(escalation_list_old); |
| @@ -1088,7 +1088,7 @@ static inline void iwl_trans_schedule_reset(struct iwl_trans *trans, · 1087 unmodified lines | |||
| 1088 | */ | 1088 | */ |
| 1089 | trans->restart.during_reset = test_bit(STATUS_IN_SW_RESET, | 1089 | trans->restart.during_reset = test_bit(STATUS_IN_SW_RESET, |
| 1090 | &trans->status); | 1090 | &trans->status); |
| 1091 | queue_delayed_work(system_unbound_wq, &trans->restart.wk, 0); | 1091 | queue_delayed_work(system_dfl_wq, &trans->restart.wk, 0); |
| 1092 | } | 1092 | } |
| 1093 | 1093 | ||
| 1094 | static inline void iwl_trans_fw_error(struct iwl_trans *trans, | 1094 | static inline void iwl_trans_fw_error(struct iwl_trans *trans, |
| @@ -1258,4 +1258,22 @@ bool iwl_trans_is_pm_supported(struct iwl_trans *trans); · 163 unmodified lines | |||
| 1258 | 1258 | ||
| 1259 | bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); | 1259 | bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); |
| 1260 | 1260 | ||
| 1261 | static inline bool iwl_trans_is_top_reset_supported(struct iwl_trans *trans) | ||
| 1262 | { | ||
| 1263 | /* not supported before Sc family */ | ||
| 1264 | if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) | ||
| 1265 | return false; | ||
| 1266 | |||
| 1267 | /* for Sc family only supported for Sc2/Sc2f */ | ||
| 1268 | if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC && | ||
| 1269 | CSR_HW_REV_TYPE(trans->info.hw_rev) == IWL_CFG_MAC_TYPE_SC) | ||
| 1270 | return false; | ||
| 1271 | |||
| 1272 | /* so far these numbers are increasing - not before Pe */ | ||
| 1273 | if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) < IWL_CFG_RF_TYPE_PE) | ||
| 1274 | return false; | ||
| 1275 | |||
| 1276 | return true; | ||
| 1277 | } | ||
| 1278 | |||
| 1261 | #endif /* __iwl_trans_h__ */ | 1279 | #endif /* __iwl_trans_h__ */ |
| @@ -36,7 +36,6 @@ · 35 unmodified lines | |||
| 36 | #define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8 | 36 | #define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8 |
| 37 | 37 | ||
| 38 | #define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30 | 38 | #define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30 |
| 39 | #define IWL_MLD_SCAN_EXPIRE_TIME_SEC 20 | ||
| 40 | 39 | ||
| 41 | #define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ) | 40 | #define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ) |
| 42 | 41 | ||
| @@ -513,7 +513,7 @@ static int iwl_mld_config_fw(struct iwl_mld *mld) · 512 unmodified lines | |||
| 513 | return ret; | 513 | return ret; |
| 514 | 514 | ||
| 515 | iwl_mld_init_tas(mld); | 515 | iwl_mld_init_tas(mld); |
| 516 | iwl_mld_init_uats(mld); | 516 | iwl_mld_init_ap_type_tables(mld); |
| 517 | 517 | ||
| 518 | return 0; | 518 | return 0; |
| 519 | } | 519 | } |
| @@ -61,20 +61,27 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif) · 60 unmodified lines | |||
| 61 | static int iwl_mld_send_mac_cmd(struct iwl_mld *mld, | 61 | static int iwl_mld_send_mac_cmd(struct iwl_mld *mld, |
| 62 | struct iwl_mac_config_cmd *cmd) | 62 | struct iwl_mac_config_cmd *cmd) |
| 63 | { | 63 | { |
| 64 | u16 cmd_id = WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD); | ||
| 65 | int len = sizeof(*cmd); | ||
| 64 | int ret; | 66 | int ret; |
| 65 | 67 | ||
| 66 | lockdep_assert_wiphy(mld->wiphy); | 68 | lockdep_assert_wiphy(mld->wiphy); |
| 67 | 69 | ||
| 68 | ret = iwl_mld_send_cmd_pdu(mld, | 70 | if (iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0) < 4) { |
| 69 | WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), | 71 | if (WARN_ON(cmd->mac_type == cpu_to_le32(FW_MAC_TYPE_NAN))) |
| 70 | cmd); | 72 | return -EINVAL; |
| 73 | |||
| 74 | len = sizeof(struct iwl_mac_config_cmd_v3); | ||
| 75 | } | ||
| 76 | |||
| 77 | ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, len); | ||
| 71 | if (ret) | 78 | if (ret) |
| 72 | IWL_ERR(mld, "Failed to send MAC_CONFIG_CMD ret = %d\n", ret); | 79 | IWL_ERR(mld, "Failed to send MAC_CONFIG_CMD ret = %d\n", ret); |
| 73 | 80 | ||
| 74 | return ret; | 81 | return ret; |
| 75 | } | 82 | } |
| 76 | 83 | ||
| 77 | int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif) | 84 | static int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif) |
| 78 | { | 85 | { |
| 79 | switch (vif->type) { | 86 | switch (vif->type) { |
| 80 | case NL80211_IFTYPE_STATION: | 87 | case NL80211_IFTYPE_STATION: |
| @@ -386,7 +393,7 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy, · 305 unmodified lines | |||
| 386 | iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif)); | 393 | iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif)); |
| 387 | } | 394 | } |
| 388 | 395 | ||
| 389 | IWL_MLD_ALLOC_FN(vif, vif) | 396 | static IWL_MLD_ALLOC_FN(vif, vif) |
| 390 | 397 | ||
| 391 | /* Constructor function for struct iwl_mld_vif */ | 398 | /* Constructor function for struct iwl_mld_vif */ |
| 392 | static void | 399 | static void |
| @@ -397,6 +404,7 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) · 4 unmodified lines | |||
| 397 | lockdep_assert_wiphy(mld->wiphy); | 404 | lockdep_assert_wiphy(mld->wiphy); |
| 398 | 405 | ||
| 399 | mld_vif->mld = mld; | 406 | mld_vif->mld = mld; |
| 407 | mld_vif->fw_id = IWL_MLD_INVALID_FW_ID; | ||
| 400 | mld_vif->roc_activity = ROC_NUM_ACTIVITIES; | 408 | mld_vif->roc_activity = ROC_NUM_ACTIVITIES; |
| 401 | 409 | ||
| 402 | if (!mld->fw_status.in_hw_restart) { | 410 | if (!mld->fw_status.in_hw_restart) { |
| @@ -444,6 +452,10 @@ void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) · 41 unmodified lines | |||
| 444 | 452 | ||
| 445 | lockdep_assert_wiphy(mld->wiphy); | 453 | lockdep_assert_wiphy(mld->wiphy); |
| 446 | 454 | ||
| 455 | /* NAN interface type is not known to FW */ | ||
| 456 | if (vif->type == NL80211_IFTYPE_NAN) | ||
| 457 | return; | ||
| 458 | |||
| 447 | iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); | 459 | iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); |
| 448 | 460 | ||
| 449 | if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) | 461 | if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) |
| @@ -1,6 +1,6 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ | 1 | /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2024-2025 Intel Corporation | 3 | * Copyright (C) 2024-2026 Intel Corporation |
| 4 | */ | 4 | */ |
| 5 | #ifndef __iwl_mld_iface_h__ | 5 | #ifndef __iwl_mld_iface_h__ |
| 6 | #define __iwl_mld_iface_h__ | 6 | #define __iwl_mld_iface_h__ |
| @@ -33,6 +33,7 @@ enum iwl_mld_cca_40mhz_wa_status { · 26 unmodified lines | |||
| 33 | * there is an indication that a non-BSS interface is to be added. | 33 | * there is an indication that a non-BSS interface is to be added. |
| 34 | * @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile | 34 | * @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile |
| 35 | * @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR. | 35 | * @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR. |
| 36 | * @IWL_MLD_EMLSR_BLOCKED_TDLS: TDLS connection is preventing EMLSR. | ||
| 36 | */ | 37 | */ |
| 37 | enum iwl_mld_emlsr_blocked { | 38 | enum iwl_mld_emlsr_blocked { |
| 38 | IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1, | 39 | IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1, |
| @@ -42,6 +43,7 @@ enum iwl_mld_emlsr_blocked { · 3 unmodified lines | |||
| 42 | IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10, | 43 | IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10, |
| 43 | IWL_MLD_EMLSR_BLOCKED_TPT = 0x20, | 44 | IWL_MLD_EMLSR_BLOCKED_TPT = 0x20, |
| 44 | IWL_MLD_EMLSR_BLOCKED_NAN = 0x40, | 45 | IWL_MLD_EMLSR_BLOCKED_NAN = 0x40, |
| 46 | IWL_MLD_EMLSR_BLOCKED_TDLS = 0x80, | ||
| 45 | }; | 47 | }; |
| 46 | 48 | ||
| 47 | /** | 49 | /** |
| @@ -201,6 +203,15 @@ iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif) · 153 unmodified lines | |||
| 201 | return container_of((void *)mld_vif, struct ieee80211_vif, drv_priv); | 203 | return container_of((void *)mld_vif, struct ieee80211_vif, drv_priv); |
| 202 | } | 204 | } |
| 203 | 205 | ||
| 206 | /* Call only for interfaces that were added to the driver! */ | ||
| 207 | static inline bool iwl_mld_vif_fw_id_valid(struct iwl_mld_vif *mld_vif) | ||
| 208 | { | ||
| 209 | if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld_vif->mld->fw_id_to_vif))) | ||
| 210 | return false; | ||
| 211 | |||
| 212 | return true; | ||
| 213 | } | ||
| 214 | |||
| 204 | #define iwl_mld_link_dereference_check(mld_vif, link_id) \ | 215 | #define iwl_mld_link_dereference_check(mld_vif, link_id) \ |
| 205 | rcu_dereference_check((mld_vif)->link[link_id], \ | 216 | rcu_dereference_check((mld_vif)->link[link_id], \ |
| 206 | lockdep_is_held(&mld_vif->mld->wiphy->mtx)) | 217 | lockdep_is_held(&mld_vif->mld->wiphy->mtx)) |
| @@ -219,8 +230,6 @@ iwl_mld_link_from_mac80211(struct ieee80211_bss_conf *bss_conf) · 12 unmodified lines | |||
| 219 | return iwl_mld_link_dereference_check(mld_vif, bss_conf->link_id); | 230 | return iwl_mld_link_dereference_check(mld_vif, bss_conf->link_id); |
| 220 | } | 231 | } |
| 221 | 232 | ||
| 222 | int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif); | ||
| 223 | |||
| 224 | /* Cleanup function for struct iwl_mld_vif, will be called in restart */ | 233 | /* Cleanup function for struct iwl_mld_vif, will be called in restart */ |
| 225 | void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); | 234 | void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); |
| 226 | int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, | 235 | int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, |
| @@ -437,7 +437,7 @@ iwl_mld_rm_link_from_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link) · 436 unmodified lines | |||
| 437 | iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE); | 437 | iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE); |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | IWL_MLD_ALLOC_FN(link, bss_conf) | 440 | static IWL_MLD_ALLOC_FN(link, bss_conf) |
| 441 | 441 | ||
| 442 | /* Constructor function for struct iwl_mld_link */ | 442 | /* Constructor function for struct iwl_mld_link */ |
| 443 | static int | 443 | static int |
| @@ -40,6 +40,7 @@ struct iwl_probe_resp_data { · 39 unmodified lines | |||
| 40 | * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. | 40 | * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. |
| 41 | * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. | 41 | * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. |
| 42 | * @mon_sta: station used for TX injection in monitor interface. | 42 | * @mon_sta: station used for TX injection in monitor interface. |
| 43 | * @last_cqm_rssi_event: rssi of the last cqm rssi event | ||
| 43 | * @average_beacon_energy: average beacon energy for beacons received during | 44 | * @average_beacon_energy: average beacon energy for beacons received during |
| 44 | * client connections | 45 | * client connections |
| 45 | * @ap_early_keys: The firmware cannot install keys before bcast/mcast STAs, | 46 | * @ap_early_keys: The firmware cannot install keys before bcast/mcast STAs, |
| @@ -66,6 +67,7 @@ struct iwl_mld_link { · 20 unmodified lines | |||
| 66 | struct iwl_mld_int_sta bcast_sta; | 67 | struct iwl_mld_int_sta bcast_sta; |
| 67 | struct iwl_mld_int_sta mcast_sta; | 68 | struct iwl_mld_int_sta mcast_sta; |
| 68 | struct iwl_mld_int_sta mon_sta; | 69 | struct iwl_mld_int_sta mon_sta; |
| 70 | int last_cqm_rssi_event; | ||
| 69 | 71 | ||
| 70 | /* we can only have 2 GTK + 2 IGTK + 2 BIGTK active at a time */ | 72 | /* we can only have 2 GTK + 2 IGTK + 2 BIGTK active at a time */ |
| 71 | struct ieee80211_key_conf *ap_early_keys[6]; | 73 | struct ieee80211_key_conf *ap_early_keys[6]; |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2024-2025 Intel Corporation | 3 | * Copyright (C) 2024-2026 Intel Corporation |
| 4 | */ | 4 | */ |
| 5 | #include "mld.h" | 5 | #include "mld.h" |
| 6 | #include "iface.h" | 6 | #include "iface.h" |
| @@ -77,9 +77,12 @@ static void iwl_mld_low_latency_iter(void *_data, u8 *mac, · 70 unmodified lines | |||
| 77 | bool prev = mld_vif->low_latency_causes & LOW_LATENCY_TRAFFIC; | 77 | bool prev = mld_vif->low_latency_causes & LOW_LATENCY_TRAFFIC; |
| 78 | bool low_latency; | 78 | bool low_latency; |
| 79 | 79 | ||
| 80 | if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->low_latency.result))) | 80 | if (!iwl_mld_vif_fw_id_valid(mld_vif)) |
| 81 | return; | 81 | return; |
| 82 | 82 | ||
| 83 | BUILD_BUG_ON(ARRAY_SIZE(mld->fw_id_to_vif) != | ||
| 84 | ARRAY_SIZE(mld->low_latency.result)); | ||
| 85 | |||
| 83 | low_latency = mld->low_latency.result[mld_vif->fw_id]; | 86 | low_latency = mld->low_latency.result[mld_vif->fw_id]; |
| 84 | 87 | ||
| 85 | if (prev != low_latency) | 88 | if (prev != low_latency) |
| @@ -272,8 +275,10 @@ void iwl_mld_low_latency_update_counters(struct iwl_mld *mld, · 186 unmodified lines | |||
| 272 | if (WARN_ON_ONCE(!mld->low_latency.pkts_counters)) | 275 | if (WARN_ON_ONCE(!mld->low_latency.pkts_counters)) |
| 273 | return; | 276 | return; |
| 274 | 277 | ||
| 275 | if (WARN_ON_ONCE(fw_id >= ARRAY_SIZE(counters->vo_vi) || | 278 | if (!iwl_mld_vif_fw_id_valid(mld_vif)) |
| 276 | queue >= mld->trans->info.num_rxqs)) | 279 | return; |
| 280 | |||
| 281 | if (WARN_ON_ONCE(queue >= mld->trans->info.num_rxqs)) | ||
| 277 | return; | 282 | return; |
| 278 | 283 | ||
| 279 | if (mld->low_latency.stopped) | 284 | if (mld->low_latency.stopped) |
| @@ -754,6 +754,30 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, · 753 unmodified lines | |||
| 754 | mld->monitor.phy.valid = false; | 754 | mld->monitor.phy.valid = false; |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | static | ||
| 758 | int iwl_mld_mac80211_change_interface(struct ieee80211_hw *hw, | ||
| 759 | struct ieee80211_vif *vif, | ||
| 760 | enum nl80211_iftype new_type, bool p2p) | ||
| 761 | { | ||
| 762 | enum nl80211_iftype old_type = vif->type; | ||
| 763 | bool old_p2p = vif->p2p; | ||
| 764 | int ret; | ||
| 765 | |||
| 766 | iwl_mld_mac80211_remove_interface(hw, vif); | ||
| 767 | |||
| 768 | /* set the new type for adding it cleanly */ | ||
| 769 | vif->type = new_type; | ||
| 770 | vif->p2p = p2p; | ||
| 771 | |||
| 772 | ret = iwl_mld_mac80211_add_interface(hw, vif); | ||
| 773 | |||
| 774 | /* restore for mac80211, it will change it again */ | ||
| 775 | vif->type = old_type; | ||
| 776 | vif->p2p = old_p2p; | ||
| 777 | |||
| 778 | return ret; | ||
| 779 | } | ||
| 780 | |||
| 757 | struct iwl_mld_mc_iter_data { | 781 | struct iwl_mld_mc_iter_data { |
| 758 | struct iwl_mld *mld; | 782 | struct iwl_mld *mld; |
| 759 | int port_id; | 783 | int port_id; |
| @@ -1124,6 +1148,8 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, · 364 unmodified lines | |||
| 1124 | 1148 | ||
| 1125 | /* Now activate the link */ | 1149 | /* Now activate the link */ |
| 1126 | if (iwl_mld_can_activate_link(mld, vif, link)) { | 1150 | if (iwl_mld_can_activate_link(mld, vif, link)) { |
| 1151 | iwl_mld_tlc_update_phy(mld, vif, link); | ||
| 1152 | |||
| 1127 | ret = iwl_mld_activate_link(mld, link); | 1153 | ret = iwl_mld_activate_link(mld, link); |
| 1128 | if (ret) | 1154 | if (ret) |
| 1129 | goto err; | 1155 | goto err; |
| @@ -1185,6 +1211,8 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, · 55 unmodified lines | |||
| 1185 | 1211 | ||
| 1186 | RCU_INIT_POINTER(mld_link->chan_ctx, NULL); | 1212 | RCU_INIT_POINTER(mld_link->chan_ctx, NULL); |
| 1187 | 1213 | ||
| 1214 | iwl_mld_tlc_update_phy(mld, vif, link); | ||
| 1215 | |||
| 1188 | /* in the non-MLO case, remove/re-add the link to clean up FW state. | 1216 | /* in the non-MLO case, remove/re-add the link to clean up FW state. |
| 1189 | * In MLO, it'll be done in drv_change_vif_link | 1217 | * In MLO, it'll be done in drv_change_vif_link |
| 1190 | */ | 1218 | */ |
| @@ -1727,14 +1755,23 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, · 536 unmodified lines | |||
| 1727 | return -EBUSY; | 1755 | return -EBUSY; |
| 1728 | } | 1756 | } |
| 1729 | 1757 | ||
| 1730 | ret = iwl_mld_add_sta(mld, sta, vif, STATION_TYPE_PEER); | 1758 | ret = iwl_mld_add_sta(mld, sta, vif); |
| 1731 | if (ret) | 1759 | if (ret) |
| 1732 | return ret; | 1760 | return ret; |
| 1733 | 1761 | ||
| 1734 | /* just added first TDLS STA, so disable PM */ | 1762 | /* just added first TDLS STA, so disable PM and block EMLSR */ |
| 1735 | if (sta->tdls && tdls_count == 0) | 1763 | if (sta->tdls && tdls_count == 0) { |
| 1736 | iwl_mld_update_mac_power(mld, vif, false); | 1764 | iwl_mld_update_mac_power(mld, vif, false); |
| 1737 | 1765 | ||
| 1766 | /* TDLS requires single-link operation with | ||
| 1767 | * direct peer communication. | ||
| 1768 | * Block and exit EMLSR when TDLS is established. | ||
| 1769 | */ | ||
| 1770 | iwl_mld_block_emlsr(mld, vif, | ||
| 1771 | IWL_MLD_EMLSR_BLOCKED_TDLS, | ||
| 1772 | iwl_mld_get_primary_link(vif)); | ||
| 1773 | } | ||
| 1774 | |||
| 1738 | if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) | 1775 | if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) |
| 1739 | mld_vif->ap_sta = sta; | 1776 | mld_vif->ap_sta = sta; |
| 1740 | 1777 | ||
| @@ -1870,8 +1907,14 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld, · 129 unmodified lines | |||
| 1870 | iwl_mld_remove_sta(mld, sta); | 1907 | iwl_mld_remove_sta(mld, sta); |
| 1871 | 1908 | ||
| 1872 | if (sta->tdls && iwl_mld_tdls_sta_count(mld) == 0) { | 1909 | if (sta->tdls && iwl_mld_tdls_sta_count(mld) == 0) { |
| 1873 | /* just removed last TDLS STA, so enable PM */ | 1910 | /* just removed last TDLS STA, so enable PM |
| 1911 | * and unblock EMLSR | ||
| 1912 | */ | ||
| 1874 | iwl_mld_update_mac_power(mld, vif, false); | 1913 | iwl_mld_update_mac_power(mld, vif, false); |
| 1914 | |||
| 1915 | /* Unblock EMLSR when TDLS connection is torn down */ | ||
| 1916 | iwl_mld_unblock_emlsr(mld, vif, | ||
| 1917 | IWL_MLD_EMLSR_BLOCKED_TDLS); | ||
| 1875 | } | 1918 | } |
| 1876 | } else { | 1919 | } else { |
| 1877 | return -EINVAL; | 1920 | return -EINVAL; |
| @@ -2716,6 +2759,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { · 838 unmodified lines | |||
| 2716 | .get_antenna = iwl_mld_get_antenna, | 2759 | .get_antenna = iwl_mld_get_antenna, |
| 2717 | .set_antenna = iwl_mld_set_antenna, | 2760 | .set_antenna = iwl_mld_set_antenna, |
| 2718 | .add_interface = iwl_mld_mac80211_add_interface, | 2761 | .add_interface = iwl_mld_mac80211_add_interface, |
| 2762 | .change_interface = iwl_mld_mac80211_change_interface, | ||
| 2719 | .remove_interface = iwl_mld_mac80211_remove_interface, | 2763 | .remove_interface = iwl_mld_mac80211_remove_interface, |
| 2720 | .conf_tx = iwl_mld_mac80211_conf_tx, | 2764 | .conf_tx = iwl_mld_mac80211_conf_tx, |
| 2721 | .prepare_multicast = iwl_mld_mac80211_prepare_multicast, | 2765 | .prepare_multicast = iwl_mld_mac80211_prepare_multicast, |
| @@ -205,7 +205,7 @@ · 204 unmodified lines | |||
| 205 | struct iwl_mld { | 205 | struct iwl_mld { |
| 206 | /* Add here fields that need clean up on restart */ | 206 | /* Add here fields that need clean up on restart */ |
| 207 | struct_group(zeroed_on_hw_restart, | 207 | struct_group(zeroed_on_hw_restart, |
| 208 | struct ieee80211_bss_conf __rcu *fw_id_to_bss_conf[IWL_FW_MAX_LINK_ID + 1]; | 208 | struct ieee80211_bss_conf __rcu *fw_id_to_bss_conf[IWL_FW_MAX_LINKS]; |
| 209 | struct ieee80211_vif __rcu *fw_id_to_vif[NUM_MAC_INDEX_DRIVER]; | 209 | struct ieee80211_vif __rcu *fw_id_to_vif[NUM_MAC_INDEX_DRIVER]; |
| 210 | struct ieee80211_txq __rcu *fw_id_to_txq[IWL_MAX_TVQM_QUEUES]; | 210 | struct ieee80211_txq __rcu *fw_id_to_txq[IWL_MAX_TVQM_QUEUES]; |
| 211 | u8 used_phy_ids: NUM_PHY_CTX; | 211 | u8 used_phy_ids: NUM_PHY_CTX; |
| @@ -530,9 +530,9 @@ void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans, · 318 unmodified lines | |||
| 530 | #define IWL_MLD_INVALID_FW_ID 0xff | 530 | #define IWL_MLD_INVALID_FW_ID 0xff |
| 531 | 531 | ||
| 532 | #define IWL_MLD_ALLOC_FN(_type, _mac80211_type) \ | 532 | #define IWL_MLD_ALLOC_FN(_type, _mac80211_type) \ |
| 533 | static int \ | 533 | int \ |
| 534 | iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld, \ | 534 | iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld, \ |
| 535 | u8 *fw_id, \ | 535 | u8 *fw_id, \ |
| 536 | struct ieee80211_##_mac80211_type *mac80211_ptr) \ | 536 | struct ieee80211_##_mac80211_type *mac80211_ptr) \ |
| 537 | { \ | 537 | { \ |
| 538 | u8 rand = IWL_MLD_DIS_RANDOM_FW_ID ? 0 : get_random_u8(); \ | 538 | u8 rand = IWL_MLD_DIS_RANDOM_FW_ID ? 0 : get_random_u8(); \ |
| @@ -13,7 +13,8 @@ · 12 unmodified lines | |||
| 13 | HOW(NON_BSS) \ | 13 | HOW(NON_BSS) \ |
| 14 | HOW(TMP_NON_BSS) \ | 14 | HOW(TMP_NON_BSS) \ |
| 15 | HOW(TPT) \ | 15 | HOW(TPT) \ |
| 16 | HOW(NAN) | 16 | HOW(NAN) \ |
| 17 | HOW(TDLS) | ||
| 17 | 18 | ||
| 18 | static const char * | 19 | static const char * |
| 19 | iwl_mld_get_emlsr_blocked_string(enum iwl_mld_emlsr_blocked blocked) | 20 | iwl_mld_get_emlsr_blocked_string(enum iwl_mld_emlsr_blocked blocked) |
| @@ -110,7 +111,6 @@ void iwl_mld_emlsr_tmp_non_bss_done_wk(struct wiphy *wiphy, · 90 unmodified lines | |||
| 110 | } | 111 | } |
| 111 | 112 | ||
| 112 | #define IWL_MLD_TRIGGER_LINK_SEL_TIME (HZ * IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC) | 113 | #define IWL_MLD_TRIGGER_LINK_SEL_TIME (HZ * IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC) |
| 113 | #define IWL_MLD_SCAN_EXPIRE_TIME (HZ * IWL_MLD_SCAN_EXPIRE_TIME_SEC) | ||
| 114 | 114 | ||
| 115 | /* Exit reasons that can cause longer EMLSR prevention */ | 115 | /* Exit reasons that can cause longer EMLSR prevention */ |
| 116 | #define IWL_MLD_PREVENT_EMLSR_REASONS (IWL_MLD_EMLSR_EXIT_MISSED_BEACON | \ | 116 | #define IWL_MLD_PREVENT_EMLSR_REASONS (IWL_MLD_EMLSR_EXIT_MISSED_BEACON | \ |
| @@ -2,7 +2,8 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2025 Intel Corporation | 3 | * Copyright (C) 2025 Intel Corporation |
| 4 | */ | 4 | */ |
| 5 | 5 | #ifndef __iwl_mld_nan_h__ | |
| 6 | #define __iwl_mld_nan_h__ | ||
| 6 | #include <net/cfg80211.h> | 7 | #include <net/cfg80211.h> |
| 7 | #include <linux/etherdevice.h> | 8 | #include <linux/etherdevice.h> |
| 8 | 9 | ||
| @@ -26,3 +27,5 @@ bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld, · 17 unmodified lines | |||
| 26 | bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, | 27 | bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, |
| 27 | struct iwl_rx_packet *pkt, | 28 | struct iwl_rx_packet *pkt, |
| 28 | u32 obj_id); | 29 | u32 obj_id); |
| 30 | |||
| 31 | #endif /* __iwl_mld_nan_h__ */ | ||
| @@ -32,9 +32,9 @@ struct iwl_mld_phy { · 31 unmodified lines | |||
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | static inline struct iwl_mld_phy * | 34 | static inline struct iwl_mld_phy * |
| 35 | iwl_mld_phy_from_mac80211(struct ieee80211_chanctx_conf *channel) | 35 | iwl_mld_phy_from_mac80211(struct ieee80211_chanctx_conf *chanctx) |
| 36 | { | 36 | { |
| 37 | return (void *)channel->drv_priv; | 37 | return (void *)chanctx->drv_priv; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | /* Cleanup function for struct iwl_mld_phy, will be called in restart */ | 40 | /* Cleanup function for struct iwl_mld_phy, will be called in restart */ |
| @@ -405,7 +405,10 @@ int iwl_mld_set_tx_power(struct iwl_mld *mld, · 404 unmodified lines | |||
| 405 | .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), | 405 | .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), |
| 406 | .common.pwr_restriction = cpu_to_le16(u_tx_power), | 406 | .common.pwr_restriction = cpu_to_le16(u_tx_power), |
| 407 | }; | 407 | }; |
| 408 | int len = sizeof(cmd.common) + sizeof(cmd.v10); | 408 | int len = sizeof(cmd.common) + sizeof(cmd.v11); |
| 409 | |||
| 410 | if (iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 10) == 10) | ||
| 411 | len = sizeof(cmd.common) + sizeof(cmd.v10); | ||
| 409 | 412 | ||
| 410 | if (WARN_ON(!mld_link)) | 413 | if (WARN_ON(!mld_link)) |
| 411 | return -ENODEV; | 414 | return -ENODEV; |
| @@ -301,10 +301,12 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) · 300 unmodified lines | |||
| 301 | mld->ptp_data.ptp_clock = | 301 | mld->ptp_data.ptp_clock = |
| 302 | ptp_clock_register(&mld->ptp_data.ptp_clock_info, mld->dev); | 302 | ptp_clock_register(&mld->ptp_data.ptp_clock_info, mld->dev); |
| 303 | 303 | ||
| 304 | if (IS_ERR_OR_NULL(mld->ptp_data.ptp_clock)) { | 304 | if (IS_ERR(mld->ptp_data.ptp_clock)) { |
| 305 | IWL_ERR(mld, "Failed to register PHC clock (%ld)\n", | 305 | IWL_ERR(mld, "Failed to register PHC clock (%ld)\n", |
| 306 | PTR_ERR(mld->ptp_data.ptp_clock)); | 306 | PTR_ERR(mld->ptp_data.ptp_clock)); |
| 307 | mld->ptp_data.ptp_clock = NULL; | 307 | mld->ptp_data.ptp_clock = NULL; |
| 308 | } else if (!mld->ptp_data.ptp_clock) { | ||
| 309 | IWL_DEBUG_INFO(mld, "PTP module unavailable on this kernel\n"); | ||
| 308 | } else { | 310 | } else { |
| 309 | IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n", | 311 | IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n", |
| 310 | mld->ptp_data.ptp_clock_info.name, | 312 | mld->ptp_data.ptp_clock_info.name, |
| @@ -64,6 +64,7 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld) · 63 unmodified lines | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | iwl_uefi_get_uats_table(mld->trans, &mld->fwrt); | 66 | iwl_uefi_get_uats_table(mld->trans, &mld->fwrt); |
| 67 | iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt); | ||
| 67 | 68 | ||
| 68 | iwl_bios_get_phy_filters(&mld->fwrt); | 69 | iwl_bios_get_phy_filters(&mld->fwrt); |
| 69 | } | 70 | } |
| @@ -72,16 +73,36 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) · 2 unmodified lines | |||
| 72 | { | 73 | { |
| 73 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); | 74 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); |
| 74 | /* Only set to South Korea if the table revision is 1 */ | 75 | /* Only set to South Korea if the table revision is 1 */ |
| 75 | __le32 sk = cpu_to_le32(mld->fwrt.geo_rev == 1 ? 1 : 0); | 76 | u8 sk = mld->fwrt.geo_rev == 1 ? 1 : 0; |
| 76 | union iwl_geo_tx_power_profiles_cmd cmd = { | 77 | union iwl_geo_tx_power_profiles_cmd cmd = { |
| 77 | .v5.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), | 78 | .v5.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), |
| 78 | .v5.table_revision = sk, | ||
| 79 | }; | 79 | }; |
| 80 | u32 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); | ||
| 81 | int n_subbands; | ||
| 82 | int cmd_size; | ||
| 80 | int ret; | 83 | int ret; |
| 81 | 84 | ||
| 82 | ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v5.table[0][0], | 85 | switch (cmd_ver) { |
| 83 | ARRAY_SIZE(cmd.v5.table[0]), | 86 | case 5: |
| 84 | BIOS_GEO_MAX_PROFILE_NUM); | 87 | n_subbands = ARRAY_SIZE(cmd.v5.table[0]); |
| 88 | cmd.v5.table_revision = cpu_to_le32(sk); | ||
| 89 | cmd_size = sizeof(cmd.v5); | ||
| 90 | break; | ||
| 91 | case 6: | ||
| 92 | n_subbands = ARRAY_SIZE(cmd.v6.table[0]); | ||
| 93 | cmd.v6.bios_hdr.table_revision = mld->fwrt.geo_rev; | ||
| 94 | cmd.v6.bios_hdr.table_source = mld->fwrt.geo_bios_source; | ||
| 95 | cmd_size = sizeof(cmd.v6); | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | WARN(false, "unsupported version: %d", cmd_ver); | ||
| 99 | return -EINVAL; | ||
| 100 | } | ||
| 101 | |||
| 102 | BUILD_BUG_ON(offsetof(typeof(cmd), v6.table) != | ||
| 103 | offsetof(typeof(cmd), v5.table)); | ||
| 104 | ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v6.table[0][0], | ||
| 105 | n_subbands, BIOS_GEO_MAX_PROFILE_NUM); | ||
| 85 | 106 | ||
| 86 | /* It is a valid scenario to not support SAR, or miss wgds table, | 107 | /* It is a valid scenario to not support SAR, or miss wgds table, |
| 87 | * but in that case there is no need to send the command. | 108 | * but in that case there is no need to send the command. |
| @@ -89,28 +110,48 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) · 1 unmodified line | |||
| 89 | if (ret) | 110 | if (ret) |
| 90 | return 0; | 111 | return 0; |
| 91 | 112 | ||
| 92 | return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, sizeof(cmd.v5)); | 113 | return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, cmd_size); |
| 93 | } | 114 | } |
| 94 | 115 | ||
| 95 | int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) | 116 | int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) |
| 96 | { | 117 | { |
| 97 | u32 cmd_id = REDUCE_TX_POWER_CMD; | ||
| 98 | struct iwl_dev_tx_power_cmd cmd = { | 118 | struct iwl_dev_tx_power_cmd cmd = { |
| 99 | .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), | 119 | .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), |
| 100 | .v10.flags = cpu_to_le32(mld->fwrt.reduced_power_flags), | ||
| 101 | }; | 120 | }; |
| 121 | u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, REDUCE_TX_POWER_CMD, 10); | ||
| 122 | int num_subbands; | ||
| 123 | int cmd_size; | ||
| 102 | int ret; | 124 | int ret; |
| 103 | 125 | ||
| 126 | switch (cmd_ver) { | ||
| 127 | case 10: | ||
| 128 | cmd.v10.flags = cpu_to_le32(mld->fwrt.reduced_power_flags); | ||
| 129 | cmd_size = sizeof(cmd.common) + sizeof(cmd.v10); | ||
| 130 | num_subbands = IWL_NUM_SUB_BANDS_V2; | ||
| 131 | break; | ||
| 132 | case 11: | ||
| 133 | cmd.v11.flags = cpu_to_le32(mld->fwrt.reduced_power_flags); | ||
| 134 | cmd_size = sizeof(cmd.common) + sizeof(cmd.v11); | ||
| 135 | num_subbands = IWL_NUM_SUB_BANDS_V3; | ||
| 136 | break; | ||
| 137 | default: | ||
| 138 | WARN_ONCE(1, "Bad version for REDUCE_TX_POWER_CMD: %d\n", | ||
| 139 | cmd_ver); | ||
| 140 | return -EOPNOTSUPP; | ||
| 141 | } | ||
| 142 | |||
| 104 | /* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */ | 143 | /* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */ |
| 105 | ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v10.per_chain[0][0][0], | 144 | /* v10 and v11 have the same position for per_chain */ |
| 106 | IWL_NUM_CHAIN_TABLES, IWL_NUM_SUB_BANDS_V2, | 145 | BUILD_BUG_ON(offsetof(typeof(cmd), v11.per_chain) != |
| 146 | offsetof(typeof(cmd), v10.per_chain)); | ||
| 147 | ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v11.per_chain[0][0][0], | ||
| 148 | IWL_NUM_CHAIN_TABLES, num_subbands, | ||
| 107 | prof_a, prof_b); | 149 | prof_a, prof_b); |
| 108 | /* return on error or if the profile is disabled (positive number) */ | 150 | /* return on error or if the profile is disabled (positive number) */ |
| 109 | if (ret) | 151 | if (ret) |
| 110 | return ret; | 152 | return ret; |
| 111 | 153 | ||
| 112 | return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, | 154 | return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd, cmd_size); |
| 113 | sizeof(cmd.common) + sizeof(cmd.v10)); | ||
| 114 | } | 155 | } |
| 115 | 156 | ||
| 116 | int iwl_mld_init_sar(struct iwl_mld *mld) | 157 | int iwl_mld_init_sar(struct iwl_mld *mld) |
| @@ -165,30 +206,86 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld) · 48 unmodified lines | |||
| 165 | { | 206 | { |
| 166 | struct iwl_fw_runtime *fwrt = &mld->fwrt; | 207 | struct iwl_fw_runtime *fwrt = &mld->fwrt; |
| 167 | union iwl_ppag_table_cmd cmd = { | 208 | union iwl_ppag_table_cmd cmd = { |
| 168 | .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, | 209 | /* v7 and v8 have the same layout for the ppag_config_info */ |
| 169 | .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev, | 210 | .v8.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, |
| 170 | .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), | 211 | .v8.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev, |
| 212 | .v8.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), | ||
| 171 | }; | 213 | }; |
| 214 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD); | ||
| 215 | int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 1); | ||
| 216 | int cmd_len = sizeof(cmd.v8); | ||
| 217 | u8 cmd_bios_rev; | ||
| 172 | int ret; | 218 | int ret; |
| 173 | 219 | ||
| 220 | BUILD_BUG_ON(offsetof(typeof(cmd), v8.ppag_config_info.hdr) != | ||
| 221 | offsetof(typeof(cmd), v7.ppag_config_info.hdr)); | ||
| 222 | BUILD_BUG_ON(offsetof(typeof(cmd), v8.gain) != | ||
| 223 | offsetof(typeof(cmd), v7.gain)); | ||
| 224 | |||
| 225 | BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain) > ARRAY_SIZE(fwrt->ppag_chains)); | ||
| 226 | BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain[0]) > | ||
| 227 | ARRAY_SIZE(fwrt->ppag_chains[0].subbands)); | ||
| 228 | BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain) > ARRAY_SIZE(fwrt->ppag_chains)); | ||
| 229 | BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain[0]) > | ||
| 230 | ARRAY_SIZE(fwrt->ppag_chains[0].subbands)); | ||
| 231 | |||
| 174 | IWL_DEBUG_RADIO(fwrt, | 232 | IWL_DEBUG_RADIO(fwrt, |
| 175 | "PPAG MODE bits going to be sent: %d\n", | 233 | "PPAG MODE bits going to be sent: %d\n", |
| 176 | fwrt->ppag_flags); | 234 | fwrt->ppag_flags); |
| 177 | 235 | ||
| 178 | for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) { | 236 | /* Since ver 7 will be deprecated at some point, don't bother making |
| 179 | for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) { | 237 | * this code generic for both ver 7 and ver 8: duplicate the code. |
| 180 | cmd.v7.gain[chain][subband] = | 238 | */ |
| 181 | fwrt->ppag_chains[chain].subbands[subband]; | 239 | if (cmd_ver == 7) { |
| 182 | IWL_DEBUG_RADIO(fwrt, | 240 | for (int chain = 0; chain < ARRAY_SIZE(cmd.v7.gain); chain++) { |
| 183 | "PPAG table: chain[%d] band[%d]: gain = %d\n", | 241 | for (int subband = 0; |
| 184 | chain, subband, cmd.v7.gain[chain][subband]); | 242 | subband < ARRAY_SIZE(cmd.v7.gain[0]); |
| 243 | subband++) { | ||
| 244 | cmd.v7.gain[chain][subband] = | ||
| 245 | fwrt->ppag_chains[chain].subbands[subband]; | ||
| 246 | IWL_DEBUG_RADIO(fwrt, | ||
| 247 | "PPAG table: chain[%d] band[%d]: gain = %d\n", | ||
| 248 | chain, subband, | ||
| 249 | cmd.v7.gain[chain][subband]); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | cmd_len = sizeof(cmd.v7); | ||
| 253 | cmd_bios_rev = | ||
| 254 | iwl_fw_lookup_cmd_bios_supported_revision(fwrt->fw, | ||
| 255 | fwrt->ppag_bios_source, | ||
| 256 | cmd_id, 4); | ||
| 257 | } else if (cmd_ver == 8) { | ||
| 258 | for (int chain = 0; chain < ARRAY_SIZE(cmd.v8.gain); chain++) { | ||
| 259 | for (int subband = 0; | ||
| 260 | subband < ARRAY_SIZE(cmd.v8.gain[0]); | ||
| 261 | subband++) { | ||
| 262 | cmd.v8.gain[chain][subband] = | ||
| 263 | fwrt->ppag_chains[chain].subbands[subband]; | ||
| 264 | IWL_DEBUG_RADIO(fwrt, | ||
| 265 | "PPAG table: chain[%d] band[%d]: gain = %d\n", | ||
| 266 | chain, subband, | ||
| 267 | cmd.v8.gain[chain][subband]); | ||
| 268 | } | ||
| 185 | } | 269 | } |
| 270 | cmd_bios_rev = | ||
| 271 | iwl_fw_lookup_cmd_bios_supported_revision(fwrt->fw, | ||
| 272 | fwrt->ppag_bios_source, | ||
| 273 | cmd_id, 5); | ||
| 274 | } else { | ||
| 275 | WARN(1, "Bad version for PER_PLATFORM_ANT_GAIN_CMD %d\n", | ||
| 276 | cmd_ver); | ||
| 277 | return -EINVAL; | ||
| 278 | } | ||
| 279 | |||
| 280 | if (cmd_bios_rev < fwrt->ppag_bios_rev) { | ||
| 281 | IWL_ERR(mld, | ||
| 282 | "BIOS revision compatibility check failed - Supported: %d, Current: %d\n", | ||
| 283 | cmd_bios_rev, fwrt->ppag_bios_rev); | ||
| 284 | return 0; | ||
| 186 | } | 285 | } |
| 187 | 286 | ||
| 188 | IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); | 287 | IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); |
| 189 | ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP, | 288 | ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, cmd_len); |
| 190 | PER_PLATFORM_ANT_GAIN_CMD), | ||
| 191 | &cmd, sizeof(cmd.v7)); | ||
| 192 | if (ret < 0) | 289 | if (ret < 0) |
| 193 | IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", | 290 | IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", |
| 194 | ret); | 291 | ret); |
| @@ -352,21 +449,42 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) · 157 unmodified lines | |||
| 352 | ret); | 449 | ret); |
| 353 | } | 450 | } |
| 354 | 451 | ||
| 355 | void iwl_mld_init_uats(struct iwl_mld *mld) | 452 | void iwl_mld_init_ap_type_tables(struct iwl_mld *mld) |
| 356 | { | 453 | { |
| 357 | int ret; | 454 | int ret; |
| 358 | struct iwl_host_cmd cmd = { | 455 | struct iwl_host_cmd cmd = { |
| 359 | .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, | 456 | .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, |
| 360 | MCC_ALLOWED_AP_TYPE_CMD), | 457 | MCC_ALLOWED_AP_TYPE_CMD), |
| 361 | .data[0] = &mld->fwrt.uats_table, | 458 | .data[0] = &mld->fwrt.ap_type_cmd, |
| 362 | .len[0] = sizeof(mld->fwrt.uats_table), | 459 | .len[0] = sizeof(mld->fwrt.ap_type_cmd), |
| 363 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | 460 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, |
| 364 | }; | 461 | }; |
| 365 | 462 | ||
| 366 | if (!mld->fwrt.uats_valid) | 463 | if (!mld->fwrt.ap_type_cmd_valid) |
| 367 | return; | 464 | return; |
| 368 | 465 | ||
| 369 | ret = iwl_mld_send_cmd(mld, &cmd); | 466 | if (iwl_fw_lookup_cmd_ver(mld->fw, cmd.id, 1) == 1) { |
| 467 | struct iwl_mcc_allowed_ap_type_cmd_v1 *cmd_v1 = | ||
| 468 | kzalloc(sizeof(*cmd_v1), GFP_KERNEL); | ||
| 469 | |||
| 470 | if (!cmd_v1) | ||
| 471 | return; | ||
| 472 | |||
| 473 | BUILD_BUG_ON(sizeof(mld->fwrt.ap_type_cmd.mcc_to_ap_type_map) != | ||
| 474 | sizeof(cmd_v1->mcc_to_ap_type_map)); | ||
| 475 | |||
| 476 | memcpy(cmd_v1->mcc_to_ap_type_map, | ||
| 477 | mld->fwrt.ap_type_cmd.mcc_to_ap_type_map, | ||
| 478 | sizeof(mld->fwrt.ap_type_cmd.mcc_to_ap_type_map)); | ||
| 479 | |||
| 480 | cmd.data[0] = cmd_v1; | ||
| 481 | cmd.len[0] = sizeof(*cmd_v1); | ||
| 482 | ret = iwl_mld_send_cmd(mld, &cmd); | ||
| 483 | kfree(cmd_v1); | ||
| 484 | } else { | ||
| 485 | ret = iwl_mld_send_cmd(mld, &cmd); | ||
| 486 | } | ||
| 487 | |||
| 370 | if (ret) | 488 | if (ret) |
| 371 | IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", | 489 | IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", |
| 372 | ret); | 490 | ret); |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | void iwl_mld_get_bios_tables(struct iwl_mld *mld); | 10 | void iwl_mld_get_bios_tables(struct iwl_mld *mld); |
| 11 | void iwl_mld_configure_lari(struct iwl_mld *mld); | 11 | void iwl_mld_configure_lari(struct iwl_mld *mld); |
| 12 | void iwl_mld_init_uats(struct iwl_mld *mld); | 12 | void iwl_mld_init_ap_type_tables(struct iwl_mld *mld); |
| 13 | void iwl_mld_init_tas(struct iwl_mld *mld); | 13 | void iwl_mld_init_tas(struct iwl_mld *mld); |
| 14 | 14 | ||
| 15 | int iwl_mld_init_ppag(struct iwl_mld *mld); | 15 | int iwl_mld_init_ppag(struct iwl_mld *mld); |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2024-2025 Intel Corporation | 3 | * Copyright (C) 2024-2026 Intel Corporation |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #include <net/mac80211.h> | 6 | #include <net/mac80211.h> |
| @@ -791,6 +791,9 @@ static void * · 784 unmodified lines | |||
| 791 | iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) | 791 | iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) |
| 792 | { | 792 | { |
| 793 | struct ieee80211_radiotap_tlv *tlv; | 793 | struct ieee80211_radiotap_tlv *tlv; |
| 794 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
| 795 | |||
| 796 | rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | ||
| 794 | 797 | ||
| 795 | tlv = skb_put(skb, sizeof(*tlv)); | 798 | tlv = skb_put(skb, sizeof(*tlv)); |
| 796 | tlv->type = cpu_to_le16(type); | 799 | tlv->type = cpu_to_le16(type); |
| @@ -1234,8 +1237,6 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, · 437 unmodified lines | |||
| 1234 | 1237 | ||
| 1235 | eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); | 1238 | eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); |
| 1236 | 1239 | ||
| 1237 | rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | ||
| 1238 | |||
| 1239 | switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { | 1240 | switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { |
| 1240 | case 0: | 1241 | case 0: |
| 1241 | if (he_type == RATE_MCS_HE_TYPE_TRIG) { | 1242 | if (he_type == RATE_MCS_HE_TYPE_TRIG) { |
| @@ -1329,7 +1330,6 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, · 87 unmodified lines | |||
| 1329 | static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, | 1330 | static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, |
| 1330 | struct sk_buff *skb) | 1331 | struct sk_buff *skb) |
| 1331 | { | 1332 | { |
| 1332 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
| 1333 | struct ieee80211_radiotap_vendor_content *radiotap; | 1333 | struct ieee80211_radiotap_vendor_content *radiotap; |
| 1334 | const u16 vendor_data_len = sizeof(mld->monitor.cur_aid); | 1334 | const u16 vendor_data_len = sizeof(mld->monitor.cur_aid); |
| 1335 | 1335 | ||
| @@ -1353,8 +1353,6 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, · 17 unmodified lines | |||
| 1353 | /* fill the data now */ | 1353 | /* fill the data now */ |
| 1354 | memcpy(radiotap->data, &mld->monitor.cur_aid, | 1354 | memcpy(radiotap->data, &mld->monitor.cur_aid, |
| 1355 | sizeof(mld->monitor.cur_aid)); | 1355 | sizeof(mld->monitor.cur_aid)); |
| 1356 | |||
| 1357 | rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | ||
| 1358 | } | 1356 | } |
| 1359 | #endif | 1357 | #endif |
| 1360 | 1358 | ||
| @@ -1362,7 +1360,6 @@ static void iwl_mld_add_rtap_sniffer_phy_data(struct iwl_mld *mld, · 1 unmodified line | |||
| 1362 | struct sk_buff *skb, | 1360 | struct sk_buff *skb, |
| 1363 | struct iwl_rx_phy_air_sniffer_ntfy *ntfy) | 1361 | struct iwl_rx_phy_air_sniffer_ntfy *ntfy) |
| 1364 | { | 1362 | { |
| 1365 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
| 1366 | struct ieee80211_radiotap_vendor_content *radiotap; | 1363 | struct ieee80211_radiotap_vendor_content *radiotap; |
| 1367 | const u16 vendor_data_len = sizeof(*ntfy); | 1364 | const u16 vendor_data_len = sizeof(*ntfy); |
| 1368 | 1365 | ||
| @@ -1382,8 +1379,6 @@ static void iwl_mld_add_rtap_sniffer_phy_data(struct iwl_mld *mld, · 13 unmodified lines | |||
| 1382 | 1379 | ||
| 1383 | /* fill the data now */ | 1380 | /* fill the data now */ |
| 1384 | memcpy(radiotap->data, ntfy, vendor_data_len); | 1381 | memcpy(radiotap->data, ntfy, vendor_data_len); |
| 1385 | |||
| 1386 | rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | ||
| 1387 | } | 1382 | } |
| 1388 | 1383 | ||
| 1389 | static void | 1384 | static void |
| @@ -1407,6 +1402,7 @@ static void iwl_mld_set_rx_rate(struct iwl_mld *mld, · 17 unmodified lines | |||
| 1407 | u32 rate_n_flags = phy_data->rate_n_flags; | 1402 | u32 rate_n_flags = phy_data->rate_n_flags; |
| 1408 | u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); | 1403 | u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); |
| 1409 | u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; | 1404 | u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK; |
| 1405 | u32 he_type = u32_get_bits(rate_n_flags, RATE_MCS_HE_TYPE_MSK); | ||
| 1410 | bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; | 1406 | bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; |
| 1411 | 1407 | ||
| 1412 | /* bandwidth may be overridden to RU by PHY ntfy */ | 1408 | /* bandwidth may be overridden to RU by PHY ntfy */ |
| @@ -1481,6 +1477,12 @@ static void iwl_mld_set_rx_rate(struct iwl_mld *mld, · 68 unmodified lines | |||
| 1481 | rx_status->encoding = RX_ENC_EHT; | 1477 | rx_status->encoding = RX_ENC_EHT; |
| 1482 | iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); | 1478 | iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); |
| 1483 | break; | 1479 | break; |
| 1480 | case RATE_MCS_MOD_TYPE_UHR: | ||
| 1481 | rx_status->encoding = RX_ENC_UHR; | ||
| 1482 | iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); | ||
| 1483 | if (he_type == RATE_MCS_HE_TYPE_UHR_ELR) | ||
| 1484 | rx_status->uhr.elr = 1; | ||
| 1485 | break; | ||
| 1484 | default: | 1486 | default: |
| 1485 | WARN_ON_ONCE(1); | 1487 | WARN_ON_ONCE(1); |
| 1486 | } | 1488 | } |
| @@ -2204,8 +2206,9 @@ void iwl_mld_sync_rx_queues(struct iwl_mld *mld, · 717 unmodified lines | |||
| 2204 | ret = wait_event_timeout(mld->rxq_sync.waitq, | 2206 | ret = wait_event_timeout(mld->rxq_sync.waitq, |
| 2205 | READ_ONCE(mld->rxq_sync.state) == 0, | 2207 | READ_ONCE(mld->rxq_sync.state) == 0, |
| 2206 | SYNC_RX_QUEUE_TIMEOUT); | 2208 | SYNC_RX_QUEUE_TIMEOUT); |
| 2207 | WARN_ONCE(!ret, "RXQ sync failed: state=0x%lx, cookie=%d\n", | 2209 | IWL_FW_CHECK(mld, !ret, |
| 2208 | mld->rxq_sync.state, mld->rxq_sync.cookie); | 2210 | "RXQ sync failed: state=0x%lx, cookie=%d\n", |
| 2211 | mld->rxq_sync.state, mld->rxq_sync.cookie); | ||
| 2209 | 2212 | ||
| 2210 | out: | 2213 | out: |
| 2211 | mld->rxq_sync.state = 0; | 2214 | mld->rxq_sync.state = 0; |
| @@ -47,8 +47,6 @@ · 46 unmodified lines | |||
| 47 | /* adaptive dwell number of APs override mask for social channels */ | 47 | /* adaptive dwell number of APs override mask for social channels */ |
| 48 | #define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT BIT(21) | 48 | #define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT BIT(21) |
| 49 | 49 | ||
| 50 | #define SCAN_TIMEOUT_MSEC (30000 * HZ) | ||
| 51 | |||
| 52 | /* minimal number of 2GHz and 5GHz channels in the regular scan request */ | 50 | /* minimal number of 2GHz and 5GHz channels in the regular scan request */ |
| 53 | #define IWL_MLD_6GHZ_PASSIVE_SCAN_MIN_CHANS 4 | 51 | #define IWL_MLD_6GHZ_PASSIVE_SCAN_MIN_CHANS 4 |
| 54 | 52 | ||
| @@ -116,6 +114,13 @@ struct iwl_mld_scan_params { · 61 unmodified lines | |||
| 116 | u8 bssid[ETH_ALEN] __aligned(2); | 114 | u8 bssid[ETH_ALEN] __aligned(2); |
| 117 | }; | 115 | }; |
| 118 | 116 | ||
| 117 | struct iwl_scan_req_params_ptrs { | ||
| 118 | struct iwl_scan_general_params_v11 *general_params; | ||
| 119 | struct iwl_scan_channel_params_v8 *channel_params; | ||
| 120 | struct iwl_scan_periodic_parms_v1 *periodic_params; | ||
| 121 | struct iwl_scan_probe_params_v4 *probe_params; | ||
| 122 | }; | ||
| 123 | |||
| 119 | struct iwl_mld_scan_respect_p2p_go_iter_data { | 124 | struct iwl_mld_scan_respect_p2p_go_iter_data { |
| 120 | struct ieee80211_vif *current_vif; | 125 | struct ieee80211_vif *current_vif; |
| 121 | bool p2p_go; | 126 | bool p2p_go; |
| @@ -512,9 +517,10 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, · 390 unmodified lines | |||
| 512 | 517 | ||
| 513 | static void | 518 | static void |
| 514 | iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld, | 519 | iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld, |
| 515 | struct iwl_scan_general_params_v11 *gp, | 520 | struct iwl_mld_scan_params *params, |
| 516 | struct iwl_mld_scan_params *params) | 521 | struct iwl_scan_req_params_ptrs *scan_ptrs) |
| 517 | { | 522 | { |
| 523 | struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params; | ||
| 518 | const struct iwl_mld_scan_timing_params *timing = | 524 | const struct iwl_mld_scan_timing_params *timing = |
| 519 | &scan_timing[params->type]; | 525 | &scan_timing[params->type]; |
| 520 | 526 | ||
| @@ -551,9 +557,10 @@ static void · 30 unmodified lines | |||
| 551 | iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, | 557 | iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, |
| 552 | struct iwl_mld_scan_params *params, | 558 | struct iwl_mld_scan_params *params, |
| 553 | struct ieee80211_vif *vif, | 559 | struct ieee80211_vif *vif, |
| 554 | struct iwl_scan_general_params_v11 *gp, | 560 | struct iwl_scan_req_params_ptrs *scan_ptrs, |
| 555 | enum iwl_mld_scan_status scan_status) | 561 | enum iwl_mld_scan_status scan_status) |
| 556 | { | 562 | { |
| 563 | struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params; | ||
| 557 | u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, | 564 | u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, |
| 558 | scan_status); | 565 | scan_status); |
| 559 | u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif, | 566 | u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif, |
| @@ -566,7 +573,7 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, · 6 unmodified lines | |||
| 566 | gp->flags = cpu_to_le16(gen_flags); | 573 | gp->flags = cpu_to_le16(gen_flags); |
| 567 | gp->flags2 = gen_flags2; | 574 | gp->flags2 = gen_flags2; |
| 568 | 575 | ||
| 569 | iwl_mld_scan_cmd_set_dwell(mld, gp, params); | 576 | iwl_mld_scan_cmd_set_dwell(mld, params, scan_ptrs); |
| 570 | 577 | ||
| 571 | if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) | 578 | if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) |
| 572 | gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; | 579 | gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; |
| @@ -577,9 +584,12 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, · 4 unmodified lines | |||
| 577 | 584 | ||
| 578 | static int | 585 | static int |
| 579 | iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params, | 586 | iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params, |
| 580 | struct iwl_scan_umac_schedule *schedule, | 587 | struct iwl_scan_req_params_ptrs *scan_ptrs) |
| 581 | __le16 *delay) | ||
| 582 | { | 588 | { |
| 589 | struct iwl_scan_umac_schedule *schedule = | ||
| 590 | scan_ptrs->periodic_params->schedule; | ||
| 591 | __le16 *delay = &scan_ptrs->periodic_params->delay; | ||
| 592 | |||
| 583 | if (WARN_ON(!params->n_scan_plans || | 593 | if (WARN_ON(!params->n_scan_plans || |
| 584 | params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) | 594 | params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) |
| 585 | return -EINVAL; | 595 | return -EINVAL; |
| @@ -657,11 +667,12 @@ iwl_mld_scan_cmd_build_ssids(struct iwl_mld_scan_params *params, · 71 unmodified lines | |||
| 657 | 667 | ||
| 658 | static void | 668 | static void |
| 659 | iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params, | 669 | iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params, |
| 660 | struct iwl_scan_probe_params_v4 *pp) | 670 | struct iwl_scan_req_params_ptrs *scan_ptrs) |
| 661 | { | 671 | { |
| 662 | int j, idex_s = 0, idex_b = 0; | 672 | int j, idex_s = 0, idex_b = 0; |
| 663 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = | 673 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = |
| 664 | params->scan_6ghz_params; | 674 | params->scan_6ghz_params; |
| 675 | struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params; | ||
| 665 | 676 | ||
| 666 | for (j = 0; | 677 | for (j = 0; |
| 667 | j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE; | 678 | j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE; |
| @@ -725,13 +736,15 @@ iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params, · 57 unmodified lines | |||
| 725 | 736 | ||
| 726 | static void | 737 | static void |
| 727 | iwl_mld_scan_cmd_set_probe_params(struct iwl_mld_scan_params *params, | 738 | iwl_mld_scan_cmd_set_probe_params(struct iwl_mld_scan_params *params, |
| 728 | struct iwl_scan_probe_params_v4 *pp, | 739 | struct iwl_scan_req_params_ptrs *scan_ptrs, |
| 729 | u32 *bitmap_ssid) | 740 | u32 *bitmap_ssid) |
| 730 | { | 741 | { |
| 742 | struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params; | ||
| 743 | |||
| 731 | pp->preq = params->preq; | 744 | pp->preq = params->preq; |
| 732 | 745 | ||
| 733 | if (params->scan_6ghz) { | 746 | if (params->scan_6ghz) { |
| 734 | iwl_mld_scan_fill_6g_chan_list(params, pp); | 747 | iwl_mld_scan_fill_6g_chan_list(params, scan_ptrs); |
| 735 | return; | 748 | return; |
| 736 | } | 749 | } |
| 737 | 750 | ||
| @@ -821,10 +834,12 @@ static u32 iwl_mld_scan_ch_n_aps_flag(enum nl80211_iftype vif_type, u8 ch_id) · 83 unmodified lines | |||
| 821 | static void | 834 | static void |
| 822 | iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld, | 835 | iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld, |
| 823 | struct ieee80211_channel **channels, | 836 | struct ieee80211_channel **channels, |
| 824 | struct iwl_scan_channel_params_v7 *cp, | 837 | struct iwl_scan_req_params_ptrs *scan_ptrs, |
| 825 | int n_channels, u32 flags, | 838 | int n_channels, u32 flags, |
| 826 | enum nl80211_iftype vif_type) | 839 | enum nl80211_iftype vif_type) |
| 827 | { | 840 | { |
| 841 | struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; | ||
| 842 | |||
| 828 | for (int i = 0; i < n_channels; i++) { | 843 | for (int i = 0; i < n_channels; i++) { |
| 829 | enum nl80211_band band = channels[i]->band; | 844 | enum nl80211_band band = channels[i]->band; |
| 830 | struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; | 845 | struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; |
| @@ -862,10 +877,11 @@ static u8 · 31 unmodified lines | |||
| 862 | iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld, | 877 | iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld, |
| 863 | struct iwl_mld_scan_params *params, | 878 | struct iwl_mld_scan_params *params, |
| 864 | u32 n_channels, | 879 | u32 n_channels, |
| 865 | struct iwl_scan_probe_params_v4 *pp, | 880 | struct iwl_scan_req_params_ptrs *scan_ptrs, |
| 866 | struct iwl_scan_channel_params_v7 *cp, | ||
| 867 | enum nl80211_iftype vif_type) | 881 | enum nl80211_iftype vif_type) |
| 868 | { | 882 | { |
| 883 | struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params; | ||
| 884 | struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; | ||
| 869 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = | 885 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = |
| 870 | params->scan_6ghz_params; | 886 | params->scan_6ghz_params; |
| 871 | u32 i; | 887 | u32 i; |
| @@ -1063,25 +1079,23 @@ static int · 191 unmodified lines | |||
| 1063 | iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld, | 1079 | iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld, |
| 1064 | struct iwl_mld_scan_params *params, | 1080 | struct iwl_mld_scan_params *params, |
| 1065 | struct ieee80211_vif *vif, | 1081 | struct ieee80211_vif *vif, |
| 1066 | struct iwl_scan_req_params_v17 *scan_p) | 1082 | struct iwl_scan_req_params_ptrs *scan_ptrs) |
| 1067 | { | 1083 | { |
| 1068 | struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params; | 1084 | struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; |
| 1069 | struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params; | ||
| 1070 | 1085 | ||
| 1071 | /* Explicitly clear the flags since most of them are not | 1086 | /* Explicitly clear the flags since most of them are not |
| 1072 | * relevant for 6 GHz scan. | 1087 | * relevant for 6 GHz scan. |
| 1073 | */ | 1088 | */ |
| 1074 | chan_p->flags = 0; | 1089 | cp->flags = 0; |
| 1075 | chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params, | 1090 | cp->count = iwl_mld_scan_cfg_channels_6g(mld, params, |
| 1076 | params->n_channels, | 1091 | params->n_channels, |
| 1077 | probe_p, chan_p, | 1092 | scan_ptrs, vif->type); |
| 1078 | vif->type); | 1093 | if (!cp->count) |
| 1079 | if (!chan_p->count) | ||
| 1080 | return -EINVAL; | 1094 | return -EINVAL; |
| 1081 | 1095 | ||
| 1082 | if (!params->n_ssids || | 1096 | if (!params->n_ssids || |
| 1083 | (params->n_ssids == 1 && !params->ssids[0].ssid_len)) | 1097 | (params->n_ssids == 1 && !params->ssids[0].ssid_len)) |
| 1084 | chan_p->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER; | 1098 | cp->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER; |
| 1085 | 1099 | ||
| 1086 | return 0; | 1100 | return 0; |
| 1087 | } | 1101 | } |
| @@ -1090,12 +1104,12 @@ static int · 2 unmodified lines | |||
| 1090 | iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, | 1104 | iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, |
| 1091 | struct iwl_mld_scan_params *params, | 1105 | struct iwl_mld_scan_params *params, |
| 1092 | struct ieee80211_vif *vif, | 1106 | struct ieee80211_vif *vif, |
| 1093 | struct iwl_scan_req_params_v17 *scan_p, | 1107 | struct iwl_scan_req_params_ptrs *scan_ptrs, |
| 1094 | bool low_latency, | 1108 | bool low_latency, |
| 1095 | enum iwl_mld_scan_status scan_status, | 1109 | enum iwl_mld_scan_status scan_status, |
| 1096 | u32 channel_cfg_flags) | 1110 | u32 channel_cfg_flags) |
| 1097 | { | 1111 | { |
| 1098 | struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params; | 1112 | struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; |
| 1099 | struct ieee80211_supported_band *sband = | 1113 | struct ieee80211_supported_band *sband = |
| 1100 | &mld->nvm_data->bands[NL80211_BAND_6GHZ]; | 1114 | &mld->nvm_data->bands[NL80211_BAND_6GHZ]; |
| 1101 | 1115 | ||
| @@ -1107,14 +1121,14 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, · 5 unmodified lines | |||
| 1107 | 1121 | ||
| 1108 | if (params->scan_6ghz) | 1122 | if (params->scan_6ghz) |
| 1109 | return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params, | 1123 | return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params, |
| 1110 | vif, scan_p); | 1124 | vif, scan_ptrs); |
| 1111 | 1125 | ||
| 1112 | /* relevant only for 2.4 GHz/5 GHz scan */ | 1126 | /* relevant only for 2.4 GHz/5 GHz scan */ |
| 1113 | cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif, | 1127 | cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif, |
| 1114 | low_latency); | 1128 | low_latency); |
| 1115 | cp->count = params->n_channels; | 1129 | cp->count = params->n_channels; |
| 1116 | 1130 | ||
| 1117 | iwl_mld_scan_cmd_set_channels(mld, params->channels, cp, | 1131 | iwl_mld_scan_cmd_set_channels(mld, params->channels, scan_ptrs, |
| 1118 | params->n_channels, channel_cfg_flags, | 1132 | params->n_channels, channel_cfg_flags, |
| 1119 | vif->type); | 1133 | vif->type); |
| 1120 | 1134 | ||
| @@ -1144,49 +1158,148 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, · 23 unmodified lines | |||
| 1144 | return 0; | 1158 | return 0; |
| 1145 | } | 1159 | } |
| 1146 | 1160 | ||
| 1147 | static int | 1161 | struct iwl_scan_umac_handler { |
| 1148 | iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, | 1162 | u8 version; |
| 1163 | int (*handler)(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 1149 | struct iwl_mld_scan_params *params, | 1164 | struct iwl_mld_scan_params *params, |
| 1150 | enum iwl_mld_scan_status scan_status, | 1165 | enum iwl_mld_scan_status scan_status, |
| 1151 | bool low_latency) | 1166 | int uid, u32 ooc_priority, bool low_latency); |
| 1167 | }; | ||
| 1168 | |||
| 1169 | #define IWL_SCAN_UMAC_HANDLER(_ver) { \ | ||
| 1170 | .version = _ver, \ | ||
| 1171 | .handler = iwl_mld_scan_umac_v##_ver, \ | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | static int iwl_mld_scan_umac_common(struct iwl_mld *mld, | ||
| 1175 | struct ieee80211_vif *vif, | ||
| 1176 | struct iwl_mld_scan_params *params, | ||
| 1177 | struct iwl_scan_req_params_ptrs *scan_ptrs, | ||
| 1178 | enum iwl_mld_scan_status scan_status, | ||
| 1179 | bool low_latency) | ||
| 1152 | { | 1180 | { |
| 1153 | struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd; | ||
| 1154 | struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params; | ||
| 1155 | u32 bitmap_ssid = 0; | 1181 | u32 bitmap_ssid = 0; |
| 1156 | int uid, ret; | 1182 | int ret; |
| 1157 | 1183 | ||
| 1158 | memset(mld->scan.cmd, 0, mld->scan.cmd_size); | 1184 | iwl_mld_scan_cmd_set_gen_params(mld, params, vif, scan_ptrs, |
| 1185 | scan_status); | ||
| 1159 | 1186 | ||
| 1160 | /* find a free UID entry */ | 1187 | ret = iwl_mld_scan_cmd_set_sched_params(params, scan_ptrs); |
| 1161 | uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE); | 1188 | if (ret) |
| 1162 | if (uid < 0) | 1189 | return ret; |
| 1163 | return uid; | ||
| 1164 | 1190 | ||
| 1165 | cmd->uid = cpu_to_le32(uid); | 1191 | iwl_mld_scan_cmd_set_probe_params(params, scan_ptrs, &bitmap_ssid); |
| 1166 | cmd->ooc_priority = | 1192 | |
| 1167 | cpu_to_le32(iwl_mld_scan_ooc_priority(scan_status)); | 1193 | return iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_ptrs, |
| 1194 | low_latency, scan_status, | ||
| 1195 | bitmap_ssid); | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | static int iwl_mld_scan_umac_v18(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 1199 | struct iwl_mld_scan_params *params, | ||
| 1200 | enum iwl_mld_scan_status scan_status, | ||
| 1201 | int uid, u32 ooc_priority, bool low_latency) | ||
| 1202 | { | ||
| 1203 | struct iwl_scan_req_umac_v18 *cmd = mld->scan.cmd; | ||
| 1204 | struct iwl_scan_req_params_ptrs scan_ptrs = { | ||
| 1205 | .general_params = &cmd->scan_params.general_params, | ||
| 1206 | .probe_params = &cmd->scan_params.probe_params, | ||
| 1207 | .channel_params = &cmd->scan_params.channel_params, | ||
| 1208 | .periodic_params = &cmd->scan_params.periodic_params | ||
| 1209 | }; | ||
| 1210 | int ret; | ||
| 1168 | 1211 | ||
| 1169 | iwl_mld_scan_cmd_set_gen_params(mld, params, vif, | 1212 | if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V4)) |
| 1170 | &scan_p->general_params, scan_status); | 1213 | return -EINVAL; |
| 1171 | 1214 | ||
| 1172 | ret = iwl_mld_scan_cmd_set_sched_params(params, | 1215 | cmd->uid = cpu_to_le32(uid); |
| 1173 | scan_p->periodic_params.schedule, | 1216 | cmd->ooc_priority = cpu_to_le32(ooc_priority); |
| 1174 | &scan_p->periodic_params.delay); | 1217 | |
| 1218 | ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs, | ||
| 1219 | scan_status, low_latency); | ||
| 1175 | if (ret) | 1220 | if (ret) |
| 1176 | return ret; | 1221 | return ret; |
| 1177 | 1222 | ||
| 1178 | iwl_mld_scan_cmd_set_probe_params(params, &scan_p->probe_params, | 1223 | return uid; |
| 1179 | &bitmap_ssid); | 1224 | } |
| 1225 | |||
| 1226 | static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 1227 | struct iwl_mld_scan_params *params, | ||
| 1228 | enum iwl_mld_scan_status scan_status, | ||
| 1229 | int uid, u32 ooc_priority, bool low_latency) | ||
| 1230 | { | ||
| 1231 | struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd; | ||
| 1232 | struct iwl_scan_req_params_ptrs scan_ptrs = { | ||
| 1233 | .general_params = &cmd->scan_params.general_params, | ||
| 1234 | .probe_params = &cmd->scan_params.probe_params, | ||
| 1235 | |||
| 1236 | /* struct iwl_scan_channel_params_v8 and struct | ||
| 1237 | * iwl_scan_channel_params_v7 are almost identical. The only | ||
| 1238 | * difference is that the newer version allows configuration of | ||
| 1239 | * more channels. So casting here is ok as long as we ensure | ||
| 1240 | * that we don't exceed the max number of channels supported by | ||
| 1241 | * the older version (see the WARN_ON below). | ||
| 1242 | */ | ||
| 1243 | .channel_params = (struct iwl_scan_channel_params_v8 *) | ||
| 1244 | &cmd->scan_params.channel_params, | ||
| 1245 | .periodic_params = &cmd->scan_params.periodic_params | ||
| 1246 | }; | ||
| 1247 | int ret; | ||
| 1248 | |||
| 1249 | if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3)) | ||
| 1250 | return -EINVAL; | ||
| 1251 | |||
| 1252 | cmd->uid = cpu_to_le32(uid); | ||
| 1253 | cmd->ooc_priority = cpu_to_le32(ooc_priority); | ||
| 1180 | 1254 | ||
| 1181 | ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_p, | 1255 | ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs, |
| 1182 | low_latency, scan_status, | 1256 | scan_status, low_latency); |
| 1183 | bitmap_ssid); | ||
| 1184 | if (ret) | 1257 | if (ret) |
| 1185 | return ret; | 1258 | return ret; |
| 1186 | 1259 | ||
| 1187 | return uid; | 1260 | return uid; |
| 1188 | } | 1261 | } |
| 1189 | 1262 | ||
| 1263 | static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { | ||
| 1264 | /* set the newest version first to shorten the list traverse time */ | ||
| 1265 | IWL_SCAN_UMAC_HANDLER(18), | ||
| 1266 | IWL_SCAN_UMAC_HANDLER(17), | ||
| 1267 | }; | ||
| 1268 | |||
| 1269 | static int | ||
| 1270 | iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 1271 | struct iwl_mld_scan_params *params, | ||
| 1272 | enum iwl_mld_scan_status scan_status, | ||
| 1273 | bool low_latency) | ||
| 1274 | { | ||
| 1275 | int uid, err; | ||
| 1276 | u32 ooc_priority; | ||
| 1277 | |||
| 1278 | memset(mld->scan.cmd, 0, mld->scan.cmd_size); | ||
| 1279 | uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE); | ||
| 1280 | if (uid < 0) | ||
| 1281 | return uid; | ||
| 1282 | |||
| 1283 | ooc_priority = iwl_mld_scan_ooc_priority(scan_status); | ||
| 1284 | |||
| 1285 | for (size_t i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) { | ||
| 1286 | const struct iwl_scan_umac_handler *ver_handler = | ||
| 1287 | &iwl_scan_umac_handlers[i]; | ||
| 1288 | |||
| 1289 | if (ver_handler->version != mld->scan.cmd_ver) | ||
| 1290 | continue; | ||
| 1291 | |||
| 1292 | err = ver_handler->handler(mld, vif, params, scan_status, | ||
| 1293 | uid, ooc_priority, low_latency); | ||
| 1294 | return err ? : uid; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | IWL_ERR(mld, "No handler for UMAC scan cmd version %d\n", | ||
| 1298 | mld->scan.cmd_ver); | ||
| 1299 | |||
| 1300 | return -EINVAL; | ||
| 1301 | } | ||
| 1302 | |||
| 1190 | static bool | 1303 | static bool |
| 1191 | iwl_mld_scan_pass_all(struct iwl_mld *mld, | 1304 | iwl_mld_scan_pass_all(struct iwl_mld *mld, |
| 1192 | struct cfg80211_sched_scan_request *req) | 1305 | struct cfg80211_sched_scan_request *req) |
| @@ -1942,9 +2055,7 @@ void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld, · 749 unmodified lines | |||
| 1942 | struct ieee80211_bss_conf *link_conf = NULL; | 2055 | struct ieee80211_bss_conf *link_conf = NULL; |
| 1943 | 2056 | ||
| 1944 | if (fw_link_id != IWL_MLD_INVALID_FW_ID) | 2057 | if (fw_link_id != IWL_MLD_INVALID_FW_ID) |
| 1945 | link_conf = | 2058 | link_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id); |
| 1946 | wiphy_dereference(mld->wiphy, | ||
| 1947 | mld->fw_id_to_bss_conf[fw_link_id]); | ||
| 1948 | 2059 | ||
| 1949 | /* It is possible that by the time the scan is complete the | 2060 | /* It is possible that by the time the scan is complete the |
| 1950 | * link was already removed and is not valid. | 2061 | * link was already removed and is not valid. |
| @@ -2031,6 +2142,8 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld) · 80 unmodified lines | |||
| 2031 | 2142 | ||
| 2032 | if (scan_cmd_ver == 17) { | 2143 | if (scan_cmd_ver == 17) { |
| 2033 | scan_cmd_size = sizeof(struct iwl_scan_req_umac_v17); | 2144 | scan_cmd_size = sizeof(struct iwl_scan_req_umac_v17); |
| 2145 | } else if (scan_cmd_ver == 18) { | ||
| 2146 | scan_cmd_size = sizeof(struct iwl_scan_req_umac_v18); | ||
| 2034 | } else { | 2147 | } else { |
| 2035 | IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver); | 2148 | IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver); |
| 2036 | return -EINVAL; | 2149 | return -EINVAL; |
| @@ -2041,6 +2154,7 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld) · 4 unmodified lines | |||
| 2041 | return -ENOMEM; | 2154 | return -ENOMEM; |
| 2042 | 2155 | ||
| 2043 | mld->scan.cmd_size = scan_cmd_size; | 2156 | mld->scan.cmd_size = scan_cmd_size; |
| 2157 | mld->scan.cmd_ver = scan_cmd_ver; | ||
| 2044 | 2158 | ||
| 2045 | return 0; | 2159 | return 0; |
| 2046 | } | 2160 | } |
| @@ -109,6 +109,7 @@ enum iwl_mld_traffic_load { · 108 unmodified lines | |||
| 109 | * @traffic_load.status: The current traffic load status, see | 109 | * @traffic_load.status: The current traffic load status, see |
| 110 | * &enum iwl_mld_traffic_load | 110 | * &enum iwl_mld_traffic_load |
| 111 | * @cmd_size: size of %cmd. | 111 | * @cmd_size: size of %cmd. |
| 112 | * @cmd_ver: version of the scan command format. | ||
| 112 | * @cmd: pointer to scan cmd buffer (allocated once in op mode start). | 113 | * @cmd: pointer to scan cmd buffer (allocated once in op mode start). |
| 113 | * @last_6ghz_passive_jiffies: stores the last 6GHz passive scan time | 114 | * @last_6ghz_passive_jiffies: stores the last 6GHz passive scan time |
| 114 | * in jiffies. | 115 | * in jiffies. |
| @@ -134,6 +135,7 @@ struct iwl_mld_scan { · 19 unmodified lines | |||
| 134 | /* And here fields that survive a fw restart */ | 135 | /* And here fields that survive a fw restart */ |
| 135 | size_t cmd_size; | 136 | size_t cmd_size; |
| 136 | void *cmd; | 137 | void *cmd; |
| 138 | u8 cmd_ver; | ||
| 137 | unsigned long last_6ghz_passive_jiffies; | 139 | unsigned long last_6ghz_passive_jiffies; |
| 138 | unsigned long last_start_time_jiffies; | 140 | unsigned long last_start_time_jiffies; |
| 139 | u64 last_mlo_scan_time; | 141 | u64 last_mlo_scan_time; |
| @@ -398,12 +398,42 @@ static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta) · 397 unmodified lines | |||
| 398 | return htc_flags; | 398 | return htc_flags; |
| 399 | } | 399 | } |
| 400 | 400 | ||
| 401 | /* Note: modifies the command depending on FW command version */ | ||
| 401 | static int iwl_mld_send_sta_cmd(struct iwl_mld *mld, | 402 | static int iwl_mld_send_sta_cmd(struct iwl_mld *mld, |
| 402 | const struct iwl_sta_cfg_cmd *cmd) | 403 | struct iwl_sta_cfg_cmd *cmd) |
| 403 | { | 404 | { |
| 404 | int ret = iwl_mld_send_cmd_pdu(mld, | 405 | int cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); |
| 405 | WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), | 406 | int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); |
| 406 | cmd); | 407 | int len = sizeof(*cmd); |
| 408 | int ret; | ||
| 409 | |||
| 410 | if (cmd_ver < 2) { | ||
| 411 | IWL_ERR(mld, "Unsupported STA_CONFIG_CMD version %d\n", | ||
| 412 | cmd_ver); | ||
| 413 | return -EINVAL; | ||
| 414 | } else if (cmd_ver == 2) { | ||
| 415 | struct iwl_sta_cfg_cmd_v2 *cmd_v2 = (void *)cmd; | ||
| 416 | |||
| 417 | if (WARN_ON(cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) || | ||
| 418 | cmd->station_type == cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) || | ||
| 419 | hweight32(le32_to_cpu(cmd->link_mask)) != 1)) | ||
| 420 | return -EINVAL; | ||
| 421 | /* | ||
| 422 | * These fields are located in a different place in the struct of v2. | ||
| 423 | * The assumption is that UHR won't be used with FW that has v2. | ||
| 424 | */ | ||
| 425 | if (WARN_ON(cmd->mic_prep_pad_delay || cmd->mic_compute_pad_delay)) | ||
| 426 | return -EINVAL; | ||
| 427 | |||
| 428 | len = sizeof(struct iwl_sta_cfg_cmd_v2); | ||
| 429 | cmd_v2->link_id = cpu_to_le32(__ffs(le32_to_cpu(cmd->link_mask))); | ||
| 430 | } else if (WARN_ON(cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) && | ||
| 431 | cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) && | ||
| 432 | hweight32(le32_to_cpu(cmd->link_mask)) != 1)) { | ||
| 433 | return -EINVAL; | ||
| 434 | } | ||
| 435 | |||
| 436 | ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, len); | ||
| 407 | if (ret) | 437 | if (ret) |
| 408 | IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); | 438 | IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); |
| 409 | return ret; | 439 | return ret; |
| @@ -431,8 +461,8 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, · 21 unmodified lines | |||
| 431 | return -EINVAL; | 461 | return -EINVAL; |
| 432 | 462 | ||
| 433 | cmd.sta_id = cpu_to_le32(fw_id); | 463 | cmd.sta_id = cpu_to_le32(fw_id); |
| 464 | cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id)); | ||
| 434 | cmd.station_type = cpu_to_le32(mld_sta->sta_type); | 465 | cmd.station_type = cpu_to_le32(mld_sta->sta_type); |
| 435 | cmd.link_id = cpu_to_le32(mld_link->fw_id); | ||
| 436 | 466 | ||
| 437 | memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN); | 467 | memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN); |
| 438 | memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN); | 468 | memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN); |
| @@ -498,7 +528,7 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, · 59 unmodified lines | |||
| 498 | return iwl_mld_send_sta_cmd(mld, &cmd); | 528 | return iwl_mld_send_sta_cmd(mld, &cmd); |
| 499 | } | 529 | } |
| 500 | 530 | ||
| 501 | IWL_MLD_ALLOC_FN(link_sta, link_sta) | 531 | static IWL_MLD_ALLOC_FN(link_sta, link_sta) |
| 502 | 532 | ||
| 503 | static int | 533 | static int |
| 504 | iwl_mld_add_link_sta(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta) | 534 | iwl_mld_add_link_sta(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta) |
| @@ -725,14 +755,14 @@ iwl_mld_init_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, · 220 unmodified lines | |||
| 725 | } | 755 | } |
| 726 | 756 | ||
| 727 | int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, | 757 | int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, |
| 728 | struct ieee80211_vif *vif, enum iwl_fw_sta_type type) | 758 | struct ieee80211_vif *vif) |
| 729 | { | 759 | { |
| 730 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); | 760 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); |
| 731 | struct ieee80211_link_sta *link_sta; | 761 | struct ieee80211_link_sta *link_sta; |
| 732 | int link_id; | 762 | int link_id; |
| 733 | int ret; | 763 | int ret; |
| 734 | 764 | ||
| 735 | ret = iwl_mld_init_sta(mld, sta, vif, type); | 765 | ret = iwl_mld_init_sta(mld, sta, vif, STATION_TYPE_PEER); |
| 736 | if (ret) | 766 | if (ret) |
| 737 | return ret; | 767 | return ret; |
| 738 | 768 | ||
| @@ -908,7 +938,7 @@ static void iwl_mld_count_mpdu(struct ieee80211_link_sta *link_sta, int queue, · 169 unmodified lines | |||
| 908 | if (!(mld_vif->emlsr.blocked_reasons & IWL_MLD_EMLSR_BLOCKED_TPT)) | 938 | if (!(mld_vif->emlsr.blocked_reasons & IWL_MLD_EMLSR_BLOCKED_TPT)) |
| 909 | goto unlock; | 939 | goto unlock; |
| 910 | 940 | ||
| 911 | for (int i = 0; i <= IWL_FW_MAX_LINK_ID; i++) | 941 | for (int i = 0; i < IWL_FW_MAX_LINKS; i++) |
| 912 | total_mpdus += tx ? queue_counter->per_link[i].tx : | 942 | total_mpdus += tx ? queue_counter->per_link[i].tx : |
| 913 | queue_counter->per_link[i].rx; | 943 | queue_counter->per_link[i].rx; |
| 914 | 944 | ||
| @@ -982,7 +1012,7 @@ iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld, · 67 unmodified lines | |||
| 982 | return iwl_mld_send_aux_sta_cmd(mld, internal_sta); | 1012 | return iwl_mld_send_aux_sta_cmd(mld, internal_sta); |
| 983 | 1013 | ||
| 984 | cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id); | 1014 | cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id); |
| 985 | cmd.link_id = cpu_to_le32(fw_link_id); | 1015 | cmd.link_mask = cpu_to_le32(BIT(fw_link_id)); |
| 986 | cmd.station_type = cpu_to_le32(internal_sta->sta_type); | 1016 | cmd.station_type = cpu_to_le32(internal_sta->sta_type); |
| 987 | 1017 | ||
| 988 | /* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP. | 1018 | /* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP. |
| @@ -89,7 +89,7 @@ struct iwl_mld_per_link_mpdu_counter { · 88 unmodified lines | |||
| 89 | */ | 89 | */ |
| 90 | struct iwl_mld_per_q_mpdu_counter { | 90 | struct iwl_mld_per_q_mpdu_counter { |
| 91 | spinlock_t lock; | 91 | spinlock_t lock; |
| 92 | struct iwl_mld_per_link_mpdu_counter per_link[IWL_FW_MAX_LINK_ID + 1]; | 92 | struct iwl_mld_per_link_mpdu_counter per_link[IWL_FW_MAX_LINKS]; |
| 93 | unsigned long window_start_time; | 93 | unsigned long window_start_time; |
| 94 | } ____cacheline_aligned_in_smp; | 94 | } ____cacheline_aligned_in_smp; |
| 95 | 95 | ||
| @@ -190,7 +190,7 @@ iwl_mld_link_sta_from_mac80211(struct ieee80211_link_sta *link_sta) · 94 unmodified lines | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, | 192 | int iwl_mld_add_sta(struct iwl_mld *mld, struct ieee80211_sta *sta, |
| 193 | struct ieee80211_vif *vif, enum iwl_fw_sta_type type); | 193 | struct ieee80211_vif *vif); |
| 194 | void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta); | 194 | void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta); |
| 195 | int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld, | 195 | int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld, |
| 196 | struct ieee80211_link_sta *link_sta); | 196 | struct ieee80211_link_sta *link_sta); |
| @@ -369,15 +369,39 @@ out: · 368 unmodified lines | |||
| 369 | static void iwl_mld_update_link_sig(struct ieee80211_vif *vif, int sig, | 369 | static void iwl_mld_update_link_sig(struct ieee80211_vif *vif, int sig, |
| 370 | struct ieee80211_bss_conf *bss_conf) | 370 | struct ieee80211_bss_conf *bss_conf) |
| 371 | { | 371 | { |
| 372 | struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf); | ||
| 372 | struct iwl_mld *mld = iwl_mld_vif_from_mac80211(vif)->mld; | 373 | struct iwl_mld *mld = iwl_mld_vif_from_mac80211(vif)->mld; |
| 373 | int exit_emlsr_thresh; | 374 | int exit_emlsr_thresh; |
| 375 | int last_event; | ||
| 374 | 376 | ||
| 375 | if (sig == 0) { | 377 | if (sig == 0) { |
| 376 | IWL_DEBUG_RX(mld, "RSSI is 0 - skip signal based decision\n"); | 378 | IWL_DEBUG_RX(mld, "RSSI is 0 - skip signal based decision\n"); |
| 377 | return; | 379 | return; |
| 378 | } | 380 | } |
| 379 | 381 | ||
| 380 | /* TODO: task=statistics handle CQM notifications */ | 382 | if (WARN_ON(!link)) |
| 383 | return; | ||
| 384 | |||
| 385 | /* CQM Notification */ | ||
| 386 | if (vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) { | ||
| 387 | int thold = bss_conf->cqm_rssi_thold; | ||
| 388 | int hyst = bss_conf->cqm_rssi_hyst; | ||
| 389 | |||
| 390 | last_event = link->last_cqm_rssi_event; | ||
| 391 | if (thold && sig < thold && | ||
| 392 | (last_event == 0 || sig < last_event - hyst)) { | ||
| 393 | link->last_cqm_rssi_event = sig; | ||
| 394 | ieee80211_cqm_rssi_notify(vif, | ||
| 395 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | ||
| 396 | sig, GFP_KERNEL); | ||
| 397 | } else if (sig > thold && | ||
| 398 | (last_event == 0 || sig > last_event + hyst)) { | ||
| 399 | link->last_cqm_rssi_event = sig; | ||
| 400 | ieee80211_cqm_rssi_notify(vif, | ||
| 401 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | ||
| 402 | sig, GFP_KERNEL); | ||
| 403 | } | ||
| 404 | } | ||
| 381 | 405 | ||
| 382 | if (!iwl_mld_emlsr_active(vif)) { | 406 | if (!iwl_mld_emlsr_active(vif)) { |
| 383 | /* We're not in EMLSR and our signal is bad, | 407 | /* We're not in EMLSR and our signal is bad, |
| @@ -407,14 +431,13 @@ iwl_mld_process_per_link_stats(struct iwl_mld *mld, · 23 unmodified lines | |||
| 407 | u32 total_airtime_usec = 0; | 431 | u32 total_airtime_usec = 0; |
| 408 | 432 | ||
| 409 | for (u32 fw_id = 0; | 433 | for (u32 fw_id = 0; |
| 410 | fw_id < ARRAY_SIZE(mld->fw_id_to_bss_conf); | 434 | fw_id < mld->fw->ucode_capa.num_links; |
| 411 | fw_id++) { | 435 | fw_id++) { |
| 412 | const struct iwl_stats_ntfy_per_link *link_stats; | 436 | const struct iwl_stats_ntfy_per_link *link_stats; |
| 413 | struct ieee80211_bss_conf *bss_conf; | 437 | struct ieee80211_bss_conf *bss_conf; |
| 414 | int sig; | 438 | int sig; |
| 415 | 439 | ||
| 416 | bss_conf = wiphy_dereference(mld->wiphy, | 440 | bss_conf = iwl_mld_fw_id_to_link_conf(mld, fw_id); |
| 417 | mld->fw_id_to_bss_conf[fw_id]); | ||
| 418 | if (!bss_conf || bss_conf->vif->type != NL80211_IFTYPE_STATION) | 441 | if (!bss_conf || bss_conf->vif->type != NL80211_IFTYPE_STATION) |
| 419 | continue; | 442 | continue; |
| 420 | 443 | ||
| @@ -42,7 +42,7 @@ int iwlmld_kunit_test_init(struct kunit *test) · 41 unmodified lines | |||
| 42 | iwl_construct_mld(mld, trans, cfg, fw, hw, NULL); | 42 | iwl_construct_mld(mld, trans, cfg, fw, hw, NULL); |
| 43 | 43 | ||
| 44 | fw->ucode_capa.num_stations = IWL_STATION_COUNT_MAX; | 44 | fw->ucode_capa.num_stations = IWL_STATION_COUNT_MAX; |
| 45 | fw->ucode_capa.num_links = IWL_FW_MAX_LINK_ID + 1; | 45 | fw->ucode_capa.num_links = IWL_FW_MAX_LINKS; |
| 46 | 46 | ||
| 47 | mld->fwrt.trans = trans; | 47 | mld->fwrt.trans = trans; |
| 48 | mld->fwrt.fw = fw; | 48 | mld->fwrt.fw = fw; |
| @@ -68,7 +68,7 @@ int iwlmld_kunit_test_init(struct kunit *test) · 19 unmodified lines | |||
| 68 | return 0; | 68 | return 0; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | IWL_MLD_ALLOC_FN(link, bss_conf) | 71 | static IWL_MLD_ALLOC_FN(link, bss_conf) |
| 72 | 72 | ||
| 73 | static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, | 73 | static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, |
| 74 | struct ieee80211_bss_conf *link, | 74 | struct ieee80211_bss_conf *link, |
| @@ -94,7 +94,7 @@ static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, · 19 unmodified lines | |||
| 94 | rcu_assign_pointer(vif->link_conf[link_id], link); | 94 | rcu_assign_pointer(vif->link_conf[link_id], link); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | IWL_MLD_ALLOC_FN(vif, vif) | 97 | static IWL_MLD_ALLOC_FN(vif, vif) |
| 98 | 98 | ||
| 99 | /* Helper function to add and initialize a VIF for KUnit tests */ | 99 | /* Helper function to add and initialize a VIF for KUnit tests */ |
| 100 | struct ieee80211_vif *iwlmld_kunit_add_vif(bool mlo, enum nl80211_iftype type) | 100 | struct ieee80211_vif *iwlmld_kunit_add_vif(bool mlo, enum nl80211_iftype type) |
| @@ -199,7 +199,7 @@ void iwlmld_kunit_assign_chanctx_to_link(struct ieee80211_vif *vif, · 98 unmodified lines | |||
| 199 | vif->active_links |= BIT(link->link_id); | 199 | vif->active_links |= BIT(link->link_id); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | IWL_MLD_ALLOC_FN(link_sta, link_sta) | 202 | static IWL_MLD_ALLOC_FN(link_sta, link_sta) |
| 203 | 203 | ||
| 204 | static void iwlmld_kunit_add_link_sta(struct ieee80211_sta *sta, | 204 | static void iwlmld_kunit_add_link_sta(struct ieee80211_sta *sta, |
| 205 | struct ieee80211_link_sta *link_sta, | 205 | struct ieee80211_link_sta *link_sta, |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include "hcmd.h" | 9 | #include "hcmd.h" |
| 10 | #include "sta.h" | 10 | #include "sta.h" |
| 11 | #include "phy.h" | 11 | #include "phy.h" |
| 12 | #include "iface.h" | ||
| 12 | 13 | ||
| 13 | #include "fw/api/rs.h" | 14 | #include "fw/api/rs.h" |
| 14 | #include "fw/api/context.h" | 15 | #include "fw/api/context.h" |
| @@ -36,7 +37,8 @@ iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld, · 21 unmodified lines | |||
| 36 | struct ieee80211_vif *vif, | 37 | struct ieee80211_vif *vif, |
| 37 | struct ieee80211_link_sta *link_sta, | 38 | struct ieee80211_link_sta *link_sta, |
| 38 | const struct ieee80211_sta_he_cap *own_he_cap, | 39 | const struct ieee80211_sta_he_cap *own_he_cap, |
| 39 | const struct ieee80211_sta_eht_cap *own_eht_cap) | 40 | const struct ieee80211_sta_eht_cap *own_eht_cap, |
| 41 | const struct ieee80211_sta_uhr_cap *own_uhr_cap) | ||
| 40 | { | 42 | { |
| 41 | struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; | 43 | struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; |
| 42 | struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; | 44 | struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; |
| @@ -90,6 +92,12 @@ iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld, · 47 unmodified lines | |||
| 90 | flags |= IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK; | 92 | flags |= IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK; |
| 91 | } | 93 | } |
| 92 | 94 | ||
| 95 | if (link_sta->uhr_cap.has_uhr && own_uhr_cap && | ||
| 96 | link_sta->uhr_cap.phy.cap & IEEE80211_UHR_PHY_CAP_ELR_RX && | ||
| 97 | own_uhr_cap->phy.cap & IEEE80211_UHR_PHY_CAP_ELR_TX) | ||
| 98 | flags |= IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK | | ||
| 99 | IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK; | ||
| 100 | |||
| 93 | return cpu_to_le16(flags); | 101 | return cpu_to_le16(flags); |
| 94 | } | 102 | } |
| 95 | 103 | ||
| @@ -406,6 +414,7 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, · 310 unmodified lines | |||
| 406 | struct ieee80211_supported_band *sband, | 414 | struct ieee80211_supported_band *sband, |
| 407 | const struct ieee80211_sta_he_cap *own_he_cap, | 415 | const struct ieee80211_sta_he_cap *own_he_cap, |
| 408 | const struct ieee80211_sta_eht_cap *own_eht_cap, | 416 | const struct ieee80211_sta_eht_cap *own_eht_cap, |
| 417 | const struct ieee80211_sta_uhr_cap *own_uhr_cap, | ||
| 409 | struct iwl_tlc_config_cmd *cmd) | 418 | struct iwl_tlc_config_cmd *cmd) |
| 410 | { | 419 | { |
| 411 | int i; | 420 | int i; |
| @@ -423,7 +432,16 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, · 11 unmodified lines | |||
| 423 | cmd->non_ht_rates = cpu_to_le16(non_ht_rates); | 432 | cmd->non_ht_rates = cpu_to_le16(non_ht_rates); |
| 424 | cmd->mode = IWL_TLC_MNG_MODE_NON_HT; | 433 | cmd->mode = IWL_TLC_MNG_MODE_NON_HT; |
| 425 | 434 | ||
| 426 | if (link_sta->eht_cap.has_eht && own_he_cap && own_eht_cap) { | 435 | if (link_sta->uhr_cap.has_uhr && own_uhr_cap) { |
| 436 | cmd->mode = IWL_TLC_MNG_MODE_UHR; | ||
| 437 | /* | ||
| 438 | * FIXME: spec currently inherits from EHT but has no | ||
| 439 | * finer MCS bits. Once that's there, need to add them | ||
| 440 | * to the bitmaps (and maybe copy this to UHR, or so.) | ||
| 441 | */ | ||
| 442 | iwl_mld_fill_eht_rates(vif, link_sta, own_he_cap, | ||
| 443 | own_eht_cap, cmd); | ||
| 444 | } else if (link_sta->eht_cap.has_eht && own_he_cap && own_eht_cap) { | ||
| 427 | cmd->mode = IWL_TLC_MNG_MODE_EHT; | 445 | cmd->mode = IWL_TLC_MNG_MODE_EHT; |
| 428 | iwl_mld_fill_eht_rates(vif, link_sta, own_he_cap, | 446 | iwl_mld_fill_eht_rates(vif, link_sta, own_he_cap, |
| 429 | own_eht_cap, cmd); | 447 | own_eht_cap, cmd); |
| @@ -513,19 +531,23 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, · 83 unmodified lines | |||
| 513 | struct ieee80211_bss_conf *link) | 531 | struct ieee80211_bss_conf *link) |
| 514 | { | 532 | { |
| 515 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); | 533 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); |
| 534 | struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); | ||
| 516 | enum nl80211_band band = link->chanreq.oper.chan->band; | 535 | enum nl80211_band band = link->chanreq.oper.chan->band; |
| 517 | struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; | 536 | struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; |
| 518 | const struct ieee80211_sta_he_cap *own_he_cap = | 537 | const struct ieee80211_sta_he_cap *own_he_cap = |
| 519 | ieee80211_get_he_iftype_cap_vif(sband, vif); | 538 | ieee80211_get_he_iftype_cap_vif(sband, vif); |
| 520 | const struct ieee80211_sta_eht_cap *own_eht_cap = | 539 | const struct ieee80211_sta_eht_cap *own_eht_cap = |
| 521 | ieee80211_get_eht_iftype_cap_vif(sband, vif); | 540 | ieee80211_get_eht_iftype_cap_vif(sband, vif); |
| 541 | const struct ieee80211_sta_uhr_cap *own_uhr_cap = | ||
| 542 | ieee80211_get_uhr_iftype_cap_vif(sband, vif); | ||
| 522 | struct iwl_tlc_config_cmd cmd = { | 543 | struct iwl_tlc_config_cmd cmd = { |
| 523 | /* For AP mode, use 20 MHz until the STA is authorized */ | 544 | /* For AP mode, use 20 MHz until the STA is authorized */ |
| 524 | .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? | 545 | .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? |
| 525 | iwl_mld_fw_bw_from_sta_bw(link_sta) : | 546 | iwl_mld_fw_bw_from_sta_bw(link_sta) : |
| 526 | IWL_TLC_MNG_CH_WIDTH_20MHZ, | 547 | IWL_TLC_MNG_CH_WIDTH_20MHZ, |
| 527 | .flags = iwl_mld_get_tlc_cmd_flags(mld, vif, link_sta, | 548 | .flags = iwl_mld_get_tlc_cmd_flags(mld, vif, link_sta, |
| 528 | own_he_cap, own_eht_cap), | 549 | own_he_cap, own_eht_cap, |
| 550 | own_uhr_cap), | ||
| 529 | .chains = iwl_mld_get_fw_chains(mld), | 551 | .chains = iwl_mld_get_fw_chains(mld), |
| 530 | .sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta), | 552 | .sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta), |
| 531 | .max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len), | 553 | .max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len), |
| @@ -546,7 +568,10 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, · 14 unmodified lines | |||
| 546 | 568 | ||
| 547 | cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id)); | 569 | cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id)); |
| 548 | 570 | ||
| 549 | chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf); | 571 | if (WARN_ON_ONCE(!mld_link)) |
| 572 | return; | ||
| 573 | |||
| 574 | chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx); | ||
| 550 | if (WARN_ON(!chan_ctx)) | 575 | if (WARN_ON(!chan_ctx)) |
| 551 | return; | 576 | return; |
| 552 | 577 | ||
| @@ -555,7 +580,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, · 2 unmodified lines | |||
| 555 | 580 | ||
| 556 | iwl_mld_fill_supp_rates(mld, vif, link_sta, sband, | 581 | iwl_mld_fill_supp_rates(mld, vif, link_sta, sband, |
| 557 | own_he_cap, own_eht_cap, | 582 | own_he_cap, own_eht_cap, |
| 558 | &cmd); | 583 | own_uhr_cap, &cmd); |
| 559 | 584 | ||
| 560 | if (cmd_ver == 6) { | 585 | if (cmd_ver == 6) { |
| 561 | cmd_ptr = &cmd; | 586 | cmd_ptr = &cmd; |
| @@ -638,6 +663,49 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, · 76 unmodified lines | |||
| 638 | iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf); | 663 | iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf); |
| 639 | } | 664 | } |
| 640 | 665 | ||
| 666 | void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 667 | struct ieee80211_bss_conf *link_conf) | ||
| 668 | { | ||
| 669 | struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf); | ||
| 670 | struct ieee80211_chanctx_conf *chan_ctx; | ||
| 671 | int link_id = link_conf->link_id; | ||
| 672 | struct ieee80211_sta *sta; | ||
| 673 | |||
| 674 | lockdep_assert_wiphy(mld->wiphy); | ||
| 675 | |||
| 676 | if (WARN_ON(!mld_link)) | ||
| 677 | return; | ||
| 678 | |||
| 679 | chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx); | ||
| 680 | |||
| 681 | for_each_station(sta, mld->hw) { | ||
| 682 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); | ||
| 683 | struct iwl_mld_link_sta *mld_link_sta; | ||
| 684 | struct ieee80211_link_sta *link_sta; | ||
| 685 | |||
| 686 | if (mld_sta->vif != vif) | ||
| 687 | continue; | ||
| 688 | |||
| 689 | link_sta = link_sta_dereference_protected(sta, link_id); | ||
| 690 | if (!link_sta) | ||
| 691 | continue; | ||
| 692 | |||
| 693 | mld_link_sta = iwl_mld_link_sta_dereference_check(mld_sta, | ||
| 694 | link_id); | ||
| 695 | |||
| 696 | /* In recovery flow, the station may not be (yet) in the | ||
| 697 | * firmware, don't send a TLC command for a station the | ||
| 698 | * firmware does not know. | ||
| 699 | */ | ||
| 700 | if (!mld_link_sta || !mld_link_sta->in_fw) | ||
| 701 | continue; | ||
| 702 | |||
| 703 | if (chan_ctx) | ||
| 704 | iwl_mld_config_tlc_link(mld, vif, link_conf, link_sta); | ||
| 705 | /* TODO: else, remove the TLC object in the firmware */ | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 641 | void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, | 709 | void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, |
| 642 | struct ieee80211_sta *sta) | 710 | struct ieee80211_sta *sta) |
| 643 | { | 711 | { |
| @@ -20,4 +20,7 @@ void iwl_mld_handle_tlc_notif(struct iwl_mld *mld, · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data); | 21 | int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data); |
| 22 | 22 | ||
| 23 | void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif, | ||
| 24 | struct ieee80211_bss_conf *link_conf); | ||
| 25 | |||
| 23 | #endif /* __iwl_mld_tlc_h__ */ | 26 | #endif /* __iwl_mld_tlc_h__ */ |
| @@ -459,23 +459,18 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, · 458 unmodified lines | |||
| 459 | 459 | ||
| 460 | static void iwl_mvm_uats_init(struct iwl_mvm *mvm) | 460 | static void iwl_mvm_uats_init(struct iwl_mvm *mvm) |
| 461 | { | 461 | { |
| 462 | int cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, | ||
| 463 | MCC_ALLOWED_AP_TYPE_CMD); | ||
| 464 | struct iwl_mcc_allowed_ap_type_cmd_v1 cmd = {}; | ||
| 462 | u8 cmd_ver; | 465 | u8 cmd_ver; |
| 463 | int ret; | 466 | int ret; |
| 464 | struct iwl_host_cmd cmd = { | ||
| 465 | .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, | ||
| 466 | MCC_ALLOWED_AP_TYPE_CMD), | ||
| 467 | .flags = 0, | ||
| 468 | .data[0] = &mvm->fwrt.uats_table, | ||
| 469 | .len[0] = sizeof(mvm->fwrt.uats_table), | ||
| 470 | .dataflags[0] = IWL_HCMD_DFL_NOCOPY, | ||
| 471 | }; | ||
| 472 | 467 | ||
| 473 | if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { | 468 | if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { |
| 474 | IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n"); | 469 | IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n"); |
| 475 | return; | 470 | return; |
| 476 | } | 471 | } |
| 477 | 472 | ||
| 478 | cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id, | 473 | cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, |
| 479 | IWL_FW_CMD_VER_UNKNOWN); | 474 | IWL_FW_CMD_VER_UNKNOWN); |
| 480 | if (cmd_ver != 1) { | 475 | if (cmd_ver != 1) { |
| 481 | IWL_DEBUG_RADIO(mvm, | 476 | IWL_DEBUG_RADIO(mvm, |
| @@ -486,10 +481,17 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm) · 4 unmodified lines | |||
| 486 | 481 | ||
| 487 | iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt); | 482 | iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt); |
| 488 | 483 | ||
| 489 | if (!mvm->fwrt.uats_valid) | 484 | if (!mvm->fwrt.ap_type_cmd_valid) |
| 490 | return; | 485 | return; |
| 491 | 486 | ||
| 492 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 487 | BUILD_BUG_ON(sizeof(mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map) != |
| 488 | sizeof(cmd.mcc_to_ap_type_map)); | ||
| 489 | |||
| 490 | memcpy(cmd.mcc_to_ap_type_map, | ||
| 491 | mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map, | ||
| 492 | sizeof(mvm->fwrt.ap_type_cmd.mcc_to_ap_type_map)); | ||
| 493 | |||
| 494 | ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); | ||
| 493 | if (ret < 0) | 495 | if (ret < 0) |
| 494 | IWL_ERR(mvm, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", | 496 | IWL_ERR(mvm, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", |
| 495 | ret); | 497 | ret); |
| @@ -906,7 +908,7 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) · 410 unmodified lines | |||
| 906 | 908 | ||
| 907 | int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) | 909 | int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) |
| 908 | { | 910 | { |
| 909 | union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; | 911 | union iwl_geo_tx_power_profiles_cmd geo_tx_cmd = {}; |
| 910 | struct iwl_geo_tx_power_profiles_resp *resp; | 912 | struct iwl_geo_tx_power_profiles_resp *resp; |
| 911 | u16 len; | 913 | u16 len; |
| 912 | int ret; | 914 | int ret; |
| @@ -958,7 +960,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) · 45 unmodified lines | |||
| 958 | static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) | 960 | static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) |
| 959 | { | 961 | { |
| 960 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); | 962 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); |
| 961 | union iwl_geo_tx_power_profiles_cmd cmd; | 963 | union iwl_geo_tx_power_profiles_cmd cmd = {}; |
| 962 | u16 len; | 964 | u16 len; |
| 963 | u32 n_bands; | 965 | u32 n_bands; |
| 964 | u32 n_profiles; | 966 | u32 n_profiles; |
| @@ -1032,12 +1034,139 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) · 67 unmodified lines | |||
| 1032 | return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); | 1034 | return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); |
| 1033 | } | 1035 | } |
| 1034 | 1036 | ||
| 1037 | static bool iwl_mvm_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, | ||
| 1038 | int subband) | ||
| 1039 | { | ||
| 1040 | s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband]; | ||
| 1041 | |||
| 1042 | if ((subband == 0 && | ||
| 1043 | (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) || | ||
| 1044 | (subband != 0 && | ||
| 1045 | (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) { | ||
| 1046 | IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val); | ||
| 1047 | return false; | ||
| 1048 | } | ||
| 1049 | return true; | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | static int iwl_mvm_fill_ppag_table(struct iwl_fw_runtime *fwrt, | ||
| 1053 | union iwl_ppag_table_cmd *cmd, | ||
| 1054 | int *cmd_size) | ||
| 1055 | { | ||
| 1056 | u8 cmd_ver; | ||
| 1057 | int i, j, num_sub_bands; | ||
| 1058 | s8 *gain; | ||
| 1059 | bool send_ppag_always; | ||
| 1060 | |||
| 1061 | /* many firmware images for JF lie about this */ | ||
| 1062 | if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) == | ||
| 1063 | CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) | ||
| 1064 | return -EOPNOTSUPP; | ||
| 1065 | |||
| 1066 | if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { | ||
| 1067 | IWL_DEBUG_RADIO(fwrt, | ||
| 1068 | "PPAG capability not supported by FW, command not sent.\n"); | ||
| 1069 | return -EINVAL; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, | ||
| 1073 | WIDE_ID(PHY_OPS_GROUP, | ||
| 1074 | PER_PLATFORM_ANT_GAIN_CMD), 1); | ||
| 1075 | /* | ||
| 1076 | * Starting from ver 4, driver needs to send the PPAG CMD regardless | ||
| 1077 | * if PPAG is enabled/disabled or valid/invalid. | ||
| 1078 | */ | ||
| 1079 | send_ppag_always = cmd_ver > 3; | ||
| 1080 | |||
| 1081 | /* Don't send PPAG if it is disabled */ | ||
| 1082 | if (!send_ppag_always && !fwrt->ppag_flags) { | ||
| 1083 | IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); | ||
| 1084 | return -EINVAL; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); | ||
| 1088 | if (cmd_ver == 1) { | ||
| 1089 | num_sub_bands = IWL_NUM_SUB_BANDS_V1; | ||
| 1090 | gain = cmd->v1.gain[0]; | ||
| 1091 | *cmd_size = sizeof(cmd->v1); | ||
| 1092 | cmd->v1.flags = | ||
| 1093 | cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK); | ||
| 1094 | if (fwrt->ppag_bios_rev >= 1) { | ||
| 1095 | /* in this case FW supports revision 0 */ | ||
| 1096 | IWL_DEBUG_RADIO(fwrt, | ||
| 1097 | "PPAG table rev is %d, send truncated table\n", | ||
| 1098 | fwrt->ppag_bios_rev); | ||
| 1099 | } | ||
| 1100 | } else if (cmd_ver == 5) { | ||
| 1101 | num_sub_bands = IWL_NUM_SUB_BANDS_V2; | ||
| 1102 | gain = cmd->v5.gain[0]; | ||
| 1103 | *cmd_size = sizeof(cmd->v5); | ||
| 1104 | cmd->v5.flags = | ||
| 1105 | cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK); | ||
| 1106 | if (fwrt->ppag_bios_rev == 0) { | ||
| 1107 | /* in this case FW supports revisions 1,2 or 3 */ | ||
| 1108 | IWL_DEBUG_RADIO(fwrt, | ||
| 1109 | "PPAG table rev is 0, send padded table\n"); | ||
| 1110 | } | ||
| 1111 | } else if (cmd_ver == 7) { | ||
| 1112 | num_sub_bands = IWL_NUM_SUB_BANDS_V2; | ||
| 1113 | gain = cmd->v7.gain[0]; | ||
| 1114 | *cmd_size = sizeof(cmd->v7); | ||
| 1115 | cmd->v7.ppag_config_info.hdr.table_source = | ||
| 1116 | fwrt->ppag_bios_source; | ||
| 1117 | cmd->v7.ppag_config_info.hdr.table_revision = | ||
| 1118 | fwrt->ppag_bios_rev; | ||
| 1119 | cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); | ||
| 1120 | } else { | ||
| 1121 | IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); | ||
| 1122 | return -EINVAL; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | /* ppag mode */ | ||
| 1126 | IWL_DEBUG_RADIO(fwrt, | ||
| 1127 | "PPAG MODE bits were read from bios: %d\n", | ||
| 1128 | fwrt->ppag_flags); | ||
| 1129 | |||
| 1130 | if (cmd_ver == 1 && | ||
| 1131 | !fw_has_capa(&fwrt->fw->ucode_capa, | ||
| 1132 | IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { | ||
| 1133 | cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); | ||
| 1134 | IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); | ||
| 1135 | } else { | ||
| 1136 | IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /* The 'flags' field is the same in v1 and v5 so we can just | ||
| 1140 | * use v1 to access it. | ||
| 1141 | */ | ||
| 1142 | IWL_DEBUG_RADIO(fwrt, | ||
| 1143 | "PPAG MODE bits going to be sent: %d\n", | ||
| 1144 | (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) : | ||
| 1145 | le32_to_cpu(cmd->v7.ppag_config_info.value)); | ||
| 1146 | |||
| 1147 | for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { | ||
| 1148 | for (j = 0; j < num_sub_bands; j++) { | ||
| 1149 | if (!send_ppag_always && | ||
| 1150 | !iwl_mvm_ppag_value_valid(fwrt, i, j)) | ||
| 1151 | return -EINVAL; | ||
| 1152 | |||
| 1153 | gain[i * num_sub_bands + j] = | ||
| 1154 | fwrt->ppag_chains[i].subbands[j]; | ||
| 1155 | IWL_DEBUG_RADIO(fwrt, | ||
| 1156 | "PPAG table: chain[%d] band[%d]: gain = %d\n", | ||
| 1157 | i, j, gain[i * num_sub_bands + j]); | ||
| 1158 | } | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | return 0; | ||
| 1162 | } | ||
| 1163 | |||
| 1035 | int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) | 1164 | int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) |
| 1036 | { | 1165 | { |
| 1037 | union iwl_ppag_table_cmd cmd; | 1166 | union iwl_ppag_table_cmd cmd; |
| 1038 | int ret, cmd_size; | 1167 | int ret, cmd_size; |
| 1039 | 1168 | ||
| 1040 | ret = iwl_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size); | 1169 | ret = iwl_mvm_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size); |
| 1041 | /* Not supporting PPAG table is a valid scenario */ | 1170 | /* Not supporting PPAG table is a valid scenario */ |
| 1042 | if (ret < 0) | 1171 | if (ret < 0) |
| 1043 | return 0; | 1172 | return 0; |
| @@ -6229,9 +6229,10 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, · 6228 unmodified lines | |||
| 6229 | ret = wait_event_timeout(mvm->rx_sync_waitq, | 6229 | ret = wait_event_timeout(mvm->rx_sync_waitq, |
| 6230 | READ_ONCE(mvm->queue_sync_state) == 0, | 6230 | READ_ONCE(mvm->queue_sync_state) == 0, |
| 6231 | SYNC_RX_QUEUE_TIMEOUT); | 6231 | SYNC_RX_QUEUE_TIMEOUT); |
| 6232 | WARN_ONCE(!ret, "queue sync: failed to sync, state is 0x%lx, cookie %d\n", | 6232 | IWL_FW_CHECK(mvm, !ret, |
| 6233 | mvm->queue_sync_state, | 6233 | "queue sync: failed to sync, state is 0x%lx, cookie %d\n", |
| 6234 | mvm->queue_sync_cookie); | 6234 | mvm->queue_sync_state, |
| 6235 | mvm->queue_sync_cookie); | ||
| 6235 | } | 6236 | } |
| 6236 | 6237 | ||
| 6237 | out: | 6238 | out: |
| @@ -121,52 +121,6 @@ struct iwl_mvm_sta_key_update_data { · 120 unmodified lines | |||
| 121 | int err; | 121 | int err; |
| 122 | }; | 122 | }; |
| 123 | 123 | ||
| 124 | static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw, | ||
| 125 | struct ieee80211_vif *vif, | ||
| 126 | struct ieee80211_sta *sta, | ||
| 127 | struct ieee80211_key_conf *key, | ||
| 128 | void *_data) | ||
| 129 | { | ||
| 130 | u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); | ||
| 131 | struct iwl_mvm_sta_key_update_data *data = _data; | ||
| 132 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 133 | struct iwl_sec_key_cmd cmd = { | ||
| 134 | .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY), | ||
| 135 | .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask), | ||
| 136 | .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask), | ||
| 137 | .u.modify.key_id = cpu_to_le32(key->keyidx), | ||
| 138 | .u.modify.key_flags = | ||
| 139 | cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)), | ||
| 140 | }; | ||
| 141 | int err; | ||
| 142 | |||
| 143 | /* only need to do this for pairwise keys (link_id == -1) */ | ||
| 144 | if (sta != data->sta || key->link_id >= 0) | ||
| 145 | return; | ||
| 146 | |||
| 147 | err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); | ||
| 148 | |||
| 149 | if (err) | ||
| 150 | data->err = err; | ||
| 151 | } | ||
| 152 | |||
| 153 | int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm, | ||
| 154 | struct ieee80211_vif *vif, | ||
| 155 | struct ieee80211_sta *sta, | ||
| 156 | u32 old_sta_mask, | ||
| 157 | u32 new_sta_mask) | ||
| 158 | { | ||
| 159 | struct iwl_mvm_sta_key_update_data data = { | ||
| 160 | .sta = sta, | ||
| 161 | .old_sta_mask = old_sta_mask, | ||
| 162 | .new_sta_mask = new_sta_mask, | ||
| 163 | }; | ||
| 164 | |||
| 165 | ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key, | ||
| 166 | &data); | ||
| 167 | return data.err; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, | 124 | static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, |
| 171 | u32 key_flags, u32 keyidx, u32 flags) | 125 | u32 key_flags, u32 keyidx, u32 flags) |
| 172 | { | 126 | { |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm, | 7 | static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm, |
| 8 | struct ieee80211_vif *vif, | 8 | struct ieee80211_vif *vif, |
| 9 | struct iwl_mac_config_cmd *cmd, | 9 | struct iwl_mac_config_cmd_v3 *cmd, |
| 10 | int cmd_ver) | 10 | int cmd_ver) |
| 11 | { | 11 | { |
| 12 | if (vif->type == NL80211_IFTYPE_AP) { | 12 | if (vif->type == NL80211_IFTYPE_AP) { |
| @@ -24,7 +24,7 @@ static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm, · 11 unmodified lines | |||
| 24 | 24 | ||
| 25 | static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | 25 | static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, |
| 26 | struct ieee80211_vif *vif, | 26 | struct ieee80211_vif *vif, |
| 27 | struct iwl_mac_config_cmd *cmd, | 27 | struct iwl_mac_config_cmd_v3 *cmd, |
| 28 | u32 action) | 28 | u32 action) |
| 29 | { | 29 | { |
| 30 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 30 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| @@ -83,7 +83,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, · 52 unmodified lines | |||
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm, | 85 | static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm, |
| 86 | struct iwl_mac_config_cmd *cmd) | 86 | struct iwl_mac_config_cmd_v3 *cmd) |
| 87 | { | 87 | { |
| 88 | int ret = iwl_mvm_send_cmd_pdu(mvm, | 88 | int ret = iwl_mvm_send_cmd_pdu(mvm, |
| 89 | WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), | 89 | WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), |
| @@ -98,7 +98,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, · 8 unmodified lines | |||
| 98 | struct ieee80211_vif *vif, | 98 | struct ieee80211_vif *vif, |
| 99 | u32 action, bool force_assoc_off) | 99 | u32 action, bool force_assoc_off) |
| 100 | { | 100 | { |
| 101 | struct iwl_mac_config_cmd cmd = {}; | 101 | struct iwl_mac_config_cmd_v3 cmd = {}; |
| 102 | 102 | ||
| 103 | WARN_ON(vif->type != NL80211_IFTYPE_STATION); | 103 | WARN_ON(vif->type != NL80211_IFTYPE_STATION); |
| 104 | 104 | ||
| @@ -151,7 +151,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, · 46 unmodified lines | |||
| 151 | struct ieee80211_vif *vif, | 151 | struct ieee80211_vif *vif, |
| 152 | u32 action) | 152 | u32 action) |
| 153 | { | 153 | { |
| 154 | struct iwl_mac_config_cmd cmd = {}; | 154 | struct iwl_mac_config_cmd_v3 cmd = {}; |
| 155 | 155 | ||
| 156 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); | 156 | WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); |
| 157 | 157 | ||
| @@ -170,7 +170,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, · 12 unmodified lines | |||
| 170 | struct ieee80211_vif *vif, | 170 | struct ieee80211_vif *vif, |
| 171 | u32 action) | 171 | u32 action) |
| 172 | { | 172 | { |
| 173 | struct iwl_mac_config_cmd cmd = {}; | 173 | struct iwl_mac_config_cmd_v3 cmd = {}; |
| 174 | 174 | ||
| 175 | WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); | 175 | WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); |
| 176 | 176 | ||
| @@ -187,7 +187,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, · 10 unmodified lines | |||
| 187 | struct ieee80211_vif *vif, | 187 | struct ieee80211_vif *vif, |
| 188 | u32 action) | 188 | u32 action) |
| 189 | { | 189 | { |
| 190 | struct iwl_mac_config_cmd cmd = {}; | 190 | struct iwl_mac_config_cmd_v3 cmd = {}; |
| 191 | 191 | ||
| 192 | WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); | 192 | WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); |
| 193 | 193 | ||
| @@ -210,7 +210,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm, · 16 unmodified lines | |||
| 210 | u32 action) | 210 | u32 action) |
| 211 | { | 211 | { |
| 212 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 212 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 213 | struct iwl_mac_config_cmd cmd = {}; | 213 | struct iwl_mac_config_cmd_v3 cmd = {}; |
| 214 | 214 | ||
| 215 | WARN_ON(vif->type != NL80211_IFTYPE_AP); | 215 | WARN_ON(vif->type != NL80211_IFTYPE_AP); |
| 216 | 216 | ||
| @@ -286,7 +286,7 @@ int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, · 69 unmodified lines | |||
| 286 | int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 286 | int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 287 | { | 287 | { |
| 288 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 288 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
| 289 | struct iwl_mac_config_cmd cmd = { | 289 | struct iwl_mac_config_cmd_v3 cmd = { |
| 290 | .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), | 290 | .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), |
| 291 | .id_and_color = cpu_to_le32(mvmvif->id), | 291 | .id_and_color = cpu_to_le32(mvmvif->id), |
| 292 | }; | 292 | }; |
| @@ -886,133 +886,6 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 885 unmodified lines | |||
| 886 | return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops); | 886 | return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops); |
| 887 | } | 887 | } |
| 888 | 888 | ||
| 889 | static int | ||
| 890 | iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, | ||
| 891 | struct ieee80211_vif *vif, | ||
| 892 | u16 old_links, u16 new_links, | ||
| 893 | struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) | ||
| 894 | { | ||
| 895 | struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {}; | ||
| 896 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
| 897 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 898 | u16 removed = old_links & ~new_links; | ||
| 899 | u16 added = new_links & ~old_links; | ||
| 900 | int err, i; | ||
| 901 | |||
| 902 | for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { | ||
| 903 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
| 904 | break; | ||
| 905 | |||
| 906 | if (!(added & BIT(i))) | ||
| 907 | continue; | ||
| 908 | new_link[i] = kzalloc_obj(*new_link[i]); | ||
| 909 | if (!new_link[i]) { | ||
| 910 | err = -ENOMEM; | ||
| 911 | goto free; | ||
| 912 | } | ||
| 913 | |||
| 914 | new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; | ||
| 915 | iwl_mvm_init_link(new_link[i]); | ||
| 916 | } | ||
| 917 | |||
| 918 | mutex_lock(&mvm->mutex); | ||
| 919 | |||
| 920 | /* If we're in RESTART flow, the default link wasn't added in | ||
| 921 | * drv_add_interface(), and link[0] doesn't point to it. | ||
| 922 | */ | ||
| 923 | if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, | ||
| 924 | &mvm->status)) { | ||
| 925 | err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf); | ||
| 926 | if (err) | ||
| 927 | goto out_err; | ||
| 928 | mvmvif->link[0] = NULL; | ||
| 929 | } | ||
| 930 | |||
| 931 | for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { | ||
| 932 | if (removed & BIT(i)) { | ||
| 933 | struct ieee80211_bss_conf *link_conf = old[i]; | ||
| 934 | |||
| 935 | err = iwl_mvm_disable_link(mvm, vif, link_conf); | ||
| 936 | if (err) | ||
| 937 | goto out_err; | ||
| 938 | kfree(mvmvif->link[i]); | ||
| 939 | mvmvif->link[i] = NULL; | ||
| 940 | } else if (added & BIT(i)) { | ||
| 941 | struct ieee80211_bss_conf *link_conf; | ||
| 942 | |||
| 943 | link_conf = link_conf_dereference_protected(vif, i); | ||
| 944 | if (WARN_ON(!link_conf)) | ||
| 945 | continue; | ||
| 946 | |||
| 947 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, | ||
| 948 | &mvm->status)) | ||
| 949 | mvmvif->link[i] = new_link[i]; | ||
| 950 | new_link[i] = NULL; | ||
| 951 | err = iwl_mvm_add_link(mvm, vif, link_conf); | ||
| 952 | if (err) | ||
| 953 | goto out_err; | ||
| 954 | } | ||
| 955 | } | ||
| 956 | |||
| 957 | err = 0; | ||
| 958 | if (new_links == 0) { | ||
| 959 | mvmvif->link[0] = &mvmvif->deflink; | ||
| 960 | err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); | ||
| 961 | } | ||
| 962 | |||
| 963 | out_err: | ||
| 964 | /* we really don't have a good way to roll back here ... */ | ||
| 965 | mutex_unlock(&mvm->mutex); | ||
| 966 | |||
| 967 | free: | ||
| 968 | for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) | ||
| 969 | kfree(new_link[i]); | ||
| 970 | return err; | ||
| 971 | } | ||
| 972 | |||
| 973 | static int | ||
| 974 | iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, | ||
| 975 | struct ieee80211_vif *vif, | ||
| 976 | struct ieee80211_sta *sta, | ||
| 977 | u16 old_links, u16 new_links) | ||
| 978 | { | ||
| 979 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
| 980 | |||
| 981 | guard(mvm)(mvm); | ||
| 982 | return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links); | ||
| 983 | } | ||
| 984 | |||
| 985 | static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, | ||
| 986 | struct ieee80211_vif *vif, | ||
| 987 | u16 desired_links) | ||
| 988 | { | ||
| 989 | int n_links = hweight16(desired_links); | ||
| 990 | |||
| 991 | if (n_links <= 1) | ||
| 992 | return true; | ||
| 993 | |||
| 994 | WARN_ON(1); | ||
| 995 | return false; | ||
| 996 | } | ||
| 997 | |||
| 998 | static enum ieee80211_neg_ttlm_res | ||
| 999 | iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
| 1000 | struct ieee80211_neg_ttlm *neg_ttlm) | ||
| 1001 | { | ||
| 1002 | u16 map; | ||
| 1003 | u8 i; | ||
| 1004 | |||
| 1005 | /* Verify all TIDs are mapped to the same links set */ | ||
| 1006 | map = neg_ttlm->downlink[0]; | ||
| 1007 | for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { | ||
| 1008 | if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] || | ||
| 1009 | neg_ttlm->uplink[i] != map) | ||
| 1010 | return NEG_TTLM_RES_REJECT; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | return NEG_TTLM_RES_ACCEPT; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | const struct ieee80211_ops iwl_mvm_mld_hw_ops = { | 889 | const struct ieee80211_ops iwl_mvm_mld_hw_ops = { |
| 1017 | .tx = iwl_mvm_mac_tx, | 890 | .tx = iwl_mvm_mac_tx, |
| 1018 | .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, | 891 | .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, |
| @@ -1102,9 +975,4 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { · 83 unmodified lines | |||
| 1102 | .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, | 975 | .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, |
| 1103 | #endif | 976 | #endif |
| 1104 | .set_hw_timestamp = iwl_mvm_set_hw_timestamp, | 977 | .set_hw_timestamp = iwl_mvm_set_hw_timestamp, |
| 1105 | |||
| 1106 | .change_vif_links = iwl_mvm_mld_change_vif_links, | ||
| 1107 | .change_sta_links = iwl_mvm_mld_change_sta_links, | ||
| 1108 | .can_activate_links = iwl_mvm_mld_can_activate_links, | ||
| 1109 | .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, | ||
| 1110 | }; | 978 | }; |
| @@ -20,7 +20,7 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, · 19 unmodified lines | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, | 22 | static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, |
| 23 | struct iwl_sta_cfg_cmd *cmd) | 23 | struct iwl_sta_cfg_cmd_v2 *cmd) |
| 24 | { | 24 | { |
| 25 | u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); | 25 | u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); |
| 26 | int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ? | 26 | int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ? |
| @@ -41,7 +41,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm, · 14 unmodified lines | |||
| 41 | struct iwl_mvm_int_sta *sta, | 41 | struct iwl_mvm_int_sta *sta, |
| 42 | const u8 *addr, int link_id) | 42 | const u8 *addr, int link_id) |
| 43 | { | 43 | { |
| 44 | struct iwl_sta_cfg_cmd cmd; | 44 | struct iwl_sta_cfg_cmd_v2 cmd; |
| 45 | 45 | ||
| 46 | lockdep_assert_held(&mvm->mutex); | 46 | lockdep_assert_held(&mvm->mutex); |
| 47 | 47 | ||
| @@ -416,7 +416,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta, · 368 unmodified lines | |||
| 416 | struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); | 416 | struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); |
| 417 | struct iwl_mvm_vif_link_info *link_info = | 417 | struct iwl_mvm_vif_link_info *link_info = |
| 418 | mvm_vif->link[link_conf->link_id]; | 418 | mvm_vif->link[link_conf->link_id]; |
| 419 | struct iwl_sta_cfg_cmd cmd = { | 419 | struct iwl_sta_cfg_cmd_v2 cmd = { |
| 420 | .sta_id = cpu_to_le32(mvm_link_sta->sta_id), | 420 | .sta_id = cpu_to_le32(mvm_link_sta->sta_id), |
| 421 | .station_type = cpu_to_le32(mvm_sta->sta_type), | 421 | .station_type = cpu_to_le32(mvm_sta->sta_type), |
| 422 | }; | 422 | }; |
| @@ -913,288 +913,3 @@ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm, · 490 unmodified lines | |||
| 913 | 913 | ||
| 914 | rcu_read_unlock(); | 914 | rcu_read_unlock(); |
| 915 | } | 915 | } |
| 916 | |||
| 917 | static int iwl_mvm_mld_update_sta_queues(struct iwl_mvm *mvm, | ||
| 918 | struct ieee80211_sta *sta, | ||
| 919 | u32 old_sta_mask, | ||
| 920 | u32 new_sta_mask) | ||
| 921 | { | ||
| 922 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | ||
| 923 | struct iwl_scd_queue_cfg_cmd cmd = { | ||
| 924 | .operation = cpu_to_le32(IWL_SCD_QUEUE_MODIFY), | ||
| 925 | .u.modify.old_sta_mask = cpu_to_le32(old_sta_mask), | ||
| 926 | .u.modify.new_sta_mask = cpu_to_le32(new_sta_mask), | ||
| 927 | }; | ||
| 928 | struct iwl_host_cmd hcmd = { | ||
| 929 | .id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD), | ||
| 930 | .len[0] = sizeof(cmd), | ||
| 931 | .data[0] = &cmd | ||
| 932 | }; | ||
| 933 | int tid; | ||
| 934 | int ret; | ||
| 935 | |||
| 936 | lockdep_assert_held(&mvm->mutex); | ||
| 937 | |||
| 938 | for (tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) { | ||
| 939 | struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[tid]; | ||
| 940 | int txq_id = tid_data->txq_id; | ||
| 941 | |||
| 942 | if (txq_id == IWL_MVM_INVALID_QUEUE) | ||
| 943 | continue; | ||
| 944 | |||
| 945 | if (tid == IWL_MAX_TID_COUNT) | ||
| 946 | cmd.u.modify.tid = cpu_to_le32(IWL_MGMT_TID); | ||
| 947 | else | ||
| 948 | cmd.u.modify.tid = cpu_to_le32(tid); | ||
| 949 | |||
| 950 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
| 951 | if (ret) | ||
| 952 | return ret; | ||
| 953 | } | ||
| 954 | |||
| 955 | return 0; | ||
| 956 | } | ||
| 957 | |||
| 958 | static int iwl_mvm_mld_update_sta_baids(struct iwl_mvm *mvm, | ||
| 959 | u32 old_sta_mask, | ||
| 960 | u32 new_sta_mask) | ||
| 961 | { | ||
| 962 | struct iwl_rx_baid_cfg_cmd cmd = { | ||
| 963 | .action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY), | ||
| 964 | .modify.old_sta_id_mask = cpu_to_le32(old_sta_mask), | ||
| 965 | .modify.new_sta_id_mask = cpu_to_le32(new_sta_mask), | ||
| 966 | }; | ||
| 967 | u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD); | ||
| 968 | int baid; | ||
| 969 | |||
| 970 | /* mac80211 will remove sessions later, but we ignore all that */ | ||
| 971 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | ||
| 972 | return 0; | ||
| 973 | |||
| 974 | BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid)); | ||
| 975 | |||
| 976 | for (baid = 0; baid < ARRAY_SIZE(mvm->baid_map); baid++) { | ||
| 977 | struct iwl_mvm_baid_data *data; | ||
| 978 | int ret; | ||
| 979 | |||
| 980 | data = rcu_dereference_protected(mvm->baid_map[baid], | ||
| 981 | lockdep_is_held(&mvm->mutex)); | ||
| 982 | if (!data) | ||
| 983 | continue; | ||
| 984 | |||
| 985 | if (!(data->sta_mask & old_sta_mask)) | ||
| 986 | continue; | ||
| 987 | |||
| 988 | WARN_ONCE(data->sta_mask != old_sta_mask, | ||
| 989 | "BAID data for %d corrupted - expected 0x%x found 0x%x\n", | ||
| 990 | baid, old_sta_mask, data->sta_mask); | ||
| 991 | |||
| 992 | cmd.modify.tid = cpu_to_le32(data->tid); | ||
| 993 | |||
| 994 | ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_SEND_IN_RFKILL, | ||
| 995 | sizeof(cmd), &cmd); | ||
| 996 | data->sta_mask = new_sta_mask; | ||
| 997 | if (ret) | ||
| 998 | return ret; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | static int iwl_mvm_mld_update_sta_resources(struct iwl_mvm *mvm, | ||
| 1005 | struct ieee80211_vif *vif, | ||
| 1006 | struct ieee80211_sta *sta, | ||
| 1007 | u32 old_sta_mask, | ||
| 1008 | u32 new_sta_mask) | ||
| 1009 | { | ||
| 1010 | int ret; | ||
| 1011 | |||
| 1012 | ret = iwl_mvm_mld_update_sta_queues(mvm, sta, | ||
| 1013 | old_sta_mask, | ||
| 1014 | new_sta_mask); | ||
| 1015 | if (ret) | ||
| 1016 | return ret; | ||
| 1017 | |||
| 1018 | ret = iwl_mvm_mld_update_sta_keys(mvm, vif, sta, | ||
| 1019 | old_sta_mask, | ||
| 1020 | new_sta_mask); | ||
| 1021 | if (ret) | ||
| 1022 | return ret; | ||
| 1023 | |||
| 1024 | return iwl_mvm_mld_update_sta_baids(mvm, old_sta_mask, new_sta_mask); | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, | ||
| 1028 | struct ieee80211_vif *vif, | ||
| 1029 | struct ieee80211_sta *sta, | ||
| 1030 | u16 old_links, u16 new_links) | ||
| 1031 | { | ||
| 1032 | struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); | ||
| 1033 | struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); | ||
| 1034 | struct iwl_mvm_link_sta *mvm_sta_link; | ||
| 1035 | struct iwl_mvm_vif_link_info *mvm_vif_link; | ||
| 1036 | unsigned long links_to_add = ~old_links & new_links; | ||
| 1037 | unsigned long links_to_rem = old_links & ~new_links; | ||
| 1038 | unsigned long old_links_long = old_links; | ||
| 1039 | u32 current_sta_mask = 0, sta_mask_added = 0, sta_mask_to_rem = 0; | ||
| 1040 | unsigned long link_sta_added_to_fw = 0, link_sta_allocated = 0; | ||
| 1041 | unsigned int link_id; | ||
| 1042 | int ret; | ||
| 1043 | |||
| 1044 | lockdep_assert_wiphy(mvm->hw->wiphy); | ||
| 1045 | lockdep_assert_held(&mvm->mutex); | ||
| 1046 | |||
| 1047 | for_each_set_bit(link_id, &old_links_long, | ||
| 1048 | IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1049 | mvm_sta_link = | ||
| 1050 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1051 | lockdep_is_held(&mvm->mutex)); | ||
| 1052 | |||
| 1053 | if (WARN_ON(!mvm_sta_link)) { | ||
| 1054 | ret = -EINVAL; | ||
| 1055 | goto err; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | current_sta_mask |= BIT(mvm_sta_link->sta_id); | ||
| 1059 | if (links_to_rem & BIT(link_id)) | ||
| 1060 | sta_mask_to_rem |= BIT(mvm_sta_link->sta_id); | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | if (sta_mask_to_rem) { | ||
| 1064 | ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta, | ||
| 1065 | current_sta_mask, | ||
| 1066 | current_sta_mask & | ||
| 1067 | ~sta_mask_to_rem); | ||
| 1068 | if (WARN_ON(ret)) | ||
| 1069 | goto err; | ||
| 1070 | |||
| 1071 | current_sta_mask &= ~sta_mask_to_rem; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1075 | mvm_sta_link = | ||
| 1076 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1077 | lockdep_is_held(&mvm->mutex)); | ||
| 1078 | mvm_vif_link = mvm_vif->link[link_id]; | ||
| 1079 | |||
| 1080 | if (WARN_ON(!mvm_sta_link || !mvm_vif_link)) { | ||
| 1081 | ret = -EINVAL; | ||
| 1082 | goto err; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id); | ||
| 1086 | if (WARN_ON(ret)) | ||
| 1087 | goto err; | ||
| 1088 | |||
| 1089 | if (vif->type == NL80211_IFTYPE_STATION) | ||
| 1090 | mvm_vif_link->ap_sta_id = IWL_INVALID_STA; | ||
| 1091 | |||
| 1092 | iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1096 | struct ieee80211_bss_conf *link_conf = | ||
| 1097 | link_conf_dereference_protected(vif, link_id); | ||
| 1098 | struct ieee80211_link_sta *link_sta = | ||
| 1099 | link_sta_dereference_protected(sta, link_id); | ||
| 1100 | mvm_vif_link = mvm_vif->link[link_id]; | ||
| 1101 | |||
| 1102 | if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta)) { | ||
| 1103 | ret = -EINVAL; | ||
| 1104 | goto err; | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||
| 1108 | struct iwl_mvm_link_sta *mvm_link_sta = | ||
| 1109 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1110 | lockdep_is_held(&mvm->mutex)); | ||
| 1111 | u32 sta_id; | ||
| 1112 | |||
| 1113 | if (WARN_ON(!mvm_link_sta)) { | ||
| 1114 | ret = -EINVAL; | ||
| 1115 | goto err; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | sta_id = mvm_link_sta->sta_id; | ||
| 1119 | |||
| 1120 | rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); | ||
| 1121 | rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id], | ||
| 1122 | link_sta); | ||
| 1123 | } else { | ||
| 1124 | if (WARN_ON(mvm_sta->link[link_id])) { | ||
| 1125 | ret = -EINVAL; | ||
| 1126 | goto err; | ||
| 1127 | } | ||
| 1128 | ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta, | ||
| 1129 | link_id); | ||
| 1130 | if (WARN_ON(ret)) | ||
| 1131 | goto err; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | link_sta->agg.max_rc_amsdu_len = 1; | ||
| 1135 | ieee80211_sta_recalc_aggregates(sta); | ||
| 1136 | |||
| 1137 | mvm_sta_link = | ||
| 1138 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1139 | lockdep_is_held(&mvm->mutex)); | ||
| 1140 | |||
| 1141 | if (WARN_ON(!mvm_sta_link)) { | ||
| 1142 | ret = -EINVAL; | ||
| 1143 | goto err; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | if (vif->type == NL80211_IFTYPE_STATION) | ||
| 1147 | iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif_link, | ||
| 1148 | mvm_sta_link); | ||
| 1149 | |||
| 1150 | link_sta_allocated |= BIT(link_id); | ||
| 1151 | |||
| 1152 | sta_mask_added |= BIT(mvm_sta_link->sta_id); | ||
| 1153 | |||
| 1154 | ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf, | ||
| 1155 | mvm_sta_link); | ||
| 1156 | if (WARN_ON(ret)) | ||
| 1157 | goto err; | ||
| 1158 | |||
| 1159 | link_sta_added_to_fw |= BIT(link_id); | ||
| 1160 | |||
| 1161 | iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link); | ||
| 1162 | |||
| 1163 | iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta, | ||
| 1164 | link_conf->chanreq.oper.chan->band); | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | if (sta_mask_added) { | ||
| 1168 | ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta, | ||
| 1169 | current_sta_mask, | ||
| 1170 | current_sta_mask | | ||
| 1171 | sta_mask_added); | ||
| 1172 | if (WARN_ON(ret)) | ||
| 1173 | goto err; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | return 0; | ||
| 1177 | |||
| 1178 | err: | ||
| 1179 | /* remove all already allocated stations in FW */ | ||
| 1180 | for_each_set_bit(link_id, &link_sta_added_to_fw, | ||
| 1181 | IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1182 | mvm_sta_link = | ||
| 1183 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1184 | lockdep_is_held(&mvm->mutex)); | ||
| 1185 | |||
| 1186 | iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | /* remove all already allocated station links in driver */ | ||
| 1190 | for_each_set_bit(link_id, &link_sta_allocated, | ||
| 1191 | IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1192 | mvm_sta_link = | ||
| 1193 | rcu_dereference_protected(mvm_sta->link[link_id], | ||
| 1194 | lockdep_is_held(&mvm->mutex)); | ||
| 1195 | |||
| 1196 | iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id); | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | return ret; | ||
| 1200 | } | ||
| @@ -2450,11 +2450,6 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, · 2449 unmodified lines | |||
| 2450 | struct ieee80211_vif *vif, | 2450 | struct ieee80211_vif *vif, |
| 2451 | struct iwl_mvm_vif_link_info *link, | 2451 | struct iwl_mvm_vif_link_info *link, |
| 2452 | unsigned int link_id); | 2452 | unsigned int link_id); |
| 2453 | int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm, | ||
| 2454 | struct ieee80211_vif *vif, | ||
| 2455 | struct ieee80211_sta *sta, | ||
| 2456 | u32 old_sta_mask, | ||
| 2457 | u32 new_sta_mask); | ||
| 2458 | int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, | 2453 | int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, |
| 2459 | struct ieee80211_key_conf *keyconf); | 2454 | struct ieee80211_key_conf *keyconf); |
| 2460 | u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, | 2455 | u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, |
| @@ -304,7 +304,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) · 303 unmodified lines | |||
| 304 | IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n", | 304 | IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n", |
| 305 | PTR_ERR(mvm->ptp_data.ptp_clock)); | 305 | PTR_ERR(mvm->ptp_data.ptp_clock)); |
| 306 | mvm->ptp_data.ptp_clock = NULL; | 306 | mvm->ptp_data.ptp_clock = NULL; |
| 307 | } else if (mvm->ptp_data.ptp_clock) { | 307 | } else if (!mvm->ptp_data.ptp_clock) { |
| 308 | IWL_DEBUG_INFO(mvm, "PTP module unavailable on this kernel\n"); | ||
| 309 | } else { | ||
| 308 | IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", | 310 | IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", |
| 309 | mvm->ptp_data.ptp_clock_info.name, | 311 | mvm->ptp_data.ptp_clock_info.name, |
| 310 | ptp_clock_index(mvm->ptp_data.ptp_clock)); | 312 | ptp_clock_index(mvm->ptp_data.ptp_clock)); |
| @@ -637,10 +637,6 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm, · 636 unmodified lines | |||
| 637 | struct iwl_mvm_link_sta *mvm_sta_link, | 637 | struct iwl_mvm_link_sta *mvm_sta_link, |
| 638 | unsigned int link_id); | 638 | unsigned int link_id); |
| 639 | int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id); | 639 | int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id); |
| 640 | int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, | ||
| 641 | struct ieee80211_vif *vif, | ||
| 642 | struct ieee80211_sta *sta, | ||
| 643 | u16 old_links, u16 new_links); | ||
| 644 | u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, | 640 | u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
| 645 | int filter_link_id); | 641 | int filter_link_id); |
| 646 | int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, | 642 | int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, |
| @@ -234,7 +234,7 @@ void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) · 233 unmodified lines | |||
| 234 | * Also convert TU to msec. | 234 | * Also convert TU to msec. |
| 235 | */ | 235 | */ |
| 236 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); | 236 | delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int); |
| 237 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | 237 | mod_delayed_work(system_percpu_wq, &mvm->tdls_cs.dwork, |
| 238 | msecs_to_jiffies(delay)); | 238 | msecs_to_jiffies(delay)); |
| 239 | 239 | ||
| 240 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); | 240 | iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); |
| @@ -548,7 +548,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, · 307 unmodified lines | |||
| 548 | */ | 548 | */ |
| 549 | delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period * | 549 | delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period * |
| 550 | vif->bss_conf.beacon_int); | 550 | vif->bss_conf.beacon_int); |
| 551 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | 551 | mod_delayed_work(system_percpu_wq, &mvm->tdls_cs.dwork, |
| 552 | msecs_to_jiffies(delay)); | 552 | msecs_to_jiffies(delay)); |
| 553 | return 0; | 553 | return 0; |
| 554 | } | 554 | } |
| @@ -659,6 +659,6 @@ retry: · 104 unmodified lines | |||
| 659 | /* register a timeout in case we don't succeed in switching */ | 659 | /* register a timeout in case we don't succeed in switching */ |
| 660 | delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int * | 660 | delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int * |
| 661 | 1024 / 1000; | 661 | 1024 / 1000; |
| 662 | mod_delayed_work(system_wq, &mvm->tdls_cs.dwork, | 662 | mod_delayed_work(system_percpu_wq, &mvm->tdls_cs.dwork, |
| 663 | msecs_to_jiffies(delay)); | 663 | msecs_to_jiffies(delay)); |
| 664 | } | 664 | } |
| @@ -95,7 +95,9 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) · 94 unmodified lines | |||
| 95 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 95 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) | 98 | static void |
| 99 | _iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans, | ||
| 100 | bool dump_on_timeout) | ||
| 99 | { | 101 | { |
| 100 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 102 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 101 | int ret; | 103 | int ret; |
| @@ -133,7 +135,7 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) · 31 unmodified lines | |||
| 133 | "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n", | 135 | "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n", |
| 134 | inta_hw, reset_done); | 136 | inta_hw, reset_done); |
| 135 | 137 | ||
| 136 | if (!reset_done) { | 138 | if (!reset_done && dump_on_timeout) { |
| 137 | struct iwl_fw_error_dump_mode mode = { | 139 | struct iwl_fw_error_dump_mode mode = { |
| 138 | .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT, | 140 | .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT, |
| 139 | .context = IWL_ERR_CONTEXT_FROM_OPMODE, | 141 | .context = IWL_ERR_CONTEXT_FROM_OPMODE, |
| @@ -147,6 +149,11 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) · 7 unmodified lines | |||
| 147 | trans_pcie->fw_reset_state = FW_RESET_IDLE; | 149 | trans_pcie->fw_reset_state = FW_RESET_IDLE; |
| 148 | } | 150 | } |
| 149 | 151 | ||
| 152 | void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) | ||
| 153 | { | ||
| 154 | _iwl_trans_pcie_fw_reset_handshake(trans, false); | ||
| 155 | } | ||
| 156 | |||
| 150 | static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) | 157 | static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) |
| 151 | { | 158 | { |
| 152 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 159 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| @@ -163,7 +170,7 @@ static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) · 10 unmodified lines | |||
| 163 | * should assume that the firmware is already dead. | 170 | * should assume that the firmware is already dead. |
| 164 | */ | 171 | */ |
| 165 | trans->state = IWL_TRANS_NO_FW; | 172 | trans->state = IWL_TRANS_NO_FW; |
| 166 | iwl_trans_pcie_fw_reset_handshake(trans); | 173 | _iwl_trans_pcie_fw_reset_handshake(trans, true); |
| 167 | } | 174 | } |
| 168 | 175 | ||
| 169 | trans_pcie->is_down = true; | 176 | trans_pcie->is_down = true; |
| @@ -3197,7 +3197,7 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file, · 3196 unmodified lines | |||
| 3197 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) | 3197 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) |
| 3198 | return -EINVAL; | 3198 | return -EINVAL; |
| 3199 | if (mode == IWL_RESET_MODE_TOP_RESET) { | 3199 | if (mode == IWL_RESET_MODE_TOP_RESET) { |
| 3200 | if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) | 3200 | if (!iwl_trans_is_top_reset_supported(trans)) |
| 3201 | return -EINVAL; | 3201 | return -EINVAL; |
| 3202 | trans->request_top_reset = 1; | 3202 | trans->request_top_reset = 1; |
| 3203 | } | 3203 | } |
| @@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw, · 87 unmodified lines | |||
| 88 | IEEE80211_CHANCTX_CHANGE_RADAR))) | 88 | IEEE80211_CHANCTX_CHANGE_RADAR))) |
| 89 | return; | 89 | return; |
| 90 | 90 | ||
| 91 | if (phy->roc_vif) | ||
| 92 | mt76_abort_roc(phy); | ||
| 93 | |||
| 91 | cancel_delayed_work_sync(&phy->mac_work); | 94 | cancel_delayed_work_sync(&phy->mac_work); |
| 92 | 95 | ||
| 93 | mutex_lock(&dev->mutex); | 96 | mutex_lock(&dev->mutex); |
| @@ -155,8 +158,6 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, · 61 unmodified lines | |||
| 155 | { | 158 | { |
| 156 | struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; | 159 | struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; |
| 157 | struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; | 160 | struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; |
| 158 | struct mt76_vif_data *mvif = mlink->mvif; | ||
| 159 | int link_id = link_conf->link_id; | ||
| 160 | struct mt76_phy *phy = ctx->phy; | 161 | struct mt76_phy *phy = ctx->phy; |
| 161 | struct mt76_dev *dev = phy->dev; | 162 | struct mt76_dev *dev = phy->dev; |
| 162 | 163 | ||
| @@ -173,15 +174,8 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, · 10 unmodified lines | |||
| 173 | if (!mlink) | 174 | if (!mlink) |
| 174 | goto out; | 175 | goto out; |
| 175 | 176 | ||
| 176 | if (mlink != (struct mt76_vif_link *)vif->drv_priv) | ||
| 177 | rcu_assign_pointer(mvif->link[link_id], NULL); | ||
| 178 | |||
| 179 | dev->drv->vif_link_remove(phy, vif, link_conf, mlink); | 177 | dev->drv->vif_link_remove(phy, vif, link_conf, mlink); |
| 180 | mlink->ctx = NULL; | 178 | mlink->ctx = NULL; |
| 181 | |||
| 182 | if (mlink != (struct mt76_vif_link *)vif->drv_priv) | ||
| 183 | kfree_rcu(mlink, rcu_head); | ||
| 184 | |||
| 185 | out: | 179 | out: |
| 186 | mutex_unlock(&dev->mutex); | 180 | mutex_unlock(&dev->mutex); |
| 187 | } | 181 | } |
| @@ -254,6 +248,8 @@ skip_link_replace: · 66 unmodified lines | |||
| 254 | continue; | 248 | continue; |
| 255 | 249 | ||
| 256 | mlink->ctx = vifs->new_ctx; | 250 | mlink->ctx = vifs->new_ctx; |
| 251 | if (mlink->beacon_mon_interval) | ||
| 252 | WRITE_ONCE(mlink->beacon_mon_last, jiffies); | ||
| 257 | } | 253 | } |
| 258 | 254 | ||
| 259 | out: | 255 | out: |
| @@ -324,9 +320,11 @@ void mt76_roc_complete(struct mt76_phy *phy) · 64 unmodified lines | |||
| 324 | 320 | ||
| 325 | if (mlink) | 321 | if (mlink) |
| 326 | mlink->mvif->roc_phy = NULL; | 322 | mlink->mvif->roc_phy = NULL; |
| 327 | if (phy->main_chandef.chan && | 323 | if (phy->chanctx && phy->main_chandef.chan && phy->offchannel && |
| 328 | !test_bit(MT76_MCU_RESET, &dev->phy.state)) | 324 | !test_bit(MT76_MCU_RESET, &dev->phy.state)) { |
| 329 | mt76_set_channel(phy, &phy->main_chandef, false); | 325 | __mt76_set_channel(phy, &phy->main_chandef, false); |
| 326 | mt76_offchannel_notify(phy, false); | ||
| 327 | } | ||
| 330 | mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); | 328 | mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); |
| 331 | phy->roc_vif = NULL; | 329 | phy->roc_vif = NULL; |
| 332 | phy->roc_link = NULL; | 330 | phy->roc_link = NULL; |
| @@ -364,12 +362,15 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 31 unmodified lines | |||
| 364 | struct mt76_phy *phy = hw->priv; | 362 | struct mt76_phy *phy = hw->priv; |
| 365 | struct mt76_dev *dev = phy->dev; | 363 | struct mt76_dev *dev = phy->dev; |
| 366 | struct mt76_vif_link *mlink; | 364 | struct mt76_vif_link *mlink; |
| 365 | bool offchannel; | ||
| 367 | int ret = 0; | 366 | int ret = 0; |
| 368 | 367 | ||
| 369 | phy = dev->band_phys[chan->band]; | 368 | phy = dev->band_phys[chan->band]; |
| 370 | if (!phy) | 369 | if (!phy) |
| 371 | return -EINVAL; | 370 | return -EINVAL; |
| 372 | 371 | ||
| 372 | cancel_delayed_work_sync(&phy->mac_work); | ||
| 373 | |||
| 373 | mutex_lock(&dev->mutex); | 374 | mutex_lock(&dev->mutex); |
| 374 | 375 | ||
| 375 | if (phy->roc_vif || dev->scan.phy == phy || | 376 | if (phy->roc_vif || dev->scan.phy == phy || |
| @@ -387,8 +388,18 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 11 unmodified lines | |||
| 387 | mlink->mvif->roc_phy = phy; | 388 | mlink->mvif->roc_phy = phy; |
| 388 | phy->roc_vif = vif; | 389 | phy->roc_vif = vif; |
| 389 | phy->roc_link = mlink; | 390 | phy->roc_link = mlink; |
| 390 | cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); | 391 | |
| 391 | mt76_set_channel(phy, &chandef, true); | 392 | offchannel = mt76_offchannel_chandef(phy, chan, &chandef); |
| 393 | if (offchannel) | ||
| 394 | mt76_offchannel_notify(phy, true); | ||
| 395 | ret = __mt76_set_channel(phy, &chandef, offchannel); | ||
| 396 | if (ret) { | ||
| 397 | mlink->mvif->roc_phy = NULL; | ||
| 398 | phy->roc_vif = NULL; | ||
| 399 | phy->roc_link = NULL; | ||
| 400 | mt76_put_vif_phy_link(phy, vif, mlink); | ||
| 401 | goto out; | ||
| 402 | } | ||
| 392 | ieee80211_ready_on_channel(hw); | 403 | ieee80211_ready_on_channel(hw); |
| 393 | ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, | 404 | ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, |
| 394 | msecs_to_jiffies(duration)); | 405 | msecs_to_jiffies(duration)); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | #include <linux/dma-mapping.h> | 6 | #include <linux/dma-mapping.h> |
| 7 | #include "mt76.h" | 7 | #include "mt76.h" |
| 8 | #include "dma.h" | 8 | #include "dma.h" |
| 9 | #include "mt76_connac.h" | ||
| 9 | 10 | ||
| 10 | static struct mt76_txwi_cache * | 11 | static struct mt76_txwi_cache * |
| 11 | mt76_alloc_txwi(struct mt76_dev *dev) | 12 | mt76_alloc_txwi(struct mt76_dev *dev) |
| @@ -188,16 +189,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q) · 176 unmodified lines | |||
| 188 | static void | 189 | static void |
| 189 | mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) | 190 | mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) |
| 190 | { | 191 | { |
| 191 | Q_WRITE(q, desc_base, q->desc_dma); | 192 | if ((q->flags & MT_QFLAG_WED_RRO_EN) && |
| 192 | if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev)) | 193 | (!is_mt7992(dev) || !mt76_npu_device_active(dev))) |
| 193 | Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); | 194 | Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); |
| 194 | else | 195 | else |
| 195 | Q_WRITE(q, ring_size, q->ndesc); | 196 | Q_WRITE(q, ring_size, q->ndesc); |
| 196 | 197 | ||
| 197 | if (mt76_queue_is_npu_tx(q)) { | 198 | if (mt76_queue_is_npu_tx(q)) { |
| 198 | writel(q->desc_dma, &q->regs->desc_base); | ||
| 199 | writel(q->ndesc, &q->regs->ring_size); | 199 | writel(q->ndesc, &q->regs->ring_size); |
| 200 | writel(q->desc_dma, &q->regs->desc_base); | ||
| 200 | } | 201 | } |
| 202 | |||
| 203 | Q_WRITE(q, desc_base, q->desc_dma); | ||
| 201 | q->head = Q_READ(q, dma_idx); | 204 | q->head = Q_READ(q, dma_idx); |
| 202 | q->tail = q->head; | 205 | q->tail = q->head; |
| 203 | } | 206 | } |
| @@ -663,6 +666,8 @@ mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, · 459 unmodified lines | |||
| 663 | if (!t) | 666 | if (!t) |
| 664 | goto free_skb; | 667 | goto free_skb; |
| 665 | 668 | ||
| 669 | t->phy_idx = phy->band_idx; | ||
| 670 | t->qid = qid; | ||
| 666 | txwi = mt76_get_txwi_ptr(dev, t); | 671 | txwi = mt76_get_txwi_ptr(dev, t); |
| 667 | 672 | ||
| 668 | skb->prev = skb->next = NULL; | 673 | skb->prev = skb->next = NULL; |
| @@ -874,7 +879,16 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) · 205 unmodified lines | |||
| 874 | if (!buf) | 879 | if (!buf) |
| 875 | break; | 880 | break; |
| 876 | 881 | ||
| 877 | if (!mt76_queue_is_wed_rro(q)) | 882 | if (mtk_wed_device_active(&dev->mmio.wed) && |
| 883 | mt76_queue_is_wed_rro(q)) | ||
| 884 | continue; | ||
| 885 | |||
| 886 | if (mt76_npu_device_active(dev) && | ||
| 887 | mt76_queue_is_wed_rro(q)) | ||
| 888 | continue; | ||
| 889 | |||
| 890 | if (!mt76_queue_is_wed_rro_rxdmad_c(q) && | ||
| 891 | !mt76_queue_is_wed_rro_ind(q)) | ||
| 878 | mt76_put_page_pool_buf(buf, false); | 892 | mt76_put_page_pool_buf(buf, false); |
| 879 | } while (1); | 893 | } while (1); |
| 880 | 894 | ||
| @@ -915,6 +929,13 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) · 34 unmodified lines | |||
| 915 | mt76_queue_is_wed_rro(q)) | 929 | mt76_queue_is_wed_rro(q)) |
| 916 | return; | 930 | return; |
| 917 | 931 | ||
| 932 | if (mt76_npu_device_active(dev) && | ||
| 933 | mt76_queue_is_wed_rro(q)) | ||
| 934 | return; | ||
| 935 | |||
| 936 | if (mt76_queue_is_npu_txfree(q)) | ||
| 937 | return; | ||
| 938 | |||
| 918 | mt76_dma_sync_idx(dev, q); | 939 | mt76_dma_sync_idx(dev, q); |
| 919 | if (mt76_queue_is_npu(q)) | 940 | if (mt76_queue_is_npu(q)) |
| 920 | mt76_npu_fill_rx_queue(dev, q); | 941 | mt76_npu_fill_rx_queue(dev, q); |
| @@ -1168,10 +1189,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev) · 247 unmodified lines | |||
| 1168 | mt76_for_each_q_rx(dev, i) { | 1189 | mt76_for_each_q_rx(dev, i) { |
| 1169 | struct mt76_queue *q = &dev->q_rx[i]; | 1190 | struct mt76_queue *q = &dev->q_rx[i]; |
| 1170 | 1191 | ||
| 1171 | if (mtk_wed_device_active(&dev->mmio.wed) && | ||
| 1172 | mt76_queue_is_wed_rro(q)) | ||
| 1173 | continue; | ||
| 1174 | |||
| 1175 | netif_napi_del(&dev->napi[i]); | 1192 | netif_napi_del(&dev->napi[i]); |
| 1176 | mt76_dma_rx_cleanup(dev, q); | 1193 | mt76_dma_rx_cleanup(dev, q); |
| 1177 | 1194 | ||
| @@ -174,7 +174,9 @@ void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, · 173 unmodified lines | |||
| 174 | static inline void | 174 | static inline void |
| 175 | mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) | 175 | mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) |
| 176 | { | 176 | { |
| 177 | dev->queue_ops->reset_q(dev, q, true); | 177 | bool reset_idx = q && !mt76_queue_is_npu_tx(q); |
| 178 | |||
| 179 | dev->queue_ops->reset_q(dev, q, reset_idx); | ||
| 178 | if (mtk_wed_device_active(&dev->mmio.wed)) | 180 | if (mtk_wed_device_active(&dev->mmio.wed)) |
| 179 | mt76_wed_dma_setup(dev, q, true); | 181 | mt76_wed_dma_setup(dev, q, true); |
| 180 | } | 182 | } |
| @@ -9,6 +9,13 @@ · 8 unmodified lines | |||
| 9 | #include <linux/nvmem-consumer.h> | 9 | #include <linux/nvmem-consumer.h> |
| 10 | #include <linux/etherdevice.h> | 10 | #include <linux/etherdevice.h> |
| 11 | #include "mt76.h" | 11 | #include "mt76.h" |
| 12 | #include "mt76_connac.h" | ||
| 13 | |||
| 14 | enum mt76_sku_type { | ||
| 15 | MT76_SKU_RATE, | ||
| 16 | MT76_SKU_BACKOFF, | ||
| 17 | MT76_SKU_BACKOFF_BF_OFFSET, | ||
| 18 | }; | ||
| 12 | 19 | ||
| 13 | static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) | 20 | static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) |
| 14 | { | 21 | { |
| @@ -292,7 +299,6 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) · 277 unmodified lines | |||
| 292 | } | 299 | } |
| 293 | EXPORT_SYMBOL_GPL(mt76_find_channel_node); | 300 | EXPORT_SYMBOL_GPL(mt76_find_channel_node); |
| 294 | 301 | ||
| 295 | |||
| 296 | static s8 | 302 | static s8 |
| 297 | mt76_get_txs_delta(struct device_node *np, u8 nss) | 303 | mt76_get_txs_delta(struct device_node *np, u8 nss) |
| 298 | { | 304 | { |
| @@ -306,9 +312,24 @@ mt76_get_txs_delta(struct device_node *np, u8 nss) · 7 unmodified lines | |||
| 306 | return be32_to_cpu(val[nss - 1]); | 312 | return be32_to_cpu(val[nss - 1]); |
| 307 | } | 313 | } |
| 308 | 314 | ||
| 315 | static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx) | ||
| 316 | { | ||
| 317 | /* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */ | ||
| 318 | static const u8 connac3_table[] = { | ||
| 319 | 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5}; | ||
| 320 | static const u8 connac2_table[] = { | ||
| 321 | 1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0}; | ||
| 322 | |||
| 323 | if (idx >= ARRAY_SIZE(connac3_table)) | ||
| 324 | return 0; | ||
| 325 | |||
| 326 | return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx]; | ||
| 327 | } | ||
| 328 | |||
| 309 | static void | 329 | static void |
| 310 | mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, | 330 | mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, |
| 311 | s8 target_power, s8 nss_delta, s8 *max_power) | 331 | const s8 *data, s8 target_power, s8 nss_delta, |
| 332 | s8 *max_power, int n_chains, enum mt76_sku_type type) | ||
| 312 | { | 333 | { |
| 313 | int i; | 334 | int i; |
| 314 | 335 | ||
| @@ -316,18 +337,51 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, · 1 unmodified line | |||
| 316 | return; | 337 | return; |
| 317 | 338 | ||
| 318 | for (i = 0; i < pwr_len; i++) { | 339 | for (i = 0; i < pwr_len; i++) { |
| 319 | pwr[i] = min_t(s8, target_power, data[i] + nss_delta); | 340 | u8 backoff_chain_idx = i; |
| 341 | int backoff_n_chains; | ||
| 342 | s8 backoff_delta; | ||
| 343 | s8 delta; | ||
| 344 | |||
| 345 | switch (type) { | ||
| 346 | case MT76_SKU_RATE: | ||
| 347 | delta = 0; | ||
| 348 | backoff_delta = 0; | ||
| 349 | backoff_n_chains = 0; | ||
| 350 | break; | ||
| 351 | case MT76_SKU_BACKOFF_BF_OFFSET: | ||
| 352 | backoff_chain_idx += 1; | ||
| 353 | fallthrough; | ||
| 354 | case MT76_SKU_BACKOFF: | ||
| 355 | delta = mt76_tx_power_path_delta(n_chains); | ||
| 356 | backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx); | ||
| 357 | backoff_delta = mt76_tx_power_path_delta(backoff_n_chains); | ||
| 358 | break; | ||
| 359 | default: | ||
| 360 | return; | ||
| 361 | } | ||
| 362 | |||
| 363 | pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta); | ||
| 364 | |||
| 365 | /* used for padding, doesn't need to be considered */ | ||
| 366 | if (data[i] >= S8_MAX - 1) | ||
| 367 | continue; | ||
| 368 | |||
| 369 | /* only consider backoff value for the configured chain number */ | ||
| 370 | if (type != MT76_SKU_RATE && n_chains != backoff_n_chains) | ||
| 371 | continue; | ||
| 372 | |||
| 320 | *max_power = max(*max_power, pwr[i]); | 373 | *max_power = max(*max_power, pwr[i]); |
| 321 | } | 374 | } |
| 322 | } | 375 | } |
| 323 | 376 | ||
| 324 | static void | 377 | static void |
| 325 | mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, | 378 | mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, |
| 326 | const s8 *data, size_t len, s8 target_power, | 379 | s8 pwr_num, const s8 *data, size_t len, |
| 327 | s8 nss_delta) | 380 | s8 target_power, s8 nss_delta, s8 *max_power, |
| 381 | int n_chains, enum mt76_sku_type type) | ||
| 328 | { | 382 | { |
| 383 | static const int connac2_backoff_ru_idx = 2; | ||
| 329 | int i, cur; | 384 | int i, cur; |
| 330 | s8 max_power = -128; | ||
| 331 | 385 | ||
| 332 | if (!data) | 386 | if (!data) |
| 333 | return; | 387 | return; |
| @@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, · 3 unmodified lines | |||
| 337 | if (len < pwr_len + 1) | 391 | if (len < pwr_len + 1) |
| 338 | break; | 392 | break; |
| 339 | 393 | ||
| 340 | mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1, | 394 | /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS |
| 341 | target_power, nss_delta, &max_power); | 395 | * corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss, |
| 396 | * 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss). | ||
| 397 | * | ||
| 398 | * For beamforming tables: | ||
| 399 | * - In connac2, beamforming entries for BW20~BW160 and OFDM | ||
| 400 | * do not include 1T1ss. | ||
| 401 | * - In connac3, beamforming entries for BW20~BW160 and RU | ||
| 402 | * include 1T1ss, but OFDM beamforming does not include 1T1ss. | ||
| 403 | * | ||
| 404 | * Non-beamforming and RU entries for both connac2 and connac3 | ||
| 405 | * include 1T1ss. | ||
| 406 | */ | ||
| 407 | if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF && | ||
| 408 | i > connac2_backoff_ru_idx) | ||
| 409 | type = MT76_SKU_BACKOFF_BF_OFFSET; | ||
| 410 | |||
| 411 | mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1, | ||
| 412 | target_power, nss_delta, max_power, | ||
| 413 | n_chains, type); | ||
| 342 | if (--cur > 0) | 414 | if (--cur > 0) |
| 343 | continue; | 415 | continue; |
| 344 | 416 | ||
| @@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, · 15 unmodified lines | |||
| 360 | struct device_node *np; | 432 | struct device_node *np; |
| 361 | const s8 *val; | 433 | const s8 *val; |
| 362 | char name[16]; | 434 | char name[16]; |
| 363 | u32 mcs_rates = dev->drv->mcs_rates; | ||
| 364 | u32 ru_rates = ARRAY_SIZE(dest->ru[0]); | ||
| 365 | char band; | 435 | char band; |
| 366 | size_t len; | 436 | size_t len; |
| 367 | s8 max_power = 0; | 437 | s8 max_power = -127; |
| 368 | s8 max_power_backoff = -127; | ||
| 369 | s8 txs_delta; | 438 | s8 txs_delta; |
| 370 | int n_chains = hweight16(phy->chainmask); | 439 | int n_chains = hweight16(phy->chainmask); |
| 371 | s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains); | ||
| 372 | |||
| 373 | if (!mcs_rates) | ||
| 374 | mcs_rates = 10; | ||
| 375 | 440 | ||
| 376 | memset(dest, target_power, sizeof(*dest) - sizeof(dest->path)); | 441 | memset(dest, target_power, sizeof(*dest) - sizeof(dest->path)); |
| 377 | memset(&dest->path, 0, sizeof(dest->path)); | 442 | memset(&dest->path, 0, sizeof(dest->path)); |
| @@ -409,46 +474,45 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, · 31 unmodified lines | |||
| 409 | txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); | 474 | txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); |
| 410 | 475 | ||
| 411 | val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); | 476 | val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); |
| 412 | mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, | 477 | mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val, |
| 413 | target_power, txs_delta, &max_power); | 478 | target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); |
| 414 | 479 | ||
| 415 | val = mt76_get_of_array_s8(np, "rates-ofdm", | 480 | val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm)); |
| 416 | &len, ARRAY_SIZE(dest->ofdm)); | 481 | mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val, |
| 417 | mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, | 482 | target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); |
| 418 | target_power, txs_delta, &max_power); | ||
| 419 | 483 | ||
| 420 | val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); | 484 | val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1); |
| 421 | mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), | 485 | mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), |
| 422 | ARRAY_SIZE(dest->mcs), val, len, | 486 | ARRAY_SIZE(dest->mcs), val, len, target_power, |
| 423 | target_power, txs_delta); | 487 | txs_delta, &max_power, n_chains, MT76_SKU_RATE); |
| 424 | 488 | ||
| 425 | val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1); | 489 | val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1); |
| 426 | mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), | 490 | mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]), |
| 427 | ARRAY_SIZE(dest->ru), val, len, | 491 | ARRAY_SIZE(dest->ru), val, len, target_power, |
| 428 | target_power, txs_delta); | 492 | txs_delta, &max_power, n_chains, MT76_SKU_RATE); |
| 429 | 493 | ||
| 430 | max_power_backoff = max_power; | ||
| 431 | val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck)); | 494 | val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck)); |
| 432 | mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val, | 495 | mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val, |
| 433 | target_power_combine, txs_delta, &max_power_backoff); | 496 | target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); |
| 434 | 497 | ||
| 435 | val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm)); | 498 | val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm)); |
| 436 | mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, | 499 | mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, |
| 437 | target_power_combine, txs_delta, &max_power_backoff); | 500 | target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); |
| 438 | 501 | ||
| 439 | val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf)); | 502 | val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf)); |
| 440 | mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, | 503 | mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, |
| 441 | target_power_combine, txs_delta, &max_power_backoff); | 504 | target_power, txs_delta, &max_power, n_chains, |
| 505 | MT76_SKU_BACKOFF_BF_OFFSET); | ||
| 442 | 506 | ||
| 443 | val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1); | 507 | val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1); |
| 444 | mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), | 508 | mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), |
| 445 | ARRAY_SIZE(dest->path.ru), val, len, | 509 | ARRAY_SIZE(dest->path.ru), val, len, target_power, |
| 446 | target_power_combine, txs_delta); | 510 | txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); |
| 447 | 511 | ||
| 448 | val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1); | 512 | val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1); |
| 449 | mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), | 513 | mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), |
| 450 | ARRAY_SIZE(dest->path.ru_bf), val, len, | 514 | ARRAY_SIZE(dest->path.ru_bf), val, len, target_power, |
| 451 | target_power_combine, txs_delta); | 515 | txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); |
| 452 | 516 | ||
| 453 | return max_power; | 517 | return max_power; |
| 454 | } | 518 | } |
| @@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, · 725 unmodified lines | |||
| 726 | INIT_LIST_HEAD(&dev->rxwi_cache); | 726 | INIT_LIST_HEAD(&dev->rxwi_cache); |
| 727 | dev->token_size = dev->drv->token_size; | 727 | dev->token_size = dev->drv->token_size; |
| 728 | INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); | 728 | INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); |
| 729 | spin_lock_init(&dev->scan_lock); | ||
| 729 | 730 | ||
| 730 | for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) | 731 | for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) |
| 731 | skb_queue_head_init(&dev->rx_skb[i]); | 732 | skb_queue_head_init(&dev->rx_skb[i]); |
| @@ -970,6 +971,9 @@ bool mt76_has_tx_pending(struct mt76_phy *phy) · 238 unmodified lines | |||
| 970 | return true; | 971 | return true; |
| 971 | } | 972 | } |
| 972 | 973 | ||
| 974 | if (atomic_read(&phy->mgmt_tx_pending)) | ||
| 975 | return true; | ||
| 976 | |||
| 973 | return false; | 977 | return false; |
| 974 | } | 978 | } |
| 975 | EXPORT_SYMBOL_GPL(mt76_has_tx_pending); | 979 | EXPORT_SYMBOL_GPL(mt76_has_tx_pending); |
| @@ -1030,9 +1034,10 @@ int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, · 54 unmodified lines | |||
| 1030 | int timeout = HZ / 5; | 1034 | int timeout = HZ / 5; |
| 1031 | int ret; | 1035 | int ret; |
| 1032 | 1036 | ||
| 1033 | set_bit(MT76_RESET, &phy->state); | ||
| 1034 | |||
| 1035 | mt76_worker_disable(&dev->tx_worker); | 1037 | mt76_worker_disable(&dev->tx_worker); |
| 1038 | mt76_txq_schedule_pending(phy); | ||
| 1039 | |||
| 1040 | set_bit(MT76_RESET, &phy->state); | ||
| 1036 | wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); | 1041 | wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); |
| 1037 | mt76_update_survey(phy); | 1042 | mt76_update_survey(phy); |
| 1038 | 1043 | ||
| @@ -1716,6 +1721,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) · 677 unmodified lines | |||
| 1716 | 1721 | ||
| 1717 | idr_destroy(&wcid->pktid); | 1722 | idr_destroy(&wcid->pktid); |
| 1718 | 1723 | ||
| 1724 | /* Remove from sta_poll_list to prevent list corruption after reset. | ||
| 1725 | * Without this, mt76_reset_device() reinitializes sta_poll_list but | ||
| 1726 | * leaves wcid->poll_list with stale pointers, causing list corruption | ||
| 1727 | * when mt76_wcid_add_poll() checks list_empty(). | ||
| 1728 | */ | ||
| 1729 | spin_lock_bh(&dev->sta_poll_lock); | ||
| 1730 | if (!list_empty(&wcid->poll_list)) | ||
| 1731 | list_del_init(&wcid->poll_list); | ||
| 1732 | spin_unlock_bh(&dev->sta_poll_lock); | ||
| 1733 | |||
| 1719 | spin_lock_bh(&phy->tx_lock); | 1734 | spin_lock_bh(&phy->tx_lock); |
| 1720 | 1735 | ||
| 1721 | if (!list_empty(&wcid->tx_list)) | 1736 | if (!list_empty(&wcid->tx_list)) |
| @@ -2121,3 +2136,214 @@ u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links) · 399 unmodified lines | |||
| 2121 | return sel_links; | 2136 | return sel_links; |
| 2122 | } | 2137 | } |
| 2123 | EXPORT_SYMBOL_GPL(mt76_select_links); | 2138 | EXPORT_SYMBOL_GPL(mt76_select_links); |
| 2139 | |||
| 2140 | struct mt76_offchannel_cb_data { | ||
| 2141 | struct mt76_phy *phy; | ||
| 2142 | bool offchannel; | ||
| 2143 | }; | ||
| 2144 | |||
| 2145 | static void | ||
| 2146 | mt76_offchannel_send_nullfunc(struct mt76_offchannel_cb_data *data, | ||
| 2147 | struct ieee80211_vif *vif, int link_id) | ||
| 2148 | { | ||
| 2149 | struct mt76_phy *phy = data->phy; | ||
| 2150 | struct ieee80211_tx_info *info; | ||
| 2151 | struct ieee80211_sta *sta = NULL; | ||
| 2152 | struct ieee80211_hdr *hdr; | ||
| 2153 | struct mt76_wcid *wcid; | ||
| 2154 | struct sk_buff *skb; | ||
| 2155 | |||
| 2156 | skb = ieee80211_nullfunc_get(phy->hw, vif, link_id, true); | ||
| 2157 | if (!skb) | ||
| 2158 | return; | ||
| 2159 | |||
| 2160 | hdr = (struct ieee80211_hdr *)skb->data; | ||
| 2161 | if (data->offchannel) | ||
| 2162 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
| 2163 | |||
| 2164 | skb->priority = 7; | ||
| 2165 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | ||
| 2166 | |||
| 2167 | if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, | ||
| 2168 | phy->main_chandef.chan->band, | ||
| 2169 | &sta)) | ||
| 2170 | return; | ||
| 2171 | |||
| 2172 | if (sta) | ||
| 2173 | wcid = (struct mt76_wcid *)sta->drv_priv; | ||
| 2174 | else | ||
| 2175 | wcid = ((struct mt76_vif_link *)vif->drv_priv)->wcid; | ||
| 2176 | |||
| 2177 | if (link_id >= 0) { | ||
| 2178 | info = IEEE80211_SKB_CB(skb); | ||
| 2179 | info->control.flags &= ~IEEE80211_TX_CTRL_MLO_LINK; | ||
| 2180 | info->control.flags |= | ||
| 2181 | u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); | ||
| 2182 | } | ||
| 2183 | |||
| 2184 | mt76_tx(phy, sta, wcid, skb); | ||
| 2185 | } | ||
| 2186 | |||
| 2187 | static void | ||
| 2188 | mt76_offchannel_notify_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) | ||
| 2189 | { | ||
| 2190 | struct mt76_offchannel_cb_data *data = _data; | ||
| 2191 | struct mt76_vif_link *mlink; | ||
| 2192 | struct mt76_vif_data *mvif; | ||
| 2193 | int link_id; | ||
| 2194 | |||
| 2195 | if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) | ||
| 2196 | return; | ||
| 2197 | |||
| 2198 | mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2199 | mvif = mlink->mvif; | ||
| 2200 | |||
| 2201 | if (!ieee80211_vif_is_mld(vif)) { | ||
| 2202 | if (mt76_vif_link_phy(mlink) == data->phy) { | ||
| 2203 | if (!data->offchannel && mlink->beacon_mon_interval) | ||
| 2204 | WRITE_ONCE(mlink->beacon_mon_last, jiffies); | ||
| 2205 | mt76_offchannel_send_nullfunc(data, vif, -1); | ||
| 2206 | } | ||
| 2207 | return; | ||
| 2208 | } | ||
| 2209 | |||
| 2210 | for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { | ||
| 2211 | if (link_id == mvif->deflink_id) | ||
| 2212 | mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2213 | else | ||
| 2214 | mlink = rcu_dereference(mvif->link[link_id]); | ||
| 2215 | if (!mlink) | ||
| 2216 | continue; | ||
| 2217 | if (mt76_vif_link_phy(mlink) != data->phy) | ||
| 2218 | continue; | ||
| 2219 | |||
| 2220 | if (!data->offchannel && mlink->beacon_mon_interval) | ||
| 2221 | WRITE_ONCE(mlink->beacon_mon_last, jiffies); | ||
| 2222 | |||
| 2223 | mt76_offchannel_send_nullfunc(data, vif, link_id); | ||
| 2224 | } | ||
| 2225 | } | ||
| 2226 | |||
| 2227 | void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel) | ||
| 2228 | { | ||
| 2229 | struct mt76_offchannel_cb_data data = { | ||
| 2230 | .phy = phy, | ||
| 2231 | .offchannel = offchannel, | ||
| 2232 | }; | ||
| 2233 | |||
| 2234 | if (!phy->num_sta) | ||
| 2235 | return; | ||
| 2236 | |||
| 2237 | local_bh_disable(); | ||
| 2238 | ieee80211_iterate_active_interfaces_atomic(phy->hw, | ||
| 2239 | IEEE80211_IFACE_ITER_NORMAL, | ||
| 2240 | mt76_offchannel_notify_iter, &data); | ||
| 2241 | local_bh_enable(); | ||
| 2242 | } | ||
| 2243 | EXPORT_SYMBOL_GPL(mt76_offchannel_notify); | ||
| 2244 | |||
| 2245 | struct mt76_rx_beacon_data { | ||
| 2246 | struct mt76_phy *phy; | ||
| 2247 | const u8 *bssid; | ||
| 2248 | }; | ||
| 2249 | |||
| 2250 | static void mt76_rx_beacon_iter(void *_data, u8 *mac, | ||
| 2251 | struct ieee80211_vif *vif) | ||
| 2252 | { | ||
| 2253 | struct mt76_rx_beacon_data *data = _data; | ||
| 2254 | struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2255 | struct mt76_vif_data *mvif = mlink->mvif; | ||
| 2256 | int link_id; | ||
| 2257 | |||
| 2258 | if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) | ||
| 2259 | return; | ||
| 2260 | |||
| 2261 | for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { | ||
| 2262 | struct ieee80211_bss_conf *link_conf; | ||
| 2263 | |||
| 2264 | if (link_id == mvif->deflink_id) | ||
| 2265 | mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2266 | else | ||
| 2267 | mlink = rcu_dereference(mvif->link[link_id]); | ||
| 2268 | if (!mlink || !mlink->beacon_mon_interval) | ||
| 2269 | continue; | ||
| 2270 | |||
| 2271 | if (mt76_vif_link_phy(mlink) != data->phy) | ||
| 2272 | continue; | ||
| 2273 | |||
| 2274 | link_conf = rcu_dereference(vif->link_conf[link_id]); | ||
| 2275 | if (!link_conf) | ||
| 2276 | continue; | ||
| 2277 | |||
| 2278 | if (!ether_addr_equal(link_conf->bssid, data->bssid) && | ||
| 2279 | (!link_conf->nontransmitted || | ||
| 2280 | !ether_addr_equal(link_conf->transmitter_bssid, | ||
| 2281 | data->bssid))) | ||
| 2282 | continue; | ||
| 2283 | |||
| 2284 | WRITE_ONCE(mlink->beacon_mon_last, jiffies); | ||
| 2285 | } | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb) | ||
| 2289 | { | ||
| 2290 | struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; | ||
| 2291 | struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); | ||
| 2292 | struct mt76_rx_beacon_data data = { | ||
| 2293 | .phy = phy, | ||
| 2294 | .bssid = hdr->addr3, | ||
| 2295 | }; | ||
| 2296 | |||
| 2297 | mt76_scan_rx_beacon(phy->dev, phy->chandef.chan); | ||
| 2298 | |||
| 2299 | if (!phy->num_sta) | ||
| 2300 | return; | ||
| 2301 | |||
| 2302 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_ONLY_MONITOR)) | ||
| 2303 | return; | ||
| 2304 | |||
| 2305 | ieee80211_iterate_active_interfaces_atomic(phy->hw, | ||
| 2306 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 2307 | mt76_rx_beacon_iter, &data); | ||
| 2308 | } | ||
| 2309 | EXPORT_SYMBOL_GPL(mt76_rx_beacon); | ||
| 2310 | |||
| 2311 | static void mt76_beacon_mon_iter(void *data, u8 *mac, | ||
| 2312 | struct ieee80211_vif *vif) | ||
| 2313 | { | ||
| 2314 | struct mt76_phy *phy = data; | ||
| 2315 | struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2316 | struct mt76_vif_data *mvif = mlink->mvif; | ||
| 2317 | int link_id; | ||
| 2318 | |||
| 2319 | if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) | ||
| 2320 | return; | ||
| 2321 | |||
| 2322 | for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { | ||
| 2323 | if (link_id == mvif->deflink_id) | ||
| 2324 | mlink = (struct mt76_vif_link *)vif->drv_priv; | ||
| 2325 | else | ||
| 2326 | mlink = rcu_dereference(mvif->link[link_id]); | ||
| 2327 | if (!mlink || !mlink->beacon_mon_interval) | ||
| 2328 | continue; | ||
| 2329 | |||
| 2330 | if (mt76_vif_link_phy(mlink) != phy) | ||
| 2331 | continue; | ||
| 2332 | |||
| 2333 | if (time_after(jiffies, | ||
| 2334 | READ_ONCE(mlink->beacon_mon_last) + | ||
| 2335 | MT76_BEACON_MON_MAX_MISS * mlink->beacon_mon_interval)) | ||
| 2336 | ieee80211_beacon_loss(vif); | ||
| 2337 | } | ||
| 2338 | } | ||
| 2339 | |||
| 2340 | void mt76_beacon_mon_check(struct mt76_phy *phy) | ||
| 2341 | { | ||
| 2342 | if (phy->offchannel) | ||
| 2343 | return; | ||
| 2344 | |||
| 2345 | ieee80211_iterate_active_interfaces_atomic(phy->hw, | ||
| 2346 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 2347 | mt76_beacon_mon_iter, phy); | ||
| 2348 | } | ||
| 2349 | EXPORT_SYMBOL_GPL(mt76_beacon_mon_check); | ||
| @@ -98,7 +98,7 @@ retry: · 97 unmodified lines | |||
| 98 | /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ | 98 | /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ |
| 99 | if (orig_skb) | 99 | if (orig_skb) |
| 100 | skb_get(orig_skb); | 100 | skb_get(orig_skb); |
| 101 | ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); | 101 | ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, wait_resp ? &seq : NULL); |
| 102 | if (ret < 0) | 102 | if (ret < 0) |
| 103 | goto out; | 103 | goto out; |
| 104 | 104 | ||
| @@ -55,6 +55,8 @@ · 54 unmodified lines | |||
| 55 | FIELD_PREP(MT_QFLAG_WED_RING, _n)) | 55 | FIELD_PREP(MT_QFLAG_WED_RING, _n)) |
| 56 | #define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n) | 56 | #define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n) |
| 57 | #define MT_NPU_Q_RX(_n) __MT_NPU_Q(MT76_WED_Q_RX, _n) | 57 | #define MT_NPU_Q_RX(_n) __MT_NPU_Q(MT76_WED_Q_RX, _n) |
| 58 | #define MT_NPU_Q_TXFREE(_n) (FIELD_PREP(MT_QFLAG_WED_TYPE, MT76_WED_Q_TXFREE) | \ | ||
| 59 | FIELD_PREP(MT_QFLAG_WED_RING, _n)) | ||
| 58 | 60 | ||
| 59 | struct mt76_dev; | 61 | struct mt76_dev; |
| 60 | struct mt76_phy; | 62 | struct mt76_phy; |
| @@ -362,6 +364,7 @@ enum mt76_wcid_flags { · 301 unmodified lines | |||
| 362 | }; | 364 | }; |
| 363 | 365 | ||
| 364 | #define MT76_N_WCIDS 1088 | 366 | #define MT76_N_WCIDS 1088 |
| 367 | #define MT76_BEACON_MON_MAX_MISS 7 | ||
| 365 | 368 | ||
| 366 | /* stored in ieee80211_tx_info::hw_queue */ | 369 | /* stored in ieee80211_tx_info::hw_queue */ |
| 367 | #define MT_TX_HW_QUEUE_PHY GENMASK(3, 2) | 370 | #define MT_TX_HW_QUEUE_PHY GENMASK(3, 2) |
| @@ -448,6 +451,7 @@ struct mt76_txwi_cache { · 80 unmodified lines | |||
| 448 | }; | 451 | }; |
| 449 | 452 | ||
| 450 | u8 qid; | 453 | u8 qid; |
| 454 | u8 phy_idx; | ||
| 451 | }; | 455 | }; |
| 452 | 456 | ||
| 453 | struct mt76_rx_tid { | 457 | struct mt76_rx_tid { |
| @@ -540,7 +544,6 @@ struct mt76_driver_ops { · 86 unmodified lines | |||
| 540 | u32 survey_flags; | 544 | u32 survey_flags; |
| 541 | u16 txwi_size; | 545 | u16 txwi_size; |
| 542 | u16 token_size; | 546 | u16 token_size; |
| 543 | u8 mcs_rates; | ||
| 544 | 547 | ||
| 545 | unsigned int link_data_size; | 548 | unsigned int link_data_size; |
| 546 | 549 | ||
| @@ -831,6 +834,8 @@ struct mt76_vif_link { · 284 unmodified lines | |||
| 831 | u8 mcast_rates_idx; | 834 | u8 mcast_rates_idx; |
| 832 | u8 beacon_rates_idx; | 835 | u8 beacon_rates_idx; |
| 833 | bool offchannel; | 836 | bool offchannel; |
| 837 | unsigned long beacon_mon_last; | ||
| 838 | u16 beacon_mon_interval; | ||
| 834 | struct ieee80211_chanctx_conf *ctx; | 839 | struct ieee80211_chanctx_conf *ctx; |
| 835 | struct mt76_wcid *wcid; | 840 | struct mt76_wcid *wcid; |
| 836 | struct mt76_vif_data *mvif; | 841 | struct mt76_vif_data *mvif; |
| @@ -859,6 +864,8 @@ struct mt76_phy { · 22 unmodified lines | |||
| 859 | struct list_head tx_list; | 864 | struct list_head tx_list; |
| 860 | struct mt76_queue *q_tx[__MT_TXQ_MAX]; | 865 | struct mt76_queue *q_tx[__MT_TXQ_MAX]; |
| 861 | 866 | ||
| 867 | atomic_t mgmt_tx_pending; | ||
| 868 | |||
| 862 | struct cfg80211_chan_def chandef; | 869 | struct cfg80211_chan_def chandef; |
| 863 | struct cfg80211_chan_def main_chandef; | 870 | struct cfg80211_chan_def main_chandef; |
| 864 | bool offchannel; | 871 | bool offchannel; |
| @@ -1002,6 +1009,7 @@ struct mt76_dev { · 137 unmodified lines | |||
| 1002 | u32 rxfilter; | 1009 | u32 rxfilter; |
| 1003 | 1010 | ||
| 1004 | struct delayed_work scan_work; | 1011 | struct delayed_work scan_work; |
| 1012 | spinlock_t scan_lock; | ||
| 1005 | struct { | 1013 | struct { |
| 1006 | struct cfg80211_scan_request *req; | 1014 | struct cfg80211_scan_request *req; |
| 1007 | struct ieee80211_channel *chan; | 1015 | struct ieee80211_channel *chan; |
| @@ -1009,6 +1017,8 @@ struct mt76_dev { · 1 unmodified line | |||
| 1009 | struct mt76_vif_link *mlink; | 1017 | struct mt76_vif_link *mlink; |
| 1010 | struct mt76_phy *phy; | 1018 | struct mt76_phy *phy; |
| 1011 | int chan_idx; | 1019 | int chan_idx; |
| 1020 | bool beacon_wait; | ||
| 1021 | bool beacon_received; | ||
| 1012 | } scan; | 1022 | } scan; |
| 1013 | 1023 | ||
| 1014 | #ifdef CONFIG_NL80211_TESTMODE | 1024 | #ifdef CONFIG_NL80211_TESTMODE |
| @@ -1518,6 +1528,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, · 503 unmodified lines | |||
| 1518 | void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); | 1528 | void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); |
| 1519 | void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); | 1529 | void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); |
| 1520 | void mt76_txq_schedule_all(struct mt76_phy *phy); | 1530 | void mt76_txq_schedule_all(struct mt76_phy *phy); |
| 1531 | void mt76_txq_schedule_pending(struct mt76_phy *phy); | ||
| 1521 | void mt76_tx_worker_run(struct mt76_dev *dev); | 1532 | void mt76_tx_worker_run(struct mt76_dev *dev); |
| 1522 | void mt76_tx_worker(struct mt76_worker *w); | 1533 | void mt76_tx_worker(struct mt76_worker *w); |
| 1523 | void mt76_release_buffered_frames(struct ieee80211_hw *hw, | 1534 | void mt76_release_buffered_frames(struct ieee80211_hw *hw, |
| @@ -1596,6 +1607,9 @@ int mt76_get_rate(struct mt76_dev *dev, · 72 unmodified lines | |||
| 1596 | int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1607 | int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1597 | struct ieee80211_scan_request *hw_req); | 1608 | struct ieee80211_scan_request *hw_req); |
| 1598 | void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 1609 | void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
| 1610 | void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan); | ||
| 1611 | void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb); | ||
| 1612 | void mt76_beacon_mon_check(struct mt76_phy *phy); | ||
| 1599 | void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1613 | void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1600 | const u8 *mac); | 1614 | const u8 *mac); |
| 1601 | void mt76_sw_scan_complete(struct ieee80211_hw *hw, | 1615 | void mt76_sw_scan_complete(struct ieee80211_hw *hw, |
| @@ -1649,6 +1663,9 @@ void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index); · 47 unmodified lines | |||
| 1649 | int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 1663 | int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1650 | struct net_device *dev, enum tc_setup_type type, | 1664 | struct net_device *dev, enum tc_setup_type type, |
| 1651 | void *type_data); | 1665 | void *type_data); |
| 1666 | int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, | ||
| 1667 | u32 direction, u32 i_count_addr, | ||
| 1668 | u32 o_status_addr, u32 o_count_addr); | ||
| 1652 | #else | 1669 | #else |
| 1653 | static inline void mt76_npu_check_ppe(struct mt76_dev *dev, | 1670 | static inline void mt76_npu_check_ppe(struct mt76_dev *dev, |
| 1654 | struct sk_buff *skb, u32 info) | 1671 | struct sk_buff *skb, u32 info) |
| @@ -1707,6 +1724,13 @@ static inline int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, · 52 unmodified lines | |||
| 1707 | { | 1724 | { |
| 1708 | return -EOPNOTSUPP; | 1725 | return -EOPNOTSUPP; |
| 1709 | } | 1726 | } |
| 1727 | |||
| 1728 | static inline int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, | ||
| 1729 | u32 direction, u32 i_count_addr, | ||
| 1730 | u32 o_status_addr, u32 o_count_addr) | ||
| 1731 | { | ||
| 1732 | return -EOPNOTSUPP; | ||
| 1733 | } | ||
| 1710 | #endif /* CONFIG_MT76_NPU */ | 1734 | #endif /* CONFIG_MT76_NPU */ |
| 1711 | 1735 | ||
| 1712 | static inline bool mt76_npu_device_active(struct mt76_dev *dev) | 1736 | static inline bool mt76_npu_device_active(struct mt76_dev *dev) |
| @@ -1775,6 +1799,18 @@ void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, · 62 unmodified lines | |||
| 1775 | struct mt76_queue_entry *e); | 1799 | struct mt76_queue_entry *e); |
| 1776 | int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, | 1800 | int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, |
| 1777 | bool offchannel); | 1801 | bool offchannel); |
| 1802 | |||
| 1803 | static inline bool | ||
| 1804 | mt76_offchannel_chandef(struct mt76_phy *phy, struct ieee80211_channel *chan, | ||
| 1805 | struct cfg80211_chan_def *chandef) | ||
| 1806 | { | ||
| 1807 | cfg80211_chandef_create(chandef, chan, NL80211_CHAN_HT20); | ||
| 1808 | if (phy->main_chandef.chan != chan) | ||
| 1809 | return true; | ||
| 1810 | |||
| 1811 | *chandef = phy->main_chandef; | ||
| 1812 | return false; | ||
| 1813 | } | ||
| 1778 | int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, | 1814 | int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, |
| 1779 | bool offchannel); | 1815 | bool offchannel); |
| 1780 | void mt76_scan_work(struct work_struct *work); | 1816 | void mt76_scan_work(struct work_struct *work); |
| @@ -1786,6 +1822,7 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, · 5 unmodified lines | |||
| 1786 | struct ieee80211_vif *vif); | 1822 | struct ieee80211_vif *vif); |
| 1787 | void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, | 1823 | void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, |
| 1788 | struct mt76_vif_link *mlink); | 1824 | struct mt76_vif_link *mlink); |
| 1825 | void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel); | ||
| 1789 | 1826 | ||
| 1790 | /* usb */ | 1827 | /* usb */ |
| 1791 | static inline bool mt76u_urb_error(struct urb *urb) | 1828 | static inline bool mt76u_urb_error(struct urb *urb) |
| @@ -1993,6 +2030,14 @@ static inline bool mt76_queue_is_npu_rx(struct mt76_queue *q) · 201 unmodified lines | |||
| 1993 | FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; | 2030 | FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; |
| 1994 | } | 2031 | } |
| 1995 | 2032 | ||
| 2033 | static inline bool mt76_queue_is_npu_txfree(struct mt76_queue *q) | ||
| 2034 | { | ||
| 2035 | if (q->flags & MT_QFLAG_WED) | ||
| 2036 | return false; | ||
| 2037 | |||
| 2038 | return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; | ||
| 2039 | } | ||
| 2040 | |||
| 1996 | struct mt76_txwi_cache * | 2041 | struct mt76_txwi_cache * |
| 1997 | mt76_token_release(struct mt76_dev *dev, int token, bool *wake); | 2042 | mt76_token_release(struct mt76_dev *dev, int token, bool *wake); |
| 1998 | int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi); | 2043 | int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi); |
| @@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, · 1166 unmodified lines | |||
| 1167 | } | 1167 | } |
| 1168 | EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); | 1168 | EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); |
| 1169 | 1169 | ||
| 1170 | void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, | ||
| 1171 | struct ieee80211_vif *vif, bool enable) | ||
| 1172 | { | ||
| 1173 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | ||
| 1174 | u32 addr; | ||
| 1175 | |||
| 1176 | addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; | ||
| 1177 | |||
| 1178 | if (enable) | ||
| 1179 | mt76_set(dev, addr, MT_WTBL_W3_RTS); | ||
| 1180 | else | ||
| 1181 | mt76_clear(dev, addr, MT_WTBL_W3_RTS); | ||
| 1182 | } | ||
| 1183 | EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); | ||
| 1184 | |||
| 1185 | static int | 1170 | static int |
| 1186 | mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, | 1171 | mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, |
| 1187 | struct ieee80211_key_conf *key, | 1172 | struct ieee80211_key_conf *key, |
| @@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, · 582 unmodified lines | |||
| 583 | } | 583 | } |
| 584 | } | 584 | } |
| 585 | 585 | ||
| 586 | if (changed & BSS_CHANGED_ERP_CTS_PROT) | ||
| 587 | mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); | ||
| 588 | |||
| 589 | if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { | 586 | if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { |
| 590 | mt7615_mcu_add_bss_info(phy, vif, NULL, true); | 587 | mt7615_mcu_add_bss_info(phy, vif, NULL, true); |
| 591 | mt7615_mcu_sta_add(phy, vif, NULL, true); | 588 | mt7615_mcu_sta_add(phy, vif, NULL, true); |
| @@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, · 6 unmodified lines | |||
| 598 | BSS_CHANGED_BEACON_ENABLED)) | 595 | BSS_CHANGED_BEACON_ENABLED)) |
| 599 | mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); | 596 | mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); |
| 600 | 597 | ||
| 598 | if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) | ||
| 599 | mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, | ||
| 600 | info->use_cts_prot); | ||
| 601 | |||
| 601 | if (changed & BSS_CHANGED_PS) | 602 | if (changed & BSS_CHANGED_PS) |
| 602 | mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); | 603 | mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); |
| 603 | 604 | ||
| @@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, · 2563 unmodified lines | |||
| 2564 | return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), | 2564 | return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), |
| 2565 | &req, sizeof(req), false); | 2565 | &req, sizeof(req), false); |
| 2566 | } | 2566 | } |
| 2567 | |||
| 2568 | int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, | ||
| 2569 | u8 ht_mode, bool use_cts_prot) | ||
| 2570 | { | ||
| 2571 | struct mt7615_dev *dev = phy->dev; | ||
| 2572 | struct { | ||
| 2573 | u8 prot_idx; | ||
| 2574 | u8 band; | ||
| 2575 | u8 rsv[2]; | ||
| 2576 | |||
| 2577 | bool long_nav; | ||
| 2578 | bool prot_mm; | ||
| 2579 | bool prot_gf; | ||
| 2580 | bool prot_bw40; | ||
| 2581 | bool prot_rifs; | ||
| 2582 | bool prot_bw80; | ||
| 2583 | bool prot_bw160; | ||
| 2584 | u8 prot_erp_mask; | ||
| 2585 | } __packed req = { | ||
| 2586 | .prot_idx = 0x2, | ||
| 2587 | .band = phy != &dev->phy, | ||
| 2588 | }; | ||
| 2589 | |||
| 2590 | switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { | ||
| 2591 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | ||
| 2592 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | ||
| 2593 | req.prot_mm = true; | ||
| 2594 | req.prot_gf = true; | ||
| 2595 | fallthrough; | ||
| 2596 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | ||
| 2597 | req.prot_bw40 = true; | ||
| 2598 | break; | ||
| 2599 | } | ||
| 2600 | |||
| 2601 | if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) | ||
| 2602 | req.prot_gf = true; | ||
| 2603 | |||
| 2604 | if (use_cts_prot) { | ||
| 2605 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | ||
| 2606 | u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; | ||
| 2607 | |||
| 2608 | req.prot_erp_mask = BIT(i); | ||
| 2609 | } | ||
| 2610 | |||
| 2611 | return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, | ||
| 2612 | sizeof(req), true); | ||
| 2613 | } | ||
| @@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); · 466 unmodified lines | |||
| 467 | void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); | 467 | void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); |
| 468 | void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); | 468 | void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); |
| 469 | void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); | 469 | void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); |
| 470 | void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, | ||
| 471 | struct ieee80211_vif *vif, bool enable); | ||
| 472 | void mt7615_mac_sta_poll(struct mt7615_dev *dev); | 470 | void mt7615_mac_sta_poll(struct mt7615_dev *dev); |
| 473 | int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, | 471 | int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, |
| 474 | struct sk_buff *skb, struct mt76_wcid *wcid, | 472 | struct sk_buff *skb, struct mt76_wcid *wcid, |
| @@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); · 48 unmodified lines | |||
| 523 | int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); | 521 | int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); |
| 524 | int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); | 522 | int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); |
| 525 | int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); | 523 | int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); |
| 526 | 524 | int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, | |
| 525 | u8 ht_mode, bool use_cts_prot); | ||
| 527 | int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, | 526 | int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, |
| 528 | struct ieee80211_channel *chan, int duration); | 527 | struct ieee80211_channel *chan, int duration); |
| 529 | 528 | ||
| @@ -455,8 +455,6 @@ enum mt7615_reg_base { · 454 unmodified lines | |||
| 455 | #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) | 455 | #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) |
| 456 | #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) | 456 | #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) |
| 457 | 457 | ||
| 458 | #define MT_WTBL_W3_RTS BIT(22) | ||
| 459 | |||
| 460 | #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) | 458 | #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) |
| 461 | #define MT_WTBL_W5_SHORT_GI_20 BIT(8) | 459 | #define MT_WTBL_W5_SHORT_GI_20 BIT(8) |
| 462 | #define MT_WTBL_W5_SHORT_GI_40 BIT(9) | 460 | #define MT_WTBL_W5_SHORT_GI_40 BIT(9) |
| @@ -182,14 +182,20 @@ static inline bool is_mt7920(struct mt76_dev *dev) · 181 unmodified lines | |||
| 182 | return mt76_chip(dev) == 0x7920; | 182 | return mt76_chip(dev) == 0x7920; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | static inline bool is_mt7902(struct mt76_dev *dev) | ||
| 186 | { | ||
| 187 | return mt76_chip(dev) == 0x7902; | ||
| 188 | } | ||
| 189 | |||
| 185 | static inline bool is_mt7922(struct mt76_dev *dev) | 190 | static inline bool is_mt7922(struct mt76_dev *dev) |
| 186 | { | 191 | { |
| 187 | return mt76_chip(dev) == 0x7922; | 192 | return mt76_chip(dev) == 0x7922; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| 190 | static inline bool is_mt7921(struct mt76_dev *dev) | 195 | static inline bool is_connac2(struct mt76_dev *dev) |
| 191 | { | 196 | { |
| 192 | return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev); | 197 | return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev) || |
| 198 | is_mt7902(dev); | ||
| 193 | } | 199 | } |
| 194 | 200 | ||
| 195 | static inline bool is_mt7663(struct mt76_dev *dev) | 201 | static inline bool is_mt7663(struct mt76_dev *dev) |
| @@ -271,6 +277,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev) · 75 unmodified lines | |||
| 271 | case 0x7961: | 277 | case 0x7961: |
| 272 | case 0x7920: | 278 | case 0x7920: |
| 273 | case 0x7922: | 279 | case 0x7922: |
| 280 | case 0x7902: | ||
| 274 | case 0x7925: | 281 | case 0x7925: |
| 275 | case 0x7663: | 282 | case 0x7663: |
| 276 | case 0x7622: | 283 | case 0x7622: |
| @@ -173,7 +173,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev, · 172 unmodified lines | |||
| 173 | 173 | ||
| 174 | txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); | 174 | txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); |
| 175 | 175 | ||
| 176 | if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) | 176 | if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev)) |
| 177 | last_mask = MT_TXD_LEN_LAST; | 177 | last_mask = MT_TXD_LEN_LAST; |
| 178 | else | 178 | else |
| 179 | last_mask = MT_TXD_LEN_AMSDU_LAST | | 179 | last_mask = MT_TXD_LEN_AMSDU_LAST | |
| @@ -217,7 +217,7 @@ mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev, · 37 unmodified lines | |||
| 217 | u32 last_mask; | 217 | u32 last_mask; |
| 218 | int i; | 218 | int i; |
| 219 | 219 | ||
| 220 | if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) | 220 | if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev)) |
| 221 | last_mask = MT_TXD_LEN_LAST; | 221 | last_mask = MT_TXD_LEN_LAST; |
| 222 | else | 222 | else |
| 223 | last_mask = MT_TXD_LEN_MSDU_LAST; | 223 | last_mask = MT_TXD_LEN_MSDU_LAST; |
| @@ -309,7 +309,7 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, · 85 unmodified lines | |||
| 309 | chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef; | 309 | chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef; |
| 310 | band = chandef->chan->band; | 310 | band = chandef->chan->band; |
| 311 | 311 | ||
| 312 | if (is_mt7921(mphy->dev)) { | 312 | if (is_connac2(mphy->dev)) { |
| 313 | rateidx = ffs(conf->basic_rates) - 1; | 313 | rateidx = ffs(conf->basic_rates) - 1; |
| 314 | goto legacy; | 314 | goto legacy; |
| 315 | } | 315 | } |
| @@ -548,7 +548,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, · 232 unmodified lines | |||
| 548 | val = MT_TXD1_LONG_FORMAT | | 548 | val = MT_TXD1_LONG_FORMAT | |
| 549 | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | | 549 | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | |
| 550 | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); | 550 | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); |
| 551 | if (!is_mt7921(dev)) | 551 | if (!is_connac2(dev)) |
| 552 | val |= MT_TXD1_VTA; | 552 | val |= MT_TXD1_VTA; |
| 553 | if (phy_idx || band_idx) | 553 | if (phy_idx || band_idx) |
| 554 | val |= MT_TXD1_TGID; | 554 | val |= MT_TXD1_TGID; |
| @@ -557,7 +557,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, · 2 unmodified lines | |||
| 557 | txwi[2] = 0; | 557 | txwi[2] = 0; |
| 558 | 558 | ||
| 559 | val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); | 559 | val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); |
| 560 | if (!is_mt7921(dev)) | 560 | if (!is_connac2(dev)) |
| 561 | val |= MT_TXD3_SW_POWER_MGMT; | 561 | val |= MT_TXD3_SW_POWER_MGMT; |
| 562 | if (key) | 562 | if (key) |
| 563 | val |= MT_TXD3_PROTECT_FRAME; | 563 | val |= MT_TXD3_PROTECT_FRAME; |
| @@ -599,7 +599,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, · 35 unmodified lines | |||
| 599 | txwi[6] |= cpu_to_le32(val); | 599 | txwi[6] |= cpu_to_le32(val); |
| 600 | txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); | 600 | txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); |
| 601 | 601 | ||
| 602 | if (!is_mt7921(dev)) { | 602 | if (!is_connac2(dev)) { |
| 603 | u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); | 603 | u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); |
| 604 | 604 | ||
| 605 | if (!spe_idx) | 605 | if (!spe_idx) |
| @@ -831,7 +831,7 @@ mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb · 225 unmodified lines | |||
| 831 | }; | 831 | }; |
| 832 | struct ieee80211_radiotap_he_mu *he_mu; | 832 | struct ieee80211_radiotap_he_mu *he_mu; |
| 833 | 833 | ||
| 834 | if (is_mt7921(dev)) { | 834 | if (is_connac2(dev)) { |
| 835 | mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); | 835 | mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); |
| 836 | mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN); | 836 | mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN); |
| 837 | } | 837 | } |
| @@ -1047,7 +1047,7 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, · 209 unmodified lines | |||
| 1047 | stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); | 1047 | stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); |
| 1048 | gi = FIELD_GET(MT_PRXV_HT_SGI, v0); | 1048 | gi = FIELD_GET(MT_PRXV_HT_SGI, v0); |
| 1049 | *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); | 1049 | *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); |
| 1050 | if (is_mt7921(dev)) | 1050 | if (is_connac2(dev)) |
| 1051 | dcm = !!(idx & MT_PRXV_TX_DCM); | 1051 | dcm = !!(idx & MT_PRXV_TX_DCM); |
| 1052 | else | 1052 | else |
| 1053 | dcm = FIELD_GET(MT_PRXV_DCM, v0); | 1053 | dcm = FIELD_GET(MT_PRXV_DCM, v0); |
| @@ -1153,8 +1153,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) · 99 unmodified lines | |||
| 1153 | return; | 1153 | return; |
| 1154 | 1154 | ||
| 1155 | wcid = (struct mt76_wcid *)sta->drv_priv; | 1155 | wcid = (struct mt76_wcid *)sta->drv_priv; |
| 1156 | if (!test_and_set_bit(tid, &wcid->ampdu_state)) | 1156 | if (!test_and_set_bit(tid, &wcid->ampdu_state)) { |
| 1157 | ieee80211_start_tx_ba_session(sta, tid, 0); | 1157 | if (ieee80211_start_tx_ba_session(sta, tid, 0)) |
| 1158 | clear_bit(tid, &wcid->ampdu_state); | ||
| 1159 | } | ||
| 1158 | } | 1160 | } |
| 1159 | EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); | 1161 | EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); |
| 1160 | 1162 | ||
| @@ -1207,5 +1209,11 @@ void mt76_connac2_tx_token_put(struct mt76_dev *dev) · 46 unmodified lines | |||
| 1207 | } | 1209 | } |
| 1208 | spin_unlock_bh(&dev->token_lock); | 1210 | spin_unlock_bh(&dev->token_lock); |
| 1209 | idr_destroy(&dev->token); | 1211 | idr_destroy(&dev->token); |
| 1212 | |||
| 1213 | for (id = 0; id < __MT_MAX_BAND; id++) { | ||
| 1214 | struct mt76_phy *phy = dev->phys[id]; | ||
| 1215 | if (phy) | ||
| 1216 | atomic_set(&phy->mgmt_tx_pending, 0); | ||
| 1217 | } | ||
| 1210 | } | 1218 | } |
| 1211 | EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put); | 1219 | EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put); |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | #include <linux/firmware.h> | 4 | #include <linux/firmware.h> |
| 5 | #include "mt76_connac2_mac.h" | 5 | #include "mt76_connac2_mac.h" |
| 6 | #include "mt76_connac_mcu.h" | 6 | #include "mt76_connac_mcu.h" |
| 7 | #include "mt792x_regs.h" | ||
| 7 | 8 | ||
| 8 | int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) | 9 | int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) |
| 9 | { | 10 | { |
| @@ -65,7 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, · 55 unmodified lines | |||
| 65 | int cmd; | 66 | int cmd; |
| 66 | 67 | ||
| 67 | if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || | 68 | if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || |
| 68 | (is_mt7921(dev) && addr == 0x900000) || | 69 | (is_connac2(dev) && addr == 0x900000) || |
| 69 | (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || | 70 | (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || |
| 70 | (is_mt799x(dev) && addr == 0x900000)) | 71 | (is_mt799x(dev) && addr == 0x900000)) |
| 71 | cmd = MCU_CMD(PATCH_START_REQ); | 72 | cmd = MCU_CMD(PATCH_START_REQ); |
| @@ -402,7 +403,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, · 330 unmodified lines | |||
| 402 | switch (vif->type) { | 403 | switch (vif->type) { |
| 403 | case NL80211_IFTYPE_MESH_POINT: | 404 | case NL80211_IFTYPE_MESH_POINT: |
| 404 | case NL80211_IFTYPE_AP: | 405 | case NL80211_IFTYPE_AP: |
| 405 | if (vif->p2p && !is_mt7921(dev)) | 406 | if (vif->p2p && !is_connac2(dev)) |
| 406 | conn_type = CONNECTION_P2P_GC; | 407 | conn_type = CONNECTION_P2P_GC; |
| 407 | else | 408 | else |
| 408 | conn_type = CONNECTION_INFRA_STA; | 409 | conn_type = CONNECTION_INFRA_STA; |
| @@ -410,7 +411,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, · 1 unmodified line | |||
| 410 | basic->aid = cpu_to_le16(link_sta->sta->aid); | 411 | basic->aid = cpu_to_le16(link_sta->sta->aid); |
| 411 | break; | 412 | break; |
| 412 | case NL80211_IFTYPE_STATION: | 413 | case NL80211_IFTYPE_STATION: |
| 413 | if (vif->p2p && !is_mt7921(dev)) | 414 | if (vif->p2p && !is_connac2(dev)) |
| 414 | conn_type = CONNECTION_P2P_GO; | 415 | conn_type = CONNECTION_P2P_GO; |
| 415 | else | 416 | else |
| 416 | conn_type = CONNECTION_INFRA_AP; | 417 | conn_type = CONNECTION_INFRA_AP; |
| @@ -874,7 +875,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, · 457 unmodified lines | |||
| 874 | struct sta_rec_vht *vht; | 875 | struct sta_rec_vht *vht; |
| 875 | int len; | 876 | int len; |
| 876 | 877 | ||
| 877 | len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4; | 878 | len = is_connac2(dev) ? sizeof(*vht) : sizeof(*vht) - 4; |
| 878 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); | 879 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); |
| 879 | vht = (struct sta_rec_vht *)tlv; | 880 | vht = (struct sta_rec_vht *)tlv; |
| 880 | vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); | 881 | vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); |
| @@ -885,7 +886,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, · 4 unmodified lines | |||
| 885 | /* starec uapsd */ | 886 | /* starec uapsd */ |
| 886 | mt76_connac_mcu_sta_uapsd(skb, vif, sta); | 887 | mt76_connac_mcu_sta_uapsd(skb, vif, sta); |
| 887 | 888 | ||
| 888 | if (!is_mt7921(dev)) | 889 | if (!is_connac2(dev)) |
| 889 | return; | 890 | return; |
| 890 | 891 | ||
| 891 | if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he) | 892 | if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he) |
| @@ -1295,8 +1296,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, · 403 unmodified lines | |||
| 1295 | wtbl_hdr); | 1296 | wtbl_hdr); |
| 1296 | 1297 | ||
| 1297 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); | 1298 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 1298 | if (ret) | 1299 | if (ret) { |
| 1300 | dev_kfree_skb(skb); | ||
| 1299 | return ret; | 1301 | return ret; |
| 1302 | } | ||
| 1300 | 1303 | ||
| 1301 | ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); | 1304 | ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); |
| 1302 | if (ret) | 1305 | if (ret) |
| @@ -1309,8 +1312,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, · 6 unmodified lines | |||
| 1309 | mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); | 1312 | mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); |
| 1310 | 1313 | ||
| 1311 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); | 1314 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 1312 | if (ret) | 1315 | if (ret) { |
| 1316 | dev_kfree_skb(skb); | ||
| 1313 | return ret; | 1317 | return ret; |
| 1318 | } | ||
| 1314 | 1319 | ||
| 1315 | return mt76_mcu_skb_send_msg(dev, skb, cmd, true); | 1320 | return mt76_mcu_skb_send_msg(dev, skb, cmd, true); |
| 1316 | } | 1321 | } |
| @@ -1774,7 +1779,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, · 457 unmodified lines | |||
| 1774 | req->ssid_type_ext = n_ssids ? BIT(0) : 0; | 1779 | req->ssid_type_ext = n_ssids ? BIT(0) : 0; |
| 1775 | req->ssids_num = n_ssids; | 1780 | req->ssids_num = n_ssids; |
| 1776 | 1781 | ||
| 1777 | duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME; | 1782 | duration = is_connac2(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME; |
| 1778 | /* increase channel time for passive scan */ | 1783 | /* increase channel time for passive scan */ |
| 1779 | if (!sreq->n_ssids) | 1784 | if (!sreq->n_ssids) |
| 1780 | duration *= 2; | 1785 | duration *= 2; |
| @@ -1817,7 +1822,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, · 36 unmodified lines | |||
| 1817 | req->ies_len = cpu_to_le16(sreq->ie_len); | 1822 | req->ies_len = cpu_to_le16(sreq->ie_len); |
| 1818 | } | 1823 | } |
| 1819 | 1824 | ||
| 1820 | if (is_mt7921(phy->dev)) | 1825 | if (is_connac2(phy->dev)) |
| 1821 | req->scan_func |= SCAN_FUNC_SPLIT_SCAN; | 1826 | req->scan_func |= SCAN_FUNC_SPLIT_SCAN; |
| 1822 | 1827 | ||
| 1823 | memcpy(req->bssid, sreq->bssid, ETH_ALEN); | 1828 | memcpy(req->bssid, sreq->bssid, ETH_ALEN); |
| @@ -1893,7 +1898,7 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, · 69 unmodified lines | |||
| 1893 | get_random_mask_addr(addr, sreq->mac_addr, | 1898 | get_random_mask_addr(addr, sreq->mac_addr, |
| 1894 | sreq->mac_addr_mask); | 1899 | sreq->mac_addr_mask); |
| 1895 | } | 1900 | } |
| 1896 | if (is_mt7921(phy->dev)) { | 1901 | if (is_connac2(phy->dev)) { |
| 1897 | req->mt7921.bss_idx = mvif->idx; | 1902 | req->mt7921.bss_idx = mvif->idx; |
| 1898 | req->mt7921.delay = cpu_to_le32(sreq->delay); | 1903 | req->mt7921.delay = cpu_to_le32(sreq->delay); |
| 1899 | } | 1904 | } |
| @@ -2033,7 +2038,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, · 133 unmodified lines | |||
| 2033 | struct mt76_power_limits *limits, | 2038 | struct mt76_power_limits *limits, |
| 2034 | enum nl80211_band band) | 2039 | enum nl80211_band band) |
| 2035 | { | 2040 | { |
| 2036 | int max_power = is_mt7921(dev) ? 127 : 63; | 2041 | int max_power = is_connac2(dev) ? 127 : 63; |
| 2037 | int i, offset = sizeof(limits->cck); | 2042 | int i, offset = sizeof(limits->cck); |
| 2038 | 2043 | ||
| 2039 | memset(sku, max_power, MT_SKU_POWER_LIMIT); | 2044 | memset(sku, max_power, MT_SKU_POWER_LIMIT); |
| @@ -2061,7 +2066,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, · 21 unmodified lines | |||
| 2061 | offset += 12; | 2066 | offset += 12; |
| 2062 | } | 2067 | } |
| 2063 | 2068 | ||
| 2064 | if (!is_mt7921(dev)) | 2069 | if (!is_connac2(dev)) |
| 2065 | return; | 2070 | return; |
| 2066 | 2071 | ||
| 2067 | /* he */ | 2072 | /* he */ |
| @@ -2117,7 +2122,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, · 49 unmodified lines | |||
| 2117 | enum nl80211_band band) | 2122 | enum nl80211_band band) |
| 2118 | { | 2123 | { |
| 2119 | struct mt76_dev *dev = phy->dev; | 2124 | struct mt76_dev *dev = phy->dev; |
| 2120 | int sku_len, batch_len = is_mt7921(dev) ? 8 : 16; | 2125 | int sku_len, batch_len = is_connac2(dev) ? 8 : 16; |
| 2121 | static const u8 chan_list_2ghz[] = { | 2126 | static const u8 chan_list_2ghz[] = { |
| 2122 | 1, 2, 3, 4, 5, 6, 7, | 2127 | 1, 2, 3, 4, 5, 6, 7, |
| 2123 | 8, 9, 10, 11, 12, 13, 14 | 2128 | 8, 9, 10, 11, 12, 13, 14 |
| @@ -2158,7 +2163,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, · 34 unmodified lines | |||
| 2158 | if (!limits) | 2163 | if (!limits) |
| 2159 | return -ENOMEM; | 2164 | return -ENOMEM; |
| 2160 | 2165 | ||
| 2161 | sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; | 2166 | sku_len = is_connac2(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; |
| 2162 | tx_power = 2 * phy->hw->conf.power_level; | 2167 | tx_power = 2 * phy->hw->conf.power_level; |
| 2163 | if (!tx_power) | 2168 | if (!tx_power) |
| 2164 | tx_power = 127; | 2169 | tx_power = 127; |
| @@ -2242,6 +2247,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, · 77 unmodified lines | |||
| 2242 | false); | 2247 | false); |
| 2243 | if (err < 0) | 2248 | if (err < 0) |
| 2244 | goto out; | 2249 | goto out; |
| 2250 | |||
| 2251 | /* read a CR to avoid PSE buffer underflow */ | ||
| 2252 | mt76_connac_mcu_reg_rr(dev, MT_PSE_BASE); | ||
| 2245 | } | 2253 | } |
| 2246 | 2254 | ||
| 2247 | out: | 2255 | out: |
| @@ -2764,12 +2772,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, · 516 unmodified lines | |||
| 2764 | return PTR_ERR(skb); | 2772 | return PTR_ERR(skb); |
| 2765 | 2773 | ||
| 2766 | ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd); | 2774 | ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd); |
| 2767 | if (ret) | 2775 | if (ret) { |
| 2776 | dev_kfree_skb(skb); | ||
| 2768 | return ret; | 2777 | return ret; |
| 2778 | } | ||
| 2769 | 2779 | ||
| 2770 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); | 2780 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 2771 | if (ret) | 2781 | if (ret) { |
| 2782 | dev_kfree_skb(skb); | ||
| 2772 | return ret; | 2783 | return ret; |
| 2784 | } | ||
| 2773 | 2785 | ||
| 2774 | return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); | 2786 | return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); |
| 2775 | } | 2787 | } |
| @@ -3072,7 +3084,7 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) · 296 unmodified lines | |||
| 3072 | { | 3084 | { |
| 3073 | u32 mode = DL_MODE_NEED_RSP; | 3085 | u32 mode = DL_MODE_NEED_RSP; |
| 3074 | 3086 | ||
| 3075 | if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT) | 3087 | if ((!is_connac2(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT) |
| 3076 | return mode; | 3088 | return mode; |
| 3077 | 3089 | ||
| 3078 | switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { | 3090 | switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { |
| @@ -628,6 +628,13 @@ struct sta_rec_tx_proc { · 627 unmodified lines | |||
| 628 | __le32 flag; | 628 | __le32 flag; |
| 629 | } __packed; | 629 | } __packed; |
| 630 | 630 | ||
| 631 | struct sta_rec_eml_op { | ||
| 632 | __le16 tag; | ||
| 633 | __le16 len; | ||
| 634 | u8 link_bitmap; | ||
| 635 | u8 link_ant_num[3]; | ||
| 636 | } __packed; | ||
| 637 | |||
| 631 | /* wtbl_rec */ | 638 | /* wtbl_rec */ |
| 632 | 639 | ||
| 633 | struct wtbl_req_hdr { | 640 | struct wtbl_req_hdr { |
| @@ -796,6 +803,7 @@ struct wtbl_raw { · 162 unmodified lines | |||
| 796 | sizeof(struct sta_rec_he_6g_capa) + \ | 803 | sizeof(struct sta_rec_he_6g_capa) + \ |
| 797 | sizeof(struct sta_rec_pn_info) + \ | 804 | sizeof(struct sta_rec_pn_info) + \ |
| 798 | sizeof(struct sta_rec_tx_proc) + \ | 805 | sizeof(struct sta_rec_tx_proc) + \ |
| 806 | sizeof(struct sta_rec_eml_op) + \ | ||
| 799 | sizeof(struct tlv) + \ | 807 | sizeof(struct tlv) + \ |
| 800 | MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) | 808 | MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) |
| 801 | 809 | ||
| @@ -832,6 +840,7 @@ enum { · 30 unmodified lines | |||
| 832 | STA_REC_PN_INFO = 0x26, | 840 | STA_REC_PN_INFO = 0x26, |
| 833 | STA_REC_KEY_V3 = 0x27, | 841 | STA_REC_KEY_V3 = 0x27, |
| 834 | STA_REC_HDRT = 0x28, | 842 | STA_REC_HDRT = 0x28, |
| 843 | STA_REC_EML_OP = 0x29, | ||
| 835 | STA_REC_HDR_TRANS = 0x2B, | 844 | STA_REC_HDR_TRANS = 0x2B, |
| 836 | STA_REC_MAX_NUM | 845 | STA_REC_MAX_NUM |
| 837 | }; | 846 | }; |
| @@ -1308,7 +1317,9 @@ enum { · 470 unmodified lines | |||
| 1308 | MCU_UNI_CMD_PER_STA_INFO = 0x6d, | 1317 | MCU_UNI_CMD_PER_STA_INFO = 0x6d, |
| 1309 | MCU_UNI_CMD_ALL_STA_INFO = 0x6e, | 1318 | MCU_UNI_CMD_ALL_STA_INFO = 0x6e, |
| 1310 | MCU_UNI_CMD_ASSERT_DUMP = 0x6f, | 1319 | MCU_UNI_CMD_ASSERT_DUMP = 0x6f, |
| 1320 | MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74, | ||
| 1311 | MCU_UNI_CMD_RADIO_STATUS = 0x80, | 1321 | MCU_UNI_CMD_RADIO_STATUS = 0x80, |
| 1322 | MCU_UNI_CMD_MLD = 0x82, | ||
| 1312 | MCU_UNI_CMD_SDO = 0x88, | 1323 | MCU_UNI_CMD_SDO = 0x88, |
| 1313 | }; | 1324 | }; |
| 1314 | 1325 | ||
| @@ -1363,6 +1374,7 @@ enum { · 48 unmodified lines | |||
| 1363 | UNI_BSS_INFO_BASIC = 0, | 1374 | UNI_BSS_INFO_BASIC = 0, |
| 1364 | UNI_BSS_INFO_RA = 1, | 1375 | UNI_BSS_INFO_RA = 1, |
| 1365 | UNI_BSS_INFO_RLM = 2, | 1376 | UNI_BSS_INFO_RLM = 2, |
| 1377 | UNI_BSS_INFO_PROTECT_INFO = 3, | ||
| 1366 | UNI_BSS_INFO_BSS_COLOR = 4, | 1378 | UNI_BSS_INFO_BSS_COLOR = 4, |
| 1367 | UNI_BSS_INFO_HE_BASIC = 5, | 1379 | UNI_BSS_INFO_HE_BASIC = 5, |
| 1368 | UNI_BSS_INFO_11V_MBSSID = 6, | 1380 | UNI_BSS_INFO_11V_MBSSID = 6, |
| @@ -1383,6 +1395,7 @@ enum { · 14 unmodified lines | |||
| 1383 | UNI_BSS_INFO_MLD = 26, | 1395 | UNI_BSS_INFO_MLD = 26, |
| 1384 | UNI_BSS_INFO_PM_DISABLE = 27, | 1396 | UNI_BSS_INFO_PM_DISABLE = 27, |
| 1385 | UNI_BSS_INFO_EHT = 30, | 1397 | UNI_BSS_INFO_EHT = 30, |
| 1398 | UNI_BSS_INFO_MLD_LINK_OP = 36, | ||
| 1386 | }; | 1399 | }; |
| 1387 | 1400 | ||
| 1388 | enum { | 1401 | enum { |
| @@ -1865,7 +1878,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa) · 476 unmodified lines | |||
| 1865 | 1878 | ||
| 1866 | ret |= feature_set & FW_FEATURE_SET_ENCRYPT ? | 1879 | ret |= feature_set & FW_FEATURE_SET_ENCRYPT ? |
| 1867 | DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0; | 1880 | DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0; |
| 1868 | if (is_mt7921(dev) || is_mt7925(dev)) | 1881 | if (is_connac2(dev) || is_mt7925(dev)) |
| 1869 | ret |= feature_set & FW_FEATURE_ENCRY_MODE ? | 1882 | ret |= feature_set & FW_FEATURE_ENCRY_MODE ? |
| 1870 | DL_CONFIG_ENCRY_MODE_SEL : 0; | 1883 | DL_CONFIG_ENCRY_MODE_SEL : 0; |
| 1871 | ret |= FIELD_PREP(DL_MODE_KEY_IDX, | 1884 | ret |= FIELD_PREP(DL_MODE_KEY_IDX, |
| @@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, · 533 unmodified lines | |||
| 534 | return; | 534 | return; |
| 535 | 535 | ||
| 536 | clear_bit(MT76_RESTART, &dev->mphy.state); | 536 | clear_bit(MT76_RESTART, &dev->mphy.state); |
| 537 | ieee80211_wake_queues(hw); | ||
| 537 | } | 538 | } |
| 538 | EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); | 539 | EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); |
| 539 | 540 | ||
| @@ -1294,6 +1294,7 @@ free_phy2: · 1293 unmodified lines | |||
| 1294 | 1294 | ||
| 1295 | void mt7915_unregister_device(struct mt7915_dev *dev) | 1295 | void mt7915_unregister_device(struct mt7915_dev *dev) |
| 1296 | { | 1296 | { |
| 1297 | cancel_work_sync(&dev->dump_work); | ||
| 1297 | mt7915_unregister_ext_phy(dev); | 1298 | mt7915_unregister_ext_phy(dev); |
| 1298 | mt7915_coredump_unregister(dev); | 1299 | mt7915_coredump_unregister(dev); |
| 1299 | mt7915_unregister_thermal(&dev->phy); | 1300 | mt7915_unregister_thermal(&dev->phy); |
| @@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) · 231 unmodified lines | |||
| 232 | rcu_read_unlock(); | 232 | rcu_read_unlock(); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, | ||
| 236 | struct ieee80211_vif *vif, bool enable) | ||
| 237 | { | ||
| 238 | struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; | ||
| 239 | u32 addr; | ||
| 240 | |||
| 241 | addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); | ||
| 242 | if (enable) | ||
| 243 | mt76_set(dev, addr, BIT(5)); | ||
| 244 | else | ||
| 245 | mt76_clear(dev, addr, BIT(5)); | ||
| 246 | } | ||
| 247 | |||
| 248 | static void | 235 | static void |
| 249 | mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, | 236 | mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, |
| 250 | struct mt7915_sta *msta, struct sk_buff *skb, | 237 | struct mt7915_sta *msta, struct sk_buff *skb, |
| @@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) · 67 unmodified lines | |||
| 68 | if (ret) | 68 | if (ret) |
| 69 | goto out; | 69 | goto out; |
| 70 | 70 | ||
| 71 | ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, | 71 | ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, |
| 72 | phy->mt76->band_idx); | 72 | phy->mt76->band_idx); |
| 73 | if (ret) | 73 | if (ret) |
| 74 | goto out; | 74 | goto out; |
| @@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, · 558 unmodified lines | |||
| 633 | if (set_sta == 1) | 633 | if (set_sta == 1) |
| 634 | mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); | 634 | mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); |
| 635 | 635 | ||
| 636 | if (changed & BSS_CHANGED_ERP_CTS_PROT) | 636 | if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) |
| 637 | mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); | 637 | mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, |
| 638 | info->use_cts_prot); | ||
| 638 | 639 | ||
| 639 | if (changed & BSS_CHANGED_ERP_SLOT) { | 640 | if (changed & BSS_CHANGED_ERP_SLOT) { |
| 640 | int slottime = 9; | 641 | int slottime = 9; |
| @@ -851,8 +852,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, · 210 unmodified lines | |||
| 851 | return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); | 852 | return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); |
| 852 | 853 | ||
| 853 | case MT76_STA_EVENT_DISASSOC: | 854 | case MT76_STA_EVENT_DISASSOC: |
| 855 | mutex_lock(&dev->mt76.mutex); | ||
| 854 | for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) | 856 | for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) |
| 855 | mt7915_mac_twt_teardown_flow(dev, msta, i); | 857 | mt7915_mac_twt_teardown_flow(dev, msta, i); |
| 858 | mutex_unlock(&dev->mt76.mutex); | ||
| 856 | 859 | ||
| 857 | mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); | 860 | mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); |
| 858 | msta->wcid.sta_disabled = 1; | 861 | msta->wcid.sta_disabled = 1; |
| @@ -1765,8 +1765,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, · 1764 unmodified lines | |||
| 1765 | } | 1765 | } |
| 1766 | out: | 1766 | out: |
| 1767 | ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); | 1767 | ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); |
| 1768 | if (ret) | 1768 | if (ret) { |
| 1769 | dev_kfree_skb(skb); | ||
| 1769 | return ret; | 1770 | return ret; |
| 1771 | } | ||
| 1770 | 1772 | ||
| 1771 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | 1773 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| 1772 | MCU_EXT_CMD(STA_REC_UPDATE), true); | 1774 | MCU_EXT_CMD(STA_REC_UPDATE), true); |
| @@ -3954,6 +3956,68 @@ out: · 2181 unmodified lines | |||
| 3954 | return ret; | 3956 | return ret; |
| 3955 | } | 3957 | } |
| 3956 | 3958 | ||
| 3959 | int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, | ||
| 3960 | u8 ht_mode, bool use_cts_prot) | ||
| 3961 | { | ||
| 3962 | struct mt7915_dev *dev = phy->dev; | ||
| 3963 | int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); | ||
| 3964 | struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; | ||
| 3965 | struct bss_info_prot *prot; | ||
| 3966 | struct sk_buff *skb; | ||
| 3967 | struct tlv *tlv; | ||
| 3968 | enum { | ||
| 3969 | PROT_NONMEMBER = BIT(1), | ||
| 3970 | PROT_20MHZ = BIT(2), | ||
| 3971 | PROT_NONHT_MIXED = BIT(3), | ||
| 3972 | PROT_LEGACY_ERP = BIT(5), | ||
| 3973 | PROT_NONGF_STA = BIT(7), | ||
| 3974 | }; | ||
| 3975 | u32 rts_threshold; | ||
| 3976 | |||
| 3977 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, | ||
| 3978 | NULL, len); | ||
| 3979 | if (IS_ERR(skb)) | ||
| 3980 | return PTR_ERR(skb); | ||
| 3981 | |||
| 3982 | tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, | ||
| 3983 | sizeof(*prot)); | ||
| 3984 | prot = (struct bss_info_prot *)tlv; | ||
| 3985 | |||
| 3986 | switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { | ||
| 3987 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | ||
| 3988 | prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); | ||
| 3989 | break; | ||
| 3990 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | ||
| 3991 | prot->prot_mode = cpu_to_le32(PROT_20MHZ); | ||
| 3992 | break; | ||
| 3993 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | ||
| 3994 | prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); | ||
| 3995 | break; | ||
| 3996 | } | ||
| 3997 | |||
| 3998 | if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) | ||
| 3999 | prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); | ||
| 4000 | |||
| 4001 | if (use_cts_prot) | ||
| 4002 | prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); | ||
| 4003 | |||
| 4004 | /* reuse current RTS setting */ | ||
| 4005 | rts_threshold = phy->mt76->hw->wiphy->rts_threshold; | ||
| 4006 | if (rts_threshold == (u32)-1) | ||
| 4007 | prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); | ||
| 4008 | else | ||
| 4009 | prot->rts_len_thres = cpu_to_le32(rts_threshold); | ||
| 4010 | |||
| 4011 | prot->rts_pkt_thres = 0x2; | ||
| 4012 | |||
| 4013 | prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); | ||
| 4014 | if (!prot->he_rts_thres) | ||
| 4015 | prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); | ||
| 4016 | |||
| 4017 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 4018 | MCU_EXT_CMD(BSS_INFO_UPDATE), true); | ||
| 4019 | } | ||
| 4020 | |||
| 3957 | int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, | 4021 | int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, |
| 3958 | struct cfg80211_he_bss_color *he_bss_color) | 4022 | struct cfg80211_he_bss_color *he_bss_color) |
| 3959 | { | 4023 | { |
| @@ -399,6 +399,17 @@ struct bss_info_inband_discovery { · 398 unmodified lines | |||
| 399 | __le16 prob_rsp_len; | 399 | __le16 prob_rsp_len; |
| 400 | } __packed __aligned(4); | 400 | } __packed __aligned(4); |
| 401 | 401 | ||
| 402 | struct bss_info_prot { | ||
| 403 | __le16 tag; | ||
| 404 | __le16 len; | ||
| 405 | __le32 prot_type; | ||
| 406 | __le32 prot_mode; | ||
| 407 | __le32 rts_len_thres; | ||
| 408 | __le16 he_rts_thres; | ||
| 409 | u8 rts_pkt_thres; | ||
| 410 | u8 rsv[5]; | ||
| 411 | } __packed; | ||
| 412 | |||
| 402 | enum { | 413 | enum { |
| 403 | BSS_INFO_BCN_CSA, | 414 | BSS_INFO_BCN_CSA, |
| 404 | BSS_INFO_BCN_BCC, | 415 | BSS_INFO_BCN_BCC, |
| @@ -84,6 +84,8 @@ · 83 unmodified lines | |||
| 84 | #define MT7915_CRIT_TEMP 110 | 84 | #define MT7915_CRIT_TEMP 110 |
| 85 | #define MT7915_MAX_TEMP 120 | 85 | #define MT7915_MAX_TEMP 120 |
| 86 | 86 | ||
| 87 | #define MT7915_RTS_LEN_THRES 0x92b | ||
| 88 | |||
| 87 | struct mt7915_vif; | 89 | struct mt7915_vif; |
| 88 | struct mt7915_sta; | 90 | struct mt7915_sta; |
| 89 | struct mt7915_dfs_pulse; | 91 | struct mt7915_dfs_pulse; |
| @@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v · 383 unmodified lines | |||
| 473 | u32 changed); | 475 | u32 changed); |
| 474 | int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 476 | int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 475 | int enable, u32 changed); | 477 | int enable, u32 changed); |
| 478 | int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, | ||
| 479 | u8 ht_mode, bool use_cts_prot); | ||
| 476 | int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, | 480 | int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, |
| 477 | struct ieee80211_he_obss_pd *he_obss_pd); | 481 | struct ieee80211_he_obss_pd *he_obss_pd); |
| 478 | int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, | 482 | int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, |
| @@ -302,7 +302,9 @@ int mt7921_register_device(struct mt792x_dev *dev) · 301 unmodified lines | |||
| 302 | dev->pm.idle_timeout = MT792x_PM_TIMEOUT; | 302 | dev->pm.idle_timeout = MT792x_PM_TIMEOUT; |
| 303 | dev->pm.stats.last_wake_event = jiffies; | 303 | dev->pm.stats.last_wake_event = jiffies; |
| 304 | dev->pm.stats.last_doze_event = jiffies; | 304 | dev->pm.stats.last_doze_event = jiffies; |
| 305 | if (!mt76_is_usb(&dev->mt76)) { | 305 | |
| 306 | if (!mt76_is_usb(&dev->mt76) && | ||
| 307 | !is_mt7902(&dev->mt76)) { | ||
| 306 | dev->pm.enable_user = true; | 308 | dev->pm.enable_user = true; |
| 307 | dev->pm.enable = true; | 309 | dev->pm.enable = true; |
| 308 | dev->pm.ds_enable_user = true; | 310 | dev->pm.ds_enable_user = true; |
| @@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev) · 370 unmodified lines | |||
| 371 | { | 371 | { |
| 372 | struct mt792x_phy *phy = &dev->phy; | 372 | struct mt792x_phy *phy = &dev->phy; |
| 373 | 373 | ||
| 374 | if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | ||
| 375 | return; | ||
| 376 | |||
| 374 | timer_delete_sync(&phy->roc_timer); | 377 | timer_delete_sync(&phy->roc_timer); |
| 375 | cancel_work_sync(&phy->roc_work); | 378 | cancel_work(&phy->roc_work); |
| 376 | if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | 379 | |
| 377 | ieee80211_iterate_interfaces(mt76_hw(dev), | 380 | ieee80211_iterate_interfaces(mt76_hw(dev), |
| 378 | IEEE80211_IFACE_ITER_RESUME_ALL, | 381 | IEEE80211_IFACE_ITER_RESUME_ALL, |
| 379 | mt7921_roc_iter, (void *)phy); | 382 | mt7921_roc_iter, (void *)phy); |
| 380 | } | 383 | } |
| 381 | EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); | 384 | EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); |
| 382 | 385 | ||
| @@ -387,10 +390,11 @@ void mt7921_roc_work(struct work_struct *work) · 4 unmodified lines | |||
| 387 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, | 390 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, |
| 388 | roc_work); | 391 | roc_work); |
| 389 | 392 | ||
| 390 | if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | ||
| 391 | return; | ||
| 392 | |||
| 393 | mt792x_mutex_acquire(phy->dev); | 393 | mt792x_mutex_acquire(phy->dev); |
| 394 | if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) { | ||
| 395 | mt792x_mutex_release(phy->dev); | ||
| 396 | return; | ||
| 397 | } | ||
| 394 | ieee80211_iterate_active_interfaces(phy->mt76->hw, | 398 | ieee80211_iterate_active_interfaces(phy->mt76->hw, |
| 395 | IEEE80211_IFACE_ITER_RESUME_ALL, | 399 | IEEE80211_IFACE_ITER_RESUME_ALL, |
| 396 | mt7921_roc_iter, phy); | 400 | mt7921_roc_iter, phy); |
| @@ -796,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) · 399 unmodified lines | |||
| 796 | } | 800 | } |
| 797 | 801 | ||
| 798 | out: | 802 | out: |
| 799 | mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); | 803 | if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) |
| 804 | mt7921_regd_update(dev); | ||
| 800 | } | 805 | } |
| 801 | 806 | ||
| 802 | int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, | 807 | int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, |
| @@ -807,6 +812,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, · 4 unmodified lines | |||
| 807 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 812 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 808 | int ret, idx; | 813 | int ret, idx; |
| 809 | 814 | ||
| 815 | if (sta->aid > MT7921_MAX_AID) | ||
| 816 | return -ENOENT; | ||
| 817 | |||
| 810 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); | 818 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); |
| 811 | if (idx < 0) | 819 | if (idx < 0) |
| 812 | return -ENOSPC; | 820 | return -ENOSPC; |
| @@ -850,6 +858,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, · 37 unmodified lines | |||
| 850 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; | 858 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 851 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 859 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 852 | 860 | ||
| 861 | if (sta->aid > MT7921_MAX_AID) | ||
| 862 | return -ENOENT; | ||
| 863 | |||
| 853 | if (ev != MT76_STA_EVENT_ASSOC) | 864 | if (ev != MT76_STA_EVENT_ASSOC) |
| 854 | return 0; | 865 | return 0; |
| 855 | 866 | ||
| @@ -1353,6 +1353,9 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, · 1352 unmodified lines | |||
| 1353 | u16 len = le16_to_cpu(rule->len); | 1353 | u16 len = le16_to_cpu(rule->len); |
| 1354 | u16 offset = len + sizeof(*rule); | 1354 | u16 offset = len + sizeof(*rule); |
| 1355 | 1355 | ||
| 1356 | if (buf_len < offset) | ||
| 1357 | break; | ||
| 1358 | |||
| 1356 | pos += offset; | 1359 | pos += offset; |
| 1357 | buf_len -= offset; | 1360 | buf_len -= offset; |
| 1358 | if (rule->alpha2[0] != alpha2[0] || | 1361 | if (rule->alpha2[0] != alpha2[0] || |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | #include "../mt792x.h" | 7 | #include "../mt792x.h" |
| 8 | #include "regs.h" | 8 | #include "regs.h" |
| 9 | 9 | ||
| 10 | #define MT7921_MAX_AID 20 | ||
| 11 | |||
| 10 | #define MT7921_TX_RING_SIZE 2048 | 12 | #define MT7921_TX_RING_SIZE 2048 |
| 11 | #define MT7921_TX_MCU_RING_SIZE 256 | 13 | #define MT7921_TX_MCU_RING_SIZE 256 |
| 12 | #define MT7921_TX_FWDL_RING_SIZE 128 | 14 | #define MT7921_TX_FWDL_RING_SIZE 128 |
| @@ -15,6 +17,9 @@ · 2 unmodified lines | |||
| 15 | #define MT7921_RX_MCU_RING_SIZE 8 | 17 | #define MT7921_RX_MCU_RING_SIZE 8 |
| 16 | #define MT7921_RX_MCU_WA_RING_SIZE 512 | 18 | #define MT7921_RX_MCU_WA_RING_SIZE 512 |
| 17 | 19 | ||
| 20 | /* MT7902 Rx Ring0 is for both Rx Event and Tx Done Event */ | ||
| 21 | #define MT7902_RX_MCU_RING_SIZE 512 | ||
| 22 | |||
| 18 | #define MT7921_EEPROM_SIZE 3584 | 23 | #define MT7921_EEPROM_SIZE 3584 |
| 19 | #define MT7921_TOKEN_SIZE 8192 | 24 | #define MT7921_TOKEN_SIZE 8192 |
| 20 | 25 | ||
| @@ -117,6 +122,17 @@ enum mt7921_rxq_id { · 96 unmodified lines | |||
| 117 | MT7921_RXQ_MCU_WM = 0, | 122 | MT7921_RXQ_MCU_WM = 0, |
| 118 | }; | 123 | }; |
| 119 | 124 | ||
| 125 | /* MT7902 assigns its MCU-WM TXQ at index 15 */ | ||
| 126 | enum mt7902_txq_id { | ||
| 127 | MT7902_TXQ_MCU_WM = 15, | ||
| 128 | }; | ||
| 129 | |||
| 130 | struct mt7921_dma_layout { | ||
| 131 | u8 mcu_wm_txq; | ||
| 132 | u16 mcu_rxdone_ring_size; | ||
| 133 | bool has_mcu_wa; | ||
| 134 | }; | ||
| 135 | |||
| 120 | enum { | 136 | enum { |
| 121 | MT7921_CLC_POWER, | 137 | MT7921_CLC_POWER, |
| 122 | MT7921_CLC_CHAN, | 138 | MT7921_CLC_CHAN, |
| @@ -26,6 +26,8 @@ static const struct pci_device_id mt7921_pci_device_table[] = { · 25 unmodified lines | |||
| 26 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, | 26 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, |
| 27 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920), | 27 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920), |
| 28 | .driver_data = (kernel_ulong_t)MT7920_FIRMWARE_WM }, | 28 | .driver_data = (kernel_ulong_t)MT7920_FIRMWARE_WM }, |
| 29 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7902), | ||
| 30 | .driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM }, | ||
| 29 | { }, | 31 | { }, |
| 30 | }; | 32 | }; |
| 31 | 33 | ||
| @@ -167,8 +169,29 @@ static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) · 135 unmodified lines | |||
| 167 | 169 | ||
| 168 | static int mt7921_dma_init(struct mt792x_dev *dev) | 170 | static int mt7921_dma_init(struct mt792x_dev *dev) |
| 169 | { | 171 | { |
| 172 | struct mt7921_dma_layout layout = { | ||
| 173 | /* General case: MT7921 / MT7922 /MT7920 */ | ||
| 174 | .mcu_wm_txq = MT7921_TXQ_MCU_WM, | ||
| 175 | .mcu_rxdone_ring_size = MT7921_RX_MCU_RING_SIZE, | ||
| 176 | .has_mcu_wa = true, | ||
| 177 | }; | ||
| 178 | bool is_mt7902; | ||
| 170 | int ret; | 179 | int ret; |
| 171 | 180 | ||
| 181 | is_mt7902 = mt7921_l1_rr(dev, MT_HW_CHIPID) == 0x7902; | ||
| 182 | |||
| 183 | /* | ||
| 184 | * MT7902 special case: | ||
| 185 | * - MCU-WM TXQ uses index 15 | ||
| 186 | * - RX Ring0 is larger and shared for event/TX-done | ||
| 187 | * - MT7902 does not use the MCU_WA ring | ||
| 188 | */ | ||
| 189 | if (is_mt7902) { | ||
| 190 | layout.mcu_wm_txq = MT7902_TXQ_MCU_WM; | ||
| 191 | layout.mcu_rxdone_ring_size = MT7902_RX_MCU_RING_SIZE; | ||
| 192 | layout.has_mcu_wa = false; | ||
| 193 | } | ||
| 194 | |||
| 172 | mt76_dma_attach(&dev->mt76); | 195 | mt76_dma_attach(&dev->mt76); |
| 173 | 196 | ||
| 174 | ret = mt792x_dma_disable(dev, true); | 197 | ret = mt792x_dma_disable(dev, true); |
| @@ -185,7 +208,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) · 10 unmodified lines | |||
| 185 | mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); | 208 | mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); |
| 186 | 209 | ||
| 187 | /* command to WM */ | 210 | /* command to WM */ |
| 188 | ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM, | 211 | ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, layout.mcu_wm_txq, |
| 189 | MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); | 212 | MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); |
| 190 | if (ret) | 213 | if (ret) |
| 191 | return ret; | 214 | return ret; |
| @@ -199,18 +222,20 @@ static int mt7921_dma_init(struct mt792x_dev *dev) · 7 unmodified lines | |||
| 199 | /* event from WM before firmware download */ | 222 | /* event from WM before firmware download */ |
| 200 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], | 223 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], |
| 201 | MT7921_RXQ_MCU_WM, | 224 | MT7921_RXQ_MCU_WM, |
| 202 | MT7921_RX_MCU_RING_SIZE, | 225 | layout.mcu_rxdone_ring_size, |
| 203 | MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); | 226 | MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); |
| 204 | if (ret) | 227 | if (ret) |
| 205 | return ret; | 228 | return ret; |
| 206 | 229 | ||
| 207 | /* Change mcu queue after firmware download */ | 230 | if (layout.has_mcu_wa) { |
| 208 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], | 231 | /* Change mcu queue after firmware download */ |
| 209 | MT7921_RXQ_MCU_WM, | 232 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], |
| 210 | MT7921_RX_MCU_WA_RING_SIZE, | 233 | MT7921_RXQ_MCU_WM, |
| 211 | MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); | 234 | MT7921_RX_MCU_WA_RING_SIZE, |
| 212 | if (ret) | 235 | MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); |
| 213 | return ret; | 236 | if (ret) |
| 237 | return ret; | ||
| 238 | } | ||
| 214 | 239 | ||
| 215 | /* rx data */ | 240 | /* rx data */ |
| 216 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], | 241 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], |
| @@ -276,6 +301,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, · 59 unmodified lines | |||
| 276 | struct mt76_bus_ops *bus_ops; | 301 | struct mt76_bus_ops *bus_ops; |
| 277 | struct mt792x_dev *dev; | 302 | struct mt792x_dev *dev; |
| 278 | struct mt76_dev *mdev; | 303 | struct mt76_dev *mdev; |
| 304 | void __iomem *regs; | ||
| 279 | u16 cmd, chipid; | 305 | u16 cmd, chipid; |
| 280 | u8 features; | 306 | u8 features; |
| 281 | int ret; | 307 | int ret; |
| @@ -284,10 +310,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev, · 2 unmodified lines | |||
| 284 | if (ret) | 310 | if (ret) |
| 285 | return ret; | 311 | return ret; |
| 286 | 312 | ||
| 287 | ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); | ||
| 288 | if (ret) | ||
| 289 | return ret; | ||
| 290 | |||
| 291 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | 313 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
| 292 | if (!(cmd & PCI_COMMAND_MEMORY)) { | 314 | if (!(cmd & PCI_COMMAND_MEMORY)) { |
| 293 | cmd |= PCI_COMMAND_MEMORY; | 315 | cmd |= PCI_COMMAND_MEMORY; |
| @@ -321,11 +343,29 @@ static int mt7921_pci_probe(struct pci_dev *pdev, · 27 unmodified lines | |||
| 321 | 343 | ||
| 322 | pci_set_drvdata(pdev, mdev); | 344 | pci_set_drvdata(pdev, mdev); |
| 323 | 345 | ||
| 346 | regs = pcim_iomap_region(pdev, 0, pci_name(pdev)); | ||
| 347 | if (IS_ERR(regs)) | ||
| 348 | return PTR_ERR(regs); | ||
| 349 | |||
| 324 | dev = container_of(mdev, struct mt792x_dev, mt76); | 350 | dev = container_of(mdev, struct mt792x_dev, mt76); |
| 325 | dev->fw_features = features; | 351 | dev->fw_features = features; |
| 326 | dev->hif_ops = &mt7921_pcie_ops; | 352 | dev->hif_ops = &mt7921_pcie_ops; |
| 327 | dev->irq_map = &irq_map; | 353 | dev->irq_map = &irq_map; |
| 328 | mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); | 354 | mt76_mmio_init(&dev->mt76, regs); |
| 355 | |||
| 356 | if (id->device == 0x7902) { | ||
| 357 | struct mt792x_irq_map *map; | ||
| 358 | |||
| 359 | /* MT7902 needs a mutable copy because wm2_complete_mask differs */ | ||
| 360 | map = devm_kmemdup(&pdev->dev, &irq_map, | ||
| 361 | sizeof(irq_map), GFP_KERNEL); | ||
| 362 | if (!map) | ||
| 363 | return -ENOMEM; | ||
| 364 | |||
| 365 | map->rx.wm2_complete_mask = 0; | ||
| 366 | dev->irq_map = map; | ||
| 367 | } | ||
| 368 | |||
| 329 | tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); | 369 | tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); |
| 330 | 370 | ||
| 331 | dev->phy.dev = dev; | 371 | dev->phy.dev = dev; |
| @@ -579,6 +619,8 @@ MODULE_FIRMWARE(MT7921_FIRMWARE_WM); · 247 unmodified lines | |||
| 579 | MODULE_FIRMWARE(MT7921_ROM_PATCH); | 619 | MODULE_FIRMWARE(MT7921_ROM_PATCH); |
| 580 | MODULE_FIRMWARE(MT7922_FIRMWARE_WM); | 620 | MODULE_FIRMWARE(MT7922_FIRMWARE_WM); |
| 581 | MODULE_FIRMWARE(MT7922_ROM_PATCH); | 621 | MODULE_FIRMWARE(MT7922_ROM_PATCH); |
| 622 | MODULE_FIRMWARE(MT7902_FIRMWARE_WM); | ||
| 623 | MODULE_FIRMWARE(MT7902_ROM_PATCH); | ||
| 582 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); | 624 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); |
| 583 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); | 625 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); |
| 584 | MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); | 626 | MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); |
| @@ -71,9 +71,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev) · 70 unmodified lines | |||
| 71 | mt76_txq_schedule_all(&dev->mphy); | 71 | mt76_txq_schedule_all(&dev->mphy); |
| 72 | 72 | ||
| 73 | mt76_worker_disable(&dev->mt76.tx_worker); | 73 | mt76_worker_disable(&dev->mt76.tx_worker); |
| 74 | napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); | 74 | mt76_for_each_q_rx(&dev->mt76, i) { |
| 75 | napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); | 75 | napi_disable(&dev->mt76.napi[i]); |
| 76 | napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); | 76 | } |
| 77 | napi_disable(&dev->mt76.tx_napi); | 77 | napi_disable(&dev->mt76.tx_napi); |
| 78 | 78 | ||
| 79 | mt76_connac2_tx_token_put(&dev->mt76); | 79 | mt76_connac2_tx_token_put(&dev->mt76); |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | |||
| 19 | static const struct sdio_device_id mt7921s_table[] = { | 19 | static const struct sdio_device_id mt7921s_table[] = { |
| 20 | { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901), | 20 | { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901), |
| 21 | .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, | 21 | .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, |
| 22 | { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7902), | ||
| 23 | .driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM }, | ||
| 22 | { } /* Terminating entry */ | 24 | { } /* Terminating entry */ |
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| @@ -317,6 +319,8 @@ failed: · 292 unmodified lines | |||
| 317 | MODULE_DEVICE_TABLE(sdio, mt7921s_table); | 319 | MODULE_DEVICE_TABLE(sdio, mt7921s_table); |
| 318 | MODULE_FIRMWARE(MT7921_FIRMWARE_WM); | 320 | MODULE_FIRMWARE(MT7921_FIRMWARE_WM); |
| 319 | MODULE_FIRMWARE(MT7921_ROM_PATCH); | 321 | MODULE_FIRMWARE(MT7921_ROM_PATCH); |
| 322 | MODULE_FIRMWARE(MT7902_FIRMWARE_WM); | ||
| 323 | MODULE_FIRMWARE(MT7902_ROM_PATCH); | ||
| 320 | 324 | ||
| 321 | static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume); | 325 | static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume); |
| 322 | 326 | ||
| @@ -91,6 +91,8 @@ int mt7925_mac_init(struct mt792x_dev *dev) · 90 unmodified lines | |||
| 91 | 91 | ||
| 92 | mt7925_mac_init_basic_rates(dev); | 92 | mt7925_mac_init_basic_rates(dev); |
| 93 | 93 | ||
| 94 | memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); | ||
| 95 | |||
| 94 | return 0; | 96 | return 0; |
| 95 | } | 97 | } |
| 96 | EXPORT_SYMBOL_GPL(mt7925_mac_init); | 98 | EXPORT_SYMBOL_GPL(mt7925_mac_init); |
| @@ -804,8 +804,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, · 803 unmodified lines | |||
| 804 | txwi[5] = cpu_to_le32(val); | 804 | txwi[5] = cpu_to_le32(val); |
| 805 | 805 | ||
| 806 | val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); | 806 | val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); |
| 807 | if (!ieee80211_vif_is_mld(vif) || | 807 | if (vif && (!ieee80211_vif_is_mld(vif) || |
| 808 | (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) | 808 | (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) |
| 809 | val |= MT_TXD6_DIS_MAT; | 809 | val |= MT_TXD6_DIS_MAT; |
| 810 | txwi[6] = cpu_to_le32(val); | 810 | txwi[6] = cpu_to_le32(val); |
| 811 | txwi[7] = 0; | 811 | txwi[7] = 0; |
| @@ -846,11 +846,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, · 34 unmodified lines | |||
| 846 | bool is_8023; | 846 | bool is_8023; |
| 847 | u16 fc, tid; | 847 | u16 fc, tid; |
| 848 | 848 | ||
| 849 | if (!sta) | ||
| 850 | return; | ||
| 851 | |||
| 849 | link_sta = rcu_dereference(sta->link[wcid->link_id]); | 852 | link_sta = rcu_dereference(sta->link[wcid->link_id]); |
| 850 | if (!link_sta) | 853 | if (!link_sta) |
| 851 | return; | 854 | return; |
| 852 | 855 | ||
| 853 | if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) | 856 | if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) |
| 854 | return; | 857 | return; |
| 855 | 858 | ||
| 856 | tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; | 859 | tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
| @@ -882,8 +885,10 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, · 25 unmodified lines | |||
| 882 | else | 885 | else |
| 883 | mlink = &msta->deflink; | 886 | mlink = &msta->deflink; |
| 884 | 887 | ||
| 885 | if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) | 888 | if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) { |
| 886 | ieee80211_start_tx_ba_session(sta, tid, 0); | 889 | if (ieee80211_start_tx_ba_session(sta, tid, 0)) |
| 890 | clear_bit(tid, &mlink->wcid.ampdu_state); | ||
| 891 | } | ||
| 887 | } | 892 | } |
| 888 | 893 | ||
| 889 | static bool | 894 | static bool |
| @@ -1280,7 +1285,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, · 390 unmodified lines | |||
| 1280 | if (vif->type == NL80211_IFTYPE_AP) { | 1285 | if (vif->type == NL80211_IFTYPE_AP) { |
| 1281 | mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, | 1286 | mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, |
| 1282 | true, NULL); | 1287 | true, NULL); |
| 1283 | mt7925_mcu_sta_update(dev, NULL, vif, true, | 1288 | mt7925_mcu_sta_update(dev, NULL, vif, |
| 1289 | &mvif->sta.deflink, true, | ||
| 1284 | MT76_STA_INFO_STATE_NONE); | 1290 | MT76_STA_INFO_STATE_NONE); |
| 1285 | mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); | 1291 | mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); |
| 1286 | } | 1292 | } |
| @@ -245,6 +245,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy) · 244 unmodified lines | |||
| 245 | { | 245 | { |
| 246 | struct wiphy *wiphy = phy->mt76->hw->wiphy; | 246 | struct wiphy *wiphy = phy->mt76->hw->wiphy; |
| 247 | static const u8 ext_capa_sta[] = { | 247 | static const u8 ext_capa_sta[] = { |
| 248 | [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, | ||
| 248 | [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, | 249 | [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, |
| 249 | [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, | 250 | [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, |
| 250 | }; | 251 | }; |
| @@ -438,6 +439,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) · 187 unmodified lines | |||
| 438 | if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) | 439 | if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) |
| 439 | vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; | 440 | vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; |
| 440 | 441 | ||
| 442 | INIT_WORK(&mvif->csa_work, mt7925_csa_work); | ||
| 443 | timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0); | ||
| 444 | |||
| 441 | out: | 445 | out: |
| 442 | mt792x_mutex_release(dev); | 446 | mt792x_mutex_release(dev); |
| 443 | 447 | ||
| @@ -457,12 +461,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev) · 13 unmodified lines | |||
| 457 | { | 461 | { |
| 458 | struct mt792x_phy *phy = &dev->phy; | 462 | struct mt792x_phy *phy = &dev->phy; |
| 459 | 463 | ||
| 464 | if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | ||
| 465 | return; | ||
| 466 | |||
| 460 | timer_delete_sync(&phy->roc_timer); | 467 | timer_delete_sync(&phy->roc_timer); |
| 461 | cancel_work_sync(&phy->roc_work); | 468 | |
| 462 | if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | 469 | cancel_work(&phy->roc_work); |
| 463 | ieee80211_iterate_interfaces(mt76_hw(dev), | 470 | |
| 464 | IEEE80211_IFACE_ITER_RESUME_ALL, | 471 | ieee80211_iterate_interfaces(mt76_hw(dev), |
| 465 | mt7925_roc_iter, (void *)phy); | 472 | IEEE80211_IFACE_ITER_RESUME_ALL, |
| 473 | mt7925_roc_iter, (void *)phy); | ||
| 466 | } | 474 | } |
| 467 | EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); | 475 | EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); |
| 468 | 476 | ||
| @@ -541,7 +549,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy, · 72 unmodified lines | |||
| 541 | 549 | ||
| 542 | phy->roc_grant = false; | 550 | phy->roc_grant = false; |
| 543 | 551 | ||
| 544 | err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); | 552 | err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id); |
| 545 | if (err < 0) { | 553 | if (err < 0) { |
| 546 | clear_bit(MT76_STATE_ROC, &phy->mt76->state); | 554 | clear_bit(MT76_STATE_ROC, &phy->mt76->state); |
| 547 | goto out; | 555 | goto out; |
| @@ -586,7 +594,8 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, · 38 unmodified lines | |||
| 586 | 594 | ||
| 587 | static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 595 | static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
| 588 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | 596 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, |
| 589 | struct ieee80211_key_conf *key, int link_id) | 597 | struct ieee80211_key_conf *key, int link_id, |
| 598 | struct mt792x_link_sta *mlink) | ||
| 590 | { | 599 | { |
| 591 | struct mt792x_dev *dev = mt792x_hw_dev(hw); | 600 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
| 592 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 601 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| @@ -595,7 +604,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 2 unmodified lines | |||
| 595 | struct ieee80211_bss_conf *link_conf; | 604 | struct ieee80211_bss_conf *link_conf; |
| 596 | struct ieee80211_link_sta *link_sta; | 605 | struct ieee80211_link_sta *link_sta; |
| 597 | int idx = key->keyidx, err = 0; | 606 | int idx = key->keyidx, err = 0; |
| 598 | struct mt792x_link_sta *mlink; | ||
| 599 | struct mt792x_bss_conf *mconf; | 607 | struct mt792x_bss_conf *mconf; |
| 600 | struct mt76_wcid *wcid; | 608 | struct mt76_wcid *wcid; |
| 601 | u8 *wcid_keyidx; | 609 | u8 *wcid_keyidx; |
| @@ -603,7 +611,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 1 unmodified line | |||
| 603 | link_conf = mt792x_vif_to_bss_conf(vif, link_id); | 611 | link_conf = mt792x_vif_to_bss_conf(vif, link_id); |
| 604 | link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; | 612 | link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; |
| 605 | mconf = mt792x_vif_to_link(mvif, link_id); | 613 | mconf = mt792x_vif_to_link(mvif, link_id); |
| 606 | mlink = mt792x_sta_to_link(msta, link_id); | ||
| 607 | wcid = &mlink->wcid; | 614 | wcid = &mlink->wcid; |
| 608 | wcid_keyidx = &wcid->hw_key_idx; | 615 | wcid_keyidx = &wcid->hw_key_idx; |
| 609 | 616 | ||
| @@ -671,6 +678,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 61 unmodified lines | |||
| 671 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 678 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 672 | struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : | 679 | struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : |
| 673 | &mvif->sta; | 680 | &mvif->sta; |
| 681 | struct mt792x_link_sta *mlink; | ||
| 674 | int err; | 682 | int err; |
| 675 | 683 | ||
| 676 | /* The hardware does not support per-STA RX GTK, fallback | 684 | /* The hardware does not support per-STA RX GTK, fallback |
| @@ -692,12 +700,16 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 15 unmodified lines | |||
| 692 | add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; | 700 | add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; |
| 693 | 701 | ||
| 694 | for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { | 702 | for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 695 | err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id); | 703 | mlink = mt792x_sta_to_link(msta, link_id); |
| 704 | err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id, | ||
| 705 | mlink); | ||
| 696 | if (err < 0) | 706 | if (err < 0) |
| 697 | break; | 707 | break; |
| 698 | } | 708 | } |
| 699 | } else { | 709 | } else { |
| 700 | err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); | 710 | mlink = mt792x_sta_to_link(msta, vif->bss_conf.link_id); |
| 711 | err = mt7925_set_link_key(hw, cmd, vif, sta, key, | ||
| 712 | vif->bss_conf.link_id, mlink); | ||
| 701 | } | 713 | } |
| 702 | 714 | ||
| 703 | mt792x_mutex_release(dev); | 715 | mt792x_mutex_release(dev); |
| @@ -842,20 +854,24 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 138 unmodified lines | |||
| 842 | 854 | ||
| 843 | static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, | 855 | static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, |
| 844 | struct ieee80211_vif *vif, | 856 | struct ieee80211_vif *vif, |
| 845 | struct ieee80211_link_sta *link_sta) | 857 | struct ieee80211_link_sta *link_sta, |
| 858 | struct mt792x_link_sta *mlink) | ||
| 846 | { | 859 | { |
| 847 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); | 860 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
| 848 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 861 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 849 | struct ieee80211_bss_conf *link_conf; | 862 | struct ieee80211_bss_conf *link_conf; |
| 850 | struct mt792x_bss_conf *mconf; | 863 | struct mt792x_bss_conf *mconf; |
| 851 | u8 link_id = link_sta->link_id; | 864 | u8 link_id = link_sta->link_id; |
| 852 | struct mt792x_link_sta *mlink; | 865 | bool wcid_published = false; |
| 853 | struct mt792x_sta *msta; | 866 | struct mt792x_sta *msta; |
| 854 | struct mt76_wcid *wcid; | 867 | struct mt76_wcid *wcid; |
| 868 | bool pm_woken = false; | ||
| 855 | int ret, idx; | 869 | int ret, idx; |
| 856 | 870 | ||
| 857 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | 871 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; |
| 858 | mlink = mt792x_sta_to_link(msta, link_id); | 872 | |
| 873 | if (WARN_ON_ONCE(!mlink)) | ||
| 874 | return -EINVAL; | ||
| 859 | 875 | ||
| 860 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); | 876 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); |
| 861 | if (idx < 0) | 877 | if (idx < 0) |
| @@ -874,14 +890,15 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, · 12 unmodified lines | |||
| 874 | wcid = &mlink->wcid; | 890 | wcid = &mlink->wcid; |
| 875 | ewma_signal_init(&wcid->rssi); | 891 | ewma_signal_init(&wcid->rssi); |
| 876 | rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); | 892 | rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); |
| 877 | mt76_wcid_init(wcid, 0); | 893 | wcid_published = true; |
| 878 | ewma_avg_signal_init(&mlink->avg_ack_signal); | 894 | ewma_avg_signal_init(&mlink->avg_ack_signal); |
| 879 | memset(mlink->airtime_ac, 0, | 895 | memset(mlink->airtime_ac, 0, |
| 880 | sizeof(msta->deflink.airtime_ac)); | 896 | sizeof(msta->deflink.airtime_ac)); |
| 881 | 897 | ||
| 882 | ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); | 898 | ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); |
| 883 | if (ret) | 899 | if (ret) |
| 884 | return ret; | 900 | goto out_wcid; |
| 901 | pm_woken = true; | ||
| 885 | 902 | ||
| 886 | mt7925_mac_wtbl_update(dev, idx, | 903 | mt7925_mac_wtbl_update(dev, idx, |
| 887 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | 904 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| @@ -890,41 +907,125 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, · 2 unmodified lines | |||
| 890 | 907 | ||
| 891 | /* should update bss info before STA add */ | 908 | /* should update bss info before STA add */ |
| 892 | if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { | 909 | if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { |
| 893 | if (ieee80211_vif_is_mld(vif)) | 910 | struct mt792x_link_sta *mlink_bc; |
| 894 | mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, | 911 | |
| 895 | link_conf, link_sta, link_sta != mlink->pri_link); | 912 | mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); |
| 896 | else | 913 | |
| 897 | mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, | 914 | if (ieee80211_vif_is_mld(vif)) { |
| 898 | link_conf, link_sta, false); | 915 | ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx, |
| 916 | link_conf, link_sta, | ||
| 917 | mlink_bc->wcid.idx, mlink->wcid.idx, | ||
| 918 | link_sta != mlink->pri_link); | ||
| 919 | if (ret) | ||
| 920 | goto out_pm; | ||
| 921 | } else { | ||
| 922 | ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx, | ||
| 923 | link_conf, link_sta, | ||
| 924 | mlink_bc->wcid.idx, mlink->wcid.idx, | ||
| 925 | false); | ||
| 926 | if (ret) | ||
| 927 | goto out_pm; | ||
| 928 | } | ||
| 899 | } | 929 | } |
| 900 | 930 | ||
| 901 | if (ieee80211_vif_is_mld(vif) && | 931 | if (ieee80211_vif_is_mld(vif) && |
| 902 | link_sta == mlink->pri_link) { | 932 | link_sta == mlink->pri_link) { |
| 903 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, | 933 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, |
| 934 | mlink, true, | ||
| 904 | MT76_STA_INFO_STATE_NONE); | 935 | MT76_STA_INFO_STATE_NONE); |
| 905 | if (ret) | 936 | if (ret) |
| 906 | return ret; | 937 | goto out_pm; |
| 907 | } else if (ieee80211_vif_is_mld(vif) && | 938 | } else if (ieee80211_vif_is_mld(vif) && |
| 908 | link_sta != mlink->pri_link) { | 939 | link_sta != mlink->pri_link) { |
| 940 | struct mt792x_link_sta *pri_mlink; | ||
| 941 | struct mt76_wcid *pri_wcid; | ||
| 942 | |||
| 943 | /* alternative lookup via def_wcid */ | ||
| 944 | pri_wcid = mlink->wcid.def_wcid; | ||
| 945 | |||
| 946 | pri_mlink = pri_wcid ? | ||
| 947 | container_of(pri_wcid, struct mt792x_link_sta, wcid) : | ||
| 948 | NULL; | ||
| 949 | |||
| 950 | if (WARN_ON_ONCE(!pri_mlink)) { | ||
| 951 | ret = -EINVAL; | ||
| 952 | goto out_pm; | ||
| 953 | } | ||
| 954 | |||
| 909 | ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, | 955 | ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, |
| 910 | true, MT76_STA_INFO_STATE_ASSOC); | 956 | pri_mlink, true, |
| 957 | MT76_STA_INFO_STATE_ASSOC); | ||
| 911 | if (ret) | 958 | if (ret) |
| 912 | return ret; | 959 | goto out_pm; |
| 913 | 960 | ||
| 914 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, | 961 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, |
| 962 | mlink, true, | ||
| 915 | MT76_STA_INFO_STATE_ASSOC); | 963 | MT76_STA_INFO_STATE_ASSOC); |
| 916 | if (ret) | 964 | if (ret) |
| 917 | return ret; | 965 | goto out_pm; |
| 918 | } else { | 966 | } else { |
| 919 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, | 967 | ret = mt7925_mcu_sta_update(dev, link_sta, vif, |
| 968 | mlink, true, | ||
| 920 | MT76_STA_INFO_STATE_NONE); | 969 | MT76_STA_INFO_STATE_NONE); |
| 921 | if (ret) | 970 | if (ret) |
| 922 | return ret; | 971 | goto out_pm; |
| 923 | } | 972 | } |
| 924 | 973 | ||
| 925 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); | 974 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); |
| 926 | 975 | ||
| 927 | return 0; | 976 | return 0; |
| 977 | |||
| 978 | out_pm: | ||
| 979 | if (pm_woken) | ||
| 980 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); | ||
| 981 | out_wcid: | ||
| 982 | if (wcid_published) { | ||
| 983 | u16 idx = wcid->idx; | ||
| 984 | |||
| 985 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); | ||
| 986 | mt76_wcid_cleanup(mdev, wcid); | ||
| 987 | mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); | ||
| 988 | } | ||
| 989 | return ret; | ||
| 990 | } | ||
| 991 | |||
| 992 | /* | ||
| 993 | * Host-only unwind for sta_add_links() failures. | ||
| 994 | * | ||
| 995 | * If add_links fail due to MCU/firmware timeouts; calling the full remove | ||
| 996 | * path would send more firmware commands and may hang again. So only rollback | ||
| 997 | * host-published state here (msta->link/valid_links, dev->mt76.wcid[idx]) and | ||
| 998 | * free mlink objects (RCU-safe). Firmware state is left for reset/recovery. | ||
| 999 | */ | ||
| 1000 | static void | ||
| 1001 | mt7925_mac_sta_unwind_links_host(struct mt792x_dev *dev, | ||
| 1002 | struct ieee80211_sta *sta, | ||
| 1003 | unsigned long links) | ||
| 1004 | { | ||
| 1005 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; | ||
| 1006 | unsigned int link_id; | ||
| 1007 | |||
| 1008 | for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1009 | struct mt792x_link_sta *mlink; | ||
| 1010 | u16 idx; | ||
| 1011 | |||
| 1012 | mlink = rcu_replace_pointer(msta->link[link_id], NULL, | ||
| 1013 | lockdep_is_held(&dev->mt76.mutex)); | ||
| 1014 | if (!mlink) | ||
| 1015 | continue; | ||
| 1016 | |||
| 1017 | msta->valid_links &= ~BIT(link_id); | ||
| 1018 | if (msta->deflink_id == link_id) | ||
| 1019 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; | ||
| 1020 | |||
| 1021 | idx = mlink->wcid.idx; | ||
| 1022 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); | ||
| 1023 | mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); | ||
| 1024 | mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); | ||
| 1025 | |||
| 1026 | if (mlink != &msta->deflink) | ||
| 1027 | kfree_rcu(mlink, rcu_head); | ||
| 1028 | } | ||
| 928 | } | 1029 | } |
| 929 | 1030 | ||
| 930 | static int | 1031 | static int |
| @@ -932,34 +1033,50 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, · 1 unmodified line | |||
| 932 | struct ieee80211_sta *sta, unsigned long new_links) | 1033 | struct ieee80211_sta *sta, unsigned long new_links) |
| 933 | { | 1034 | { |
| 934 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; | 1035 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1036 | unsigned long added_links = 0; | ||
| 935 | unsigned int link_id; | 1037 | unsigned int link_id; |
| 936 | int err = 0; | 1038 | int err = 0; |
| 937 | 1039 | ||
| 938 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { | 1040 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 939 | struct ieee80211_link_sta *link_sta; | 1041 | struct ieee80211_link_sta *link_sta; |
| 940 | struct mt792x_link_sta *mlink; | 1042 | struct mt792x_link_sta *mlink; |
| 1043 | bool is_deflink = false; | ||
| 941 | 1044 | ||
| 942 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { | 1045 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { |
| 943 | mlink = &msta->deflink; | 1046 | mlink = &msta->deflink; |
| 944 | msta->deflink_id = link_id; | 1047 | is_deflink = true; |
| 945 | } else { | 1048 | } else { |
| 946 | mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); | 1049 | mlink = kzalloc(sizeof(*mlink), GFP_KERNEL); |
| 947 | if (!mlink) { | 1050 | if (!mlink) { |
| 948 | err = -ENOMEM; | 1051 | err = -ENOMEM; |
| 949 | break; | 1052 | break; |
| 950 | } | 1053 | } |
| 951 | } | 1054 | } |
| 952 | 1055 | ||
| 953 | msta->valid_links |= BIT(link_id); | ||
| 954 | rcu_assign_pointer(msta->link[link_id], mlink); | ||
| 955 | mlink->sta = msta; | 1056 | mlink->sta = msta; |
| 956 | mlink->pri_link = &sta->deflink; | 1057 | mlink->pri_link = &sta->deflink; |
| 957 | mlink->wcid.def_wcid = &msta->deflink.wcid; | 1058 | mlink->wcid.def_wcid = &msta->deflink.wcid; |
| 958 | 1059 | ||
| 959 | link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); | 1060 | link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); |
| 960 | mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta); | 1061 | err = mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink); |
| 1062 | if (err) { | ||
| 1063 | if (!is_deflink) | ||
| 1064 | kfree_rcu(mlink, rcu_head); | ||
| 1065 | break; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | if (is_deflink) | ||
| 1069 | msta->deflink_id = link_id; | ||
| 1070 | |||
| 1071 | rcu_assign_pointer(msta->link[link_id], mlink); | ||
| 1072 | msta->valid_links |= BIT(link_id); | ||
| 1073 | |||
| 1074 | added_links |= BIT(link_id); | ||
| 961 | } | 1075 | } |
| 962 | 1076 | ||
| 1077 | if (err && added_links) | ||
| 1078 | mt7925_mac_sta_unwind_links_host(dev, sta, added_links); | ||
| 1079 | |||
| 963 | return err; | 1080 | return err; |
| 964 | } | 1081 | } |
| 965 | 1082 | ||
| @@ -981,7 +1098,8 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, · 15 unmodified lines | |||
| 981 | 1098 | ||
| 982 | err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); | 1099 | err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); |
| 983 | } else { | 1100 | } else { |
| 984 | err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); | 1101 | err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink, |
| 1102 | &msta->deflink); | ||
| 985 | } | 1103 | } |
| 986 | 1104 | ||
| 987 | return err; | 1105 | return err; |
| @@ -1030,11 +1148,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, · 42 unmodified lines | |||
| 1030 | struct mt792x_link_sta *mlink; | 1148 | struct mt792x_link_sta *mlink; |
| 1031 | struct mt792x_sta *msta; | 1149 | struct mt792x_sta *msta; |
| 1032 | 1150 | ||
| 1151 | mt792x_mutex_acquire(dev); | ||
| 1152 | |||
| 1033 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | 1153 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; |
| 1034 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | 1154 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); |
| 1035 | 1155 | ||
| 1036 | mt792x_mutex_acquire(dev); | ||
| 1037 | |||
| 1038 | if (ieee80211_vif_is_mld(vif)) { | 1156 | if (ieee80211_vif_is_mld(vif)) { |
| 1039 | link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); | 1157 | link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); |
| 1040 | } else { | 1158 | } else { |
| @@ -1055,7 +1173,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, · 14 unmodified lines | |||
| 1055 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | 1173 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 1056 | memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); | 1174 | memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); |
| 1057 | 1175 | ||
| 1058 | mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC); | 1176 | mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, |
| 1177 | MT76_STA_INFO_STATE_ASSOC); | ||
| 1059 | 1178 | ||
| 1060 | mt792x_mutex_release(dev); | 1179 | mt792x_mutex_release(dev); |
| 1061 | } | 1180 | } |
| @@ -1083,23 +1202,21 @@ EXPORT_SYMBOL_GPL(mt7925_mac_sta_event); · 21 unmodified lines | |||
| 1083 | 1202 | ||
| 1084 | static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, | 1203 | static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, |
| 1085 | struct ieee80211_vif *vif, | 1204 | struct ieee80211_vif *vif, |
| 1086 | struct ieee80211_link_sta *link_sta) | 1205 | struct ieee80211_link_sta *link_sta, |
| 1206 | struct mt792x_link_sta *mlink) | ||
| 1087 | { | 1207 | { |
| 1088 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); | 1208 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
| 1209 | struct mt76_wcid *wcid = &mlink->wcid; | ||
| 1089 | struct ieee80211_bss_conf *link_conf; | 1210 | struct ieee80211_bss_conf *link_conf; |
| 1090 | u8 link_id = link_sta->link_id; | 1211 | u8 link_id = link_sta->link_id; |
| 1091 | struct mt792x_link_sta *mlink; | 1212 | u16 idx = wcid->idx; |
| 1092 | struct mt792x_sta *msta; | ||
| 1093 | |||
| 1094 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | ||
| 1095 | mlink = mt792x_sta_to_link(msta, link_id); | ||
| 1096 | 1213 | ||
| 1097 | mt7925_roc_abort_sync(dev); | 1214 | mt7925_roc_abort_sync(dev); |
| 1098 | 1215 | ||
| 1099 | mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); | 1216 | mt76_connac_free_pending_tx_skbs(&dev->pm, wcid); |
| 1100 | mt76_connac_pm_wake(&dev->mphy, &dev->pm); | 1217 | mt76_connac_pm_wake(&dev->mphy, &dev->pm); |
| 1101 | 1218 | ||
| 1102 | mt7925_mcu_sta_update(dev, link_sta, vif, false, | 1219 | mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false, |
| 1103 | MT76_STA_INFO_STATE_NONE); | 1220 | MT76_STA_INFO_STATE_NONE); |
| 1104 | mt7925_mac_wtbl_update(dev, mlink->wcid.idx, | 1221 | mt7925_mac_wtbl_update(dev, mlink->wcid.idx, |
| 1105 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | 1222 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| @@ -1123,6 +1240,10 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, · 17 unmodified lines | |||
| 1123 | list_del_init(&mlink->wcid.poll_list); | 1240 | list_del_init(&mlink->wcid.poll_list); |
| 1124 | spin_unlock_bh(&mdev->sta_poll_lock); | 1241 | spin_unlock_bh(&mdev->sta_poll_lock); |
| 1125 | 1242 | ||
| 1243 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); | ||
| 1244 | mt76_wcid_cleanup(mdev, wcid); | ||
| 1245 | mt76_wcid_mask_clear(mdev->wcid_mask, idx); | ||
| 1246 | |||
| 1126 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); | 1247 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); |
| 1127 | } | 1248 | } |
| 1128 | 1249 | ||
| @@ -1132,7 +1253,6 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, · 3 unmodified lines | |||
| 1132 | { | 1253 | { |
| 1133 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; | 1254 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1134 | struct mt76_dev *mdev = &dev->mt76; | 1255 | struct mt76_dev *mdev = &dev->mt76; |
| 1135 | struct mt76_wcid *wcid; | ||
| 1136 | unsigned int link_id; | 1256 | unsigned int link_id; |
| 1137 | 1257 | ||
| 1138 | /* clean up bss before starec */ | 1258 | /* clean up bss before starec */ |
| @@ -1171,22 +1291,19 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, · 32 unmodified lines | |||
| 1171 | if (!link_sta) | 1291 | if (!link_sta) |
| 1172 | continue; | 1292 | continue; |
| 1173 | 1293 | ||
| 1174 | mlink = mt792x_sta_to_link(msta, link_id); | 1294 | mlink = rcu_replace_pointer(msta->link[link_id], NULL, |
| 1295 | lockdep_is_held(&mdev->mutex)); | ||
| 1175 | if (!mlink) | 1296 | if (!mlink) |
| 1176 | continue; | 1297 | continue; |
| 1177 | 1298 | ||
| 1178 | mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta); | ||
| 1179 | |||
| 1180 | wcid = &mlink->wcid; | ||
| 1181 | rcu_assign_pointer(msta->link[link_id], NULL); | ||
| 1182 | msta->valid_links &= ~BIT(link_id); | 1299 | msta->valid_links &= ~BIT(link_id); |
| 1183 | mlink->sta = NULL; | 1300 | mlink->sta = NULL; |
| 1184 | mlink->pri_link = NULL; | 1301 | mlink->pri_link = NULL; |
| 1185 | 1302 | ||
| 1186 | if (link_sta != mlink->pri_link) { | 1303 | mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink); |
| 1187 | mt76_wcid_cleanup(mdev, wcid); | 1304 | |
| 1188 | mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); | 1305 | if (mlink != &msta->deflink) |
| 1189 | } | 1306 | kfree_rcu(mlink, rcu_head); |
| 1190 | 1307 | ||
| 1191 | if (msta->deflink_id == link_id) | 1308 | if (msta->deflink_id == link_id) |
| 1192 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; | 1309 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; |
| @@ -1323,10 +1440,18 @@ void mt7925_mlo_pm_work(struct work_struct *work) · 130 unmodified lines | |||
| 1323 | void mt7925_scan_work(struct work_struct *work) | 1440 | void mt7925_scan_work(struct work_struct *work) |
| 1324 | { | 1441 | { |
| 1325 | struct mt792x_phy *phy; | 1442 | struct mt792x_phy *phy; |
| 1443 | struct mt792x_dev *dev; | ||
| 1444 | struct mt76_connac_pm *pm; | ||
| 1326 | 1445 | ||
| 1327 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, | 1446 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, |
| 1328 | scan_work.work); | 1447 | scan_work.work); |
| 1329 | 1448 | ||
| 1449 | dev = phy->dev; | ||
| 1450 | pm = &dev->pm; | ||
| 1451 | |||
| 1452 | if (pm->suspended) | ||
| 1453 | return; | ||
| 1454 | |||
| 1330 | while (true) { | 1455 | while (true) { |
| 1331 | struct sk_buff *skb; | 1456 | struct sk_buff *skb; |
| 1332 | struct tlv *tlv; | 1457 | struct tlv *tlv; |
| @@ -1544,8 +1669,10 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, · 211 unmodified lines | |||
| 1544 | valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); | 1669 | valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); |
| 1545 | 1670 | ||
| 1546 | for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { | 1671 | for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 1672 | struct mt792x_bss_conf *mconf; | ||
| 1547 | struct mt792x_link_sta *mlink; | 1673 | struct mt792x_link_sta *mlink; |
| 1548 | 1674 | ||
| 1675 | mconf = mt792x_vif_to_link(mvif, i); | ||
| 1549 | mlink = mt792x_sta_to_link(msta, i); | 1676 | mlink = mt792x_sta_to_link(msta, i); |
| 1550 | 1677 | ||
| 1551 | if (enabled) | 1678 | if (enabled) |
| @@ -1556,7 +1683,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, · 4 unmodified lines | |||
| 1556 | if (!mlink->wcid.sta) | 1683 | if (!mlink->wcid.sta) |
| 1557 | continue; | 1684 | continue; |
| 1558 | 1685 | ||
| 1559 | mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i); | 1686 | mt7925_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink); |
| 1560 | } | 1687 | } |
| 1561 | 1688 | ||
| 1562 | mt792x_mutex_release(dev); | 1689 | mt792x_mutex_release(dev); |
| @@ -1716,7 +1843,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 153 unmodified lines | |||
| 1716 | if (err) | 1843 | if (err) |
| 1717 | goto out; | 1844 | goto out; |
| 1718 | 1845 | ||
| 1719 | err = mt7925_mcu_sta_update(dev, NULL, vif, true, | 1846 | err = mt7925_mcu_sta_update(dev, NULL, vif, |
| 1847 | &mvif->sta.deflink, true, | ||
| 1720 | MT76_STA_INFO_STATE_NONE); | 1848 | MT76_STA_INFO_STATE_NONE); |
| 1721 | out: | 1849 | out: |
| 1722 | mt792x_mutex_release(dev); | 1850 | mt792x_mutex_release(dev); |
| @@ -1749,6 +1877,10 @@ static int · 26 unmodified lines | |||
| 1749 | mt7925_add_chanctx(struct ieee80211_hw *hw, | 1877 | mt7925_add_chanctx(struct ieee80211_hw *hw, |
| 1750 | struct ieee80211_chanctx_conf *ctx) | 1878 | struct ieee80211_chanctx_conf *ctx) |
| 1751 | { | 1879 | { |
| 1880 | struct mt792x_dev *dev = mt792x_hw_dev(hw); | ||
| 1881 | |||
| 1882 | dev->new_ctx = ctx; | ||
| 1883 | |||
| 1752 | return 0; | 1884 | return 0; |
| 1753 | } | 1885 | } |
| 1754 | 1886 | ||
| @@ -1756,6 +1888,11 @@ static void · 1 unmodified line | |||
| 1756 | mt7925_remove_chanctx(struct ieee80211_hw *hw, | 1888 | mt7925_remove_chanctx(struct ieee80211_hw *hw, |
| 1757 | struct ieee80211_chanctx_conf *ctx) | 1889 | struct ieee80211_chanctx_conf *ctx) |
| 1758 | { | 1890 | { |
| 1891 | struct mt792x_dev *dev = mt792x_hw_dev(hw); | ||
| 1892 | |||
| 1893 | if (dev->new_ctx == ctx) | ||
| 1894 | dev->new_ctx = NULL; | ||
| 1895 | |||
| 1759 | } | 1896 | } |
| 1760 | 1897 | ||
| 1761 | static void | 1898 | static void |
| @@ -1850,7 +1987,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, · 88 unmodified lines | |||
| 1850 | mt792x_mutex_acquire(dev); | 1987 | mt792x_mutex_acquire(dev); |
| 1851 | 1988 | ||
| 1852 | if (changed & BSS_CHANGED_ASSOC) { | 1989 | if (changed & BSS_CHANGED_ASSOC) { |
| 1853 | mt7925_mcu_sta_update(dev, NULL, vif, true, | 1990 | mt7925_mcu_sta_update(dev, NULL, vif, |
| 1991 | &mvif->sta.deflink, true, | ||
| 1854 | MT76_STA_INFO_STATE_ASSOC); | 1992 | MT76_STA_INFO_STATE_ASSOC); |
| 1855 | mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); | 1993 | mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); |
| 1856 | 1994 | ||
| @@ -1894,10 +2032,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, · 37 unmodified lines | |||
| 1894 | struct mt792x_phy *phy = mt792x_hw_phy(hw); | 2032 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
| 1895 | struct mt792x_dev *dev = mt792x_hw_dev(hw); | 2033 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
| 1896 | struct mt792x_bss_conf *mconf; | 2034 | struct mt792x_bss_conf *mconf; |
| 1897 | struct ieee80211_bss_conf *link_conf; | ||
| 1898 | 2035 | ||
| 1899 | mconf = mt792x_vif_to_link(mvif, info->link_id); | 2036 | mconf = mt792x_vif_to_link(mvif, info->link_id); |
| 1900 | link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); | ||
| 1901 | 2037 | ||
| 1902 | mt792x_mutex_acquire(dev); | 2038 | mt792x_mutex_acquire(dev); |
| 1903 | 2039 | ||
| @@ -1939,10 +2075,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, · 35 unmodified lines | |||
| 1939 | mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; | 2075 | mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; |
| 1940 | } | 2076 | } |
| 1941 | 2077 | ||
| 1942 | if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) | ||
| 1943 | mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, | ||
| 1944 | link_conf, NULL); | ||
| 1945 | |||
| 1946 | if (changed & BSS_CHANGED_CQM) | 2078 | if (changed & BSS_CHANGED_CQM) |
| 1947 | mt7925_mcu_set_rssimonitor(dev, vif); | 2079 | mt7925_mcu_set_rssimonitor(dev, vif); |
| 1948 | 2080 | ||
| @@ -2144,6 +2276,11 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw, · 195 unmodified lines | |||
| 2144 | mctx->bss_conf = NULL; | 2276 | mctx->bss_conf = NULL; |
| 2145 | mconf->mt76.ctx = NULL; | 2277 | mconf->mt76.ctx = NULL; |
| 2146 | mutex_unlock(&dev->mt76.mutex); | 2278 | mutex_unlock(&dev->mt76.mutex); |
| 2279 | |||
| 2280 | if (link_conf->csa_active) { | ||
| 2281 | timer_delete_sync(&mvif->csa_timer); | ||
| 2282 | cancel_work_sync(&mvif->csa_work); | ||
| 2283 | } | ||
| 2147 | } | 2284 | } |
| 2148 | 2285 | ||
| 2149 | static void mt7925_rfkill_poll(struct ieee80211_hw *hw) | 2286 | static void mt7925_rfkill_poll(struct ieee80211_hw *hw) |
| @@ -2158,6 +2295,121 @@ static void mt7925_rfkill_poll(struct ieee80211_hw *hw) · 8 unmodified lines | |||
| 2158 | wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0); | 2295 | wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0); |
| 2159 | } | 2296 | } |
| 2160 | 2297 | ||
| 2298 | static int mt7925_switch_vif_chanctx(struct ieee80211_hw *hw, | ||
| 2299 | struct ieee80211_vif_chanctx_switch *vifs, | ||
| 2300 | int n_vifs, | ||
| 2301 | enum ieee80211_chanctx_switch_mode mode) | ||
| 2302 | { | ||
| 2303 | return mt7925_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf, | ||
| 2304 | vifs->new_ctx); | ||
| 2305 | } | ||
| 2306 | |||
| 2307 | void mt7925_csa_work(struct work_struct *work) | ||
| 2308 | { | ||
| 2309 | struct mt792x_vif *mvif; | ||
| 2310 | struct mt792x_dev *dev; | ||
| 2311 | struct ieee80211_vif *vif; | ||
| 2312 | struct ieee80211_bss_conf *link_conf; | ||
| 2313 | struct mt792x_bss_conf *mconf; | ||
| 2314 | u8 link_id, roc_rtype; | ||
| 2315 | int ret = 0; | ||
| 2316 | |||
| 2317 | mvif = (struct mt792x_vif *)container_of(work, struct mt792x_vif, | ||
| 2318 | csa_work); | ||
| 2319 | dev = mvif->phy->dev; | ||
| 2320 | vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); | ||
| 2321 | |||
| 2322 | if (ieee80211_vif_is_mld(vif)) | ||
| 2323 | return; | ||
| 2324 | |||
| 2325 | if (!dev->new_ctx) | ||
| 2326 | return; | ||
| 2327 | |||
| 2328 | link_id = 0; | ||
| 2329 | mconf = &mvif->bss_conf; | ||
| 2330 | link_conf = &vif->bss_conf; | ||
| 2331 | roc_rtype = MT7925_ROC_REQ_JOIN; | ||
| 2332 | |||
| 2333 | mt792x_mutex_acquire(dev); | ||
| 2334 | ret = mt7925_set_roc(mvif->phy, mconf, dev->new_ctx->def.chan, | ||
| 2335 | 4000, roc_rtype); | ||
| 2336 | mt792x_mutex_release(dev); | ||
| 2337 | if (!ret) { | ||
| 2338 | mt792x_mutex_acquire(dev); | ||
| 2339 | ret = mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, link_conf, | ||
| 2340 | dev->new_ctx); | ||
| 2341 | mt792x_mutex_release(dev); | ||
| 2342 | |||
| 2343 | mt7925_abort_roc(mvif->phy, mconf); | ||
| 2344 | } | ||
| 2345 | |||
| 2346 | ieee80211_chswitch_done(vif, !ret, link_id); | ||
| 2347 | } | ||
| 2348 | |||
| 2349 | static int mt7925_pre_channel_switch(struct ieee80211_hw *hw, | ||
| 2350 | struct ieee80211_vif *vif, | ||
| 2351 | struct ieee80211_channel_switch *chsw) | ||
| 2352 | { | ||
| 2353 | if (ieee80211_vif_is_mld(vif)) | ||
| 2354 | return -EOPNOTSUPP; | ||
| 2355 | |||
| 2356 | if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) | ||
| 2357 | return -EOPNOTSUPP; | ||
| 2358 | |||
| 2359 | if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef, | ||
| 2360 | IEEE80211_CHAN_DISABLED)) | ||
| 2361 | return -EOPNOTSUPP; | ||
| 2362 | |||
| 2363 | return 0; | ||
| 2364 | } | ||
| 2365 | |||
| 2366 | static void mt7925_channel_switch(struct ieee80211_hw *hw, | ||
| 2367 | struct ieee80211_vif *vif, | ||
| 2368 | struct ieee80211_channel_switch *chsw) | ||
| 2369 | { | ||
| 2370 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | ||
| 2371 | u16 beacon_interval; | ||
| 2372 | |||
| 2373 | if (ieee80211_vif_is_mld(vif)) | ||
| 2374 | return; | ||
| 2375 | |||
| 2376 | beacon_interval = vif->bss_conf.beacon_int; | ||
| 2377 | |||
| 2378 | mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count); | ||
| 2379 | add_timer(&mvif->csa_timer); | ||
| 2380 | } | ||
| 2381 | |||
| 2382 | static void mt7925_abort_channel_switch(struct ieee80211_hw *hw, | ||
| 2383 | struct ieee80211_vif *vif, | ||
| 2384 | struct ieee80211_bss_conf *link_conf) | ||
| 2385 | { | ||
| 2386 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | ||
| 2387 | |||
| 2388 | timer_delete_sync(&mvif->csa_timer); | ||
| 2389 | cancel_work_sync(&mvif->csa_work); | ||
| 2390 | } | ||
| 2391 | |||
| 2392 | static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw, | ||
| 2393 | struct ieee80211_vif *vif, | ||
| 2394 | struct ieee80211_channel_switch *chsw) | ||
| 2395 | { | ||
| 2396 | struct mt792x_dev *dev = mt792x_hw_dev(hw); | ||
| 2397 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | ||
| 2398 | u16 beacon_interval; | ||
| 2399 | |||
| 2400 | if (ieee80211_vif_is_mld(vif)) | ||
| 2401 | return; | ||
| 2402 | |||
| 2403 | beacon_interval = vif->bss_conf.beacon_int; | ||
| 2404 | |||
| 2405 | if (cfg80211_chandef_identical(&chsw->chandef, | ||
| 2406 | &dev->new_ctx->def) && | ||
| 2407 | chsw->count) { | ||
| 2408 | mod_timer(&mvif->csa_timer, | ||
| 2409 | TU_TO_EXP_TIME(beacon_interval * chsw->count)); | ||
| 2410 | } | ||
| 2411 | } | ||
| 2412 | |||
| 2161 | const struct ieee80211_ops mt7925_ops = { | 2413 | const struct ieee80211_ops mt7925_ops = { |
| 2162 | .tx = mt792x_tx, | 2414 | .tx = mt792x_tx, |
| 2163 | .start = mt7925_start, | 2415 | .start = mt7925_start, |
| @@ -2221,6 +2473,12 @@ const struct ieee80211_ops mt7925_ops = { · 57 unmodified lines | |||
| 2221 | .change_vif_links = mt7925_change_vif_links, | 2473 | .change_vif_links = mt7925_change_vif_links, |
| 2222 | .change_sta_links = mt7925_change_sta_links, | 2474 | .change_sta_links = mt7925_change_sta_links, |
| 2223 | .rfkill_poll = mt7925_rfkill_poll, | 2475 | .rfkill_poll = mt7925_rfkill_poll, |
| 2476 | |||
| 2477 | .switch_vif_chanctx = mt7925_switch_vif_chanctx, | ||
| 2478 | .pre_channel_switch = mt7925_pre_channel_switch, | ||
| 2479 | .channel_switch = mt7925_channel_switch, | ||
| 2480 | .abort_channel_switch = mt7925_abort_channel_switch, | ||
| 2481 | .channel_switch_rx_beacon = mt7925_channel_switch_rx_beacon, | ||
| 2224 | }; | 2482 | }; |
| 2225 | EXPORT_SYMBOL_GPL(mt7925_ops); | 2483 | EXPORT_SYMBOL_GPL(mt7925_ops); |
| 2226 | 2484 | ||
| @@ -1066,9 +1066,8 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware); · 1065 unmodified lines | |||
| 1066 | static void | 1066 | static void |
| 1067 | mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, | 1067 | mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, |
| 1068 | struct ieee80211_vif *vif, | 1068 | struct ieee80211_vif *vif, |
| 1069 | struct ieee80211_link_sta *link_sta) | 1069 | struct mt792x_link_sta *mlink) |
| 1070 | { | 1070 | { |
| 1071 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | ||
| 1072 | struct sta_rec_hdr_trans *hdr_trans; | 1071 | struct sta_rec_hdr_trans *hdr_trans; |
| 1073 | struct mt76_wcid *wcid; | 1072 | struct mt76_wcid *wcid; |
| 1074 | struct tlv *tlv; | 1073 | struct tlv *tlv; |
| @@ -1082,19 +1081,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, · 7 unmodified lines | |||
| 1082 | else | 1081 | else |
| 1083 | hdr_trans->from_ds = true; | 1082 | hdr_trans->from_ds = true; |
| 1084 | 1083 | ||
| 1085 | if (link_sta) { | 1084 | if (WARN_ON_ONCE(!mlink)) |
| 1086 | struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | ||
| 1087 | struct mt792x_link_sta *mlink; | ||
| 1088 | |||
| 1089 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | ||
| 1090 | wcid = &mlink->wcid; | ||
| 1091 | } else { | ||
| 1092 | wcid = &mvif->sta.deflink.wcid; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | if (!wcid) | ||
| 1096 | return; | 1085 | return; |
| 1097 | 1086 | ||
| 1087 | wcid = &mlink->wcid; | ||
| 1088 | |||
| 1098 | hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); | 1089 | hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); |
| 1099 | if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { | 1090 | if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { |
| 1100 | hdr_trans->to_ds = true; | 1091 | hdr_trans->to_ds = true; |
| @@ -1104,30 +1095,18 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, · 3 unmodified lines | |||
| 1104 | 1095 | ||
| 1105 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, | 1096 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, |
| 1106 | struct ieee80211_vif *vif, | 1097 | struct ieee80211_vif *vif, |
| 1107 | struct ieee80211_sta *sta, | 1098 | struct mt792x_bss_conf *mconf, |
| 1108 | int link_id) | 1099 | struct mt792x_link_sta *mlink) |
| 1109 | { | 1100 | { |
| 1110 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | ||
| 1111 | struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; | ||
| 1112 | struct mt792x_link_sta *mlink; | ||
| 1113 | struct mt792x_bss_conf *mconf; | ||
| 1114 | struct mt792x_sta *msta; | ||
| 1115 | struct sk_buff *skb; | 1101 | struct sk_buff *skb; |
| 1116 | 1102 | ||
| 1117 | msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; | ||
| 1118 | |||
| 1119 | mlink = mt792x_sta_to_link(msta, link_id); | ||
| 1120 | link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); | ||
| 1121 | mconf = mt792x_vif_to_link(mvif, link_id); | ||
| 1122 | |||
| 1123 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, | 1103 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, |
| 1124 | &mlink->wcid, | 1104 | &mlink->wcid, |
| 1125 | MT7925_STA_UPDATE_MAX_SIZE); | 1105 | MT7925_STA_UPDATE_MAX_SIZE); |
| 1126 | if (IS_ERR(skb)) | 1106 | if (IS_ERR(skb)) |
| 1127 | return PTR_ERR(skb); | 1107 | return PTR_ERR(skb); |
| 1128 | 1108 | ||
| 1129 | /* starec hdr trans */ | 1109 | mt7925_mcu_sta_hdr_trans_tlv(skb, vif, mlink); |
| 1130 | mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta); | ||
| 1131 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | 1110 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| 1132 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); | 1111 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); |
| 1133 | } | 1112 | } |
| @@ -1288,14 +1267,16 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, · 154 unmodified lines | |||
| 1288 | return PTR_ERR(skb); | 1267 | return PTR_ERR(skb); |
| 1289 | 1268 | ||
| 1290 | ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); | 1269 | ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); |
| 1291 | if (ret) | 1270 | if (ret) { |
| 1271 | dev_kfree_skb(skb); | ||
| 1292 | return ret; | 1272 | return ret; |
| 1273 | } | ||
| 1293 | 1274 | ||
| 1294 | return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); | 1275 | return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); |
| 1295 | } | 1276 | } |
| 1296 | 1277 | ||
| 1297 | int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, | 1278 | int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, |
| 1298 | int duration, u8 token_id) | 1279 | u16 sel_links, int duration, u8 token_id) |
| 1299 | { | 1280 | { |
| 1300 | struct mt792x_vif *mvif = mconf->vif; | 1281 | struct mt792x_vif *mvif = mconf->vif; |
| 1301 | struct ieee80211_vif *vif = container_of((void *)mvif, | 1282 | struct ieee80211_vif *vif = container_of((void *)mvif, |
| @@ -1330,6 +1311,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, · 28 unmodified lines | |||
| 1330 | .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) | 1311 | .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) |
| 1331 | }; | 1312 | }; |
| 1332 | 1313 | ||
| 1314 | struct wiphy *wiphy = phy->mt76->hw->wiphy; | ||
| 1315 | |||
| 1333 | if (!mconf || hweight16(vif->valid_links) < 2 || | 1316 | if (!mconf || hweight16(vif->valid_links) < 2 || |
| 1334 | hweight16(sel_links) != 2) | 1317 | hweight16(sel_links) != 2) |
| 1335 | return -EPERM; | 1318 | return -EPERM; |
| @@ -1352,7 +1335,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, · 16 unmodified lines | |||
| 1352 | is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; | 1335 | is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; |
| 1353 | } | 1336 | } |
| 1354 | 1337 | ||
| 1355 | if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) | 1338 | if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops & |
| 1339 | IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS)) | ||
| 1356 | type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : | 1340 | type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : |
| 1357 | MT7925_ROC_REQ_MLSR_AA; | 1341 | MT7925_ROC_REQ_MLSR_AA; |
| 1358 | else | 1342 | else |
| @@ -1721,10 +1705,9 @@ mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) · 362 unmodified lines | |||
| 1721 | static void | 1705 | static void |
| 1722 | mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, | 1706 | mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, |
| 1723 | struct ieee80211_vif *vif, | 1707 | struct ieee80211_vif *vif, |
| 1724 | struct ieee80211_link_sta *link_sta) | 1708 | struct ieee80211_link_sta *link_sta, |
| 1709 | struct mt792x_link_sta *mlink) | ||
| 1725 | { | 1710 | { |
| 1726 | struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | ||
| 1727 | struct mt792x_link_sta *mlink; | ||
| 1728 | struct sta_rec_amsdu *amsdu; | 1711 | struct sta_rec_amsdu *amsdu; |
| 1729 | struct tlv *tlv; | 1712 | struct tlv *tlv; |
| 1730 | 1713 | ||
| @@ -1740,7 +1723,6 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, · 9 unmodified lines | |||
| 1740 | amsdu->max_amsdu_num = 8; | 1723 | amsdu->max_amsdu_num = 8; |
| 1741 | amsdu->amsdu_en = true; | 1724 | amsdu->amsdu_en = true; |
| 1742 | 1725 | ||
| 1743 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | ||
| 1744 | mlink->wcid.amsdu = true; | 1726 | mlink->wcid.amsdu = true; |
| 1745 | 1727 | ||
| 1746 | switch (link_sta->agg.max_amsdu_len) { | 1728 | switch (link_sta->agg.max_amsdu_len) { |
| @@ -1911,36 +1893,53 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, · 164 unmodified lines | |||
| 1911 | 1893 | ||
| 1912 | static void | 1894 | static void |
| 1913 | mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, | 1895 | mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, |
| 1914 | struct ieee80211_vif *vif, struct ieee80211_sta *sta) | 1896 | struct ieee80211_vif *vif, |
| 1897 | struct ieee80211_sta *sta, | ||
| 1898 | struct mt792x_bss_conf *mconf, | ||
| 1899 | struct mt792x_link_sta *mlink) | ||
| 1915 | { | 1900 | { |
| 1916 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 1901 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 1917 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; | 1902 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1918 | unsigned long valid = mvif->valid_links; | 1903 | struct mt792x_dev *dev = mvif->phy->dev; |
| 1919 | struct mt792x_bss_conf *mconf; | 1904 | struct mt792x_bss_conf *mconf_pri; |
| 1920 | struct mt792x_link_sta *mlink; | ||
| 1921 | struct sta_rec_mld *mld; | 1905 | struct sta_rec_mld *mld; |
| 1922 | struct tlv *tlv; | 1906 | struct tlv *tlv; |
| 1923 | int i, cnt = 0; | 1907 | u8 cnt = 0; |
| 1908 | |||
| 1909 | /* Primary link always uses driver's deflink WCID. */ | ||
| 1910 | mconf_pri = (msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) ? | ||
| 1911 | mt792x_vif_to_link(mvif, msta->deflink_id) : NULL; | ||
| 1912 | |||
| 1913 | /* If caller is operating on deflink, reuse its mconf as primary. */ | ||
| 1914 | if (!mconf_pri && mlink == &msta->deflink) | ||
| 1915 | mconf_pri = mconf; | ||
| 1916 | |||
| 1917 | if (!mconf_pri) { | ||
| 1918 | dev_warn_ratelimited(dev->mt76.dev, | ||
| 1919 | "mt7925: MLD_TLV_LINK skip (no primary mconf) sta=%pM\n", | ||
| 1920 | sta->addr); | ||
| 1921 | return; | ||
| 1922 | } | ||
| 1924 | 1923 | ||
| 1925 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); | 1924 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); |
| 1926 | mld = (struct sta_rec_mld *)tlv; | 1925 | mld = (struct sta_rec_mld *)tlv; |
| 1927 | memcpy(mld->mac_addr, sta->addr, ETH_ALEN); | 1926 | memcpy(mld->mac_addr, sta->addr, ETH_ALEN); |
| 1927 | |||
| 1928 | mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); | 1928 | mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); |
| 1929 | mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx); | 1929 | mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx); |
| 1930 | mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2); | ||
| 1931 | 1930 | ||
| 1932 | for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { | 1931 | /* Always encode primary link first. */ |
| 1933 | if (cnt == mld->link_num) | 1932 | mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx); |
| 1934 | break; | 1933 | mld->link[cnt++].bss_idx = mconf_pri->mt76.idx; |
| 1935 | 1934 | ||
| 1936 | mconf = mt792x_vif_to_link(mvif, i); | 1935 | /* Optionally encode the currently-updated secondary link. */ |
| 1937 | mlink = mt792x_sta_to_link(msta, i); | 1936 | if (mlink && mlink != &msta->deflink && mconf) { |
| 1937 | mld->secondary_id = cpu_to_le16(mlink->wcid.idx); | ||
| 1938 | mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); | 1938 | mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); |
| 1939 | mld->link[cnt++].bss_idx = mconf->mt76.idx; | 1939 | mld->link[cnt++].bss_idx = mconf->mt76.idx; |
| 1940 | |||
| 1941 | if (mlink != &msta->deflink) | ||
| 1942 | mld->secondary_id = cpu_to_le16(mlink->wcid.idx); | ||
| 1943 | } | 1940 | } |
| 1941 | |||
| 1942 | mld->link_num = cnt; | ||
| 1944 | } | 1943 | } |
| 1945 | 1944 | ||
| 1946 | static void | 1945 | static void |
| @@ -1961,10 +1960,12 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 14 unmodified lines | |||
| 1961 | struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; | 1960 | struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; |
| 1962 | struct mt76_dev *dev = phy->dev; | 1961 | struct mt76_dev *dev = phy->dev; |
| 1963 | struct mt792x_bss_conf *mconf; | 1962 | struct mt792x_bss_conf *mconf; |
| 1963 | struct mt792x_link_sta *mlink; | ||
| 1964 | struct sk_buff *skb; | 1964 | struct sk_buff *skb; |
| 1965 | int conn_state; | 1965 | int conn_state; |
| 1966 | 1966 | ||
| 1967 | mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); | 1967 | mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); |
| 1968 | mlink = container_of(info->wcid, struct mt792x_link_sta, wcid); | ||
| 1968 | 1969 | ||
| 1969 | skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, | 1970 | skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, |
| 1970 | MT7925_STA_UPDATE_MAX_SIZE); | 1971 | MT7925_STA_UPDATE_MAX_SIZE); |
| @@ -1982,7 +1983,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 11 unmodified lines | |||
| 1982 | mt7925_mcu_sta_ht_tlv(skb, info->link_sta); | 1983 | mt7925_mcu_sta_ht_tlv(skb, info->link_sta); |
| 1983 | mt7925_mcu_sta_vht_tlv(skb, info->link_sta); | 1984 | mt7925_mcu_sta_vht_tlv(skb, info->link_sta); |
| 1984 | mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); | 1985 | mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); |
| 1985 | mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); | 1986 | mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta, mlink); |
| 1986 | mt7925_mcu_sta_he_tlv(skb, info->link_sta); | 1987 | mt7925_mcu_sta_he_tlv(skb, info->link_sta); |
| 1987 | mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); | 1988 | mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); |
| 1988 | mt7925_mcu_sta_eht_tlv(skb, info->link_sta); | 1989 | mt7925_mcu_sta_eht_tlv(skb, info->link_sta); |
| @@ -1993,7 +1994,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 4 unmodified lines | |||
| 1993 | info->state); | 1994 | info->state); |
| 1994 | 1995 | ||
| 1995 | if (info->state != MT76_STA_INFO_STATE_NONE) { | 1996 | if (info->state != MT76_STA_INFO_STATE_NONE) { |
| 1996 | mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); | 1997 | mt7925_mcu_sta_mld_tlv(skb, info->vif, |
| 1998 | info->link_sta->sta, | ||
| 1999 | mconf, mlink); | ||
| 2000 | |||
| 1997 | mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); | 2001 | mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); |
| 1998 | } | 2002 | } |
| 1999 | } | 2003 | } |
| @@ -2003,7 +2007,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 3 unmodified lines | |||
| 2003 | mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, | 2007 | mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, |
| 2004 | sizeof(struct tlv)); | 2008 | sizeof(struct tlv)); |
| 2005 | } else { | 2009 | } else { |
| 2006 | mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); | 2010 | if (!info->link_sta) |
| 2011 | mlink = &mvif->sta.deflink; | ||
| 2012 | |||
| 2013 | mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, mlink); | ||
| 2007 | } | 2014 | } |
| 2008 | 2015 | ||
| 2009 | return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); | 2016 | return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); |
| @@ -2011,7 +2018,9 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 1 unmodified line | |||
| 2011 | 2018 | ||
| 2012 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, | 2019 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, |
| 2013 | struct ieee80211_link_sta *link_sta, | 2020 | struct ieee80211_link_sta *link_sta, |
| 2014 | struct ieee80211_vif *vif, bool enable, | 2021 | struct ieee80211_vif *vif, |
| 2022 | struct mt792x_link_sta *mlink, | ||
| 2023 | bool enable, | ||
| 2015 | enum mt76_sta_info_state state) | 2024 | enum mt76_sta_info_state state) |
| 2016 | { | 2025 | { |
| 2017 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; | 2026 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| @@ -2026,14 +2035,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, · 8 unmodified lines | |||
| 2026 | .offload_fw = true, | 2035 | .offload_fw = true, |
| 2027 | .rcpi = to_rcpi(rssi), | 2036 | .rcpi = to_rcpi(rssi), |
| 2028 | }; | 2037 | }; |
| 2029 | struct mt792x_sta *msta; | ||
| 2030 | struct mt792x_link_sta *mlink; | ||
| 2031 | 2038 | ||
| 2032 | if (link_sta) { | 2039 | info.wcid = &mlink->wcid; |
| 2033 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | ||
| 2034 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | ||
| 2035 | } | ||
| 2036 | info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; | ||
| 2037 | info.newly = state != MT76_STA_INFO_STATE_ASSOC; | 2040 | info.newly = state != MT76_STA_INFO_STATE_ASSOC; |
| 2038 | 2041 | ||
| 2039 | return mt7925_mcu_sta_cmd(&dev->mphy, &info); | 2042 | return mt7925_mcu_sta_cmd(&dev->mphy, &info); |
| @@ -2470,7 +2473,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, · 430 unmodified lines | |||
| 2470 | struct ieee80211_bss_conf *link_conf, | 2473 | struct ieee80211_bss_conf *link_conf, |
| 2471 | struct ieee80211_link_sta *link_sta, | 2474 | struct ieee80211_link_sta *link_sta, |
| 2472 | struct ieee80211_chanctx_conf *ctx, | 2475 | struct ieee80211_chanctx_conf *ctx, |
| 2473 | struct mt76_phy *phy, u16 wlan_idx, | 2476 | struct mt76_phy *phy, |
| 2477 | u16 bmc_tx_wlan_idx, | ||
| 2478 | u16 sta_wlan_idx, | ||
| 2474 | bool enable) | 2479 | bool enable) |
| 2475 | { | 2480 | { |
| 2476 | struct ieee80211_vif *vif = link_conf->vif; | 2481 | struct ieee80211_vif *vif = link_conf->vif; |
| @@ -2479,7 +2484,6 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, · 2 unmodified lines | |||
| 2479 | &link_conf->chanreq.oper; | 2484 | &link_conf->chanreq.oper; |
| 2480 | enum nl80211_band band = chandef->chan->band; | 2485 | enum nl80211_band band = chandef->chan->band; |
| 2481 | struct mt76_connac_bss_basic_tlv *basic_req; | 2486 | struct mt76_connac_bss_basic_tlv *basic_req; |
| 2482 | struct mt792x_link_sta *mlink; | ||
| 2483 | struct tlv *tlv; | 2487 | struct tlv *tlv; |
| 2484 | int conn_type; | 2488 | int conn_type; |
| 2485 | u8 idx; | 2489 | u8 idx; |
| @@ -2503,20 +2507,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, · 17 unmodified lines | |||
| 2503 | basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); | 2507 | basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); |
| 2504 | basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); | 2508 | basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); |
| 2505 | basic_req->dtim_period = link_conf->dtim_period; | 2509 | basic_req->dtim_period = link_conf->dtim_period; |
| 2506 | basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); | 2510 | basic_req->bmc_tx_wlan_idx = cpu_to_le16(bmc_tx_wlan_idx); |
| 2507 | basic_req->link_idx = mconf->mt76.idx; | 2511 | basic_req->link_idx = mconf->mt76.idx; |
| 2508 | 2512 | basic_req->sta_idx = cpu_to_le16(sta_wlan_idx); | |
| 2509 | if (link_sta) { | ||
| 2510 | struct mt792x_sta *msta; | ||
| 2511 | |||
| 2512 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; | ||
| 2513 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | ||
| 2514 | |||
| 2515 | } else { | ||
| 2516 | mlink = &mconf->vif->sta.deflink; | ||
| 2517 | } | ||
| 2518 | |||
| 2519 | basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx); | ||
| 2520 | basic_req->omac_idx = mconf->mt76.omac_idx; | 2513 | basic_req->omac_idx = mconf->mt76.omac_idx; |
| 2521 | basic_req->band_idx = mconf->mt76.band_idx; | 2514 | basic_req->band_idx = mconf->mt76.band_idx; |
| 2522 | basic_req->wmm_idx = mconf->mt76.wmm_idx; | 2515 | basic_req->wmm_idx = mconf->mt76.wmm_idx; |
| @@ -2823,16 +2816,16 @@ void mt7925_mcu_del_dev(struct mt76_dev *mdev, · 300 unmodified lines | |||
| 2823 | &dev_req, sizeof(dev_req), true); | 2816 | &dev_req, sizeof(dev_req), true); |
| 2824 | } | 2817 | } |
| 2825 | 2818 | ||
| 2826 | int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, | 2819 | int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy, |
| 2827 | struct ieee80211_chanctx_conf *ctx, | 2820 | struct ieee80211_chanctx_conf *ctx, |
| 2828 | struct ieee80211_bss_conf *link_conf, | 2821 | struct ieee80211_bss_conf *link_conf, |
| 2829 | struct ieee80211_link_sta *link_sta, | 2822 | struct ieee80211_link_sta *link_sta, |
| 2830 | int enable) | 2823 | u16 bmc_tx_wlan_idx, |
| 2824 | u16 sta_wlan_idx, | ||
| 2825 | int enable) | ||
| 2831 | { | 2826 | { |
| 2832 | struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; | ||
| 2833 | struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); | 2827 | struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); |
| 2834 | struct mt792x_dev *dev = phy->dev; | 2828 | struct mt792x_dev *dev = phy->dev; |
| 2835 | struct mt792x_link_sta *mlink_bc; | ||
| 2836 | struct sk_buff *skb; | 2829 | struct sk_buff *skb; |
| 2837 | 2830 | ||
| 2838 | skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, | 2831 | skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, |
| @@ -2840,11 +2833,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, · 1 unmodified line | |||
| 2840 | if (IS_ERR(skb)) | 2833 | if (IS_ERR(skb)) |
| 2841 | return PTR_ERR(skb); | 2834 | return PTR_ERR(skb); |
| 2842 | 2835 | ||
| 2843 | mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); | ||
| 2844 | |||
| 2845 | /* bss_basic must be first */ | 2836 | /* bss_basic must be first */ |
| 2846 | mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, | 2837 | mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, |
| 2847 | mlink_bc->wcid.idx, enable); | 2838 | bmc_tx_wlan_idx, sta_wlan_idx, enable); |
| 2848 | mt7925_mcu_bss_sec_tlv(skb, link_conf); | 2839 | mt7925_mcu_bss_sec_tlv(skb, link_conf); |
| 2849 | mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); | 2840 | mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); |
| 2850 | mt7925_mcu_bss_qos_tlv(skb, link_conf); | 2841 | mt7925_mcu_bss_qos_tlv(skb, link_conf); |
| @@ -2865,6 +2856,33 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, · 14 unmodified lines | |||
| 2865 | MCU_UNI_CMD(BSS_INFO_UPDATE), true); | 2856 | MCU_UNI_CMD(BSS_INFO_UPDATE), true); |
| 2866 | } | 2857 | } |
| 2867 | 2858 | ||
| 2859 | int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, | ||
| 2860 | struct ieee80211_chanctx_conf *ctx, | ||
| 2861 | struct ieee80211_bss_conf *link_conf, | ||
| 2862 | struct ieee80211_link_sta *link_sta, | ||
| 2863 | int enable) | ||
| 2864 | { | ||
| 2865 | struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; | ||
| 2866 | struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); | ||
| 2867 | struct mt792x_link_sta *mlink_bc; | ||
| 2868 | struct mt792x_link_sta *mlink; | ||
| 2869 | |||
| 2870 | mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); | ||
| 2871 | |||
| 2872 | if (link_sta) { | ||
| 2873 | struct mt792x_sta *msta = (void *)link_sta->sta->drv_priv; | ||
| 2874 | |||
| 2875 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); | ||
| 2876 | if (WARN_ON(!mlink)) | ||
| 2877 | return -EINVAL; | ||
| 2878 | } else { | ||
| 2879 | mlink = &mconf->vif->sta.deflink; | ||
| 2880 | } | ||
| 2881 | |||
| 2882 | return mt7925_mcu_add_bss_info_sta(phy, ctx, link_conf, link_sta, | ||
| 2883 | mlink_bc->wcid.idx, mlink->wcid.idx, enable); | ||
| 2884 | } | ||
| 2885 | |||
| 2868 | int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) | 2886 | int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) |
| 2869 | { | 2887 | { |
| 2870 | struct mt76_dev *mdev = phy->dev; | 2888 | struct mt76_dev *mdev = phy->dev; |
| @@ -3375,7 +3393,6 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, · 504 unmodified lines | |||
| 3375 | u8 rsvd[64]; | 3393 | u8 rsvd[64]; |
| 3376 | } __packed req = { | 3394 | } __packed req = { |
| 3377 | .tag = cpu_to_le16(0x3), | 3395 | .tag = cpu_to_le16(0x3), |
| 3378 | .len = cpu_to_le16(sizeof(req) - 4), | ||
| 3379 | 3396 | ||
| 3380 | .idx = idx, | 3397 | .idx = idx, |
| 3381 | .env = env_cap, | 3398 | .env = env_cap, |
| @@ -3404,6 +3421,7 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, · 22 unmodified lines | |||
| 3404 | memcpy(req.type, rule->type, 2); | 3421 | memcpy(req.type, rule->type, 2); |
| 3405 | 3422 | ||
| 3406 | req.size = cpu_to_le16(seg->len); | 3423 | req.size = cpu_to_le16(seg->len); |
| 3424 | req.len = cpu_to_le16(sizeof(req) + seg->len - 4); | ||
| 3407 | dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag; | 3425 | dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag; |
| 3408 | skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, | 3426 | skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, |
| 3409 | le16_to_cpu(req.size) + sizeof(req), | 3427 | le16_to_cpu(req.size) + sizeof(req), |
| @@ -3727,7 +3745,7 @@ mt7925_mcu_rate_txpower_band(struct mt76_phy *phy, · 317 unmodified lines | |||
| 3727 | memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2)); | 3745 | memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2)); |
| 3728 | tx_power_tlv->n_chan = num_ch; | 3746 | tx_power_tlv->n_chan = num_ch; |
| 3729 | tx_power_tlv->tag = cpu_to_le16(0x1); | 3747 | tx_power_tlv->tag = cpu_to_le16(0x1); |
| 3730 | tx_power_tlv->len = cpu_to_le16(sizeof(*tx_power_tlv)); | 3748 | tx_power_tlv->len = cpu_to_le16(msg_len); |
| 3731 | 3749 | ||
| 3732 | switch (band) { | 3750 | switch (band) { |
| 3733 | case NL80211_BAND_2GHZ: | 3751 | case NL80211_BAND_2GHZ: |
| @@ -693,6 +693,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, · 692 unmodified lines | |||
| 693 | struct ieee80211_bss_conf *link_conf, | 693 | struct ieee80211_bss_conf *link_conf, |
| 694 | struct ieee80211_link_sta *link_sta, | 694 | struct ieee80211_link_sta *link_sta, |
| 695 | int enable); | 695 | int enable); |
| 696 | int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy, | ||
| 697 | struct ieee80211_chanctx_conf *ctx, | ||
| 698 | struct ieee80211_bss_conf *link_conf, | ||
| 699 | struct ieee80211_link_sta *link_sta, | ||
| 700 | u16 bmc_tx_wlan_idx, | ||
| 701 | u16 sta_wlan_idx, | ||
| 702 | int enable); | ||
| 696 | int mt7925_mcu_set_timing(struct mt792x_phy *phy, | 703 | int mt7925_mcu_set_timing(struct mt792x_phy *phy, |
| 697 | struct ieee80211_bss_conf *link_conf); | 704 | struct ieee80211_bss_conf *link_conf); |
| 698 | int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); | 705 | int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); |
| @@ -250,7 +250,9 @@ int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, · 249 unmodified lines | |||
| 250 | bool enable); | 250 | bool enable); |
| 251 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, | 251 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, |
| 252 | struct ieee80211_link_sta *link_sta, | 252 | struct ieee80211_link_sta *link_sta, |
| 253 | struct ieee80211_vif *vif, bool enable, | 253 | struct ieee80211_vif *vif, |
| 254 | struct mt792x_link_sta *mlink, | ||
| 255 | bool enable, | ||
| 254 | enum mt76_sta_info_state state); | 256 | enum mt76_sta_info_state state); |
| 255 | int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); | 257 | int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); |
| 256 | int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf); | 258 | int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf); |
| @@ -298,6 +300,7 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, · 41 unmodified lines | |||
| 298 | void mt7925_mlo_pm_work(struct work_struct *work); | 300 | void mt7925_mlo_pm_work(struct work_struct *work); |
| 299 | void mt7925_scan_work(struct work_struct *work); | 301 | void mt7925_scan_work(struct work_struct *work); |
| 300 | void mt7925_roc_work(struct work_struct *work); | 302 | void mt7925_roc_work(struct work_struct *work); |
| 303 | void mt7925_csa_work(struct work_struct *work); | ||
| 301 | int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, | 304 | int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, |
| 302 | struct ieee80211_bss_conf *link_conf); | 305 | struct ieee80211_bss_conf *link_conf); |
| 303 | void mt7925_coredump_work(struct work_struct *work); | 306 | void mt7925_coredump_work(struct work_struct *work); |
| @@ -349,8 +352,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, · 45 unmodified lines | |||
| 349 | int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); | 352 | int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); |
| 350 | int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, | 353 | int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, |
| 351 | enum environment_cap env_cap); | 354 | enum environment_cap env_cap); |
| 352 | int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, | 355 | int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, |
| 353 | int duration, u8 token_id); | 356 | u16 sel_links, int duration, u8 token_id); |
| 354 | int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, | 357 | int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, |
| 355 | struct ieee80211_channel *chan, int duration, | 358 | struct ieee80211_channel *chan, int duration, |
| 356 | enum mt7925_roc_req type, u8 token_id); | 359 | enum mt7925_roc_req type, u8 token_id); |
| @@ -367,8 +370,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, · 10 unmodified lines | |||
| 367 | int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); | 370 | int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); |
| 368 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, | 371 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, |
| 369 | struct ieee80211_vif *vif, | 372 | struct ieee80211_vif *vif, |
| 370 | struct ieee80211_sta *sta, | 373 | struct mt792x_bss_conf *mconf, |
| 371 | int link_id); | 374 | struct mt792x_link_sta *mlink); |
| 372 | int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy); | 375 | int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy); |
| 373 | 376 | ||
| 374 | int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 377 | int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| @@ -232,7 +232,8 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) · 231 unmodified lines | |||
| 232 | dev->regd_user) | 232 | dev->regd_user) |
| 233 | return -EINVAL; | 233 | return -EINVAL; |
| 234 | 234 | ||
| 235 | if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') | 235 | if ((mdev->alpha2[0] && mdev->alpha2[0] != '0') && |
| 236 | (mdev->alpha2[1] && mdev->alpha2[1] != '0')) | ||
| 236 | return 0; | 237 | return 0; |
| 237 | 238 | ||
| 238 | /* do not need to update the same country twice */ | 239 | /* do not need to update the same country twice */ |
| @@ -41,11 +41,13 @@ · 40 unmodified lines | |||
| 41 | #define MT792x_MCU_INIT_RETRY_COUNT 10 | 41 | #define MT792x_MCU_INIT_RETRY_COUNT 10 |
| 42 | #define MT792x_WFSYS_INIT_RETRY_COUNT 2 | 42 | #define MT792x_WFSYS_INIT_RETRY_COUNT 2 |
| 43 | 43 | ||
| 44 | #define MT7902_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7902_1.bin" | ||
| 44 | #define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin" | 45 | #define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin" |
| 45 | #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" | 46 | #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" |
| 46 | #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" | 47 | #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" |
| 47 | #define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin" | 48 | #define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin" |
| 48 | 49 | ||
| 50 | #define MT7902_ROM_PATCH "mediatek/WIFI_MT7902_patch_mcu_1_1_hdr.bin" | ||
| 49 | #define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" | 51 | #define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" |
| 50 | #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" | 52 | #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" |
| 51 | #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" | 53 | #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" |
| @@ -95,6 +97,7 @@ DECLARE_EWMA(avg_signal, 10, 8) · 43 unmodified lines | |||
| 95 | 97 | ||
| 96 | struct mt792x_link_sta { | 98 | struct mt792x_link_sta { |
| 97 | struct mt76_wcid wcid; /* must be first */ | 99 | struct mt76_wcid wcid; /* must be first */ |
| 100 | struct rcu_head rcu_head; | ||
| 98 | 101 | ||
| 99 | u32 airtime_ac[8]; | 102 | u32 airtime_ac[8]; |
| 100 | 103 | ||
| @@ -448,6 +451,8 @@ void mt792x_config_mac_addr_list(struct mt792x_dev *dev); · 347 unmodified lines | |||
| 448 | static inline char *mt792x_ram_name(struct mt792x_dev *dev) | 451 | static inline char *mt792x_ram_name(struct mt792x_dev *dev) |
| 449 | { | 452 | { |
| 450 | switch (mt76_chip(&dev->mt76)) { | 453 | switch (mt76_chip(&dev->mt76)) { |
| 454 | case 0x7902: | ||
| 455 | return MT7902_FIRMWARE_WM; | ||
| 451 | case 0x7920: | 456 | case 0x7920: |
| 452 | return MT7920_FIRMWARE_WM; | 457 | return MT7920_FIRMWARE_WM; |
| 453 | case 0x7922: | 458 | case 0x7922: |
| @@ -462,6 +467,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev) · 8 unmodified lines | |||
| 462 | static inline char *mt792x_patch_name(struct mt792x_dev *dev) | 467 | static inline char *mt792x_patch_name(struct mt792x_dev *dev) |
| 463 | { | 468 | { |
| 464 | switch (mt76_chip(&dev->mt76)) { | 469 | switch (mt76_chip(&dev->mt76)) { |
| 470 | case 0x7902: | ||
| 471 | return MT7902_ROM_PATCH; | ||
| 465 | case 0x7920: | 472 | case 0x7920: |
| 466 | return MT7920_ROM_PATCH; | 473 | return MT7920_ROM_PATCH; |
| 467 | case 0x7922: | 474 | case 0x7922: |
| @@ -151,7 +151,7 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend) · 150 unmodified lines | |||
| 151 | cancel_work_sync(&dev->reset_work); | 151 | cancel_work_sync(&dev->reset_work); |
| 152 | mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); | 152 | mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); |
| 153 | 153 | ||
| 154 | if (is_mt7921(&dev->mt76)) { | 154 | if (is_connac2(&dev->mt76)) { |
| 155 | mt792x_mutex_acquire(dev); | 155 | mt792x_mutex_acquire(dev); |
| 156 | mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); | 156 | mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); |
| 157 | mt792x_mutex_release(dev); | 157 | mt792x_mutex_release(dev); |
| @@ -691,9 +691,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) · 533 unmodified lines | |||
| 691 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); | 691 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); |
| 692 | ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); | 692 | ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); |
| 693 | 693 | ||
| 694 | if (is_mt7921(&dev->mt76)) { | 694 | ieee80211_hw_set(hw, CHANCTX_STA_CSA); |
| 695 | ieee80211_hw_set(hw, CHANCTX_STA_CSA); | 695 | |
| 696 | } | ||
| 697 | 696 | ||
| 698 | if (dev->pm.enable) | 697 | if (dev->pm.enable) |
| 699 | ieee80211_hw_set(hw, CONNECTION_MONITOR); | 698 | ieee80211_hw_set(hw, CONNECTION_MONITOR); |
| @@ -927,6 +926,13 @@ int mt792x_load_firmware(struct mt792x_dev *dev) · 227 unmodified lines | |||
| 927 | { | 926 | { |
| 928 | int ret; | 927 | int ret; |
| 929 | 928 | ||
| 929 | mt76_connac_mcu_restart(&dev->mt76); | ||
| 930 | |||
| 931 | if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC_FW_STATE, | ||
| 932 | MT_TOP_MISC2_FW_PWR_ON, 1000)) | ||
| 933 | dev_warn(dev->mt76.dev, | ||
| 934 | "MCU is not ready for firmware download\n"); | ||
| 935 | |||
| 930 | ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); | 936 | ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); |
| 931 | if (ret) | 937 | if (ret) |
| 932 | return ret; | 938 | return ret; |
| @@ -103,6 +103,22 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) · 102 unmodified lines | |||
| 103 | mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10)); | 103 | mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10)); |
| 104 | mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4)); | 104 | mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4)); |
| 105 | mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4)); | 105 | mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4)); |
| 106 | } else if (is_mt7902(&dev->mt76)) { | ||
| 107 | /* rx ring */ | ||
| 108 | mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4)); | ||
| 109 | mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4)); | ||
| 110 | mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4)); | ||
| 111 | mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4)); | ||
| 112 | /* tx ring */ | ||
| 113 | mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x4)); | ||
| 114 | mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0140, 0x4)); | ||
| 115 | mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0180, 0x4)); | ||
| 116 | mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x01c0, 0x4)); | ||
| 117 | mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x0200, 0x4)); | ||
| 118 | mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x0240, 0x4)); | ||
| 119 | mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x0280, 0x4)); | ||
| 120 | mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x02c0, 0x4)); | ||
| 121 | mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0300, 0x4)); | ||
| 106 | } else { | 122 | } else { |
| 107 | /* rx ring */ | 123 | /* rx ring */ |
| 108 | mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); | 124 | mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); |
| @@ -356,7 +372,7 @@ EXPORT_SYMBOL_GPL(mt792x_poll_rx); · 247 unmodified lines | |||
| 356 | 372 | ||
| 357 | int mt792x_wfsys_reset(struct mt792x_dev *dev) | 373 | int mt792x_wfsys_reset(struct mt792x_dev *dev) |
| 358 | { | 374 | { |
| 359 | u32 addr = is_mt7921(&dev->mt76) ? 0x18000140 : 0x7c000140; | 375 | u32 addr = is_connac2(&dev->mt76) ? 0x18000140 : 0x7c000140; |
| 360 | 376 | ||
| 361 | mt76_clear(dev, addr, WFSYS_SW_RST_B); | 377 | mt76_clear(dev, addr, WFSYS_SW_RST_B); |
| 362 | msleep(50); | 378 | msleep(50); |
| @@ -375,7 +375,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) · 374 unmodified lines | |||
| 375 | } | 375 | } |
| 376 | 376 | ||
| 377 | if (!mt792x_mcu_fw_pmctrl(dev)) { | 377 | if (!mt792x_mcu_fw_pmctrl(dev)) { |
| 378 | cancel_delayed_work_sync(&mphy->mac_work); | 378 | cancel_delayed_work(&mphy->mac_work); |
| 379 | return; | 379 | return; |
| 380 | } | 380 | } |
| 381 | out: | 381 | out: |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | |||
| 25 | #define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) | 25 | #define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) |
| 26 | #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) | 26 | #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) |
| 27 | 27 | ||
| 28 | #define MT_PSE_BASE 0x820c8000 | ||
| 29 | |||
| 28 | /* TMAC: band 0(0x21000), band 1(0xa1000) */ | 30 | /* TMAC: band 0(0x21000), band 1(0xa1000) */ |
| 29 | #define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) | 31 | #define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) |
| 30 | #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) | 32 | #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) |
| @@ -390,6 +392,10 @@ · 359 unmodified lines | |||
| 390 | #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600) | 392 | #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600) |
| 391 | #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0) | 393 | #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0) |
| 392 | 394 | ||
| 395 | #define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600 | ||
| 396 | #define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604 | ||
| 397 | #define MT7925_WFSYS_INIT_DONE 0x00001d1e | ||
| 398 | |||
| 393 | #define MT_HW_BOUND 0x70010020 | 399 | #define MT_HW_BOUND 0x70010020 |
| 394 | #define MT_HW_CHIPID 0x70010200 | 400 | #define MT_HW_CHIPID 0x70010200 |
| 395 | #define MT_HW_REV 0x70010204 | 401 | #define MT_HW_REV 0x70010204 |
| @@ -206,6 +206,33 @@ static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset) · 205 unmodified lines | |||
| 206 | mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val); | 206 | mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | struct mt792xu_wfsys_desc { | ||
| 210 | u32 rst_reg; | ||
| 211 | u32 done_reg; | ||
| 212 | u32 done_mask; | ||
| 213 | u32 done_val; | ||
| 214 | u32 delay_ms; | ||
| 215 | bool need_status_sel; | ||
| 216 | }; | ||
| 217 | |||
| 218 | static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = { | ||
| 219 | .rst_reg = MT_CBTOP_RGU_WF_SUBSYS_RST, | ||
| 220 | .done_reg = MT_UDMA_CONN_INFRA_STATUS, | ||
| 221 | .done_mask = MT_UDMA_CONN_WFSYS_INIT_DONE, | ||
| 222 | .done_val = MT_UDMA_CONN_WFSYS_INIT_DONE, | ||
| 223 | .delay_ms = 0, | ||
| 224 | .need_status_sel = true, | ||
| 225 | }; | ||
| 226 | |||
| 227 | static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = { | ||
| 228 | .rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST, | ||
| 229 | .done_reg = MT7925_WFSYS_INIT_DONE_ADDR, | ||
| 230 | .done_mask = U32_MAX, | ||
| 231 | .done_val = MT7925_WFSYS_INIT_DONE, | ||
| 232 | .delay_ms = 20, | ||
| 233 | .need_status_sel = false, | ||
| 234 | }; | ||
| 235 | |||
| 209 | int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) | 236 | int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) |
| 210 | { | 237 | { |
| 211 | int err; | 238 | int err; |
| @@ -236,25 +263,33 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init); · 24 unmodified lines | |||
| 236 | 263 | ||
| 237 | int mt792xu_wfsys_reset(struct mt792x_dev *dev) | 264 | int mt792xu_wfsys_reset(struct mt792x_dev *dev) |
| 238 | { | 265 | { |
| 266 | const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ? | ||
| 267 | &mt7925_wfsys_desc : | ||
| 268 | &mt7921_wfsys_desc; | ||
| 239 | u32 val; | 269 | u32 val; |
| 240 | int i; | 270 | int i; |
| 241 | 271 | ||
| 242 | mt792xu_epctl_rst_opt(dev, false); | 272 | mt792xu_epctl_rst_opt(dev, false); |
| 243 | 273 | ||
| 244 | val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); | 274 | val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg); |
| 245 | val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; | 275 | val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; |
| 246 | mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); | 276 | mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val); |
| 247 | 277 | ||
| 248 | usleep_range(10, 20); | 278 | if (desc->delay_ms) |
| 279 | msleep(desc->delay_ms); | ||
| 280 | else | ||
| 281 | usleep_range(10, 20); | ||
| 249 | 282 | ||
| 250 | val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); | 283 | val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg); |
| 251 | val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; | 284 | val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; |
| 252 | mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); | 285 | mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val); |
| 286 | |||
| 287 | if (desc->need_status_sel) | ||
| 288 | mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0); | ||
| 253 | 289 | ||
| 254 | mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0); | ||
| 255 | for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) { | 290 | for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) { |
| 256 | val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS); | 291 | val = mt792xu_uhw_rr(&dev->mt76, desc->done_reg); |
| 257 | if (val & MT_UDMA_CONN_WFSYS_INIT_DONE) | 292 | if ((val & desc->done_mask) == desc->done_val) |
| 258 | break; | 293 | break; |
| 259 | 294 | ||
| 260 | msleep(100); | 295 | msleep(100); |
| @@ -226,14 +226,23 @@ mt7996_radar_trigger(void *data, u64 val) · 225 unmodified lines | |||
| 226 | #define RADAR_BACKGROUND 2 | 226 | #define RADAR_BACKGROUND 2 |
| 227 | struct mt7996_dev *dev = data; | 227 | struct mt7996_dev *dev = data; |
| 228 | struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ); | 228 | struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ); |
| 229 | int rdd_idx; | 229 | struct cfg80211_chan_def *chandef; |
| 230 | int rdd_idx, ret; | ||
| 230 | 231 | ||
| 231 | if (!phy || !val || val > RADAR_BACKGROUND) | 232 | if (!phy || !val || val > RADAR_BACKGROUND) |
| 232 | return -EINVAL; | 233 | return -EINVAL; |
| 233 | 234 | ||
| 234 | if (val == RADAR_BACKGROUND && !dev->rdd2_phy) { | 235 | if (test_bit(MT76_SCANNING, &phy->mt76->state)) |
| 235 | dev_err(dev->mt76.dev, "Background radar is not enabled\n"); | 236 | return -EBUSY; |
| 236 | return -EINVAL; | 237 | |
| 238 | if (val == RADAR_BACKGROUND) { | ||
| 239 | if (!dev->rdd2_phy || !cfg80211_chandef_valid(&dev->rdd2_chandef)) { | ||
| 240 | dev_err(dev->mt76.dev, "Background radar is not enabled\n"); | ||
| 241 | return -EINVAL; | ||
| 242 | } | ||
| 243 | chandef = &dev->rdd2_chandef; | ||
| 244 | } else { | ||
| 245 | chandef = &phy->mt76->chandef; | ||
| 237 | } | 246 | } |
| 238 | 247 | ||
| 239 | rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND); | 248 | rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND); |
| @@ -242,6 +251,11 @@ mt7996_radar_trigger(void *data, u64 val) · 2 unmodified lines | |||
| 242 | return -EINVAL; | 251 | return -EINVAL; |
| 243 | } | 252 | } |
| 244 | 253 | ||
| 254 | ret = cfg80211_chandef_dfs_required(dev->mt76.hw->wiphy, chandef, | ||
| 255 | NL80211_IFTYPE_AP); | ||
| 256 | if (ret <= 0) | ||
| 257 | return ret; | ||
| 258 | |||
| 245 | return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0); | 259 | return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0); |
| 246 | } | 260 | } |
| 247 | 261 | ||
| @@ -626,13 +640,18 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) · 378 unmodified lines | |||
| 626 | { | 640 | { |
| 627 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | 641 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 628 | struct mt7996_vif *mvif = msta->vif; | 642 | struct mt7996_vif *mvif = msta->vif; |
| 629 | struct mt7996_dev *dev = mvif->deflink.phy->dev; | 643 | struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); |
| 630 | struct ieee80211_link_sta *link_sta; | 644 | struct ieee80211_link_sta *link_sta; |
| 631 | struct seq_file *s = data; | 645 | struct seq_file *s = data; |
| 632 | struct ieee80211_vif *vif; | 646 | struct ieee80211_vif *vif; |
| 647 | struct mt7996_dev *dev; | ||
| 633 | unsigned int link_id; | 648 | unsigned int link_id; |
| 634 | 649 | ||
| 650 | if (!phy) | ||
| 651 | return; | ||
| 652 | |||
| 635 | vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); | 653 | vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); |
| 654 | dev = phy->dev; | ||
| 636 | 655 | ||
| 637 | rcu_read_lock(); | 656 | rcu_read_lock(); |
| 638 | 657 | ||
| @@ -979,13 +998,17 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file, · 340 unmodified lines | |||
| 979 | #define LONG_PREAMBLE 1 | 998 | #define LONG_PREAMBLE 1 |
| 980 | struct ieee80211_link_sta *link_sta = file->private_data; | 999 | struct ieee80211_link_sta *link_sta = file->private_data; |
| 981 | struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv; | 1000 | struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv; |
| 982 | struct mt7996_dev *dev = msta->vif->deflink.phy->dev; | 1001 | struct mt7996_phy *link_phy = mt7996_vif_link_phy(&msta->vif->deflink); |
| 983 | struct mt7996_sta_link *msta_link; | 1002 | struct mt7996_sta_link *msta_link; |
| 984 | struct ra_rate phy = {}; | 1003 | struct ra_rate phy = {}; |
| 1004 | struct mt7996_dev *dev; | ||
| 985 | char buf[100]; | 1005 | char buf[100]; |
| 986 | int ret; | 1006 | int ret; |
| 987 | u16 gi, ltf; | 1007 | u16 gi, ltf; |
| 988 | 1008 | ||
| 1009 | if (!link_phy) | ||
| 1010 | return -EINVAL; | ||
| 1011 | |||
| 989 | if (count >= sizeof(buf)) | 1012 | if (count >= sizeof(buf)) |
| 990 | return -EINVAL; | 1013 | return -EINVAL; |
| 991 | 1014 | ||
| @@ -1008,6 +1031,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file, · 16 unmodified lines | |||
| 1008 | * spe - off: 0, on: 1 | 1031 | * spe - off: 0, on: 1 |
| 1009 | * ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 | 1032 | * ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 |
| 1010 | */ | 1033 | */ |
| 1034 | dev = link_phy->dev; | ||
| 1011 | if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu", | 1035 | if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu", |
| 1012 | &phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi, | 1036 | &phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi, |
| 1013 | &phy.preamble, &phy.stbc, &phy.ldpc, &phy.spe, <f) != 10) { | 1037 | &phy.preamble, &phy.stbc, &phy.ldpc, &phy.spe, <f) != 10) { |
| @@ -128,15 +128,27 @@ static void mt7996_dma_config(struct mt7996_dev *dev) · 127 unmodified lines | |||
| 128 | 128 | ||
| 129 | /* data tx queue */ | 129 | /* data tx queue */ |
| 130 | if (is_mt7996(&dev->mt76)) { | 130 | if (is_mt7996(&dev->mt76)) { |
| 131 | TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); | ||
| 132 | if (dev->hif2) { | 131 | if (dev->hif2) { |
| 133 | /* default bn1:ring19 bn2:ring21 */ | 132 | if (mt76_npu_device_active(&dev->mt76)) { |
| 134 | TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, | 133 | TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND2, |
| 135 | MT7996_TXQ_BAND1); | 134 | MT7996_TXQ_BAND2); |
| 136 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, | 135 | TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND0, |
| 137 | MT7996_TXQ_BAND2); | 136 | MT7996_TXQ_BAND0); |
| 137 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, | ||
| 138 | MT7996_TXQ_BAND1); | ||
| 139 | } else { | ||
| 140 | /* default bn1:ring19 bn2:ring21 */ | ||
| 141 | TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, | ||
| 142 | MT7996_TXQ_BAND0); | ||
| 143 | TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, | ||
| 144 | MT7996_TXQ_BAND1); | ||
| 145 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, | ||
| 146 | MT7996_TXQ_BAND2); | ||
| 147 | } | ||
| 138 | } else { | 148 | } else { |
| 139 | /* single pcie bn0/1:ring18 bn2:ring19 */ | 149 | /* single pcie bn0/1:ring18 bn2:ring19 */ |
| 150 | TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, | ||
| 151 | MT7996_TXQ_BAND0); | ||
| 140 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, | 152 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, |
| 141 | MT7996_TXQ_BAND1); | 153 | MT7996_TXQ_BAND1); |
| 142 | } | 154 | } |
| @@ -350,6 +362,9 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) · 207 unmodified lines | |||
| 350 | if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76)) | 362 | if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76)) |
| 351 | irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) | | 363 | irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) | |
| 352 | MT_INT_RX(MT_RXQ_BAND1_WA)); | 364 | MT_INT_RX(MT_RXQ_BAND1_WA)); |
| 365 | if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) | ||
| 366 | irq_mask &= ~(MT_INT_RX(MT_RXQ_TXFREE_BAND0) | | ||
| 367 | MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)); | ||
| 353 | irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; | 368 | irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; |
| 354 | 369 | ||
| 355 | mt7996_irq_enable(dev, irq_mask); | 370 | mt7996_irq_enable(dev, irq_mask); |
| @@ -430,39 +445,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) · 74 unmodified lines | |||
| 430 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 | | 445 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 | |
| 431 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); | 446 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); |
| 432 | 447 | ||
| 433 | if (is_mt7996(&dev->mt76)) | 448 | if (is_mt7996(&dev->mt76)) { |
| 434 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, | 449 | if (mt76_npu_device_active(&dev->mt76)) |
| 435 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); | 450 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, |
| 436 | else | 451 | MT_WFDMA_HOST_CONFIG_BAND0_PCIE1); |
| 452 | else | ||
| 453 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, | ||
| 454 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); | ||
| 455 | } else { | ||
| 437 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, | 456 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, |
| 438 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1); | 457 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1); |
| 458 | } | ||
| 439 | 459 | ||
| 440 | /* AXI read outstanding number */ | 460 | /* AXI read outstanding number */ |
| 441 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, | 461 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, |
| 442 | MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); | 462 | MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); |
| 443 | 463 | ||
| 444 | if (dev->hif2->speed < PCIE_SPEED_5_0GT || | 464 | if (!is_mt7996(&dev->mt76) || |
| 445 | (dev->hif2->speed == PCIE_SPEED_5_0GT && | 465 | !mt76_npu_device_active(&dev->mt76)) { |
| 446 | dev->hif2->width < PCIE_LNK_X2)) { | 466 | if (dev->hif2->speed < PCIE_SPEED_5_0GT || |
| 447 | mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | 467 | (dev->hif2->speed == PCIE_SPEED_5_0GT && |
| 448 | WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | 468 | dev->hif2->width < PCIE_LNK_X2)) { |
| 449 | FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | 469 | mt76_rmw(dev, |
| 450 | 0x1)); | 470 | WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, |
| 451 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, | 471 | WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, |
| 452 | MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | 472 | FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, |
| 453 | FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | 473 | 0x1)); |
| 454 | 0x1)); | 474 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, |
| 455 | } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || | 475 | MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, |
| 456 | (dev->hif2->speed == PCIE_SPEED_8_0GT && | 476 | FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, |
| 457 | dev->hif2->width < PCIE_LNK_X2)) { | 477 | 0x1)); |
| 458 | mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | 478 | } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || |
| 459 | WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | 479 | (dev->hif2->speed == PCIE_SPEED_8_0GT && |
| 460 | FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | 480 | dev->hif2->width < PCIE_LNK_X2)) { |
| 461 | 0x2)); | 481 | mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, |
| 462 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, | 482 | WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, |
| 463 | MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | 483 | FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, |
| 464 | FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | 484 | 0x2)); |
| 465 | 0x2)); | 485 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, |
| 486 | MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | ||
| 487 | FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | ||
| 488 | 0x2)); | ||
| 489 | } | ||
| 466 | } | 490 | } |
| 467 | 491 | ||
| 468 | /* WFDMA rx threshold */ | 492 | /* WFDMA rx threshold */ |
| @@ -497,7 +521,7 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) · 28 unmodified lines | |||
| 497 | int mt7996_dma_rro_init(struct mt7996_dev *dev) | 521 | int mt7996_dma_rro_init(struct mt7996_dev *dev) |
| 498 | { | 522 | { |
| 499 | struct mt76_dev *mdev = &dev->mt76; | 523 | struct mt76_dev *mdev = &dev->mt76; |
| 500 | u32 irq_mask; | 524 | u32 size; |
| 501 | int ret; | 525 | int ret; |
| 502 | 526 | ||
| 503 | if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { | 527 | if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { |
| @@ -524,7 +548,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 20 unmodified lines | |||
| 524 | mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], | 548 | mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], |
| 525 | true); | 549 | true); |
| 526 | } | 550 | } |
| 527 | goto start_hw_rro; | 551 | |
| 552 | return 0; | ||
| 528 | } | 553 | } |
| 529 | 554 | ||
| 530 | /* ind cmd */ | 555 | /* ind cmd */ |
| @@ -545,10 +570,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 14 unmodified lines | |||
| 545 | if (mtk_wed_device_active(&mdev->mmio.wed) && | 570 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 546 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) | 571 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 547 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; | 572 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; |
| 573 | |||
| 574 | size = is_mt7996(mdev) && mt76_npu_device_active(mdev) | ||
| 575 | ? MT7996_NPU_RX_RING_SIZE / 4 : MT7996_RX_RING_SIZE; | ||
| 548 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], | 576 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], |
| 549 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), | 577 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), |
| 550 | MT7996_RX_RING_SIZE, | 578 | size, MT7996_RX_MSDU_PAGE_SIZE, |
| 551 | MT7996_RX_MSDU_PAGE_SIZE, | ||
| 552 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); | 579 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); |
| 553 | if (ret) | 580 | if (ret) |
| 554 | return ret; | 581 | return ret; |
| @@ -560,10 +587,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 5 unmodified lines | |||
| 560 | if (mtk_wed_device_active(&mdev->mmio.wed) && | 587 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 561 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) | 588 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 562 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; | 589 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; |
| 590 | |||
| 591 | size = is_mt7996(mdev) && mt76_npu_device_active(mdev) | ||
| 592 | ? MT7996_NPU_RX_RING_SIZE / 2 : MT7996_RX_RING_SIZE; | ||
| 563 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], | 593 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], |
| 564 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), | 594 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), |
| 565 | MT7996_RX_RING_SIZE, | 595 | size, MT7996_RX_MSDU_PAGE_SIZE, |
| 566 | MT7996_RX_MSDU_PAGE_SIZE, | ||
| 567 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); | 596 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); |
| 568 | if (ret) | 597 | if (ret) |
| 569 | return ret; | 598 | return ret; |
| @@ -576,52 +605,60 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 6 unmodified lines | |||
| 576 | if (mtk_wed_device_active(&mdev->mmio.wed) && | 605 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 577 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) | 606 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 578 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; | 607 | mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; |
| 608 | |||
| 609 | size = is_mt7996(mdev) && mt76_npu_device_active(mdev) | ||
| 610 | ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE; | ||
| 579 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], | 611 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], |
| 580 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), | 612 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), |
| 581 | MT7996_RX_RING_SIZE, | 613 | size, MT7996_RX_MSDU_PAGE_SIZE, |
| 582 | MT7996_RX_MSDU_PAGE_SIZE, | ||
| 583 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); | 614 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); |
| 584 | if (ret) | 615 | if (ret) |
| 585 | return ret; | 616 | return ret; |
| 586 | } | 617 | } |
| 587 | 618 | ||
| 588 | start_hw_rro: | 619 | return 0; |
| 589 | if (mtk_wed_device_active(&mdev->mmio.wed)) { | 620 | } |
| 590 | irq_mask = mdev->mmio.irqmask | | 621 | |
| 622 | void mt7996_dma_rro_start(struct mt7996_dev *dev) | ||
| 623 | { | ||
| 624 | u32 irq_mask; | ||
| 625 | |||
| 626 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { | ||
| 627 | irq_mask = dev->mt76.mmio.irqmask | | ||
| 591 | MT_INT_TX_DONE_BAND2; | 628 | MT_INT_TX_DONE_BAND2; |
| 592 | 629 | ||
| 593 | mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); | 630 | mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); |
| 594 | mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); | 631 | mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, irq_mask, |
| 632 | false); | ||
| 595 | mt7996_irq_enable(dev, irq_mask); | 633 | mt7996_irq_enable(dev, irq_mask); |
| 596 | } else { | 634 | return; |
| 597 | if (is_mt7996(&dev->mt76)) { | 635 | } |
| 598 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, | ||
| 599 | mt76_dma_rx_poll); | ||
| 600 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, | ||
| 601 | mt76_dma_rx_poll); | ||
| 602 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, | ||
| 603 | mt76_dma_rx_poll); | ||
| 604 | } else { | ||
| 605 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, | ||
| 606 | mt76_dma_rx_poll); | ||
| 607 | } | ||
| 608 | 636 | ||
| 609 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); | 637 | if (is_mt7996(&dev->mt76)) { |
| 610 | if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { | 638 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, |
| 611 | mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, | 639 | mt76_dma_rx_poll); |
| 612 | mt76_dma_rx_poll); | 640 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, |
| 613 | } else { | 641 | mt76_dma_rx_poll); |
| 614 | mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, | 642 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, |
| 615 | mt76_dma_rx_poll); | 643 | mt76_dma_rx_poll); |
| 616 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, | 644 | } else { |
| 617 | mt76_dma_rx_poll); | 645 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, |
| 618 | } | 646 | mt76_dma_rx_poll); |
| 647 | } | ||
| 619 | 648 | ||
| 620 | if (!mt76_npu_device_active(&dev->mt76)) | 649 | mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); |
| 621 | mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); | 650 | if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { |
| 651 | mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, | ||
| 652 | mt76_dma_rx_poll); | ||
| 653 | } else { | ||
| 654 | mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, | ||
| 655 | mt76_dma_rx_poll); | ||
| 656 | mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, | ||
| 657 | mt76_dma_rx_poll); | ||
| 622 | } | 658 | } |
| 623 | 659 | ||
| 624 | return 0; | 660 | if (!mt76_npu_device_active(&dev->mt76)) |
| 661 | mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); | ||
| 625 | } | 662 | } |
| 626 | 663 | ||
| 627 | int mt7996_dma_init(struct mt7996_dev *dev) | 664 | int mt7996_dma_init(struct mt7996_dev *dev) |
| @@ -642,11 +679,16 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 14 unmodified lines | |||
| 642 | mt7996_dma_disable(dev, true); | 679 | mt7996_dma_disable(dev, true); |
| 643 | 680 | ||
| 644 | /* init tx queue */ | 681 | /* init tx queue */ |
| 645 | ret = mt7996_init_tx_queues(&dev->phy, | 682 | if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) |
| 646 | MT_TXQ_ID(dev->mphy.band_idx), | 683 | ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0), |
| 647 | MT7996_TX_RING_SIZE, | 684 | MT7996_NPU_TX_RING_SIZE, |
| 648 | MT_TXQ_RING_BASE(0), | 685 | MT_TXQ_RING_BASE(0) + hif1_ofs, |
| 649 | wed); | 686 | NULL); |
| 687 | else | ||
| 688 | ret = mt7996_init_tx_queues(&dev->phy, | ||
| 689 | MT_TXQ_ID(dev->mphy.band_idx), | ||
| 690 | MT7996_TX_RING_SIZE, | ||
| 691 | MT_TXQ_RING_BASE(0), wed); | ||
| 650 | if (ret) | 692 | if (ret) |
| 651 | return ret; | 693 | return ret; |
| 652 | 694 | ||
| @@ -714,6 +756,9 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 61 unmodified lines | |||
| 714 | (is_mt7992(&dev->mt76)))) { | 756 | (is_mt7992(&dev->mt76)))) { |
| 715 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; | 757 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; |
| 716 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; | 758 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; |
| 759 | } else if (is_mt7992(&dev->mt76) && | ||
| 760 | mt76_npu_device_active(&dev->mt76)) { | ||
| 761 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_NPU_Q_TXFREE(0); | ||
| 717 | } | 762 | } |
| 718 | 763 | ||
| 719 | if (mt7996_has_wa(dev)) { | 764 | if (mt7996_has_wa(dev)) { |
| @@ -846,6 +891,8 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 126 unmodified lines | |||
| 846 | /* tx free notify event from WA for band0 */ | 891 | /* tx free notify event from WA for band0 */ |
| 847 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; | 892 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; |
| 848 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; | 893 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; |
| 894 | } else if (mt76_npu_device_active(&dev->mt76)) { | ||
| 895 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_NPU_Q_TXFREE(0); | ||
| 849 | } | 896 | } |
| 850 | 897 | ||
| 851 | ret = mt76_queue_alloc(dev, | 898 | ret = mt76_queue_alloc(dev, |
| @@ -859,16 +906,21 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 7 unmodified lines | |||
| 859 | } | 906 | } |
| 860 | 907 | ||
| 861 | if (mt7996_band_valid(dev, MT_BAND2)) { | 908 | if (mt7996_band_valid(dev, MT_BAND2)) { |
| 909 | u32 size; | ||
| 910 | |||
| 862 | /* rx rro data queue for band2 */ | 911 | /* rx rro data queue for band2 */ |
| 863 | dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = | 912 | dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = |
| 864 | MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; | 913 | MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; |
| 865 | if (mtk_wed_device_active(wed) && | 914 | if (mtk_wed_device_active(wed) && |
| 866 | mtk_wed_get_rx_capa(wed)) | 915 | mtk_wed_get_rx_capa(wed)) |
| 867 | dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; | 916 | dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; |
| 917 | |||
| 918 | size = is_mt7996(&dev->mt76) && | ||
| 919 | mt76_npu_device_active(&dev->mt76) | ||
| 920 | ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE; | ||
| 868 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], | 921 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], |
| 869 | MT_RXQ_ID(MT_RXQ_RRO_BAND2), | 922 | MT_RXQ_ID(MT_RXQ_RRO_BAND2), |
| 870 | MT7996_RX_RING_SIZE, | 923 | size, MT7996_RX_BUF_SIZE, |
| 871 | MT7996_RX_BUF_SIZE, | ||
| 872 | MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); | 924 | MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); |
| 873 | if (ret) | 925 | if (ret) |
| 874 | return ret; | 926 | return ret; |
| @@ -33,6 +33,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) · 32 unmodified lines | |||
| 33 | if (dev->var.fem == MT7996_FEM_INT) | 33 | if (dev->var.fem == MT7996_FEM_INT) |
| 34 | return MT7992_EEPROM_DEFAULT_23_INT; | 34 | return MT7992_EEPROM_DEFAULT_23_INT; |
| 35 | return MT7992_EEPROM_DEFAULT_23; | 35 | return MT7992_EEPROM_DEFAULT_23; |
| 36 | case MT7992_VAR_TYPE_24: | ||
| 37 | return MT7992_EEPROM_DEFAULT_24; | ||
| 36 | case MT7992_VAR_TYPE_44: | 38 | case MT7992_VAR_TYPE_44: |
| 37 | default: | 39 | default: |
| 38 | if (dev->var.fem == MT7996_FEM_INT) | 40 | if (dev->var.fem == MT7996_FEM_INT) |
| @@ -153,7 +155,7 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) · 114 unmodified lines | |||
| 153 | 155 | ||
| 154 | dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); | 156 | dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); |
| 155 | memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); | 157 | memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); |
| 156 | dev->flash_mode = true; | 158 | dev->eeprom_mode = EEPROM_MODE_DEFAULT_BIN; |
| 157 | 159 | ||
| 158 | out: | 160 | out: |
| 159 | release_firmware(fw); | 161 | release_firmware(fw); |
| @@ -163,26 +165,31 @@ out: · 3 unmodified lines | |||
| 163 | 165 | ||
| 164 | static int mt7996_eeprom_load(struct mt7996_dev *dev) | 166 | static int mt7996_eeprom_load(struct mt7996_dev *dev) |
| 165 | { | 167 | { |
| 168 | u32 eeprom_blk_size, block_num; | ||
| 166 | bool use_default = false; | 169 | bool use_default = false; |
| 167 | int ret; | 170 | int ret, i; |
| 168 | 171 | ||
| 169 | ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); | 172 | ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); |
| 170 | if (ret < 0) | 173 | if (ret < 0) |
| 171 | return ret; | 174 | return ret; |
| 172 | 175 | ||
| 173 | if (ret && !mt7996_check_eeprom(dev)) { | 176 | if (ret && !mt7996_check_eeprom(dev)) { |
| 174 | dev->flash_mode = true; | 177 | dev->eeprom_mode = EEPROM_MODE_FLASH; |
| 175 | goto out; | 178 | goto out; |
| 176 | } | 179 | } |
| 177 | 180 | ||
| 178 | if (!dev->flash_mode) { | 181 | memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); |
| 179 | u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; | 182 | if (mt7996_has_ext_eeprom(dev)) { |
| 180 | u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); | 183 | /* external eeprom mode */ |
| 184 | dev->eeprom_mode = EEPROM_MODE_EXT; | ||
| 185 | eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE; | ||
| 186 | } else { | ||
| 181 | u8 free_block_num; | 187 | u8 free_block_num; |
| 182 | int i; | ||
| 183 | 188 | ||
| 184 | memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); | 189 | /* efuse mode */ |
| 185 | ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); | 190 | dev->eeprom_mode = EEPROM_MODE_EFUSE; |
| 191 | eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; | ||
| 192 | ret = mt7996_mcu_get_efuse_free_block(dev, &free_block_num); | ||
| 186 | if (ret < 0) | 193 | if (ret < 0) |
| 187 | return ret; | 194 | return ret; |
| 188 | 195 | ||
| @@ -191,27 +198,29 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) · 2 unmodified lines | |||
| 191 | use_default = true; | 198 | use_default = true; |
| 192 | goto out; | 199 | goto out; |
| 193 | } | 200 | } |
| 201 | } | ||
| 202 | |||
| 203 | /* check if eeprom data from fw is valid */ | ||
| 204 | if (mt7996_mcu_get_eeprom(dev, 0, NULL, eeprom_blk_size, | ||
| 205 | dev->eeprom_mode) || | ||
| 206 | mt7996_check_eeprom(dev)) { | ||
| 207 | use_default = true; | ||
| 208 | goto out; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* read eeprom data from fw */ | ||
| 212 | block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); | ||
| 213 | for (i = 1; i < block_num; i++) { | ||
| 214 | u32 len = eeprom_blk_size; | ||
| 194 | 215 | ||
| 195 | /* check if eeprom data from fw is valid */ | 216 | if (i == block_num - 1) |
| 196 | if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || | 217 | len = MT7996_EEPROM_SIZE % eeprom_blk_size; |
| 197 | mt7996_check_eeprom(dev)) { | 218 | ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, |
| 219 | NULL, len, dev->eeprom_mode); | ||
| 220 | if (ret && ret != -EINVAL) { | ||
| 198 | use_default = true; | 221 | use_default = true; |
| 199 | goto out; | 222 | goto out; |
| 200 | } | 223 | } |
| 201 | |||
| 202 | /* read eeprom data from fw */ | ||
| 203 | for (i = 1; i < block_num; i++) { | ||
| 204 | u32 len = eeprom_blk_size; | ||
| 205 | |||
| 206 | if (i == block_num - 1) | ||
| 207 | len = MT7996_EEPROM_SIZE % eeprom_blk_size; | ||
| 208 | ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, | ||
| 209 | NULL, len); | ||
| 210 | if (ret && ret != -EINVAL) { | ||
| 211 | use_default = true; | ||
| 212 | goto out; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | 224 | } |
| 216 | 225 | ||
| 217 | out: | 226 | out: |
| @@ -385,7 +394,8 @@ bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev) · 167 unmodified lines | |||
| 385 | return false; | 394 | return false; |
| 386 | break; | 395 | break; |
| 387 | case MT7992_DEVICE_ID: | 396 | case MT7992_DEVICE_ID: |
| 388 | if (dev->var.type == MT7992_VAR_TYPE_23) | 397 | if (dev->var.type == MT7992_VAR_TYPE_23 || |
| 398 | dev->var.type == MT7992_VAR_TYPE_24) | ||
| 389 | return false; | 399 | return false; |
| 390 | break; | 400 | break; |
| 391 | case MT7990_DEVICE_ID: { | 401 | case MT7990_DEVICE_ID: { |
| @@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = { · 33 unmodified lines | |||
| 34 | BIT(NL80211_CHAN_WIDTH_40) | | 34 | BIT(NL80211_CHAN_WIDTH_40) | |
| 35 | BIT(NL80211_CHAN_WIDTH_80) | | 35 | BIT(NL80211_CHAN_WIDTH_80) | |
| 36 | BIT(NL80211_CHAN_WIDTH_160), | 36 | BIT(NL80211_CHAN_WIDTH_160), |
| 37 | .beacon_int_min_gcd = 100, | ||
| 38 | }; | ||
| 39 | |||
| 40 | static const struct ieee80211_iface_combination if_comb_global_7992 = { | ||
| 41 | .limits = &if_limits_global, | ||
| 42 | .n_limits = 1, | ||
| 43 | .max_interfaces = 32, | ||
| 44 | .num_different_channels = MT7996_MAX_RADIOS - 1, | ||
| 45 | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||
| 46 | BIT(NL80211_CHAN_WIDTH_20) | | ||
| 47 | BIT(NL80211_CHAN_WIDTH_40) | | ||
| 48 | BIT(NL80211_CHAN_WIDTH_80) | | ||
| 49 | BIT(NL80211_CHAN_WIDTH_160), | ||
| 50 | .beacon_int_min_gcd = 100, | ||
| 37 | }; | 51 | }; |
| 38 | 52 | ||
| 39 | static const struct ieee80211_iface_limit if_limits[] = { | 53 | static const struct ieee80211_iface_limit if_limits[] = { |
| @@ -85,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { · 45 unmodified lines | |||
| 85 | .extended_capabilities_mask = if_types_ext_capa_ap, | 99 | .extended_capabilities_mask = if_types_ext_capa_ap, |
| 86 | .extended_capabilities_len = sizeof(if_types_ext_capa_ap), | 100 | .extended_capabilities_len = sizeof(if_types_ext_capa_ap), |
| 87 | .mld_capa_and_ops = | 101 | .mld_capa_and_ops = |
| 102 | FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) | | ||
| 88 | FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, | 103 | FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, |
| 89 | MT7996_MAX_RADIOS - 1), | 104 | MT7996_MAX_RADIOS - 1), |
| 90 | }, | 105 | }, |
| @@ -485,7 +500,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) · 394 unmodified lines | |||
| 485 | hw->vif_data_size = sizeof(struct mt7996_vif); | 500 | hw->vif_data_size = sizeof(struct mt7996_vif); |
| 486 | hw->chanctx_data_size = sizeof(struct mt76_chanctx); | 501 | hw->chanctx_data_size = sizeof(struct mt76_chanctx); |
| 487 | 502 | ||
| 488 | wiphy->iface_combinations = &if_comb_global; | 503 | wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global : |
| 504 | &if_comb_global_7992; | ||
| 489 | wiphy->n_iface_combinations = 1; | 505 | wiphy->n_iface_combinations = 1; |
| 490 | 506 | ||
| 491 | wiphy->radio = dev->radios; | 507 | wiphy->radio = dev->radios; |
| @@ -521,8 +537,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) · 29 unmodified lines | |||
| 521 | ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); | 537 | ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); |
| 522 | ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); | 538 | ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); |
| 523 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); | 539 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); |
| 540 | ieee80211_hw_set(hw, CHANCTX_STA_CSA); | ||
| 524 | 541 | ||
| 525 | hw->max_tx_fragments = 4; | 542 | hw->max_tx_fragments = 4; |
| 543 | wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */ | ||
| 526 | 544 | ||
| 527 | /* init led callbacks */ | 545 | /* init led callbacks */ |
| 528 | if (IS_ENABLED(CONFIG_MT76_LEDS)) { | 546 | if (IS_ENABLED(CONFIG_MT76_LEDS)) { |
| @@ -592,7 +610,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) · 63 unmodified lines | |||
| 592 | void mt7996_mac_init(struct mt7996_dev *dev) | 610 | void mt7996_mac_init(struct mt7996_dev *dev) |
| 593 | { | 611 | { |
| 594 | #define HIF_TXD_V2_1 0x21 | 612 | #define HIF_TXD_V2_1 0x21 |
| 595 | int i; | 613 | int i, rx_path_type; |
| 596 | 614 | ||
| 597 | mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); | 615 | mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); |
| 598 | 616 | ||
| @@ -606,11 +624,16 @@ void mt7996_mac_init(struct mt7996_dev *dev) · 7 unmodified lines | |||
| 606 | } | 624 | } |
| 607 | 625 | ||
| 608 | /* rro module init */ | 626 | /* rro module init */ |
| 609 | if (dev->hif2) | 627 | if (dev->hif2) { |
| 628 | if (mt76_npu_device_active(&dev->mt76)) | ||
| 629 | rx_path_type = is_mt7996(&dev->mt76) ? 6 : 8; | ||
| 630 | else | ||
| 631 | rx_path_type = is_mt7996(&dev->mt76) ? 2 : 7; | ||
| 610 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, | 632 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, |
| 611 | is_mt7996(&dev->mt76) ? 2 : 7); | 633 | rx_path_type); |
| 612 | else | 634 | } else { |
| 613 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0); | 635 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0); |
| 636 | } | ||
| 614 | 637 | ||
| 615 | if (mt7996_has_hwrro(dev)) { | 638 | if (mt7996_has_hwrro(dev)) { |
| 616 | u16 timeout; | 639 | u16 timeout; |
| @@ -668,8 +691,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) · 51 unmodified lines | |||
| 668 | return 0; | 691 | return 0; |
| 669 | 692 | ||
| 670 | if (dev->hif2 && | 693 | if (dev->hif2 && |
| 671 | ((is_mt7996(&dev->mt76) && band == MT_BAND2) || | 694 | ((is_mt7992(&dev->mt76) && band == MT_BAND1) || |
| 672 | (is_mt7992(&dev->mt76) && band == MT_BAND1))) { | 695 | (is_mt7996(&dev->mt76) && band == MT_BAND2 && |
| 696 | !mt76_npu_device_active(&dev->mt76)))) { | ||
| 673 | hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); | 697 | hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); |
| 674 | wed = &dev->mt76.mmio.wed_hif2; | 698 | wed = &dev->mt76.mmio.wed_hif2; |
| 675 | } | 699 | } |
| @@ -709,14 +733,19 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) · 33 unmodified lines | |||
| 709 | /* init wiphy according to mphy and phy */ | 733 | /* init wiphy according to mphy and phy */ |
| 710 | mt7996_init_wiphy_band(mphy->hw, phy); | 734 | mt7996_init_wiphy_band(mphy->hw, phy); |
| 711 | 735 | ||
| 712 | if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) { | 736 | if (is_mt7996(&dev->mt76) && |
| 737 | ((band == MT_BAND1 && !dev->hif2) || | ||
| 738 | (band == MT_BAND2 && mt76_npu_device_active(&dev->mt76)))) { | ||
| 713 | int i; | 739 | int i; |
| 714 | 740 | ||
| 715 | for (i = 0; i <= MT_TXQ_PSD; i++) | 741 | for (i = 0; i <= MT_TXQ_PSD; i++) |
| 716 | mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0]; | 742 | mphy->q_tx[i] = dev->mt76.phys[band - 1]->q_tx[0]; |
| 717 | } else { | 743 | } else { |
| 718 | ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), | 744 | int size = is_mt7996(&dev->mt76) && |
| 719 | MT7996_TX_RING_SIZE, | 745 | mt76_npu_device_active(&dev->mt76) |
| 746 | ? MT7996_NPU_TX_RING_SIZE / 2 : MT7996_TX_RING_SIZE; | ||
| 747 | |||
| 748 | ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), size, | ||
| 720 | MT_TXQ_RING_BASE(band) + hif1_ofs, | 749 | MT_TXQ_RING_BASE(band) + hif1_ofs, |
| 721 | wed); | 750 | wed); |
| 722 | if (ret) | 751 | if (ret) |
| @@ -756,15 +785,41 @@ static void mt7996_init_work(struct work_struct *work) · 33 unmodified lines | |||
| 756 | mt7996_mcu_set_eeprom(dev); | 785 | mt7996_mcu_set_eeprom(dev); |
| 757 | mt7996_mac_init(dev); | 786 | mt7996_mac_init(dev); |
| 758 | mt7996_txbf_init(dev); | 787 | mt7996_txbf_init(dev); |
| 788 | |||
| 789 | if (!is_mt7990(&dev->mt76)) | ||
| 790 | mt7996_mcu_set_dup_wtbl(dev); | ||
| 759 | } | 791 | } |
| 760 | 792 | ||
| 761 | void mt7996_wfsys_reset(struct mt7996_dev *dev) | 793 | void mt7996_wfsys_reset(struct mt7996_dev *dev) |
| 762 | { | 794 | { |
| 763 | mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); | 795 | if (!is_mt7990(&dev->mt76)) { |
| 764 | msleep(20); | 796 | mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); |
| 797 | msleep(20); | ||
| 798 | |||
| 799 | mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); | ||
| 800 | msleep(20); | ||
| 801 | |||
| 802 | return; | ||
| 803 | } | ||
| 804 | |||
| 805 | if (!dev->recovery.hw_full_reset) | ||
| 806 | return; | ||
| 765 | 807 | ||
| 766 | mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); | 808 | mt76_set(dev, MT_WF_SUBSYS_RST, |
| 809 | MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT | | ||
| 810 | MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT | | ||
| 811 | MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT); | ||
| 812 | mt76_rmw(dev, MT_WF_SUBSYS_RST, | ||
| 813 | MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE, | ||
| 814 | u32_encode_bits(0x20, MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE)); | ||
| 815 | mt76_clear(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK); | ||
| 816 | mt76_set(dev, MT_WF_SUBSYS_RST, MT_WF_SUBSYS_RST_WHOLE_PATH_RST); | ||
| 767 | msleep(20); | 817 | msleep(20); |
| 818 | |||
| 819 | if (mt76_poll(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK, 0x1a, 1000)) | ||
| 820 | return; | ||
| 821 | |||
| 822 | dev_err(dev->mt76.dev, "wfsys reset fail\n"); | ||
| 768 | } | 823 | } |
| 769 | 824 | ||
| 770 | static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev) | 825 | static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev) |
| @@ -842,8 +897,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev) · 71 unmodified lines | |||
| 842 | } | 897 | } |
| 843 | } else { | 898 | } else { |
| 844 | /* set emul 3.0 function */ | 899 | /* set emul 3.0 function */ |
| 845 | mt76_wr(dev, MT_RRO_3_0_EMU_CONF, | 900 | mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); |
| 846 | MT_RRO_3_0_EMU_CONF_EN_MASK); | ||
| 847 | 901 | ||
| 848 | mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, | 902 | mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, |
| 849 | dev->wed_rro.addr_elem[0].phy_addr); | 903 | dev->wed_rro.addr_elem[0].phy_addr); |
| @@ -935,6 +989,12 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) · 85 unmodified lines | |||
| 935 | addr++; | 989 | addr++; |
| 936 | } | 990 | } |
| 937 | 991 | ||
| 992 | if (is_mt7996(&dev->mt76) && | ||
| 993 | mt76_npu_device_active(&dev->mt76)) | ||
| 994 | mt76_npu_send_txrx_addr(&dev->mt76, 0, i, | ||
| 995 | dev->wed_rro.addr_elem[i].phy_addr, | ||
| 996 | 0, 0); | ||
| 997 | |||
| 938 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED | 998 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 939 | if (mtk_wed_device_active(&dev->mt76.mmio.wed) && | 999 | if (mtk_wed_device_active(&dev->mt76.mmio.wed) && |
| 940 | mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) { | 1000 | mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) { |
| @@ -995,6 +1055,10 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) · 54 unmodified lines | |||
| 995 | addr++; | 1055 | addr++; |
| 996 | } | 1056 | } |
| 997 | 1057 | ||
| 1058 | if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) | ||
| 1059 | mt76_npu_send_txrx_addr(&dev->mt76, 1, 0, | ||
| 1060 | dev->wed_rro.session.phy_addr, 0, 0); | ||
| 1061 | |||
| 998 | mt7996_rro_hw_init(dev); | 1062 | mt7996_rro_hw_init(dev); |
| 999 | 1063 | ||
| 1000 | return mt7996_dma_rro_init(dev); | 1064 | return mt7996_dma_rro_init(dev); |
| @@ -1081,8 +1145,12 @@ static void mt7996_wed_rro_work(struct work_struct *work) · 80 unmodified lines | |||
| 1081 | list); | 1145 | list); |
| 1082 | list_del_init(&e->list); | 1146 | list_del_init(&e->list); |
| 1083 | 1147 | ||
| 1084 | if (mt76_npu_device_active(&dev->mt76)) | 1148 | if (mt76_npu_device_active(&dev->mt76)) { |
| 1149 | if (is_mt7996(&dev->mt76)) | ||
| 1150 | mt76_npu_send_txrx_addr(&dev->mt76, 3, e->id, | ||
| 1151 | 0, 0, 0); | ||
| 1085 | goto reset_session; | 1152 | goto reset_session; |
| 1153 | } | ||
| 1086 | 1154 | ||
| 1087 | for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { | 1155 | for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { |
| 1088 | void *ptr = dev->wed_rro.session.ptr; | 1156 | void *ptr = dev->wed_rro.session.ptr; |
| @@ -1129,7 +1197,7 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev) · 40 unmodified lines | |||
| 1129 | else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) | 1197 | else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) |
| 1130 | var_type = MT7992_VAR_TYPE_44; | 1198 | var_type = MT7992_VAR_TYPE_44; |
| 1131 | else | 1199 | else |
| 1132 | return -EINVAL; | 1200 | var_type = MT7992_VAR_TYPE_24; |
| 1133 | break; | 1201 | break; |
| 1134 | case MT7990_DEVICE_ID: | 1202 | case MT7990_DEVICE_ID: |
| 1135 | var_type = MT7990_VAR_TYPE_23; | 1203 | var_type = MT7990_VAR_TYPE_23; |
| @@ -1163,7 +1231,8 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev) · 27 unmodified lines | |||
| 1163 | if (ret) | 1231 | if (ret) |
| 1164 | return ret; | 1232 | return ret; |
| 1165 | 1233 | ||
| 1166 | ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf)); | 1234 | ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf), |
| 1235 | EEPROM_MODE_EFUSE); | ||
| 1167 | if (ret && ret != -EINVAL) | 1236 | if (ret && ret != -EINVAL) |
| 1168 | return ret; | 1237 | return ret; |
| 1169 | 1238 | ||
| @@ -1696,6 +1765,8 @@ int mt7996_register_device(struct mt7996_dev *dev) · 526 unmodified lines | |||
| 1696 | if (ret) | 1765 | if (ret) |
| 1697 | return ret; | 1766 | return ret; |
| 1698 | 1767 | ||
| 1768 | mt7996_dma_rro_start(dev); | ||
| 1769 | |||
| 1699 | ret = mt76_register_device(&dev->mt76, true, mt76_rates, | 1770 | ret = mt76_register_device(&dev->mt76, true, mt76_rates, |
| 1700 | ARRAY_SIZE(mt76_rates)); | 1771 | ARRAY_SIZE(mt76_rates)); |
| 1701 | if (ret) | 1772 | if (ret) |
| @@ -1726,6 +1797,7 @@ error: · 24 unmodified lines | |||
| 1726 | 1797 | ||
| 1727 | void mt7996_unregister_device(struct mt7996_dev *dev) | 1798 | void mt7996_unregister_device(struct mt7996_dev *dev) |
| 1728 | { | 1799 | { |
| 1800 | cancel_work_sync(&dev->dump_work); | ||
| 1729 | cancel_work_sync(&dev->wed_rro.work); | 1801 | cancel_work_sync(&dev->wed_rro.work); |
| 1730 | mt7996_unregister_phy(mt7996_phy3(dev)); | 1802 | mt7996_unregister_phy(mt7996_phy3(dev)); |
| 1731 | mt7996_unregister_phy(mt7996_phy2(dev)); | 1803 | mt7996_unregister_phy(mt7996_phy2(dev)); |
| @@ -13,45 +13,6 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) | 14 | #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) |
| 15 | 15 | ||
| 16 | static const struct mt7996_dfs_radar_spec etsi_radar_specs = { | ||
| 17 | .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, | ||
| 18 | .radar_pattern = { | ||
| 19 | [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, | ||
| 20 | [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, | ||
| 21 | [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, | ||
| 22 | [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, | ||
| 23 | [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, | ||
| 24 | [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, | ||
| 25 | [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, | ||
| 26 | [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, | ||
| 27 | }, | ||
| 28 | }; | ||
| 29 | |||
| 30 | static const struct mt7996_dfs_radar_spec fcc_radar_specs = { | ||
| 31 | .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, | ||
| 32 | .radar_pattern = { | ||
| 33 | [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, | ||
| 34 | [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, | ||
| 35 | [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, | ||
| 36 | [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, | ||
| 37 | [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, | ||
| 38 | }, | ||
| 39 | }; | ||
| 40 | |||
| 41 | static const struct mt7996_dfs_radar_spec jp_radar_specs = { | ||
| 42 | .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, | ||
| 43 | .radar_pattern = { | ||
| 44 | [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, | ||
| 45 | [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, | ||
| 46 | [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, | ||
| 47 | [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, | ||
| 48 | [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, | ||
| 49 | [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, | ||
| 50 | [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, | ||
| 51 | [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, | ||
| 52 | }, | ||
| 53 | }; | ||
| 54 | |||
| 55 | static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, | 16 | static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, |
| 56 | u16 idx, u8 band_idx) | 17 | u16 idx, u8 band_idx) |
| 57 | { | 18 | { |
| @@ -527,7 +488,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, · 469 unmodified lines | |||
| 527 | !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) | 488 | !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) |
| 528 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 489 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 529 | 490 | ||
| 530 | if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) | 491 | if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) |
| 531 | status->flag |= RX_FLAG_FAILED_FCS_CRC; | 492 | status->flag |= RX_FLAG_FAILED_FCS_CRC; |
| 532 | 493 | ||
| 533 | if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) | 494 | if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) |
| @@ -700,6 +661,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, · 166 unmodified lines | |||
| 700 | 661 | ||
| 701 | hdr = mt76_skb_get_hdr(skb); | 662 | hdr = mt76_skb_get_hdr(skb); |
| 702 | fc = hdr->frame_control; | 663 | fc = hdr->frame_control; |
| 664 | if (ieee80211_is_beacon(fc)) | ||
| 665 | mt76_rx_beacon(mphy, skb); | ||
| 703 | if (ieee80211_is_data_qos(fc)) { | 666 | if (ieee80211_is_data_qos(fc)) { |
| 704 | u8 *qos = ieee80211_get_qos_ctl(hdr); | 667 | u8 *qos = ieee80211_get_qos_ctl(hdr); |
| 705 | 668 | ||
| @@ -1139,10 +1102,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, · 433 unmodified lines | |||
| 1139 | * req | 1102 | * req |
| 1140 | */ | 1103 | */ |
| 1141 | if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { | 1104 | if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { |
| 1142 | u32 val; | 1105 | u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp); |
| 1143 | 1106 | ||
| 1144 | ptr = (__le32 *)(txwi + MT_TXD_SIZE); | 1107 | ptr = (__le32 *)(txwi + MT_TXD_SIZE); |
| 1145 | memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp)); | 1108 | memset((void *)ptr, 0, mac_txp_size); |
| 1146 | 1109 | ||
| 1147 | val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | | 1110 | val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | |
| 1148 | MT_TXP0_TOKEN_ID0_VALID_MASK; | 1111 | MT_TXP0_TOKEN_ID0_VALID_MASK; |
| @@ -1161,6 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, · 12 unmodified lines | |||
| 1161 | tx_info->buf[1].addr >> 32); | 1124 | tx_info->buf[1].addr >> 32); |
| 1162 | #endif | 1125 | #endif |
| 1163 | ptr[3] = cpu_to_le32(val); | 1126 | ptr[3] = cpu_to_le32(val); |
| 1127 | |||
| 1128 | tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size; | ||
| 1164 | } else { | 1129 | } else { |
| 1165 | struct mt76_connac_txp_common *txp; | 1130 | struct mt76_connac_txp_common *txp; |
| 1166 | 1131 | ||
| @@ -1270,8 +1235,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, · 103 unmodified lines | |||
| 1270 | if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) | 1235 | if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) |
| 1271 | return; | 1236 | return; |
| 1272 | 1237 | ||
| 1273 | if (!test_and_set_bit(tid, &wcid->ampdu_state)) | 1238 | if (!test_and_set_bit(tid, &wcid->ampdu_state) && |
| 1274 | ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); | 1239 | ieee80211_start_tx_ba_session(link_sta->sta, tid, 0)) |
| 1240 | clear_bit(tid, &wcid->ampdu_state); | ||
| 1275 | } | 1241 | } |
| 1276 | 1242 | ||
| 1277 | static void | 1243 | static void |
| @@ -2203,9 +2169,14 @@ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) · 925 unmodified lines | |||
| 2203 | 2169 | ||
| 2204 | for_each_vif_active_link(vif, link_conf, link_id) { | 2170 | for_each_vif_active_link(vif, link_conf, link_id) { |
| 2205 | struct mt7996_vif_link *link; | 2171 | struct mt7996_vif_link *link; |
| 2172 | struct mt7996_phy *link_phy; | ||
| 2206 | 2173 | ||
| 2207 | link = mt7996_vif_link(dev, vif, link_id); | 2174 | link = mt7996_vif_link(dev, vif, link_id); |
| 2208 | if (!link || link->phy != phy) | 2175 | if (!link) |
| 2176 | continue; | ||
| 2177 | |||
| 2178 | link_phy = mt7996_vif_link_phy(link); | ||
| 2179 | if (link_phy != phy) | ||
| 2209 | continue; | 2180 | continue; |
| 2210 | 2181 | ||
| 2211 | mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf, | 2182 | mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf, |
| @@ -2248,6 +2219,12 @@ void mt7996_tx_token_put(struct mt7996_dev *dev) · 36 unmodified lines | |||
| 2248 | } | 2219 | } |
| 2249 | spin_unlock_bh(&dev->mt76.token_lock); | 2220 | spin_unlock_bh(&dev->mt76.token_lock); |
| 2250 | idr_destroy(&dev->mt76.token); | 2221 | idr_destroy(&dev->mt76.token); |
| 2222 | |||
| 2223 | for (id = 0; id < __MT_MAX_BAND; id++) { | ||
| 2224 | struct mt76_phy *phy = dev->mt76.phys[id]; | ||
| 2225 | if (phy) | ||
| 2226 | atomic_set(&phy->mgmt_tx_pending, 0); | ||
| 2227 | } | ||
| 2251 | } | 2228 | } |
| 2252 | 2229 | ||
| 2253 | static int | 2230 | static int |
| @@ -2395,23 +2372,8 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) · 141 unmodified lines | |||
| 2395 | struct mt7996_dev *dev = data; | 2372 | struct mt7996_dev *dev = data; |
| 2396 | int i; | 2373 | int i; |
| 2397 | 2374 | ||
| 2398 | for (i = 0; i < ARRAY_SIZE(msta->link); i++) { | 2375 | for (i = 0; i < ARRAY_SIZE(msta->link); i++) |
| 2399 | struct mt7996_sta_link *msta_link = NULL; | 2376 | mt7996_mac_sta_remove_link(dev, sta, i, true); |
| 2400 | |||
| 2401 | msta_link = rcu_replace_pointer(msta->link[i], msta_link, | ||
| 2402 | lockdep_is_held(&dev->mt76.mutex)); | ||
| 2403 | if (!msta_link) | ||
| 2404 | continue; | ||
| 2405 | |||
| 2406 | mt7996_mac_sta_deinit_link(dev, msta_link); | ||
| 2407 | |||
| 2408 | if (msta->deflink_id == i) { | ||
| 2409 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; | ||
| 2410 | continue; | ||
| 2411 | } | ||
| 2412 | |||
| 2413 | kfree_rcu(msta_link, rcu_head); | ||
| 2414 | } | ||
| 2415 | } | 2377 | } |
| 2416 | 2378 | ||
| 2417 | static void | 2379 | static void |
| @@ -2544,6 +2506,7 @@ void mt7996_mac_reset_work(struct work_struct *work) · 126 unmodified lines | |||
| 2544 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) | 2506 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) |
| 2545 | mtk_wed_device_stop(&dev->mt76.mmio.wed); | 2507 | mtk_wed_device_stop(&dev->mt76.mmio.wed); |
| 2546 | 2508 | ||
| 2509 | mt7996_npu_hw_stop(dev); | ||
| 2547 | ieee80211_stop_queues(mt76_hw(dev)); | 2510 | ieee80211_stop_queues(mt76_hw(dev)); |
| 2548 | 2511 | ||
| 2549 | set_bit(MT76_RESET, &dev->mphy.state); | 2512 | set_bit(MT76_RESET, &dev->mphy.state); |
| @@ -2564,14 +2527,19 @@ void mt7996_mac_reset_work(struct work_struct *work) · 14 unmodified lines | |||
| 2564 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) | 2527 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) |
| 2565 | continue; | 2528 | continue; |
| 2566 | 2529 | ||
| 2530 | if (mt76_npu_device_active(&dev->mt76) && | ||
| 2531 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) | ||
| 2532 | continue; | ||
| 2533 | |||
| 2534 | if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i])) | ||
| 2535 | continue; | ||
| 2536 | |||
| 2567 | napi_disable(&dev->mt76.napi[i]); | 2537 | napi_disable(&dev->mt76.napi[i]); |
| 2568 | } | 2538 | } |
| 2569 | napi_disable(&dev->mt76.tx_napi); | 2539 | napi_disable(&dev->mt76.tx_napi); |
| 2570 | 2540 | ||
| 2571 | mutex_lock(&dev->mt76.mutex); | 2541 | mutex_lock(&dev->mt76.mutex); |
| 2572 | 2542 | ||
| 2573 | mt7996_npu_hw_stop(dev); | ||
| 2574 | |||
| 2575 | mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); | 2543 | mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); |
| 2576 | 2544 | ||
| 2577 | if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { | 2545 | if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { |
| @@ -2591,7 +2559,7 @@ void mt7996_mac_reset_work(struct work_struct *work) · 13 unmodified lines | |||
| 2591 | mt7996_dma_start(dev, false, false); | 2559 | mt7996_dma_start(dev, false, false); |
| 2592 | 2560 | ||
| 2593 | if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) | 2561 | if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) |
| 2594 | mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); | 2562 | mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); |
| 2595 | 2563 | ||
| 2596 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { | 2564 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { |
| 2597 | u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | | 2565 | u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | |
| @@ -2610,6 +2578,8 @@ void mt7996_mac_reset_work(struct work_struct *work) · 12 unmodified lines | |||
| 2610 | MT_INT_TX_RX_DONE_EXT); | 2578 | MT_INT_TX_RX_DONE_EXT); |
| 2611 | } | 2579 | } |
| 2612 | 2580 | ||
| 2581 | __mt7996_npu_hw_init(dev); | ||
| 2582 | |||
| 2613 | clear_bit(MT76_MCU_RESET, &dev->mphy.state); | 2583 | clear_bit(MT76_MCU_RESET, &dev->mphy.state); |
| 2614 | mt7996_for_each_phy(dev, phy) | 2584 | mt7996_for_each_phy(dev, phy) |
| 2615 | clear_bit(MT76_RESET, &phy->mt76->state); | 2585 | clear_bit(MT76_RESET, &phy->mt76->state); |
| @@ -2619,6 +2589,13 @@ void mt7996_mac_reset_work(struct work_struct *work) · 3 unmodified lines | |||
| 2619 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) | 2589 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) |
| 2620 | continue; | 2590 | continue; |
| 2621 | 2591 | ||
| 2592 | if (mt76_npu_device_active(&dev->mt76) && | ||
| 2593 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) | ||
| 2594 | continue; | ||
| 2595 | |||
| 2596 | if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i])) | ||
| 2597 | continue; | ||
| 2598 | |||
| 2622 | napi_enable(&dev->mt76.napi[i]); | 2599 | napi_enable(&dev->mt76.napi[i]); |
| 2623 | local_bh_disable(); | 2600 | local_bh_disable(); |
| 2624 | napi_schedule(&dev->mt76.napi[i]); | 2601 | napi_schedule(&dev->mt76.napi[i]); |
| @@ -2639,8 +2616,6 @@ void mt7996_mac_reset_work(struct work_struct *work) · 14 unmodified lines | |||
| 2639 | 2616 | ||
| 2640 | mutex_unlock(&dev->mt76.mutex); | 2617 | mutex_unlock(&dev->mt76.mutex); |
| 2641 | 2618 | ||
| 2642 | mt7996_npu_hw_init(dev); | ||
| 2643 | |||
| 2644 | mt7996_for_each_phy(dev, phy) | 2619 | mt7996_for_each_phy(dev, phy) |
| 2645 | ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, | 2620 | ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, |
| 2646 | MT7996_WATCHDOG_TIME); | 2621 | MT7996_WATCHDOG_TIME); |
| @@ -2737,6 +2712,11 @@ void mt7996_reset(struct mt7996_dev *dev) · 90 unmodified lines | |||
| 2737 | return; | 2712 | return; |
| 2738 | } | 2713 | } |
| 2739 | 2714 | ||
| 2715 | if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { | ||
| 2716 | set_bit(MT76_MCU_RESET, &dev->mphy.state); | ||
| 2717 | wake_up(&dev->mt76.mcu.wait); | ||
| 2718 | } | ||
| 2719 | |||
| 2740 | queue_work(dev->mt76.wq, &dev->reset_work); | 2720 | queue_work(dev->mt76.wq, &dev->reset_work); |
| 2741 | wake_up(&dev->reset_wait); | 2721 | wake_up(&dev->reset_wait); |
| 2742 | } | 2722 | } |
| @@ -2955,6 +2935,7 @@ void mt7996_mac_work(struct work_struct *work) · 212 unmodified lines | |||
| 2955 | 2935 | ||
| 2956 | mutex_unlock(&mphy->dev->mutex); | 2936 | mutex_unlock(&mphy->dev->mutex); |
| 2957 | 2937 | ||
| 2938 | mt76_beacon_mon_check(mphy); | ||
| 2958 | mt76_tx_status_check(mphy->dev, false); | 2939 | mt76_tx_status_check(mphy->dev, false); |
| 2959 | 2940 | ||
| 2960 | ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, | 2941 | ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, |
| @@ -2974,7 +2955,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) · 13 unmodified lines | |||
| 2974 | 2955 | ||
| 2975 | static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) | 2956 | static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) |
| 2976 | { | 2957 | { |
| 2977 | int err, region; | 2958 | int region; |
| 2978 | 2959 | ||
| 2979 | switch (dev->mt76.region) { | 2960 | switch (dev->mt76.region) { |
| 2980 | case NL80211_DFS_ETSI: | 2961 | case NL80211_DFS_ETSI: |
| @@ -2989,11 +2970,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) · 8 unmodified lines | |||
| 2989 | break; | 2970 | break; |
| 2990 | } | 2971 | } |
| 2991 | 2972 | ||
| 2992 | err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); | 2973 | return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); |
| 2993 | if (err < 0) | ||
| 2994 | return err; | ||
| 2995 | |||
| 2996 | return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1); | ||
| 2997 | } | 2974 | } |
| 2998 | 2975 | ||
| 2999 | static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) | 2976 | static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) |
| @@ -3015,40 +2992,6 @@ static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) · 15 unmodified lines | |||
| 3015 | return err; | 2992 | return err; |
| 3016 | } | 2993 | } |
| 3017 | 2994 | ||
| 3018 | static int | ||
| 3019 | mt7996_dfs_init_radar_specs(struct mt7996_phy *phy) | ||
| 3020 | { | ||
| 3021 | const struct mt7996_dfs_radar_spec *radar_specs; | ||
| 3022 | struct mt7996_dev *dev = phy->dev; | ||
| 3023 | int err, i; | ||
| 3024 | |||
| 3025 | switch (dev->mt76.region) { | ||
| 3026 | case NL80211_DFS_FCC: | ||
| 3027 | radar_specs = &fcc_radar_specs; | ||
| 3028 | err = mt7996_mcu_set_fcc5_lpn(dev, 8); | ||
| 3029 | if (err < 0) | ||
| 3030 | return err; | ||
| 3031 | break; | ||
| 3032 | case NL80211_DFS_ETSI: | ||
| 3033 | radar_specs = &etsi_radar_specs; | ||
| 3034 | break; | ||
| 3035 | case NL80211_DFS_JP: | ||
| 3036 | radar_specs = &jp_radar_specs; | ||
| 3037 | break; | ||
| 3038 | default: | ||
| 3039 | return -EINVAL; | ||
| 3040 | } | ||
| 3041 | |||
| 3042 | for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { | ||
| 3043 | err = mt7996_mcu_set_radar_th(dev, i, | ||
| 3044 | &radar_specs->radar_pattern[i]); | ||
| 3045 | if (err < 0) | ||
| 3046 | return err; | ||
| 3047 | } | ||
| 3048 | |||
| 3049 | return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th); | ||
| 3050 | } | ||
| 3051 | |||
| 3052 | int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) | 2995 | int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) |
| 3053 | { | 2996 | { |
| 3054 | struct mt7996_dev *dev = phy->dev; | 2997 | struct mt7996_dev *dev = phy->dev; |
| @@ -3068,10 +3011,6 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) · 13 unmodified lines | |||
| 3068 | goto stop; | 3011 | goto stop; |
| 3069 | 3012 | ||
| 3070 | if (prev_state <= MT_DFS_STATE_DISABLED) { | 3013 | if (prev_state <= MT_DFS_STATE_DISABLED) { |
| 3071 | err = mt7996_dfs_init_radar_specs(phy); | ||
| 3072 | if (err < 0) | ||
| 3073 | return err; | ||
| 3074 | |||
| 3075 | err = mt7996_dfs_start_radar_detector(phy); | 3014 | err = mt7996_dfs_start_radar_detector(phy); |
| 3076 | if (err < 0) | 3015 | if (err < 0) |
| 3077 | return err; | 3016 | return err; |
| @@ -37,9 +37,4 @@ struct mt7996_dfs_pattern { · 36 unmodified lines | |||
| 37 | u32 min_stgpr_diff; | 37 | u32 min_stgpr_diff; |
| 38 | } __packed; | 38 | } __packed; |
| 39 | 39 | ||
| 40 | struct mt7996_dfs_radar_spec { | ||
| 41 | struct mt7996_dfs_pulse pulse_th; | ||
| 42 | struct mt7996_dfs_pattern radar_pattern[16]; | ||
| 43 | }; | ||
| 44 | |||
| 45 | #endif | 40 | #endif |
| @@ -56,7 +56,7 @@ static int mt7996_start(struct ieee80211_hw *hw) · 55 unmodified lines | |||
| 56 | 56 | ||
| 57 | mutex_lock(&dev->mt76.mutex); | 57 | mutex_lock(&dev->mt76.mutex); |
| 58 | ret = mt7996_mcu_set_hdr_trans(dev, true); | 58 | ret = mt7996_mcu_set_hdr_trans(dev, true); |
| 59 | if (!ret && is_mt7992(&dev->mt76)) { | 59 | if (!ret && !is_mt7996(&dev->mt76)) { |
| 60 | u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); | 60 | u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); |
| 61 | 61 | ||
| 62 | ret = mt7996_mcu_cp_support(dev, queue); | 62 | ret = mt7996_mcu_cp_support(dev, queue); |
| @@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy) · 16 unmodified lines | |||
| 79 | 79 | ||
| 80 | mutex_lock(&dev->mt76.mutex); | 80 | mutex_lock(&dev->mt76.mutex); |
| 81 | 81 | ||
| 82 | mt7996_mcu_rdd_resume_tx(phy); | ||
| 82 | mt7996_mcu_set_radio_en(phy, false); | 83 | mt7996_mcu_set_radio_en(phy, false); |
| 83 | 84 | ||
| 84 | clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); | 85 | clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); |
| @@ -238,10 +239,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, · 153 unmodified lines | |||
| 238 | link_conf = &vif->bss_conf; | 239 | link_conf = &vif->bss_conf; |
| 239 | 240 | ||
| 240 | if (cmd == SET_KEY && !sta && !link->mt76.cipher) { | 241 | if (cmd == SET_KEY && !sta && !link->mt76.cipher) { |
| 242 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); | ||
| 243 | |||
| 241 | link->mt76.cipher = | 244 | link->mt76.cipher = |
| 242 | mt76_connac_mcu_get_cipher(key->cipher); | 245 | mt76_connac_mcu_get_cipher(key->cipher); |
| 243 | mt7996_mcu_add_bss_info(link->phy, vif, link_conf, | 246 | if (phy) |
| 244 | &link->mt76, msta_link, true); | 247 | mt7996_mcu_add_bss_info(phy, vif, link_conf, |
| 248 | &link->mt76, msta_link, true); | ||
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | if (cmd == SET_KEY) | 251 | if (cmd == SET_KEY) |
| @@ -300,9 +304,16 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 52 unmodified lines | |||
| 300 | .cmd = SET_KEY, | 304 | .cmd = SET_KEY, |
| 301 | .link_id = link_conf->link_id, | 305 | .link_id = link_conf->link_id, |
| 302 | }; | 306 | }; |
| 303 | struct mt76_txq *mtxq; | ||
| 304 | int mld_idx, idx, ret; | 307 | int mld_idx, idx, ret; |
| 305 | 308 | ||
| 309 | if ((mvif->mt76.valid_links & BIT(link_conf->link_id)) && | ||
| 310 | !mlink->offchannel) { | ||
| 311 | if (vif->type == NL80211_IFTYPE_AP) | ||
| 312 | return mt7996_mcu_mld_link_oper(dev, link_conf, link, | ||
| 313 | true); | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 306 | mlink->idx = __ffs64(~dev->mt76.vif_mask); | 317 | mlink->idx = __ffs64(~dev->mt76.vif_mask); |
| 307 | if (mlink->idx >= mt7996_max_interface_num(dev)) | 318 | if (mlink->idx >= mt7996_max_interface_num(dev)) |
| 308 | return -ENOSPC; | 319 | return -ENOSPC; |
| @@ -316,7 +327,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 7 unmodified lines | |||
| 316 | return -ENOSPC; | 327 | return -ENOSPC; |
| 317 | 328 | ||
| 318 | link->mld_idx = mld_idx; | 329 | link->mld_idx = mld_idx; |
| 319 | link->phy = phy; | ||
| 320 | mlink->omac_idx = idx; | 330 | mlink->omac_idx = idx; |
| 321 | mlink->band_idx = band_idx; | 331 | mlink->band_idx = band_idx; |
| 322 | mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; | 332 | mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; |
| @@ -343,11 +353,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 20 unmodified lines | |||
| 343 | mt7996_mac_wtbl_update(dev, idx, | 353 | mt7996_mac_wtbl_update(dev, idx, |
| 344 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | 354 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 345 | 355 | ||
| 346 | if (vif->txq) { | ||
| 347 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; | ||
| 348 | mtxq->wcid = idx; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (vif->type != NL80211_IFTYPE_AP && | 356 | if (vif->type != NL80211_IFTYPE_AP && |
| 352 | (!mlink->omac_idx || mlink->omac_idx > 3)) | 357 | (!mlink->omac_idx || mlink->omac_idx > 3)) |
| 353 | vif->offload_flags = 0; | 358 | vif->offload_flags = 0; |
| @@ -370,56 +375,66 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 16 unmodified lines | |||
| 370 | 375 | ||
| 371 | ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); | 376 | ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); |
| 372 | 377 | ||
| 373 | if (!mlink->wcid->offchannel && | 378 | if (!mlink->wcid->offchannel) { |
| 374 | mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) | 379 | if (vif->txq && |
| 375 | mvif->mt76.deflink_id = link_conf->link_id; | 380 | mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) { |
| 381 | struct mt76_txq *mtxq; | ||
| 382 | |||
| 383 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; | ||
| 384 | mvif->mt76.deflink_id = link_conf->link_id; | ||
| 385 | mtxq->wcid = idx; | ||
| 386 | } | ||
| 387 | mvif->mt76.valid_links |= BIT(link_conf->link_id); | ||
| 388 | } | ||
| 389 | |||
| 390 | if (vif->type == NL80211_IFTYPE_STATION) { | ||
| 391 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; | ||
| 392 | |||
| 393 | if (vif->cfg.assoc && link_conf->beacon_int) { | ||
| 394 | mlink->beacon_mon_interval = | ||
| 395 | msecs_to_jiffies(ieee80211_tu_to_usec( | ||
| 396 | link_conf->beacon_int) / 1000); | ||
| 397 | WRITE_ONCE(mlink->beacon_mon_last, jiffies); | ||
| 398 | } | ||
| 399 | } | ||
| 376 | 400 | ||
| 377 | return 0; | 401 | return 0; |
| 378 | } | 402 | } |
| 379 | 403 | ||
| 380 | void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, | 404 | static void mt7996_vif_link_destroy(struct mt7996_phy *phy, |
| 381 | struct ieee80211_bss_conf *link_conf, | 405 | struct mt7996_vif_link *link, |
| 382 | struct mt76_vif_link *mlink) | 406 | struct ieee80211_vif *vif, |
| 407 | struct ieee80211_bss_conf *link_conf) | ||
| 383 | { | 408 | { |
| 384 | struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); | ||
| 385 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | 409 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| 386 | struct mt7996_sta_link *msta_link = &link->msta_link; | 410 | struct mt7996_sta_link *msta_link = &link->msta_link; |
| 387 | struct mt7996_phy *phy = mphy->priv; | 411 | unsigned int link_id = msta_link->wcid.link_id; |
| 388 | struct mt7996_dev *dev = phy->dev; | 412 | struct mt76_vif_link *mlink = &link->mt76; |
| 389 | struct mt7996_key_iter_data it = { | 413 | struct mt7996_key_iter_data it = { |
| 390 | .cmd = SET_KEY, | 414 | .cmd = SET_KEY, |
| 391 | .link_id = link_conf->link_id, | 415 | .link_id = link_id, |
| 392 | }; | 416 | }; |
| 417 | struct mt7996_dev *dev = phy->dev; | ||
| 393 | int idx = msta_link->wcid.idx; | 418 | int idx = msta_link->wcid.idx; |
| 394 | 419 | ||
| 420 | if (!link_conf) | ||
| 421 | link_conf = &vif->bss_conf; | ||
| 422 | |||
| 395 | if (!mlink->wcid->offchannel) | 423 | if (!mlink->wcid->offchannel) |
| 396 | ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); | 424 | ieee80211_iter_keys(phy->mt76->hw, vif, mt7996_key_iter, &it); |
| 397 | 425 | ||
| 398 | mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, | 426 | mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, |
| 399 | CONN_STATE_DISCONNECT, false); | 427 | CONN_STATE_DISCONNECT, false); |
| 400 | mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false); | 428 | mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false); |
| 401 | |||
| 402 | mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); | 429 | mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); |
| 403 | 430 | ||
| 404 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); | 431 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); |
| 405 | 432 | ||
| 406 | if (!mlink->wcid->offchannel && | ||
| 407 | mvif->mt76.deflink_id == link_conf->link_id) { | ||
| 408 | struct ieee80211_bss_conf *iter; | ||
| 409 | unsigned int link_id; | ||
| 410 | |||
| 411 | mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; | ||
| 412 | for_each_vif_active_link(vif, iter, link_id) { | ||
| 413 | if (link_id != IEEE80211_LINK_UNSPECIFIED) { | ||
| 414 | mvif->mt76.deflink_id = link_id; | ||
| 415 | break; | ||
| 416 | } | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); | 433 | dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); |
| 421 | dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); | 434 | dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); |
| 422 | phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); | 435 | phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); |
| 436 | if (!mlink->wcid->offchannel) | ||
| 437 | mvif->mt76.valid_links &= ~BIT(link_id); | ||
| 423 | 438 | ||
| 424 | spin_lock_bh(&dev->mt76.sta_poll_lock); | 439 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 425 | if (!list_empty(&msta_link->wcid.poll_list)) | 440 | if (!list_empty(&msta_link->wcid.poll_list)) |
| @@ -427,6 +442,58 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 1 unmodified line | |||
| 427 | spin_unlock_bh(&dev->mt76.sta_poll_lock); | 442 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 428 | 443 | ||
| 429 | mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); | 444 | mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); |
| 445 | |||
| 446 | if (mlink != (struct mt76_vif_link *)vif->drv_priv && | ||
| 447 | !mlink->wcid->offchannel) { | ||
| 448 | rcu_assign_pointer(mlink->mvif->link[link_id], NULL); | ||
| 449 | kfree_rcu(mlink, rcu_head); | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, | ||
| 454 | struct ieee80211_bss_conf *link_conf, | ||
| 455 | struct mt76_vif_link *mlink) | ||
| 456 | { | ||
| 457 | struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); | ||
| 458 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | ||
| 459 | struct mt7996_sta_link *msta_link = &link->msta_link; | ||
| 460 | unsigned int link_id = msta_link->wcid.link_id; | ||
| 461 | struct mt7996_phy *phy = mphy->priv; | ||
| 462 | |||
| 463 | /* Hw requires to destroy active links tearing down the interface, so | ||
| 464 | * postpone it removing the interface. | ||
| 465 | */ | ||
| 466 | if (mlink->wcid->offchannel) { | ||
| 467 | mt7996_vif_link_destroy(phy, link, vif, link_conf); | ||
| 468 | } else { | ||
| 469 | if (vif->type == NL80211_IFTYPE_AP) { | ||
| 470 | mt7996_mcu_mld_reconf_stop_link(phy->dev, vif, | ||
| 471 | BIT(link_id)); | ||
| 472 | mt7996_mcu_mld_link_oper(phy->dev, link_conf, link, | ||
| 473 | false); | ||
| 474 | } | ||
| 475 | |||
| 476 | if (vif->txq && mvif->mt76.deflink_id == link_id) { | ||
| 477 | struct ieee80211_bss_conf *iter; | ||
| 478 | struct mt76_txq *mtxq; | ||
| 479 | |||
| 480 | mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; | ||
| 481 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; | ||
| 482 | /* Primary link will be removed, look for a new one */ | ||
| 483 | for_each_vif_active_link(vif, iter, link_id) { | ||
| 484 | if (link_id == msta_link->wcid.link_id) | ||
| 485 | continue; | ||
| 486 | |||
| 487 | link = mt7996_vif_link(phy->dev, vif, link_id); | ||
| 488 | if (!link) | ||
| 489 | continue; | ||
| 490 | |||
| 491 | mtxq->wcid = link->msta_link.wcid.idx; | ||
| 492 | mvif->mt76.deflink_id = link_id; | ||
| 493 | break; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | } | ||
| 430 | } | 497 | } |
| 431 | 498 | ||
| 432 | static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) | 499 | static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) |
| @@ -472,6 +539,8 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) · 39 unmodified lines | |||
| 472 | 539 | ||
| 473 | mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), | 540 | mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), |
| 474 | MT_DMA_DCR0_RXD_G5_EN, enabled); | 541 | MT_DMA_DCR0_RXD_G5_EN, enabled); |
| 542 | mt76_rmw_field(dev, MT_MDP_DCR0, | ||
| 543 | MT_MDP_DCR0_RX_HDR_TRANS_EN, !enabled); | ||
| 475 | mt7996_phy_set_rxfilter(phy); | 544 | mt7996_phy_set_rxfilter(phy); |
| 476 | mt7996_mcu_set_sniffer_mode(phy, enabled); | 545 | mt7996_mcu_set_sniffer_mode(phy, enabled); |
| 477 | } | 546 | } |
| @@ -530,10 +599,29 @@ static void mt7996_remove_iter(void *data, u8 *mac, struct ieee80211_vif *vif) · 52 unmodified lines | |||
| 530 | static void mt7996_remove_interface(struct ieee80211_hw *hw, | 599 | static void mt7996_remove_interface(struct ieee80211_hw *hw, |
| 531 | struct ieee80211_vif *vif) | 600 | struct ieee80211_vif *vif) |
| 532 | { | 601 | { |
| 602 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | ||
| 603 | unsigned long rem_links = mvif->mt76.valid_links; | ||
| 533 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | 604 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 534 | struct mt7996_radio_data rdata = {}; | 605 | struct mt7996_radio_data rdata = {}; |
| 606 | unsigned int link_id; | ||
| 535 | int i; | 607 | int i; |
| 536 | 608 | ||
| 609 | /* Remove all active links */ | ||
| 610 | for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 611 | struct mt7996_vif_link *link; | ||
| 612 | struct mt7996_phy *phy; | ||
| 613 | |||
| 614 | link = mt7996_vif_link(dev, vif, link_id); | ||
| 615 | if (!link) | ||
| 616 | continue; | ||
| 617 | |||
| 618 | phy = __mt7996_phy(dev, link->msta_link.wcid.phy_idx); | ||
| 619 | if (!phy) | ||
| 620 | continue; | ||
| 621 | |||
| 622 | mt7996_vif_link_destroy(phy, link, vif, NULL); | ||
| 623 | } | ||
| 624 | |||
| 537 | ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, | 625 | ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, |
| 538 | &rdata); | 626 | &rdata); |
| 539 | mt76_vif_cleanup(&dev->mt76, vif); | 627 | mt76_vif_cleanup(&dev->mt76, vif); |
| @@ -811,15 +899,24 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 271 unmodified lines | |||
| 811 | 899 | ||
| 812 | for_each_vif_active_link(vif, link_conf, link_id) { | 900 | for_each_vif_active_link(vif, link_conf, link_id) { |
| 813 | struct mt7996_vif_link *link; | 901 | struct mt7996_vif_link *link; |
| 902 | struct mt7996_phy *phy; | ||
| 814 | 903 | ||
| 815 | link = mt7996_vif_link(dev, vif, link_id); | 904 | link = mt7996_vif_link(dev, vif, link_id); |
| 816 | if (!link) | 905 | if (!link) |
| 817 | continue; | 906 | continue; |
| 818 | 907 | ||
| 819 | if (!link->phy) | 908 | if (vif->type == NL80211_IFTYPE_STATION) { |
| 909 | link->mt76.beacon_mon_interval = | ||
| 910 | msecs_to_jiffies(ieee80211_tu_to_usec( | ||
| 911 | link_conf->beacon_int) / 1000); | ||
| 912 | WRITE_ONCE(link->mt76.beacon_mon_last, jiffies); | ||
| 913 | } | ||
| 914 | |||
| 915 | phy = mt7996_vif_link_phy(link); | ||
| 916 | if (!phy) | ||
| 820 | continue; | 917 | continue; |
| 821 | 918 | ||
| 822 | mt7996_mcu_add_bss_info(link->phy, vif, link_conf, | 919 | mt7996_mcu_add_bss_info(phy, vif, link_conf, |
| 823 | &link->mt76, &link->msta_link, | 920 | &link->mt76, &link->msta_link, |
| 824 | true); | 921 | true); |
| 825 | mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, | 922 | mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, |
| @@ -828,6 +925,20 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 2 unmodified lines | |||
| 828 | } | 925 | } |
| 829 | } | 926 | } |
| 830 | 927 | ||
| 928 | if ((changed & BSS_CHANGED_ASSOC) && !vif->cfg.assoc && | ||
| 929 | vif->type == NL80211_IFTYPE_STATION) { | ||
| 930 | struct ieee80211_bss_conf *link_conf; | ||
| 931 | unsigned long link_id; | ||
| 932 | |||
| 933 | for_each_vif_active_link(vif, link_conf, link_id) { | ||
| 934 | struct mt7996_vif_link *link; | ||
| 935 | |||
| 936 | link = mt7996_vif_link(dev, vif, link_id); | ||
| 937 | if (link) | ||
| 938 | link->mt76.beacon_mon_interval = 0; | ||
| 939 | } | ||
| 940 | } | ||
| 941 | |||
| 831 | mutex_unlock(&dev->mt76.mutex); | 942 | mutex_unlock(&dev->mt76.mutex); |
| 832 | } | 943 | } |
| 833 | 944 | ||
| @@ -864,6 +975,10 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 30 unmodified lines | |||
| 864 | !!(changed & BSS_CHANGED_BSSID)); | 975 | !!(changed & BSS_CHANGED_BSSID)); |
| 865 | } | 976 | } |
| 866 | 977 | ||
| 978 | if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) | ||
| 979 | mt7996_mcu_set_protection(phy, link, info->ht_operation_mode, | ||
| 980 | info->use_cts_prot); | ||
| 981 | |||
| 867 | if (changed & BSS_CHANGED_ERP_SLOT) { | 982 | if (changed & BSS_CHANGED_ERP_SLOT) { |
| 868 | int slottime = info->use_short_slot ? 9 : 20; | 983 | int slottime = info->use_short_slot ? 9 : 20; |
| 869 | 984 | ||
| @@ -927,10 +1042,82 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, · 57 unmodified lines | |||
| 927 | struct cfg80211_chan_def *chandef) | 1042 | struct cfg80211_chan_def *chandef) |
| 928 | { | 1043 | { |
| 929 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | 1044 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 1045 | struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); | ||
| 1046 | struct ieee80211_bss_conf *link_conf; | ||
| 1047 | unsigned int link_id; | ||
| 930 | 1048 | ||
| 931 | mutex_lock(&dev->mt76.mutex); | 1049 | mutex_lock(&dev->mt76.mutex); |
| 932 | mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon); | 1050 | |
| 1051 | for_each_vif_active_link(vif, link_conf, link_id) { | ||
| 1052 | struct mt7996_vif_link *link; | ||
| 1053 | struct mt7996_phy *link_phy; | ||
| 1054 | |||
| 1055 | link = mt7996_vif_link(dev, vif, link_id); | ||
| 1056 | if (!link) | ||
| 1057 | continue; | ||
| 1058 | |||
| 1059 | link_phy = mt7996_vif_link_phy(link); | ||
| 1060 | if (link_phy != phy) | ||
| 1061 | continue; | ||
| 1062 | |||
| 1063 | /* Reset beacon when channel switch triggered during CAC to let | ||
| 1064 | * FW correctly perform CSA countdown | ||
| 1065 | */ | ||
| 1066 | if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef, | ||
| 1067 | vif->type)) | ||
| 1068 | mt7996_mcu_add_beacon(hw, vif, link_conf, false); | ||
| 1069 | |||
| 1070 | mt7996_mcu_add_beacon(hw, vif, link_conf, true); | ||
| 1071 | break; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | mutex_unlock(&dev->mt76.mutex); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | static int | ||
| 1078 | mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
| 1079 | struct ieee80211_bss_conf *link_conf) | ||
| 1080 | { | ||
| 1081 | struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; | ||
| 1082 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | ||
| 1083 | struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); | ||
| 1084 | struct mt7996_vif_link *link; | ||
| 1085 | int ret = -EINVAL; | ||
| 1086 | |||
| 1087 | mutex_lock(&dev->mt76.mutex); | ||
| 1088 | |||
| 1089 | link = mt7996_vif_conf_link(dev, vif, link_conf); | ||
| 1090 | if (!link) | ||
| 1091 | goto out; | ||
| 1092 | |||
| 1093 | ret = mt7996_mcu_update_bss_rfch(phy, link); | ||
| 1094 | if (ret) | ||
| 1095 | goto out; | ||
| 1096 | |||
| 1097 | ieee80211_iterate_stations_mtx(hw, mt7996_mcu_update_sta_rec_bw, link); | ||
| 1098 | |||
| 1099 | ret = mt7996_mcu_rdd_resume_tx(phy); | ||
| 1100 | |||
| 1101 | out: | ||
| 933 | mutex_unlock(&dev->mt76.mutex); | 1102 | mutex_unlock(&dev->mt76.mutex); |
| 1103 | |||
| 1104 | return ret; | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | static void | ||
| 1108 | mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx) | ||
| 1109 | { | ||
| 1110 | int i; | ||
| 1111 | |||
| 1112 | for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { | ||
| 1113 | struct mt76_txq *mtxq; | ||
| 1114 | |||
| 1115 | if (!sta->txq[i]) | ||
| 1116 | continue; | ||
| 1117 | |||
| 1118 | mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; | ||
| 1119 | mtxq->wcid = idx; | ||
| 1120 | } | ||
| 934 | } | 1121 | } |
| 935 | 1122 | ||
| 936 | static int | 1123 | static int |
| @@ -941,30 +1128,22 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, · 4 unmodified lines | |||
| 941 | { | 1128 | { |
| 942 | struct ieee80211_sta *sta = link_sta->sta; | 1129 | struct ieee80211_sta *sta = link_sta->sta; |
| 943 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | 1130 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 944 | struct mt7996_phy *phy = link->phy; | 1131 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); |
| 945 | struct mt7996_sta_link *msta_link; | 1132 | struct mt7996_sta_link *msta_link; |
| 946 | int idx; | 1133 | int idx; |
| 947 | 1134 | ||
| 1135 | if (!phy) | ||
| 1136 | return -EINVAL; | ||
| 1137 | |||
| 948 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); | 1138 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); |
| 949 | if (idx < 0) | 1139 | if (idx < 0) |
| 950 | return -ENOSPC; | 1140 | return -ENOSPC; |
| 951 | 1141 | ||
| 952 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { | 1142 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { |
| 953 | int i; | ||
| 954 | |||
| 955 | msta_link = &msta->deflink; | 1143 | msta_link = &msta->deflink; |
| 956 | msta->deflink_id = link_id; | 1144 | msta->deflink_id = link_id; |
| 957 | msta->seclink_id = msta->deflink_id; | 1145 | msta->seclink_id = msta->deflink_id; |
| 958 | 1146 | mt7996_sta_init_txq_wcid(sta, idx); | |
| 959 | for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { | ||
| 960 | struct mt76_txq *mtxq; | ||
| 961 | |||
| 962 | if (!sta->txq[i]) | ||
| 963 | continue; | ||
| 964 | |||
| 965 | mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; | ||
| 966 | mtxq->wcid = idx; | ||
| 967 | } | ||
| 968 | } else { | 1147 | } else { |
| 969 | msta_link = kzalloc_obj(*msta_link); | 1148 | msta_link = kzalloc_obj(*msta_link); |
| 970 | if (!msta_link) | 1149 | if (!msta_link) |
| @@ -1000,9 +1179,17 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, · 29 unmodified lines | |||
| 1000 | return 0; | 1179 | return 0; |
| 1001 | } | 1180 | } |
| 1002 | 1181 | ||
| 1003 | void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, | 1182 | void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, |
| 1004 | struct mt7996_sta_link *msta_link) | 1183 | struct ieee80211_sta *sta, |
| 1184 | unsigned int link_id, bool flush) | ||
| 1005 | { | 1185 | { |
| 1186 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | ||
| 1187 | struct mt7996_sta_link *msta_link; | ||
| 1188 | |||
| 1189 | msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); | ||
| 1190 | if (!msta_link) | ||
| 1191 | return; | ||
| 1192 | |||
| 1006 | spin_lock_bh(&dev->mt76.sta_poll_lock); | 1193 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 1007 | if (!list_empty(&msta_link->wcid.poll_list)) | 1194 | if (!list_empty(&msta_link->wcid.poll_list)) |
| 1008 | list_del_init(&msta_link->wcid.poll_list); | 1195 | list_del_init(&msta_link->wcid.poll_list); |
| @@ -1011,51 +1198,61 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, · 2 unmodified lines | |||
| 1011 | spin_unlock_bh(&dev->mt76.sta_poll_lock); | 1198 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 1012 | 1199 | ||
| 1013 | mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); | 1200 | mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); |
| 1014 | mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | static void | ||
| 1018 | mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, | ||
| 1019 | struct ieee80211_sta *sta, unsigned long links) | ||
| 1020 | { | ||
| 1021 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | ||
| 1022 | struct mt76_dev *mdev = &dev->mt76; | ||
| 1023 | unsigned int link_id; | ||
| 1024 | 1201 | ||
| 1025 | for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { | 1202 | if (msta_link->wcid.link_valid) { |
| 1026 | struct mt7996_sta_link *msta_link = NULL; | 1203 | struct mt7996_phy *phy; |
| 1027 | struct mt7996_vif_link *link; | ||
| 1028 | struct mt76_phy *mphy; | ||
| 1029 | |||
| 1030 | msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, | ||
| 1031 | lockdep_is_held(&mdev->mutex)); | ||
| 1032 | if (!msta_link) | ||
| 1033 | continue; | ||
| 1034 | 1204 | ||
| 1035 | mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, | 1205 | mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, |
| 1036 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | 1206 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 1037 | 1207 | ||
| 1038 | mt7996_mac_sta_deinit_link(dev, msta_link); | 1208 | phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); |
| 1039 | link = mt7996_vif_link(dev, vif, link_id); | 1209 | if (phy) |
| 1040 | if (!link) | 1210 | phy->mt76->num_sta--; |
| 1041 | continue; | ||
| 1042 | 1211 | ||
| 1043 | mphy = mt76_vif_link_phy(&link->mt76); | ||
| 1044 | if (!mphy) | ||
| 1045 | continue; | ||
| 1046 | |||
| 1047 | mphy->num_sta--; | ||
| 1048 | if (msta->deflink_id == link_id) { | 1212 | if (msta->deflink_id == link_id) { |
| 1049 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; | 1213 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; |
| 1050 | continue; | 1214 | if (msta->seclink_id == link_id) { |
| 1215 | /* no secondary link available */ | ||
| 1216 | msta->seclink_id = msta->deflink_id; | ||
| 1217 | } else { | ||
| 1218 | struct mt7996_sta_link *msta_seclink; | ||
| 1219 | |||
| 1220 | /* switch to the secondary link */ | ||
| 1221 | msta_seclink = mt76_dereference( | ||
| 1222 | msta->link[msta->seclink_id], | ||
| 1223 | &dev->mt76); | ||
| 1224 | if (msta_seclink) { | ||
| 1225 | msta->deflink_id = msta->seclink_id; | ||
| 1226 | mt7996_sta_init_txq_wcid(sta, | ||
| 1227 | msta_seclink->wcid.idx); | ||
| 1228 | } | ||
| 1229 | } | ||
| 1051 | } else if (msta->seclink_id == link_id) { | 1230 | } else if (msta->seclink_id == link_id) { |
| 1052 | msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; | 1231 | msta->seclink_id = msta->deflink_id; |
| 1053 | } | 1232 | } |
| 1233 | msta_link->wcid.link_valid = false; | ||
| 1234 | } | ||
| 1054 | 1235 | ||
| 1055 | kfree_rcu(msta_link, rcu_head); | 1236 | if (flush) { |
| 1237 | rcu_assign_pointer(msta->link[link_id], NULL); | ||
| 1238 | rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL); | ||
| 1239 | mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); | ||
| 1240 | if (msta_link != &msta->deflink) | ||
| 1241 | kfree_rcu(msta_link, rcu_head); | ||
| 1056 | } | 1242 | } |
| 1057 | } | 1243 | } |
| 1058 | 1244 | ||
| 1245 | static void | ||
| 1246 | mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, | ||
| 1247 | struct ieee80211_sta *sta, unsigned long links, | ||
| 1248 | bool flush) | ||
| 1249 | { | ||
| 1250 | unsigned int link_id; | ||
| 1251 | |||
| 1252 | for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) | ||
| 1253 | mt7996_mac_sta_remove_link(dev, sta, link_id, flush); | ||
| 1254 | } | ||
| 1255 | |||
| 1059 | static int | 1256 | static int |
| 1060 | mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, | 1257 | mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 1061 | struct ieee80211_sta *sta, unsigned long new_links) | 1258 | struct ieee80211_sta *sta, unsigned long new_links) |
| @@ -1067,11 +1264,15 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, · 5 unmodified lines | |||
| 1067 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { | 1264 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 1068 | struct ieee80211_bss_conf *link_conf; | 1265 | struct ieee80211_bss_conf *link_conf; |
| 1069 | struct ieee80211_link_sta *link_sta; | 1266 | struct ieee80211_link_sta *link_sta; |
| 1267 | struct mt7996_sta_link *msta_link; | ||
| 1070 | struct mt7996_vif_link *link; | 1268 | struct mt7996_vif_link *link; |
| 1071 | struct mt76_phy *mphy; | 1269 | struct mt76_phy *mphy; |
| 1072 | 1270 | ||
| 1073 | if (rcu_access_pointer(msta->link[link_id])) | 1271 | msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); |
| 1272 | if (msta_link) { | ||
| 1273 | msta_link->wcid.link_valid = true; | ||
| 1074 | continue; | 1274 | continue; |
| 1275 | } | ||
| 1075 | 1276 | ||
| 1076 | link_conf = link_conf_dereference_protected(vif, link_id); | 1277 | link_conf = link_conf_dereference_protected(vif, link_id); |
| 1077 | if (!link_conf) { | 1278 | if (!link_conf) { |
| @@ -1108,7 +1309,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, · 30 unmodified lines | |||
| 1108 | return 0; | 1309 | return 0; |
| 1109 | 1310 | ||
| 1110 | error_unlink: | 1311 | error_unlink: |
| 1111 | mt7996_mac_sta_remove_links(dev, vif, sta, new_links); | 1312 | mt7996_mac_sta_remove_links(dev, vif, sta, new_links, true); |
| 1112 | 1313 | ||
| 1113 | return err; | 1314 | return err; |
| 1114 | } | 1315 | } |
| @@ -1125,7 +1326,7 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 10 unmodified lines | |||
| 1125 | 1326 | ||
| 1126 | mutex_lock(&dev->mt76.mutex); | 1327 | mutex_lock(&dev->mt76.mutex); |
| 1127 | 1328 | ||
| 1128 | mt7996_mac_sta_remove_links(dev, vif, sta, rem); | 1329 | mt7996_mac_sta_remove_links(dev, vif, sta, rem, false); |
| 1129 | ret = mt7996_mac_sta_add_links(dev, vif, sta, add); | 1330 | ret = mt7996_mac_sta_add_links(dev, vif, sta, add); |
| 1130 | 1331 | ||
| 1131 | mutex_unlock(&dev->mt76.mutex); | 1332 | mutex_unlock(&dev->mt76.mutex); |
| @@ -1234,10 +1435,12 @@ static void · 102 unmodified lines | |||
| 1234 | mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, | 1435 | mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 1235 | struct ieee80211_sta *sta) | 1436 | struct ieee80211_sta *sta) |
| 1236 | { | 1437 | { |
| 1237 | unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); | 1438 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 1439 | int i; | ||
| 1238 | 1440 | ||
| 1239 | mutex_lock(&dev->mt76.mutex); | 1441 | mutex_lock(&dev->mt76.mutex); |
| 1240 | mt7996_mac_sta_remove_links(dev, vif, sta, links); | 1442 | for (i = 0; i < ARRAY_SIZE(msta->link); i++) |
| 1443 | mt7996_mac_sta_remove_link(dev, sta, i, true); | ||
| 1241 | mutex_unlock(&dev->mt76.mutex); | 1444 | mutex_unlock(&dev->mt76.mutex); |
| 1242 | } | 1445 | } |
| 1243 | 1446 | ||
| @@ -1489,8 +1692,8 @@ mt7996_get_stats(struct ieee80211_hw *hw, · 245 unmodified lines | |||
| 1489 | 1692 | ||
| 1490 | u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link) | 1693 | u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link) |
| 1491 | { | 1694 | { |
| 1695 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); | ||
| 1492 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | 1696 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 1493 | struct mt7996_phy *phy = link->phy; | ||
| 1494 | union { | 1697 | union { |
| 1495 | u64 t64; | 1698 | u64 t64; |
| 1496 | u32 t32[2]; | 1699 | u32 t32[2]; |
| @@ -1549,7 +1752,7 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 52 unmodified lines | |||
| 1549 | 1752 | ||
| 1550 | n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 | 1753 | n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 |
| 1551 | : link->mt76.omac_idx; | 1754 | : link->mt76.omac_idx; |
| 1552 | phy = link->phy; | 1755 | phy = mt7996_vif_link_phy(link); |
| 1553 | if (!phy) | 1756 | if (!phy) |
| 1554 | goto unlock; | 1757 | goto unlock; |
| 1555 | 1758 | ||
| @@ -1583,7 +1786,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 27 unmodified lines | |||
| 1583 | if (!link) | 1786 | if (!link) |
| 1584 | goto unlock; | 1787 | goto unlock; |
| 1585 | 1788 | ||
| 1586 | phy = link->phy; | 1789 | phy = mt7996_vif_link_phy(link); |
| 1587 | if (!phy) | 1790 | if (!phy) |
| 1588 | goto unlock; | 1791 | goto unlock; |
| 1589 | 1792 | ||
| @@ -1713,9 +1916,14 @@ static void mt7996_link_rate_ctrl_update(void *data, · 123 unmodified lines | |||
| 1713 | struct mt7996_sta_link *msta_link) | 1916 | struct mt7996_sta_link *msta_link) |
| 1714 | { | 1917 | { |
| 1715 | struct mt7996_sta *msta = msta_link->sta; | 1918 | struct mt7996_sta *msta = msta_link->sta; |
| 1716 | struct mt7996_dev *dev = msta->vif->deflink.phy->dev; | 1919 | struct mt7996_phy *phy = mt7996_vif_link_phy(&msta->vif->deflink); |
| 1920 | struct mt7996_dev *dev; | ||
| 1717 | u32 *changed = data; | 1921 | u32 *changed = data; |
| 1718 | 1922 | ||
| 1923 | if (!phy) | ||
| 1924 | return; | ||
| 1925 | |||
| 1926 | dev = phy->dev; | ||
| 1719 | spin_lock_bh(&dev->mt76.sta_poll_lock); | 1927 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 1720 | 1928 | ||
| 1721 | msta_link->changed |= *changed; | 1929 | msta_link->changed |= *changed; |
| @@ -2204,6 +2412,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, · 482 unmodified lines | |||
| 2204 | path->mtk_wdma.wdma_idx = wed->wdma_idx; | 2412 | path->mtk_wdma.wdma_idx = wed->wdma_idx; |
| 2205 | else | 2413 | else |
| 2206 | #endif | 2414 | #endif |
| 2415 | if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76) && | ||
| 2416 | msta_link->wcid.phy_idx == MT_BAND2) | ||
| 2417 | path->mtk_wdma.wdma_idx = 1; | ||
| 2418 | else | ||
| 2207 | path->mtk_wdma.wdma_idx = link->mt76.band_idx; | 2419 | path->mtk_wdma.wdma_idx = link->mt76.band_idx; |
| 2208 | path->mtk_wdma.bss = link->mt76.idx; | 2420 | path->mtk_wdma.bss = link->mt76.idx; |
| 2209 | path->mtk_wdma.queue = 0; | 2421 | path->mtk_wdma.queue = 0; |
| @@ -2275,6 +2487,21 @@ mt7996_reconfig_complete(struct ieee80211_hw *hw, · 65 unmodified lines | |||
| 2275 | MT7996_WATCHDOG_TIME); | 2487 | MT7996_WATCHDOG_TIME); |
| 2276 | } | 2488 | } |
| 2277 | 2489 | ||
| 2490 | static int | ||
| 2491 | mt7996_set_eml_op_mode(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
| 2492 | struct ieee80211_sta *sta, | ||
| 2493 | struct ieee80211_eml_params *eml_params) | ||
| 2494 | { | ||
| 2495 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | ||
| 2496 | int ret; | ||
| 2497 | |||
| 2498 | mutex_lock(&dev->mt76.mutex); | ||
| 2499 | ret = mt7996_mcu_set_emlsr_mode(dev, vif, sta, eml_params); | ||
| 2500 | mutex_unlock(&dev->mt76.mutex); | ||
| 2501 | |||
| 2502 | return ret; | ||
| 2503 | } | ||
| 2504 | |||
| 2278 | const struct ieee80211_ops mt7996_ops = { | 2505 | const struct ieee80211_ops mt7996_ops = { |
| 2279 | .add_chanctx = mt76_add_chanctx, | 2506 | .add_chanctx = mt76_add_chanctx, |
| 2280 | .remove_chanctx = mt76_remove_chanctx, | 2507 | .remove_chanctx = mt76_remove_chanctx, |
| @@ -2306,6 +2533,7 @@ const struct ieee80211_ops mt7996_ops = { · 25 unmodified lines | |||
| 2306 | .release_buffered_frames = mt76_release_buffered_frames, | 2533 | .release_buffered_frames = mt76_release_buffered_frames, |
| 2307 | .get_txpower = mt7996_get_txpower, | 2534 | .get_txpower = mt7996_get_txpower, |
| 2308 | .channel_switch_beacon = mt7996_channel_switch_beacon, | 2535 | .channel_switch_beacon = mt7996_channel_switch_beacon, |
| 2536 | .post_channel_switch = mt7996_post_channel_switch, | ||
| 2309 | .get_stats = mt7996_get_stats, | 2537 | .get_stats = mt7996_get_stats, |
| 2310 | .get_et_sset_count = mt7996_get_et_sset_count, | 2538 | .get_et_sset_count = mt7996_get_et_sset_count, |
| 2311 | .get_et_stats = mt7996_get_et_stats, | 2539 | .get_et_stats = mt7996_get_et_stats, |
| @@ -2337,4 +2565,5 @@ const struct ieee80211_ops mt7996_ops = { · 25 unmodified lines | |||
| 2337 | .change_vif_links = mt7996_change_vif_links, | 2565 | .change_vif_links = mt7996_change_vif_links, |
| 2338 | .change_sta_links = mt7996_mac_sta_change_links, | 2566 | .change_sta_links = mt7996_mac_sta_change_links, |
| 2339 | .reconfig_complete = mt7996_reconfig_complete, | 2567 | .reconfig_complete = mt7996_reconfig_complete, |
| 2568 | .set_eml_op_mode = mt7996_set_eml_op_mode, | ||
| 2340 | }; | 2569 | }; |
| @@ -18,6 +18,9 @@ · 17 unmodified lines | |||
| 18 | case MT7992_VAR_TYPE_23: \ | 18 | case MT7992_VAR_TYPE_23: \ |
| 19 | _fw = MT7992_##name##_23; \ | 19 | _fw = MT7992_##name##_23; \ |
| 20 | break; \ | 20 | break; \ |
| 21 | case MT7992_VAR_TYPE_24: \ | ||
| 22 | _fw = MT7992_##name##_24; \ | ||
| 23 | break; \ | ||
| 21 | default: \ | 24 | default: \ |
| 22 | _fw = MT7992_##name; \ | 25 | _fw = MT7992_##name; \ |
| 23 | } \ | 26 | } \ |
| @@ -125,9 +128,16 @@ mt7996_mcu_set_sta_he_mcs(struct ieee80211_link_sta *link_sta, · 101 unmodified lines | |||
| 125 | struct mt7996_vif_link *link, | 128 | struct mt7996_vif_link *link, |
| 126 | __le16 *he_mcs, u16 mcs_map) | 129 | __le16 *he_mcs, u16 mcs_map) |
| 127 | { | 130 | { |
| 131 | struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); | ||
| 128 | int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss; | 132 | int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss; |
| 129 | enum nl80211_band band = link->phy->mt76->chandef.chan->band; | 133 | enum nl80211_band band; |
| 130 | const u16 *mask = link->bitrate_mask.control[band].he_mcs; | 134 | const u16 *mask; |
| 135 | |||
| 136 | if (!mphy) | ||
| 137 | return; | ||
| 138 | |||
| 139 | band = mphy->chandef.chan->band; | ||
| 140 | mask = link->bitrate_mask.control[band].he_mcs; | ||
| 131 | 141 | ||
| 132 | for (nss = 0; nss < max_nss; nss++) { | 142 | for (nss = 0; nss < max_nss; nss++) { |
| 133 | int mcs; | 143 | int mcs; |
| @@ -209,6 +219,7 @@ static int · 75 unmodified lines | |||
| 209 | mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, | 219 | mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, |
| 210 | struct sk_buff *skb, int seq) | 220 | struct sk_buff *skb, int seq) |
| 211 | { | 221 | { |
| 222 | struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); | ||
| 212 | struct mt7996_mcu_rxd *rxd; | 223 | struct mt7996_mcu_rxd *rxd; |
| 213 | struct mt7996_mcu_uni_event *event; | 224 | struct mt7996_mcu_uni_event *event; |
| 214 | int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); | 225 | int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); |
| @@ -217,6 +228,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, · 2 unmodified lines | |||
| 217 | if (!skb) { | 228 | if (!skb) { |
| 218 | dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", | 229 | dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", |
| 219 | cmd, seq); | 230 | cmd, seq); |
| 231 | |||
| 232 | if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { | ||
| 233 | dev->recovery.restart = true; | ||
| 234 | wake_up(&dev->mt76.mcu.wait); | ||
| 235 | queue_work(dev->mt76.wq, &dev->reset_work); | ||
| 236 | wake_up(&dev->reset_wait); | ||
| 237 | } | ||
| 238 | |||
| 220 | return -ETIMEDOUT; | 239 | return -ETIMEDOUT; |
| 221 | } | 240 | } |
| 222 | 241 | ||
| @@ -233,7 +252,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, · 10 unmodified lines | |||
| 233 | event = (struct mt7996_mcu_uni_event *)skb->data; | 252 | event = (struct mt7996_mcu_uni_event *)skb->data; |
| 234 | ret = le32_to_cpu(event->status); | 253 | ret = le32_to_cpu(event->status); |
| 235 | /* skip invalid event */ | 254 | /* skip invalid event */ |
| 236 | if (mcu_cmd != event->cid) | 255 | if (mcu_cmd != le16_to_cpu(event->cid)) |
| 237 | ret = -EAGAIN; | 256 | ret = -EAGAIN; |
| 238 | } else { | 257 | } else { |
| 239 | skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); | 258 | skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); |
| @@ -259,7 +278,8 @@ mt7996_mcu_set_timeout(struct mt76_dev *mdev, int cmd) · 19 unmodified lines | |||
| 259 | mdev->mcu.timeout = 2 * HZ; | 278 | mdev->mcu.timeout = 2 * HZ; |
| 260 | return; | 279 | return; |
| 261 | case MCU_UNI_CMD_EFUSE_CTRL: | 280 | case MCU_UNI_CMD_EFUSE_CTRL: |
| 262 | mdev->mcu.timeout = 20 * HZ; | 281 | case MCU_UNI_CMD_EXT_EEPROM_CTRL: |
| 282 | mdev->mcu.timeout = 30 * HZ; | ||
| 263 | return; | 283 | return; |
| 264 | default: | 284 | default: |
| 265 | break; | 285 | break; |
| @@ -313,13 +333,12 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, · 47 unmodified lines | |||
| 313 | uni_txd->pkt_type = MCU_PKT_ID; | 333 | uni_txd->pkt_type = MCU_PKT_ID; |
| 314 | uni_txd->seq = seq; | 334 | uni_txd->seq = seq; |
| 315 | 335 | ||
| 316 | if (cmd & __MCU_CMD_FIELD_QUERY) | 336 | uni_txd->option = MCU_CMD_UNI; |
| 317 | uni_txd->option = MCU_CMD_UNI_QUERY_ACK; | 337 | if (!(cmd & __MCU_CMD_FIELD_QUERY)) |
| 318 | else | 338 | uni_txd->option |= MCU_CMD_SET; |
| 319 | uni_txd->option = MCU_CMD_UNI_EXT_ACK; | ||
| 320 | 339 | ||
| 321 | if (mcu_cmd == MCU_UNI_CMD_SDO) | 340 | if (wait_seq) |
| 322 | uni_txd->option &= ~MCU_CMD_ACK; | 341 | uni_txd->option |= MCU_CMD_ACK; |
| 323 | 342 | ||
| 324 | if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) | 343 | if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) |
| 325 | uni_txd->s2d_index = MCU_S2D_H2CN; | 344 | uni_txd->s2d_index = MCU_S2D_H2CN; |
| @@ -390,13 +409,117 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) · 64 unmodified lines | |||
| 390 | sizeof(req), false); | 409 | sizeof(req), false); |
| 391 | } | 410 | } |
| 392 | 411 | ||
| 412 | struct mt7996_mcu_countdown_data { | ||
| 413 | struct mt76_phy *mphy; | ||
| 414 | u8 omac_idx; | ||
| 415 | }; | ||
| 416 | |||
| 393 | static void | 417 | static void |
| 394 | mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) | 418 | mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) |
| 395 | { | 419 | { |
| 396 | if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) | 420 | struct mt7996_mcu_countdown_data *cdata = (void *)priv; |
| 421 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | ||
| 422 | struct ieee80211_bss_conf *link_conf = NULL; | ||
| 423 | unsigned long valid_links = vif->valid_links ?: BIT(0); | ||
| 424 | unsigned int link_id; | ||
| 425 | |||
| 426 | if (vif->type == NL80211_IFTYPE_STATION) | ||
| 427 | return; | ||
| 428 | |||
| 429 | for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 430 | struct mt76_vif_link *mlink = | ||
| 431 | rcu_dereference(mvif->mt76.link[link_id]); | ||
| 432 | |||
| 433 | if (mlink && mlink->band_idx == cdata->mphy->band_idx && | ||
| 434 | mlink->omac_idx == cdata->omac_idx) { | ||
| 435 | link_conf = rcu_dereference(vif->link_conf[link_id]); | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | if (!link_conf || !link_conf->csa_active) | ||
| 441 | return; | ||
| 442 | |||
| 443 | ieee80211_csa_finish(vif, link_conf->link_id); | ||
| 444 | } | ||
| 445 | |||
| 446 | static void | ||
| 447 | mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) | ||
| 448 | { | ||
| 449 | struct mt7996_mcu_countdown_data *cdata = (void *)priv; | ||
| 450 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | ||
| 451 | struct ieee80211_bss_conf *link_conf = NULL; | ||
| 452 | unsigned long valid_links = vif->valid_links ?: BIT(0); | ||
| 453 | unsigned int link_id; | ||
| 454 | |||
| 455 | if (vif->type == NL80211_IFTYPE_STATION) | ||
| 456 | return; | ||
| 457 | |||
| 458 | for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 459 | struct mt76_vif_link *mlink = | ||
| 460 | rcu_dereference(mvif->mt76.link[link_id]); | ||
| 461 | |||
| 462 | if (mlink && mlink->band_idx == cdata->mphy->band_idx && | ||
| 463 | mlink->omac_idx == cdata->omac_idx) { | ||
| 464 | link_conf = rcu_dereference(vif->link_conf[link_id]); | ||
| 465 | break; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | if (!link_conf || !link_conf->color_change_active) | ||
| 470 | return; | ||
| 471 | |||
| 472 | ieee80211_color_change_finish(vif, link_conf->link_id); | ||
| 473 | } | ||
| 474 | |||
| 475 | static void | ||
| 476 | mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) | ||
| 477 | { | ||
| 478 | #define UNI_EVENT_IE_COUNTDOWN_CSA 0 | ||
| 479 | #define UNI_EVENT_IE_COUNTDOWN_BCC 1 | ||
| 480 | struct header { | ||
| 481 | u8 band; | ||
| 482 | u8 rsv[3]; | ||
| 483 | }; | ||
| 484 | struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; | ||
| 485 | const char *data = (char *)&rxd[1], *tail; | ||
| 486 | struct header *hdr = (struct header *)data; | ||
| 487 | struct tlv *tlv = (struct tlv *)(data + 4); | ||
| 488 | struct mt7996_mcu_countdown_notify *event; | ||
| 489 | struct mt7996_mcu_countdown_data cdata; | ||
| 490 | |||
| 491 | if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) | ||
| 397 | return; | 492 | return; |
| 398 | 493 | ||
| 399 | ieee80211_csa_finish(vif, 0); | 494 | cdata.mphy = dev->mt76.phys[hdr->band]; |
| 495 | if (!cdata.mphy) | ||
| 496 | return; | ||
| 497 | |||
| 498 | tail = skb->data + skb->len; | ||
| 499 | data += sizeof(*hdr); | ||
| 500 | while (data + sizeof(*tlv) < tail && le16_to_cpu(tlv->len)) { | ||
| 501 | event = (struct mt7996_mcu_countdown_notify *)tlv->data; | ||
| 502 | |||
| 503 | cdata.omac_idx = event->omac_idx; | ||
| 504 | |||
| 505 | switch (le16_to_cpu(tlv->tag)) { | ||
| 506 | case UNI_EVENT_IE_COUNTDOWN_CSA: | ||
| 507 | ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), | ||
| 508 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 509 | mt7996_mcu_csa_finish, &cdata); | ||
| 510 | break; | ||
| 511 | case UNI_EVENT_IE_COUNTDOWN_BCC: | ||
| 512 | ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), | ||
| 513 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 514 | mt7996_mcu_cca_finish, &cdata); | ||
| 515 | break; | ||
| 516 | default: | ||
| 517 | break; | ||
| 518 | } | ||
| 519 | |||
| 520 | data += le16_to_cpu(tlv->len); | ||
| 521 | tlv = (struct tlv *)data; | ||
| 522 | } | ||
| 400 | } | 523 | } |
| 401 | 524 | ||
| 402 | static void | 525 | static void |
| @@ -416,24 +539,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) · 13 unmodified lines | |||
| 416 | break; | 539 | break; |
| 417 | case MT_RDD_IDX_BACKGROUND: | 540 | case MT_RDD_IDX_BACKGROUND: |
| 418 | if (!dev->rdd2_phy) | 541 | if (!dev->rdd2_phy) |
| 419 | return; | 542 | goto err; |
| 420 | mphy = dev->rdd2_phy->mt76; | 543 | mphy = dev->rdd2_phy->mt76; |
| 421 | break; | 544 | break; |
| 422 | default: | 545 | default: |
| 423 | dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); | 546 | goto err; |
| 424 | return; | ||
| 425 | } | 547 | } |
| 426 | 548 | ||
| 427 | if (!mphy) | 549 | if (!mphy) |
| 428 | return; | 550 | goto err; |
| 429 | 551 | ||
| 430 | if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) | 552 | if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) { |
| 431 | cfg80211_background_radar_event(mphy->hw->wiphy, | 553 | cfg80211_background_radar_event(mphy->hw->wiphy, |
| 432 | &dev->rdd2_chandef, | 554 | &dev->rdd2_chandef, |
| 433 | GFP_ATOMIC); | 555 | GFP_ATOMIC); |
| 434 | else | 556 | } else { |
| 557 | struct mt7996_phy *phy = mphy->priv; | ||
| 558 | |||
| 559 | phy->rdd_tx_paused = true; | ||
| 435 | ieee80211_radar_detected(mphy->hw, NULL); | 560 | ieee80211_radar_detected(mphy->hw, NULL); |
| 561 | } | ||
| 436 | dev->hw_pattern++; | 562 | dev->hw_pattern++; |
| 563 | |||
| 564 | return; | ||
| 565 | |||
| 566 | err: | ||
| 567 | dev_err(dev->mt76.dev, "Invalid RDD idx %d\n", r->rdd_idx); | ||
| 437 | } | 568 | } |
| 438 | 569 | ||
| 439 | static void | 570 | static void |
| @@ -476,57 +607,6 @@ out: · 36 unmodified lines | |||
| 476 | wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); | 607 | wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); |
| 477 | } | 608 | } |
| 478 | 609 | ||
| 479 | static void | ||
| 480 | mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) | ||
| 481 | { | ||
| 482 | if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) | ||
| 483 | return; | ||
| 484 | |||
| 485 | ieee80211_color_change_finish(vif, 0); | ||
| 486 | } | ||
| 487 | |||
| 488 | static void | ||
| 489 | mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) | ||
| 490 | { | ||
| 491 | #define UNI_EVENT_IE_COUNTDOWN_CSA 0 | ||
| 492 | #define UNI_EVENT_IE_COUNTDOWN_BCC 1 | ||
| 493 | struct header { | ||
| 494 | u8 band; | ||
| 495 | u8 rsv[3]; | ||
| 496 | }; | ||
| 497 | struct mt76_phy *mphy = &dev->mt76.phy; | ||
| 498 | struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; | ||
| 499 | const char *data = (char *)&rxd[1], *tail; | ||
| 500 | struct header *hdr = (struct header *)data; | ||
| 501 | struct tlv *tlv = (struct tlv *)(data + 4); | ||
| 502 | |||
| 503 | if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) | ||
| 504 | return; | ||
| 505 | |||
| 506 | if (hdr->band && dev->mt76.phys[hdr->band]) | ||
| 507 | mphy = dev->mt76.phys[hdr->band]; | ||
| 508 | |||
| 509 | tail = skb->data + skb->len; | ||
| 510 | data += sizeof(struct header); | ||
| 511 | while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) { | ||
| 512 | switch (le16_to_cpu(tlv->tag)) { | ||
| 513 | case UNI_EVENT_IE_COUNTDOWN_CSA: | ||
| 514 | ieee80211_iterate_active_interfaces_atomic(mphy->hw, | ||
| 515 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 516 | mt7996_mcu_csa_finish, mphy->hw); | ||
| 517 | break; | ||
| 518 | case UNI_EVENT_IE_COUNTDOWN_BCC: | ||
| 519 | ieee80211_iterate_active_interfaces_atomic(mphy->hw, | ||
| 520 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
| 521 | mt7996_mcu_cca_finish, mphy->hw); | ||
| 522 | break; | ||
| 523 | } | ||
| 524 | |||
| 525 | data += le16_to_cpu(tlv->len); | ||
| 526 | tlv = (struct tlv *)data; | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | static int | 610 | static int |
| 531 | mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) | 611 | mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) |
| 532 | { | 612 | { |
| @@ -1170,6 +1250,123 @@ out: · 637 unmodified lines | |||
| 1170 | MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); | 1250 | MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); |
| 1171 | } | 1251 | } |
| 1172 | 1252 | ||
| 1253 | int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy, struct mt7996_vif_link *link) | ||
| 1254 | { | ||
| 1255 | struct mt7996_dev *dev = phy->dev; | ||
| 1256 | struct sk_buff *skb; | ||
| 1257 | |||
| 1258 | skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, | ||
| 1259 | MT7996_BSS_UPDATE_MAX_SIZE); | ||
| 1260 | if (IS_ERR(skb)) | ||
| 1261 | return PTR_ERR(skb); | ||
| 1262 | |||
| 1263 | mt7996_mcu_bss_rfch_tlv(skb, phy); | ||
| 1264 | |||
| 1265 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 1266 | MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link, | ||
| 1270 | u8 ht_mode, bool use_cts_prot) | ||
| 1271 | { | ||
| 1272 | struct mt7996_dev *dev = phy->dev; | ||
| 1273 | struct bss_prot_tlv *prot; | ||
| 1274 | struct sk_buff *skb; | ||
| 1275 | struct tlv *tlv; | ||
| 1276 | enum { | ||
| 1277 | PROT_NONMEMBER = BIT(1), | ||
| 1278 | PROT_20MHZ = BIT(2), | ||
| 1279 | PROT_NONHT_MIXED = BIT(3), | ||
| 1280 | PROT_LEGACY_ERP = BIT(5), | ||
| 1281 | PROT_NONGF_STA = BIT(7), | ||
| 1282 | }; | ||
| 1283 | |||
| 1284 | skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, | ||
| 1285 | MT7996_BSS_UPDATE_MAX_SIZE); | ||
| 1286 | if (IS_ERR(skb)) | ||
| 1287 | return PTR_ERR(skb); | ||
| 1288 | |||
| 1289 | tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PROTECT_INFO, | ||
| 1290 | sizeof(*prot)); | ||
| 1291 | prot = (struct bss_prot_tlv *)tlv; | ||
| 1292 | |||
| 1293 | switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { | ||
| 1294 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | ||
| 1295 | prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); | ||
| 1296 | break; | ||
| 1297 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | ||
| 1298 | prot->prot_mode = cpu_to_le32(PROT_20MHZ); | ||
| 1299 | break; | ||
| 1300 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | ||
| 1301 | prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); | ||
| 1302 | break; | ||
| 1303 | } | ||
| 1304 | |||
| 1305 | if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) | ||
| 1306 | prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); | ||
| 1307 | |||
| 1308 | if (use_cts_prot) | ||
| 1309 | prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); | ||
| 1310 | |||
| 1311 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 1312 | MCU_WM_UNI_CMD(BSS_INFO_UPDATE), true); | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | int mt7996_mcu_set_emlsr_mode(struct mt7996_dev *dev, | ||
| 1316 | struct ieee80211_vif *vif, | ||
| 1317 | struct ieee80211_sta *sta, | ||
| 1318 | struct ieee80211_eml_params *eml_params) | ||
| 1319 | { | ||
| 1320 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | ||
| 1321 | struct mt7996_sta_link *msta_link; | ||
| 1322 | struct sta_rec_eml_op *eml_op; | ||
| 1323 | struct mt7996_vif_link *link; | ||
| 1324 | struct sk_buff *skb; | ||
| 1325 | struct tlv *tlv; | ||
| 1326 | |||
| 1327 | msta_link = mt76_dereference(msta->link[eml_params->link_id], | ||
| 1328 | &dev->mt76); | ||
| 1329 | if (!msta_link) | ||
| 1330 | return -EINVAL; | ||
| 1331 | |||
| 1332 | link = mt7996_vif_link(dev, vif, eml_params->link_id); | ||
| 1333 | if (!link) | ||
| 1334 | return -EINVAL; | ||
| 1335 | |||
| 1336 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, | ||
| 1337 | &msta_link->wcid, | ||
| 1338 | MT7996_STA_UPDATE_MAX_SIZE); | ||
| 1339 | if (IS_ERR(skb)) | ||
| 1340 | return PTR_ERR(skb); | ||
| 1341 | |||
| 1342 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EML_OP, sizeof(*eml_op)); | ||
| 1343 | eml_op = (struct sta_rec_eml_op *)tlv; | ||
| 1344 | eml_op->link_bitmap = 0; | ||
| 1345 | |||
| 1346 | if (eml_params->control & IEEE80211_EML_CTRL_EMLSR_MODE) { | ||
| 1347 | unsigned long link_bitmap = eml_params->link_bitmap; | ||
| 1348 | unsigned int link_id; | ||
| 1349 | |||
| 1350 | for_each_set_bit(link_id, &link_bitmap, | ||
| 1351 | IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 1352 | struct mt76_phy *mphy; | ||
| 1353 | |||
| 1354 | link = mt7996_vif_link(dev, vif, link_id); | ||
| 1355 | if (!link) | ||
| 1356 | continue; | ||
| 1357 | |||
| 1358 | mphy = mt76_vif_link_phy(&link->mt76); | ||
| 1359 | if (!mphy) | ||
| 1360 | continue; | ||
| 1361 | |||
| 1362 | eml_op->link_bitmap |= BIT(mphy->band_idx); | ||
| 1363 | } | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 1367 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); | ||
| 1368 | } | ||
| 1369 | |||
| 1173 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, | 1370 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, |
| 1174 | struct ieee80211_bss_conf *link_conf) | 1371 | struct ieee80211_bss_conf *link_conf) |
| 1175 | { | 1372 | { |
| @@ -1779,9 +1976,8 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, · 603 unmodified lines | |||
| 1779 | #define EBF_MODE BIT(0) | 1976 | #define EBF_MODE BIT(0) |
| 1780 | #define IBF_MODE BIT(1) | 1977 | #define IBF_MODE BIT(1) |
| 1781 | #define BF_MAT_ORDER 4 | 1978 | #define BF_MAT_ORDER 4 |
| 1979 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); | ||
| 1782 | struct ieee80211_vif *vif = link_conf->vif; | 1980 | struct ieee80211_vif *vif = link_conf->vif; |
| 1783 | struct mt7996_phy *phy = link->phy; | ||
| 1784 | int tx_ant = hweight16(phy->mt76->chainmask) - 1; | ||
| 1785 | struct sta_rec_bf *bf; | 1981 | struct sta_rec_bf *bf; |
| 1786 | struct tlv *tlv; | 1982 | struct tlv *tlv; |
| 1787 | static const u8 matrix[BF_MAT_ORDER][BF_MAT_ORDER] = { | 1983 | static const u8 matrix[BF_MAT_ORDER][BF_MAT_ORDER] = { |
| @@ -1790,8 +1986,12 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, · 2 unmodified lines | |||
| 1790 | {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ | 1986 | {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ |
| 1791 | {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ | 1987 | {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ |
| 1792 | }; | 1988 | }; |
| 1989 | int tx_ant; | ||
| 1793 | bool ebf; | 1990 | bool ebf; |
| 1794 | 1991 | ||
| 1992 | if (!phy) | ||
| 1993 | return; | ||
| 1994 | |||
| 1795 | if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) | 1995 | if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) |
| 1796 | return; | 1996 | return; |
| 1797 | 1997 | ||
| @@ -1807,17 +2007,18 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, · 9 unmodified lines | |||
| 1807 | * ht: iBF only, since mac80211 lacks of eBF support | 2007 | * ht: iBF only, since mac80211 lacks of eBF support |
| 1808 | */ | 2008 | */ |
| 1809 | if (link_sta->eht_cap.has_eht) | 2009 | if (link_sta->eht_cap.has_eht) |
| 1810 | mt7996_mcu_sta_bfer_eht(link_sta, vif, link->phy, bf, ebf); | 2010 | mt7996_mcu_sta_bfer_eht(link_sta, vif, phy, bf, ebf); |
| 1811 | else if (link_sta->he_cap.has_he) | 2011 | else if (link_sta->he_cap.has_he) |
| 1812 | mt7996_mcu_sta_bfer_he(link_sta, vif, link->phy, bf, ebf); | 2012 | mt7996_mcu_sta_bfer_he(link_sta, vif, phy, bf, ebf); |
| 1813 | else if (link_sta->vht_cap.vht_supported) | 2013 | else if (link_sta->vht_cap.vht_supported) |
| 1814 | mt7996_mcu_sta_bfer_vht(link_sta, link->phy, bf, ebf); | 2014 | mt7996_mcu_sta_bfer_vht(link_sta, phy, bf, ebf); |
| 1815 | else if (link_sta->ht_cap.ht_supported) | 2015 | else if (link_sta->ht_cap.ht_supported) |
| 1816 | mt7996_mcu_sta_bfer_ht(link_sta, link->phy, bf, ebf); | 2016 | mt7996_mcu_sta_bfer_ht(link_sta, phy, bf, ebf); |
| 1817 | else | 2017 | else |
| 1818 | return; | 2018 | return; |
| 1819 | 2019 | ||
| 1820 | bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0); | 2020 | bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0); |
| 2021 | tx_ant = hweight16(phy->mt76->chainmask) - 1; | ||
| 1821 | if (is_mt7992(&dev->mt76) && tx_ant == 4) | 2022 | if (is_mt7992(&dev->mt76) && tx_ant == 4) |
| 1822 | bf->bf_cap |= IBF_MODE; | 2023 | bf->bf_cap |= IBF_MODE; |
| 1823 | 2024 | ||
| @@ -1849,11 +2050,14 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, · 25 unmodified lines | |||
| 1849 | struct ieee80211_link_sta *link_sta, | 2050 | struct ieee80211_link_sta *link_sta, |
| 1850 | struct mt7996_vif_link *link) | 2051 | struct mt7996_vif_link *link) |
| 1851 | { | 2052 | { |
| 1852 | struct mt7996_phy *phy = link->phy; | 2053 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); |
| 1853 | int tx_ant = hweight8(phy->mt76->antenna_mask) - 1; | ||
| 1854 | struct sta_rec_bfee *bfee; | 2054 | struct sta_rec_bfee *bfee; |
| 1855 | struct tlv *tlv; | 2055 | struct tlv *tlv; |
| 1856 | u8 nrow = 0; | 2056 | u8 nrow = 0; |
| 2057 | int tx_ant; | ||
| 2058 | |||
| 2059 | if (!phy) | ||
| 2060 | return; | ||
| 1857 | 2061 | ||
| 1858 | if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he)) | 2062 | if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he)) |
| 1859 | return; | 2063 | return; |
| @@ -1877,6 +2081,7 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, · 17 unmodified lines | |||
| 1877 | } | 2081 | } |
| 1878 | 2082 | ||
| 1879 | /* reply with identity matrix to avoid 2x2 BF negative gain */ | 2083 | /* reply with identity matrix to avoid 2x2 BF negative gain */ |
| 2084 | tx_ant = hweight8(phy->mt76->antenna_mask) - 1; | ||
| 1880 | bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); | 2085 | bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); |
| 1881 | } | 2086 | } |
| 1882 | 2087 | ||
| @@ -2060,6 +2265,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta, · 177 unmodified lines | |||
| 2060 | struct ieee80211_sta *sta; | 2265 | struct ieee80211_sta *sta; |
| 2061 | int ret, nrates = 0, idx; | 2266 | int ret, nrates = 0, idx; |
| 2062 | enum nl80211_band band; | 2267 | enum nl80211_band band; |
| 2268 | struct mt76_phy *mphy; | ||
| 2063 | bool has_he; | 2269 | bool has_he; |
| 2064 | 2270 | ||
| 2065 | #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ | 2271 | #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ |
| @@ -2093,7 +2299,11 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta, · 27 unmodified lines | |||
| 2093 | if (!link_sta) | 2299 | if (!link_sta) |
| 2094 | goto error_unlock; | 2300 | goto error_unlock; |
| 2095 | 2301 | ||
| 2096 | band = link->phy->mt76->chandef.chan->band; | 2302 | mphy = mt76_vif_link_phy(&link->mt76); |
| 2303 | if (!mphy) | ||
| 2304 | goto error_unlock; | ||
| 2305 | |||
| 2306 | band = mphy->chandef.chan->band; | ||
| 2097 | has_he = link_sta->he_cap.has_he; | 2307 | has_he = link_sta->he_cap.has_he; |
| 2098 | mask = link->bitrate_mask; | 2308 | mask = link->bitrate_mask; |
| 2099 | idx = msta_link->wcid.idx; | 2309 | idx = msta_link->wcid.idx; |
| @@ -2173,18 +2383,25 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, · 73 unmodified lines | |||
| 2173 | struct mt7996_vif_link *link) | 2383 | struct mt7996_vif_link *link) |
| 2174 | { | 2384 | { |
| 2175 | #define INIT_RCPI 180 | 2385 | #define INIT_RCPI 180 |
| 2176 | struct mt76_phy *mphy = link->phy->mt76; | 2386 | struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); |
| 2177 | struct cfg80211_chan_def *chandef = &mphy->chandef; | ||
| 2178 | struct cfg80211_bitrate_mask *mask = &link->bitrate_mask; | 2387 | struct cfg80211_bitrate_mask *mask = &link->bitrate_mask; |
| 2179 | u32 cap = link_sta->sta->wme ? STA_CAP_WMM : 0; | 2388 | u32 cap = link_sta->sta->wme ? STA_CAP_WMM : 0; |
| 2180 | enum nl80211_band band = chandef->chan->band; | 2389 | struct cfg80211_chan_def *chandef; |
| 2181 | struct sta_rec_ra_uni *ra; | 2390 | struct sta_rec_ra_uni *ra; |
| 2391 | enum nl80211_band band; | ||
| 2182 | struct tlv *tlv; | 2392 | struct tlv *tlv; |
| 2183 | u32 supp_rate = link_sta->supp_rates[band]; | 2393 | u32 supp_rate; |
| 2394 | |||
| 2395 | if (!mphy) | ||
| 2396 | return; | ||
| 2184 | 2397 | ||
| 2185 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); | 2398 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); |
| 2186 | ra = (struct sta_rec_ra_uni *)tlv; | 2399 | ra = (struct sta_rec_ra_uni *)tlv; |
| 2187 | 2400 | ||
| 2401 | chandef = &mphy->chandef; | ||
| 2402 | band = chandef->chan->band; | ||
| 2403 | supp_rate = link_sta->supp_rates[band]; | ||
| 2404 | |||
| 2188 | ra->valid = true; | 2405 | ra->valid = true; |
| 2189 | ra->auto_rate = true; | 2406 | ra->auto_rate = true; |
| 2190 | ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, link_sta); | 2407 | ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, link_sta); |
| @@ -2366,6 +2583,72 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct mt7996_vif_link *link, · 175 unmodified lines | |||
| 2366 | sizeof(req), true); | 2583 | sizeof(req), true); |
| 2367 | } | 2584 | } |
| 2368 | 2585 | ||
| 2586 | int mt7996_mcu_mld_reconf_stop_link(struct mt7996_dev *dev, | ||
| 2587 | struct ieee80211_vif *vif, | ||
| 2588 | u16 removed_links) | ||
| 2589 | { | ||
| 2590 | unsigned long rem_links = removed_links; | ||
| 2591 | struct mld_reconf_stop_link *sl; | ||
| 2592 | struct mld_req_hdr hdr = {}; | ||
| 2593 | unsigned int link_id; | ||
| 2594 | struct sk_buff *skb; | ||
| 2595 | struct tlv *tlv; | ||
| 2596 | |||
| 2597 | skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(hdr) + sizeof(*sl)); | ||
| 2598 | if (!skb) | ||
| 2599 | return -ENOMEM; | ||
| 2600 | |||
| 2601 | memcpy(hdr.mld_addr, vif->addr, ETH_ALEN); | ||
| 2602 | skb_put_data(skb, &hdr, sizeof(hdr)); | ||
| 2603 | |||
| 2604 | tlv = mt7996_mcu_add_uni_tlv(skb, UNI_CMD_MLD_RECONF_STOP_LINK, | ||
| 2605 | sizeof(*sl)); | ||
| 2606 | sl = (struct mld_reconf_stop_link *)tlv; | ||
| 2607 | sl->link_bitmap = cpu_to_le16(removed_links); | ||
| 2608 | |||
| 2609 | for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 2610 | struct mt7996_vif_link *link; | ||
| 2611 | |||
| 2612 | link = mt7996_vif_link(dev, vif, link_id); | ||
| 2613 | if (!link) | ||
| 2614 | continue; | ||
| 2615 | |||
| 2616 | sl->bss_idx[link_id] = link->mt76.idx; | ||
| 2617 | } | ||
| 2618 | |||
| 2619 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(MLD), | ||
| 2620 | true); | ||
| 2621 | } | ||
| 2622 | |||
| 2623 | int mt7996_mcu_mld_link_oper(struct mt7996_dev *dev, | ||
| 2624 | struct ieee80211_bss_conf *link_conf, | ||
| 2625 | struct mt7996_vif_link *link, bool add) | ||
| 2626 | { | ||
| 2627 | struct ieee80211_vif *vif = link_conf->vif; | ||
| 2628 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; | ||
| 2629 | struct bss_mld_link_op_tlv *mld_op; | ||
| 2630 | struct sk_buff *skb; | ||
| 2631 | struct tlv *tlv; | ||
| 2632 | |||
| 2633 | skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, | ||
| 2634 | MT7996_BSS_UPDATE_MAX_SIZE); | ||
| 2635 | if (IS_ERR(skb)) | ||
| 2636 | return PTR_ERR(skb); | ||
| 2637 | |||
| 2638 | tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD_LINK_OP, | ||
| 2639 | sizeof(*mld_op)); | ||
| 2640 | mld_op = (struct bss_mld_link_op_tlv *)tlv; | ||
| 2641 | mld_op->link_operation = add; | ||
| 2642 | mld_op->own_mld_id = link->mld_idx; | ||
| 2643 | mld_op->link_id = link_conf->link_id; | ||
| 2644 | mld_op->group_mld_id = add ? mvif->mld_group_idx : 0xff; | ||
| 2645 | mld_op->remap_idx = add ? mvif->mld_remap_idx : 0xff; | ||
| 2646 | memcpy(mld_op->mac_addr, vif->addr, ETH_ALEN); | ||
| 2647 | |||
| 2648 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 2649 | MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); | ||
| 2650 | } | ||
| 2651 | |||
| 2369 | static void | 2652 | static void |
| 2370 | mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, | 2653 | mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, |
| 2371 | struct ieee80211_vif *vif, | 2654 | struct ieee80211_vif *vif, |
| @@ -2529,6 +2812,53 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, · 157 unmodified lines | |||
| 2529 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); | 2812 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); |
| 2530 | } | 2813 | } |
| 2531 | 2814 | ||
| 2815 | void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta) | ||
| 2816 | { | ||
| 2817 | struct mt7996_vif_link *link = (struct mt7996_vif_link *)data; | ||
| 2818 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; | ||
| 2819 | struct mt7996_phy *phy = mt7996_vif_link_phy(link); | ||
| 2820 | struct mt7996_sta_link *msta_link; | ||
| 2821 | struct mt7996_dev *dev; | ||
| 2822 | struct ieee80211_bss_conf *link_conf; | ||
| 2823 | struct ieee80211_link_sta *link_sta; | ||
| 2824 | struct ieee80211_vif *vif; | ||
| 2825 | struct sk_buff *skb; | ||
| 2826 | int link_id; | ||
| 2827 | |||
| 2828 | if (!phy) | ||
| 2829 | return; | ||
| 2830 | |||
| 2831 | if (link->mt76.mvif != &msta->vif->mt76) | ||
| 2832 | return; | ||
| 2833 | |||
| 2834 | dev = phy->dev; | ||
| 2835 | link_id = link->msta_link.wcid.link_id; | ||
| 2836 | link_sta = link_sta_dereference_protected(sta, link_id); | ||
| 2837 | if (!link_sta) | ||
| 2838 | return; | ||
| 2839 | |||
| 2840 | msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); | ||
| 2841 | if (!msta_link) | ||
| 2842 | return; | ||
| 2843 | |||
| 2844 | vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); | ||
| 2845 | link_conf = link_conf_dereference_protected(vif, link_id); | ||
| 2846 | if (!link_conf) | ||
| 2847 | return; | ||
| 2848 | |||
| 2849 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, | ||
| 2850 | &msta_link->wcid, | ||
| 2851 | MT7996_STA_UPDATE_MAX_SIZE); | ||
| 2852 | if (IS_ERR(skb)) | ||
| 2853 | return; | ||
| 2854 | |||
| 2855 | mt7996_mcu_sta_bfer_tlv(dev, skb, link_conf, link_sta, link); | ||
| 2856 | mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link); | ||
| 2857 | |||
| 2858 | mt76_mcu_skb_send_msg(&dev->mt76, skb, | ||
| 2859 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); | ||
| 2860 | } | ||
| 2861 | |||
| 2532 | static int | 2862 | static int |
| 2533 | mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid, | 2863 | mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid, |
| 2534 | struct sk_buff *skb, | 2864 | struct sk_buff *skb, |
| @@ -2676,6 +3006,16 @@ mt7996_mcu_beacon_cntdwn(struct sk_buff *rskb, struct sk_buff *skb, · 141 unmodified lines | |||
| 2676 | 3006 | ||
| 2677 | info = (struct bss_bcn_cntdwn_tlv *)tlv; | 3007 | info = (struct bss_bcn_cntdwn_tlv *)tlv; |
| 2678 | info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; | 3008 | info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; |
| 3009 | |||
| 3010 | /* abort the CCA countdown when starting CSA countdown */ | ||
| 3011 | if (csa) { | ||
| 3012 | struct bss_bcn_cntdwn_tlv *cca_info; | ||
| 3013 | |||
| 3014 | tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_BCC, | ||
| 3015 | sizeof(*cca_info)); | ||
| 3016 | cca_info = (struct bss_bcn_cntdwn_tlv *)tlv; | ||
| 3017 | cca_info->cca.abort = true; | ||
| 3018 | } | ||
| 2679 | } | 3019 | } |
| 2680 | 3020 | ||
| 2681 | static void | 3021 | static void |
| @@ -2768,6 +3108,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 86 unmodified lines | |||
| 2768 | { | 3108 | { |
| 2769 | struct mt7996_dev *dev = mt7996_hw_dev(hw); | 3109 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 2770 | struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); | 3110 | struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); |
| 3111 | struct mt76_phy *mphy = link ? mt76_vif_link_phy(&link->mt76) : NULL; | ||
| 2771 | struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; | 3112 | struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; |
| 2772 | struct ieee80211_mutable_offsets offs; | 3113 | struct ieee80211_mutable_offsets offs; |
| 2773 | struct ieee80211_tx_info *info; | 3114 | struct ieee80211_tx_info *info; |
| @@ -2782,7 +3123,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 8 unmodified lines | |||
| 2782 | if (!mlink) | 3123 | if (!mlink) |
| 2783 | return -EINVAL; | 3124 | return -EINVAL; |
| 2784 | 3125 | ||
| 2785 | if (link->phy && link->phy->mt76->offchannel) | 3126 | if (mphy && mphy->offchannel) |
| 2786 | enabled = false; | 3127 | enabled = false; |
| 2787 | 3128 | ||
| 2788 | rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, | 3129 | rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, |
| @@ -2833,9 +3174,9 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, · 44 unmodified lines | |||
| 2833 | { | 3174 | { |
| 2834 | #define OFFLOAD_TX_MODE_SU BIT(0) | 3175 | #define OFFLOAD_TX_MODE_SU BIT(0) |
| 2835 | #define OFFLOAD_TX_MODE_MU BIT(1) | 3176 | #define OFFLOAD_TX_MODE_MU BIT(1) |
| 3177 | struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); | ||
| 2836 | struct ieee80211_vif *vif = link_conf->vif; | 3178 | struct ieee80211_vif *vif = link_conf->vif; |
| 2837 | struct ieee80211_hw *hw = mt76_hw(dev); | 3179 | struct ieee80211_hw *hw = mt76_hw(dev); |
| 2838 | struct mt7996_phy *phy = link->phy; | ||
| 2839 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; | 3180 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; |
| 2840 | struct bss_inband_discovery_tlv *discov; | 3181 | struct bss_inband_discovery_tlv *discov; |
| 2841 | struct ieee80211_tx_info *info; | 3182 | struct ieee80211_tx_info *info; |
| @@ -2846,10 +3187,10 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, · 4 unmodified lines | |||
| 2846 | u8 *buf, interval; | 3187 | u8 *buf, interval; |
| 2847 | int len; | 3188 | int len; |
| 2848 | 3189 | ||
| 2849 | if (!phy) | 3190 | if (!mphy) |
| 2850 | return -EINVAL; | 3191 | return -EINVAL; |
| 2851 | 3192 | ||
| 2852 | chandef = &phy->mt76->chandef; | 3193 | chandef = &mphy->chandef; |
| 2853 | band = chandef->chan->band; | 3194 | band = chandef->chan->band; |
| 2854 | 3195 | ||
| 2855 | if (link_conf->nontransmitted) | 3196 | if (link_conf->nontransmitted) |
| @@ -2887,7 +3228,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, · 31 unmodified lines | |||
| 2887 | info = IEEE80211_SKB_CB(skb); | 3228 | info = IEEE80211_SKB_CB(skb); |
| 2888 | info->control.vif = vif; | 3229 | info->control.vif = vif; |
| 2889 | info->band = band; | 3230 | info->band = band; |
| 2890 | info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); | 3231 | info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mphy->band_idx); |
| 2891 | 3232 | ||
| 2892 | len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); | 3233 | len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); |
| 2893 | tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len); | 3234 | tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len); |
| @@ -3742,8 +4083,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) · 848 unmodified lines | |||
| 3742 | 4083 | ||
| 3743 | if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) | 4084 | if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) |
| 3744 | req.switch_reason = CH_SWITCH_NORMAL; | 4085 | req.switch_reason = CH_SWITCH_NORMAL; |
| 3745 | else if (phy->mt76->offchannel || | 4086 | else if (phy->mt76->offchannel || !phy->mt76->chanctx) |
| 3746 | phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) | ||
| 3747 | req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; | 4087 | req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; |
| 3748 | else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, | 4088 | else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, |
| 3749 | NL80211_IFTYPE_AP)) | 4089 | NL80211_IFTYPE_AP)) |
| @@ -3764,23 +4104,173 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) · 14 unmodified lines | |||
| 3764 | &req, sizeof(req), true); | 4104 | &req, sizeof(req), true); |
| 3765 | } | 4105 | } |
| 3766 | 4106 | ||
| 3767 | static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) | 4107 | static int |
| 4108 | mt7996_mcu_get_cal_free_data(struct mt7996_dev *dev) | ||
| 4109 | { | ||
| 4110 | #define MT_EE_7977BN_OFFSET (0x1200 - 0x500) | ||
| 4111 | struct cal_free_data { | ||
| 4112 | u16 adie_offs; | ||
| 4113 | u16 eep_offs; | ||
| 4114 | }; | ||
| 4115 | static const struct cal_free_data cal_7975[] = { | ||
| 4116 | { 0x5cd, 0x451 }, { 0x5cf, 0x453 }, { 0x5d1, 0x455 }, | ||
| 4117 | { 0x5d3, 0x457 }, { 0x6c0, 0x44c }, { 0x6c1, 0x44d }, | ||
| 4118 | { 0x6c2, 0x44e }, { 0x6c3, 0x44f }, { 0x7a1, 0xba1 }, | ||
| 4119 | { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 }, { 0x7aa, 0xbaa }, | ||
| 4120 | }; | ||
| 4121 | static const struct cal_free_data cal_7976[] = { | ||
| 4122 | { 0x4c, 0x44c }, { 0x4d, 0x44d }, { 0x4e, 0x44e }, | ||
| 4123 | { 0x4f, 0x44f }, { 0x50, 0x450 }, { 0x51, 0x451 }, | ||
| 4124 | { 0x53, 0x453 }, { 0x55, 0x455 }, { 0x57, 0x457 }, | ||
| 4125 | { 0x59, 0x459 }, { 0x70, 0x470 }, { 0x71, 0x471 }, | ||
| 4126 | { 0x790, 0xb90 }, { 0x791, 0xb91 }, { 0x794, 0xb94 }, | ||
| 4127 | { 0x795, 0xb95 }, { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 }, | ||
| 4128 | { 0x7aa, 0xbaa }, | ||
| 4129 | }; | ||
| 4130 | static const struct cal_free_data cal_7977[] = { | ||
| 4131 | { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e }, | ||
| 4132 | { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 }, | ||
| 4133 | { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 }, | ||
| 4134 | { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a }, | ||
| 4135 | { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c }, | ||
| 4136 | { 0x7d, 0x127d }, { 0x7e, 0x127e }, | ||
| 4137 | }; | ||
| 4138 | static const struct cal_free_data cal_7978[] = { | ||
| 4139 | { 0x91, 0xb91 }, { 0x95, 0xb95 }, { 0x100, 0x480 }, | ||
| 4140 | { 0x102, 0x482 }, { 0x104, 0x484 }, { 0x106, 0x486 }, | ||
| 4141 | { 0x107, 0x487 }, { 0x108, 0x488 }, { 0x109, 0x489 }, | ||
| 4142 | { 0x10a, 0x48a }, { 0x10b, 0x48b }, { 0x10c, 0x48c }, | ||
| 4143 | { 0x10e, 0x48e }, { 0x110, 0x490 }, | ||
| 4144 | }; | ||
| 4145 | static const struct cal_free_data cal_7979[] = { | ||
| 4146 | { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e }, | ||
| 4147 | { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 }, | ||
| 4148 | { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 }, | ||
| 4149 | { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a }, | ||
| 4150 | { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c }, | ||
| 4151 | { 0x7e, 0x127e }, { 0x80, 0x1280 }, | ||
| 4152 | }; | ||
| 4153 | const struct cal_free_data *cal_arr[__MT_MAX_BAND]; | ||
| 4154 | u16 cal_arr_len[__MT_MAX_BAND] = {}; | ||
| 4155 | u8 *eeprom = (u8 *)dev->mt76.eeprom.data; | ||
| 4156 | int band, i, ret; | ||
| 4157 | |||
| 4158 | #define CAL_ARR(_band, _adie) do { \ | ||
| 4159 | cal_arr[_band] = cal_##_adie; \ | ||
| 4160 | cal_arr_len[_band] = ARRAY_SIZE(cal_##_adie); \ | ||
| 4161 | } while (0) | ||
| 4162 | |||
| 4163 | switch (mt76_chip(&dev->mt76)) { | ||
| 4164 | case MT7996_DEVICE_ID: | ||
| 4165 | /* adie 0 */ | ||
| 4166 | if (dev->var.fem == MT7996_FEM_INT && | ||
| 4167 | dev->var.type != MT7996_VAR_TYPE_233) | ||
| 4168 | CAL_ARR(0, 7975); | ||
| 4169 | else | ||
| 4170 | CAL_ARR(0, 7976); | ||
| 4171 | |||
| 4172 | /* adie 1 */ | ||
| 4173 | if (dev->var.type == MT7996_VAR_TYPE_444) | ||
| 4174 | CAL_ARR(1, 7977); | ||
| 4175 | |||
| 4176 | /* adie 2 */ | ||
| 4177 | CAL_ARR(2, 7977); | ||
| 4178 | break; | ||
| 4179 | case MT7992_DEVICE_ID: | ||
| 4180 | /* adie 0 */ | ||
| 4181 | if (dev->var.type == MT7992_VAR_TYPE_44 && | ||
| 4182 | dev->var.fem != MT7996_FEM_EXT) | ||
| 4183 | CAL_ARR(0, 7975); | ||
| 4184 | else if (dev->var.type == MT7992_VAR_TYPE_24) | ||
| 4185 | CAL_ARR(0, 7978); | ||
| 4186 | else | ||
| 4187 | CAL_ARR(0, 7976); | ||
| 4188 | |||
| 4189 | /* adie 1 */ | ||
| 4190 | if (dev->var.type == MT7992_VAR_TYPE_44 && | ||
| 4191 | dev->var.fem != MT7996_FEM_INT) | ||
| 4192 | CAL_ARR(1, 7977); | ||
| 4193 | else if (dev->var.type != MT7992_VAR_TYPE_23) | ||
| 4194 | CAL_ARR(1, 7979); | ||
| 4195 | break; | ||
| 4196 | case MT7990_DEVICE_ID: | ||
| 4197 | /* adie 0 */ | ||
| 4198 | CAL_ARR(0, 7976); | ||
| 4199 | break; | ||
| 4200 | default: | ||
| 4201 | return -EINVAL; | ||
| 4202 | } | ||
| 4203 | |||
| 4204 | for (band = 0; band < __MT_MAX_BAND; band++) { | ||
| 4205 | u8 buf[MT7996_EEPROM_BLOCK_SIZE]; | ||
| 4206 | const struct cal_free_data *cal; | ||
| 4207 | u16 prev_block_idx = -1; | ||
| 4208 | u16 adie_base; | ||
| 4209 | |||
| 4210 | if (!cal_arr_len[band]) | ||
| 4211 | continue; | ||
| 4212 | |||
| 4213 | if (band == MT_BAND0) | ||
| 4214 | adie_base = MT7996_EFUSE_BASE_OFFS_ADIE0; | ||
| 4215 | else if (band == MT_BAND1 && is_mt7992(&dev->mt76)) | ||
| 4216 | adie_base = MT7992_EFUSE_BASE_OFFS_ADIE1; | ||
| 4217 | else if (band == MT_BAND1) | ||
| 4218 | adie_base = MT7996_EFUSE_BASE_OFFS_ADIE1; | ||
| 4219 | else | ||
| 4220 | adie_base = MT7996_EFUSE_BASE_OFFS_ADIE2; | ||
| 4221 | |||
| 4222 | cal = cal_arr[band]; | ||
| 4223 | for (i = 0; i < cal_arr_len[band]; i++) { | ||
| 4224 | u16 adie_offset = cal[i].adie_offs + adie_base; | ||
| 4225 | u16 eep_offset = cal[i].eep_offs; | ||
| 4226 | u16 block_idx = adie_offset / MT7996_EEPROM_BLOCK_SIZE; | ||
| 4227 | u16 offset = adie_offset % MT7996_EEPROM_BLOCK_SIZE; | ||
| 4228 | |||
| 4229 | if (is_mt7996(&dev->mt76) && band == MT_BAND1 && | ||
| 4230 | dev->var.type == MT7996_VAR_TYPE_444) | ||
| 4231 | eep_offset -= MT_EE_7977BN_OFFSET; | ||
| 4232 | |||
| 4233 | if (prev_block_idx != block_idx) { | ||
| 4234 | memset(buf, 0, sizeof(buf)); | ||
| 4235 | ret = mt7996_mcu_get_eeprom(dev, adie_offset, buf, | ||
| 4236 | MT7996_EEPROM_BLOCK_SIZE, | ||
| 4237 | EEPROM_MODE_EFUSE); | ||
| 4238 | if (ret) { | ||
| 4239 | if (ret != -EINVAL) | ||
| 4240 | return ret; | ||
| 4241 | prev_block_idx = -1; | ||
| 4242 | continue; | ||
| 4243 | } | ||
| 4244 | } | ||
| 4245 | eeprom[eep_offset] = buf[offset]; | ||
| 4246 | prev_block_idx = block_idx; | ||
| 4247 | } | ||
| 4248 | } | ||
| 4249 | |||
| 4250 | return 0; | ||
| 4251 | } | ||
| 4252 | |||
| 4253 | int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) | ||
| 3768 | { | 4254 | { |
| 3769 | #define MAX_PAGE_IDX_MASK GENMASK(7, 5) | 4255 | #define MAX_PAGE_IDX_MASK GENMASK(7, 5) |
| 3770 | #define PAGE_IDX_MASK GENMASK(4, 2) | 4256 | #define PAGE_IDX_MASK GENMASK(4, 2) |
| 3771 | #define PER_PAGE_SIZE 0x400 | 4257 | #define PER_PAGE_SIZE 0x400 |
| 3772 | struct mt7996_mcu_eeprom req = { | 4258 | struct mt7996_mcu_eeprom_update req = { |
| 3773 | .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), | 4259 | .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), |
| 3774 | .buffer_mode = EE_MODE_BUFFER | 4260 | .buffer_mode = EE_MODE_BUFFER |
| 3775 | }; | 4261 | }; |
| 3776 | u16 eeprom_size = MT7996_EEPROM_SIZE; | 4262 | u16 eeprom_size = MT7996_EEPROM_SIZE; |
| 3777 | u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); | 4263 | u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); |
| 3778 | u8 *eep = (u8 *)dev->mt76.eeprom.data; | 4264 | u8 *eep = (u8 *)dev->mt76.eeprom.data; |
| 3779 | int eep_len, i; | 4265 | int ret, eep_len, i; |
| 4266 | |||
| 4267 | ret = mt7996_mcu_get_cal_free_data(dev); | ||
| 4268 | if (ret) | ||
| 4269 | return ret; | ||
| 3780 | 4270 | ||
| 3781 | for (i = 0; i < total; i++, eep += eep_len) { | 4271 | for (i = 0; i < total; i++, eep += eep_len) { |
| 3782 | struct sk_buff *skb; | 4272 | struct sk_buff *skb; |
| 3783 | int ret, msg_len; | 4273 | int msg_len; |
| 3784 | 4274 | ||
| 3785 | if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) | 4275 | if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) |
| 3786 | eep_len = eeprom_size % PER_PAGE_SIZE; | 4276 | eep_len = eeprom_size % PER_PAGE_SIZE; |
| @@ -3809,59 +4299,66 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) · 22 unmodified lines | |||
| 3809 | return 0; | 4299 | return 0; |
| 3810 | } | 4300 | } |
| 3811 | 4301 | ||
| 3812 | int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) | 4302 | int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, |
| 3813 | { | 4303 | enum mt7996_eeprom_mode mode) |
| 3814 | struct mt7996_mcu_eeprom req = { | ||
| 3815 | .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), | ||
| 3816 | .len = cpu_to_le16(sizeof(req) - 4), | ||
| 3817 | .buffer_mode = EE_MODE_EFUSE, | ||
| 3818 | .format = EE_FORMAT_WHOLE | ||
| 3819 | }; | ||
| 3820 | |||
| 3821 | if (dev->flash_mode) | ||
| 3822 | return mt7996_mcu_set_eeprom_flash(dev); | ||
| 3823 | |||
| 3824 | return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL), | ||
| 3825 | &req, sizeof(req), true); | ||
| 3826 | } | ||
| 3827 | |||
| 3828 | int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len) | ||
| 3829 | { | 4304 | { |
| 3830 | struct { | 4305 | struct mt7996_mcu_eeprom_access req = { |
| 3831 | u8 _rsv[4]; | 4306 | .info.len = cpu_to_le16(sizeof(req) - 4), |
| 3832 | |||
| 3833 | __le16 tag; | ||
| 3834 | __le16 len; | ||
| 3835 | __le32 addr; | ||
| 3836 | __le32 valid; | ||
| 3837 | u8 data[16]; | ||
| 3838 | } __packed req = { | ||
| 3839 | .tag = cpu_to_le16(UNI_EFUSE_ACCESS), | ||
| 3840 | .len = cpu_to_le16(sizeof(req) - 4), | ||
| 3841 | .addr = cpu_to_le32(round_down(offset, | ||
| 3842 | MT7996_EEPROM_BLOCK_SIZE)), | ||
| 3843 | }; | 4307 | }; |
| 4308 | struct mt7996_mcu_eeprom_access_event *event; | ||
| 3844 | struct sk_buff *skb; | 4309 | struct sk_buff *skb; |
| 3845 | bool valid; | 4310 | int ret, cmd; |
| 3846 | int ret; | 4311 | u32 addr; |
| 4312 | |||
| 4313 | switch (mode) { | ||
| 4314 | case EEPROM_MODE_EFUSE: | ||
| 4315 | addr = round_down(offset, MT7996_EEPROM_BLOCK_SIZE); | ||
| 4316 | cmd = MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL); | ||
| 4317 | req.info.tag = cpu_to_le16(UNI_EFUSE_ACCESS); | ||
| 4318 | break; | ||
| 4319 | case EEPROM_MODE_EXT: | ||
| 4320 | addr = round_down(offset, MT7996_EXT_EEPROM_BLOCK_SIZE); | ||
| 4321 | cmd = MCU_WM_UNI_CMD_QUERY(EXT_EEPROM_CTRL); | ||
| 4322 | req.info.tag = cpu_to_le16(UNI_EXT_EEPROM_ACCESS); | ||
| 4323 | req.eeprom.ext_eeprom.data_len = cpu_to_le32(buf_len); | ||
| 4324 | break; | ||
| 4325 | default: | ||
| 4326 | return -EINVAL; | ||
| 4327 | } | ||
| 3847 | 4328 | ||
| 3848 | ret = mt76_mcu_send_and_get_msg(&dev->mt76, | 4329 | req.info.addr = cpu_to_le32(addr); |
| 3849 | MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), | 4330 | ret = mt76_mcu_send_and_get_msg(&dev->mt76, cmd, &req, sizeof(req), |
| 3850 | &req, sizeof(req), true, &skb); | 4331 | true, &skb); |
| 3851 | if (ret) | 4332 | if (ret) |
| 3852 | return ret; | 4333 | return ret; |
| 3853 | 4334 | ||
| 3854 | valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); | 4335 | event = (struct mt7996_mcu_eeprom_access_event *)skb->data; |
| 3855 | if (valid) { | 4336 | if (event->valid) { |
| 3856 | u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); | 4337 | u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len); |
| 4338 | |||
| 4339 | addr = le32_to_cpu(event->addr); | ||
| 3857 | 4340 | ||
| 3858 | if (!buf) | 4341 | if (!buf) |
| 3859 | buf = (u8 *)dev->mt76.eeprom.data + addr; | 4342 | buf = (u8 *)dev->mt76.eeprom.data + addr; |
| 3860 | if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) | ||
| 3861 | buf_len = MT7996_EEPROM_BLOCK_SIZE; | ||
| 3862 | 4343 | ||
| 3863 | skb_pull(skb, 48); | 4344 | switch (mode) { |
| 3864 | memcpy(buf, skb->data, buf_len); | 4345 | case EEPROM_MODE_EFUSE: |
| 4346 | if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) | ||
| 4347 | buf_len = MT7996_EEPROM_BLOCK_SIZE; | ||
| 4348 | |||
| 4349 | memcpy(buf, event->eeprom.efuse, buf_len); | ||
| 4350 | break; | ||
| 4351 | case EEPROM_MODE_EXT: | ||
| 4352 | if (!buf_len || buf_len > MT7996_EXT_EEPROM_BLOCK_SIZE) | ||
| 4353 | buf_len = MT7996_EXT_EEPROM_BLOCK_SIZE; | ||
| 4354 | |||
| 4355 | memcpy(buf, event->eeprom.ext_eeprom.data, | ||
| 4356 | ret_len < buf_len ? ret_len : buf_len); | ||
| 4357 | break; | ||
| 4358 | default: | ||
| 4359 | ret = -EINVAL; | ||
| 4360 | break; | ||
| 4361 | } | ||
| 3865 | } else { | 4362 | } else { |
| 3866 | ret = -EINVAL; | 4363 | ret = -EINVAL; |
| 3867 | } | 4364 | } |
| @@ -3871,7 +4368,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l · 3 unmodified lines | |||
| 3871 | return ret; | 4368 | return ret; |
| 3872 | } | 4369 | } |
| 3873 | 4370 | ||
| 3874 | int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) | 4371 | int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num) |
| 3875 | { | 4372 | { |
| 3876 | struct { | 4373 | struct { |
| 3877 | u8 _rsv[4]; | 4374 | u8 _rsv[4]; |
| @@ -3903,7 +4400,6 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) · 25 unmodified lines | |||
| 3903 | 4400 | ||
| 3904 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) | 4401 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) |
| 3905 | { | 4402 | { |
| 3906 | #define NIC_CAP 3 | ||
| 3907 | #define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21 | 4403 | #define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21 |
| 3908 | struct { | 4404 | struct { |
| 3909 | u8 _rsv[4]; | 4405 | u8 _rsv[4]; |
| @@ -3911,7 +4407,7 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) · 1 unmodified line | |||
| 3911 | __le16 tag; | 4407 | __le16 tag; |
| 3912 | __le16 len; | 4408 | __le16 len; |
| 3913 | } __packed req = { | 4409 | } __packed req = { |
| 3914 | .tag = cpu_to_le16(NIC_CAP), | 4410 | .tag = cpu_to_le16(UNI_CHIP_CONFIG_NIC_CAPA), |
| 3915 | .len = cpu_to_le16(sizeof(req) - 4), | 4411 | .len = cpu_to_le16(sizeof(req) - 4), |
| 3916 | }; | 4412 | }; |
| 3917 | struct sk_buff *skb; | 4413 | struct sk_buff *skb; |
| @@ -4559,6 +5055,35 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) · 641 unmodified lines | |||
| 4559 | &req, sizeof(req), true); | 5055 | &req, sizeof(req), true); |
| 4560 | } | 5056 | } |
| 4561 | 5057 | ||
| 5058 | int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy) | ||
| 5059 | { | ||
| 5060 | struct { | ||
| 5061 | u8 band_idx; | ||
| 5062 | u8 _rsv[3]; | ||
| 5063 | |||
| 5064 | __le16 tag; | ||
| 5065 | __le16 len; | ||
| 5066 | u8 mac_enable; | ||
| 5067 | u8 _rsv2[3]; | ||
| 5068 | } __packed req = { | ||
| 5069 | .band_idx = phy->mt76->band_idx, | ||
| 5070 | .tag = cpu_to_le16(UNI_BAND_CONFIG_MAC_ENABLE_CTRL), | ||
| 5071 | .len = cpu_to_le16(sizeof(req) - 4), | ||
| 5072 | .mac_enable = 2, | ||
| 5073 | }; | ||
| 5074 | int ret; | ||
| 5075 | |||
| 5076 | if (!phy->rdd_tx_paused) | ||
| 5077 | return 0; | ||
| 5078 | |||
| 5079 | ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), | ||
| 5080 | &req, sizeof(req), true); | ||
| 5081 | if (!ret) | ||
| 5082 | phy->rdd_tx_paused = false; | ||
| 5083 | |||
| 5084 | return ret; | ||
| 5085 | } | ||
| 5086 | |||
| 4562 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) | 5087 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) |
| 4563 | { | 5088 | { |
| 4564 | struct { | 5089 | struct { |
| @@ -4889,3 +5414,25 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode) · 324 unmodified lines | |||
| 4889 | return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), | 5414 | return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), |
| 4890 | &cp_mode, sizeof(cp_mode), true); | 5415 | &cp_mode, sizeof(cp_mode), true); |
| 4891 | } | 5416 | } |
| 5417 | |||
| 5418 | int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev) | ||
| 5419 | { | ||
| 5420 | #define DUP_WTBL_NUM 80 | ||
| 5421 | struct { | ||
| 5422 | u8 _rsv[4]; | ||
| 5423 | |||
| 5424 | __le16 tag; | ||
| 5425 | __le16 len; | ||
| 5426 | __le16 base; | ||
| 5427 | __le16 num; | ||
| 5428 | u8 _rsv2[4]; | ||
| 5429 | } __packed req = { | ||
| 5430 | .tag = cpu_to_le16(UNI_CHIP_CONFIG_DUP_WTBL), | ||
| 5431 | .len = cpu_to_le16(sizeof(req) - 4), | ||
| 5432 | .base = cpu_to_le16(MT7996_WTBL_STA - DUP_WTBL_NUM + 1), | ||
| 5433 | .num = cpu_to_le16(DUP_WTBL_NUM), | ||
| 5434 | }; | ||
| 5435 | |||
| 5436 | return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(CHIP_CONFIG), &req, | ||
| 5437 | sizeof(req), true); | ||
| 5438 | } | ||
| @@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { · 24 unmodified lines | |||
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | struct mt7996_mcu_uni_event { | 27 | struct mt7996_mcu_uni_event { |
| 28 | u8 cid; | 28 | __le16 cid; |
| 29 | u8 __rsv[3]; | 29 | u8 __rsv[2]; |
| 30 | __le32 status; /* 0: success, others: fail */ | 30 | __le32 status; /* 0: success, others: fail */ |
| 31 | } __packed; | 31 | } __packed; |
| 32 | 32 | ||
| @@ -52,12 +52,10 @@ struct mt7996_mcu_thermal_enable { · 19 unmodified lines | |||
| 52 | u8 rsv[2]; | 52 | u8 rsv[2]; |
| 53 | } __packed; | 53 | } __packed; |
| 54 | 54 | ||
| 55 | struct mt7996_mcu_csa_notify { | 55 | struct mt7996_mcu_countdown_notify { |
| 56 | struct mt7996_mcu_rxd rxd; | ||
| 57 | |||
| 58 | u8 omac_idx; | 56 | u8 omac_idx; |
| 59 | u8 csa_count; | 57 | u8 count; |
| 60 | u8 band_idx; | 58 | u8 csa_failure_reason; /* 0: success, 1: beacon disabled */ |
| 61 | u8 rsv; | 59 | u8 rsv; |
| 62 | } __packed; | 60 | } __packed; |
| 63 | 61 | ||
| @@ -147,7 +145,7 @@ struct mt7996_mcu_background_chain_ctrl { · 83 unmodified lines | |||
| 147 | u8 rsv[2]; | 145 | u8 rsv[2]; |
| 148 | } __packed; | 146 | } __packed; |
| 149 | 147 | ||
| 150 | struct mt7996_mcu_eeprom { | 148 | struct mt7996_mcu_eeprom_update { |
| 151 | u8 _rsv[4]; | 149 | u8 _rsv[4]; |
| 152 | 150 | ||
| 153 | __le16 tag; | 151 | __le16 tag; |
| @@ -157,6 +155,43 @@ struct mt7996_mcu_eeprom { · 3 unmodified lines | |||
| 157 | __le16 buf_len; | 155 | __le16 buf_len; |
| 158 | } __packed; | 156 | } __packed; |
| 159 | 157 | ||
| 158 | union eeprom_data { | ||
| 159 | struct { | ||
| 160 | __le32 data_len; | ||
| 161 | DECLARE_FLEX_ARRAY(u8, data); | ||
| 162 | } ext_eeprom; | ||
| 163 | DECLARE_FLEX_ARRAY(u8, efuse); | ||
| 164 | } __packed; | ||
| 165 | |||
| 166 | struct mt7996_mcu_eeprom_info { | ||
| 167 | u8 _rsv[4]; | ||
| 168 | |||
| 169 | __le16 tag; | ||
| 170 | __le16 len; | ||
| 171 | __le32 addr; | ||
| 172 | __le32 valid; | ||
| 173 | } __packed; | ||
| 174 | |||
| 175 | struct mt7996_mcu_eeprom_access { | ||
| 176 | struct mt7996_mcu_eeprom_info info; | ||
| 177 | union eeprom_data eeprom; | ||
| 178 | } __packed; | ||
| 179 | |||
| 180 | struct mt7996_mcu_eeprom_access_event { | ||
| 181 | u8 _rsv[4]; | ||
| 182 | |||
| 183 | __le16 tag; | ||
| 184 | __le16 len; | ||
| 185 | __le32 version; | ||
| 186 | __le32 addr; | ||
| 187 | __le32 valid; | ||
| 188 | __le32 size; | ||
| 189 | __le32 magic_no; | ||
| 190 | __le32 type; | ||
| 191 | __le32 rsv[4]; | ||
| 192 | union eeprom_data eeprom; | ||
| 193 | } __packed; | ||
| 194 | |||
| 160 | struct mt7996_mcu_phy_rx_info { | 195 | struct mt7996_mcu_phy_rx_info { |
| 161 | u8 category; | 196 | u8 category; |
| 162 | u8 rate; | 197 | u8 rate; |
| @@ -414,7 +449,16 @@ struct bss_bcn_cntdwn_tlv { · 251 unmodified lines | |||
| 414 | __le16 tag; | 449 | __le16 tag; |
| 415 | __le16 len; | 450 | __le16 len; |
| 416 | u8 cnt; | 451 | u8 cnt; |
| 417 | u8 rsv[3]; | 452 | union { |
| 453 | struct { | ||
| 454 | bool static_pp; | ||
| 455 | bool abort; | ||
| 456 | } csa; | ||
| 457 | struct { | ||
| 458 | bool abort; | ||
| 459 | } cca; | ||
| 460 | }; | ||
| 461 | u8 rsv; | ||
| 418 | } __packed; | 462 | } __packed; |
| 419 | 463 | ||
| 420 | struct bss_bcn_mbss_tlv { | 464 | struct bss_bcn_mbss_tlv { |
| @@ -474,6 +518,24 @@ struct bss_mld_tlv { · 53 unmodified lines | |||
| 474 | u8 __rsv[2]; | 518 | u8 __rsv[2]; |
| 475 | } __packed; | 519 | } __packed; |
| 476 | 520 | ||
| 521 | struct bss_prot_tlv { | ||
| 522 | __le16 tag; | ||
| 523 | __le16 len; | ||
| 524 | __le32 prot_mode; | ||
| 525 | } __packed; | ||
| 526 | |||
| 527 | struct bss_mld_link_op_tlv { | ||
| 528 | __le16 tag; | ||
| 529 | __le16 len; | ||
| 530 | u8 group_mld_id; | ||
| 531 | u8 own_mld_id; | ||
| 532 | u8 mac_addr[ETH_ALEN]; | ||
| 533 | u8 remap_idx; | ||
| 534 | u8 link_operation; | ||
| 535 | u8 link_id; | ||
| 536 | u8 rsv[2]; | ||
| 537 | } __packed; | ||
| 538 | |||
| 477 | struct sta_rec_ht_uni { | 539 | struct sta_rec_ht_uni { |
| 478 | __le16 tag; | 540 | __le16 tag; |
| 479 | __le16 len; | 541 | __le16 len; |
| @@ -647,6 +709,28 @@ struct mld_setup_link { · 167 unmodified lines | |||
| 647 | u8 __rsv; | 709 | u8 __rsv; |
| 648 | } __packed; | 710 | } __packed; |
| 649 | 711 | ||
| 712 | struct mld_req_hdr { | ||
| 713 | u8 ver; | ||
| 714 | u8 mld_addr[ETH_ALEN]; | ||
| 715 | u8 mld_idx; | ||
| 716 | u8 flag; | ||
| 717 | u8 rsv[3]; | ||
| 718 | u8 buf[]; | ||
| 719 | } __packed; | ||
| 720 | |||
| 721 | struct mld_reconf_stop_link { | ||
| 722 | __le16 tag; | ||
| 723 | __le16 len; | ||
| 724 | __le16 link_bitmap; | ||
| 725 | u8 rsv[2]; | ||
| 726 | u8 bss_idx[16]; | ||
| 727 | } __packed; | ||
| 728 | |||
| 729 | enum { | ||
| 730 | UNI_CMD_MLD_RECONF_AP_REM_TIMER = 0x03, | ||
| 731 | UNI_CMD_MLD_RECONF_STOP_LINK = 0x04, | ||
| 732 | }; | ||
| 733 | |||
| 650 | struct hdr_trans_en { | 734 | struct hdr_trans_en { |
| 651 | __le16 tag; | 735 | __le16 tag; |
| 652 | __le16 len; | 736 | __le16 len; |
| @@ -791,6 +875,11 @@ enum { · 138 unmodified lines | |||
| 791 | UNI_CHANNEL_RX_PATH, | 875 | UNI_CHANNEL_RX_PATH, |
| 792 | }; | 876 | }; |
| 793 | 877 | ||
| 878 | enum { | ||
| 879 | UNI_CHIP_CONFIG_NIC_CAPA = 3, | ||
| 880 | UNI_CHIP_CONFIG_DUP_WTBL = 4, | ||
| 881 | }; | ||
| 882 | |||
| 794 | #define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ | 883 | #define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ |
| 795 | sizeof(struct mt76_connac_bss_basic_tlv) + \ | 884 | sizeof(struct mt76_connac_bss_basic_tlv) + \ |
| 796 | sizeof(struct bss_rlm_tlv) + \ | 885 | sizeof(struct bss_rlm_tlv) + \ |
| @@ -837,6 +926,7 @@ enum { · 40 unmodified lines | |||
| 837 | enum { | 926 | enum { |
| 838 | UNI_BAND_CONFIG_RADIO_ENABLE, | 927 | UNI_BAND_CONFIG_RADIO_ENABLE, |
| 839 | UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, | 928 | UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, |
| 929 | UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, | ||
| 840 | }; | 930 | }; |
| 841 | 931 | ||
| 842 | enum { | 932 | enum { |
| @@ -856,6 +946,10 @@ enum { · 13 unmodified lines | |||
| 856 | UNI_EFUSE_BUFFER_RD, | 946 | UNI_EFUSE_BUFFER_RD, |
| 857 | }; | 947 | }; |
| 858 | 948 | ||
| 949 | enum { | ||
| 950 | UNI_EXT_EEPROM_ACCESS = 1, | ||
| 951 | }; | ||
| 952 | |||
| 859 | enum { | 953 | enum { |
| 860 | UNI_VOW_DRR_CTRL, | 954 | UNI_VOW_DRR_CTRL, |
| 861 | UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, | 955 | UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, |
| @@ -29,6 +29,10 @@ · 28 unmodified lines | |||
| 29 | #define MT7996_RX_RING_SIZE 1536 | 29 | #define MT7996_RX_RING_SIZE 1536 |
| 30 | #define MT7996_RX_MCU_RING_SIZE 512 | 30 | #define MT7996_RX_MCU_RING_SIZE 512 |
| 31 | #define MT7996_RX_MCU_RING_SIZE_WA 1024 | 31 | #define MT7996_RX_MCU_RING_SIZE_WA 1024 |
| 32 | #define MT7996_NPU_TX_RING_SIZE 1024 | ||
| 33 | #define MT7996_NPU_RX_RING_SIZE 1024 | ||
| 34 | #define MT7996_NPU_TXD_SIZE 3 | ||
| 35 | |||
| 32 | /* scatter-gather of mcu event is not supported in connac3 */ | 36 | /* scatter-gather of mcu event is not supported in connac3 */ |
| 33 | #define MT7996_RX_MCU_BUF_SIZE (2048 + \ | 37 | #define MT7996_RX_MCU_BUF_SIZE (2048 + \ |
| 34 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) | 38 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
| @@ -60,6 +64,11 @@ · 25 unmodified lines | |||
| 60 | #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" | 64 | #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" |
| 61 | #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" | 65 | #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" |
| 62 | 66 | ||
| 67 | #define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin" | ||
| 68 | #define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin" | ||
| 69 | #define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin" | ||
| 70 | #define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin" | ||
| 71 | |||
| 63 | #define MT7990_FIRMWARE_WA "" | 72 | #define MT7990_FIRMWARE_WA "" |
| 64 | #define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" | 73 | #define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" |
| 65 | #define MT7990_FIRMWARE_DSP "" | 74 | #define MT7990_FIRMWARE_DSP "" |
| @@ -75,12 +84,14 @@ · 9 unmodified lines | |||
| 75 | #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" | 84 | #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" |
| 76 | #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" | 85 | #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" |
| 77 | #define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" | 86 | #define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" |
| 87 | #define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin" | ||
| 78 | 88 | ||
| 79 | #define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" | 89 | #define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" |
| 80 | #define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" | 90 | #define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" |
| 81 | 91 | ||
| 82 | #define MT7996_EEPROM_SIZE 7680 | 92 | #define MT7996_EEPROM_SIZE 7680 |
| 83 | #define MT7996_EEPROM_BLOCK_SIZE 16 | 93 | #define MT7996_EEPROM_BLOCK_SIZE 16 |
| 94 | #define MT7996_EXT_EEPROM_BLOCK_SIZE 1024 | ||
| 84 | #define MT7996_TOKEN_SIZE 16384 | 95 | #define MT7996_TOKEN_SIZE 16384 |
| 85 | #define MT7996_HW_TOKEN_SIZE 8192 | 96 | #define MT7996_HW_TOKEN_SIZE 8192 |
| 86 | 97 | ||
| @@ -153,6 +164,7 @@ enum mt7996_var_type { · 66 unmodified lines | |||
| 153 | enum mt7992_var_type { | 164 | enum mt7992_var_type { |
| 154 | MT7992_VAR_TYPE_44, | 165 | MT7992_VAR_TYPE_44, |
| 155 | MT7992_VAR_TYPE_23, | 166 | MT7992_VAR_TYPE_23, |
| 167 | MT7992_VAR_TYPE_24, | ||
| 156 | }; | 168 | }; |
| 157 | 169 | ||
| 158 | enum mt7990_var_type { | 170 | enum mt7990_var_type { |
| @@ -165,6 +177,18 @@ enum mt7996_fem_type { · 6 unmodified lines | |||
| 165 | MT7996_FEM_MIX, | 177 | MT7996_FEM_MIX, |
| 166 | }; | 178 | }; |
| 167 | 179 | ||
| 180 | enum mt7996_eeprom_mode { | ||
| 181 | EEPROM_MODE_DEFAULT_BIN, | ||
| 182 | EEPROM_MODE_EFUSE, | ||
| 183 | EEPROM_MODE_FLASH, | ||
| 184 | EEPROM_MODE_EXT, | ||
| 185 | }; | ||
| 186 | |||
| 187 | #define MT7996_EFUSE_BASE_OFFS_ADIE0 0x400 | ||
| 188 | #define MT7996_EFUSE_BASE_OFFS_ADIE1 0x1e00 | ||
| 189 | #define MT7996_EFUSE_BASE_OFFS_ADIE2 0x1200 | ||
| 190 | #define MT7992_EFUSE_BASE_OFFS_ADIE1 0x1200 | ||
| 191 | |||
| 168 | enum mt7996_txq_id { | 192 | enum mt7996_txq_id { |
| 169 | MT7996_TXQ_FWDL = 16, | 193 | MT7996_TXQ_FWDL = 16, |
| 170 | MT7996_TXQ_MCU_WM, | 194 | MT7996_TXQ_MCU_WM, |
| @@ -252,8 +276,6 @@ struct mt7996_vif_link { · 81 unmodified lines | |||
| 252 | struct mt76_vif_link mt76; /* must be first */ | 276 | struct mt76_vif_link mt76; /* must be first */ |
| 253 | 277 | ||
| 254 | struct mt7996_sta_link msta_link; | 278 | struct mt7996_sta_link msta_link; |
| 255 | struct mt7996_phy *phy; | ||
| 256 | |||
| 257 | struct cfg80211_bitrate_mask bitrate_mask; | 279 | struct cfg80211_bitrate_mask bitrate_mask; |
| 258 | 280 | ||
| 259 | u8 mld_idx; | 281 | u8 mld_idx; |
| @@ -377,6 +399,7 @@ struct mt7996_phy { · 117 unmodified lines | |||
| 377 | 399 | ||
| 378 | bool has_aux_rx; | 400 | bool has_aux_rx; |
| 379 | bool counter_reset; | 401 | bool counter_reset; |
| 402 | bool rdd_tx_paused; | ||
| 380 | }; | 403 | }; |
| 381 | 404 | ||
| 382 | struct mt7996_dev { | 405 | struct mt7996_dev { |
| @@ -436,7 +459,7 @@ struct mt7996_dev { · 53 unmodified lines | |||
| 436 | 459 | ||
| 437 | u32 hw_pattern; | 460 | u32 hw_pattern; |
| 438 | 461 | ||
| 439 | bool flash_mode:1; | 462 | u8 eeprom_mode; |
| 440 | bool has_eht:1; | 463 | bool has_eht:1; |
| 441 | 464 | ||
| 442 | struct { | 465 | struct { |
| @@ -473,6 +496,8 @@ struct mt7996_dev { · 30 unmodified lines | |||
| 473 | struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE]; | 496 | struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE]; |
| 474 | } wed_rro; | 497 | } wed_rro; |
| 475 | 498 | ||
| 499 | dma_addr_t npu_txd_addr[2 * MT7996_NPU_TXD_SIZE]; | ||
| 500 | |||
| 476 | bool ibf; | 501 | bool ibf; |
| 477 | u8 fw_debug_wm; | 502 | u8 fw_debug_wm; |
| 478 | u8 fw_debug_wa; | 503 | u8 fw_debug_wa; |
| @@ -669,6 +694,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, · 190 unmodified lines | |||
| 669 | struct ieee80211_bss_conf *link_conf, | 694 | struct ieee80211_bss_conf *link_conf, |
| 670 | struct mt76_vif_link *mlink, | 695 | struct mt76_vif_link *mlink, |
| 671 | struct mt7996_sta_link *msta_link, int enable); | 696 | struct mt7996_sta_link *msta_link, int enable); |
| 697 | int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy, | ||
| 698 | struct mt7996_vif_link *link); | ||
| 672 | int mt7996_mcu_add_sta(struct mt7996_dev *dev, | 699 | int mt7996_mcu_add_sta(struct mt7996_dev *dev, |
| 673 | struct ieee80211_bss_conf *link_conf, | 700 | struct ieee80211_bss_conf *link_conf, |
| 674 | struct ieee80211_link_sta *link_sta, | 701 | struct ieee80211_link_sta *link_sta, |
| @@ -678,6 +705,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, · 3 unmodified lines | |||
| 678 | int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, | 705 | int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, |
| 679 | struct mt7996_vif_link *link, | 706 | struct mt7996_vif_link *link, |
| 680 | struct mt7996_sta_link *msta_link); | 707 | struct mt7996_sta_link *msta_link); |
| 708 | void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta); | ||
| 681 | int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, | 709 | int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, |
| 682 | struct ieee80211_ampdu_params *params, | 710 | struct ieee80211_ampdu_params *params, |
| 683 | struct ieee80211_vif *vif, bool enable); | 711 | struct ieee80211_vif *vif, bool enable); |
| @@ -707,8 +735,9 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, · 23 unmodified lines | |||
| 707 | int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, | 735 | int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, |
| 708 | void *data, u8 link_id, u32 field); | 736 | void *data, u8 link_id, u32 field); |
| 709 | int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); | 737 | int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); |
| 710 | int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len); | 738 | int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, |
| 711 | int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); | 739 | enum mt7996_eeprom_mode mode); |
| 740 | int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num); | ||
| 712 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); | 741 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); |
| 713 | int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); | 742 | int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); |
| 714 | int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action); | 743 | int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action); |
| @@ -719,6 +748,8 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index, · 4 unmodified lines | |||
| 719 | const struct mt7996_dfs_pattern *pattern); | 748 | const struct mt7996_dfs_pattern *pattern); |
| 720 | int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); | 749 | int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); |
| 721 | int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); | 750 | int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); |
| 751 | int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link, | ||
| 752 | u8 ht_mode, bool use_cts_prot); | ||
| 722 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, | 753 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, |
| 723 | struct ieee80211_bss_conf *link_conf); | 754 | struct ieee80211_bss_conf *link_conf); |
| 724 | int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); | 755 | int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); |
| @@ -726,6 +757,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); · 1 unmodified line | |||
| 726 | int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); | 757 | int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); |
| 727 | int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); | 758 | int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); |
| 728 | int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); | 759 | int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); |
| 760 | int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); | ||
| 729 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); | 761 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); |
| 730 | int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, | 762 | int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, |
| 731 | struct cfg80211_chan_def *chandef); | 763 | struct cfg80211_chan_def *chandef); |
| @@ -743,6 +775,13 @@ void mt7996_mcu_exit(struct mt7996_dev *dev); · 11 unmodified lines | |||
| 743 | int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); | 775 | int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); |
| 744 | int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); | 776 | int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); |
| 745 | int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); | 777 | int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); |
| 778 | int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev); | ||
| 779 | int mt7996_mcu_mld_reconf_stop_link(struct mt7996_dev *dev, | ||
| 780 | struct ieee80211_vif *vif, | ||
| 781 | u16 removed_links); | ||
| 782 | int mt7996_mcu_mld_link_oper(struct mt7996_dev *dev, | ||
| 783 | struct ieee80211_bss_conf *link_conf, | ||
| 784 | struct mt7996_vif_link *link, bool add); | ||
| 746 | 785 | ||
| 747 | static inline bool mt7996_has_hwrro(struct mt7996_dev *dev) | 786 | static inline bool mt7996_has_hwrro(struct mt7996_dev *dev) |
| 748 | { | 787 | { |
| @@ -802,6 +841,11 @@ static inline bool mt7996_has_wa(struct mt7996_dev *dev) · 53 unmodified lines | |||
| 802 | return !is_mt7990(&dev->mt76); | 841 | return !is_mt7990(&dev->mt76); |
| 803 | } | 842 | } |
| 804 | 843 | ||
| 844 | static inline bool mt7996_has_ext_eeprom(struct mt7996_dev *dev) | ||
| 845 | { | ||
| 846 | return !is_mt7996(&dev->mt76); | ||
| 847 | } | ||
| 848 | |||
| 805 | void mt7996_mac_init(struct mt7996_dev *dev); | 849 | void mt7996_mac_init(struct mt7996_dev *dev); |
| 806 | u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); | 850 | u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); |
| 807 | bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); | 851 | bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); |
| @@ -823,8 +867,9 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, · 15 unmodified lines | |||
| 823 | struct mt7996_vif_link *link, | 867 | struct mt7996_vif_link *link, |
| 824 | struct mt7996_sta_link *msta_link, | 868 | struct mt7996_sta_link *msta_link, |
| 825 | u8 flowid); | 869 | u8 flowid); |
| 826 | void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, | 870 | void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, |
| 827 | struct mt7996_sta_link *msta_link); | 871 | struct ieee80211_sta *sta, |
| 872 | unsigned int link_id, bool flush); | ||
| 828 | void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, | 873 | void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, |
| 829 | struct ieee80211_sta *sta, | 874 | struct ieee80211_sta *sta, |
| 830 | struct ieee80211_twt_setup *twt); | 875 | struct ieee80211_twt_setup *twt); |
| @@ -861,6 +906,10 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, · 30 unmodified lines | |||
| 861 | struct mt7996_vif_link *link, | 906 | struct mt7996_vif_link *link, |
| 862 | struct mt7996_sta_link *msta_link); | 907 | struct mt7996_sta_link *msta_link); |
| 863 | int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode); | 908 | int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode); |
| 909 | int mt7996_mcu_set_emlsr_mode(struct mt7996_dev *dev, | ||
| 910 | struct ieee80211_vif *vif, | ||
| 911 | struct ieee80211_sta *sta, | ||
| 912 | struct ieee80211_eml_params *eml_params); | ||
| 864 | #ifdef CONFIG_MAC80211_DEBUGFS | 913 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 865 | void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 914 | void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 866 | struct ieee80211_sta *sta, struct dentry *dir); | 915 | struct ieee80211_sta *sta, struct dentry *dir); |
| @@ -877,12 +926,19 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); · 10 unmodified lines | |||
| 877 | #endif | 926 | #endif |
| 878 | 927 | ||
| 879 | int mt7996_dma_rro_init(struct mt7996_dev *dev); | 928 | int mt7996_dma_rro_init(struct mt7996_dev *dev); |
| 929 | void mt7996_dma_rro_start(struct mt7996_dev *dev); | ||
| 880 | 930 | ||
| 881 | #ifdef CONFIG_MT7996_NPU | 931 | #ifdef CONFIG_MT7996_NPU |
| 932 | int __mt7996_npu_hw_init(struct mt7996_dev *dev); | ||
| 882 | int mt7996_npu_hw_init(struct mt7996_dev *dev); | 933 | int mt7996_npu_hw_init(struct mt7996_dev *dev); |
| 883 | int mt7996_npu_hw_stop(struct mt7996_dev *dev); | 934 | int mt7996_npu_hw_stop(struct mt7996_dev *dev); |
| 884 | int mt7996_npu_rx_queues_init(struct mt7996_dev *dev); | 935 | int mt7996_npu_rx_queues_init(struct mt7996_dev *dev); |
| 885 | #else | 936 | #else |
| 937 | static inline int __mt7996_npu_hw_init(struct mt7996_dev *dev) | ||
| 938 | { | ||
| 939 | return 0; | ||
| 940 | } | ||
| 941 | |||
| 886 | static inline int mt7996_npu_hw_init(struct mt7996_dev *dev) | 942 | static inline int mt7996_npu_hw_init(struct mt7996_dev *dev) |
| 887 | { | 943 | { |
| 888 | return 0; | 944 | return 0; |
| @@ -8,55 +8,20 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include "mt7996.h" | 9 | #include "mt7996.h" |
| 10 | 10 | ||
| 11 | static int mt7996_npu_offload_init(struct mt7996_dev *dev, | 11 | static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev, |
| 12 | struct airoha_npu *npu) | 12 | struct airoha_npu *npu) |
| 13 | { | 13 | { |
| 14 | u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; | ||
| 14 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; | 15 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; |
| 15 | u32 val, hif1_ofs = 0, dma_addr; | 16 | u32 dma_addr; |
| 16 | int i, err; | 17 | int i, err; |
| 17 | 18 | ||
| 18 | err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION, | ||
| 19 | &val, GFP_KERNEL); | ||
| 20 | if (err) { | ||
| 21 | dev_warn(dev->mt76.dev, "failed getting NPU fw version\n"); | ||
| 22 | return err; | ||
| 23 | } | ||
| 24 | |||
| 25 | dev_info(dev->mt76.dev, "NPU version: %0d.%d\n", | ||
| 26 | (val >> 16) & 0xffff, val & 0xffff); | ||
| 27 | |||
| 28 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, | ||
| 29 | dev->mt76.mmio.npu_type, GFP_KERNEL); | ||
| 30 | if (err) { | ||
| 31 | dev_warn(dev->mt76.dev, | ||
| 32 | "failed setting NPU wlan PCIe port type\n"); | ||
| 33 | return err; | ||
| 34 | } | ||
| 35 | |||
| 36 | if (dev->hif2) | ||
| 37 | hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); | ||
| 38 | |||
| 39 | for (i = MT_BAND0; i < MT_BAND2; i++) { | 19 | for (i = MT_BAND0; i < MT_BAND2; i++) { |
| 40 | dma_addr = phy_addr; | ||
| 41 | if (i) | ||
| 42 | dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90 + | ||
| 43 | hif1_ofs; | ||
| 44 | else | ||
| 45 | dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80; | ||
| 46 | |||
| 47 | err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 48 | dma_addr, GFP_KERNEL); | ||
| 49 | if (err) { | ||
| 50 | dev_warn(dev->mt76.dev, | ||
| 51 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 52 | return err; | ||
| 53 | } | ||
| 54 | |||
| 55 | err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC, | 20 | err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC, |
| 56 | MT7996_RX_RING_SIZE, GFP_KERNEL); | 21 | MT7996_RX_RING_SIZE, GFP_KERNEL); |
| 57 | if (err) { | 22 | if (err) { |
| 58 | dev_warn(dev->mt76.dev, | 23 | dev_warn(dev->mt76.dev, |
| 59 | "failed setting NPU wlan PCIe desc size\n"); | 24 | "failed setting NPU wlan rx desc size\n"); |
| 60 | return err; | 25 | return err; |
| 61 | } | 26 | } |
| 62 | 27 | ||
| @@ -97,10 +62,173 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev, · 34 unmodified lines | |||
| 97 | phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); | 62 | phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); |
| 98 | if (err) { | 63 | if (err) { |
| 99 | dev_warn(dev->mt76.dev, | 64 | dev_warn(dev->mt76.dev, |
| 100 | "failed setting NPU wlan rro_ack_sn desc addr\n"); | 65 | "failed setting NPU wlan tx desc addr\n"); |
| 66 | return err; | ||
| 67 | } | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int mt7996_npu_txrx_offload_init(struct mt7996_dev *dev, | ||
| 73 | struct airoha_npu *npu) | ||
| 74 | { | ||
| 75 | u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; | ||
| 76 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; | ||
| 77 | u32 dma_addr; | ||
| 78 | int err; | ||
| 79 | |||
| 80 | /* npu rx rro ring0 */ | ||
| 81 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_DESC, | ||
| 82 | MT7996_RX_RING_SIZE, GFP_KERNEL); | ||
| 83 | if (err) { | ||
| 84 | dev_warn(dev->mt76.dev, | ||
| 85 | "failed setting NPU wlan rx desc size\n"); | ||
| 86 | return err; | ||
| 87 | } | ||
| 88 | |||
| 89 | /* npu rx rro ring1 */ | ||
| 90 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_DESC, | ||
| 91 | MT7996_NPU_RX_RING_SIZE, GFP_KERNEL); | ||
| 92 | if (err) { | ||
| 93 | dev_warn(dev->mt76.dev, | ||
| 94 | "failed setting NPU wlan rx desc size\n"); | ||
| 95 | return err; | ||
| 96 | } | ||
| 97 | |||
| 98 | /* msdu pg 2GHz */ | ||
| 99 | dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0) + 0xa0; | ||
| 100 | err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 101 | dma_addr, GFP_KERNEL); | ||
| 102 | if (err) { | ||
| 103 | dev_warn(dev->mt76.dev, | ||
| 104 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 105 | return err; | ||
| 106 | } | ||
| 107 | |||
| 108 | err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_DESC, | ||
| 109 | MT7996_NPU_RX_RING_SIZE / 4, GFP_KERNEL); | ||
| 110 | if (err) { | ||
| 111 | dev_warn(dev->mt76.dev, | ||
| 112 | "failed setting NPU wlan rx desc size\n"); | ||
| 113 | return err; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* msdu pg 5GHz */ | ||
| 117 | dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1) + 0xb0; | ||
| 118 | err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 119 | dma_addr, GFP_KERNEL); | ||
| 120 | if (err) { | ||
| 121 | dev_warn(dev->mt76.dev, | ||
| 122 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 123 | return err; | ||
| 124 | } | ||
| 125 | |||
| 126 | err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_DESC, | ||
| 127 | MT7996_NPU_RX_RING_SIZE / 2, GFP_KERNEL); | ||
| 128 | if (err) { | ||
| 129 | dev_warn(dev->mt76.dev, | ||
| 130 | "failed setting NPU wlan rx desc size\n"); | ||
| 131 | return err; | ||
| 132 | } | ||
| 133 | |||
| 134 | /* msdu pg 6GHz */ | ||
| 135 | dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2) + 0xc0; | ||
| 136 | err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 137 | dma_addr, GFP_KERNEL); | ||
| 138 | if (err) { | ||
| 139 | dev_warn(dev->mt76.dev, | ||
| 140 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 141 | return err; | ||
| 142 | } | ||
| 143 | |||
| 144 | err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_DESC, | ||
| 145 | MT7996_NPU_RX_RING_SIZE, GFP_KERNEL); | ||
| 146 | if (err) { | ||
| 147 | dev_warn(dev->mt76.dev, | ||
| 148 | "failed setting NPU wlan rx desc size\n"); | ||
| 149 | return err; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* ind cmd ring */ | ||
| 153 | err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 154 | phy_addr + MT_RXQ_RRO_IND_RING_BASE, | ||
| 155 | GFP_KERNEL); | ||
| 156 | if (err) { | ||
| 157 | dev_warn(dev->mt76.dev, | ||
| 158 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 159 | return err; | ||
| 160 | } | ||
| 161 | |||
| 162 | err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_DESC, | ||
| 163 | MT7996_RX_RING_SIZE, GFP_KERNEL); | ||
| 164 | if (err) { | ||
| 165 | dev_warn(dev->mt76.dev, | ||
| 166 | "failed setting NPU wlan rx desc size\n"); | ||
| 167 | return err; | ||
| 168 | } | ||
| 169 | |||
| 170 | err = mt76_npu_send_msg(npu, 3, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, | ||
| 171 | phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); | ||
| 172 | if (err) { | ||
| 173 | dev_warn(dev->mt76.dev, | ||
| 174 | "failed setting NPU wlan tx desc addr\n"); | ||
| 175 | return err; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* npu tx */ | ||
| 179 | dma_addr = phy_addr + MT_TXQ_RING_BASE(1) + 0x120; | ||
| 180 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, | ||
| 181 | dma_addr, GFP_KERNEL); | ||
| 182 | if (err) { | ||
| 183 | dev_warn(dev->mt76.dev, | ||
| 184 | "failed setting NPU wlan tx desc addr\n"); | ||
| 185 | return err; | ||
| 186 | } | ||
| 187 | |||
| 188 | dma_addr = phy_addr + MT_TXQ_RING_BASE(0) + 0x150 + hif1_ofs; | ||
| 189 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, | ||
| 190 | dma_addr, GFP_KERNEL); | ||
| 191 | if (err) { | ||
| 192 | dev_warn(dev->mt76.dev, | ||
| 193 | "failed setting NPU wlan tx desc addr\n"); | ||
| 101 | return err; | 194 | return err; |
| 102 | } | 195 | } |
| 103 | 196 | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int mt7996_npu_offload_init(struct mt7996_dev *dev, | ||
| 201 | struct airoha_npu *npu) | ||
| 202 | { | ||
| 203 | u32 val; | ||
| 204 | int err; | ||
| 205 | |||
| 206 | err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION, | ||
| 207 | &val, GFP_KERNEL); | ||
| 208 | if (err) { | ||
| 209 | dev_warn(dev->mt76.dev, "failed getting NPU fw version\n"); | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | |||
| 213 | dev_info(dev->mt76.dev, "NPU version: %0d.%d\n", | ||
| 214 | (val >> 16) & 0xffff, val & 0xffff); | ||
| 215 | |||
| 216 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, | ||
| 217 | dev->mt76.mmio.npu_type, GFP_KERNEL); | ||
| 218 | if (err) { | ||
| 219 | dev_warn(dev->mt76.dev, | ||
| 220 | "failed setting NPU wlan PCIe port type\n"); | ||
| 221 | return err; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (is_mt7996(&dev->mt76)) | ||
| 225 | err = mt7996_npu_txrx_offload_init(dev, npu); | ||
| 226 | else | ||
| 227 | err = mt7992_npu_txrx_offload_init(dev, npu); | ||
| 228 | |||
| 229 | if (err) | ||
| 230 | return err; | ||
| 231 | |||
| 104 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, | 232 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, |
| 105 | MT7996_HW_TOKEN_SIZE, GFP_KERNEL); | 233 | MT7996_HW_TOKEN_SIZE, GFP_KERNEL); |
| 106 | if (err) | 234 | if (err) |
| @@ -111,7 +239,7 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev, · 4 unmodified lines | |||
| 111 | return 0; | 239 | return 0; |
| 112 | } | 240 | } |
| 113 | 241 | ||
| 114 | static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) | 242 | static int mt7992_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) |
| 115 | { | 243 | { |
| 116 | u32 val; | 244 | u32 val; |
| 117 | int err; | 245 | int err; |
| @@ -120,7 +248,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) · 2 unmodified lines | |||
| 120 | &val, GFP_KERNEL); | 248 | &val, GFP_KERNEL); |
| 121 | if (err) { | 249 | if (err) { |
| 122 | dev_warn(dev->mt76.dev, | 250 | dev_warn(dev->mt76.dev, |
| 123 | "failed retriving NPU wlan rx ring0 addr\n"); | 251 | "failed retrieving NPU wlan rx ring0 addr\n"); |
| 124 | return err; | 252 | return err; |
| 125 | } | 253 | } |
| 126 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); | 254 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); |
| @@ -129,7 +257,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) · 2 unmodified lines | |||
| 129 | &val, GFP_KERNEL); | 257 | &val, GFP_KERNEL); |
| 130 | if (err) { | 258 | if (err) { |
| 131 | dev_warn(dev->mt76.dev, | 259 | dev_warn(dev->mt76.dev, |
| 132 | "failed retriving NPU wlan rx ring1 addr\n"); | 260 | "failed retrieving NPU wlan rx ring1 addr\n"); |
| 133 | return err; | 261 | return err; |
| 134 | } | 262 | } |
| 135 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base); | 263 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base); |
| @@ -138,7 +266,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) · 2 unmodified lines | |||
| 138 | &val, GFP_KERNEL); | 266 | &val, GFP_KERNEL); |
| 139 | if (err) { | 267 | if (err) { |
| 140 | dev_warn(dev->mt76.dev, | 268 | dev_warn(dev->mt76.dev, |
| 141 | "failed retriving NPU wlan rxdmad_c ring addr\n"); | 269 | "failed retrieving NPU wlan rxdmad_c ring addr\n"); |
| 142 | return err; | 270 | return err; |
| 143 | } | 271 | } |
| 144 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base); | 272 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base); |
| @@ -146,59 +274,121 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) · 1 unmodified line | |||
| 146 | return 0; | 274 | return 0; |
| 147 | } | 275 | } |
| 148 | 276 | ||
| 277 | static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) | ||
| 278 | { | ||
| 279 | u32 val; | ||
| 280 | int err; | ||
| 281 | |||
| 282 | err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 283 | &val, GFP_KERNEL); | ||
| 284 | if (err) { | ||
| 285 | dev_warn(dev->mt76.dev, | ||
| 286 | "failed retriving NPU wlan rx ring0 addr\n"); | ||
| 287 | return err; | ||
| 288 | } | ||
| 289 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); | ||
| 290 | |||
| 291 | err = mt76_npu_get_msg(npu, 2, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 292 | &val, GFP_KERNEL); | ||
| 293 | if (err) { | ||
| 294 | dev_warn(dev->mt76.dev, | ||
| 295 | "failed retriving NPU wlan rx ring2 addr\n"); | ||
| 296 | return err; | ||
| 297 | } | ||
| 298 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base); | ||
| 299 | |||
| 300 | /* msdu pg ring */ | ||
| 301 | err = mt76_npu_get_msg(npu, 10, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 302 | &val, GFP_KERNEL); | ||
| 303 | if (err) { | ||
| 304 | dev_warn(dev->mt76.dev, | ||
| 305 | "failed retriving NPU wlan msdu pg ring addr\n"); | ||
| 306 | return err; | ||
| 307 | } | ||
| 308 | writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base); | ||
| 309 | |||
| 310 | err = mt76_npu_get_msg(npu, 11, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 311 | &val, GFP_KERNEL); | ||
| 312 | if (err) { | ||
| 313 | dev_warn(dev->mt76.dev, | ||
| 314 | "failed retriving NPU wlan msdu pg ring addr\n"); | ||
| 315 | return err; | ||
| 316 | } | ||
| 317 | writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base); | ||
| 318 | |||
| 319 | err = mt76_npu_get_msg(npu, 12, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 320 | &val, GFP_KERNEL); | ||
| 321 | if (err) { | ||
| 322 | dev_warn(dev->mt76.dev, | ||
| 323 | "failed retriving NPU wlan msdu pg ring addr\n"); | ||
| 324 | return err; | ||
| 325 | } | ||
| 326 | writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base); | ||
| 327 | |||
| 328 | /* ind_cmd ring */ | ||
| 329 | err = mt76_npu_get_msg(npu, 8, WLAN_FUNC_GET_WAIT_RXDESC_BASE, | ||
| 330 | &val, GFP_KERNEL); | ||
| 331 | if (err) { | ||
| 332 | dev_warn(dev->mt76.dev, | ||
| 333 | "failed retriving NPU wlan ind_cmd ring addr\n"); | ||
| 334 | return err; | ||
| 335 | } | ||
| 336 | writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base); | ||
| 337 | |||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 149 | static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu) | 341 | static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu) |
| 150 | { | 342 | { |
| 151 | int i, err; | 343 | const enum mt76_band_id band_list[] = { |
| 344 | MT_BAND0, | ||
| 345 | is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND1, | ||
| 346 | }; | ||
| 347 | int i, index = 0; | ||
| 152 | 348 | ||
| 153 | for (i = MT_BAND0; i < MT_BAND2; i++) { | 349 | BUILD_BUG_ON(ARRAY_SIZE(band_list) * 3 != |
| 154 | dma_addr_t dma_addr; | 350 | ARRAY_SIZE(dev->npu_txd_addr)); |
| 351 | |||
| 352 | for (i = 0; i < ARRAY_SIZE(band_list); i++) { | ||
| 353 | int err, band = band_list[i], phy_id; | ||
| 155 | u32 val; | 354 | u32 val; |
| 156 | 355 | ||
| 157 | err = mt76_npu_get_msg(npu, i + 5, | 356 | err = mt76_npu_get_msg(npu, band + 5, |
| 158 | WLAN_FUNC_GET_WAIT_RXDESC_BASE, | 357 | WLAN_FUNC_GET_WAIT_RXDESC_BASE, |
| 159 | &val, GFP_KERNEL); | 358 | &val, GFP_KERNEL); |
| 160 | if (err) { | 359 | if (err) { |
| 161 | dev_warn(dev->mt76.dev, | 360 | dev_warn(dev->mt76.dev, |
| 162 | "failed retriving NPU wlan tx ring addr\n"); | 361 | "failed retrieving NPU wlan tx ring addr\n"); |
| 163 | return err; | 362 | return err; |
| 164 | } | 363 | } |
| 165 | writel(val, &dev->mt76.phys[i]->q_tx[0]->regs->desc_base); | ||
| 166 | 364 | ||
| 167 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, | 365 | phy_id = is_mt7996(&dev->mt76) ? band == MT_BAND0 ? 1 : 0 |
| 168 | 256 * MT7996_TX_RING_SIZE, | 366 | : band; |
| 169 | &dma_addr, GFP_KERNEL)) | 367 | writel(val, &dev->mt76.phys[phy_id]->q_tx[0]->regs->desc_base); |
| 170 | return -ENOMEM; | ||
| 171 | 368 | ||
| 172 | err = mt76_npu_send_msg(npu, i, | 369 | err = mt76_npu_send_msg(npu, band, |
| 173 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, | 370 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, |
| 174 | dma_addr, GFP_KERNEL); | 371 | dev->npu_txd_addr[index++], GFP_KERNEL); |
| 175 | if (err) { | 372 | if (err) { |
| 176 | dev_warn(dev->mt76.dev, | 373 | dev_warn(dev->mt76.dev, |
| 177 | "failed setting NPU wlan queue buf addr\n"); | 374 | "failed setting NPU wlan queue buf addr\n"); |
| 178 | return err; | 375 | return err; |
| 179 | } | 376 | } |
| 180 | 377 | ||
| 181 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, | 378 | err = mt76_npu_send_msg(npu, band + 5, |
| 182 | 256 * MT7996_TX_RING_SIZE, | ||
| 183 | &dma_addr, GFP_KERNEL)) | ||
| 184 | return -ENOMEM; | ||
| 185 | |||
| 186 | err = mt76_npu_send_msg(npu, i + 5, | ||
| 187 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, | 379 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, |
| 188 | dma_addr, GFP_KERNEL); | 380 | dev->npu_txd_addr[index++], |
| 381 | GFP_KERNEL); | ||
| 189 | if (err) { | 382 | if (err) { |
| 190 | dev_warn(dev->mt76.dev, | 383 | dev_warn(dev->mt76.dev, |
| 191 | "failed setting NPU wlan tx buf addr\n"); | 384 | "failed setting NPU wlan tx buf addr\n"); |
| 192 | return err; | 385 | return err; |
| 193 | } | 386 | } |
| 194 | 387 | ||
| 195 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024, | 388 | err = mt76_npu_send_msg(npu, band + 10, |
| 196 | &dma_addr, GFP_KERNEL)) | ||
| 197 | return -ENOMEM; | ||
| 198 | |||
| 199 | err = mt76_npu_send_msg(npu, i + 10, | ||
| 200 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, | 389 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, |
| 201 | dma_addr, GFP_KERNEL); | 390 | dev->npu_txd_addr[index++], |
| 391 | GFP_KERNEL); | ||
| 202 | if (err) { | 392 | if (err) { |
| 203 | dev_warn(dev->mt76.dev, | 393 | dev_warn(dev->mt76.dev, |
| 204 | "failed setting NPU wlan tx buf base\n"); | 394 | "failed setting NPU wlan tx buf base\n"); |
| @@ -212,8 +402,9 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu) · 7 unmodified lines | |||
| 212 | static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, | 402 | static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, |
| 213 | struct airoha_npu *npu) | 403 | struct airoha_npu *npu) |
| 214 | { | 404 | { |
| 215 | struct mt76_queue *q = &dev->mt76.q_rx[MT_RXQ_MAIN_WA]; | 405 | int qid = is_mt7996(&dev->mt76) ? MT_RXQ_TXFREE_BAND0 : MT_RXQ_MAIN_WA; |
| 216 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; | 406 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; |
| 407 | struct mt76_queue *q = &dev->mt76.q_rx[qid]; | ||
| 217 | int err; | 408 | int err; |
| 218 | 409 | ||
| 219 | err = mt76_npu_send_msg(npu, 0, | 410 | err = mt76_npu_send_msg(npu, 0, |
| @@ -233,7 +424,8 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, · 13 unmodified lines | |||
| 233 | return err; | 424 | return err; |
| 234 | } | 425 | } |
| 235 | 426 | ||
| 236 | phy_addr += MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA) + 0x20; | 427 | phy_addr += MT_RXQ_RING_BASE(qid); |
| 428 | phy_addr += is_mt7996(&dev->mt76) ? 0x90 : 0x20; | ||
| 237 | err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | 429 | err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR, |
| 238 | phy_addr, GFP_KERNEL); | 430 | phy_addr, GFP_KERNEL); |
| 239 | if (err) | 431 | if (err) |
| @@ -242,11 +434,54 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, · 2 unmodified lines | |||
| 242 | return err; | 434 | return err; |
| 243 | } | 435 | } |
| 244 | 436 | ||
| 437 | static int mt7996_npu_set_pcie_addr(struct mt7996_dev *dev, | ||
| 438 | struct airoha_npu *npu) | ||
| 439 | { | ||
| 440 | u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; | ||
| 441 | dma_addr_t dma_addr = dev->mt76.mmio.phy_addr; | ||
| 442 | int err; | ||
| 443 | |||
| 444 | dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80; | ||
| 445 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 446 | dma_addr, GFP_KERNEL); | ||
| 447 | if (err) { | ||
| 448 | dev_warn(dev->mt76.dev, | ||
| 449 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 450 | return err; | ||
| 451 | } | ||
| 452 | |||
| 453 | dma_addr = dev->mt76.mmio.phy_addr + hif1_ofs; | ||
| 454 | if (is_mt7996(&dev->mt76)) { | ||
| 455 | dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + 0x60; | ||
| 456 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 457 | dma_addr, GFP_KERNEL); | ||
| 458 | } else { | ||
| 459 | dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90; | ||
| 460 | err = mt76_npu_send_msg(npu, 1, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 461 | dma_addr, GFP_KERNEL); | ||
| 462 | } | ||
| 463 | |||
| 464 | if (err) | ||
| 465 | dev_warn(dev->mt76.dev, | ||
| 466 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 467 | |||
| 468 | return err; | ||
| 469 | } | ||
| 470 | |||
| 245 | static int mt7996_npu_tx_done_init(struct mt7996_dev *dev, | 471 | static int mt7996_npu_tx_done_init(struct mt7996_dev *dev, |
| 246 | struct airoha_npu *npu) | 472 | struct airoha_npu *npu) |
| 247 | { | 473 | { |
| 248 | int err; | 474 | int err; |
| 249 | 475 | ||
| 476 | /* rro ring cpu idx */ | ||
| 477 | err = mt76_npu_send_msg(npu, 15, WLAN_FUNC_SET_WAIT_PCIE_ADDR, | ||
| 478 | 0, GFP_KERNEL); | ||
| 479 | if (err) { | ||
| 480 | dev_warn(dev->mt76.dev, | ||
| 481 | "failed setting NPU wlan PCIe desc addr\n"); | ||
| 482 | return err; | ||
| 483 | } | ||
| 484 | |||
| 250 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, | 485 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 251 | 0, GFP_KERNEL); | 486 | 0, GFP_KERNEL); |
| 252 | if (err) { | 487 | if (err) { |
| @@ -278,40 +513,79 @@ int mt7996_npu_rx_queues_init(struct mt7996_dev *dev) · 25 unmodified lines | |||
| 278 | &dev->mt76.q_rx[MT_RXQ_NPU1]); | 513 | &dev->mt76.q_rx[MT_RXQ_NPU1]); |
| 279 | } | 514 | } |
| 280 | 515 | ||
| 281 | int mt7996_npu_hw_init(struct mt7996_dev *dev) | 516 | int __mt7996_npu_hw_init(struct mt7996_dev *dev) |
| 282 | { | 517 | { |
| 283 | struct airoha_npu *npu; | 518 | struct airoha_npu *npu; |
| 284 | int i, err = 0; | 519 | int i, err; |
| 285 | |||
| 286 | mutex_lock(&dev->mt76.mutex); | ||
| 287 | 520 | ||
| 288 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); | 521 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); |
| 289 | if (!npu) | 522 | if (!npu) |
| 290 | goto unlock; | 523 | return 0; |
| 291 | 524 | ||
| 292 | err = mt7996_npu_offload_init(dev, npu); | 525 | err = mt7996_npu_offload_init(dev, npu); |
| 293 | if (err) | 526 | if (err) |
| 294 | goto unlock; | 527 | return err; |
| 528 | |||
| 529 | if (is_mt7996(&dev->mt76)) | ||
| 530 | err = mt7996_npu_rxd_init(dev, npu); | ||
| 531 | else | ||
| 532 | err = mt7992_npu_rxd_init(dev, npu); | ||
| 295 | 533 | ||
| 296 | err = mt7996_npu_rxd_init(dev, npu); | ||
| 297 | if (err) | 534 | if (err) |
| 298 | goto unlock; | 535 | return err; |
| 299 | 536 | ||
| 300 | err = mt7996_npu_txd_init(dev, npu); | 537 | err = mt7996_npu_txd_init(dev, npu); |
| 301 | if (err) | 538 | if (err) |
| 302 | goto unlock; | 539 | return err; |
| 303 | 540 | ||
| 304 | err = mt7996_npu_rx_event_init(dev, npu); | 541 | err = mt7996_npu_rx_event_init(dev, npu); |
| 305 | if (err) | 542 | if (err) |
| 306 | goto unlock; | 543 | return err; |
| 544 | |||
| 545 | err = mt7996_npu_set_pcie_addr(dev, npu); | ||
| 546 | if (err) | ||
| 547 | return err; | ||
| 307 | 548 | ||
| 308 | err = mt7996_npu_tx_done_init(dev, npu); | 549 | err = mt7996_npu_tx_done_init(dev, npu); |
| 309 | if (err) | 550 | if (err) |
| 310 | goto unlock; | 551 | return err; |
| 311 | 552 | ||
| 312 | for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) | 553 | for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) |
| 313 | airoha_npu_wlan_enable_irq(npu, i - MT_RXQ_NPU0); | 554 | airoha_npu_wlan_enable_irq(npu, i - MT_RXQ_NPU0); |
| 314 | unlock: | 555 | |
| 556 | return 0; | ||
| 557 | } | ||
| 558 | |||
| 559 | int mt7996_npu_hw_init(struct mt7996_dev *dev) | ||
| 560 | { | ||
| 561 | int i, err; | ||
| 562 | |||
| 563 | BUILD_BUG_ON(ARRAY_SIZE(dev->npu_txd_addr) % 3); | ||
| 564 | |||
| 565 | for (i = 0; i < ARRAY_SIZE(dev->npu_txd_addr); i += 3) { | ||
| 566 | int band = i && is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND0; | ||
| 567 | u32 size = is_mt7996(&dev->mt76) ? band == MT_BAND2 | ||
| 568 | ? MT7996_NPU_TX_RING_SIZE | ||
| 569 | : MT7996_NPU_RX_RING_SIZE / 2 | ||
| 570 | : MT7996_TX_RING_SIZE; | ||
| 571 | |||
| 572 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size, | ||
| 573 | &dev->npu_txd_addr[i], GFP_KERNEL)) | ||
| 574 | return -ENOMEM; | ||
| 575 | |||
| 576 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size, | ||
| 577 | &dev->npu_txd_addr[i + 1], | ||
| 578 | GFP_KERNEL)) | ||
| 579 | return -ENOMEM; | ||
| 580 | |||
| 581 | if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024, | ||
| 582 | &dev->npu_txd_addr[i + 2], | ||
| 583 | GFP_KERNEL)) | ||
| 584 | return -ENOMEM; | ||
| 585 | } | ||
| 586 | |||
| 587 | mutex_lock(&dev->mt76.mutex); | ||
| 588 | err = __mt7996_npu_hw_init(dev); | ||
| 315 | mutex_unlock(&dev->mt76.mutex); | 589 | mutex_unlock(&dev->mt76.mutex); |
| 316 | 590 | ||
| 317 | return err; | 591 | return err; |
| @@ -320,33 +594,38 @@ unlock: · 2 unmodified lines | |||
| 320 | int mt7996_npu_hw_stop(struct mt7996_dev *dev) | 594 | int mt7996_npu_hw_stop(struct mt7996_dev *dev) |
| 321 | { | 595 | { |
| 322 | struct airoha_npu *npu; | 596 | struct airoha_npu *npu; |
| 323 | int i, err; | 597 | int i, err = 0; |
| 324 | u32 info; | 598 | u32 info; |
| 325 | 599 | ||
| 600 | mutex_lock(&dev->mt76.mutex); | ||
| 601 | |||
| 326 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); | 602 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); |
| 327 | if (!npu) | 603 | if (!npu) |
| 328 | return 0; | 604 | goto unlock; |
| 329 | 605 | ||
| 330 | err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, | 606 | err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 331 | 0, GFP_KERNEL); | 607 | 0, GFP_KERNEL); |
| 332 | if (err) | 608 | if (err) |
| 333 | return err; | 609 | goto unlock; |
| 334 | 610 | ||
| 335 | for (i = 0; i < 10; i++) { | 611 | for (i = 0; i < 10; i++) { |
| 336 | err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO, | 612 | err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO, |
| 337 | &info, GFP_KERNEL); | 613 | &info, GFP_KERNEL); |
| 338 | if (err) | 614 | if (!err && !info) |
| 339 | continue; | 615 | break; |
| 340 | 616 | ||
| 341 | if (info) { | 617 | err = -ETIMEDOUT; |
| 342 | err = -ETIMEDOUT; | 618 | usleep_range(10000, 15000); |
| 343 | continue; | ||
| 344 | } | ||
| 345 | } | 619 | } |
| 346 | 620 | ||
| 347 | if (!err) | 621 | if (!err) |
| 348 | err = mt76_npu_send_msg(npu, 6, | 622 | err = mt76_npu_send_msg(npu, 6, |
| 349 | WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, | 623 | WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 350 | 0, GFP_KERNEL); | 624 | 0, GFP_KERNEL); |
| 625 | else | ||
| 626 | dev_err(dev->mt76.dev, "npu stop failed\n"); | ||
| 627 | unlock: | ||
| 628 | mutex_unlock(&dev->mt76.mutex); | ||
| 629 | |||
| 351 | return err; | 630 | return err; |
| 352 | } | 631 | } |
| @@ -159,6 +159,9 @@ enum offs_rev { · 158 unmodified lines | |||
| 159 | #define MT_MDP_BASE 0x820cc000 | 159 | #define MT_MDP_BASE 0x820cc000 |
| 160 | #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) | 160 | #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) |
| 161 | 161 | ||
| 162 | #define MT_MDP_DCR0 MT_MDP(0x800) | ||
| 163 | #define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) | ||
| 164 | |||
| 162 | #define MT_MDP_DCR2 MT_MDP(0x8e8) | 165 | #define MT_MDP_DCR2 MT_MDP(0x8e8) |
| 163 | #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) | 166 | #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) |
| 164 | 167 | ||
| @@ -733,7 +736,15 @@ enum offs_rev { · 568 unmodified lines | |||
| 733 | #define MT_HW_REV 0x70010204 | 736 | #define MT_HW_REV 0x70010204 |
| 734 | #define MT_HW_REV1 0x8a00 | 737 | #define MT_HW_REV1 0x8a00 |
| 735 | 738 | ||
| 739 | #define MT_WF_L05_RST 0x70028550 | ||
| 740 | #define MT_WF_L05_RST_WF_RST_MASK GENMASK(4, 0) | ||
| 741 | |||
| 736 | #define MT_WF_SUBSYS_RST 0x70028600 | 742 | #define MT_WF_SUBSYS_RST 0x70028600 |
| 743 | #define MT_WF_SUBSYS_RST_WHOLE_PATH_RST BIT(0) | ||
| 744 | #define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT BIT(5) | ||
| 745 | #define MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT BIT(6) | ||
| 746 | #define MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT BIT(16) | ||
| 747 | #define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE GENMASK(15, 8) | ||
| 737 | 748 | ||
| 738 | /* PCIE MAC */ | 749 | /* PCIE MAC */ |
| 739 | #define MT_PCIE_MAC_BASE 0x74030000 | 750 | #define MT_PCIE_MAC_BASE 0x74030000 |
| @@ -390,6 +390,36 @@ int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 389 unmodified lines | |||
| 390 | } | 390 | } |
| 391 | EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc); | 391 | EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc); |
| 392 | 392 | ||
| 393 | int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, | ||
| 394 | u32 direction, u32 i_count_addr, | ||
| 395 | u32 o_status_addr, u32 o_count_addr) | ||
| 396 | { | ||
| 397 | struct { | ||
| 398 | __le32 dir; | ||
| 399 | __le32 in_count_addr; | ||
| 400 | __le32 out_status_addr; | ||
| 401 | __le32 out_count_addr; | ||
| 402 | } info = { | ||
| 403 | .dir = cpu_to_le32(direction), | ||
| 404 | .in_count_addr = cpu_to_le32(i_count_addr), | ||
| 405 | .out_status_addr = cpu_to_le32(o_status_addr), | ||
| 406 | .out_count_addr = cpu_to_le32(o_count_addr), | ||
| 407 | }; | ||
| 408 | struct airoha_npu *npu; | ||
| 409 | int err = -ENODEV; | ||
| 410 | |||
| 411 | rcu_read_lock(); | ||
| 412 | npu = rcu_dereference(dev->mmio.npu); | ||
| 413 | if (npu) | ||
| 414 | err = airoha_npu_wlan_send_msg(npu, ifindex, | ||
| 415 | WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, | ||
| 416 | &info, sizeof(info), GFP_ATOMIC); | ||
| 417 | rcu_read_unlock(); | ||
| 418 | |||
| 419 | return err; | ||
| 420 | } | ||
| 421 | EXPORT_SYMBOL_GPL(mt76_npu_send_txrx_addr); | ||
| 422 | |||
| 393 | void mt76_npu_disable_irqs(struct mt76_dev *dev) | 423 | void mt76_npu_disable_irqs(struct mt76_dev *dev) |
| 394 | { | 424 | { |
| 395 | struct airoha_npu *npu; | 425 | struct airoha_npu *npu; |
| @@ -420,10 +450,6 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) · 24 unmodified lines | |||
| 420 | struct airoha_npu *npu; | 450 | struct airoha_npu *npu; |
| 421 | int err = 0; | 451 | int err = 0; |
| 422 | 452 | ||
| 423 | /* NPU offloading is only supported by MT7992 */ | ||
| 424 | if (!is_mt7992(dev)) | ||
| 425 | return 0; | ||
| 426 | |||
| 427 | mutex_lock(&dev->mutex); | 453 | mutex_lock(&dev->mutex); |
| 428 | 454 | ||
| 429 | npu = airoha_npu_get(dev->dev); | 455 | npu = airoha_npu_get(dev->dev); |
| @@ -456,7 +482,8 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) · 26 unmodified lines | |||
| 456 | dev->mmio.phy_addr = phy_addr; | 482 | dev->mmio.phy_addr = phy_addr; |
| 457 | dev->mmio.npu_type = type; | 483 | dev->mmio.npu_type = type; |
| 458 | /* NPU offloading requires HW-RRO for RX packet reordering. */ | 484 | /* NPU offloading requires HW-RRO for RX packet reordering. */ |
| 459 | dev->hwrro_mode = MT76_HWRRO_V3_1; | 485 | dev->hwrro_mode = is_mt7996(dev) ? MT76_HWRRO_V3 : MT76_HWRRO_V3_1; |
| 486 | dev->rx_token_size = 32768; | ||
| 460 | 487 | ||
| 461 | rcu_assign_pointer(dev->mmio.npu, npu); | 488 | rcu_assign_pointer(dev->mmio.npu, npu); |
| 462 | rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev); | 489 | rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev); |
| @@ -16,9 +16,11 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | clear_bit(MT76_SCANNING, &phy->state); | 17 | clear_bit(MT76_SCANNING, &phy->state); |
| 18 | 18 | ||
| 19 | if (dev->scan.chan && phy->main_chandef.chan && | 19 | if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && |
| 20 | !test_bit(MT76_MCU_RESET, &dev->phy.state)) | 20 | !test_bit(MT76_MCU_RESET, &dev->phy.state)) { |
| 21 | mt76_set_channel(phy, &phy->main_chandef, false); | 21 | mt76_set_channel(phy, &phy->main_chandef, false); |
| 22 | mt76_offchannel_notify(phy, false); | ||
| 23 | } | ||
| 22 | mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); | 24 | mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); |
| 23 | memset(&dev->scan, 0, sizeof(dev->scan)); | 25 | memset(&dev->scan, 0, sizeof(dev->scan)); |
| 24 | if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) | 26 | if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) |
| @@ -27,6 +29,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) · 2 unmodified lines | |||
| 27 | 29 | ||
| 28 | void mt76_abort_scan(struct mt76_dev *dev) | 30 | void mt76_abort_scan(struct mt76_dev *dev) |
| 29 | { | 31 | { |
| 32 | spin_lock_bh(&dev->scan_lock); | ||
| 33 | dev->scan.beacon_wait = false; | ||
| 34 | spin_unlock_bh(&dev->scan_lock); | ||
| 35 | |||
| 30 | cancel_delayed_work_sync(&dev->scan_work); | 36 | cancel_delayed_work_sync(&dev->scan_work); |
| 31 | mt76_scan_complete(dev, true); | 37 | mt76_scan_complete(dev, true); |
| 32 | } | 38 | } |
| @@ -77,6 +83,27 @@ out: · 44 unmodified lines | |||
| 77 | rcu_read_unlock(); | 83 | rcu_read_unlock(); |
| 78 | } | 84 | } |
| 79 | 85 | ||
| 86 | void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan) | ||
| 87 | { | ||
| 88 | struct mt76_phy *phy; | ||
| 89 | |||
| 90 | spin_lock(&dev->scan_lock); | ||
| 91 | |||
| 92 | if (!dev->scan.beacon_wait || dev->scan.beacon_received || | ||
| 93 | dev->scan.chan != chan) | ||
| 94 | goto out; | ||
| 95 | |||
| 96 | phy = dev->scan.phy; | ||
| 97 | if (!phy) | ||
| 98 | goto out; | ||
| 99 | |||
| 100 | dev->scan.beacon_received = true; | ||
| 101 | ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0); | ||
| 102 | |||
| 103 | out: | ||
| 104 | spin_unlock(&dev->scan_lock); | ||
| 105 | } | ||
| 106 | |||
| 80 | void mt76_scan_work(struct work_struct *work) | 107 | void mt76_scan_work(struct work_struct *work) |
| 81 | { | 108 | { |
| 82 | struct mt76_dev *dev = container_of(work, struct mt76_dev, | 109 | struct mt76_dev *dev = container_of(work, struct mt76_dev, |
| @@ -85,35 +112,60 @@ void mt76_scan_work(struct work_struct *work) · 2 unmodified lines | |||
| 85 | struct cfg80211_chan_def chandef = {}; | 112 | struct cfg80211_chan_def chandef = {}; |
| 86 | struct mt76_phy *phy = dev->scan.phy; | 113 | struct mt76_phy *phy = dev->scan.phy; |
| 87 | int duration = HZ / 9; /* ~110 ms */ | 114 | int duration = HZ / 9; /* ~110 ms */ |
| 115 | bool beacon_rx, offchannel = true; | ||
| 88 | int i; | 116 | int i; |
| 89 | 117 | ||
| 118 | if (!phy || !req) | ||
| 119 | return; | ||
| 120 | |||
| 121 | spin_lock_bh(&dev->scan_lock); | ||
| 122 | beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received; | ||
| 123 | dev->scan.beacon_wait = false; | ||
| 124 | spin_unlock_bh(&dev->scan_lock); | ||
| 125 | |||
| 126 | if (beacon_rx) | ||
| 127 | goto probe; | ||
| 128 | |||
| 90 | if (dev->scan.chan_idx >= req->n_channels) { | 129 | if (dev->scan.chan_idx >= req->n_channels) { |
| 91 | mt76_scan_complete(dev, false); | 130 | mt76_scan_complete(dev, false); |
| 92 | return; | 131 | return; |
| 93 | } | 132 | } |
| 94 | 133 | ||
| 95 | if (dev->scan.chan && phy->num_sta) { | 134 | if (dev->scan.chan && phy->num_sta && phy->offchannel) { |
| 96 | dev->scan.chan = NULL; | 135 | dev->scan.chan = NULL; |
| 97 | mt76_set_channel(phy, &phy->main_chandef, false); | 136 | mt76_set_channel(phy, &phy->main_chandef, false); |
| 137 | mt76_offchannel_notify(phy, false); | ||
| 98 | goto out; | 138 | goto out; |
| 99 | } | 139 | } |
| 100 | 140 | ||
| 101 | dev->scan.chan = req->channels[dev->scan.chan_idx++]; | 141 | dev->scan.chan = req->channels[dev->scan.chan_idx++]; |
| 102 | cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); | 142 | offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef); |
| 103 | mt76_set_channel(phy, &chandef, true); | 143 | |
| 144 | if (offchannel) | ||
| 145 | mt76_offchannel_notify(phy, true); | ||
| 146 | mt76_set_channel(phy, &chandef, offchannel); | ||
| 104 | 147 | ||
| 105 | if (!req->n_ssids || | 148 | if (!req->n_ssids) |
| 106 | chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) | ||
| 107 | goto out; | 149 | goto out; |
| 108 | 150 | ||
| 109 | duration = HZ / 16; /* ~60 ms */ | 151 | if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) { |
| 152 | spin_lock_bh(&dev->scan_lock); | ||
| 153 | dev->scan.beacon_received = false; | ||
| 154 | dev->scan.beacon_wait = true; | ||
| 155 | spin_unlock_bh(&dev->scan_lock); | ||
| 156 | goto out; | ||
| 157 | } | ||
| 158 | |||
| 159 | probe: | ||
| 160 | if (phy->offchannel) | ||
| 161 | duration = HZ / 16; /* ~60 ms */ | ||
| 110 | local_bh_disable(); | 162 | local_bh_disable(); |
| 111 | for (i = 0; i < req->n_ssids; i++) | 163 | for (i = 0; i < req->n_ssids; i++) |
| 112 | mt76_scan_send_probe(dev, &req->ssids[i]); | 164 | mt76_scan_send_probe(dev, &req->ssids[i]); |
| 113 | local_bh_enable(); | 165 | local_bh_enable(); |
| 114 | 166 | ||
| 115 | out: | 167 | out: |
| 116 | if (dev->scan.chan) | 168 | if (dev->scan.chan && phy->offchannel) |
| 117 | duration = max_t(int, duration, | 169 | duration = max_t(int, duration, |
| 118 | msecs_to_jiffies(req->duration + | 170 | msecs_to_jiffies(req->duration + |
| 119 | (req->duration >> 5))); | 171 | (req->duration >> 5))); |
| @@ -227,7 +227,9 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, · 226 unmodified lines | |||
| 227 | struct sk_buff *skb) | 227 | struct sk_buff *skb) |
| 228 | { | 228 | { |
| 229 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 229 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 230 | struct ieee80211_sta *sta; | ||
| 230 | int pending; | 231 | int pending; |
| 232 | int i; | ||
| 231 | 233 | ||
| 232 | if (!wcid || info->tx_time_est) | 234 | if (!wcid || info->tx_time_est) |
| 233 | return; | 235 | return; |
| @@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, · 1 unmodified line | |||
| 235 | pending = atomic_dec_return(&wcid->non_aql_packets); | 237 | pending = atomic_dec_return(&wcid->non_aql_packets); |
| 236 | if (pending < 0) | 238 | if (pending < 0) |
| 237 | atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); | 239 | atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); |
| 240 | |||
| 241 | sta = wcid_to_sta(wcid); | ||
| 242 | if (!sta || pending != MT_MAX_NON_AQL_PKT - 1) | ||
| 243 | return; | ||
| 244 | |||
| 245 | for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { | ||
| 246 | if (!sta->txq[i]) | ||
| 247 | continue; | ||
| 248 | |||
| 249 | ieee80211_schedule_txq(dev->hw, sta->txq[i]); | ||
| 250 | } | ||
| 238 | } | 251 | } |
| 239 | 252 | ||
| 240 | void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, | 253 | void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, |
| @@ -542,6 +555,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) · 301 unmodified lines | |||
| 542 | if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) | 555 | if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) |
| 543 | continue; | 556 | continue; |
| 544 | 557 | ||
| 558 | if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) | ||
| 559 | continue; | ||
| 560 | |||
| 545 | phy = mt76_dev_phy(dev, wcid->phy_idx); | 561 | phy = mt76_dev_phy(dev, wcid->phy_idx); |
| 546 | if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) | 562 | if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) |
| 547 | continue; | 563 | continue; |
| @@ -616,7 +632,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, · 68 unmodified lines | |||
| 616 | 632 | ||
| 617 | if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && | 633 | if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && |
| 618 | !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && | 634 | !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && |
| 619 | !ieee80211_is_data(hdr->frame_control) && | 635 | !ieee80211_is_data_present(hdr->frame_control) && |
| 620 | (!ieee80211_is_bufferable_mmpdu(skb) || | 636 | (!ieee80211_is_bufferable_mmpdu(skb) || |
| 621 | ieee80211_is_deauth(hdr->frame_control) || | 637 | ieee80211_is_deauth(hdr->frame_control) || |
| 622 | head == &wcid->tx_offchannel)) | 638 | head == &wcid->tx_offchannel)) |
| @@ -644,7 +660,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, · 21 unmodified lines | |||
| 644 | return ret; | 660 | return ret; |
| 645 | } | 661 | } |
| 646 | 662 | ||
| 647 | static void mt76_txq_schedule_pending(struct mt76_phy *phy) | 663 | void mt76_txq_schedule_pending(struct mt76_phy *phy) |
| 648 | { | 664 | { |
| 649 | LIST_HEAD(tx_list); | 665 | LIST_HEAD(tx_list); |
| 650 | int ret = 0; | 666 | int ret = 0; |
| @@ -850,9 +866,15 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi) · 199 unmodified lines | |||
| 850 | token = idr_alloc(&dev->token, *ptxwi, dev->token_start, | 866 | token = idr_alloc(&dev->token, *ptxwi, dev->token_start, |
| 851 | dev->token_start + dev->token_size, | 867 | dev->token_start + dev->token_size, |
| 852 | GFP_ATOMIC); | 868 | GFP_ATOMIC); |
| 853 | if (token >= dev->token_start) | 869 | if (token >= dev->token_start) { |
| 854 | dev->token_count++; | 870 | dev->token_count++; |
| 855 | 871 | ||
| 872 | if ((*ptxwi)->qid == MT_TXQ_PSD) { | ||
| 873 | struct mt76_phy *mphy = mt76_dev_phy(dev, (*ptxwi)->phy_idx); | ||
| 874 | atomic_inc(&mphy->mgmt_tx_pending); | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 856 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED | 878 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 857 | if (mtk_wed_device_active(&dev->mmio.wed) && | 879 | if (mtk_wed_device_active(&dev->mmio.wed) && |
| 858 | token >= dev->mmio.wed.wlan.token_start) | 880 | token >= dev->mmio.wed.wlan.token_start) |
| @@ -897,6 +919,12 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake) · 38 unmodified lines | |||
| 897 | if (txwi) { | 919 | if (txwi) { |
| 898 | dev->token_count--; | 920 | dev->token_count--; |
| 899 | 921 | ||
| 922 | if (txwi->qid == MT_TXQ_PSD) { | ||
| 923 | struct mt76_phy *mphy = mt76_dev_phy(dev, txwi->phy_idx); | ||
| 924 | if (atomic_dec_and_test(&mphy->mgmt_tx_pending)) | ||
| 925 | wake_up(&dev->tx_wait); | ||
| 926 | } | ||
| 927 | |||
| 900 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED | 928 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 901 | if (mtk_wed_device_active(&dev->mmio.wed) && | 929 | if (mtk_wed_device_active(&dev->mmio.wed) && |
| 902 | token >= dev->mmio.wed.wlan.token_start && | 930 | token >= dev->mmio.wed.wlan.token_start && |
| @@ -403,12 +403,18 @@ error: · 402 unmodified lines | |||
| 403 | return ret; | 403 | return ret; |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | static const char * const mt7601u_fw_paths[] = { | ||
| 407 | "mediatek/" MT7601U_FIRMWARE, | ||
| 408 | MT7601U_FIRMWARE, | ||
| 409 | }; | ||
| 410 | |||
| 406 | static int mt7601u_load_firmware(struct mt7601u_dev *dev) | 411 | static int mt7601u_load_firmware(struct mt7601u_dev *dev) |
| 407 | { | 412 | { |
| 408 | const struct firmware *fw; | 413 | const struct firmware *fw; |
| 409 | const struct mt76_fw_header *hdr; | 414 | const struct mt76_fw_header *hdr; |
| 410 | int len, ret; | 415 | int len, ret; |
| 411 | u32 val; | 416 | u32 val; |
| 417 | int i; | ||
| 412 | 418 | ||
| 413 | mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | | 419 | mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | |
| 414 | MT_USB_DMA_CFG_TX_BULK_EN)); | 420 | MT_USB_DMA_CFG_TX_BULK_EN)); |
| @@ -416,7 +422,14 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev) · 1 unmodified line | |||
| 416 | if (firmware_running(dev)) | 422 | if (firmware_running(dev)) |
| 417 | return firmware_request_cache(dev->dev, MT7601U_FIRMWARE); | 423 | return firmware_request_cache(dev->dev, MT7601U_FIRMWARE); |
| 418 | 424 | ||
| 419 | ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev); | 425 | /* Try loading firmware from multiple locations */ |
| 426 | fw = NULL; | ||
| 427 | for (i = 0; i < MT7601U_FIRMWARE_PATHS; i++) { | ||
| 428 | ret = request_firmware(&fw, mt7601u_fw_paths[i], dev->dev); | ||
| 429 | if (ret == 0) | ||
| 430 | break; | ||
| 431 | } | ||
| 432 | |||
| 420 | if (ret) | 433 | if (ret) |
| 421 | return ret; | 434 | return ret; |
| 422 | 435 | ||
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include "mt7601u.h" | 9 | #include "mt7601u.h" |
| 10 | 10 | ||
| 11 | #define MT7601U_FIRMWARE "mt7601u.bin" | 11 | #define MT7601U_FIRMWARE "mt7601u.bin" |
| 12 | #define MT7601U_FIRMWARE_PATHS ARRAY_SIZE(mt7601u_fw_paths) | ||
| 12 | 13 | ||
| 13 | #define MT_VEND_REQ_MAX_RETRY 10 | 14 | #define MT_VEND_REQ_MAX_RETRY 10 |
| 14 | #define MT_VEND_REQ_TOUT_MS 300 | 15 | #define MT_VEND_REQ_TOUT_MS 300 |
| @@ -4640,6 +4640,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { · 4639 unmodified lines | |||
| 4640 | }, | 4640 | }, |
| 4641 | /* PPE threshold information is not supported */ | 4641 | /* PPE threshold information is not supported */ |
| 4642 | }, | 4642 | }, |
| 4643 | .uhr_cap = { | ||
| 4644 | .has_uhr = true, | ||
| 4645 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 4646 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 4647 | }, | ||
| 4643 | }, | 4648 | }, |
| 4644 | { | 4649 | { |
| 4645 | .types_mask = BIT(NL80211_IFTYPE_AP) | | 4650 | .types_mask = BIT(NL80211_IFTYPE_AP) | |
| @@ -4748,6 +4753,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = { · 102 unmodified lines | |||
| 4748 | }, | 4753 | }, |
| 4749 | /* PPE threshold information is not supported */ | 4754 | /* PPE threshold information is not supported */ |
| 4750 | }, | 4755 | }, |
| 4756 | .uhr_cap = { | ||
| 4757 | .has_uhr = true, | ||
| 4758 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 4759 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 4760 | }, | ||
| 4751 | }, | 4761 | }, |
| 4752 | #ifdef CONFIG_MAC80211_MESH | 4762 | #ifdef CONFIG_MAC80211_MESH |
| 4753 | { | 4763 | { |
| @@ -4917,6 +4927,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { · 163 unmodified lines | |||
| 4917 | }, | 4927 | }, |
| 4918 | /* PPE threshold information is not supported */ | 4928 | /* PPE threshold information is not supported */ |
| 4919 | }, | 4929 | }, |
| 4930 | .uhr_cap = { | ||
| 4931 | .has_uhr = true, | ||
| 4932 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 4933 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 4934 | }, | ||
| 4920 | }, | 4935 | }, |
| 4921 | { | 4936 | { |
| 4922 | .types_mask = BIT(NL80211_IFTYPE_AP) | | 4937 | .types_mask = BIT(NL80211_IFTYPE_AP) | |
| @@ -5042,6 +5057,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_5ghz[] = { · 119 unmodified lines | |||
| 5042 | }, | 5057 | }, |
| 5043 | /* PPE threshold information is not supported */ | 5058 | /* PPE threshold information is not supported */ |
| 5044 | }, | 5059 | }, |
| 5060 | .uhr_cap = { | ||
| 5061 | .has_uhr = true, | ||
| 5062 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 5063 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 5064 | }, | ||
| 5045 | }, | 5065 | }, |
| 5046 | #ifdef CONFIG_MAC80211_MESH | 5066 | #ifdef CONFIG_MAC80211_MESH |
| 5047 | { | 5067 | { |
| @@ -5235,6 +5255,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { · 187 unmodified lines | |||
| 5235 | }, | 5255 | }, |
| 5236 | /* PPE threshold information is not supported */ | 5256 | /* PPE threshold information is not supported */ |
| 5237 | }, | 5257 | }, |
| 5258 | .uhr_cap = { | ||
| 5259 | .has_uhr = true, | ||
| 5260 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 5261 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 5262 | }, | ||
| 5238 | }, | 5263 | }, |
| 5239 | { | 5264 | { |
| 5240 | .types_mask = BIT(NL80211_IFTYPE_AP) | | 5265 | .types_mask = BIT(NL80211_IFTYPE_AP) | |
| @@ -5381,6 +5406,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { · 140 unmodified lines | |||
| 5381 | }, | 5406 | }, |
| 5382 | /* PPE threshold information is not supported */ | 5407 | /* PPE threshold information is not supported */ |
| 5383 | }, | 5408 | }, |
| 5409 | .uhr_cap = { | ||
| 5410 | .has_uhr = true, | ||
| 5411 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 5412 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 5413 | }, | ||
| 5384 | }, | 5414 | }, |
| 5385 | #ifdef CONFIG_MAC80211_MESH | 5415 | #ifdef CONFIG_MAC80211_MESH |
| 5386 | { | 5416 | { |
| @@ -5472,6 +5502,11 @@ static const struct ieee80211_sband_iftype_data sband_capa_6ghz[] = { · 85 unmodified lines | |||
| 5472 | }, | 5502 | }, |
| 5473 | /* PPE threshold information is not supported */ | 5503 | /* PPE threshold information is not supported */ |
| 5474 | }, | 5504 | }, |
| 5505 | .uhr_cap = { | ||
| 5506 | .has_uhr = true, | ||
| 5507 | .phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX | | ||
| 5508 | IEEE80211_UHR_PHY_CAP_ELR_TX, | ||
| 5509 | }, | ||
| 5475 | }, | 5510 | }, |
| 5476 | #endif | 5511 | #endif |
| 5477 | }; | 5512 | }; |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> | 9 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
| 10 | * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH | 10 | * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH |
| 11 | * Copyright (c) 2016 - 2017 Intel Deutschland GmbH | 11 | * Copyright (c) 2016 - 2017 Intel Deutschland GmbH |
| 12 | * Copyright (c) 2018 - 2025 Intel Corporation | 12 | * Copyright (c) 2018 - 2026 Intel Corporation |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #ifndef LINUX_IEEE80211_NAN_H | 15 | #ifndef LINUX_IEEE80211_NAN_H |
| @@ -23,6 +23,11 @@ · 7 unmodified lines | |||
| 23 | #define NAN_OP_MODE_160MHZ 0x04 | 23 | #define NAN_OP_MODE_160MHZ 0x04 |
| 24 | #define NAN_OP_MODE_PNDL_SUPPRTED 0x08 | 24 | #define NAN_OP_MODE_PNDL_SUPPRTED 0x08 |
| 25 | 25 | ||
| 26 | #define NAN_DEV_CAPA_NUM_TX_ANT_POS 0 | ||
| 27 | #define NAN_DEV_CAPA_NUM_TX_ANT_MASK 0x0f | ||
| 28 | #define NAN_DEV_CAPA_NUM_RX_ANT_POS 4 | ||
| 29 | #define NAN_DEV_CAPA_NUM_RX_ANT_MASK 0xf0 | ||
| 30 | |||
| 26 | /* NAN Device capabilities, as defined in Wi-Fi Aware (TM) specification | 31 | /* NAN Device capabilities, as defined in Wi-Fi Aware (TM) specification |
| 27 | * Table 79 | 32 | * Table 79 |
| 28 | */ | 33 | */ |
| @@ -1194,6 +1194,13 @@ struct ieee80211_mgmt { · 1193 unmodified lines | |||
| 1194 | 1194 | ||
| 1195 | #define IEEE80211_MIN_ACTION_SIZE(type) offsetofend(struct ieee80211_mgmt, u.action.type) | 1195 | #define IEEE80211_MIN_ACTION_SIZE(type) offsetofend(struct ieee80211_mgmt, u.action.type) |
| 1196 | 1196 | ||
| 1197 | /* Link Reconfiguration Status Duple field */ | ||
| 1198 | struct ieee80211_ml_reconf_status { | ||
| 1199 | u8 info; | ||
| 1200 | __le16 status; | ||
| 1201 | } __packed; | ||
| 1202 | |||
| 1203 | #define IEEE80211_ML_RECONF_LINK_ID_MASK 0xf | ||
| 1197 | 1204 | ||
| 1198 | /* Management MIC information element (IEEE 802.11w) for CMAC */ | 1205 | /* Management MIC information element (IEEE 802.11w) for CMAC */ |
| 1199 | struct ieee80211_mmie { | 1206 | struct ieee80211_mmie { |
| @@ -1831,6 +1831,7 @@ struct cfg80211_ttlm_params { · 1830 unmodified lines | |||
| 1831 | * @eml_cap: EML capabilities of this station | 1831 | * @eml_cap: EML capabilities of this station |
| 1832 | * @link_sta_params: link related params. | 1832 | * @link_sta_params: link related params. |
| 1833 | * @epp_peer: EPP peer indication | 1833 | * @epp_peer: EPP peer indication |
| 1834 | * @nmi_mac: MAC address of the NMI station of the NAN peer | ||
| 1834 | */ | 1835 | */ |
| 1835 | struct station_parameters { | 1836 | struct station_parameters { |
| 1836 | struct net_device *vlan; | 1837 | struct net_device *vlan; |
| @@ -1858,6 +1859,7 @@ struct station_parameters { · 21 unmodified lines | |||
| 1858 | u16 eml_cap; | 1859 | u16 eml_cap; |
| 1859 | struct link_station_parameters link_sta_params; | 1860 | struct link_station_parameters link_sta_params; |
| 1860 | bool epp_peer; | 1861 | bool epp_peer; |
| 1862 | const u8 *nmi_mac; | ||
| 1861 | }; | 1863 | }; |
| 1862 | 1864 | ||
| 1863 | /** | 1865 | /** |
| @@ -1897,6 +1899,8 @@ struct station_del_parameters { · 33 unmodified lines | |||
| 1897 | * entry that is operating, has been marked authorized by userspace) | 1899 | * entry that is operating, has been marked authorized by userspace) |
| 1898 | * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed) | 1900 | * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed) |
| 1899 | * @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed) | 1901 | * @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed) |
| 1902 | * @CFG80211_STA_NAN_MGMT: NAN management interface station | ||
| 1903 | * @CFG80211_STA_NAN_DATA: NAN data path station | ||
| 1900 | */ | 1904 | */ |
| 1901 | enum cfg80211_station_type { | 1905 | enum cfg80211_station_type { |
| 1902 | CFG80211_STA_AP_CLIENT, | 1906 | CFG80211_STA_AP_CLIENT, |
| @@ -1908,6 +1912,8 @@ enum cfg80211_station_type { · 5 unmodified lines | |||
| 1908 | CFG80211_STA_TDLS_PEER_ACTIVE, | 1912 | CFG80211_STA_TDLS_PEER_ACTIVE, |
| 1909 | CFG80211_STA_MESH_PEER_KERNEL, | 1913 | CFG80211_STA_MESH_PEER_KERNEL, |
| 1910 | CFG80211_STA_MESH_PEER_USER, | 1914 | CFG80211_STA_MESH_PEER_USER, |
| 1915 | CFG80211_STA_NAN_MGMT, | ||
| 1916 | CFG80211_STA_NAN_DATA, | ||
| 1911 | }; | 1917 | }; |
| 1912 | 1918 | ||
| 1913 | /** | 1919 | /** |
| @@ -3980,6 +3986,77 @@ struct cfg80211_qos_map { · 2066 unmodified lines | |||
| 3980 | struct cfg80211_dscp_range up[8]; | 3986 | struct cfg80211_dscp_range up[8]; |
| 3981 | }; | 3987 | }; |
| 3982 | 3988 | ||
| 3989 | /** | ||
| 3990 | * DOC: Neighbor Awareness Networking (NAN) | ||
| 3991 | * | ||
| 3992 | * NAN uses two interface types: | ||
| 3993 | * | ||
| 3994 | * - %NL80211_IFTYPE_NAN: a non-netdev interface. This has two roles: (1) holds | ||
| 3995 | * the configuration of all NAN activities (DE parameters, synchronisation | ||
| 3996 | * parameters, local schedule, etc.), and (2) uses as the NAN Management | ||
| 3997 | * Interface (NMI), which is used for NAN management communication. | ||
| 3998 | * | ||
| 3999 | * - %NL80211_IFTYPE_NAN_DATA: The NAN Data Interface (NDI), used for data | ||
| 4000 | * communication with NAN peers. | ||
| 4001 | * | ||
| 4002 | * An NDI interface can only be started (IFF_UP) if the NMI one is running and | ||
| 4003 | * NAN is started. Before NAN is stopped, all associated NDI interfaces | ||
| 4004 | * must be stopped first. | ||
| 4005 | * | ||
| 4006 | * The local schedule specifies which channels the device is available on and | ||
| 4007 | * when. Must be cancelled before NAN is stopped. | ||
| 4008 | * | ||
| 4009 | * NAN Stations | ||
| 4010 | * ~~~~~~~~~~~~ | ||
| 4011 | * | ||
| 4012 | * There are two types of stations corresponding to the two interface types: | ||
| 4013 | * | ||
| 4014 | * - NMI station: Represents the NAN peer. Peer-specific data such as the peer's | ||
| 4015 | * schedule and the HT, VHT and HE capabilities belongs to the NMI station. | ||
| 4016 | * Also used for Tx/Rx of NAN management frames to/from the peer. | ||
| 4017 | * Added on the %NL80211_IFTYPE_NAN interface. | ||
| 4018 | * | ||
| 4019 | * - NDI station: Used for Tx/Rx of data frames (and non-NAN management frames) | ||
| 4020 | * for a specific NDP established with the NAN peer. Added on the | ||
| 4021 | * %NL80211_IFTYPE_NAN_DATA interface. | ||
| 4022 | * | ||
| 4023 | * A peer may reuse its NMI address as the NDI address. In that case, two | ||
| 4024 | * separate stations should be added even though they share the same MAC | ||
| 4025 | * address. | ||
| 4026 | * | ||
| 4027 | * HT, VHT and HE capabilities should not changes after it was set. It is the | ||
| 4028 | * driver's responsibility to check that. | ||
| 4029 | * | ||
| 4030 | * An NDI station can only be added if the corresponding NMI station has already | ||
| 4031 | * been configured with HT (and possibly VHT and HE) capabilities. It is the | ||
| 4032 | * driver's responsibility to check that. | ||
| 4033 | * | ||
| 4034 | * All NDI stations must be removed before corresponding NMI station is removed. | ||
| 4035 | * Therefore, removing a NMI station implies that the associated NDI station(s) | ||
| 4036 | * (if any) will be removed first. | ||
| 4037 | * | ||
| 4038 | * NAN Dependencies | ||
| 4039 | * ~~~~~~~~~~~~~~~~ | ||
| 4040 | * | ||
| 4041 | * The following diagram shows the dependencies between NAN components. | ||
| 4042 | * An arrow from A to B means A must be started/added before B, and B must be | ||
| 4043 | * stopped/removed before A: | ||
| 4044 | * | ||
| 4045 | * +-------------+ | ||
| 4046 | * | NMI iface |---(local schedule) | ||
| 4047 | * +------+------+ | ||
| 4048 | * / \ | ||
| 4049 | * v v | ||
| 4050 | * +-----------+ +-------------+ | ||
| 4051 | * | NDI iface | | NMI sta |---(peer schedule) | ||
| 4052 | * +-----+-----+ +------+------+ | ||
| 4053 | * \ / | ||
| 4054 | * v v | ||
| 4055 | * +----------+ | ||
| 4056 | * | NDI sta | | ||
| 4057 | * +----------+ | ||
| 4058 | */ | ||
| 4059 | |||
| 3983 | /** | 4060 | /** |
| 3984 | * struct cfg80211_nan_band_config - NAN band specific configuration | 4061 | * struct cfg80211_nan_band_config - NAN band specific configuration |
| 3985 | * | 4062 | * |
| @@ -4050,6 +4127,102 @@ struct cfg80211_nan_conf { · 64 unmodified lines | |||
| 4050 | u16 vendor_elems_len; | 4127 | u16 vendor_elems_len; |
| 4051 | }; | 4128 | }; |
| 4052 | 4129 | ||
| 4130 | #define CFG80211_NAN_SCHED_NUM_TIME_SLOTS 32 | ||
| 4131 | |||
| 4132 | /** | ||
| 4133 | * struct cfg80211_nan_channel - NAN channel configuration | ||
| 4134 | * | ||
| 4135 | * This struct defines a NAN channel configuration | ||
| 4136 | * | ||
| 4137 | * @chandef: the channel definition | ||
| 4138 | * @channel_entry: pointer to the Channel Entry blob as defined in Wi-Fi Aware | ||
| 4139 | * (TM) 4.0 specification Table 100 (Channel Entry format for the NAN | ||
| 4140 | * Availability attribute). | ||
| 4141 | * @rx_nss: number of spatial streams supported on this channel | ||
| 4142 | */ | ||
| 4143 | struct cfg80211_nan_channel { | ||
| 4144 | struct cfg80211_chan_def chandef; | ||
| 4145 | const u8 *channel_entry; | ||
| 4146 | u8 rx_nss; | ||
| 4147 | }; | ||
| 4148 | |||
| 4149 | /** | ||
| 4150 | * struct cfg80211_nan_local_sched - NAN local schedule | ||
| 4151 | * | ||
| 4152 | * This struct defines NAN local schedule parameters | ||
| 4153 | * | ||
| 4154 | * @schedule: a mapping of time slots to chandef indexes in %nan_channels. | ||
| 4155 | * An unscheduled slot will be set to %NL80211_NAN_SCHED_NOT_AVAIL_SLOT. | ||
| 4156 | * @n_channels: number of channel definitions in %nan_channels. | ||
| 4157 | * @nan_avail_blob: pointer to NAN Availability attribute blob. | ||
| 4158 | * See %NL80211_ATTR_NAN_AVAIL_BLOB for more details. | ||
| 4159 | * @nan_avail_blob_len: length of the @nan_avail_blob in bytes. | ||
| 4160 | * @deferred: if true, the command containing this schedule configuration is a | ||
| 4161 | * request from the device to perform an announced schedule update. This | ||
| 4162 | * means that it needs to send the updated NAN availability to the peers, | ||
| 4163 | * and do the actual switch on the right time (i.e. at the end of the slot | ||
| 4164 | * after the slot in which the updated NAN Availability was sent). | ||
| 4165 | * See %NL80211_ATTR_NAN_SCHED_DEFERRED for more details. | ||
| 4166 | * If false, the schedule is applied immediately. | ||
| 4167 | * @nan_channels: array of NAN channel definitions that can be scheduled. | ||
| 4168 | */ | ||
| 4169 | struct cfg80211_nan_local_sched { | ||
| 4170 | u8 schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; | ||
| 4171 | u8 n_channels; | ||
| 4172 | const u8 *nan_avail_blob; | ||
| 4173 | u16 nan_avail_blob_len; | ||
| 4174 | bool deferred; | ||
| 4175 | struct cfg80211_nan_channel nan_channels[] __counted_by(n_channels); | ||
| 4176 | }; | ||
| 4177 | |||
| 4178 | /** | ||
| 4179 | * struct cfg80211_nan_peer_map - NAN peer schedule map | ||
| 4180 | * | ||
| 4181 | * This struct defines a single NAN peer schedule map | ||
| 4182 | * | ||
| 4183 | * @map_id: map ID of this schedule map | ||
| 4184 | * @schedule: a mapping of time slots to chandef indexes in the schedule's | ||
| 4185 | * @nan_channels. Each slot lasts 16TUs. An unscheduled slot will be | ||
| 4186 | * set to %NL80211_NAN_SCHED_NOT_AVAIL_SLOT. | ||
| 4187 | */ | ||
| 4188 | struct cfg80211_nan_peer_map { | ||
| 4189 | u8 map_id; | ||
| 4190 | u8 schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; | ||
| 4191 | }; | ||
| 4192 | |||
| 4193 | #define CFG80211_NAN_MAX_PEER_MAPS 2 | ||
| 4194 | #define CFG80211_NAN_INVALID_MAP_ID 0xff | ||
| 4195 | |||
| 4196 | /** | ||
| 4197 | * struct cfg80211_nan_peer_sched - NAN peer schedule | ||
| 4198 | * | ||
| 4199 | * This struct defines NAN peer schedule parameters for a peer. | ||
| 4200 | * | ||
| 4201 | * @peer_addr: MAC address of the peer (NMI address) | ||
| 4202 | * @seq_id: sequence ID of the peer schedule. | ||
| 4203 | * @committed_dw: committed DW as published by the peer. | ||
| 4204 | * See %NL80211_ATTR_NAN_COMMITTED_DW | ||
| 4205 | * @max_chan_switch: maximum channel switch time in microseconds as published | ||
| 4206 | * by the peer. See %NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME. | ||
| 4207 | * @init_ulw: initial ULWs as published by the peer. | ||
| 4208 | * @ulw_size: number of bytes in @init_ulw. | ||
| 4209 | * @n_channels: number of channel definitions in @nan_channels. | ||
| 4210 | * @nan_channels: array of NAN channel definitions for this schedule. | ||
| 4211 | * @maps: array of peer schedule maps. Unused entries have | ||
| 4212 | * map_id = %CFG80211_NAN_INVALID_MAP_ID. | ||
| 4213 | */ | ||
| 4214 | struct cfg80211_nan_peer_sched { | ||
| 4215 | const u8 *peer_addr; | ||
| 4216 | u8 seq_id; | ||
| 4217 | u16 committed_dw; | ||
| 4218 | u16 max_chan_switch; | ||
| 4219 | const u8 *init_ulw; | ||
| 4220 | u16 ulw_size; | ||
| 4221 | u8 n_channels; | ||
| 4222 | struct cfg80211_nan_channel *nan_channels; | ||
| 4223 | struct cfg80211_nan_peer_map maps[CFG80211_NAN_MAX_PEER_MAPS]; | ||
| 4224 | }; | ||
| 4225 | |||
| 4053 | /** | 4226 | /** |
| 4054 | * enum cfg80211_nan_conf_changes - indicates changed fields in NAN | 4227 | * enum cfg80211_nan_conf_changes - indicates changed fields in NAN |
| 4055 | * configuration | 4228 | * configuration |
| @@ -4830,6 +5003,19 @@ struct mgmt_frame_regs { · 774 unmodified lines | |||
| 4830 | * @nan_change_conf: changes NAN configuration. The changed parameters must | 5003 | * @nan_change_conf: changes NAN configuration. The changed parameters must |
| 4831 | * be specified in @changes (using &enum cfg80211_nan_conf_changes); | 5004 | * be specified in @changes (using &enum cfg80211_nan_conf_changes); |
| 4832 | * All other parameters must be ignored. | 5005 | * All other parameters must be ignored. |
| 5006 | * @nan_set_local_sched: configure the local schedule for NAN. The schedule | ||
| 5007 | * consists of an array of %cfg80211_nan_channel and the schedule itself, | ||
| 5008 | * in which each entry maps each time slot to the channel on which the | ||
| 5009 | * radio should operate on. If the chandef of a NAN channel is not | ||
| 5010 | * changed, the channel entry must also remain unchanged. It is the | ||
| 5011 | * driver's responsibility to verify this. | ||
| 5012 | * @nan_set_peer_sched: configure the peer schedule for NAN. The schedule | ||
| 5013 | * consists of an array of %cfg80211_nan_channel and the schedule itself, | ||
| 5014 | * in which each entry maps each time slot to a channel on which the | ||
| 5015 | * radio should operate on. In addition, it contains more peer's schedule | ||
| 5016 | * information such as committed DW, etc. When updating an existing peer | ||
| 5017 | * schedule, the full new schedule is provided - partial updates are not | ||
| 5018 | * supported, and the new schedule completely replaces the previous one. | ||
| 4833 | * | 5019 | * |
| 4834 | * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS | 5020 | * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS |
| 4835 | * | 5021 | * |
| @@ -5207,7 +5393,12 @@ struct cfg80211_ops { · 371 unmodified lines | |||
| 5207 | struct wireless_dev *wdev, | 5393 | struct wireless_dev *wdev, |
| 5208 | struct cfg80211_nan_conf *conf, | 5394 | struct cfg80211_nan_conf *conf, |
| 5209 | u32 changes); | 5395 | u32 changes); |
| 5210 | 5396 | int (*nan_set_local_sched)(struct wiphy *wiphy, | |
| 5397 | struct wireless_dev *wdev, | ||
| 5398 | struct cfg80211_nan_local_sched *sched); | ||
| 5399 | int (*nan_set_peer_sched)(struct wiphy *wiphy, | ||
| 5400 | struct wireless_dev *wdev, | ||
| 5401 | struct cfg80211_nan_peer_sched *sched); | ||
| 5211 | int (*set_multicast_to_unicast)(struct wiphy *wiphy, | 5402 | int (*set_multicast_to_unicast)(struct wiphy *wiphy, |
| 5212 | struct net_device *dev, | 5403 | struct net_device *dev, |
| 5213 | const bool enabled); | 5404 | const bool enabled); |
| @@ -5836,6 +6027,12 @@ enum wiphy_nan_flags { · 622 unmodified lines | |||
| 5836 | * @max_channel_switch_time: maximum channel switch time in milliseconds. | 6027 | * @max_channel_switch_time: maximum channel switch time in milliseconds. |
| 5837 | * @dev_capabilities: NAN device capabilities as defined in Wi-Fi Aware (TM) | 6028 | * @dev_capabilities: NAN device capabilities as defined in Wi-Fi Aware (TM) |
| 5838 | * specification Table 79 (Capabilities field). | 6029 | * specification Table 79 (Capabilities field). |
| 6030 | * @phy: Band-agnostic capabilities for NAN data interfaces. Since NAN | ||
| 6031 | * operates on multiple channels simultaneously, these capabilities apply | ||
| 6032 | * across all bands. Valid only if NL80211_IFTYPE_NAN_DATA is supported. | ||
| 6033 | * @phy.ht: HT capabilities (mandatory for NAN data) | ||
| 6034 | * @phy.vht: VHT capabilities (optional) | ||
| 6035 | * @phy.he: HE capabilities (optional) | ||
| 5839 | */ | 6036 | */ |
| 5840 | struct wiphy_nan_capa { | 6037 | struct wiphy_nan_capa { |
| 5841 | u32 flags; | 6038 | u32 flags; |
| @@ -5843,6 +6040,11 @@ struct wiphy_nan_capa { · 1 unmodified line | |||
| 5843 | u8 n_antennas; | 6040 | u8 n_antennas; |
| 5844 | u16 max_channel_switch_time; | 6041 | u16 max_channel_switch_time; |
| 5845 | u8 dev_capabilities; | 6042 | u8 dev_capabilities; |
| 6043 | struct { | ||
| 6044 | struct ieee80211_sta_ht_cap ht; | ||
| 6045 | struct ieee80211_sta_vht_cap vht; | ||
| 6046 | struct ieee80211_sta_he_cap he; | ||
| 6047 | } phy; | ||
| 5846 | }; | 6048 | }; |
| 5847 | 6049 | ||
| 5848 | #define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff | 6050 | #define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff |
| @@ -6736,8 +6938,8 @@ enum ieee80211_ap_reg_power { · 887 unmodified lines | |||
| 6736 | * the P2P Device. | 6938 | * the P2P Device. |
| 6737 | * @ps: powersave mode is enabled | 6939 | * @ps: powersave mode is enabled |
| 6738 | * @ps_timeout: dynamic powersave timeout | 6940 | * @ps_timeout: dynamic powersave timeout |
| 6739 | * @ap_unexpected_nlportid: (private) netlink port ID of application | 6941 | * @unexpected_nlportid: (private) netlink port ID of application |
| 6740 | * registered for unexpected class 3 frames (AP mode) | 6942 | * registered for unexpected frames (AP mode or NAN_DATA mode) |
| 6741 | * @conn: (private) cfg80211 software SME connection state machine data | 6943 | * @conn: (private) cfg80211 software SME connection state machine data |
| 6742 | * @connect_keys: (private) keys to set after connection is established | 6944 | * @connect_keys: (private) keys to set after connection is established |
| 6743 | * @conn_bss_type: connecting/connected BSS type | 6945 | * @conn_bss_type: connecting/connected BSS type |
| @@ -6799,7 +7001,7 @@ struct wireless_dev { · 55 unmodified lines | |||
| 6799 | bool ps; | 7001 | bool ps; |
| 6800 | int ps_timeout; | 7002 | int ps_timeout; |
| 6801 | 7003 | ||
| 6802 | u32 ap_unexpected_nlportid; | 7004 | u32 unexpected_nlportid; |
| 6803 | 7005 | ||
| 6804 | u32 owner_nlportid; | 7006 | u32 owner_nlportid; |
| 6805 | bool nl_owner_dead; | 7007 | bool nl_owner_dead; |
| @@ -6859,6 +7061,9 @@ struct wireless_dev { · 53 unmodified lines | |||
| 6859 | } ocb; | 7061 | } ocb; |
| 6860 | struct { | 7062 | struct { |
| 6861 | u8 cluster_id[ETH_ALEN] __aligned(2); | 7063 | u8 cluster_id[ETH_ALEN] __aligned(2); |
| 7064 | u8 n_channels; | ||
| 7065 | struct cfg80211_chan_def *chandefs; | ||
| 7066 | bool sched_update_pending; | ||
| 6862 | } nan; | 7067 | } nan; |
| 6863 | } u; | 7068 | } u; |
| 6864 | 7069 | ||
| @@ -9367,9 +9572,10 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, · 2502 unmodified lines | |||
| 9367 | * @addr: the transmitter address | 9572 | * @addr: the transmitter address |
| 9368 | * @gfp: context flags | 9573 | * @gfp: context flags |
| 9369 | * | 9574 | * |
| 9370 | * This function is used in AP mode (only!) to inform userspace that | 9575 | * This function is used in AP mode to inform userspace that a spurious |
| 9371 | * a spurious class 3 frame was received, to be able to deauth the | 9576 | * class 3 frame was received, to be able to deauth the sender. |
| 9372 | * sender. | 9577 | * It is also used in NAN_DATA mode to report frames from unknown peers |
| 9578 | * (A2 not assigned to any active NDP), per Wi-Fi Aware (TM) 4.0 specification 6.2.5. | ||
| 9373 | * Return: %true if the frame was passed to userspace (or this failed | 9579 | * Return: %true if the frame was passed to userspace (or this failed |
| 9374 | * for a reason other than not having a subscription.) | 9580 | * for a reason other than not having a subscription.) |
| 9375 | */ | 9581 | */ |
| @@ -10016,6 +10222,18 @@ void cfg80211_nan_func_terminated(struct wireless_dev *wdev, · 640 unmodified lines | |||
| 10016 | enum nl80211_nan_func_term_reason reason, | 10222 | enum nl80211_nan_func_term_reason reason, |
| 10017 | u64 cookie, gfp_t gfp); | 10223 | u64 cookie, gfp_t gfp); |
| 10018 | 10224 | ||
| 10225 | /** | ||
| 10226 | * cfg80211_nan_sched_update_done - notify deferred schedule update completion | ||
| 10227 | * @wdev: the wireless device reporting the event | ||
| 10228 | * @success: whether or not the schedule update was successful | ||
| 10229 | * @gfp: allocation flags | ||
| 10230 | * | ||
| 10231 | * This function notifies user space that a deferred local NAN schedule update | ||
| 10232 | * (requested with %NL80211_ATTR_NAN_SCHED_DEFERRED) has been completed. | ||
| 10233 | */ | ||
| 10234 | void cfg80211_nan_sched_update_done(struct wireless_dev *wdev, bool success, | ||
| 10235 | gfp_t gfp); | ||
| 10236 | |||
| 10019 | /* ethtool helper */ | 10237 | /* ethtool helper */ |
| 10020 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); | 10238 | void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info); |
| 10021 | 10239 | ||
| @@ -10356,6 +10574,39 @@ void cfg80211_nan_cluster_joined(struct wireless_dev *wdev, · 334 unmodified lines | |||
| 10356 | const u8 *cluster_id, bool new_cluster, | 10574 | const u8 *cluster_id, bool new_cluster, |
| 10357 | gfp_t gfp); | 10575 | gfp_t gfp); |
| 10358 | 10576 | ||
| 10577 | /** | ||
| 10578 | * cfg80211_nan_ulw_update - Notify user space about ULW update | ||
| 10579 | * @wdev: Pointer to the wireless device structure | ||
| 10580 | * @ulw: Pointer to the ULW blob data | ||
| 10581 | * @ulw_len: Length of the ULW blob in bytes | ||
| 10582 | * @gfp: Memory allocation flags | ||
| 10583 | * | ||
| 10584 | * This function is used by drivers to notify user space when the device's | ||
| 10585 | * ULW (Unaligned Schedule) blob has been updated. User space can use this | ||
| 10586 | * blob to attach to frames sent to peers. | ||
| 10587 | */ | ||
| 10588 | void cfg80211_nan_ulw_update(struct wireless_dev *wdev, | ||
| 10589 | const u8 *ulw, size_t ulw_len, gfp_t gfp); | ||
| 10590 | |||
| 10591 | /** | ||
| 10592 | * cfg80211_nan_channel_evac - Notify user space about NAN channel evacuation | ||
| 10593 | * @wdev: Pointer to the wireless device structure | ||
| 10594 | * @chandef: Pointer to the channel definition of the NAN channel that was | ||
| 10595 | * evacuated | ||
| 10596 | * @gfp: Memory allocation flags | ||
| 10597 | * | ||
| 10598 | * This function is used by drivers to notify user space when a NAN | ||
| 10599 | * channel has been evacuated (i.e. ULWed) due to channel resource conflicts | ||
| 10600 | * with other interfaces. | ||
| 10601 | * This can happen when another interface sharing the channel resource with NAN | ||
| 10602 | * needs to move to a different channel (e.g. due to channel switch or link | ||
| 10603 | * switch). User space may reconfigure the local schedule to exclude the | ||
| 10604 | * evacuated channel. | ||
| 10605 | */ | ||
| 10606 | void cfg80211_nan_channel_evac(struct wireless_dev *wdev, | ||
| 10607 | const struct cfg80211_chan_def *chandef, | ||
| 10608 | gfp_t gfp); | ||
| 10609 | |||
| 10359 | #ifdef CONFIG_CFG80211_DEBUGFS | 10610 | #ifdef CONFIG_CFG80211_DEBUGFS |
| 10360 | /** | 10611 | /** |
| 10361 | * wiphy_locked_debugfs_read - do a locked read in debugfs | 10612 | * wiphy_locked_debugfs_read - do a locked read in debugfs |
| @@ -906,8 +906,9 @@ · 905 unmodified lines | |||
| 906 | * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP | 906 | * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP |
| 907 | * (or GO) interface (i.e. hostapd) to ask for unexpected frames to | 907 | * (or GO) interface (i.e. hostapd) to ask for unexpected frames to |
| 908 | * implement sending deauth to stations that send unexpected class 3 | 908 | * implement sending deauth to stations that send unexpected class 3 |
| 909 | * frames. Also used as the event sent by the kernel when such a frame | 909 | * frames. For NAN_DATA interfaces, this is used to report frames from |
| 910 | * is received. | 910 | * unknown peers (A2 not assigned to any active NDP). |
| 911 | * Also used as the event sent by the kernel when such a frame is received. | ||
| 911 | * For the event, the %NL80211_ATTR_MAC attribute carries the TA and | 912 | * For the event, the %NL80211_ATTR_MAC attribute carries the TA and |
| 912 | * other attributes like the interface index are present. | 913 | * other attributes like the interface index are present. |
| 913 | * If used as the command it must have an interface index and you can | 914 | * If used as the command it must have an interface index and you can |
| @@ -1367,6 +1368,53 @@ · 453 unmodified lines | |||
| 1367 | * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel | 1368 | * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel |
| 1368 | * definition is also sent. | 1369 | * definition is also sent. |
| 1369 | * | 1370 | * |
| 1371 | * @NL80211_CMD_NAN_SET_LOCAL_SCHED: Set the local NAN schedule. NAN must be | ||
| 1372 | * operational (%NL80211_CMD_START_NAN was executed). Must contain | ||
| 1373 | * %NL80211_ATTR_NAN_TIME_SLOTS and %NL80211_ATTR_NAN_AVAIL_BLOB, but | ||
| 1374 | * %NL80211_ATTR_NAN_CHANNEL is optional (for example in case of a channel | ||
| 1375 | * removal, that channel won't be provided). | ||
| 1376 | * If %NL80211_ATTR_NAN_SCHED_DEFERRED is set, the command is a request | ||
| 1377 | * from the device to perform an announced schedule update. See | ||
| 1378 | * %NL80211_ATTR_NAN_SCHED_DEFERRED for more details. | ||
| 1379 | * If not set, the schedule should be applied immediately. | ||
| 1380 | * @NL80211_CMD_NAN_SCHED_UPDATE_DONE: Event sent to user space to notify that | ||
| 1381 | * a deferred local NAN schedule update (requested with | ||
| 1382 | * %NL80211_CMD_NAN_SET_LOCAL_SCHED and %NL80211_ATTR_NAN_SCHED_DEFERRED) | ||
| 1383 | * has been completed. The presence of %NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS | ||
| 1384 | * indicates that the update was successful. | ||
| 1385 | * @NL80211_CMD_NAN_SET_PEER_SCHED: Set the peer NAN schedule. NAN | ||
| 1386 | * must be operational (%NL80211_CMD_START_NAN was executed). | ||
| 1387 | * Required attributes: %NL80211_ATTR_MAC (peer NMI address) and | ||
| 1388 | * %NL80211_ATTR_NAN_COMMITTED_DW. | ||
| 1389 | * Optionally, the full schedule can be provided by including all of: | ||
| 1390 | * %NL80211_ATTR_NAN_SEQ_ID, %NL80211_ATTR_NAN_CHANNEL (one or more), and | ||
| 1391 | * %NL80211_ATTR_NAN_PEER_MAPS (see &enum nl80211_nan_peer_map_attrs). | ||
| 1392 | * If any of these three optional attributes is provided, all three must | ||
| 1393 | * be provided. | ||
| 1394 | * Each peer channel must be compatible with at least one local channel | ||
| 1395 | * set by %NL80211_CMD_SET_LOCAL_NAN_SCHED. Different maps must not | ||
| 1396 | * contain compatible channels. | ||
| 1397 | * For single-radio devices (n_radio <= 1), different maps must not | ||
| 1398 | * schedule the same time slot, as the device cannot operate on multiple | ||
| 1399 | * channels simultaneously. | ||
| 1400 | * When updating an existing peer schedule, the full new schedule must be | ||
| 1401 | * provided - partial updates are not supported. The new schedule will | ||
| 1402 | * completely replace the previous one. | ||
| 1403 | * The peer schedule is automatically removed when the NMI station is | ||
| 1404 | * removed. | ||
| 1405 | * @NL80211_CMD_NAN_ULW_UPDATE: Notification from the driver to user space | ||
| 1406 | * with the updated ULW blob of the device. User space can use this blob | ||
| 1407 | * to attach to frames sent to peers. This notification contains | ||
| 1408 | * %NL80211_ATTR_NAN_ULW with the ULW blob. | ||
| 1409 | * @NL80211_CMD_NAN_CHANNEL_EVAC: Notification to indicate that a NAN | ||
| 1410 | * channel has been evacuated due to resource conflicts with other | ||
| 1411 | * interfaces. This can happen when another interface sharing the channel | ||
| 1412 | * resource with NAN needs to move to a different channel (e.g., channel | ||
| 1413 | * switch or link switch on a BSS interface). | ||
| 1414 | * The notification contains %NL80211_ATTR_NAN_CHANNEL attribute | ||
| 1415 | * identifying the evacuated channel. | ||
| 1416 | * User space may reconfigure the local schedule in response to this | ||
| 1417 | * notification. | ||
| 1370 | * @NL80211_CMD_MAX: highest used command number | 1418 | * @NL80211_CMD_MAX: highest used command number |
| 1371 | * @__NL80211_CMD_AFTER_LAST: internal use | 1419 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 1372 | */ | 1420 | */ |
| @@ -1632,6 +1680,16 @@ enum nl80211_commands { · 259 unmodified lines | |||
| 1632 | 1680 | ||
| 1633 | NL80211_CMD_INCUMBENT_SIGNAL_DETECT, | 1681 | NL80211_CMD_INCUMBENT_SIGNAL_DETECT, |
| 1634 | 1682 | ||
| 1683 | NL80211_CMD_NAN_SET_LOCAL_SCHED, | ||
| 1684 | |||
| 1685 | NL80211_CMD_NAN_SCHED_UPDATE_DONE, | ||
| 1686 | |||
| 1687 | NL80211_CMD_NAN_SET_PEER_SCHED, | ||
| 1688 | |||
| 1689 | NL80211_CMD_NAN_ULW_UPDATE, | ||
| 1690 | |||
| 1691 | NL80211_CMD_NAN_CHANNEL_EVAC, | ||
| 1692 | |||
| 1635 | /* add new commands above here */ | 1693 | /* add new commands above here */ |
| 1636 | 1694 | ||
| 1637 | /* used to define NL80211_CMD_MAX below */ | 1695 | /* used to define NL80211_CMD_MAX below */ |
| @@ -2659,7 +2717,8 @@ enum nl80211_commands { · 1021 unmodified lines | |||
| 2659 | * a flow is assigned on each round of the DRR scheduler. | 2717 | * a flow is assigned on each round of the DRR scheduler. |
| 2660 | * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from | 2718 | * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from |
| 2661 | * association request when used with NL80211_CMD_NEW_STATION). Can be set | 2719 | * association request when used with NL80211_CMD_NEW_STATION). Can be set |
| 2662 | * only if %NL80211_STA_FLAG_WME is set. | 2720 | * only if %NL80211_STA_FLAG_WME is set (except for NAN, which uses WME |
| 2721 | * anyway). | ||
| 2663 | * | 2722 | * |
| 2664 | * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include | 2723 | * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include |
| 2665 | * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing | 2724 | * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing |
| @@ -2991,6 +3050,82 @@ enum nl80211_commands { · 325 unmodified lines | |||
| 2991 | * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable | 3050 | * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable |
| 2992 | * this feature during association. This is a flag attribute. | 3051 | * this feature during association. This is a flag attribute. |
| 2993 | * Currently only supported in mac80211 drivers. | 3052 | * Currently only supported in mac80211 drivers. |
| 3053 | * @NL80211_ATTR_NAN_CHANNEL: This is a nested attribute. There can be multiple | ||
| 3054 | * attributes of this type, each one represents a channel definition and | ||
| 3055 | * consists of top-level attributes like %NL80211_ATTR_WIPHY_FREQ. | ||
| 3056 | * When used with %NL80211_CMD_NAN_SET_LOCAL_SCHED, it specifies | ||
| 3057 | * the channel definitions on which the radio needs to operate during | ||
| 3058 | * specific time slots. All of the channel definitions should be mutually | ||
| 3059 | * incompatible. With this command, %NL80211_ATTR_NAN_CHANNEL_ENTRY and | ||
| 3060 | * %NL80211_ATTR_NAN_RX_NSS are mandatory. | ||
| 3061 | * When used with %NL80211_CMD_NAN_SET_PEER_SCHED, it configures the | ||
| 3062 | * peer NAN channels. In that case, the channel definitions can be | ||
| 3063 | * compatible to each other, or even identical just with different RX NSS. | ||
| 3064 | * With this command, %NL80211_ATTR_NAN_CHANNEL_ENTRY and | ||
| 3065 | * %NL80211_ATTR_NAN_RX_NSS are mandatory. | ||
| 3066 | * The number of channels should fit the current configuration of channels | ||
| 3067 | * and the possible interface combinations. | ||
| 3068 | * If an existing NAN channel is changed but the chandef isn't, the | ||
| 3069 | * channel entry must also remain unchanged. | ||
| 3070 | * When used with %NL80211_CMD_NAN_CHANNEL_EVAC, this identifies the | ||
| 3071 | * channels that were evacuated. | ||
| 3072 | * @NL80211_ATTR_NAN_CHANNEL_ENTRY: a byte array of 6 bytes. contains the | ||
| 3073 | * Channel Entry as defined in Wi-Fi Aware (TM) 4.0 specification Table | ||
| 3074 | * 100 (Channel Entry format for the NAN Availability attribute). | ||
| 3075 | * @NL80211_ATTR_NAN_RX_NSS: (u8) RX NSS used for a NAN channel. This is | ||
| 3076 | * used with %NL80211_ATTR_NAN_CHANNEL when configuring NAN channels with | ||
| 3077 | * %NL80211_CMD_NAN_SET_LOCAL_SCHED or %NL80211_CMD_NAN_SET_PEER_SCHED. | ||
| 3078 | * @NL80211_ATTR_NAN_TIME_SLOTS: an array of u8 values and 32 cells. each value | ||
| 3079 | * maps a time slot to the chandef on which the radio should operate on in | ||
| 3080 | * that time. %NL80211_NAN_SCHED_NOT_AVAIL_SLOT indicates unscheduled. | ||
| 3081 | * The chandef is represented using its index, where the index is the | ||
| 3082 | * sequential number of the %NL80211_ATTR_NAN_CHANNEL attribute within all | ||
| 3083 | * the attributes of this type. | ||
| 3084 | * Each slots spans over 16TUs, hence the entire schedule spans over | ||
| 3085 | * 512TUs. Other slot durations and periods are currently not supported. | ||
| 3086 | * @NL80211_ATTR_NAN_AVAIL_BLOB: (Binary) The NAN Availability attribute blob, | ||
| 3087 | * including the attribute header, as defined in Wi-Fi Aware (TM) 4.0 | ||
| 3088 | * specification Table 93 (NAN Availability attribute format). Required with | ||
| 3089 | * %NL80211_CMD_NAN_SET_LOCAL_SCHED to provide the raw NAN Availability | ||
| 3090 | * attribute. Used by the device to publish Schedule Update NAFs. | ||
| 3091 | * @NL80211_ATTR_NAN_SCHED_DEFERRED: Flag attribute used with | ||
| 3092 | * %NL80211_CMD_NAN_SET_LOCAL_SCHED. When present, the command is a | ||
| 3093 | * request from the device to perform an announced schedule update. This | ||
| 3094 | * means that it needs to send the updated NAN availability to the peers, | ||
| 3095 | * and do the actual switch on the right time (i.e. at the end of the slot | ||
| 3096 | * after the slot in which the updated NAN Availability was sent). Since | ||
| 3097 | * the slots management is done in the device, the update to the peers | ||
| 3098 | * needs to be sent by the device, so it knows the actual switch time. | ||
| 3099 | * If the flag is not set, the schedule should be applied immediately. | ||
| 3100 | * When this flag is set, the total number of NAN channels from both the | ||
| 3101 | * old and new schedules must not exceed the allowed number of local NAN | ||
| 3102 | * channels, because with deferred scheduling the old channels cannot be | ||
| 3103 | * removed before adding the new ones to free up space. | ||
| 3104 | * @NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS: flag attribute used with | ||
| 3105 | * %NL80211_CMD_NAN_SCHED_UPDATE_DONE to indicate that the deferred | ||
| 3106 | * schedule update completed successfully. If this flag is not present, | ||
| 3107 | * the update failed. | ||
| 3108 | * @NL80211_ATTR_NAN_NMI_MAC: The address of the NMI station to which this NDI | ||
| 3109 | * station belongs. Used with %NL80211_CMD_NEW_STATION when adding an NDI | ||
| 3110 | * station. | ||
| 3111 | * @NL80211_ATTR_NAN_ULW: (Binary) The initial ULW(s) as published by the | ||
| 3112 | * peer, as defined in the Wi-Fi Aware (TM) 4.0 specification Table 109 | ||
| 3113 | * (Unaligned Schedule attribute format). Used to configure the device | ||
| 3114 | * with the initial ULW(s) of a peer, before the device starts tracking it. | ||
| 3115 | * @NL80211_ATTR_NAN_COMMITTED_DW: (u16) The committed DW as published by the | ||
| 3116 | * peer, as defined in the Wi-Fi Aware (TM) 4.0 specification Table 80 | ||
| 3117 | * (Committed DW Information field format). | ||
| 3118 | * @NL80211_ATTR_NAN_SEQ_ID: (u8) The sequence ID of the peer schedule that | ||
| 3119 | * %NL80211_CMD_NAN_SET_PEER_SCHED defines. The device follows the | ||
| 3120 | * sequence ID in the frames to identify newer schedules. Once a schedule | ||
| 3121 | * with a higher sequence ID is received, the device may stop communicating | ||
| 3122 | * with that peer until a new peer schedule with a matching sequence ID is | ||
| 3123 | * received. | ||
| 3124 | * @NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME: (u16) The maximum channel switch | ||
| 3125 | * time, in microseconds. | ||
| 3126 | * @NL80211_ATTR_NAN_PEER_MAPS: Nested array of peer schedule maps. | ||
| 3127 | * Used with %NL80211_CMD_NAN_SET_PEER_SCHED. Contains up to 2 entries, | ||
| 3128 | * each containing nested attributes from &enum nl80211_nan_peer_map_attrs. | ||
| 2994 | * | 3129 | * |
| 2995 | * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying | 3130 | * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying |
| 2996 | * the signal interference bitmap detected on the operating bandwidth for | 3131 | * the signal interference bitmap detected on the operating bandwidth for |
| @@ -3582,6 +3717,22 @@ enum nl80211_attrs { · 585 unmodified lines | |||
| 3582 | 3717 | ||
| 3583 | NL80211_ATTR_UHR_OPERATION, | 3718 | NL80211_ATTR_UHR_OPERATION, |
| 3584 | 3719 | ||
| 3720 | NL80211_ATTR_NAN_CHANNEL, | ||
| 3721 | NL80211_ATTR_NAN_CHANNEL_ENTRY, | ||
| 3722 | NL80211_ATTR_NAN_TIME_SLOTS, | ||
| 3723 | NL80211_ATTR_NAN_RX_NSS, | ||
| 3724 | NL80211_ATTR_NAN_AVAIL_BLOB, | ||
| 3725 | NL80211_ATTR_NAN_SCHED_DEFERRED, | ||
| 3726 | NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS, | ||
| 3727 | |||
| 3728 | NL80211_ATTR_NAN_NMI_MAC, | ||
| 3729 | |||
| 3730 | NL80211_ATTR_NAN_ULW, | ||
| 3731 | NL80211_ATTR_NAN_COMMITTED_DW, | ||
| 3732 | NL80211_ATTR_NAN_SEQ_ID, | ||
| 3733 | NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME, | ||
| 3734 | NL80211_ATTR_NAN_PEER_MAPS, | ||
| 3735 | |||
| 3585 | /* add attributes here, update the policy in nl80211.c */ | 3736 | /* add attributes here, update the policy in nl80211.c */ |
| 3586 | 3737 | ||
| 3587 | __NL80211_ATTR_AFTER_LAST, | 3738 | __NL80211_ATTR_AFTER_LAST, |
| @@ -3675,6 +3826,9 @@ enum nl80211_attrs { · 87 unmodified lines | |||
| 3675 | * @NL80211_IFTYPE_OCB: Outside Context of a BSS | 3826 | * @NL80211_IFTYPE_OCB: Outside Context of a BSS |
| 3676 | * This mode corresponds to the MIB variable dot11OCBActivated=true | 3827 | * This mode corresponds to the MIB variable dot11OCBActivated=true |
| 3677 | * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) | 3828 | * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) |
| 3829 | * @NL80211_IFTYPE_NAN_DATA: NAN data interface type (netdev); NAN data | ||
| 3830 | * interfaces can only be brought up (IFF_UP) when a NAN interface | ||
| 3831 | * already exists and NAN has been started (using %NL80211_CMD_START_NAN). | ||
| 3678 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 3832 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
| 3679 | * @NUM_NL80211_IFTYPES: number of defined interface types | 3833 | * @NUM_NL80211_IFTYPES: number of defined interface types |
| 3680 | * | 3834 | * |
| @@ -3696,6 +3850,7 @@ enum nl80211_iftype { · 15 unmodified lines | |||
| 3696 | NL80211_IFTYPE_P2P_DEVICE, | 3850 | NL80211_IFTYPE_P2P_DEVICE, |
| 3697 | NL80211_IFTYPE_OCB, | 3851 | NL80211_IFTYPE_OCB, |
| 3698 | NL80211_IFTYPE_NAN, | 3852 | NL80211_IFTYPE_NAN, |
| 3853 | NL80211_IFTYPE_NAN_DATA, | ||
| 3699 | 3854 | ||
| 3700 | /* keep last */ | 3855 | /* keep last */ |
| 3701 | NUM_NL80211_IFTYPES, | 3856 | NUM_NL80211_IFTYPES, |
| @@ -4384,6 +4539,46 @@ enum nl80211_band_attr { · 682 unmodified lines | |||
| 4384 | 4539 | ||
| 4385 | #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA | 4540 | #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA |
| 4386 | 4541 | ||
| 4542 | /** | ||
| 4543 | * enum nl80211_nan_phy_cap_attr - NAN PHY capabilities attributes | ||
| 4544 | * @__NL80211_NAN_PHY_CAP_ATTR_INVALID: attribute number 0 is reserved | ||
| 4545 | * @NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET: 16-byte attribute containing HT MCS set | ||
| 4546 | * @NL80211_NAN_PHY_CAP_ATTR_HT_CAPA: HT capabilities (u16) | ||
| 4547 | * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR: HT A-MPDU factor (u8) | ||
| 4548 | * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY: HT A-MPDU density (u8) | ||
| 4549 | * @NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET: 8-byte attribute containing VHT MCS set | ||
| 4550 | * @NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA: VHT capabilities (u32) | ||
| 4551 | * @NL80211_NAN_PHY_CAP_ATTR_HE_MAC: HE MAC capabilities | ||
| 4552 | * @NL80211_NAN_PHY_CAP_ATTR_HE_PHY: HE PHY capabilities | ||
| 4553 | * @NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET: HE supported NSS/MCS combinations | ||
| 4554 | * @NL80211_NAN_PHY_CAP_ATTR_HE_PPE: HE PPE thresholds | ||
| 4555 | * @NL80211_NAN_PHY_CAP_ATTR_MAX: highest NAN PHY cap attribute number | ||
| 4556 | * @__NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST: internal use | ||
| 4557 | */ | ||
| 4558 | enum nl80211_nan_phy_cap_attr { | ||
| 4559 | __NL80211_NAN_PHY_CAP_ATTR_INVALID, | ||
| 4560 | |||
| 4561 | /* HT capabilities */ | ||
| 4562 | NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET, | ||
| 4563 | NL80211_NAN_PHY_CAP_ATTR_HT_CAPA, | ||
| 4564 | NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR, | ||
| 4565 | NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY, | ||
| 4566 | |||
| 4567 | /* VHT capabilities */ | ||
| 4568 | NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET, | ||
| 4569 | NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA, | ||
| 4570 | |||
| 4571 | /* HE capabilities */ | ||
| 4572 | NL80211_NAN_PHY_CAP_ATTR_HE_MAC, | ||
| 4573 | NL80211_NAN_PHY_CAP_ATTR_HE_PHY, | ||
| 4574 | NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET, | ||
| 4575 | NL80211_NAN_PHY_CAP_ATTR_HE_PPE, | ||
| 4576 | |||
| 4577 | /* keep last */ | ||
| 4578 | __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST, | ||
| 4579 | NL80211_NAN_PHY_CAP_ATTR_MAX = __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST - 1 | ||
| 4580 | }; | ||
| 4581 | |||
| 4387 | /** | 4582 | /** |
| 4388 | * enum nl80211_wmm_rule - regulatory wmm rule | 4583 | * enum nl80211_wmm_rule - regulatory wmm rule |
| 4389 | * | 4584 | * |
| @@ -8557,6 +8752,8 @@ enum nl80211_s1g_short_beacon_attrs { · 4167 unmodified lines | |||
| 8557 | * @NL80211_NAN_CAPA_CAPABILITIES: u8 attribute containing the | 8752 | * @NL80211_NAN_CAPA_CAPABILITIES: u8 attribute containing the |
| 8558 | * capabilities of the device as defined in Wi-Fi Aware (TM) | 8753 | * capabilities of the device as defined in Wi-Fi Aware (TM) |
| 8559 | * specification Table 79 (Capabilities field). | 8754 | * specification Table 79 (Capabilities field). |
| 8755 | * @NL80211_NAN_CAPA_PHY: nested attribute containing band-agnostic | ||
| 8756 | * capabilities for NAN data path. See &enum nl80211_nan_phy_cap_attr. | ||
| 8560 | * @__NL80211_NAN_CAPABILITIES_LAST: Internal | 8757 | * @__NL80211_NAN_CAPABILITIES_LAST: Internal |
| 8561 | * @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute. | 8758 | * @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute. |
| 8562 | */ | 8759 | */ |
| @@ -8569,9 +8766,38 @@ enum nl80211_nan_capabilities { · 6 unmodified lines | |||
| 8569 | NL80211_NAN_CAPA_NUM_ANTENNAS, | 8766 | NL80211_NAN_CAPA_NUM_ANTENNAS, |
| 8570 | NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME, | 8767 | NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME, |
| 8571 | NL80211_NAN_CAPA_CAPABILITIES, | 8768 | NL80211_NAN_CAPA_CAPABILITIES, |
| 8769 | NL80211_NAN_CAPA_PHY, | ||
| 8572 | /* keep last */ | 8770 | /* keep last */ |
| 8573 | __NL80211_NAN_CAPABILITIES_LAST, | 8771 | __NL80211_NAN_CAPABILITIES_LAST, |
| 8574 | NL80211_NAN_CAPABILITIES_MAX = __NL80211_NAN_CAPABILITIES_LAST - 1, | 8772 | NL80211_NAN_CAPABILITIES_MAX = __NL80211_NAN_CAPABILITIES_LAST - 1, |
| 8575 | }; | 8773 | }; |
| 8576 | 8774 | ||
| 8775 | /** | ||
| 8776 | * enum nl80211_nan_peer_map_attrs - NAN peer schedule map attributes | ||
| 8777 | * | ||
| 8778 | * Nested attributes used within %NL80211_ATTR_NAN_PEER_MAPS to define | ||
| 8779 | * individual peer schedule maps. | ||
| 8780 | * | ||
| 8781 | * @__NL80211_NAN_PEER_MAP_ATTR_INVALID: Invalid | ||
| 8782 | * @NL80211_NAN_PEER_MAP_ATTR_MAP_ID: (u8) The map ID for this schedule map. | ||
| 8783 | * @NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS: An array of u8 values with 32 cells. | ||
| 8784 | * Each value maps a time slot to a channel index within the schedule's | ||
| 8785 | * channel list (%NL80211_ATTR_NAN_CHANNEL attributes). | ||
| 8786 | * %NL80211_NAN_SCHED_NOT_AVAIL_SLOT indicates unscheduled. | ||
| 8787 | * @__NL80211_NAN_PEER_MAP_ATTR_LAST: Internal | ||
| 8788 | * @NL80211_NAN_PEER_MAP_ATTR_MAX: Highest peer map attribute | ||
| 8789 | */ | ||
| 8790 | enum nl80211_nan_peer_map_attrs { | ||
| 8791 | __NL80211_NAN_PEER_MAP_ATTR_INVALID, | ||
| 8792 | |||
| 8793 | NL80211_NAN_PEER_MAP_ATTR_MAP_ID, | ||
| 8794 | NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS, | ||
| 8795 | |||
| 8796 | /* keep last */ | ||
| 8797 | __NL80211_NAN_PEER_MAP_ATTR_LAST, | ||
| 8798 | NL80211_NAN_PEER_MAP_ATTR_MAX = __NL80211_NAN_PEER_MAP_ATTR_LAST - 1, | ||
| 8799 | }; | ||
| 8800 | |||
| 8801 | #define NL80211_NAN_SCHED_NOT_AVAIL_SLOT 0xff | ||
| 8802 | |||
| 8577 | #endif /* __LINUX_NL80211_H */ | 8803 | #endif /* __LINUX_NL80211_H */ |
| @@ -718,6 +718,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct wireless_dev *wdev, · 717 unmodified lines | |||
| 718 | case NL80211_IFTYPE_P2P_CLIENT: | 718 | case NL80211_IFTYPE_P2P_CLIENT: |
| 719 | case NL80211_IFTYPE_P2P_GO: | 719 | case NL80211_IFTYPE_P2P_GO: |
| 720 | case NL80211_IFTYPE_OCB: | 720 | case NL80211_IFTYPE_OCB: |
| 721 | case NL80211_IFTYPE_NAN_DATA: | ||
| 721 | /* shouldn't happen */ | 722 | /* shouldn't happen */ |
| 722 | WARN_ON_ONCE(1); | 723 | WARN_ON_ONCE(1); |
| 723 | break; | 724 | break; |
| @@ -2140,12 +2141,13 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, · 1416 unmodified lines | |||
| 2140 | return -EINVAL; | 2141 | return -EINVAL; |
| 2141 | 2142 | ||
| 2142 | if (params->ht_capa) | 2143 | if (params->ht_capa) |
| 2143 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2144 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, &sband->ht_cap, |
| 2144 | params->ht_capa, link_sta); | 2145 | params->ht_capa, link_sta); |
| 2145 | 2146 | ||
| 2146 | /* VHT can override some HT caps such as the A-MSDU max length */ | 2147 | /* VHT can override some HT caps such as the A-MSDU max length */ |
| 2147 | if (params->vht_capa) | 2148 | if (params->vht_capa) |
| 2148 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 2149 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 2150 | &sband->vht_cap, | ||
| 2149 | params->vht_capa, NULL, | 2151 | params->vht_capa, NULL, |
| 2150 | link_sta); | 2152 | link_sta); |
| 2151 | 2153 | ||
| @@ -166,6 +166,13 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local, · 165 unmodified lines | |||
| 166 | for_each_chanctx_user_all(local, ctx, &iter) | 166 | for_each_chanctx_user_all(local, ctx, &iter) |
| 167 | num++; | 167 | num++; |
| 168 | 168 | ||
| 169 | /* | ||
| 170 | * This ctx is in the process of getting used, | ||
| 171 | * take it into consideration | ||
| 172 | */ | ||
| 173 | if (ctx->will_be_used) | ||
| 174 | num++; | ||
| 175 | |||
| 169 | return num; | 176 | return num; |
| 170 | } | 177 | } |
| 171 | 178 | ||
| @@ -447,74 +454,94 @@ ieee80211_get_max_required_bw(struct ieee80211_link_data *link) · 275 unmodified lines | |||
| 447 | return max_bw; | 454 | return max_bw; |
| 448 | } | 455 | } |
| 449 | 456 | ||
| 457 | static enum nl80211_chan_width | ||
| 458 | ieee80211_get_width_of_link(struct ieee80211_link_data *link) | ||
| 459 | { | ||
| 460 | struct ieee80211_local *local = link->sdata->local; | ||
| 461 | |||
| 462 | switch (link->sdata->vif.type) { | ||
| 463 | case NL80211_IFTYPE_STATION: | ||
| 464 | if (!link->sdata->vif.cfg.assoc) { | ||
| 465 | /* | ||
| 466 | * The AP's sta->bandwidth may not yet be set | ||
| 467 | * at this point (pre-association), so simply | ||
| 468 | * take the width from the chandef. We cannot | ||
| 469 | * have TDLS peers yet (only after association). | ||
| 470 | */ | ||
| 471 | return link->conf->chanreq.oper.width; | ||
| 472 | } | ||
| 473 | /* | ||
| 474 | * otherwise just use min_def like in AP, depending on what | ||
| 475 | * we currently think the AP STA (and possibly TDLS peers) | ||
| 476 | * require(s) | ||
| 477 | */ | ||
| 478 | fallthrough; | ||
| 479 | case NL80211_IFTYPE_AP: | ||
| 480 | case NL80211_IFTYPE_AP_VLAN: | ||
| 481 | return ieee80211_get_max_required_bw(link); | ||
| 482 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 483 | case NL80211_IFTYPE_NAN: | ||
| 484 | break; | ||
| 485 | case NL80211_IFTYPE_MONITOR: | ||
| 486 | WARN_ON_ONCE(!ieee80211_hw_check(&local->hw, | ||
| 487 | NO_VIRTUAL_MONITOR)); | ||
| 488 | fallthrough; | ||
| 489 | case NL80211_IFTYPE_ADHOC: | ||
| 490 | case NL80211_IFTYPE_MESH_POINT: | ||
| 491 | case NL80211_IFTYPE_OCB: | ||
| 492 | return link->conf->chanreq.oper.width; | ||
| 493 | case NL80211_IFTYPE_WDS: | ||
| 494 | case NL80211_IFTYPE_UNSPECIFIED: | ||
| 495 | case NUM_NL80211_IFTYPES: | ||
| 496 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 497 | case NL80211_IFTYPE_P2P_GO: | ||
| 498 | case NL80211_IFTYPE_NAN_DATA: | ||
| 499 | WARN_ON_ONCE(1); | ||
| 500 | break; | ||
| 501 | } | ||
| 502 | |||
| 503 | /* Take the lowest possible, so it won't change the max width */ | ||
| 504 | return NL80211_CHAN_WIDTH_20_NOHT; | ||
| 505 | } | ||
| 506 | |||
| 450 | static enum nl80211_chan_width | 507 | static enum nl80211_chan_width |
| 451 | ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | 508 | ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, |
| 452 | struct ieee80211_chanctx *ctx, | 509 | struct ieee80211_chanctx *ctx, |
| 453 | struct ieee80211_link_data *rsvd_for, | 510 | struct ieee80211_link_data *rsvd_for, |
| 454 | bool check_reserved) | 511 | bool check_reserved) |
| 455 | { | 512 | { |
| 456 | struct ieee80211_sub_if_data *sdata; | ||
| 457 | struct ieee80211_link_data *link; | ||
| 458 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; | 513 | enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT; |
| 514 | struct ieee80211_chanctx_user_iter iter; | ||
| 515 | struct ieee80211_sub_if_data *sdata; | ||
| 516 | enum nl80211_chan_width width; | ||
| 459 | 517 | ||
| 460 | if (WARN_ON(check_reserved && rsvd_for)) | 518 | if (WARN_ON(check_reserved && rsvd_for)) |
| 461 | return ctx->conf.def.width; | 519 | return ctx->conf.def.width; |
| 462 | 520 | ||
| 463 | for_each_sdata_link(local, link) { | 521 | /* When this is true we only care about the reserving links */ |
| 464 | enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; | 522 | if (check_reserved) { |
| 465 | 523 | for_each_chanctx_user_reserved(local, ctx, &iter) { | |
| 466 | if (check_reserved) { | 524 | width = ieee80211_get_width_of_link(iter.link); |
| 467 | if (link->reserved_chanctx != ctx) | 525 | max_bw = max(max_bw, width); |
| 468 | continue; | ||
| 469 | } else if (link != rsvd_for && | ||
| 470 | rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf) | ||
| 471 | continue; | ||
| 472 | |||
| 473 | switch (link->sdata->vif.type) { | ||
| 474 | case NL80211_IFTYPE_STATION: | ||
| 475 | if (!link->sdata->vif.cfg.assoc) { | ||
| 476 | /* | ||
| 477 | * The AP's sta->bandwidth may not yet be set | ||
| 478 | * at this point (pre-association), so simply | ||
| 479 | * take the width from the chandef. We cannot | ||
| 480 | * have TDLS peers yet (only after association). | ||
| 481 | */ | ||
| 482 | width = link->conf->chanreq.oper.width; | ||
| 483 | break; | ||
| 484 | } | ||
| 485 | /* | ||
| 486 | * otherwise just use min_def like in AP, depending on what | ||
| 487 | * we currently think the AP STA (and possibly TDLS peers) | ||
| 488 | * require(s) | ||
| 489 | */ | ||
| 490 | fallthrough; | ||
| 491 | case NL80211_IFTYPE_AP: | ||
| 492 | case NL80211_IFTYPE_AP_VLAN: | ||
| 493 | width = ieee80211_get_max_required_bw(link); | ||
| 494 | break; | ||
| 495 | case NL80211_IFTYPE_P2P_DEVICE: | ||
| 496 | case NL80211_IFTYPE_NAN: | ||
| 497 | continue; | ||
| 498 | case NL80211_IFTYPE_MONITOR: | ||
| 499 | WARN_ON_ONCE(!ieee80211_hw_check(&local->hw, | ||
| 500 | NO_VIRTUAL_MONITOR)); | ||
| 501 | fallthrough; | ||
| 502 | case NL80211_IFTYPE_ADHOC: | ||
| 503 | case NL80211_IFTYPE_MESH_POINT: | ||
| 504 | case NL80211_IFTYPE_OCB: | ||
| 505 | width = link->conf->chanreq.oper.width; | ||
| 506 | break; | ||
| 507 | case NL80211_IFTYPE_WDS: | ||
| 508 | case NL80211_IFTYPE_UNSPECIFIED: | ||
| 509 | case NUM_NL80211_IFTYPES: | ||
| 510 | case NL80211_IFTYPE_P2P_CLIENT: | ||
| 511 | case NL80211_IFTYPE_P2P_GO: | ||
| 512 | WARN_ON_ONCE(1); | ||
| 513 | } | 526 | } |
| 527 | goto check_monitor; | ||
| 528 | } | ||
| 514 | 529 | ||
| 530 | /* Consider all assigned links */ | ||
| 531 | for_each_chanctx_user_assigned(local, ctx, &iter) { | ||
| 532 | width = ieee80211_get_width_of_link(iter.link); | ||
| 515 | max_bw = max(max_bw, width); | 533 | max_bw = max(max_bw, width); |
| 516 | } | 534 | } |
| 517 | 535 | ||
| 536 | if (!rsvd_for || | ||
| 537 | rsvd_for->sdata == rcu_access_pointer(local->monitor_sdata)) | ||
| 538 | goto check_monitor; | ||
| 539 | |||
| 540 | /* Consider the link for which this chanctx is reserved/going to be assigned */ | ||
| 541 | width = ieee80211_get_width_of_link(rsvd_for); | ||
| 542 | max_bw = max(max_bw, width); | ||
| 543 | |||
| 544 | check_monitor: | ||
| 518 | /* use the configured bandwidth in case of monitor interface */ | 545 | /* use the configured bandwidth in case of monitor interface */ |
| 519 | sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); | 546 | sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); |
| 520 | if (sdata && | 547 | if (sdata && |
| @@ -752,10 +779,9 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local, · 231 unmodified lines | |||
| 752 | _ieee80211_change_chanctx(local, ctx, old_ctx, chanreq, NULL); | 779 | _ieee80211_change_chanctx(local, ctx, old_ctx, chanreq, NULL); |
| 753 | } | 780 | } |
| 754 | 781 | ||
| 755 | /* Note: if successful, the returned chanctx is reserved for the link */ | 782 | /* Note: if successful, the returned chanctx will_be_used flag is set */ |
| 756 | static struct ieee80211_chanctx * | 783 | static struct ieee80211_chanctx * |
| 757 | ieee80211_find_chanctx(struct ieee80211_local *local, | 784 | ieee80211_find_chanctx(struct ieee80211_local *local, |
| 758 | struct ieee80211_link_data *link, | ||
| 759 | const struct ieee80211_chan_req *chanreq, | 785 | const struct ieee80211_chan_req *chanreq, |
| 760 | enum ieee80211_chanctx_mode mode) | 786 | enum ieee80211_chanctx_mode mode) |
| 761 | { | 787 | { |
| @@ -767,9 +793,6 @@ ieee80211_find_chanctx(struct ieee80211_local *local, · 5 unmodified lines | |||
| 767 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) | 793 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 768 | return NULL; | 794 | return NULL; |
| 769 | 795 | ||
| 770 | if (WARN_ON(link->reserved_chanctx)) | ||
| 771 | return NULL; | ||
| 772 | |||
| 773 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 796 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 774 | const struct ieee80211_chan_req *compat; | 797 | const struct ieee80211_chan_req *compat; |
| 775 | 798 | ||
| @@ -790,12 +813,12 @@ ieee80211_find_chanctx(struct ieee80211_local *local, · 14 unmodified lines | |||
| 790 | continue; | 813 | continue; |
| 791 | 814 | ||
| 792 | /* | 815 | /* |
| 793 | * Reserve the chanctx temporarily, as the driver might change | 816 | * Mark the chanctx as will be used, as the driver might change |
| 794 | * active links during callbacks we make into it below and/or | 817 | * active links during callbacks we make into it below and/or |
| 795 | * later during assignment, which could (otherwise) cause the | 818 | * later during assignment, which could (otherwise) cause the |
| 796 | * context to actually be removed. | 819 | * context to actually be removed. |
| 797 | */ | 820 | */ |
| 798 | link->reserved_chanctx = ctx; | 821 | ctx->will_be_used = true; |
| 799 | 822 | ||
| 800 | ieee80211_change_chanctx(local, ctx, ctx, compat); | 823 | ieee80211_change_chanctx(local, ctx, ctx, compat); |
| 801 | 824 | ||
| @@ -1438,6 +1461,7 @@ ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link) · 636 unmodified lines | |||
| 1438 | case NL80211_IFTYPE_P2P_GO: | 1461 | case NL80211_IFTYPE_P2P_GO: |
| 1439 | case NL80211_IFTYPE_P2P_DEVICE: | 1462 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1440 | case NL80211_IFTYPE_NAN: | 1463 | case NL80211_IFTYPE_NAN: |
| 1464 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1441 | case NUM_NL80211_IFTYPES: | 1465 | case NUM_NL80211_IFTYPES: |
| 1442 | WARN_ON(1); | 1466 | WARN_ON(1); |
| 1443 | break; | 1467 | break; |
| @@ -2011,6 +2035,36 @@ void __ieee80211_link_release_channel(struct ieee80211_link_data *link, · 567 unmodified lines | |||
| 2011 | ieee80211_vif_use_reserved_switch(local); | 2035 | ieee80211_vif_use_reserved_switch(local); |
| 2012 | } | 2036 | } |
| 2013 | 2037 | ||
| 2038 | static struct ieee80211_chanctx * | ||
| 2039 | ieee80211_find_or_create_chanctx(struct ieee80211_sub_if_data *sdata, | ||
| 2040 | const struct ieee80211_chan_req *chanreq, | ||
| 2041 | enum ieee80211_chanctx_mode mode, | ||
| 2042 | bool assign_on_failure, | ||
| 2043 | bool *reused_ctx) | ||
| 2044 | { | ||
| 2045 | struct ieee80211_local *local = sdata->local; | ||
| 2046 | struct ieee80211_chanctx *ctx; | ||
| 2047 | int radio_idx; | ||
| 2048 | |||
| 2049 | lockdep_assert_wiphy(local->hw.wiphy); | ||
| 2050 | |||
| 2051 | ctx = ieee80211_find_chanctx(local, chanreq, mode); | ||
| 2052 | if (ctx) { | ||
| 2053 | *reused_ctx = true; | ||
| 2054 | return ctx; | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | *reused_ctx = false; | ||
| 2058 | |||
| 2059 | if (!ieee80211_find_available_radio(local, chanreq, | ||
| 2060 | sdata->wdev.radio_mask, | ||
| 2061 | &radio_idx)) | ||
| 2062 | return ERR_PTR(-EBUSY); | ||
| 2063 | |||
| 2064 | return ieee80211_new_chanctx(local, chanreq, mode, | ||
| 2065 | assign_on_failure, radio_idx); | ||
| 2066 | } | ||
| 2067 | |||
| 2014 | int _ieee80211_link_use_channel(struct ieee80211_link_data *link, | 2068 | int _ieee80211_link_use_channel(struct ieee80211_link_data *link, |
| 2015 | const struct ieee80211_chan_req *chanreq, | 2069 | const struct ieee80211_chan_req *chanreq, |
| 2016 | enum ieee80211_chanctx_mode mode, | 2070 | enum ieee80211_chanctx_mode mode, |
| @@ -2020,8 +2074,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, · 3 unmodified lines | |||
| 2020 | struct ieee80211_local *local = sdata->local; | 2074 | struct ieee80211_local *local = sdata->local; |
| 2021 | struct ieee80211_chanctx *ctx; | 2075 | struct ieee80211_chanctx *ctx; |
| 2022 | u8 radar_detect_width = 0; | 2076 | u8 radar_detect_width = 0; |
| 2023 | bool reserved = false; | 2077 | bool reused_ctx = false; |
| 2024 | int radio_idx; | ||
| 2025 | int ret; | 2078 | int ret; |
| 2026 | 2079 | ||
| 2027 | lockdep_assert_wiphy(local->hw.wiphy); | 2080 | lockdep_assert_wiphy(local->hw.wiphy); |
| @@ -2049,17 +2102,8 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, · 21 unmodified lines | |||
| 2049 | if (!local->in_reconfig) | 2102 | if (!local->in_reconfig) |
| 2050 | __ieee80211_link_release_channel(link, false); | 2103 | __ieee80211_link_release_channel(link, false); |
| 2051 | 2104 | ||
| 2052 | ctx = ieee80211_find_chanctx(local, link, chanreq, mode); | 2105 | ctx = ieee80211_find_or_create_chanctx(sdata, chanreq, mode, |
| 2053 | /* Note: context is now reserved */ | 2106 | assign_on_failure, &reused_ctx); |
| 2054 | if (ctx) | ||
| 2055 | reserved = true; | ||
| 2056 | else if (!ieee80211_find_available_radio(local, chanreq, | ||
| 2057 | sdata->wdev.radio_mask, | ||
| 2058 | &radio_idx)) | ||
| 2059 | ctx = ERR_PTR(-EBUSY); | ||
| 2060 | else | ||
| 2061 | ctx = ieee80211_new_chanctx(local, chanreq, mode, | ||
| 2062 | assign_on_failure, radio_idx); | ||
| 2063 | if (IS_ERR(ctx)) { | 2107 | if (IS_ERR(ctx)) { |
| 2064 | ret = PTR_ERR(ctx); | 2108 | ret = PTR_ERR(ctx); |
| 2065 | goto out; | 2109 | goto out; |
| @@ -2069,10 +2113,13 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, · 3 unmodified lines | |||
| 2069 | 2113 | ||
| 2070 | ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure); | 2114 | ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure); |
| 2071 | 2115 | ||
| 2072 | if (reserved) { | 2116 | /* |
| 2073 | /* remove reservation */ | 2117 | * In case an existing channel context is being used, we marked it as |
| 2074 | WARN_ON(link->reserved_chanctx != ctx); | 2118 | * will_be_used, now that it is assigned - clear this indication |
| 2075 | link->reserved_chanctx = NULL; | 2119 | */ |
| 2120 | if (reused_ctx) { | ||
| 2121 | WARN_ON(!ctx->will_be_used); | ||
| 2122 | ctx->will_be_used = false; | ||
| 2076 | } | 2123 | } |
| 2077 | 2124 | ||
| 2078 | if (ret) { | 2125 | if (ret) { |
| @@ -108,14 +108,13 @@ static void ieee80211_he_mcs_intersection(__le16 *he_own_rx, __le16 *he_peer_rx, · 107 unmodified lines | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void | 110 | void |
| 111 | ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | 111 | _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, |
| 112 | struct ieee80211_supported_band *sband, | 112 | const struct ieee80211_sta_he_cap *own_he_cap_ptr, |
| 113 | const u8 *he_cap_ie, u8 he_cap_len, | 113 | const u8 *he_cap_ie, u8 he_cap_len, |
| 114 | const struct ieee80211_he_6ghz_capa *he_6ghz_capa, | 114 | const struct ieee80211_he_6ghz_capa *he_6ghz_capa, |
| 115 | struct link_sta_info *link_sta) | 115 | struct link_sta_info *link_sta) |
| 116 | { | 116 | { |
| 117 | struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; | 117 | struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap; |
| 118 | const struct ieee80211_sta_he_cap *own_he_cap_ptr; | ||
| 119 | struct ieee80211_sta_he_cap own_he_cap; | 118 | struct ieee80211_sta_he_cap own_he_cap; |
| 120 | struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; | 119 | struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; |
| 121 | u8 he_ppe_size; | 120 | u8 he_ppe_size; |
| @@ -125,12 +124,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, · 3 unmodified lines | |||
| 125 | 124 | ||
| 126 | memset(he_cap, 0, sizeof(*he_cap)); | 125 | memset(he_cap, 0, sizeof(*he_cap)); |
| 127 | 126 | ||
| 128 | if (!he_cap_ie) | 127 | if (!he_cap_ie || !own_he_cap_ptr || !own_he_cap_ptr->has_he) |
| 129 | return; | ||
| 130 | |||
| 131 | own_he_cap_ptr = | ||
| 132 | ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); | ||
| 133 | if (!own_he_cap_ptr) | ||
| 134 | return; | 128 | return; |
| 135 | 129 | ||
| 136 | own_he_cap = *own_he_cap_ptr; | 130 | own_he_cap = *own_he_cap_ptr; |
| @@ -164,7 +158,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, · 27 unmodified lines | |||
| 164 | link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); | 158 | link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); |
| 165 | link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); | 159 | link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta); |
| 166 | 160 | ||
| 167 | if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa) | 161 | if (he_6ghz_capa) |
| 168 | ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta); | 162 | ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta); |
| 169 | 163 | ||
| 170 | ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80, | 164 | ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80, |
| @@ -207,6 +201,23 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, · 36 unmodified lines | |||
| 207 | } | 201 | } |
| 208 | } | 202 | } |
| 209 | 203 | ||
| 204 | void | ||
| 205 | ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | ||
| 206 | struct ieee80211_supported_band *sband, | ||
| 207 | const u8 *he_cap_ie, u8 he_cap_len, | ||
| 208 | const struct ieee80211_he_6ghz_capa *he_6ghz_capa, | ||
| 209 | struct link_sta_info *link_sta) | ||
| 210 | { | ||
| 211 | const struct ieee80211_sta_he_cap *own_he_cap = | ||
| 212 | ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); | ||
| 213 | |||
| 214 | _ieee80211_he_cap_ie_to_sta_he_cap(sdata, own_he_cap, he_cap_ie, | ||
| 215 | he_cap_len, | ||
| 216 | (sband->band == NL80211_BAND_6GHZ) ? | ||
| 217 | he_6ghz_capa : NULL, | ||
| 218 | link_sta); | ||
| 219 | } | ||
| 220 | |||
| 210 | void | 221 | void |
| 211 | ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, | 222 | ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, |
| 212 | const struct ieee80211_he_operation *he_op_ie) | 223 | const struct ieee80211_he_operation *he_op_ie) |
| @@ -136,7 +136,7 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, · 135 unmodified lines | |||
| 136 | 136 | ||
| 137 | 137 | ||
| 138 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 138 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
| 139 | struct ieee80211_supported_band *sband, | 139 | const struct ieee80211_sta_ht_cap *own_cap_ptr, |
| 140 | const struct ieee80211_ht_cap *ht_cap_ie, | 140 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 141 | struct link_sta_info *link_sta) | 141 | struct link_sta_info *link_sta) |
| 142 | { | 142 | { |
| @@ -151,12 +151,12 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, · 8 unmodified lines | |||
| 151 | 151 | ||
| 152 | memset(&ht_cap, 0, sizeof(ht_cap)); | 152 | memset(&ht_cap, 0, sizeof(ht_cap)); |
| 153 | 153 | ||
| 154 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) | 154 | if (!ht_cap_ie || !own_cap_ptr->ht_supported) |
| 155 | goto apply; | 155 | goto apply; |
| 156 | 156 | ||
| 157 | ht_cap.ht_supported = true; | 157 | ht_cap.ht_supported = true; |
| 158 | 158 | ||
| 159 | own_cap = sband->ht_cap; | 159 | own_cap = *own_cap_ptr; |
| 160 | 160 | ||
| 161 | /* | 161 | /* |
| 162 | * If user has specified capability over-rides, take care | 162 | * If user has specified capability over-rides, take care |
| @@ -1014,7 +1014,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, · 1013 unmodified lines | |||
| 1014 | ieee80211_chandef_ht_oper(elems->ht_operation, &chandef); | 1014 | ieee80211_chandef_ht_oper(elems->ht_operation, &chandef); |
| 1015 | 1015 | ||
| 1016 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); | 1016 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
| 1017 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1017 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, |
| 1018 | &sband->ht_cap, | ||
| 1018 | &htcap_ie, | 1019 | &htcap_ie, |
| 1019 | &sta->deflink); | 1020 | &sta->deflink); |
| 1020 | 1021 | ||
| @@ -1033,6 +1034,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, · 12 unmodified lines | |||
| 1033 | &chandef); | 1034 | &chandef); |
| 1034 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); | 1035 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); |
| 1035 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1036 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 1037 | &sband->vht_cap, | ||
| 1036 | &cap_ie, NULL, | 1038 | &cap_ie, NULL, |
| 1037 | &sta->deflink); | 1039 | &sta->deflink); |
| 1038 | if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) | 1040 | if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) |
| @@ -928,6 +928,9 @@ struct ieee80211_chanctx { · 927 unmodified lines | |||
| 928 | 928 | ||
| 929 | bool radar_detected; | 929 | bool radar_detected; |
| 930 | 930 | ||
| 931 | /* This chanctx is in process of getting used */ | ||
| 932 | bool will_be_used; | ||
| 933 | |||
| 931 | /* MUST be last - ends in a flexible-array member. */ | 934 | /* MUST be last - ends in a flexible-array member. */ |
| 932 | struct ieee80211_chanctx_conf conf; | 935 | struct ieee80211_chanctx_conf conf; |
| 933 | }; | 936 | }; |
| @@ -2185,7 +2188,7 @@ void ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata, · 1251 unmodified lines | |||
| 2185 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 2188 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
| 2186 | struct ieee80211_sta_ht_cap *ht_cap); | 2189 | struct ieee80211_sta_ht_cap *ht_cap); |
| 2187 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 2190 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
| 2188 | struct ieee80211_supported_band *sband, | 2191 | const struct ieee80211_sta_ht_cap *own_cap, |
| 2189 | const struct ieee80211_ht_cap *ht_cap_ie, | 2192 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 2190 | struct link_sta_info *link_sta); | 2193 | struct link_sta_info *link_sta); |
| 2191 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 2194 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
| @@ -2270,6 +2273,7 @@ void ieee80211_ht_handle_chanwidth_notif(struct ieee80211_local *local, · 78 unmodified lines | |||
| 2270 | void | 2273 | void |
| 2271 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 2274 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 2272 | struct ieee80211_supported_band *sband, | 2275 | struct ieee80211_supported_band *sband, |
| 2276 | const struct ieee80211_sta_vht_cap *own_vht_cap, | ||
| 2273 | const struct ieee80211_vht_cap *vht_cap_ie, | 2277 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 2274 | const struct ieee80211_vht_cap *vht_cap_ie2, | 2278 | const struct ieee80211_vht_cap *vht_cap_ie2, |
| 2275 | struct link_sta_info *link_sta); | 2279 | struct link_sta_info *link_sta); |
| @@ -2310,6 +2314,12 @@ ieee80211_sta_rx_bw_to_chan_width(struct link_sta_info *sta); · 34 unmodified lines | |||
| 2310 | 2314 | ||
| 2311 | /* HE */ | 2315 | /* HE */ |
| 2312 | void | 2316 | void |
| 2317 | _ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | ||
| 2318 | const struct ieee80211_sta_he_cap *own_he_cap, | ||
| 2319 | const u8 *he_cap_ie, u8 he_cap_len, | ||
| 2320 | const struct ieee80211_he_6ghz_capa *he_6ghz_capa, | ||
| 2321 | struct link_sta_info *link_sta); | ||
| 2322 | void | ||
| 2313 | ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | 2323 | ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, |
| 2314 | struct ieee80211_supported_band *sband, | 2324 | struct ieee80211_supported_band *sband, |
| 2315 | const u8 *he_cap_ie, u8 he_cap_len, | 2325 | const u8 *he_cap_ie, u8 he_cap_len, |
| @@ -1222,14 +1222,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local, · 1221 unmodified lines | |||
| 1222 | } | 1222 | } |
| 1223 | } | 1223 | } |
| 1224 | 1224 | ||
| 1225 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
| 1226 | |||
| 1227 | ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); | 1225 | ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); |
| 1228 | if (ret) { | 1226 | if (ret) { |
| 1229 | kfree(sdata); | 1227 | kfree(sdata); |
| 1230 | return ret; | 1228 | return ret; |
| 1231 | } | 1229 | } |
| 1232 | 1230 | ||
| 1231 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
| 1232 | |||
| 1233 | mutex_lock(&local->iflist_mtx); | 1233 | mutex_lock(&local->iflist_mtx); |
| 1234 | rcu_assign_pointer(local->monitor_sdata, sdata); | 1234 | rcu_assign_pointer(local->monitor_sdata, sdata); |
| 1235 | mutex_unlock(&local->iflist_mtx); | 1235 | mutex_unlock(&local->iflist_mtx); |
| @@ -1242,6 +1242,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local, · 6 unmodified lines | |||
| 1242 | mutex_unlock(&local->iflist_mtx); | 1242 | mutex_unlock(&local->iflist_mtx); |
| 1243 | synchronize_net(); | 1243 | synchronize_net(); |
| 1244 | drv_remove_interface(local, sdata); | 1244 | drv_remove_interface(local, sdata); |
| 1245 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
| 1245 | kfree(sdata); | 1246 | kfree(sdata); |
| 1246 | return ret; | 1247 | return ret; |
| 1247 | } | 1248 | } |
| @@ -1360,8 +1361,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 112 unmodified lines | |||
| 1360 | break; | 1361 | break; |
| 1361 | } | 1362 | } |
| 1362 | case NL80211_IFTYPE_AP: | 1363 | case NL80211_IFTYPE_AP: |
| 1363 | sdata->bss = &sdata->u.ap; | ||
| 1364 | break; | ||
| 1365 | case NL80211_IFTYPE_MESH_POINT: | 1364 | case NL80211_IFTYPE_MESH_POINT: |
| 1366 | case NL80211_IFTYPE_STATION: | 1365 | case NL80211_IFTYPE_STATION: |
| 1367 | case NL80211_IFTYPE_MONITOR: | 1366 | case NL80211_IFTYPE_MONITOR: |
| @@ -1369,6 +1368,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 1 unmodified line | |||
| 1369 | case NL80211_IFTYPE_P2P_DEVICE: | 1368 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1370 | case NL80211_IFTYPE_OCB: | 1369 | case NL80211_IFTYPE_OCB: |
| 1371 | case NL80211_IFTYPE_NAN: | 1370 | case NL80211_IFTYPE_NAN: |
| 1371 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1372 | /* no special treatment */ | 1372 | /* no special treatment */ |
| 1373 | break; | 1373 | break; |
| 1374 | case NL80211_IFTYPE_UNSPECIFIED: | 1374 | case NL80211_IFTYPE_UNSPECIFIED: |
| @@ -1386,8 +1386,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 11 unmodified lines | |||
| 1386 | local->reconfig_failure = false; | 1386 | local->reconfig_failure = false; |
| 1387 | 1387 | ||
| 1388 | res = drv_start(local); | 1388 | res = drv_start(local); |
| 1389 | if (res) | 1389 | if (res) { |
| 1390 | goto err_del_bss; | 1390 | /* |
| 1391 | * no need to worry about AP_VLAN cleanup since in that | ||
| 1392 | * case we can't have open_count == 0 | ||
| 1393 | */ | ||
| 1394 | return res; | ||
| 1395 | } | ||
| 1391 | ieee80211_led_radio(local, true); | 1396 | ieee80211_led_radio(local, true); |
| 1392 | ieee80211_mod_tpt_led_trig(local, | 1397 | ieee80211_mod_tpt_led_trig(local, |
| 1393 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); | 1398 | IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); |
| @@ -1458,6 +1463,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 64 unmodified lines | |||
| 1458 | netif_carrier_on(dev); | 1463 | netif_carrier_on(dev); |
| 1459 | list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); | 1464 | list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); |
| 1460 | break; | 1465 | break; |
| 1466 | case NL80211_IFTYPE_AP: | ||
| 1467 | sdata->bss = &sdata->u.ap; | ||
| 1468 | fallthrough; | ||
| 1461 | default: | 1469 | default: |
| 1462 | if (coming_up) { | 1470 | if (coming_up) { |
| 1463 | ieee80211_del_virtual_monitor(local); | 1471 | ieee80211_del_virtual_monitor(local); |
| @@ -1546,12 +1554,10 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 82 unmodified lines | |||
| 1546 | err_stop: | 1554 | err_stop: |
| 1547 | if (!local->open_count) | 1555 | if (!local->open_count) |
| 1548 | drv_stop(local, false); | 1556 | drv_stop(local, false); |
| 1549 | err_del_bss: | ||
| 1550 | sdata->bss = NULL; | ||
| 1551 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1557 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 1552 | list_del(&sdata->u.vlan.list); | 1558 | list_del(&sdata->u.vlan.list); |
| 1553 | /* might already be clear but that doesn't matter */ | 1559 | /* Might not be initialized yet, but it is harmless */ |
| 1554 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | 1560 | sdata->bss = NULL; |
| 1555 | return res; | 1561 | return res; |
| 1556 | } | 1562 | } |
| 1557 | 1563 | ||
| @@ -1940,6 +1946,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, · 382 unmodified lines | |||
| 1940 | case NL80211_IFTYPE_P2P_DEVICE: | 1946 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1941 | sdata->vif.bss_conf.bssid = sdata->vif.addr; | 1947 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
| 1942 | break; | 1948 | break; |
| 1949 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1950 | break; | ||
| 1943 | case NL80211_IFTYPE_UNSPECIFIED: | 1951 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1944 | case NL80211_IFTYPE_WDS: | 1952 | case NL80211_IFTYPE_WDS: |
| 1945 | case NUM_NL80211_IFTYPES: | 1953 | case NUM_NL80211_IFTYPES: |
| @@ -450,12 +450,13 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, · 449 unmodified lines | |||
| 450 | changed |= IEEE80211_RC_SUPP_RATES_CHANGED; | 450 | changed |= IEEE80211_RC_SUPP_RATES_CHANGED; |
| 451 | sta->sta.deflink.supp_rates[sband->band] = rates; | 451 | sta->sta.deflink.supp_rates[sband->band] = rates; |
| 452 | 452 | ||
| 453 | if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 453 | if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, &sband->ht_cap, |
| 454 | elems->ht_cap_elem, | 454 | elems->ht_cap_elem, |
| 455 | &sta->deflink)) | 455 | &sta->deflink)) |
| 456 | changed |= IEEE80211_RC_BW_CHANGED; | 456 | changed |= IEEE80211_RC_BW_CHANGED; |
| 457 | 457 | ||
| 458 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 458 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 459 | &sband->vht_cap, | ||
| 459 | elems->vht_cap_elem, NULL, | 460 | elems->vht_cap_elem, NULL, |
| 460 | &sta->deflink); | 461 | &sta->deflink); |
| 461 | 462 | ||
| @@ -5586,7 +5586,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, · 5585 unmodified lines | |||
| 5586 | 5586 | ||
| 5587 | /* Set up internal HT/VHT capabilities */ | 5587 | /* Set up internal HT/VHT capabilities */ |
| 5588 | if (elems->ht_cap_elem && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) | 5588 | if (elems->ht_cap_elem && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HT) |
| 5589 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 5589 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, &sband->ht_cap, |
| 5590 | elems->ht_cap_elem, | 5590 | elems->ht_cap_elem, |
| 5591 | link_sta); | 5591 | link_sta); |
| 5592 | 5592 | ||
| @@ -5622,6 +5622,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, · 29 unmodified lines | |||
| 5622 | } | 5622 | } |
| 5623 | 5623 | ||
| 5624 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 5624 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 5625 | &sband->vht_cap, | ||
| 5625 | elems->vht_cap_elem, | 5626 | elems->vht_cap_elem, |
| 5626 | bss_vht_cap, link_sta); | 5627 | bss_vht_cap, link_sta); |
| 5627 | rcu_read_unlock(); | 5628 | rcu_read_unlock(); |
| @@ -10458,8 +10459,8 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, · 4830 unmodified lines | |||
| 10458 | pos = mgmt->u.action.ml_reconf_resp.variable; | 10459 | pos = mgmt->u.action.ml_reconf_resp.variable; |
| 10459 | len -= offsetofend(typeof(*mgmt), u.action.ml_reconf_resp); | 10460 | len -= offsetofend(typeof(*mgmt), u.action.ml_reconf_resp); |
| 10460 | 10461 | ||
| 10461 | /* each status duple is 3 octets */ | 10462 | if (len < mgmt->u.action.ml_reconf_resp.count * |
| 10462 | if (len < mgmt->u.action.ml_reconf_resp.count * 3) { | 10463 | sizeof(struct ieee80211_ml_reconf_status)) { |
| 10463 | sdata_info(sdata, | 10464 | sdata_info(sdata, |
| 10464 | "mlo: reconf: unexpected len=%zu, count=%u\n", | 10465 | "mlo: reconf: unexpected len=%zu, count=%u\n", |
| 10465 | len, mgmt->u.action.ml_reconf_resp.count); | 10466 | len, mgmt->u.action.ml_reconf_resp.count); |
| @@ -10468,9 +10469,11 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, · 2 unmodified lines | |||
| 10468 | 10469 | ||
| 10469 | link_mask = sta_changed_links; | 10470 | link_mask = sta_changed_links; |
| 10470 | for (i = 0; i < mgmt->u.action.ml_reconf_resp.count; i++) { | 10471 | for (i = 0; i < mgmt->u.action.ml_reconf_resp.count; i++) { |
| 10471 | u16 status = get_unaligned_le16(pos + 1); | 10472 | struct ieee80211_ml_reconf_status *reconf_status = (void *)pos; |
| 10473 | u16 status = le16_to_cpu(reconf_status->status); | ||
| 10472 | 10474 | ||
| 10473 | link_id = *pos; | 10475 | link_id = u8_get_bits(reconf_status->info, |
| 10476 | IEEE80211_ML_RECONF_LINK_ID_MASK); | ||
| 10474 | 10477 | ||
| 10475 | if (!(link_mask & BIT(link_id))) { | 10478 | if (!(link_mask & BIT(link_id))) { |
| 10476 | sdata_info(sdata, | 10479 | sdata_info(sdata, |
| @@ -10505,8 +10508,8 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, · 28 unmodified lines | |||
| 10505 | sdata->u.mgd.reconf.added_links &= ~BIT(link_id); | 10508 | sdata->u.mgd.reconf.added_links &= ~BIT(link_id); |
| 10506 | } | 10509 | } |
| 10507 | 10510 | ||
| 10508 | pos += 3; | 10511 | pos += sizeof(*reconf_status); |
| 10509 | len -= 3; | 10512 | len -= sizeof(*reconf_status); |
| 10510 | } | 10513 | } |
| 10511 | 10514 | ||
| 10512 | if (link_mask) { | 10515 | if (link_mask) { |
| @@ -4607,6 +4607,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) · 4606 unmodified lines | |||
| 4607 | (ieee80211_is_public_action(hdr, skb->len) || | 4607 | (ieee80211_is_public_action(hdr, skb->len) || |
| 4608 | (ieee80211_is_auth(hdr->frame_control) && | 4608 | (ieee80211_is_auth(hdr->frame_control) && |
| 4609 | ether_addr_equal(sdata->vif.addr, hdr->addr1))); | 4609 | ether_addr_equal(sdata->vif.addr, hdr->addr1))); |
| 4610 | case NL80211_IFTYPE_NAN_DATA: | ||
| 4611 | return false; | ||
| 4610 | default: | 4612 | default: |
| 4611 | break; | 4613 | break; |
| 4612 | } | 4614 | } |
| @@ -1778,9 +1778,8 @@ TRACE_EVENT(drv_switch_vif_chanctx, · 1777 unmodified lines | |||
| 1778 | SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); | 1778 | SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); |
| 1779 | SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); | 1779 | SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); |
| 1780 | SWITCH_ENTRY_ASSIGN(link_id, link_conf->link_id); | 1780 | SWITCH_ENTRY_ASSIGN(link_id, link_conf->link_id); |
| 1781 | strncpy(local_vifs[i].vif.vif_name, | 1781 | strscpy_pad(local_vifs[i].vif.vif_name, |
| 1782 | sdata->name, | 1782 | sdata->name); |
| 1783 | sizeof(local_vifs[i].vif.vif_name)); | ||
| 1784 | SWITCH_ENTRY_ASSIGN(old_chandef.control_freq, | 1783 | SWITCH_ENTRY_ASSIGN(old_chandef.control_freq, |
| 1785 | old_ctx->def.chan->center_freq); | 1784 | old_ctx->def.chan->center_freq); |
| 1786 | SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset, | 1785 | SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset, |
| @@ -2118,6 +2118,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) · 2117 unmodified lines | |||
| 2118 | return res; | 2118 | return res; |
| 2119 | } | 2119 | } |
| 2120 | break; | 2120 | break; |
| 2121 | case NL80211_IFTYPE_NAN_DATA: | ||
| 2121 | case NL80211_IFTYPE_AP_VLAN: | 2122 | case NL80211_IFTYPE_AP_VLAN: |
| 2122 | case NL80211_IFTYPE_MONITOR: | 2123 | case NL80211_IFTYPE_MONITOR: |
| 2123 | case NL80211_IFTYPE_P2P_DEVICE: | 2124 | case NL80211_IFTYPE_P2P_DEVICE: |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | |||
| 4 | * | 4 | * |
| 5 | * Portions of this file | 5 | * Portions of this file |
| 6 | * Copyright(c) 2015 - 2016 Intel Deutschland GmbH | 6 | * Copyright(c) 2015 - 2016 Intel Deutschland GmbH |
| 7 | * Copyright (C) 2018-2026 Intel Corporation | 7 | * Copyright (C) 2018 - 2026 Intel Corporation |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/ieee80211.h> | 10 | #include <linux/ieee80211.h> |
| @@ -115,6 +115,7 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, · 104 unmodified lines | |||
| 115 | void | 115 | void |
| 116 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | 116 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 117 | struct ieee80211_supported_band *sband, | 117 | struct ieee80211_supported_band *sband, |
| 118 | const struct ieee80211_sta_vht_cap *own_vht_cap, | ||
| 118 | const struct ieee80211_vht_cap *vht_cap_ie, | 119 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 119 | const struct ieee80211_vht_cap *vht_cap_ie2, | 120 | const struct ieee80211_vht_cap *vht_cap_ie2, |
| 120 | struct link_sta_info *link_sta) | 121 | struct link_sta_info *link_sta) |
| @@ -122,7 +123,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, · 1 unmodified line | |||
| 122 | struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; | 123 | struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; |
| 123 | struct ieee80211_sta_vht_cap own_cap; | 124 | struct ieee80211_sta_vht_cap own_cap; |
| 124 | u32 cap_info, i; | 125 | u32 cap_info, i; |
| 125 | bool have_80mhz; | ||
| 126 | u32 mpdu_len; | 126 | u32 mpdu_len; |
| 127 | 127 | ||
| 128 | memset(vht_cap, 0, sizeof(*vht_cap)); | 128 | memset(vht_cap, 0, sizeof(*vht_cap)); |
| @@ -130,22 +130,25 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, · 1 unmodified line | |||
| 130 | if (!link_sta->pub->ht_cap.ht_supported) | 130 | if (!link_sta->pub->ht_cap.ht_supported) |
| 131 | return; | 131 | return; |
| 132 | 132 | ||
| 133 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 133 | if (!vht_cap_ie || !own_vht_cap->vht_supported) |
| 134 | return; | 134 | return; |
| 135 | 135 | ||
| 136 | /* Allow VHT if at least one channel on the sband supports 80 MHz */ | 136 | if (sband) { |
| 137 | have_80mhz = false; | 137 | /* Allow VHT if at least one channel on the sband supports 80 MHz */ |
| 138 | for (i = 0; i < sband->n_channels; i++) { | 138 | bool have_80mhz = false; |
| 139 | if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | | ||
| 140 | IEEE80211_CHAN_NO_80MHZ)) | ||
| 141 | continue; | ||
| 142 | 139 | ||
| 143 | have_80mhz = true; | 140 | for (i = 0; i < sband->n_channels; i++) { |
| 144 | break; | 141 | if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | |
| 145 | } | 142 | IEEE80211_CHAN_NO_80MHZ)) |
| 143 | continue; | ||
| 146 | 144 | ||
| 147 | if (!have_80mhz) | 145 | have_80mhz = true; |
| 148 | return; | 146 | break; |
| 147 | } | ||
| 148 | |||
| 149 | if (!have_80mhz) | ||
| 150 | return; | ||
| 151 | } | ||
| 149 | 152 | ||
| 150 | /* | 153 | /* |
| 151 | * A VHT STA must support 40 MHz, but if we verify that here | 154 | * A VHT STA must support 40 MHz, but if we verify that here |
| @@ -156,7 +159,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, · 4 unmodified lines | |||
| 156 | 159 | ||
| 157 | vht_cap->vht_supported = true; | 160 | vht_cap->vht_supported = true; |
| 158 | 161 | ||
| 159 | own_cap = sband->vht_cap; | 162 | own_cap = *own_vht_cap; |
| 160 | /* | 163 | /* |
| 161 | * If user has specified capability overrides, take care | 164 | * If user has specified capability overrides, take care |
| 162 | * of that if the station we're setting up is the AP that | 165 | * of that if the station we're setting up is the AP that |
| @@ -317,7 +317,7 @@ static bool cfg80211_valid_center_freq(u32 center, · 316 unmodified lines | |||
| 317 | int step; | 317 | int step; |
| 318 | 318 | ||
| 319 | /* We only do strict verification on 6 GHz */ | 319 | /* We only do strict verification on 6 GHz */ |
| 320 | if (center < 5955 || center > 7115) | 320 | if (center < 5955 || center > 7215) |
| 321 | return true; | 321 | return true; |
| 322 | 322 | ||
| 323 | bw = nl80211_chan_width_to_mhz(width); | 323 | bw = nl80211_chan_width_to_mhz(width); |
| @@ -325,7 +325,7 @@ static bool cfg80211_valid_center_freq(u32 center, · 1 unmodified line | |||
| 325 | return false; | 325 | return false; |
| 326 | 326 | ||
| 327 | /* Validate that the channels bw is entirely within the 6 GHz band */ | 327 | /* Validate that the channels bw is entirely within the 6 GHz band */ |
| 328 | if (center - bw / 2 < 5945 || center + bw / 2 > 7125) | 328 | if (center - bw / 2 < 5945 || center + bw / 2 > 7225) |
| 329 | return false; | 329 | return false; |
| 330 | 330 | ||
| 331 | /* With 320 MHz the permitted channels overlap */ | 331 | /* With 320 MHz the permitted channels overlap */ |
| @@ -816,6 +816,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, · 484 unmodified lines | |||
| 816 | case NL80211_IFTYPE_MONITOR: | 816 | case NL80211_IFTYPE_MONITOR: |
| 817 | case NL80211_IFTYPE_AP_VLAN: | 817 | case NL80211_IFTYPE_AP_VLAN: |
| 818 | case NL80211_IFTYPE_P2P_DEVICE: | 818 | case NL80211_IFTYPE_P2P_DEVICE: |
| 819 | case NL80211_IFTYPE_NAN_DATA: | ||
| 819 | break; | 820 | break; |
| 820 | case NL80211_IFTYPE_WDS: | 821 | case NL80211_IFTYPE_WDS: |
| 821 | case NL80211_IFTYPE_UNSPECIFIED: | 822 | case NL80211_IFTYPE_UNSPECIFIED: |
| @@ -939,6 +940,7 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) · 117 unmodified lines | |||
| 939 | case NL80211_IFTYPE_P2P_DEVICE: | 940 | case NL80211_IFTYPE_P2P_DEVICE: |
| 940 | /* Can NAN type be considered as beaconing interface? */ | 941 | /* Can NAN type be considered as beaconing interface? */ |
| 941 | case NL80211_IFTYPE_NAN: | 942 | case NL80211_IFTYPE_NAN: |
| 943 | case NL80211_IFTYPE_NAN_DATA: | ||
| 942 | break; | 944 | break; |
| 943 | case NL80211_IFTYPE_UNSPECIFIED: | 945 | case NL80211_IFTYPE_UNSPECIFIED: |
| 944 | case NL80211_IFTYPE_WDS: | 946 | case NL80211_IFTYPE_WDS: |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
| 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
| 7 | * Copyright 2015-2017 Intel Deutschland GmbH | 7 | * Copyright 2015-2017 Intel Deutschland GmbH |
| 8 | * Copyright (C) 2018-2025 Intel Corporation | 8 | * Copyright (C) 2018-2026 Intel Corporation |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| @@ -254,6 +254,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, · 242 unmodified lines | |||
| 254 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, | 254 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, |
| 255 | struct wireless_dev *wdev) | 255 | struct wireless_dev *wdev) |
| 256 | { | 256 | { |
| 257 | struct cfg80211_nan_local_sched empty_sched = {}; | ||
| 258 | |||
| 257 | lockdep_assert_held(&rdev->wiphy.mtx); | 259 | lockdep_assert_held(&rdev->wiphy.mtx); |
| 258 | 260 | ||
| 259 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN)) | 261 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN)) |
| @@ -262,6 +264,15 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, · 2 unmodified lines | |||
| 262 | if (!wdev_running(wdev)) | 264 | if (!wdev_running(wdev)) |
| 263 | return; | 265 | return; |
| 264 | 266 | ||
| 267 | /* | ||
| 268 | * If there is a scheduled update pending, mark it as canceled, so the | ||
| 269 | * empty schedule will be accepted | ||
| 270 | */ | ||
| 271 | wdev->u.nan.sched_update_pending = false; | ||
| 272 | |||
| 273 | /* Unschedule all */ | ||
| 274 | cfg80211_nan_set_local_schedule(rdev, wdev, &empty_sched); | ||
| 275 | |||
| 265 | rdev_stop_nan(rdev, wdev); | 276 | rdev_stop_nan(rdev, wdev); |
| 266 | wdev->is_running = false; | 277 | wdev->is_running = false; |
| 267 | 278 | ||
| @@ -270,6 +281,47 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, · 2 unmodified lines | |||
| 270 | rdev->opencount--; | 281 | rdev->opencount--; |
| 271 | } | 282 | } |
| 272 | 283 | ||
| 284 | int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev, | ||
| 285 | struct wireless_dev *wdev, | ||
| 286 | struct cfg80211_nan_local_sched *sched) | ||
| 287 | { | ||
| 288 | int ret; | ||
| 289 | |||
| 290 | lockdep_assert_held(&rdev->wiphy.mtx); | ||
| 291 | |||
| 292 | if (wdev->iftype != NL80211_IFTYPE_NAN || !wdev_running(wdev)) | ||
| 293 | return -EINVAL; | ||
| 294 | |||
| 295 | if (wdev->u.nan.sched_update_pending) | ||
| 296 | return -EBUSY; | ||
| 297 | |||
| 298 | ret = rdev_nan_set_local_sched(rdev, wdev, sched); | ||
| 299 | if (ret) | ||
| 300 | return ret; | ||
| 301 | |||
| 302 | wdev->u.nan.sched_update_pending = sched->deferred; | ||
| 303 | |||
| 304 | kfree(wdev->u.nan.chandefs); | ||
| 305 | wdev->u.nan.chandefs = NULL; | ||
| 306 | wdev->u.nan.n_channels = 0; | ||
| 307 | |||
| 308 | if (!sched->n_channels) | ||
| 309 | return 0; | ||
| 310 | |||
| 311 | wdev->u.nan.chandefs = kcalloc(sched->n_channels, | ||
| 312 | sizeof(*wdev->u.nan.chandefs), | ||
| 313 | GFP_KERNEL); | ||
| 314 | if (!wdev->u.nan.chandefs) | ||
| 315 | return -ENOMEM; | ||
| 316 | |||
| 317 | for (int i = 0; i < sched->n_channels; i++) | ||
| 318 | wdev->u.nan.chandefs[i] = sched->nan_channels[i].chandef; | ||
| 319 | |||
| 320 | wdev->u.nan.n_channels = sched->n_channels; | ||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 273 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) | 325 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) |
| 274 | { | 326 | { |
| 275 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 327 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| @@ -277,16 +329,21 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) · 1 unmodified line | |||
| 277 | 329 | ||
| 278 | ASSERT_RTNL(); | 330 | ASSERT_RTNL(); |
| 279 | 331 | ||
| 332 | /* | ||
| 333 | * Some netdev interfaces need to be closed before some non-netdev | ||
| 334 | * ones, i.e. NAN_DATA interfaces need to be closed before the NAN | ||
| 335 | * interface | ||
| 336 | */ | ||
| 280 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | 337 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
| 281 | if (wdev->netdev) { | 338 | if (wdev->netdev) { |
| 282 | dev_close(wdev->netdev); | 339 | dev_close(wdev->netdev); |
| 283 | continue; | 340 | continue; |
| 284 | } | 341 | } |
| 342 | } | ||
| 285 | 343 | ||
| 286 | /* otherwise, check iftype */ | 344 | guard(wiphy)(wiphy); |
| 287 | |||
| 288 | guard(wiphy)(wiphy); | ||
| 289 | 345 | ||
| 346 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | ||
| 290 | switch (wdev->iftype) { | 347 | switch (wdev->iftype) { |
| 291 | case NL80211_IFTYPE_P2P_DEVICE: | 348 | case NL80211_IFTYPE_P2P_DEVICE: |
| 292 | cfg80211_stop_p2p_device(rdev, wdev); | 349 | cfg80211_stop_p2p_device(rdev, wdev); |
| @@ -344,6 +401,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) · 51 unmodified lines | |||
| 344 | 401 | ||
| 345 | list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { | 402 | list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { |
| 346 | if (wdev->nl_owner_dead) { | 403 | if (wdev->nl_owner_dead) { |
| 404 | cfg80211_close_dependents(rdev, wdev); | ||
| 405 | |||
| 347 | if (wdev->netdev) | 406 | if (wdev->netdev) |
| 348 | dev_close(wdev->netdev); | 407 | dev_close(wdev->netdev); |
| 349 | 408 | ||
| @@ -354,6 +413,21 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) · 4 unmodified lines | |||
| 354 | } | 413 | } |
| 355 | } | 414 | } |
| 356 | 415 | ||
| 416 | void cfg80211_close_dependents(struct cfg80211_registered_device *rdev, | ||
| 417 | struct wireless_dev *wdev) | ||
| 418 | { | ||
| 419 | ASSERT_RTNL(); | ||
| 420 | |||
| 421 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
| 422 | return; | ||
| 423 | |||
| 424 | /* Close all NAN DATA interfaces */ | ||
| 425 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | ||
| 426 | if (wdev->iftype == NL80211_IFTYPE_NAN_DATA) | ||
| 427 | dev_close(wdev->netdev); | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 357 | static void cfg80211_destroy_iface_wk(struct work_struct *work) | 431 | static void cfg80211_destroy_iface_wk(struct work_struct *work) |
| 358 | { | 432 | { |
| 359 | struct cfg80211_registered_device *rdev; | 433 | struct cfg80211_registered_device *rdev; |
| @@ -761,6 +835,10 @@ int wiphy_register(struct wiphy *wiphy) · 401 unmodified lines | |||
| 761 | !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))))) | 835 | !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))))) |
| 762 | return -EINVAL; | 836 | return -EINVAL; |
| 763 | 837 | ||
| 838 | if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN_DATA)) && | ||
| 839 | !wiphy->nan_capa.phy.ht.ht_supported)) | ||
| 840 | return -EINVAL; | ||
| 841 | |||
| 764 | if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))) | 842 | if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))) |
| 765 | return -EINVAL; | 843 | return -EINVAL; |
| 766 | 844 | ||
| @@ -1367,9 +1445,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, · 600 unmodified lines | |||
| 1367 | rdev->num_running_monitor_ifaces += num; | 1445 | rdev->num_running_monitor_ifaces += num; |
| 1368 | } | 1446 | } |
| 1369 | 1447 | ||
| 1370 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 1448 | void cfg80211_leave_locked(struct cfg80211_registered_device *rdev, |
| 1371 | struct wireless_dev *wdev, | 1449 | struct wireless_dev *wdev, int link_id) |
| 1372 | int link_id) | ||
| 1373 | { | 1450 | { |
| 1374 | struct net_device *dev = wdev->netdev; | 1451 | struct net_device *dev = wdev->netdev; |
| 1375 | struct cfg80211_sched_scan_request *pos, *tmp; | 1452 | struct cfg80211_sched_scan_request *pos, *tmp; |
| @@ -1420,6 +1497,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, · 44 unmodified lines | |||
| 1420 | break; | 1497 | break; |
| 1421 | case NL80211_IFTYPE_AP_VLAN: | 1498 | case NL80211_IFTYPE_AP_VLAN: |
| 1422 | case NL80211_IFTYPE_MONITOR: | 1499 | case NL80211_IFTYPE_MONITOR: |
| 1500 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1423 | /* nothing to do */ | 1501 | /* nothing to do */ |
| 1424 | break; | 1502 | break; |
| 1425 | case NL80211_IFTYPE_UNSPECIFIED: | 1503 | case NL80211_IFTYPE_UNSPECIFIED: |
| @@ -1430,6 +1508,19 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, · 4 unmodified lines | |||
| 1430 | } | 1508 | } |
| 1431 | } | 1509 | } |
| 1432 | 1510 | ||
| 1511 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | ||
| 1512 | struct wireless_dev *wdev, int link_id) | ||
| 1513 | { | ||
| 1514 | ASSERT_RTNL(); | ||
| 1515 | |||
| 1516 | /* NAN_DATA interfaces must be closed before stopping NAN */ | ||
| 1517 | cfg80211_close_dependents(rdev, wdev); | ||
| 1518 | |||
| 1519 | guard(wiphy)(&rdev->wiphy); | ||
| 1520 | |||
| 1521 | cfg80211_leave_locked(rdev, wdev, link_id); | ||
| 1522 | } | ||
| 1523 | |||
| 1433 | void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, | 1524 | void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1434 | int link_id, gfp_t gfp) | 1525 | int link_id, gfp_t gfp) |
| 1435 | { | 1526 | { |
| @@ -1445,6 +1536,9 @@ void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, · 9 unmodified lines | |||
| 1445 | 1536 | ||
| 1446 | trace_cfg80211_stop_link(wiphy, wdev, link_id); | 1537 | trace_cfg80211_stop_link(wiphy, wdev, link_id); |
| 1447 | 1538 | ||
| 1539 | if (wdev->iftype == NL80211_IFTYPE_NAN) | ||
| 1540 | return; | ||
| 1541 | |||
| 1448 | ev = kzalloc_obj(*ev, gfp); | 1542 | ev = kzalloc_obj(*ev, gfp); |
| 1449 | if (!ev) | 1543 | if (!ev) |
| 1450 | return; | 1544 | return; |
| @@ -1595,10 +1689,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 144 unmodified lines | |||
| 1595 | } | 1689 | } |
| 1596 | break; | 1690 | break; |
| 1597 | case NETDEV_GOING_DOWN: | 1691 | case NETDEV_GOING_DOWN: |
| 1598 | scoped_guard(wiphy, &rdev->wiphy) { | 1692 | cfg80211_leave(rdev, wdev, -1); |
| 1599 | cfg80211_leave(rdev, wdev, -1); | 1693 | scoped_guard(wiphy, &rdev->wiphy) |
| 1600 | cfg80211_remove_links(wdev); | 1694 | cfg80211_remove_links(wdev); |
| 1601 | } | ||
| 1602 | /* since we just did cfg80211_leave() nothing to do there */ | 1695 | /* since we just did cfg80211_leave() nothing to do there */ |
| 1603 | cancel_work_sync(&wdev->disconnect_wk); | 1696 | cancel_work_sync(&wdev->disconnect_wk); |
| 1604 | cancel_work_sync(&wdev->pmsr_free_wk); | 1697 | cancel_work_sync(&wdev->pmsr_free_wk); |
| @@ -1679,6 +1772,23 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 74 unmodified lines | |||
| 1679 | 1772 | ||
| 1680 | if (rfkill_blocked(rdev->wiphy.rfkill)) | 1773 | if (rfkill_blocked(rdev->wiphy.rfkill)) |
| 1681 | return notifier_from_errno(-ERFKILL); | 1774 | return notifier_from_errno(-ERFKILL); |
| 1775 | |||
| 1776 | /* NAN_DATA interfaces require a running NAN interface */ | ||
| 1777 | if (wdev->iftype == NL80211_IFTYPE_NAN_DATA) { | ||
| 1778 | struct wireless_dev *iter; | ||
| 1779 | bool nan_started = false; | ||
| 1780 | |||
| 1781 | list_for_each_entry(iter, &rdev->wiphy.wdev_list, list) { | ||
| 1782 | if (iter->iftype == NL80211_IFTYPE_NAN && | ||
| 1783 | wdev_running(iter)) { | ||
| 1784 | nan_started = true; | ||
| 1785 | break; | ||
| 1786 | } | ||
| 1787 | } | ||
| 1788 | |||
| 1789 | if (!nan_started) | ||
| 1790 | return notifier_from_errno(-ENOLINK); | ||
| 1791 | } | ||
| 1682 | break; | 1792 | break; |
| 1683 | default: | 1793 | default: |
| 1684 | return NOTIFY_DONE; | 1794 | return NOTIFY_DONE; |
| @@ -318,6 +318,9 @@ void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, · 317 unmodified lines | |||
| 318 | 318 | ||
| 319 | void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); | 319 | void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); |
| 320 | 320 | ||
| 321 | void cfg80211_close_dependents(struct cfg80211_registered_device *rdev, | ||
| 322 | struct wireless_dev *wdev); | ||
| 323 | |||
| 321 | /* free object */ | 324 | /* free object */ |
| 322 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 325 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
| 323 | 326 | ||
| @@ -541,6 +544,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, · 217 unmodified lines | |||
| 541 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 544 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
| 542 | enum nl80211_iftype iftype, int num); | 545 | enum nl80211_iftype iftype, int num); |
| 543 | 546 | ||
| 547 | void cfg80211_leave_locked(struct cfg80211_registered_device *rdev, | ||
| 548 | struct wireless_dev *wdev, int link_id); | ||
| 549 | |||
| 544 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 550 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
| 545 | struct wireless_dev *wdev, | 551 | struct wireless_dev *wdev, |
| 546 | int link_id); | 552 | int link_id); |
| @@ -551,6 +557,10 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, · 4 unmodified lines | |||
| 551 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, | 557 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, |
| 552 | struct wireless_dev *wdev); | 558 | struct wireless_dev *wdev); |
| 553 | 559 | ||
| 560 | int cfg80211_nan_set_local_schedule(struct cfg80211_registered_device *rdev, | ||
| 561 | struct wireless_dev *wdev, | ||
| 562 | struct cfg80211_nan_local_sched *sched); | ||
| 563 | |||
| 554 | struct cfg80211_internal_bss * | 564 | struct cfg80211_internal_bss * |
| 555 | cfg80211_bss_update(struct cfg80211_registered_device *rdev, | 565 | cfg80211_bss_update(struct cfg80211_registered_device *rdev, |
| 556 | struct cfg80211_internal_bss *tmp, | 566 | struct cfg80211_internal_bss *tmp, |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | |||
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> | 5 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> |
| 6 | * Copyright (c) 2015 Intel Deutschland GmbH | 6 | * Copyright (c) 2015 Intel Deutschland GmbH |
| 7 | * Copyright (C) 2019-2020, 2022-2025 Intel Corporation | 7 | * Copyright (C) 2019-2020, 2022-2026 Intel Corporation |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| @@ -782,8 +782,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) · 771 unmodified lines | |||
| 782 | rdev_crit_proto_stop(rdev, wdev); | 782 | rdev_crit_proto_stop(rdev, wdev); |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | if (nlportid == wdev->ap_unexpected_nlportid) | 785 | if (nlportid == wdev->unexpected_nlportid) |
| 786 | wdev->ap_unexpected_nlportid = 0; | 786 | wdev->unexpected_nlportid = 0; |
| 787 | } | 787 | } |
| 788 | 788 | ||
| 789 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | 789 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
| @@ -933,12 +933,17 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, · 143 unmodified lines | |||
| 933 | * cfg80211 doesn't track the stations | 933 | * cfg80211 doesn't track the stations |
| 934 | */ | 934 | */ |
| 935 | break; | 935 | break; |
| 936 | case NL80211_IFTYPE_NAN: | ||
| 937 | case NL80211_IFTYPE_NAN_DATA: | ||
| 938 | if (mgmt->u.action.category != | ||
| 939 | WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION) | ||
| 940 | err = -EOPNOTSUPP; | ||
| 941 | break; | ||
| 936 | case NL80211_IFTYPE_P2P_DEVICE: | 942 | case NL80211_IFTYPE_P2P_DEVICE: |
| 937 | /* | 943 | /* |
| 938 | * fall through, P2P device only supports | 944 | * fall through, P2P device only supports |
| 939 | * public action frames | 945 | * public action frames |
| 940 | */ | 946 | */ |
| 941 | case NL80211_IFTYPE_NAN: | ||
| 942 | default: | 947 | default: |
| 943 | err = -EOPNOTSUPP; | 948 | err = -EOPNOTSUPP; |
| 944 | break; | 949 | break; |
| @@ -333,6 +333,97 @@ static int validate_nan_cluster_id(const struct nlattr *attr, · 332 unmodified lines | |||
| 333 | return 0; | 333 | return 0; |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | static int validate_nan_avail_blob(const struct nlattr *attr, | ||
| 337 | struct netlink_ext_ack *extack) | ||
| 338 | { | ||
| 339 | const u8 *data = nla_data(attr); | ||
| 340 | unsigned int len = nla_len(attr); | ||
| 341 | u16 attr_len; | ||
| 342 | |||
| 343 | /* Need at least: Attr ID (1) + Length (2) */ | ||
| 344 | if (len < 3) { | ||
| 345 | NL_SET_ERR_MSG_FMT(extack, | ||
| 346 | "NAN Availability: Too short (need at least 3 bytes, have %u)", | ||
| 347 | len); | ||
| 348 | return -EINVAL; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (data[0] != 0x12) { | ||
| 352 | NL_SET_ERR_MSG_FMT(extack, | ||
| 353 | "NAN Availability: Invalid Attribute ID 0x%02x (expected 0x12)", | ||
| 354 | data[0]); | ||
| 355 | return -EINVAL; | ||
| 356 | } | ||
| 357 | |||
| 358 | attr_len = get_unaligned_le16(&data[1]); | ||
| 359 | |||
| 360 | if (attr_len != len - 3) { | ||
| 361 | NL_SET_ERR_MSG_FMT(extack, | ||
| 362 | "NAN Availability: Length field (%u) doesn't match data length (%u)", | ||
| 363 | attr_len, len - 3); | ||
| 364 | return -EINVAL; | ||
| 365 | } | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int validate_nan_ulw(const struct nlattr *attr, | ||
| 371 | struct netlink_ext_ack *extack) | ||
| 372 | { | ||
| 373 | const u8 *data = nla_data(attr); | ||
| 374 | unsigned int len = nla_len(attr); | ||
| 375 | unsigned int pos = 0; | ||
| 376 | |||
| 377 | while (pos < len) { | ||
| 378 | u16 attr_len; | ||
| 379 | |||
| 380 | /* Need at least: Attr ID (1) + Length (2) */ | ||
| 381 | if (pos + 3 > len) { | ||
| 382 | NL_SET_ERR_MSG_FMT(extack, | ||
| 383 | "ULW: Incomplete header (need 3 bytes, have %u)", | ||
| 384 | len - pos); | ||
| 385 | return -EINVAL; | ||
| 386 | } | ||
| 387 | |||
| 388 | if (data[pos] != 0x17) { | ||
| 389 | NL_SET_ERR_MSG_FMT(extack, | ||
| 390 | "ULW: Invalid Attribute ID 0x%02x (expected 0x17)", | ||
| 391 | data[pos]); | ||
| 392 | return -EINVAL; | ||
| 393 | } | ||
| 394 | pos++; | ||
| 395 | |||
| 396 | /* Length is in little-endian format */ | ||
| 397 | attr_len = get_unaligned_le16(&data[pos]); | ||
| 398 | pos += 2; | ||
| 399 | |||
| 400 | /* | ||
| 401 | * Check if length is one of the valid values: 16 (no | ||
| 402 | * channel/band entry included), 18 (band entry included), | ||
| 403 | * 21 (channel entry included without Auxiliary channel bitmap), | ||
| 404 | * or 23 (channel entry included with Auxiliary channel bitmap). | ||
| 405 | */ | ||
| 406 | if (attr_len != 16 && attr_len != 18 && attr_len != 21 && | ||
| 407 | attr_len != 23) { | ||
| 408 | NL_SET_ERR_MSG_FMT(extack, | ||
| 409 | "ULW: Invalid length %u (must be 16, 18, 21, or 23)", | ||
| 410 | attr_len); | ||
| 411 | return -EINVAL; | ||
| 412 | } | ||
| 413 | |||
| 414 | if (pos + attr_len > len) { | ||
| 415 | NL_SET_ERR_MSG_FMT(extack, | ||
| 416 | "ULW: Length field (%u) exceeds remaining data (%u)", | ||
| 417 | attr_len, len - pos); | ||
| 418 | return -EINVAL; | ||
| 419 | } | ||
| 420 | |||
| 421 | pos += attr_len; | ||
| 422 | } | ||
| 423 | |||
| 424 | return 0; | ||
| 425 | } | ||
| 426 | |||
| 336 | static int validate_uhr_capa(const struct nlattr *attr, | 427 | static int validate_uhr_capa(const struct nlattr *attr, |
| 337 | struct netlink_ext_ack *extack) | 428 | struct netlink_ext_ack *extack) |
| 338 | { | 429 | { |
| @@ -555,6 +646,13 @@ nl80211_nan_band_conf_policy[NL80211_NAN_BAND_CONF_ATTR_MAX + 1] = { · 216 unmodified lines | |||
| 555 | [NL80211_NAN_BAND_CONF_DISABLE_SCAN] = { .type = NLA_FLAG }, | 646 | [NL80211_NAN_BAND_CONF_DISABLE_SCAN] = { .type = NLA_FLAG }, |
| 556 | }; | 647 | }; |
| 557 | 648 | ||
| 649 | static const struct nla_policy | ||
| 650 | nl80211_nan_peer_map_policy[NL80211_NAN_PEER_MAP_ATTR_MAX + 1] = { | ||
| 651 | [NL80211_NAN_PEER_MAP_ATTR_MAP_ID] = NLA_POLICY_MAX(NLA_U8, 15), | ||
| 652 | [NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS] = | ||
| 653 | NLA_POLICY_EXACT_LEN(CFG80211_NAN_SCHED_NUM_TIME_SLOTS), | ||
| 654 | }; | ||
| 655 | |||
| 558 | static const struct nla_policy | 656 | static const struct nla_policy |
| 559 | nl80211_nan_conf_policy[NL80211_NAN_CONF_ATTR_MAX + 1] = { | 657 | nl80211_nan_conf_policy[NL80211_NAN_CONF_ATTR_MAX + 1] = { |
| 560 | [NL80211_NAN_CONF_CLUSTER_ID] = | 658 | [NL80211_NAN_CONF_CLUSTER_ID] = |
| @@ -962,6 +1060,22 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 401 unmodified lines | |||
| 962 | [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, | 1060 | [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, |
| 963 | [NL80211_ATTR_UHR_OPERATION] = | 1061 | [NL80211_ATTR_UHR_OPERATION] = |
| 964 | NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_operation), | 1062 | NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_uhr_operation), |
| 1063 | [NL80211_ATTR_NAN_CHANNEL] = NLA_POLICY_NESTED(nl80211_policy), | ||
| 1064 | [NL80211_ATTR_NAN_CHANNEL_ENTRY] = NLA_POLICY_EXACT_LEN(6), | ||
| 1065 | [NL80211_ATTR_NAN_RX_NSS] = { .type = NLA_U8 }, | ||
| 1066 | [NL80211_ATTR_NAN_TIME_SLOTS] = | ||
| 1067 | NLA_POLICY_EXACT_LEN(CFG80211_NAN_SCHED_NUM_TIME_SLOTS), | ||
| 1068 | [NL80211_ATTR_NAN_AVAIL_BLOB] = | ||
| 1069 | NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_nan_avail_blob), | ||
| 1070 | [NL80211_ATTR_NAN_SCHED_DEFERRED] = { .type = NLA_FLAG }, | ||
| 1071 | [NL80211_ATTR_NAN_NMI_MAC] = NLA_POLICY_ETH_ADDR, | ||
| 1072 | [NL80211_ATTR_NAN_ULW] = | ||
| 1073 | NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_nan_ulw), | ||
| 1074 | [NL80211_ATTR_NAN_COMMITTED_DW] = { .type = NLA_U16 }, | ||
| 1075 | [NL80211_ATTR_NAN_SEQ_ID] = { .type = NLA_U8 }, | ||
| 1076 | [NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME] = { .type = NLA_U16 }, | ||
| 1077 | [NL80211_ATTR_NAN_PEER_MAPS] = | ||
| 1078 | NLA_POLICY_NESTED_ARRAY(nl80211_nan_peer_map_policy), | ||
| 965 | }; | 1079 | }; |
| 966 | 1080 | ||
| 967 | /* policy for the key attributes */ | 1081 | /* policy for the key attributes */ |
| @@ -1722,6 +1836,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) · 754 unmodified lines | |||
| 1722 | return 0; | 1836 | return 0; |
| 1723 | return -ENOLINK; | 1837 | return -ENOLINK; |
| 1724 | case NL80211_IFTYPE_NAN: | 1838 | case NL80211_IFTYPE_NAN: |
| 1839 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1725 | if (wiphy_ext_feature_isset(wdev->wiphy, | 1840 | if (wiphy_ext_feature_isset(wdev->wiphy, |
| 1726 | NL80211_EXT_FEATURE_SECURE_NAN)) | 1841 | NL80211_EXT_FEATURE_SECURE_NAN)) |
| 1727 | return 0; | 1842 | return 0; |
| @@ -2678,6 +2793,68 @@ fail: · 950 unmodified lines | |||
| 2678 | return -ENOBUFS; | 2793 | return -ENOBUFS; |
| 2679 | } | 2794 | } |
| 2680 | 2795 | ||
| 2796 | static int nl80211_put_nan_phy_cap(struct wiphy *wiphy, struct sk_buff *msg) | ||
| 2797 | { | ||
| 2798 | struct nlattr *nl_phy_cap; | ||
| 2799 | const struct ieee80211_sta_ht_cap *ht_cap; | ||
| 2800 | const struct ieee80211_sta_vht_cap *vht_cap; | ||
| 2801 | const struct ieee80211_sta_he_cap *he_cap; | ||
| 2802 | |||
| 2803 | if (!cfg80211_iftype_allowed(wiphy, NL80211_IFTYPE_NAN_DATA, false, 0)) | ||
| 2804 | return 0; | ||
| 2805 | |||
| 2806 | ht_cap = &wiphy->nan_capa.phy.ht; | ||
| 2807 | vht_cap = &wiphy->nan_capa.phy.vht; | ||
| 2808 | he_cap = &wiphy->nan_capa.phy.he; | ||
| 2809 | |||
| 2810 | /* HT is mandatory */ | ||
| 2811 | if (WARN_ON(!ht_cap->ht_supported)) | ||
| 2812 | return 0; | ||
| 2813 | |||
| 2814 | nl_phy_cap = nla_nest_start_noflag(msg, NL80211_NAN_CAPA_PHY); | ||
| 2815 | if (!nl_phy_cap) | ||
| 2816 | return -ENOBUFS; | ||
| 2817 | |||
| 2818 | if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET, | ||
| 2819 | sizeof(ht_cap->mcs), &ht_cap->mcs) || | ||
| 2820 | nla_put_u16(msg, NL80211_NAN_PHY_CAP_ATTR_HT_CAPA, ht_cap->cap) || | ||
| 2821 | nla_put_u8(msg, NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR, | ||
| 2822 | ht_cap->ampdu_factor) || | ||
| 2823 | nla_put_u8(msg, NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY, | ||
| 2824 | ht_cap->ampdu_density)) | ||
| 2825 | goto fail; | ||
| 2826 | |||
| 2827 | if (vht_cap->vht_supported) { | ||
| 2828 | if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET, | ||
| 2829 | sizeof(vht_cap->vht_mcs), &vht_cap->vht_mcs) || | ||
| 2830 | nla_put_u32(msg, NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA, | ||
| 2831 | vht_cap->cap)) | ||
| 2832 | goto fail; | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | if (he_cap->has_he) { | ||
| 2836 | if (nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_MAC, | ||
| 2837 | sizeof(he_cap->he_cap_elem.mac_cap_info), | ||
| 2838 | he_cap->he_cap_elem.mac_cap_info) || | ||
| 2839 | nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_PHY, | ||
| 2840 | sizeof(he_cap->he_cap_elem.phy_cap_info), | ||
| 2841 | he_cap->he_cap_elem.phy_cap_info) || | ||
| 2842 | nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET, | ||
| 2843 | sizeof(he_cap->he_mcs_nss_supp), | ||
| 2844 | &he_cap->he_mcs_nss_supp) || | ||
| 2845 | nla_put(msg, NL80211_NAN_PHY_CAP_ATTR_HE_PPE, | ||
| 2846 | sizeof(he_cap->ppe_thres), he_cap->ppe_thres)) | ||
| 2847 | goto fail; | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | nla_nest_end(msg, nl_phy_cap); | ||
| 2851 | return 0; | ||
| 2852 | |||
| 2853 | fail: | ||
| 2854 | nla_nest_cancel(msg, nl_phy_cap); | ||
| 2855 | return -ENOBUFS; | ||
| 2856 | } | ||
| 2857 | |||
| 2681 | static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg) | 2858 | static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg) |
| 2682 | { | 2859 | { |
| 2683 | struct nlattr *nan_caps; | 2860 | struct nlattr *nan_caps; |
| @@ -2704,6 +2881,9 @@ static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg) · 20 unmodified lines | |||
| 2704 | wiphy->nan_capa.dev_capabilities)) | 2881 | wiphy->nan_capa.dev_capabilities)) |
| 2705 | goto fail; | 2882 | goto fail; |
| 2706 | 2883 | ||
| 2884 | if (nl80211_put_nan_phy_cap(wiphy, msg)) | ||
| 2885 | goto fail; | ||
| 2886 | |||
| 2707 | nla_nest_end(msg, nan_caps); | 2887 | nla_nest_end(msg, nan_caps); |
| 2708 | 2888 | ||
| 2709 | return 0; | 2889 | return 0; |
| @@ -4879,6 +5059,8 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) · 2169 unmodified lines | |||
| 4879 | else | 5059 | else |
| 4880 | dev_close(wdev->netdev); | 5060 | dev_close(wdev->netdev); |
| 4881 | 5061 | ||
| 5062 | cfg80211_close_dependents(rdev, wdev); | ||
| 5063 | |||
| 4882 | mutex_lock(&rdev->wiphy.mtx); | 5064 | mutex_lock(&rdev->wiphy.mtx); |
| 4883 | 5065 | ||
| 4884 | return cfg80211_remove_virtual_intf(rdev, wdev); | 5066 | return cfg80211_remove_virtual_intf(rdev, wdev); |
| @@ -7123,6 +7305,26 @@ static int parse_station_flags(struct genl_info *info, · 2238 unmodified lines | |||
| 7123 | if ((params->sta_flags_mask | | 7305 | if ((params->sta_flags_mask | |
| 7124 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | 7306 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
| 7125 | return -EINVAL; | 7307 | return -EINVAL; |
| 7308 | |||
| 7309 | if ((iftype == NL80211_IFTYPE_NAN || | ||
| 7310 | iftype == NL80211_IFTYPE_NAN_DATA) && | ||
| 7311 | params->sta_flags_mask & | ||
| 7312 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
| 7313 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
| 7314 | BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 7315 | BIT(NL80211_STA_FLAG_MFP))) | ||
| 7316 | return -EINVAL; | ||
| 7317 | |||
| 7318 | /* WME is always used in NAN */ | ||
| 7319 | if (iftype == NL80211_IFTYPE_NAN_DATA) { | ||
| 7320 | /* but don't let userspace control it */ | ||
| 7321 | if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME)) | ||
| 7322 | return -EINVAL; | ||
| 7323 | |||
| 7324 | params->sta_flags_mask |= BIT(NL80211_STA_FLAG_WME); | ||
| 7325 | params->sta_flags_set |= BIT(NL80211_STA_FLAG_WME); | ||
| 7326 | } | ||
| 7327 | |||
| 7126 | return 0; | 7328 | return 0; |
| 7127 | } | 7329 | } |
| 7128 | 7330 | ||
| @@ -8005,7 +8207,7 @@ static int nl80211_dump_station(struct sk_buff *skb, · 876 unmodified lines | |||
| 8005 | /* nl80211_prepare_wdev_dump acquired it in the successful case */ | 8207 | /* nl80211_prepare_wdev_dump acquired it in the successful case */ |
| 8006 | __acquire(&rdev->wiphy.mtx); | 8208 | __acquire(&rdev->wiphy.mtx); |
| 8007 | 8209 | ||
| 8008 | if (!wdev->netdev) { | 8210 | if (!wdev->netdev && wdev->iftype != NL80211_IFTYPE_NAN) { |
| 8009 | err = -EINVAL; | 8211 | err = -EINVAL; |
| 8010 | goto out_err; | 8212 | goto out_err; |
| 8011 | } | 8213 | } |
| @@ -8192,10 +8394,12 @@ int cfg80211_check_station_change(struct wiphy *wiphy, · 180 unmodified lines | |||
| 8192 | return -EINVAL; | 8394 | return -EINVAL; |
| 8193 | if (params->link_sta_params.supported_rates) | 8395 | if (params->link_sta_params.supported_rates) |
| 8194 | return -EINVAL; | 8396 | return -EINVAL; |
| 8195 | if (params->ext_capab || params->link_sta_params.ht_capa || | 8397 | if (statype != CFG80211_STA_NAN_MGMT && |
| 8196 | params->link_sta_params.vht_capa || | 8398 | (params->link_sta_params.ht_capa || |
| 8197 | params->link_sta_params.he_capa || | 8399 | params->link_sta_params.vht_capa || |
| 8198 | params->link_sta_params.eht_capa || | 8400 | params->link_sta_params.he_capa)) |
| 8401 | return -EINVAL; | ||
| 8402 | if (params->ext_capab || params->link_sta_params.eht_capa || | ||
| 8199 | params->link_sta_params.uhr_capa) | 8403 | params->link_sta_params.uhr_capa) |
| 8200 | return -EINVAL; | 8404 | return -EINVAL; |
| 8201 | if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) | 8405 | if (params->sta_flags_mask & BIT(NL80211_STA_FLAG_SPP_AMSDU)) |
| @@ -8267,6 +8471,19 @@ int cfg80211_check_station_change(struct wiphy *wiphy, · 65 unmodified lines | |||
| 8267 | params->plink_action != NL80211_PLINK_ACTION_BLOCK) | 8471 | params->plink_action != NL80211_PLINK_ACTION_BLOCK) |
| 8268 | return -EINVAL; | 8472 | return -EINVAL; |
| 8269 | break; | 8473 | break; |
| 8474 | case CFG80211_STA_NAN_MGMT: | ||
| 8475 | if (params->sta_flags_mask & | ||
| 8476 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 8477 | BIT(NL80211_STA_FLAG_MFP))) | ||
| 8478 | return -EINVAL; | ||
| 8479 | break; | ||
| 8480 | case CFG80211_STA_NAN_DATA: | ||
| 8481 | if (params->sta_flags_mask & | ||
| 8482 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
| 8483 | BIT(NL80211_STA_FLAG_MFP) | | ||
| 8484 | BIT(NL80211_STA_FLAG_WME))) | ||
| 8485 | return -EINVAL; | ||
| 8486 | break; | ||
| 8270 | } | 8487 | } |
| 8271 | 8488 | ||
| 8272 | /* | 8489 | /* |
| @@ -8481,7 +8698,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) · 208 unmodified lines | |||
| 8481 | 8698 | ||
| 8482 | memset(¶ms, 0, sizeof(params)); | 8699 | memset(¶ms, 0, sizeof(params)); |
| 8483 | 8700 | ||
| 8484 | if (!dev) | 8701 | if (!dev && wdev->iftype != NL80211_IFTYPE_NAN && |
| 8702 | wdev->iftype != NL80211_IFTYPE_NAN_DATA) | ||
| 8485 | return -EINVAL; | 8703 | return -EINVAL; |
| 8486 | 8704 | ||
| 8487 | if (!rdev->ops->change_station) | 8705 | if (!rdev->ops->change_station) |
| @@ -8624,6 +8842,8 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) · 136 unmodified lines | |||
| 8624 | case NL80211_IFTYPE_STATION: | 8842 | case NL80211_IFTYPE_STATION: |
| 8625 | case NL80211_IFTYPE_ADHOC: | 8843 | case NL80211_IFTYPE_ADHOC: |
| 8626 | case NL80211_IFTYPE_MESH_POINT: | 8844 | case NL80211_IFTYPE_MESH_POINT: |
| 8845 | case NL80211_IFTYPE_NAN: | ||
| 8846 | case NL80211_IFTYPE_NAN_DATA: | ||
| 8627 | break; | 8847 | break; |
| 8628 | default: | 8848 | default: |
| 8629 | err = -EOPNOTSUPP; | 8849 | err = -EOPNOTSUPP; |
| @@ -8652,7 +8872,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 22 unmodified lines | |||
| 8652 | 8872 | ||
| 8653 | memset(¶ms, 0, sizeof(params)); | 8873 | memset(¶ms, 0, sizeof(params)); |
| 8654 | 8874 | ||
| 8655 | if (!dev) | 8875 | if (!dev && wdev->iftype != NL80211_IFTYPE_NAN) |
| 8656 | return -EINVAL; | 8876 | return -EINVAL; |
| 8657 | 8877 | ||
| 8658 | if (!rdev->ops->add_station) | 8878 | if (!rdev->ops->add_station) |
| @@ -8661,15 +8881,31 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 2 unmodified lines | |||
| 8661 | if (!info->attrs[NL80211_ATTR_MAC]) | 8881 | if (!info->attrs[NL80211_ATTR_MAC]) |
| 8662 | return -EINVAL; | 8882 | return -EINVAL; |
| 8663 | 8883 | ||
| 8664 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 8884 | if (wdev->iftype == NL80211_IFTYPE_NAN || |
| 8665 | return -EINVAL; | 8885 | wdev->iftype == NL80211_IFTYPE_NAN_DATA) { |
| 8886 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | ||
| 8887 | return -EINVAL; | ||
| 8888 | if (wdev->iftype == NL80211_IFTYPE_NAN_DATA) { | ||
| 8889 | if (!info->attrs[NL80211_ATTR_NAN_NMI_MAC]) | ||
| 8890 | return -EINVAL; | ||
| 8666 | 8891 | ||
| 8667 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | 8892 | /* Only NMI stations receive the HT/VHT/HE capabilities */ |
| 8668 | return -EINVAL; | 8893 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || |
| 8894 | info->attrs[NL80211_ATTR_VHT_CAPABILITY] || | ||
| 8895 | info->attrs[NL80211_ATTR_HE_CAPABILITY]) | ||
| 8896 | return -EINVAL; | ||
| 8897 | } | ||
| 8898 | } else { | ||
| 8899 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
| 8900 | return -EINVAL; | ||
| 8669 | 8901 | ||
| 8670 | if (!info->attrs[NL80211_ATTR_STA_AID] && | 8902 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) |
| 8671 | !info->attrs[NL80211_ATTR_PEER_AID]) | 8903 | return -EINVAL; |
| 8672 | return -EINVAL; | 8904 | |
| 8905 | if (!info->attrs[NL80211_ATTR_STA_AID] && | ||
| 8906 | !info->attrs[NL80211_ATTR_PEER_AID]) | ||
| 8907 | return -EINVAL; | ||
| 8908 | } | ||
| 8673 | 8909 | ||
| 8674 | params.link_sta_params.link_id = | 8910 | params.link_sta_params.link_id = |
| 8675 | nl80211_link_id_or_invalid(info->attrs); | 8911 | nl80211_link_id_or_invalid(info->attrs); |
| @@ -8685,12 +8921,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 9 unmodified lines | |||
| 8685 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 8921 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
| 8686 | } | 8922 | } |
| 8687 | 8923 | ||
| 8688 | params.link_sta_params.supported_rates = | 8924 | if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { |
| 8689 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 8925 | params.link_sta_params.supported_rates = |
| 8690 | params.link_sta_params.supported_rates_len = | 8926 | nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
| 8691 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 8927 | params.link_sta_params.supported_rates_len = |
| 8692 | params.listen_interval = | 8928 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
| 8693 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 8929 | } |
| 8930 | |||
| 8931 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
| 8932 | params.listen_interval = | ||
| 8933 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | ||
| 8694 | 8934 | ||
| 8695 | if (info->attrs[NL80211_ATTR_VLAN_ID]) | 8935 | if (info->attrs[NL80211_ATTR_VLAN_ID]) |
| 8696 | params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]); | 8936 | params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]); |
| @@ -8709,7 +8949,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 12 unmodified lines | |||
| 8709 | 8949 | ||
| 8710 | if (info->attrs[NL80211_ATTR_PEER_AID]) | 8950 | if (info->attrs[NL80211_ATTR_PEER_AID]) |
| 8711 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); | 8951 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); |
| 8712 | else | 8952 | else if (info->attrs[NL80211_ATTR_STA_AID]) |
| 8713 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 8953 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
| 8714 | 8954 | ||
| 8715 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { | 8955 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { |
| @@ -8830,6 +9070,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 114 unmodified lines | |||
| 8830 | return -EINVAL; | 9070 | return -EINVAL; |
| 8831 | } | 9071 | } |
| 8832 | 9072 | ||
| 9073 | if (wdev->iftype == NL80211_IFTYPE_NAN || | ||
| 9074 | wdev->iftype == NL80211_IFTYPE_NAN_DATA) { | ||
| 9075 | if (params.sta_modify_mask & STATION_PARAM_APPLY_UAPSD) | ||
| 9076 | return -EINVAL; | ||
| 9077 | /* NAN NMI station must be added in associated or authorized state */ | ||
| 9078 | if (!(params.sta_flags_set & (BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
| 9079 | BIT(NL80211_STA_FLAG_AUTHENTICATED)))) | ||
| 9080 | return -EINVAL; | ||
| 9081 | } | ||
| 9082 | |||
| 8833 | /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */ | 9083 | /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */ |
| 8834 | if (params.link_sta_params.he_6ghz_capa && | 9084 | if (params.link_sta_params.he_6ghz_capa && |
| 8835 | (params.link_sta_params.ht_capa || params.link_sta_params.vht_capa)) | 9085 | (params.link_sta_params.ht_capa || params.link_sta_params.vht_capa)) |
| @@ -8922,6 +9172,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) · 86 unmodified lines | |||
| 8922 | */ | 9172 | */ |
| 8923 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); | 9173 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); |
| 8924 | break; | 9174 | break; |
| 9175 | case NL80211_IFTYPE_NAN: | ||
| 9176 | break; | ||
| 9177 | case NL80211_IFTYPE_NAN_DATA: | ||
| 9178 | params.nmi_mac = nla_data(info->attrs[NL80211_ATTR_NAN_NMI_MAC]); | ||
| 9179 | break; | ||
| 8925 | default: | 9180 | default: |
| 8926 | return -EOPNOTSUPP; | 9181 | return -EOPNOTSUPP; |
| 8927 | } | 9182 | } |
| @@ -8963,7 +9218,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) · 35 unmodified lines | |||
| 8963 | 9218 | ||
| 8964 | memset(¶ms, 0, sizeof(params)); | 9219 | memset(¶ms, 0, sizeof(params)); |
| 8965 | 9220 | ||
| 8966 | if (!dev) | 9221 | if (!dev && wdev->iftype != NL80211_IFTYPE_NAN) |
| 8967 | return -EINVAL; | 9222 | return -EINVAL; |
| 8968 | 9223 | ||
| 8969 | if (info->attrs[NL80211_ATTR_MAC]) | 9224 | if (info->attrs[NL80211_ATTR_MAC]) |
| @@ -8974,6 +9229,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) · 4 unmodified lines | |||
| 8974 | case NL80211_IFTYPE_AP_VLAN: | 9229 | case NL80211_IFTYPE_AP_VLAN: |
| 8975 | case NL80211_IFTYPE_MESH_POINT: | 9230 | case NL80211_IFTYPE_MESH_POINT: |
| 8976 | case NL80211_IFTYPE_P2P_GO: | 9231 | case NL80211_IFTYPE_P2P_GO: |
| 9232 | case NL80211_IFTYPE_NAN: | ||
| 9233 | case NL80211_IFTYPE_NAN_DATA: | ||
| 8977 | /* always accept these */ | 9234 | /* always accept these */ |
| 8978 | break; | 9235 | break; |
| 8979 | case NL80211_IFTYPE_ADHOC: | 9236 | case NL80211_IFTYPE_ADHOC: |
| @@ -13950,6 +14207,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) · 4970 unmodified lines | |||
| 13950 | case NL80211_IFTYPE_P2P_DEVICE: | 14207 | case NL80211_IFTYPE_P2P_DEVICE: |
| 13951 | break; | 14208 | break; |
| 13952 | case NL80211_IFTYPE_NAN: | 14209 | case NL80211_IFTYPE_NAN: |
| 14210 | case NL80211_IFTYPE_NAN_DATA: | ||
| 13953 | if (!wiphy_ext_feature_isset(wdev->wiphy, | 14211 | if (!wiphy_ext_feature_isset(wdev->wiphy, |
| 13954 | NL80211_EXT_FEATURE_SECURE_NAN) && | 14212 | NL80211_EXT_FEATURE_SECURE_NAN) && |
| 13955 | !(wdev->wiphy->nan_capa.flags & | 14213 | !(wdev->wiphy->nan_capa.flags & |
| @@ -14013,6 +14271,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) · 57 unmodified lines | |||
| 14013 | case NL80211_IFTYPE_P2P_GO: | 14271 | case NL80211_IFTYPE_P2P_GO: |
| 14014 | break; | 14272 | break; |
| 14015 | case NL80211_IFTYPE_NAN: | 14273 | case NL80211_IFTYPE_NAN: |
| 14274 | case NL80211_IFTYPE_NAN_DATA: | ||
| 14016 | if (!wiphy_ext_feature_isset(wdev->wiphy, | 14275 | if (!wiphy_ext_feature_isset(wdev->wiphy, |
| 14017 | NL80211_EXT_FEATURE_SECURE_NAN) && | 14276 | NL80211_EXT_FEATURE_SECURE_NAN) && |
| 14018 | !(wdev->wiphy->nan_capa.flags & | 14277 | !(wdev->wiphy->nan_capa.flags & |
| @@ -15520,13 +15779,14 @@ static int nl80211_register_unexpected_frame(struct sk_buff *skb, · 1501 unmodified lines | |||
| 15520 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 15779 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 15521 | 15780 | ||
| 15522 | if (wdev->iftype != NL80211_IFTYPE_AP && | 15781 | if (wdev->iftype != NL80211_IFTYPE_AP && |
| 15523 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 15782 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
| 15783 | wdev->iftype != NL80211_IFTYPE_NAN_DATA) | ||
| 15524 | return -EINVAL; | 15784 | return -EINVAL; |
| 15525 | 15785 | ||
| 15526 | if (wdev->ap_unexpected_nlportid) | 15786 | if (wdev->unexpected_nlportid) |
| 15527 | return -EBUSY; | 15787 | return -EBUSY; |
| 15528 | 15788 | ||
| 15529 | wdev->ap_unexpected_nlportid = info->snd_portid; | 15789 | wdev->unexpected_nlportid = info->snd_portid; |
| 15530 | return 0; | 15790 | return 0; |
| 15531 | } | 15791 | } |
| 15532 | 15792 | ||
| @@ -15922,6 +16182,10 @@ static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info) · 389 unmodified lines | |||
| 15922 | if (wdev->iftype != NL80211_IFTYPE_NAN) | 16182 | if (wdev->iftype != NL80211_IFTYPE_NAN) |
| 15923 | return -EOPNOTSUPP; | 16183 | return -EOPNOTSUPP; |
| 15924 | 16184 | ||
| 16185 | cfg80211_close_dependents(rdev, wdev); | ||
| 16186 | |||
| 16187 | guard(wiphy)(&rdev->wiphy); | ||
| 16188 | |||
| 15925 | cfg80211_stop_nan(rdev, wdev); | 16189 | cfg80211_stop_nan(rdev, wdev); |
| 15926 | 16190 | ||
| 15927 | return 0; | 16191 | return 0; |
| @@ -16421,6 +16685,482 @@ nla_put_failure: · 493 unmodified lines | |||
| 16421 | } | 16685 | } |
| 16422 | EXPORT_SYMBOL(cfg80211_nan_func_terminated); | 16686 | EXPORT_SYMBOL(cfg80211_nan_func_terminated); |
| 16423 | 16687 | ||
| 16688 | void cfg80211_nan_sched_update_done(struct wireless_dev *wdev, bool success, | ||
| 16689 | gfp_t gfp) | ||
| 16690 | { | ||
| 16691 | struct wiphy *wiphy = wdev->wiphy; | ||
| 16692 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
| 16693 | struct sk_buff *msg; | ||
| 16694 | void *hdr; | ||
| 16695 | |||
| 16696 | trace_cfg80211_nan_sched_update_done(wiphy, wdev, success); | ||
| 16697 | |||
| 16698 | /* Can happen if we stopped NAN */ | ||
| 16699 | if (!wdev->u.nan.sched_update_pending) | ||
| 16700 | return; | ||
| 16701 | |||
| 16702 | wdev->u.nan.sched_update_pending = false; | ||
| 16703 | |||
| 16704 | if (!wdev->owner_nlportid) | ||
| 16705 | return; | ||
| 16706 | |||
| 16707 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
| 16708 | if (!msg) | ||
| 16709 | return; | ||
| 16710 | |||
| 16711 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_SCHED_UPDATE_DONE); | ||
| 16712 | if (!hdr) | ||
| 16713 | goto nla_put_failure; | ||
| 16714 | |||
| 16715 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
| 16716 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
| 16717 | NL80211_ATTR_PAD) || | ||
| 16718 | (success && | ||
| 16719 | nla_put_flag(msg, NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS))) | ||
| 16720 | goto nla_put_failure; | ||
| 16721 | |||
| 16722 | genlmsg_end(msg, hdr); | ||
| 16723 | |||
| 16724 | genlmsg_unicast(wiphy_net(wiphy), msg, wdev->owner_nlportid); | ||
| 16725 | |||
| 16726 | return; | ||
| 16727 | |||
| 16728 | nla_put_failure: | ||
| 16729 | nlmsg_free(msg); | ||
| 16730 | } | ||
| 16731 | EXPORT_SYMBOL(cfg80211_nan_sched_update_done); | ||
| 16732 | |||
| 16733 | static int nl80211_parse_nan_channel(struct cfg80211_registered_device *rdev, | ||
| 16734 | struct nlattr *channel, | ||
| 16735 | struct genl_info *info, | ||
| 16736 | struct cfg80211_nan_channel *nan_channels, | ||
| 16737 | u8 index, bool local) | ||
| 16738 | { | ||
| 16739 | struct nlattr **channel_parsed __free(kfree) = NULL; | ||
| 16740 | struct cfg80211_chan_def chandef; | ||
| 16741 | u8 n_rx_nss; | ||
| 16742 | int ret; | ||
| 16743 | |||
| 16744 | channel_parsed = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*channel_parsed), | ||
| 16745 | GFP_KERNEL); | ||
| 16746 | if (!channel_parsed) | ||
| 16747 | return -ENOMEM; | ||
| 16748 | |||
| 16749 | ret = nla_parse_nested(channel_parsed, NL80211_ATTR_MAX, channel, NULL, | ||
| 16750 | info->extack); | ||
| 16751 | if (ret) | ||
| 16752 | return ret; | ||
| 16753 | |||
| 16754 | ret = nl80211_parse_chandef(rdev, info->extack, channel_parsed, | ||
| 16755 | &chandef); | ||
| 16756 | if (ret) | ||
| 16757 | return ret; | ||
| 16758 | |||
| 16759 | if (chandef.chan->band == NL80211_BAND_6GHZ) { | ||
| 16760 | NL_SET_ERR_MSG(info->extack, | ||
| 16761 | "6 GHz band is not supported"); | ||
| 16762 | return -EOPNOTSUPP; | ||
| 16763 | } | ||
| 16764 | |||
| 16765 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, | ||
| 16766 | NL80211_IFTYPE_NAN)) { | ||
| 16767 | NL_SET_ERR_MSG_ATTR(info->extack, channel, | ||
| 16768 | "Channel in NAN schedule is not allowed for NAN operation"); | ||
| 16769 | return -EINVAL; | ||
| 16770 | } | ||
| 16771 | |||
| 16772 | if (local) { | ||
| 16773 | for (int i = 0; i < index; i++) { | ||
| 16774 | if (cfg80211_chandef_compatible(&nan_channels[i].chandef, | ||
| 16775 | &chandef)) { | ||
| 16776 | NL_SET_ERR_MSG_ATTR(info->extack, channel, | ||
| 16777 | "Channels in NAN schedule must be mutually incompatible"); | ||
| 16778 | return -EINVAL; | ||
| 16779 | } | ||
| 16780 | } | ||
| 16781 | } | ||
| 16782 | |||
| 16783 | if (!channel_parsed[NL80211_ATTR_NAN_CHANNEL_ENTRY]) { | ||
| 16784 | NL_SET_ERR_MSG(info->extack, | ||
| 16785 | "Missing NAN channel entry attribute"); | ||
| 16786 | return -EINVAL; | ||
| 16787 | } | ||
| 16788 | |||
| 16789 | nan_channels[index].channel_entry = | ||
| 16790 | nla_data(channel_parsed[NL80211_ATTR_NAN_CHANNEL_ENTRY]); | ||
| 16791 | |||
| 16792 | if (!channel_parsed[NL80211_ATTR_NAN_RX_NSS]) { | ||
| 16793 | NL_SET_ERR_MSG(info->extack, | ||
| 16794 | "Missing NAN RX NSS attribute"); | ||
| 16795 | return -EINVAL; | ||
| 16796 | } | ||
| 16797 | |||
| 16798 | nan_channels[index].rx_nss = | ||
| 16799 | nla_get_u8(channel_parsed[NL80211_ATTR_NAN_RX_NSS]); | ||
| 16800 | |||
| 16801 | n_rx_nss = u8_get_bits(rdev->wiphy.nan_capa.n_antennas, 0x03); | ||
| 16802 | if ((local && nan_channels[index].rx_nss > n_rx_nss) || | ||
| 16803 | !nan_channels[index].rx_nss) { | ||
| 16804 | NL_SET_ERR_MSG_ATTR(info->extack, channel, | ||
| 16805 | "Invalid RX NSS in NAN channel definition"); | ||
| 16806 | return -EINVAL; | ||
| 16807 | } | ||
| 16808 | |||
| 16809 | nan_channels[index].chandef = chandef; | ||
| 16810 | |||
| 16811 | return 0; | ||
| 16812 | } | ||
| 16813 | |||
| 16814 | static int | ||
| 16815 | nl80211_parse_nan_schedule(struct genl_info *info, struct nlattr *slots_attr, | ||
| 16816 | u8 schedule[CFG80211_NAN_SCHED_NUM_TIME_SLOTS], | ||
| 16817 | u8 n_channels) | ||
| 16818 | { | ||
| 16819 | if (WARN_ON(nla_len(slots_attr) != CFG80211_NAN_SCHED_NUM_TIME_SLOTS)) | ||
| 16820 | return -EINVAL; | ||
| 16821 | |||
| 16822 | memcpy(schedule, nla_data(slots_attr), nla_len(slots_attr)); | ||
| 16823 | |||
| 16824 | for (int slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; slot++) { | ||
| 16825 | if (schedule[slot] != NL80211_NAN_SCHED_NOT_AVAIL_SLOT && | ||
| 16826 | schedule[slot] >= n_channels) { | ||
| 16827 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 16828 | "Invalid time slot: slot %d refers to channel index %d, n_channels=%d", | ||
| 16829 | slot, schedule[slot], n_channels); | ||
| 16830 | return -EINVAL; | ||
| 16831 | } | ||
| 16832 | } | ||
| 16833 | |||
| 16834 | return 0; | ||
| 16835 | } | ||
| 16836 | |||
| 16837 | static int | ||
| 16838 | nl80211_parse_nan_peer_map(struct genl_info *info, struct nlattr *map_attr, | ||
| 16839 | struct cfg80211_nan_peer_map *map, u8 n_channels) | ||
| 16840 | { | ||
| 16841 | struct nlattr *tb[NL80211_NAN_PEER_MAP_ATTR_MAX + 1]; | ||
| 16842 | int ret; | ||
| 16843 | |||
| 16844 | ret = nla_parse_nested(tb, NL80211_NAN_PEER_MAP_ATTR_MAX, map_attr, | ||
| 16845 | nl80211_nan_peer_map_policy, info->extack); | ||
| 16846 | if (ret) | ||
| 16847 | return ret; | ||
| 16848 | |||
| 16849 | if (!tb[NL80211_NAN_PEER_MAP_ATTR_MAP_ID] || | ||
| 16850 | !tb[NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS]) { | ||
| 16851 | NL_SET_ERR_MSG(info->extack, | ||
| 16852 | "Missing required peer map attributes"); | ||
| 16853 | return -EINVAL; | ||
| 16854 | } | ||
| 16855 | |||
| 16856 | map->map_id = nla_get_u8(tb[NL80211_NAN_PEER_MAP_ATTR_MAP_ID]); | ||
| 16857 | |||
| 16858 | /* Parse schedule */ | ||
| 16859 | return nl80211_parse_nan_schedule(info, | ||
| 16860 | tb[NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS], | ||
| 16861 | map->schedule, n_channels); | ||
| 16862 | } | ||
| 16863 | |||
| 16864 | static int nl80211_nan_validate_map_pair(struct wiphy *wiphy, | ||
| 16865 | struct genl_info *info, | ||
| 16866 | const struct cfg80211_nan_peer_map *map1, | ||
| 16867 | const struct cfg80211_nan_peer_map *map2, | ||
| 16868 | struct cfg80211_nan_channel *nan_channels) | ||
| 16869 | { | ||
| 16870 | /* Check for duplicate map_id */ | ||
| 16871 | if (map1->map_id == map2->map_id) { | ||
| 16872 | NL_SET_ERR_MSG_FMT(info->extack, "Duplicate map_id %u", | ||
| 16873 | map1->map_id); | ||
| 16874 | return -EINVAL; | ||
| 16875 | } | ||
| 16876 | |||
| 16877 | /* Check for compatible channels between maps */ | ||
| 16878 | for (int i = 0; i < ARRAY_SIZE(map1->schedule); i++) { | ||
| 16879 | if (map1->schedule[i] == NL80211_NAN_SCHED_NOT_AVAIL_SLOT) | ||
| 16880 | continue; | ||
| 16881 | |||
| 16882 | for (int j = 0; j < ARRAY_SIZE(map2->schedule); j++) { | ||
| 16883 | u8 ch1 = map1->schedule[i]; | ||
| 16884 | u8 ch2 = map2->schedule[j]; | ||
| 16885 | |||
| 16886 | if (ch2 == NL80211_NAN_SCHED_NOT_AVAIL_SLOT) | ||
| 16887 | continue; | ||
| 16888 | |||
| 16889 | if (cfg80211_chandef_compatible(&nan_channels[ch1].chandef, | ||
| 16890 | &nan_channels[ch2].chandef)) { | ||
| 16891 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 16892 | "Maps %u and %u have compatible channels %d and %d", | ||
| 16893 | map1->map_id, map2->map_id, | ||
| 16894 | ch1, ch2); | ||
| 16895 | return -EINVAL; | ||
| 16896 | } | ||
| 16897 | } | ||
| 16898 | } | ||
| 16899 | |||
| 16900 | /* | ||
| 16901 | * Check for conflicting time slots between maps. | ||
| 16902 | * Only check for single-radio devices (n_radio <= 1) which cannot | ||
| 16903 | * operate on multiple channels simultaneously. | ||
| 16904 | */ | ||
| 16905 | if (wiphy->n_radio > 1) | ||
| 16906 | return 0; | ||
| 16907 | |||
| 16908 | for (int i = 0; i < ARRAY_SIZE(map1->schedule); i++) { | ||
| 16909 | if (map1->schedule[i] != NL80211_NAN_SCHED_NOT_AVAIL_SLOT && | ||
| 16910 | map2->schedule[i] != NL80211_NAN_SCHED_NOT_AVAIL_SLOT) { | ||
| 16911 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 16912 | "Maps %u and %u both schedule slot %d", | ||
| 16913 | map1->map_id, map2->map_id, i); | ||
| 16914 | return -EINVAL; | ||
| 16915 | } | ||
| 16916 | } | ||
| 16917 | |||
| 16918 | return 0; | ||
| 16919 | } | ||
| 16920 | |||
| 16921 | static int nl80211_nan_set_peer_sched(struct sk_buff *skb, | ||
| 16922 | struct genl_info *info) | ||
| 16923 | { | ||
| 16924 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 16925 | struct cfg80211_nan_channel *nan_channels __free(kfree) = NULL; | ||
| 16926 | struct cfg80211_nan_peer_sched sched = {}; | ||
| 16927 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
| 16928 | struct nlattr *map_attr, *channel; | ||
| 16929 | int ret, n_maps = 0, n_channels = 0, i = 0, rem; | ||
| 16930 | |||
| 16931 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
| 16932 | return -EOPNOTSUPP; | ||
| 16933 | |||
| 16934 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
| 16935 | !info->attrs[NL80211_ATTR_NAN_COMMITTED_DW]) { | ||
| 16936 | NL_SET_ERR_MSG(info->extack, | ||
| 16937 | "Required NAN peer schedule attributes are missing"); | ||
| 16938 | return -EINVAL; | ||
| 16939 | } | ||
| 16940 | |||
| 16941 | /* First count how many channel attributes we got */ | ||
| 16942 | nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL, | ||
| 16943 | info->nlhdr, GENL_HDRLEN, rem) | ||
| 16944 | n_channels++; | ||
| 16945 | |||
| 16946 | if (!((info->attrs[NL80211_ATTR_NAN_SEQ_ID] && | ||
| 16947 | info->attrs[NL80211_ATTR_NAN_PEER_MAPS] && n_channels) || | ||
| 16948 | ((!info->attrs[NL80211_ATTR_NAN_SEQ_ID] && | ||
| 16949 | !info->attrs[NL80211_ATTR_NAN_PEER_MAPS] && !n_channels)))) { | ||
| 16950 | NL_SET_ERR_MSG(info->extack, | ||
| 16951 | "Either provide all of: seq id, channels and maps, or none"); | ||
| 16952 | return -EINVAL; | ||
| 16953 | } | ||
| 16954 | |||
| 16955 | /* | ||
| 16956 | * Limit the number of peer channels to: | ||
| 16957 | * local_channels * 4 (possible BWs) * 2 (possible NSS values) | ||
| 16958 | */ | ||
| 16959 | if (n_channels && n_channels > wdev->u.nan.n_channels * 4 * 2) { | ||
| 16960 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 16961 | "Too many peer channels: %d (max %d)", | ||
| 16962 | n_channels, | ||
| 16963 | wdev->u.nan.n_channels * 4 * 2); | ||
| 16964 | return -EINVAL; | ||
| 16965 | } | ||
| 16966 | |||
| 16967 | if (n_channels) { | ||
| 16968 | nan_channels = kcalloc(n_channels, sizeof(*nan_channels), | ||
| 16969 | GFP_KERNEL); | ||
| 16970 | if (!nan_channels) | ||
| 16971 | return -ENOMEM; | ||
| 16972 | } | ||
| 16973 | |||
| 16974 | /* Parse peer channels */ | ||
| 16975 | nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL, | ||
| 16976 | info->nlhdr, GENL_HDRLEN, rem) { | ||
| 16977 | bool compatible = false; | ||
| 16978 | |||
| 16979 | ret = nl80211_parse_nan_channel(rdev, channel, info, | ||
| 16980 | nan_channels, i, false); | ||
| 16981 | if (ret) | ||
| 16982 | return ret; | ||
| 16983 | |||
| 16984 | /* Verify channel is compatible with at least one local channel */ | ||
| 16985 | for (int j = 0; j < wdev->u.nan.n_channels; j++) { | ||
| 16986 | if (cfg80211_chandef_compatible(&nan_channels[i].chandef, | ||
| 16987 | &wdev->u.nan.chandefs[j])) { | ||
| 16988 | compatible = true; | ||
| 16989 | break; | ||
| 16990 | } | ||
| 16991 | } | ||
| 16992 | if (!compatible) { | ||
| 16993 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 16994 | "Channel %d not compatible with any local channel", | ||
| 16995 | i); | ||
| 16996 | return -EINVAL; | ||
| 16997 | } | ||
| 16998 | i++; | ||
| 16999 | } | ||
| 17000 | |||
| 17001 | sched.n_channels = n_channels; | ||
| 17002 | sched.nan_channels = nan_channels; | ||
| 17003 | sched.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
| 17004 | sched.seq_id = nla_get_u8_default(info->attrs[NL80211_ATTR_NAN_SEQ_ID], 0); | ||
| 17005 | sched.committed_dw = nla_get_u16(info->attrs[NL80211_ATTR_NAN_COMMITTED_DW]); | ||
| 17006 | sched.max_chan_switch = | ||
| 17007 | nla_get_u16_default(info->attrs[NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME], 0); | ||
| 17008 | |||
| 17009 | if (info->attrs[NL80211_ATTR_NAN_ULW]) { | ||
| 17010 | sched.ulw_size = nla_len(info->attrs[NL80211_ATTR_NAN_ULW]); | ||
| 17011 | sched.init_ulw = nla_data(info->attrs[NL80211_ATTR_NAN_ULW]); | ||
| 17012 | } | ||
| 17013 | |||
| 17014 | /* Initialize all maps as invalid */ | ||
| 17015 | for (int j = 0; j < ARRAY_SIZE(sched.maps); j++) | ||
| 17016 | sched.maps[j].map_id = CFG80211_NAN_INVALID_MAP_ID; | ||
| 17017 | |||
| 17018 | if (info->attrs[NL80211_ATTR_NAN_PEER_MAPS]) { | ||
| 17019 | /* Parse each map */ | ||
| 17020 | nla_for_each_nested(map_attr, info->attrs[NL80211_ATTR_NAN_PEER_MAPS], | ||
| 17021 | rem) { | ||
| 17022 | if (n_maps >= ARRAY_SIZE(sched.maps)) { | ||
| 17023 | NL_SET_ERR_MSG(info->extack, "Too many peer maps"); | ||
| 17024 | return -EINVAL; | ||
| 17025 | } | ||
| 17026 | |||
| 17027 | ret = nl80211_parse_nan_peer_map(info, map_attr, | ||
| 17028 | &sched.maps[n_maps], | ||
| 17029 | n_channels); | ||
| 17030 | if (ret) | ||
| 17031 | return ret; | ||
| 17032 | |||
| 17033 | /* Validate against previous maps */ | ||
| 17034 | for (int j = 0; j < n_maps; j++) { | ||
| 17035 | ret = nl80211_nan_validate_map_pair(&rdev->wiphy, info, | ||
| 17036 | &sched.maps[j], | ||
| 17037 | &sched.maps[n_maps], | ||
| 17038 | nan_channels); | ||
| 17039 | if (ret) | ||
| 17040 | return ret; | ||
| 17041 | } | ||
| 17042 | |||
| 17043 | n_maps++; | ||
| 17044 | } | ||
| 17045 | } | ||
| 17046 | |||
| 17047 | /* Verify each channel is scheduled at least once */ | ||
| 17048 | for (int ch = 0; ch < n_channels; ch++) { | ||
| 17049 | bool scheduled = false; | ||
| 17050 | |||
| 17051 | for (int m = 0; m < n_maps && !scheduled; m++) { | ||
| 17052 | for (int s = 0; s < ARRAY_SIZE(sched.maps[m].schedule); s++) { | ||
| 17053 | if (sched.maps[m].schedule[s] == ch) { | ||
| 17054 | scheduled = true; | ||
| 17055 | break; | ||
| 17056 | } | ||
| 17057 | } | ||
| 17058 | } | ||
| 17059 | if (!scheduled) { | ||
| 17060 | NL_SET_ERR_MSG_FMT(info->extack, | ||
| 17061 | "Channel %d is not scheduled in any map", | ||
| 17062 | ch); | ||
| 17063 | return -EINVAL; | ||
| 17064 | } | ||
| 17065 | } | ||
| 17066 | |||
| 17067 | return rdev_nan_set_peer_sched(rdev, wdev, &sched); | ||
| 17068 | } | ||
| 17069 | |||
| 17070 | static bool nl80211_nan_is_sched_empty(struct cfg80211_nan_local_sched *sched) | ||
| 17071 | { | ||
| 17072 | if (!sched->n_channels) | ||
| 17073 | return true; | ||
| 17074 | |||
| 17075 | for (int i = 0; i < ARRAY_SIZE(sched->schedule); i++) { | ||
| 17076 | if (sched->schedule[i] != NL80211_NAN_SCHED_NOT_AVAIL_SLOT) | ||
| 17077 | return false; | ||
| 17078 | } | ||
| 17079 | |||
| 17080 | return true; | ||
| 17081 | } | ||
| 17082 | |||
| 17083 | static int nl80211_nan_set_local_sched(struct sk_buff *skb, | ||
| 17084 | struct genl_info *info) | ||
| 17085 | { | ||
| 17086 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
| 17087 | struct cfg80211_nan_local_sched *sched __free(kfree) = NULL; | ||
| 17088 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
| 17089 | int rem, i = 0, n_channels = 0, ret; | ||
| 17090 | struct nlattr *channel; | ||
| 17091 | bool sched_empty; | ||
| 17092 | |||
| 17093 | if (wdev->iftype != NL80211_IFTYPE_NAN) | ||
| 17094 | return -EOPNOTSUPP; | ||
| 17095 | |||
| 17096 | if (!wdev_running(wdev)) | ||
| 17097 | return -ENOTCONN; | ||
| 17098 | |||
| 17099 | if (!info->attrs[NL80211_ATTR_NAN_TIME_SLOTS]) | ||
| 17100 | return -EINVAL; | ||
| 17101 | |||
| 17102 | /* First count how many channel attributes we got */ | ||
| 17103 | nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL, | ||
| 17104 | info->nlhdr, GENL_HDRLEN, rem) | ||
| 17105 | n_channels++; | ||
| 17106 | |||
| 17107 | sched = kzalloc(struct_size(sched, nan_channels, n_channels), | ||
| 17108 | GFP_KERNEL); | ||
| 17109 | if (!sched) | ||
| 17110 | return -ENOMEM; | ||
| 17111 | |||
| 17112 | sched->n_channels = n_channels; | ||
| 17113 | |||
| 17114 | nlmsg_for_each_attr_type(channel, NL80211_ATTR_NAN_CHANNEL, | ||
| 17115 | info->nlhdr, GENL_HDRLEN, rem) { | ||
| 17116 | ret = nl80211_parse_nan_channel(rdev, channel, info, | ||
| 17117 | sched->nan_channels, i, true); | ||
| 17118 | |||
| 17119 | if (ret) | ||
| 17120 | return ret; | ||
| 17121 | i++; | ||
| 17122 | } | ||
| 17123 | |||
| 17124 | /* Parse and validate schedule */ | ||
| 17125 | ret = nl80211_parse_nan_schedule(info, | ||
| 17126 | info->attrs[NL80211_ATTR_NAN_TIME_SLOTS], | ||
| 17127 | sched->schedule, sched->n_channels); | ||
| 17128 | if (ret) | ||
| 17129 | return ret; | ||
| 17130 | |||
| 17131 | sched_empty = nl80211_nan_is_sched_empty(sched); | ||
| 17132 | |||
| 17133 | sched->deferred = | ||
| 17134 | nla_get_flag(info->attrs[NL80211_ATTR_NAN_SCHED_DEFERRED]); | ||
| 17135 | |||
| 17136 | if (sched_empty) { | ||
| 17137 | if (sched->deferred) { | ||
| 17138 | NL_SET_ERR_MSG(info->extack, | ||
| 17139 | "Schedule cannot be deferred if all time slots are unavailable"); | ||
| 17140 | return -EINVAL; | ||
| 17141 | } | ||
| 17142 | |||
| 17143 | if (info->attrs[NL80211_ATTR_NAN_AVAIL_BLOB]) { | ||
| 17144 | NL_SET_ERR_MSG(info->extack, | ||
| 17145 | "NAN Availability blob must be empty if all time slots are unavailable"); | ||
| 17146 | return -EINVAL; | ||
| 17147 | } | ||
| 17148 | } else { | ||
| 17149 | if (!info->attrs[NL80211_ATTR_NAN_AVAIL_BLOB]) { | ||
| 17150 | NL_SET_ERR_MSG(info->extack, | ||
| 17151 | "NAN Availability blob attribute is required"); | ||
| 17152 | return -EINVAL; | ||
| 17153 | } | ||
| 17154 | |||
| 17155 | sched->nan_avail_blob = | ||
| 17156 | nla_data(info->attrs[NL80211_ATTR_NAN_AVAIL_BLOB]); | ||
| 17157 | sched->nan_avail_blob_len = | ||
| 17158 | nla_len(info->attrs[NL80211_ATTR_NAN_AVAIL_BLOB]); | ||
| 17159 | } | ||
| 17160 | |||
| 17161 | return cfg80211_nan_set_local_schedule(rdev, wdev, sched); | ||
| 17162 | } | ||
| 17163 | |||
| 16424 | static int nl80211_get_protocol_features(struct sk_buff *skb, | 17164 | static int nl80211_get_protocol_features(struct sk_buff *skb, |
| 16425 | struct genl_info *info) | 17165 | struct genl_info *info) |
| 16426 | { | 17166 | { |
| @@ -18096,7 +18836,11 @@ nl80211_epcs_cfg(struct sk_buff *skb, struct genl_info *info) · 1669 unmodified lines | |||
| 18096 | NL80211_FLAG_NEED_RTNL) \ | 18836 | NL80211_FLAG_NEED_RTNL) \ |
| 18097 | SELECTOR(__sel, WIPHY_CLEAR, \ | 18837 | SELECTOR(__sel, WIPHY_CLEAR, \ |
| 18098 | NL80211_FLAG_NEED_WIPHY | \ | 18838 | NL80211_FLAG_NEED_WIPHY | \ |
| 18099 | NL80211_FLAG_CLEAR_SKB) | 18839 | NL80211_FLAG_CLEAR_SKB) \ |
| 18840 | SELECTOR(__sel, WDEV_UP_RTNL_NOMTX, \ | ||
| 18841 | NL80211_FLAG_NEED_WDEV_UP | \ | ||
| 18842 | NL80211_FLAG_NO_WIPHY_MTX | \ | ||
| 18843 | NL80211_FLAG_NEED_RTNL) | ||
| 18100 | 18844 | ||
| 18101 | enum nl80211_internal_flags_selector { | 18845 | enum nl80211_internal_flags_selector { |
| 18102 | #define SELECTOR(_, name, value) NL80211_IFL_SEL_##name, | 18846 | #define SELECTOR(_, name, value) NL80211_IFL_SEL_##name, |
| @@ -18933,6 +19677,7 @@ static const struct genl_small_ops nl80211_small_ops[] = { · 830 unmodified lines | |||
| 18933 | .doit = nl80211_stop_nan, | 19677 | .doit = nl80211_stop_nan, |
| 18934 | .flags = GENL_ADMIN_PERM, | 19678 | .flags = GENL_ADMIN_PERM, |
| 18935 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | | 19679 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | |
| 19680 | NL80211_FLAG_NO_WIPHY_MTX | | ||
| 18936 | NL80211_FLAG_NEED_RTNL), | 19681 | NL80211_FLAG_NEED_RTNL), |
| 18937 | }, | 19682 | }, |
| 18938 | { | 19683 | { |
| @@ -19227,6 +19972,18 @@ static const struct genl_small_ops nl80211_small_ops[] = { · 288 unmodified lines | |||
| 19227 | .flags = GENL_UNS_ADMIN_PERM, | 19972 | .flags = GENL_UNS_ADMIN_PERM, |
| 19228 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), | 19973 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), |
| 19229 | }, | 19974 | }, |
| 19975 | { | ||
| 19976 | .cmd = NL80211_CMD_NAN_SET_LOCAL_SCHED, | ||
| 19977 | .doit = nl80211_nan_set_local_sched, | ||
| 19978 | .flags = GENL_ADMIN_PERM, | ||
| 19979 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP), | ||
| 19980 | }, | ||
| 19981 | { | ||
| 19982 | .cmd = NL80211_CMD_NAN_SET_PEER_SCHED, | ||
| 19983 | .doit = nl80211_nan_set_peer_sched, | ||
| 19984 | .flags = GENL_ADMIN_PERM, | ||
| 19985 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP), | ||
| 19986 | }, | ||
| 19230 | }; | 19987 | }; |
| 19231 | 19988 | ||
| 19232 | static struct genl_family nl80211_fam __ro_after_init = { | 19989 | static struct genl_family nl80211_fam __ro_after_init = { |
| @@ -20527,7 +21284,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd, · 1294 unmodified lines | |||
| 20527 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | 21284 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
| 20528 | struct sk_buff *msg; | 21285 | struct sk_buff *msg; |
| 20529 | void *hdr; | 21286 | void *hdr; |
| 20530 | u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid); | 21287 | u32 nlportid = READ_ONCE(wdev->unexpected_nlportid); |
| 20531 | 21288 | ||
| 20532 | if (!nlportid) | 21289 | if (!nlportid) |
| 20533 | return false; | 21290 | return false; |
| @@ -20567,7 +21324,8 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, · 33 unmodified lines | |||
| 20567 | trace_cfg80211_rx_spurious_frame(dev, addr, link_id); | 21324 | trace_cfg80211_rx_spurious_frame(dev, addr, link_id); |
| 20568 | 21325 | ||
| 20569 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && | 21326 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && |
| 20570 | wdev->iftype != NL80211_IFTYPE_P2P_GO)) { | 21327 | wdev->iftype != NL80211_IFTYPE_P2P_GO && |
| 21328 | wdev->iftype != NL80211_IFTYPE_NAN_DATA)) { | ||
| 20571 | trace_cfg80211_return_bool(false); | 21329 | trace_cfg80211_return_bool(false); |
| 20572 | return false; | 21330 | return false; |
| 20573 | } | 21331 | } |
| @@ -22137,6 +22895,97 @@ void cfg80211_nan_cluster_joined(struct wireless_dev *wdev, · 1563 unmodified lines | |||
| 22137 | } | 22895 | } |
| 22138 | EXPORT_SYMBOL(cfg80211_nan_cluster_joined); | 22896 | EXPORT_SYMBOL(cfg80211_nan_cluster_joined); |
| 22139 | 22897 | ||
| 22898 | void cfg80211_nan_ulw_update(struct wireless_dev *wdev, | ||
| 22899 | const u8 *ulw, size_t ulw_len, gfp_t gfp) | ||
| 22900 | { | ||
| 22901 | struct wiphy *wiphy = wdev->wiphy; | ||
| 22902 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
| 22903 | struct sk_buff *msg; | ||
| 22904 | void *hdr; | ||
| 22905 | |||
| 22906 | trace_cfg80211_nan_ulw_update(wiphy, wdev, ulw, ulw_len); | ||
| 22907 | |||
| 22908 | if (!wdev->owner_nlportid) | ||
| 22909 | return; | ||
| 22910 | |||
| 22911 | /* 32 for the wiphy idx, 64 for the wdev id, 100 for padding */ | ||
| 22912 | msg = nlmsg_new(nla_total_size(sizeof(u32)) + | ||
| 22913 | nla_total_size(ulw_len) + | ||
| 22914 | nla_total_size(sizeof(u64)) + 100, | ||
| 22915 | gfp); | ||
| 22916 | if (!msg) | ||
| 22917 | return; | ||
| 22918 | |||
| 22919 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_ULW_UPDATE); | ||
| 22920 | if (!hdr) | ||
| 22921 | goto nla_put_failure; | ||
| 22922 | |||
| 22923 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
| 22924 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
| 22925 | NL80211_ATTR_PAD) || | ||
| 22926 | (ulw && ulw_len && | ||
| 22927 | nla_put(msg, NL80211_ATTR_NAN_ULW, ulw_len, ulw))) | ||
| 22928 | goto nla_put_failure; | ||
| 22929 | |||
| 22930 | genlmsg_end(msg, hdr); | ||
| 22931 | |||
| 22932 | genlmsg_unicast(wiphy_net(wiphy), msg, wdev->owner_nlportid); | ||
| 22933 | |||
| 22934 | return; | ||
| 22935 | |||
| 22936 | nla_put_failure: | ||
| 22937 | nlmsg_free(msg); | ||
| 22938 | } | ||
| 22939 | EXPORT_SYMBOL(cfg80211_nan_ulw_update); | ||
| 22940 | |||
| 22941 | void cfg80211_nan_channel_evac(struct wireless_dev *wdev, | ||
| 22942 | const struct cfg80211_chan_def *chandef, | ||
| 22943 | gfp_t gfp) | ||
| 22944 | { | ||
| 22945 | struct wiphy *wiphy = wdev->wiphy; | ||
| 22946 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
| 22947 | struct sk_buff *msg; | ||
| 22948 | struct nlattr *chan_attr; | ||
| 22949 | void *hdr; | ||
| 22950 | |||
| 22951 | trace_cfg80211_nan_channel_evac(wiphy, wdev, chandef); | ||
| 22952 | |||
| 22953 | if (!wdev->owner_nlportid) | ||
| 22954 | return; | ||
| 22955 | |||
| 22956 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
| 22957 | if (!msg) | ||
| 22958 | return; | ||
| 22959 | |||
| 22960 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_CHANNEL_EVAC); | ||
| 22961 | if (!hdr) | ||
| 22962 | goto nla_put_failure; | ||
| 22963 | |||
| 22964 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
| 22965 | nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), | ||
| 22966 | NL80211_ATTR_PAD)) | ||
| 22967 | goto nla_put_failure; | ||
| 22968 | |||
| 22969 | chan_attr = nla_nest_start(msg, NL80211_ATTR_NAN_CHANNEL); | ||
| 22970 | if (!chan_attr) | ||
| 22971 | goto nla_put_failure; | ||
| 22972 | |||
| 22973 | if (nl80211_send_chandef(msg, chandef)) | ||
| 22974 | goto nla_put_failure; | ||
| 22975 | |||
| 22976 | nla_nest_end(msg, chan_attr); | ||
| 22977 | |||
| 22978 | genlmsg_end(msg, hdr); | ||
| 22979 | |||
| 22980 | genlmsg_unicast(wiphy_net(wiphy), msg, wdev->owner_nlportid); | ||
| 22981 | |||
| 22982 | return; | ||
| 22983 | |||
| 22984 | nla_put_failure: | ||
| 22985 | nlmsg_free(msg); | ||
| 22986 | } | ||
| 22987 | EXPORT_SYMBOL(cfg80211_nan_channel_evac); | ||
| 22988 | |||
| 22140 | /* initialisation/exit functions */ | 22989 | /* initialisation/exit functions */ |
| 22141 | 22990 | ||
| 22142 | int __init nl80211_init(void) | 22991 | int __init nl80211_init(void) |
| @@ -1060,6 +1060,38 @@ rdev_nan_change_conf(struct cfg80211_registered_device *rdev, · 1059 unmodified lines | |||
| 1060 | return ret; | 1060 | return ret; |
| 1061 | } | 1061 | } |
| 1062 | 1062 | ||
| 1063 | static inline int | ||
| 1064 | rdev_nan_set_local_sched(struct cfg80211_registered_device *rdev, | ||
| 1065 | struct wireless_dev *wdev, | ||
| 1066 | struct cfg80211_nan_local_sched *sched) | ||
| 1067 | { | ||
| 1068 | int ret; | ||
| 1069 | |||
| 1070 | trace_rdev_nan_set_local_sched(&rdev->wiphy, wdev, sched); | ||
| 1071 | if (rdev->ops->nan_set_local_sched) | ||
| 1072 | ret = rdev->ops->nan_set_local_sched(&rdev->wiphy, wdev, sched); | ||
| 1073 | else | ||
| 1074 | ret = -EOPNOTSUPP; | ||
| 1075 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 1076 | return ret; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static inline int | ||
| 1080 | rdev_nan_set_peer_sched(struct cfg80211_registered_device *rdev, | ||
| 1081 | struct wireless_dev *wdev, | ||
| 1082 | struct cfg80211_nan_peer_sched *sched) | ||
| 1083 | { | ||
| 1084 | int ret; | ||
| 1085 | |||
| 1086 | trace_rdev_nan_set_peer_sched(&rdev->wiphy, wdev, sched); | ||
| 1087 | if (rdev->ops->nan_set_peer_sched) | ||
| 1088 | ret = rdev->ops->nan_set_peer_sched(&rdev->wiphy, wdev, sched); | ||
| 1089 | else | ||
| 1090 | ret = -EOPNOTSUPP; | ||
| 1091 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
| 1092 | return ret; | ||
| 1093 | } | ||
| 1094 | |||
| 1063 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, | 1095 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
| 1064 | struct net_device *dev, | 1096 | struct net_device *dev, |
| 1065 | struct cfg80211_acl_data *params) | 1097 | struct cfg80211_acl_data *params) |
| @@ -2348,6 +2348,18 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) · 2347 unmodified lines | |||
| 2348 | if (!wdev->netdev || !netif_running(wdev->netdev)) | 2348 | if (!wdev->netdev || !netif_running(wdev->netdev)) |
| 2349 | return true; | 2349 | return true; |
| 2350 | 2350 | ||
| 2351 | /* NAN doesn't have links, handle it separately */ | ||
| 2352 | if (iftype == NL80211_IFTYPE_NAN) { | ||
| 2353 | for (int i = 0; i < wdev->u.nan.n_channels; i++) { | ||
| 2354 | ret = cfg80211_reg_can_beacon(wiphy, | ||
| 2355 | &wdev->u.nan.chandefs[i], | ||
| 2356 | NL80211_IFTYPE_NAN); | ||
| 2357 | if (!ret) | ||
| 2358 | return false; | ||
| 2359 | } | ||
| 2360 | return true; | ||
| 2361 | } | ||
| 2362 | |||
| 2351 | for (link = 0; link < ARRAY_SIZE(wdev->links); link++) { | 2363 | for (link = 0; link < ARRAY_SIZE(wdev->links); link++) { |
| 2352 | struct ieee80211_channel *chan; | 2364 | struct ieee80211_channel *chan; |
| 2353 | 2365 | ||
| @@ -2397,9 +2409,9 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) · 43 unmodified lines | |||
| 2397 | continue; | 2409 | continue; |
| 2398 | chandef = wdev->u.ocb.chandef; | 2410 | chandef = wdev->u.ocb.chandef; |
| 2399 | break; | 2411 | break; |
| 2400 | case NL80211_IFTYPE_NAN: | 2412 | case NL80211_IFTYPE_NAN_DATA: |
| 2401 | /* we have no info, but NAN is also pretty universal */ | 2413 | /* NAN channels are checked in NL80211_IFTYPE_NAN interface */ |
| 2402 | continue; | 2414 | break; |
| 2403 | default: | 2415 | default: |
| 2404 | /* others not implemented for now */ | 2416 | /* others not implemented for now */ |
| 2405 | WARN_ON_ONCE(1); | 2417 | WARN_ON_ONCE(1); |
| @@ -2436,11 +2448,14 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy) · 30 unmodified lines | |||
| 2436 | struct wireless_dev *wdev; | 2448 | struct wireless_dev *wdev; |
| 2437 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | 2449 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 2438 | 2450 | ||
| 2439 | guard(wiphy)(wiphy); | 2451 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
| 2452 | bool valid; | ||
| 2440 | 2453 | ||
| 2441 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) | 2454 | scoped_guard(wiphy, wiphy) |
| 2442 | if (!reg_wdev_chan_valid(wiphy, wdev)) | 2455 | valid = reg_wdev_chan_valid(wiphy, wdev); |
| 2456 | if (!valid) | ||
| 2443 | cfg80211_leave(rdev, wdev, -1); | 2457 | cfg80211_leave(rdev, wdev, -1); |
| 2458 | } | ||
| 2444 | } | 2459 | } |
| 2445 | 2460 | ||
| 2446 | static void reg_check_chans_work(struct work_struct *work) | 2461 | static void reg_check_chans_work(struct work_struct *work) |
| @@ -102,25 +102,26 @@ static int wiphy_suspend(struct device *dev) · 101 unmodified lines | |||
| 102 | if (!rdev->wiphy.registered) | 102 | if (!rdev->wiphy.registered) |
| 103 | goto out_unlock_rtnl; | 103 | goto out_unlock_rtnl; |
| 104 | 104 | ||
| 105 | wiphy_lock(&rdev->wiphy); | ||
| 106 | if (rdev->wiphy.wowlan_config) { | 105 | if (rdev->wiphy.wowlan_config) { |
| 107 | cfg80211_process_wiphy_works(rdev, NULL); | 106 | scoped_guard(wiphy, &rdev->wiphy) { |
| 108 | if (rdev->ops->suspend) | 107 | cfg80211_process_wiphy_works(rdev, NULL); |
| 109 | ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); | 108 | if (rdev->ops->suspend) |
| 110 | if (ret <= 0) | 109 | ret = rdev_suspend(rdev, |
| 111 | goto out_unlock_wiphy; | 110 | rdev->wiphy.wowlan_config); |
| 111 | if (ret <= 0) | ||
| 112 | goto out_unlock_rtnl; | ||
| 113 | } | ||
| 112 | } | 114 | } |
| 113 | 115 | ||
| 114 | /* Driver refused to configure wowlan (ret = 1) or no wowlan */ | 116 | /* Driver refused to configure wowlan (ret = 1) or no wowlan */ |
| 115 | 117 | ||
| 116 | cfg80211_leave_all(rdev); | 118 | cfg80211_leave_all(rdev); |
| 117 | cfg80211_process_rdev_events(rdev); | 119 | scoped_guard(wiphy, &rdev->wiphy) { |
| 118 | cfg80211_process_wiphy_works(rdev, NULL); | 120 | cfg80211_process_rdev_events(rdev); |
| 119 | if (rdev->ops->suspend) | 121 | cfg80211_process_wiphy_works(rdev, NULL); |
| 120 | ret = rdev_suspend(rdev, NULL); | 122 | if (rdev->ops->suspend) |
| 121 | 123 | ret = rdev_suspend(rdev, NULL); | |
| 122 | out_unlock_wiphy: | 124 | } |
| 123 | wiphy_unlock(&rdev->wiphy); | ||
| 124 | out_unlock_rtnl: | 125 | out_unlock_rtnl: |
| 125 | if (ret == 0) | 126 | if (ret == 0) |
| 126 | rdev->suspended = true; | 127 | rdev->suspended = true; |
| @@ -2410,6 +2410,55 @@ TRACE_EVENT(rdev_del_nan_func, · 2409 unmodified lines | |||
| 2410 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) | 2410 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie) |
| 2411 | ); | 2411 | ); |
| 2412 | 2412 | ||
| 2413 | TRACE_EVENT(rdev_nan_set_local_sched, | ||
| 2414 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 2415 | struct cfg80211_nan_local_sched *sched), | ||
| 2416 | TP_ARGS(wiphy, wdev, sched), | ||
| 2417 | TP_STRUCT__entry( | ||
| 2418 | WIPHY_ENTRY | ||
| 2419 | WDEV_ENTRY | ||
| 2420 | __array(u8, schedule, CFG80211_NAN_SCHED_NUM_TIME_SLOTS) | ||
| 2421 | ), | ||
| 2422 | TP_fast_assign( | ||
| 2423 | WIPHY_ASSIGN; | ||
| 2424 | WDEV_ASSIGN; | ||
| 2425 | memcpy(__entry->schedule, sched->schedule, | ||
| 2426 | CFG80211_NAN_SCHED_NUM_TIME_SLOTS); | ||
| 2427 | ), | ||
| 2428 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", schedule: %s", | ||
| 2429 | WIPHY_PR_ARG, WDEV_PR_ARG, | ||
| 2430 | __print_array(__entry->schedule, | ||
| 2431 | CFG80211_NAN_SCHED_NUM_TIME_SLOTS, 1)) | ||
| 2432 | ); | ||
| 2433 | |||
| 2434 | TRACE_EVENT(rdev_nan_set_peer_sched, | ||
| 2435 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 2436 | struct cfg80211_nan_peer_sched *sched), | ||
| 2437 | TP_ARGS(wiphy, wdev, sched), | ||
| 2438 | TP_STRUCT__entry( | ||
| 2439 | WIPHY_ENTRY | ||
| 2440 | WDEV_ENTRY | ||
| 2441 | __array(u8, peer_addr, ETH_ALEN) | ||
| 2442 | __field(u8, seq_id) | ||
| 2443 | __field(u16, committed_dw) | ||
| 2444 | __field(u16, max_chan_switch) | ||
| 2445 | ), | ||
| 2446 | TP_fast_assign( | ||
| 2447 | WIPHY_ASSIGN; | ||
| 2448 | WDEV_ASSIGN; | ||
| 2449 | memcpy(__entry->peer_addr, sched->peer_addr, ETH_ALEN); | ||
| 2450 | __entry->seq_id = sched->seq_id; | ||
| 2451 | __entry->committed_dw = sched->committed_dw; | ||
| 2452 | __entry->max_chan_switch = sched->max_chan_switch; | ||
| 2453 | ), | ||
| 2454 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT | ||
| 2455 | ", peer: %pM, seq_id: %u, committed_dw: 0x%x, max_chan_switch: %u", | ||
| 2456 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->peer_addr, | ||
| 2457 | __entry->seq_id, __entry->committed_dw, | ||
| 2458 | __entry->max_chan_switch | ||
| 2459 | ) | ||
| 2460 | ); | ||
| 2461 | |||
| 2413 | TRACE_EVENT(rdev_set_mac_acl, | 2462 | TRACE_EVENT(rdev_set_mac_acl, |
| 2414 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | 2463 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
| 2415 | struct cfg80211_acl_data *params), | 2464 | struct cfg80211_acl_data *params), |
| @@ -4276,6 +4325,62 @@ TRACE_EVENT(cfg80211_incumbent_signal_notify, · 1860 unmodified lines | |||
| 4276 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", signal_interference_bitmap=0x%x", | 4325 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", signal_interference_bitmap=0x%x", |
| 4277 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->signal_interference_bitmap) | 4326 | WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->signal_interference_bitmap) |
| 4278 | ); | 4327 | ); |
| 4328 | |||
| 4329 | TRACE_EVENT(cfg80211_nan_sched_update_done, | ||
| 4330 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, bool success), | ||
| 4331 | TP_ARGS(wiphy, wdev, success), | ||
| 4332 | TP_STRUCT__entry( | ||
| 4333 | WIPHY_ENTRY | ||
| 4334 | WDEV_ENTRY | ||
| 4335 | __field(bool, success) | ||
| 4336 | ), | ||
| 4337 | TP_fast_assign( | ||
| 4338 | WIPHY_ASSIGN; | ||
| 4339 | WDEV_ASSIGN; | ||
| 4340 | __entry->success = success; | ||
| 4341 | ), | ||
| 4342 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT " success=%d", | ||
| 4343 | WIPHY_PR_ARG, WDEV_PR_ARG, __entry->success) | ||
| 4344 | ); | ||
| 4345 | |||
| 4346 | TRACE_EVENT(cfg80211_nan_ulw_update, | ||
| 4347 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 4348 | const u8 *ulw, size_t ulw_len), | ||
| 4349 | TP_ARGS(wiphy, wdev, ulw, ulw_len), | ||
| 4350 | TP_STRUCT__entry( | ||
| 4351 | WIPHY_ENTRY | ||
| 4352 | WDEV_ENTRY | ||
| 4353 | __dynamic_array(u8, ulw, ulw_len) | ||
| 4354 | ), | ||
| 4355 | TP_fast_assign( | ||
| 4356 | WIPHY_ASSIGN; | ||
| 4357 | WDEV_ASSIGN; | ||
| 4358 | if (ulw && ulw_len) | ||
| 4359 | memcpy(__get_dynamic_array(ulw), ulw, ulw_len); | ||
| 4360 | ), | ||
| 4361 | TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT " ulw: %s", | ||
| 4362 | WIPHY_PR_ARG, WDEV_PR_ARG, | ||
| 4363 | __print_array(__get_dynamic_array(ulw), | ||
| 4364 | __get_dynamic_array_len(ulw), 1)) | ||
| 4365 | ); | ||
| 4366 | |||
| 4367 | TRACE_EVENT(cfg80211_nan_channel_evac, | ||
| 4368 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
| 4369 | const struct cfg80211_chan_def *chandef), | ||
| 4370 | TP_ARGS(wiphy, wdev, chandef), | ||
| 4371 | TP_STRUCT__entry( | ||
| 4372 | WDEV_ENTRY | ||
| 4373 | WIPHY_ENTRY | ||
| 4374 | CHAN_DEF_ENTRY | ||
| 4375 | ), | ||
| 4376 | TP_fast_assign( | ||
| 4377 | WDEV_ASSIGN; | ||
| 4378 | WIPHY_ASSIGN; | ||
| 4379 | CHAN_DEF_ASSIGN(chandef); | ||
| 4380 | ), | ||
| 4381 | TP_printk(WDEV_PR_FMT ", " WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, | ||
| 4382 | WDEV_PR_ARG, WIPHY_PR_ARG, CHAN_DEF_PR_ARG) | ||
| 4383 | ); | ||
| 4279 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 4384 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
| 4280 | 4385 | ||
| 4281 | #undef TRACE_INCLUDE_PATH | 4386 | #undef TRACE_INCLUDE_PATH |
| @@ -90,7 +90,7 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band) · 89 unmodified lines | |||
| 90 | /* see 802.11ax D6.1 27.3.23.2 */ | 90 | /* see 802.11ax D6.1 27.3.23.2 */ |
| 91 | if (chan == 2) | 91 | if (chan == 2) |
| 92 | return MHZ_TO_KHZ(5935); | 92 | return MHZ_TO_KHZ(5935); |
| 93 | if (chan <= 233) | 93 | if (chan <= 253) |
| 94 | return MHZ_TO_KHZ(5950 + chan * 5); | 94 | return MHZ_TO_KHZ(5950 + chan * 5); |
| 95 | break; | 95 | break; |
| 96 | case NL80211_BAND_60GHZ: | 96 | case NL80211_BAND_60GHZ: |
| @@ -625,8 +625,9 @@ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr, · 528 unmodified lines | |||
| 625 | case cpu_to_le16(0): | 625 | case cpu_to_le16(0): |
| 626 | if (iftype != NL80211_IFTYPE_ADHOC && | 626 | if (iftype != NL80211_IFTYPE_ADHOC && |
| 627 | iftype != NL80211_IFTYPE_STATION && | 627 | iftype != NL80211_IFTYPE_STATION && |
| 628 | iftype != NL80211_IFTYPE_OCB) | 628 | iftype != NL80211_IFTYPE_OCB && |
| 629 | return -1; | 629 | iftype != NL80211_IFTYPE_NAN_DATA) |
| 630 | return -1; | ||
| 630 | break; | 631 | break; |
| 631 | } | 632 | } |
| 632 | 633 | ||
| @@ -1144,8 +1145,15 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) · 511 unmodified lines | |||
| 1144 | ev->ij.channel); | 1145 | ev->ij.channel); |
| 1145 | break; | 1146 | break; |
| 1146 | case EVENT_STOPPED: | 1147 | case EVENT_STOPPED: |
| 1147 | cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev, | 1148 | /* |
| 1148 | ev->link_id); | 1149 | * for NAN interfaces cfg80211_leave must be called but |
| 1150 | * locking here doesn't allow this. | ||
| 1151 | */ | ||
| 1152 | if (WARN_ON(wdev->iftype == NL80211_IFTYPE_NAN)) | ||
| 1153 | break; | ||
| 1154 | |||
| 1155 | cfg80211_leave_locked(wiphy_to_rdev(wdev->wiphy), wdev, | ||
| 1156 | ev->link_id); | ||
| 1149 | break; | 1157 | break; |
| 1150 | case EVENT_PORT_AUTHORIZED: | 1158 | case EVENT_PORT_AUTHORIZED: |
| 1151 | __cfg80211_port_authorized(wdev, ev->pa.peer_addr, | 1159 | __cfg80211_port_authorized(wdev, ev->pa.peer_addr, |
| @@ -1184,6 +1192,13 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 32 unmodified lines | |||
| 1184 | if (otype == NL80211_IFTYPE_AP_VLAN) | 1192 | if (otype == NL80211_IFTYPE_AP_VLAN) |
| 1185 | return -EOPNOTSUPP; | 1193 | return -EOPNOTSUPP; |
| 1186 | 1194 | ||
| 1195 | /* | ||
| 1196 | * for NAN interfaces cfg80211_leave must be called for leaving, | ||
| 1197 | * but locking here doesn't allow this. | ||
| 1198 | */ | ||
| 1199 | if (otype == NL80211_IFTYPE_NAN) | ||
| 1200 | return -EOPNOTSUPP; | ||
| 1201 | |||
| 1187 | /* cannot change into P2P device or NAN */ | 1202 | /* cannot change into P2P device or NAN */ |
| 1188 | if (ntype == NL80211_IFTYPE_P2P_DEVICE || | 1203 | if (ntype == NL80211_IFTYPE_P2P_DEVICE || |
| 1189 | ntype == NL80211_IFTYPE_NAN) | 1204 | ntype == NL80211_IFTYPE_NAN) |
| @@ -1204,7 +1219,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 14 unmodified lines | |||
| 1204 | dev->ieee80211_ptr->use_4addr = false; | 1219 | dev->ieee80211_ptr->use_4addr = false; |
| 1205 | rdev_set_qos_map(rdev, dev, NULL); | 1220 | rdev_set_qos_map(rdev, dev, NULL); |
| 1206 | 1221 | ||
| 1207 | cfg80211_leave(rdev, dev->ieee80211_ptr, -1); | 1222 | cfg80211_leave_locked(rdev, dev->ieee80211_ptr, -1); |
| 1208 | 1223 | ||
| 1209 | cfg80211_process_rdev_events(rdev); | 1224 | cfg80211_process_rdev_events(rdev); |
| 1210 | cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); | 1225 | cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); |
| @@ -1232,6 +1247,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 21 unmodified lines | |||
| 1232 | case NL80211_IFTYPE_OCB: | 1247 | case NL80211_IFTYPE_OCB: |
| 1233 | case NL80211_IFTYPE_P2P_CLIENT: | 1248 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1234 | case NL80211_IFTYPE_ADHOC: | 1249 | case NL80211_IFTYPE_ADHOC: |
| 1250 | case NL80211_IFTYPE_NAN_DATA: | ||
| 1235 | dev->priv_flags |= IFF_DONT_BRIDGE; | 1251 | dev->priv_flags |= IFF_DONT_BRIDGE; |
| 1236 | break; | 1252 | break; |
| 1237 | case NL80211_IFTYPE_P2P_GO: | 1253 | case NL80211_IFTYPE_P2P_GO: |