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 | 1017 | netif_napi_add(ar->napi_dev, &ar->napi, ath10k_usb_napi_poll); |
| 1018 | 1018 | |
| 1019 | − usb_get_dev(dev); | |
| 1020 | 1019 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); |
| 1021 | 1020 | product_id = le16_to_cpu(dev->descriptor.idProduct); |
| 1022 | 1021 | |
| @@ -1055,12 +1054,10 @@ err_usb_destroy: · 32 unmodified lines | ||
| 1055 | 1054 | err: |
| 1056 | 1055 | ath10k_core_destroy(ar); |
| 1057 | 1056 | |
| 1058 | − usb_put_dev(dev); | |
| 1059 | − | |
| 1060 | 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 | 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 | 1068 | ath10k_core_unregister(ar_usb->ar); |
| 1072 | 1069 | netif_napi_del(&ar_usb->ar->napi); |
| 1073 | 1070 | ath10k_usb_destroy(ar_usb->ar); |
| 1074 | − usb_put_dev(interface_to_usbdev(interface)); | |
| 1075 | 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 | 1113 | .probe = ath10k_usb_probe, |
| 1118 | 1114 | .suspend = ath10k_usb_pm_suspend, |
| 1119 | 1115 | .resume = ath10k_usb_pm_resume, |
| 1120 | − .disconnect = ath10k_usb_remove, | |
| 1116 | + .disconnect = ath10k_usb_disconnect, | |
| 1121 | 1117 | .id_table = ath10k_usb_ids, |
| 1122 | 1118 | .supports_autosuspend = true, |
| 1123 | 1119 | .disable_hub_initiated_lpm = 1, |
| @@ -21,8 +21,8 @@ · 20 unmodified lines | ||
| 21 | 21 | #define ATH12K_ROOTPD_READY_TIMEOUT (5 * HZ) |
| 22 | 22 | #define ATH12K_RPROC_AFTER_POWERUP QCOM_SSR_AFTER_POWERUP |
| 23 | 23 | #define ATH12K_AHB_FW_PREFIX "q6_fw" |
| 24 | −#define ATH12K_AHB_FW_SUFFIX ".mdt" | |
| 25 | −#define ATH12K_AHB_FW2 "iu_fw.mdt" | |
| 24 | +#define ATH12K_AHB_FW_SUFFIX ".mbn" | |
| 25 | +#define ATH12K_AHB_FW2 "iu_fw.mbn" | |
| 26 | 26 | #define ATH12K_AHB_UPD_SWID 0x12 |
| 27 | 27 | #define ATH12K_USERPD_SPAWN_TIMEOUT (5 * HZ) |
| 28 | 28 | #define ATH12K_USERPD_READY_TIMEOUT (10 * HZ) |
| @@ -523,7 +523,7 @@ struct ath12k_sta { · 522 unmodified lines | ||
| 523 | 523 | u16 links_map; |
| 524 | 524 | u8 assoc_link_id; |
| 525 | 525 | u16 ml_peer_id; |
| 526 | − u8 num_peer; | |
| 526 | + u16 free_logical_link_idx_map; | |
| 527 | 527 | |
| 528 | 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 | 205 | if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) |
| 206 | 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 | 209 | is_ampdu = |
| 210 | 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 | 212 | if (usr_stats->tlv_flags & |
| 220 | 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 | 216 | HTT_PPDU_STATS_ACK_BA_INFO_NUM_MSDU_M); |
| 224 | 217 | tid = le32_get_bits(usr_stats->ack_ba.info, |
| 225 | 218 | HTT_PPDU_STATS_ACK_BA_INFO_TID_NUM); |
| 226 | − } | |
| 227 | 219 | |
| 228 | − if (common->fes_duration_us) | |
| 229 | − tx_duration = le32_to_cpu(common->fes_duration_us); | |
| 220 | + if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { | |
| 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 | 233 | user_rate = &usr_stats->rate; |
| 232 | 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 | 270 | enum hal_rx_legacy_rate { |
| 271 | − HAL_RX_LEGACY_RATE_1_MBPS, | |
| 272 | − HAL_RX_LEGACY_RATE_2_MBPS, | |
| 273 | − HAL_RX_LEGACY_RATE_5_5_MBPS, | |
| 274 | − HAL_RX_LEGACY_RATE_6_MBPS, | |
| 275 | − HAL_RX_LEGACY_RATE_9_MBPS, | |
| 276 | − HAL_RX_LEGACY_RATE_11_MBPS, | |
| 277 | − HAL_RX_LEGACY_RATE_12_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, | |
| 271 | + HAL_RX_LEGACY_RATE_LP_1_MBPS, | |
| 272 | + HAL_RX_LEGACY_RATE_LP_2_MBPS, | |
| 273 | + HAL_RX_LEGACY_RATE_LP_5_5_MBPS, | |
| 274 | + HAL_RX_LEGACY_RATE_LP_11_MBPS, | |
| 275 | + HAL_RX_LEGACY_RATE_SP_2_MBPS, | |
| 276 | + HAL_RX_LEGACY_RATE_SP_5_5_MBPS, | |
| 277 | + HAL_RX_LEGACY_RATE_SP_11_MBPS, | |
| 283 | 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 | 293 | enum hal_ring_type { |
| 287 | 294 | HAL_REO_DST, |
| 288 | 295 | HAL_REO_EXCEPTION, |
| @@ -164,30 +164,31 @@ static const struct ieee80211_channel ath12k_6ghz_channels[] = { · 163 unmodified lines | ||
| 164 | 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 | 175 | static struct ieee80211_rate ath12k_legacy_rates[] = { |
| 168 | 176 | { .bitrate = 10, |
| 169 | 177 | .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, |
| 170 | − { .bitrate = 20, | |
| 171 | − .hw_value = ATH12K_HW_RATE_CCK_LP_2M, | |
| 172 | − .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M, | |
| 173 | − .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | |
| 174 | − { .bitrate = 55, | |
| 175 | − .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M, | |
| 176 | − .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M, | |
| 177 | − .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | |
| 178 | − { .bitrate = 110, | |
| 179 | − .hw_value = ATH12K_HW_RATE_CCK_LP_11M, | |
| 180 | − .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M, | |
| 181 | − .flags = IEEE80211_RATE_SHORT_PREAMBLE }, | |
| 182 | − | |
| 183 | − { .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M }, | |
| 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 }, | |
| 178 | + ATH12K_MAC_RATE_B(20, ATH12K_HW_RATE_CCK_LP_2M, | |
| 179 | + ATH12K_HW_RATE_CCK_SP_2M), | |
| 180 | + ATH12K_MAC_RATE_B(55, ATH12K_HW_RATE_CCK_LP_5_5M, | |
| 181 | + ATH12K_HW_RATE_CCK_SP_5_5M), | |
| 182 | + ATH12K_MAC_RATE_B(110, ATH12K_HW_RATE_CCK_LP_11M, | |
| 183 | + ATH12K_HW_RATE_CCK_SP_11M), | |
| 184 | + ATH12K_MAC_RATE_A_M(60, ATH12K_HW_RATE_OFDM_6M), | |
| 185 | + ATH12K_MAC_RATE_A_M(90, ATH12K_HW_RATE_OFDM_9M), | |
| 186 | + ATH12K_MAC_RATE_A_M(120, ATH12K_HW_RATE_OFDM_12M), | |
| 187 | + ATH12K_MAC_RATE_A_M(180, ATH12K_HW_RATE_OFDM_18M), | |
| 188 | + ATH12K_MAC_RATE_A_M(240, ATH12K_HW_RATE_OFDM_24M), | |
| 189 | + ATH12K_MAC_RATE_A_M(360, ATH12K_HW_RATE_OFDM_36M), | |
| 190 | + ATH12K_MAC_RATE_A_M(480, ATH12K_HW_RATE_OFDM_48M), | |
| 191 | + ATH12K_MAC_RATE_A_M(540, ATH12K_HW_RATE_OFDM_54M), | |
| 191 | 192 | }; |
| 192 | 193 | |
| 193 | 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 | 733 | if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck) |
| 733 | 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 | 739 | return i; |
| 740 | + /* To handle 802.11b short PPDU type */ | |
| 737 | 741 | else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && |
| 738 | 742 | rate->hw_value_short == hw_rate) |
| 739 | 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 | 749 | return 0; |
| @@ -6786,6 +6793,8 @@ static void ath12k_mac_free_unassign_link_sta(struct ath12k_hw *ah, · 6043 unmodified lines | ||
| 6786 | 6793 | return; |
| 6787 | 6794 | |
| 6788 | 6795 | ahsta->links_map &= ~BIT(link_id); |
| 6796 | + ahsta->free_logical_link_idx_map |= BIT(arsta->link_idx); | |
| 6797 | + | |
| 6789 | 6798 | rcu_assign_pointer(ahsta->link[link_id], NULL); |
| 6790 | 6799 | synchronize_rcu(); |
| 6791 | 6800 | |
| @@ -7104,6 +7113,7 @@ static int ath12k_mac_assign_link_sta(struct ath12k_hw *ah, · 312 unmodified lines | ||
| 7104 | 7113 | struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta); |
| 7105 | 7114 | struct ieee80211_link_sta *link_sta; |
| 7106 | 7115 | struct ath12k_link_vif *arvif; |
| 7116 | + int link_idx; | |
| 7107 | 7117 | |
| 7108 | 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 | 7133 | ether_addr_copy(arsta->addr, link_sta->addr); |
| 7124 | 7134 | |
| 7125 | − /* logical index of the link sta in order of creation */ | |
| 7126 | − arsta->link_idx = ahsta->num_peer++; | |
| 7135 | + if (!ahsta->free_logical_link_idx_map) | |
| 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 | 7146 | arsta->link_id = link_id; |
| 7129 | 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 | 7650 | if (old_state == IEEE80211_STA_NOTEXIST && |
| 7633 | 7651 | new_state == IEEE80211_STA_NONE) { |
| 7634 | 7652 | memset(ahsta, 0, sizeof(*ahsta)); |
| 7653 | + ahsta->free_logical_link_idx_map = U16_MAX; | |
| 7635 | 7654 | |
| 7636 | 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 | 444 | static void |
| 409 | 445 | ath12k_wifi7_dp_mon_parse_l_sig_b(const struct hal_rx_lsig_b_info *lsigb, |
| 410 | 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 | 451 | rate = u32_get_bits(info0, HAL_RX_LSIG_B_INFO_INFO0_RATE); |
| 416 | 452 | switch (rate) { |
| 417 | 453 | case 1: |
| 418 | − rate = HAL_RX_LEGACY_RATE_1_MBPS; | |
| 454 | + rate = HAL_RX_LEGACY_RATE_LP_1_MBPS; | |
| 419 | 455 | break; |
| 420 | 456 | case 2: |
| 421 | − case 5: | |
| 422 | − rate = HAL_RX_LEGACY_RATE_2_MBPS; | |
| 457 | + rate = HAL_RX_LEGACY_RATE_LP_2_MBPS; | |
| 423 | 458 | break; |
| 424 | 459 | case 3: |
| 425 | − case 6: | |
| 426 | − rate = HAL_RX_LEGACY_RATE_5_5_MBPS; | |
| 460 | + rate = HAL_RX_LEGACY_RATE_LP_5_5_MBPS; | |
| 427 | 461 | break; |
| 428 | 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 | 471 | case 7: |
| 430 | − rate = HAL_RX_LEGACY_RATE_11_MBPS; | |
| 472 | + rate = HAL_RX_LEGACY_RATE_SP_11_MBPS; | |
| 431 | 473 | break; |
| 432 | 474 | default: |
| 433 | 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 | 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 | 490 | rate = u32_get_bits(info0, HAL_RX_LSIG_A_INFO_INFO0_RATE); |
| 448 | 491 | switch (rate) { |
| 449 | 492 | case 8: |
| 450 | − rate = HAL_RX_LEGACY_RATE_48_MBPS; | |
| 493 | + rate = HAL_RX_LEGACY_RATE_OFDM_48_MBPS; | |
| 451 | 494 | break; |
| 452 | 495 | case 9: |
| 453 | − rate = HAL_RX_LEGACY_RATE_24_MBPS; | |
| 496 | + rate = HAL_RX_LEGACY_RATE_OFDM_24_MBPS; | |
| 454 | 497 | break; |
| 455 | 498 | case 10: |
| 456 | − rate = HAL_RX_LEGACY_RATE_12_MBPS; | |
| 499 | + rate = HAL_RX_LEGACY_RATE_OFDM_12_MBPS; | |
| 457 | 500 | break; |
| 458 | 501 | case 11: |
| 459 | − rate = HAL_RX_LEGACY_RATE_6_MBPS; | |
| 502 | + rate = HAL_RX_LEGACY_RATE_OFDM_6_MBPS; | |
| 460 | 503 | break; |
| 461 | 504 | case 12: |
| 462 | − rate = HAL_RX_LEGACY_RATE_54_MBPS; | |
| 505 | + rate = HAL_RX_LEGACY_RATE_OFDM_54_MBPS; | |
| 463 | 506 | break; |
| 464 | 507 | case 13: |
| 465 | − rate = HAL_RX_LEGACY_RATE_36_MBPS; | |
| 508 | + rate = HAL_RX_LEGACY_RATE_OFDM_36_MBPS; | |
| 466 | 509 | break; |
| 467 | 510 | case 14: |
| 468 | − rate = HAL_RX_LEGACY_RATE_18_MBPS; | |
| 511 | + rate = HAL_RX_LEGACY_RATE_OFDM_18_MBPS; | |
| 469 | 512 | break; |
| 470 | 513 | case 15: |
| 471 | − rate = HAL_RX_LEGACY_RATE_9_MBPS; | |
| 514 | + rate = HAL_RX_LEGACY_RATE_OFDM_9_MBPS; | |
| 472 | 515 | break; |
| 473 | 516 | default: |
| 474 | − rate = HAL_RX_LEGACY_RATE_INVALID; | |
| 517 | + rate = HAL_RX_LEGACY_RATE_OFDM_INVALID; | |
| 518 | + break; | |
| 475 | 519 | } |
| 476 | 520 | |
| 477 | 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 | 10018 | static int |
| 10019 | 10019 | ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, |
| 10020 | − struct wmi_unit_test_cmd ut_cmd, | |
| 10021 | − u32 *test_args) | |
| 10020 | + const struct wmi_unit_test_arg *ut) | |
| 10022 | 10021 | { |
| 10023 | 10022 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
| 10024 | 10023 | struct wmi_unit_test_cmd *cmd; |
| 10024 | + int buf_len, arg_len; | |
| 10025 | 10025 | struct sk_buff *skb; |
| 10026 | 10026 | struct wmi_tlv *tlv; |
| 10027 | + __le32 *ut_cmd_args; | |
| 10027 | 10028 | void *ptr; |
| 10028 | − u32 *ut_cmd_args; | |
| 10029 | − int buf_len, arg_len; | |
| 10030 | 10029 | int ret; |
| 10031 | 10030 | int i; |
| 10032 | 10031 | |
| 10033 | − arg_len = sizeof(u32) * le32_to_cpu(ut_cmd.num_args); | |
| 10034 | − buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE; | |
| 10032 | + arg_len = sizeof(*ut_cmd_args) * ut->num_args; | |
| 10033 | + buf_len = sizeof(*cmd) + arg_len + TLV_HDR_SIZE; | |
| 10035 | 10034 | |
| 10036 | 10035 | skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len); |
| 10037 | 10036 | if (!skb) |
| 10038 | 10037 | return -ENOMEM; |
| 10039 | 10038 | |
| 10040 | − cmd = (struct wmi_unit_test_cmd *)skb->data; | |
| 10039 | + ptr = skb->data; | |
| 10040 | + cmd = ptr; | |
| 10041 | 10041 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_UNIT_TEST_CMD, |
| 10042 | − sizeof(ut_cmd)); | |
| 10043 | − | |
| 10044 | − cmd->vdev_id = ut_cmd.vdev_id; | |
| 10045 | − cmd->module_id = ut_cmd.module_id; | |
| 10046 | − cmd->num_args = ut_cmd.num_args; | |
| 10047 | − cmd->diag_token = ut_cmd.diag_token; | |
| 10048 | − | |
| 10049 | − ptr = skb->data + sizeof(ut_cmd); | |
| 10042 | + sizeof(*cmd)); | |
| 10043 | + cmd->vdev_id = cpu_to_le32(ut->vdev_id); | |
| 10044 | + cmd->module_id = cpu_to_le32(ut->module_id); | |
| 10045 | + cmd->num_args = cpu_to_le32(ut->num_args); | |
| 10046 | + cmd->diag_token = cpu_to_le32(ut->diag_token); | |
| 10050 | 10047 | |
| 10048 | + ptr += sizeof(*cmd); | |
| 10051 | 10049 | tlv = ptr; |
| 10052 | 10050 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, arg_len); |
| 10053 | 10051 | |
| 10054 | 10052 | ptr += TLV_HDR_SIZE; |
| 10055 | − | |
| 10056 | 10053 | ut_cmd_args = ptr; |
| 10057 | − for (i = 0; i < le32_to_cpu(ut_cmd.num_args); i++) | |
| 10058 | − ut_cmd_args[i] = test_args[i]; | |
| 10054 | + for (i = 0; i < ut->num_args; i++) | |
| 10055 | + ut_cmd_args[i] = cpu_to_le32(ut->args[i]); | |
| 10059 | 10056 | |
| 10060 | 10057 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
| 10061 | 10058 | "WMI unit test : module %d vdev %d n_args %d token %d\n", |
| 10062 | − cmd->module_id, cmd->vdev_id, cmd->num_args, | |
| 10063 | − cmd->diag_token); | |
| 10059 | + ut->module_id, ut->vdev_id, ut->num_args, ut->diag_token); | |
| 10064 | 10060 | |
| 10065 | 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 | 10072 | int ath12k_wmi_simulate_radar(struct ath12k *ar) |
| 10077 | 10073 | { |
| 10078 | 10074 | struct ath12k_link_vif *arvif; |
| 10079 | − u32 dfs_args[DFS_MAX_TEST_ARGS]; | |
| 10080 | − struct wmi_unit_test_cmd wmi_ut; | |
| 10075 | + struct wmi_unit_test_arg wmi_ut = {}; | |
| 10081 | 10076 | bool arvif_found = false; |
| 10082 | 10077 | |
| 10083 | 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 | 10085 | if (!arvif_found) |
| 10091 | 10086 | return -EINVAL; |
| 10092 | 10087 | |
| 10093 | − dfs_args[DFS_TEST_CMDID] = 0; | |
| 10094 | − dfs_args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id; | |
| 10095 | − /* Currently we could pass segment_id(b0 - b1), chirp(b2) | |
| 10088 | + wmi_ut.args[DFS_TEST_CMDID] = 0; | |
| 10089 | + wmi_ut.args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id; | |
| 10090 | + /* | |
| 10091 | + * Currently we could pass segment_id(b0 - b1), chirp(b2) | |
| 10096 | 10092 | * freq offset (b3 - b10) to unit test. For simulation |
| 10097 | 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); | |
| 10102 | − wmi_ut.module_id = cpu_to_le32(DFS_UNIT_TEST_MODULE); | |
| 10103 | − wmi_ut.num_args = cpu_to_le32(DFS_MAX_TEST_ARGS); | |
| 10104 | − wmi_ut.diag_token = cpu_to_le32(DFS_UNIT_TEST_TOKEN); | |
| 10097 | + wmi_ut.vdev_id = arvif->vdev_id; | |
| 10098 | + wmi_ut.module_id = DFS_UNIT_TEST_MODULE; | |
| 10099 | + wmi_ut.num_args = DFS_MAX_TEST_ARGS; | |
| 10100 | + wmi_ut.diag_token = DFS_UNIT_TEST_TOKEN; | |
| 10105 | 10101 | |
| 10106 | 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 | 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 | 4193 | struct ath12k_wmi_mac_addr_params peer_macaddr; |
| 4194 | 4194 | } __packed; |
| 4195 | 4195 | |
| 4196 | −#define DFS_PHYERR_UNIT_TEST_CMD 0 | |
| 4197 | 4196 | #define DFS_UNIT_TEST_MODULE 0x2b |
| 4198 | 4197 | #define DFS_UNIT_TEST_TOKEN 0xAA |
| 4199 | 4198 | |
| @@ -4204,10 +4203,15 @@ enum dfs_test_args_idx { · 4 unmodified lines | ||
| 4204 | 4203 | DFS_MAX_TEST_ARGS, |
| 4205 | 4204 | }; |
| 4206 | 4205 | |
| 4207 | −struct wmi_dfs_unit_test_arg { | |
| 4208 | − u32 cmd_id; | |
| 4209 | − u32 pdev_id; | |
| 4210 | − u32 radar_param; | |
| 4206 | +/* update if another test command requires more */ | |
| 4207 | +#define WMI_UNIT_TEST_ARGS_MAX DFS_MAX_TEST_ARGS | |
| 4208 | + | |
| 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 | 4217 | struct wmi_unit_test_cmd { |
| @@ -1124,8 +1124,6 @@ static int ath6kl_usb_probe(struct usb_interface *interface, · 1123 unmodified lines | ||
| 1124 | 1124 | int vendor_id, product_id; |
| 1125 | 1125 | int ret = 0; |
| 1126 | 1126 | |
| 1127 | − usb_get_dev(dev); | |
| 1128 | − | |
| 1129 | 1127 | vendor_id = le16_to_cpu(dev->descriptor.idVendor); |
| 1130 | 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 | 1141 | ath6kl_dbg(ATH6KL_DBG_USB, "USB 1.1 Host\n"); |
| 1144 | 1142 | |
| 1145 | 1143 | ar_usb = ath6kl_usb_create(interface); |
| 1146 | − | |
| 1147 | − if (ar_usb == NULL) { | |
| 1148 | − ret = -ENOMEM; | |
| 1149 | − goto err_usb_put; | |
| 1150 | − } | |
| 1144 | + if (ar_usb == NULL) | |
| 1145 | + return -ENOMEM; | |
| 1151 | 1146 | |
| 1152 | 1147 | ar = ath6kl_core_create(&ar_usb->udev->dev); |
| 1153 | 1148 | if (ar == NULL) { |
| @@ -1176,15 +1171,12 @@ err_core_free: · 22 unmodified lines | ||
| 1176 | 1171 | ath6kl_core_destroy(ar); |
| 1177 | 1172 | err_usb_destroy: |
| 1178 | 1173 | ath6kl_usb_destroy(ar_usb); |
| 1179 | −err_usb_put: | |
| 1180 | − usb_put_dev(dev); | |
| 1181 | 1174 | |
| 1182 | 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 | 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 | 1227 | .probe = ath6kl_usb_probe, |
| 1236 | 1228 | .suspend = ath6kl_usb_pm_suspend, |
| 1237 | 1229 | .resume = ath6kl_usb_pm_resume, |
| 1238 | − .disconnect = ath6kl_usb_remove, | |
| 1230 | + .disconnect = ath6kl_usb_disconnect, | |
| 1239 | 1231 | .id_table = ath6kl_usb_ids, |
| 1240 | 1232 | .supports_autosuspend = true, |
| 1241 | 1233 | .disable_hub_initiated_lpm = 1, |
| @@ -1630,16 +1630,6 @@ enum wmi_roam_mode { · 1629 unmodified lines | ||
| 1630 | 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 | 1633 | struct low_rssi_scan_params { |
| 1644 | 1634 | __le16 lrssi_scan_period; |
| 1645 | 1635 | a_sle16 lrssi_scan_threshold; |
| @@ -1652,7 +1642,6 @@ struct roam_ctrl_cmd { · 6 unmodified lines | ||
| 1652 | 1642 | union { |
| 1653 | 1643 | u8 bssid[ETH_ALEN]; /* WMI_FORCE_ROAM */ |
| 1654 | 1644 | u8 roam_mode; /* WMI_SET_ROAM_MODE */ |
| 1655 | − struct bss_bias_info bss; /* WMI_SET_HOST_BIAS */ | |
| 1656 | 1645 | struct low_rssi_scan_params params; /* WMI_SET_LRSSI_SCAN_PARAMS |
| 1657 | 1646 | */ |
| 1658 | 1647 | } __packed info; |
| @@ -1382,8 +1382,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, · 1381 unmodified lines | ||
| 1382 | 1382 | goto err_alloc; |
| 1383 | 1383 | } |
| 1384 | 1384 | |
| 1385 | − usb_get_dev(udev); | |
| 1386 | − | |
| 1387 | 1385 | hif_dev->udev = udev; |
| 1388 | 1386 | hif_dev->interface = interface; |
| 1389 | 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 | 1401 | err_fw_req: |
| 1404 | 1402 | usb_set_intfdata(interface, NULL); |
| 1405 | 1403 | kfree(hif_dev); |
| 1406 | − usb_put_dev(udev); | |
| 1407 | 1404 | err_alloc: |
| 1408 | 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 | 1449 | kfree(hif_dev); |
| 1453 | 1450 | dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n"); |
| 1454 | − usb_put_dev(udev); | |
| 1455 | 1451 | } |
| 1456 | 1452 | |
| 1457 | 1453 | #ifdef CONFIG_PM |
| @@ -837,18 +837,19 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, · 836 unmodified lines | ||
| 837 | 837 | struct b43_dmaring *ring; |
| 838 | 838 | int i, err; |
| 839 | 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 | 848 | if (!ring) |
| 843 | 849 | goto out; |
| 844 | 850 | |
| 845 | − ring->nr_slots = B43_RXRING_SLOTS; | |
| 846 | − if (for_tx) | |
| 847 | − ring->nr_slots = B43_TXRING_SLOTS; | |
| 851 | + ring->nr_slots = nr_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 | 853 | for (i = 0; i < ring->nr_slots; i++) |
| 853 | 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 | 944 | err_kfree_txhdr_cache: |
| 944 | 945 | kfree(ring->txhdr_cache); |
| 945 | 946 | err_kfree_meta: |
| 946 | − kfree(ring->meta); | |
| 947 | − err_kfree_ring: | |
| 948 | 947 | kfree(ring); |
| 949 | 948 | ring = NULL; |
| 950 | 949 | goto out; |
| @@ -1004,7 +1003,6 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring, · 53 unmodified lines | ||
| 1004 | 1003 | free_ringmemory(ring); |
| 1005 | 1004 | |
| 1006 | 1005 | kfree(ring->txhdr_cache); |
| 1007 | − kfree(ring->meta); | |
| 1008 | 1006 | kfree(ring); |
| 1009 | 1007 | } |
| 1010 | 1008 | |
| @@ -228,8 +228,6 @@ struct b43_dmaring { · 227 unmodified lines | ||
| 228 | 228 | const struct b43_dma_ops *ops; |
| 229 | 229 | /* Kernel virtual base address of the ring memory. */ |
| 230 | 230 | void *descbase; |
| 231 | − /* Meta data about all descriptors. */ | |
| 232 | − struct b43_dmadesc_meta *meta; | |
| 233 | 231 | /* Cache of TX headers for each TX frame. |
| 234 | 232 | * This is to avoid an allocation on each TX. |
| 235 | 233 | * This is NULL for an RX ring. |
| @@ -273,6 +271,8 @@ struct b43_dmaring { · 37 unmodified lines | ||
| 273 | 271 | /* Statistics: Total number of TX plus all retries. */ |
| 274 | 272 | u64 nr_total_packet_tries; |
| 275 | 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 | 278 | static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset) |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "fw/api/txq.h" |
| 11 | 11 | |
| 12 | 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 | 15 | /* Lowest firmware API version supported */ |
| 16 | 16 | #define IWL_BZ_UCODE_API_MIN 100 |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "fw/api/txq.h" |
| 10 | 10 | |
| 11 | 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 | 14 | /* Lowest firmware API version supported */ |
| 15 | 15 | #define IWL_DR_UCODE_API_MIN 100 |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "fw/api/txq.h" |
| 11 | 11 | |
| 12 | 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 | 15 | /* Lowest firmware API version supported */ |
| 16 | 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 | 504 | u8 num_chains, u8 num_sub_bands) |
| 505 | 505 | { |
| 506 | 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 | 509 | subband++) { |
| 509 | 510 | /* if we don't have the values, use the default */ |
| 510 | 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 | 535 | if (IS_ERR(data)) |
| 535 | 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 | 555 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 539 | 556 | ACPI_WRDS_WIFI_DATA_SIZE_REV2, |
| 540 | 557 | &tbl_rev); |
| @@ -591,6 +608,13 @@ read_table: · 50 unmodified lines | ||
| 591 | 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 | 618 | IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); |
| 595 | 619 | |
| 596 | 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 | 648 | if (IS_ERR(data)) |
| 625 | 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 | 667 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 629 | 668 | ACPI_EWRD_WIFI_DATA_SIZE_REV2, |
| 630 | 669 | &tbl_rev); |
| @@ -679,6 +718,13 @@ read_table: · 48 unmodified lines | ||
| 679 | 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 | 728 | enabled = !!(wifi_pkg->package.elements[1].integer.value); |
| 683 | 729 | n_profiles = wifi_pkg->package.elements[2].integer.value; |
| 684 | 730 | |
| @@ -721,6 +767,13 @@ read_table: · 36 unmodified lines | ||
| 721 | 767 | if (tbl_rev < 2) |
| 722 | 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 | 777 | /* parse cdb chains for all profiles */ |
| 725 | 778 | for (i = 0; i < n_profiles; i++) { |
| 726 | 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 | 812 | u8 profiles; |
| 760 | 813 | u8 min_profiles; |
| 761 | 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 | 822 | .revisions = BIT(3), |
| 764 | 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 | 871 | num_bands = rev_data[idx].bands; |
| 813 | 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 | 886 | if (rev_data[idx].min_profiles) { |
| 816 | 887 | /* read header that says # of profiles */ |
| 817 | 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 | 923 | read_table: |
| 853 | 924 | fwrt->geo_rev = tbl_rev; |
| 925 | + | |
| 854 | 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 | 930 | union acpi_object *entry; |
| 857 | 931 | |
| 858 | 932 | /* |
| 859 | − * num_bands is either 2 or 3, if it's only 2 then | |
| 860 | − * fill the third band (6 GHz) with the values from | |
| 861 | − * 5 GHz (second band) | |
| 933 | + * num_bands is either 2 or 3 or 4, if it's lower | |
| 934 | + * than 4, fill the third band (6 GHz) with the values | |
| 935 | + * from 5 GHz (second band) | |
| 862 | 936 | */ |
| 863 | 937 | if (j >= num_bands) { |
| 864 | − fwrt->geo_profiles[i].bands[j].max = | |
| 865 | − fwrt->geo_profiles[i].bands[1].max; | |
| 938 | + prof->bands[j].max = prof->bands[1].max; | |
| 866 | 939 | } else { |
| 867 | 940 | entry = &wifi_pkg->package.elements[entry_idx]; |
| 868 | 941 | entry_idx++; |
| @@ -872,15 +945,17 @@ read_table: · 3 unmodified lines | ||
| 872 | 945 | goto out_free; |
| 873 | 946 | } |
| 874 | 947 | |
| 875 | − fwrt->geo_profiles[i].bands[j].max = | |
| 948 | + prof->bands[j].max = | |
| 876 | 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 | 955 | /* same here as above */ |
| 881 | 956 | if (j >= num_bands) { |
| 882 | − fwrt->geo_profiles[i].bands[j].chains[k] = | |
| 883 | − fwrt->geo_profiles[i].bands[1].chains[k]; | |
| 957 | + prof->bands[j].chains[k] = | |
| 958 | + prof->bands[1].chains[k]; | |
| 884 | 959 | } else { |
| 885 | 960 | entry = &wifi_pkg->package.elements[entry_idx]; |
| 886 | 961 | entry_idx++; |
| @@ -890,7 +965,7 @@ read_table: · 3 unmodified lines | ||
| 890 | 965 | goto out_free; |
| 891 | 966 | } |
| 892 | 967 | |
| 893 | − fwrt->geo_profiles[i].bands[j].chains[k] = | |
| 968 | + prof->bands[j].chains[k] = | |
| 894 | 969 | entry->integer.value; |
| 895 | 970 | } |
| 896 | 971 | } |
| @@ -898,6 +973,7 @@ read_table: · 1 unmodified line | ||
| 898 | 973 | } |
| 899 | 974 | |
| 900 | 975 | fwrt->geo_num_profiles = num_profiles; |
| 976 | + fwrt->geo_bios_source = BIOS_SOURCE_ACPI; | |
| 901 | 977 | fwrt->geo_enabled = true; |
| 902 | 978 | ret = 0; |
| 903 | 979 | out_free: |
| @@ -915,6 +991,22 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) · 11 unmodified lines | ||
| 915 | 991 | if (IS_ERR(data)) |
| 916 | 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 | 1010 | /* try to read ppag table rev 1 to 4 (all have the same data size) */ |
| 919 | 1011 | wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, |
| 920 | 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 | 1042 | goto out_free; |
| 951 | 1043 | |
| 952 | 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 | 1054 | fwrt->ppag_bios_rev = tbl_rev; |
| 954 | 1055 | flags = &wifi_pkg->package.elements[1]; |
| 955 | 1056 | |
| @@ -966,7 +1067,7 @@ read_table: · 10 unmodified lines | ||
| 966 | 1067 | * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the |
| 967 | 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 | 1071 | for (j = 0; j < num_sub_bands; j++) { |
| 971 | 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 | 1085 | fwrt->ppag_bios_source = BIOS_SOURCE_ACPI; |
| 984 | 1086 | ret = 0; |
| 985 | 1087 | |
| @@ -8,11 +8,6 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <linux/acpi.h> |
| 10 | 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 | 11 | #include "fw/img.h" |
| 17 | 12 | #include "iwl-trans.h" |
| 18 | 13 | |
| @@ -44,6 +39,7 @@ · 25 unmodified lines | ||
| 44 | 39 | #define ACPI_SAR_NUM_SUB_BANDS_REV0 5 |
| 45 | 40 | #define ACPI_SAR_NUM_SUB_BANDS_REV1 11 |
| 46 | 41 | #define ACPI_SAR_NUM_SUB_BANDS_REV2 11 |
| 42 | +#define ACPI_SAR_NUM_SUB_BANDS_REV3 12 | |
| 47 | 43 | |
| 48 | 44 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV0 (ACPI_SAR_NUM_CHAINS_REV0 * \ |
| 49 | 45 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 2) |
| @@ -51,6 +47,8 @@ · 1 unmodified line | ||
| 51 | 47 | ACPI_SAR_NUM_SUB_BANDS_REV1 + 2) |
| 52 | 48 | #define ACPI_WRDS_WIFI_DATA_SIZE_REV2 (ACPI_SAR_NUM_CHAINS_REV2 * \ |
| 53 | 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 | 52 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV0 ((ACPI_SAR_PROFILE_NUM - 1) * \ |
| 55 | 53 | ACPI_SAR_NUM_CHAINS_REV0 * \ |
| 56 | 54 | ACPI_SAR_NUM_SUB_BANDS_REV0 + 3) |
| @@ -60,11 +58,15 @@ · 3 unmodified lines | ||
| 60 | 58 | #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ |
| 61 | 59 | ACPI_SAR_NUM_CHAINS_REV2 * \ |
| 62 | 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 | 64 | #define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ |
| 64 | 65 | |
| 65 | 66 | /* revision 0 and 1 are identical, except for the semantics in the FW */ |
| 66 | 67 | #define ACPI_GEO_NUM_BANDS_REV0 2 |
| 67 | 68 | #define ACPI_GEO_NUM_BANDS_REV2 3 |
| 69 | +#define ACPI_GEO_NUM_BANDS_REV4 4 | |
| 68 | 70 | |
| 69 | 71 | #define ACPI_WRDD_WIFI_DATA_SIZE 2 |
| 70 | 72 | #define ACPI_SPLC_WIFI_DATA_SIZE 2 |
| @@ -96,10 +98,18 @@ · 25 unmodified lines | ||
| 96 | 98 | */ |
| 97 | 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 * \ | |
| 100 | − IWL_NUM_SUB_BANDS_V1) + 2) | |
| 101 | −#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ | |
| 102 | − IWL_NUM_SUB_BANDS_V2) + 2) | |
| 101 | +#define ACPI_PPAG_NUM_CHAINS 2 | |
| 102 | +#define ACPI_PPAG_NUM_BANDS_V1 5 | |
| 103 | +#define ACPI_PPAG_NUM_BANDS_V2 11 | |
| 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 | 114 | #define IWL_SAR_ENABLE_MSK BIT(0) |
| 105 | 115 | #define IWL_REDUCE_POWER_FLAGS_POS 1 |
| @@ -56,7 +56,8 @@ enum iwl_data_path_subcmd_ids { · 55 unmodified lines | ||
| 56 | 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 | 62 | TLC_MNG_CONFIG_CMD = 0xF, |
| 62 | 63 | |
| @@ -1,6 +1,6 @@ | ||
| 1 | 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 | 4 | * Copyright (C) 2013-2015 Intel Mobile Communications GmbH |
| 5 | 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 | 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 | 31 | SESSION_PROTECTION_CMD = 0x5, |
| 32 | 32 | /** |
| @@ -34,7 +34,8 @@ enum iwl_mac_conf_subcmd_ids { · 1 unmodified line | ||
| 34 | 34 | */ |
| 35 | 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 | 40 | MAC_CONFIG_CMD = 0x8, |
| 40 | 41 | /** |
| @@ -42,7 +43,8 @@ enum iwl_mac_conf_subcmd_ids { · 1 unmodified line | ||
| 42 | 43 | */ |
| 43 | 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 | 49 | STA_CONFIG_CMD = 0xA, |
| 48 | 50 | /** |
| @@ -356,7 +358,7 @@ struct iwl_mac_wifi_gen_support { · 307 unmodified lines | ||
| 356 | 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 | 362 | * MLD API for versions 2 and 3 |
| 361 | 363 | * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) |
| 362 | 364 | * |
| @@ -375,7 +377,7 @@ struct iwl_mac_wifi_gen_support { · 12 unmodified lines | ||
| 375 | 377 | * @client: client mac data |
| 376 | 378 | * @p2p_dev: mac data for p2p device |
| 377 | 379 | */ |
| 378 | −struct iwl_mac_config_cmd { | |
| 380 | +struct iwl_mac_config_cmd_v3 { | |
| 379 | 381 | __le32 id_and_color; |
| 380 | 382 | __le32 action; |
| 381 | 383 | /* MAC_CONTEXT_TYPE_API_E */ |
| @@ -393,7 +395,62 @@ struct iwl_mac_config_cmd { · 11 unmodified lines | ||
| 393 | 395 | struct iwl_mac_client_data client; |
| 394 | 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 | 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 | 710 | #define IWL_FW_MAX_ACTIVE_LINKS_NUM 2 |
| 654 | 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 | 715 | * enum iwl_fw_sta_type - FW station types |
| @@ -662,6 +720,13 @@ struct iwl_link_config_cmd { · 4 unmodified lines | ||
| 662 | 720 | * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be |
| 663 | 721 | * suspended / resumed at the right timing depending on the clients' |
| 664 | 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 | 730 | * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type |
| 666 | 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 | 734 | STATION_TYPE_PEER, |
| 670 | 735 | STATION_TYPE_BCAST_MGMT, |
| 671 | 736 | STATION_TYPE_MCAST, |
| 672 | − STATION_TYPE_AUX, | |
| 673 | −}; /* STATION_TYPE_E_VER_1 */ | |
| 737 | + STATION_TYPE_NAN_PEER_NMI, | |
| 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 | 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 | 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 | 801 | * station table |
| 734 | 802 | * ( STA_CONFIG_CMD = 0xA ) |
| 735 | 803 | * |
| @@ -769,7 +837,7 @@ struct iwl_sta_cfg_cmd_v1 { · 33 unmodified lines | ||
| 769 | 837 | * @mic_compute_pad_delay: MIC compute time padding |
| 770 | 838 | * @reserved: Reserved for alignment |
| 771 | 839 | */ |
| 772 | −struct iwl_sta_cfg_cmd { | |
| 840 | +struct iwl_sta_cfg_cmd_v2 { | |
| 773 | 841 | __le32 sta_id; |
| 774 | 842 | __le32 link_id; |
| 775 | 843 | u8 peer_mld_address[ETH_ALEN]; |
| @@ -799,6 +867,83 @@ struct iwl_sta_cfg_cmd { · 23 unmodified lines | ||
| 799 | 867 | u8 reserved[2]; |
| 800 | 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 | 948 | * struct iwl_aux_sta_cmd - command for AUX STA configuration |
| 804 | 949 | * ( AUX_STA_CMD = 0xB ) |
| @@ -57,8 +57,7 @@ enum iwl_mac_protection_flags { · 56 unmodified lines | ||
| 57 | 57 | * @FW_MAC_TYPE_P2P_DEVICE: P2P Device |
| 58 | 58 | * @FW_MAC_TYPE_P2P_STA: P2P client |
| 59 | 59 | * @FW_MAC_TYPE_GO: P2P GO |
| 60 | − * @FW_MAC_TYPE_TEST: ? | |
| 61 | − * @FW_MAC_TYPE_MAX: highest support MAC type | |
| 60 | + * @FW_MAC_TYPE_NAN: NAN (since version 4) | |
| 62 | 61 | */ |
| 63 | 62 | enum iwl_mac_types { |
| 64 | 63 | FW_MAC_TYPE_FIRST = 1, |
| @@ -70,8 +69,7 @@ enum iwl_mac_types { · 5 unmodified lines | ||
| 70 | 69 | FW_MAC_TYPE_P2P_DEVICE, |
| 71 | 70 | FW_MAC_TYPE_P2P_STA, |
| 72 | 71 | FW_MAC_TYPE_GO, |
| 73 | − FW_MAC_TYPE_TEST, | |
| 74 | − FW_MAC_TYPE_MAX = FW_MAC_TYPE_TEST | |
| 72 | + FW_MAC_TYPE_NAN, | |
| 75 | 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 | 204 | } __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ |
| 205 | 205 | |
| 206 | 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 | 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 | 227 | struct iwl_nvm_get_info_regulatory { |
| 228 | 228 | __le32 lar_enabled; |
| 229 | 229 | __le32 n_channels; |
| 230 | − __le32 channel_profile[IWL_NUM_CHANNELS]; | |
| 230 | + __le32 channel_profile[IWL_NUM_CHANNELS_V2]; | |
| 231 | 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 | 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 | 705 | * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) |
| 706 | 706 | * @reserved: reserved |
| 707 | 707 | */ |
| 708 | −struct iwl_mcc_allowed_ap_type_cmd { | |
| 708 | +struct iwl_mcc_allowed_ap_type_cmd_v1 { | |
| 709 | 709 | u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; |
| 710 | 710 | __le16 reserved; |
| 711 | 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 | 723 | #endif /* __iwl_fw_api_nvm_reg_h__ */ |
| @@ -269,6 +269,7 @@ enum iwl_dev_tx_power_cmd_mode { · 268 unmodified lines | ||
| 269 | 269 | #define IWL_NUM_CHAIN_LIMITS 2 |
| 270 | 270 | #define IWL_NUM_SUB_BANDS_V1 5 |
| 271 | 271 | #define IWL_NUM_SUB_BANDS_V2 11 |
| 272 | +#define IWL_NUM_SUB_BANDS_V3 12 | |
| 272 | 273 | |
| 273 | 274 | /** |
| 274 | 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 | 426 | __le32 flags; |
| 426 | 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 | 438 | * struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion) |
| 430 | 439 | * @common: common part of the command |
| 431 | 440 | * @v9: version 9 part of the command |
| 432 | 441 | * @v10: version 10 part of the command |
| 442 | + * @v11: version 11 part of the command | |
| 433 | 443 | */ |
| 434 | 444 | struct iwl_dev_tx_power_cmd { |
| 435 | 445 | struct iwl_dev_tx_power_common common; |
| 436 | 446 | union { |
| 437 | 447 | struct iwl_dev_tx_power_cmd_v9 v9; |
| 438 | 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 | 456 | #define IWL_NUM_GEO_PROFILES 3 |
| 443 | 457 | #define IWL_NUM_GEO_PROFILES_V3 8 |
| 444 | 458 | #define IWL_NUM_BANDS_PER_CHAIN_V1 2 |
| 445 | 459 | #define IWL_NUM_BANDS_PER_CHAIN_V2 3 |
| 460 | +#define IWL_NUM_BANDS_PER_CHAIN_V6 4 | |
| 446 | 461 | |
| 447 | 462 | /** |
| 448 | 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 | 539 | __le32 table_revision; |
| 525 | 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 | 554 | union iwl_geo_tx_power_profiles_cmd { |
| 528 | 555 | struct iwl_geo_tx_power_profiles_cmd_v1 v1; |
| 529 | 556 | struct iwl_geo_tx_power_profiles_cmd_v2 v2; |
| 530 | 557 | struct iwl_geo_tx_power_profiles_cmd_v3 v3; |
| 531 | 558 | struct iwl_geo_tx_power_profiles_cmd_v4 v4; |
| 532 | 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 | 601 | * @v1: command version 1 structure. |
| 574 | 602 | * @v5: command version 5 structure. |
| 575 | 603 | * @v7: command version 7 structure. |
| 604 | + * @v8: command version 8 structure. | |
| 576 | 605 | * @v1.flags: values from &enum iwl_ppag_flags |
| 577 | 606 | * @v1.gain: table of antenna gain values per chain and sub-band |
| 578 | 607 | * @v1.reserved: reserved |
| @@ -581,6 +610,8 @@ enum iwl_ppag_flags { · 2 unmodified lines | ||
| 581 | 610 | * @v7.ppag_config_info: see @struct bios_value_u32 |
| 582 | 611 | * @v7.gain: table of antenna gain values per chain and sub-band |
| 583 | 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 | 616 | union iwl_ppag_table_cmd { |
| 586 | 617 | struct { |
| @@ -598,6 +629,10 @@ union iwl_ppag_table_cmd { · 11 unmodified lines | ||
| 598 | 629 | s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; |
| 599 | 630 | s8 reserved[2]; |
| 600 | 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 | 636 | } __packed; |
| 602 | 637 | |
| 603 | 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 | 985 | } __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ |
| 986 | 986 | |
| 987 | 987 | #define SCAN_MAX_NUM_CHANS_V3 67 |
| 988 | +#define SCAN_MAX_NUM_CHANS_V4 68 | |
| 988 | 989 | |
| 989 | 990 | /** |
| 990 | 991 | * struct iwl_scan_channel_params_v4 - channel params |
| @@ -1027,6 +1028,24 @@ struct iwl_scan_channel_params_v7 { · 36 unmodified lines | ||
| 1027 | 1028 | struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; |
| 1028 | 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 | 1050 | * struct iwl_scan_general_params_v11 - channel params |
| 1032 | 1051 | * @flags: &enum iwl_umac_scan_general_flags_v2 |
| @@ -1109,6 +1128,20 @@ struct iwl_scan_req_params_v17 { · 76 unmodified lines | ||
| 1109 | 1128 | struct iwl_scan_probe_params_v4 probe_params; |
| 1110 | 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 | 1146 | * struct iwl_scan_req_umac_v12 - scan request command (v12) |
| 1114 | 1147 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets |
| @@ -1133,6 +1166,18 @@ struct iwl_scan_req_umac_v17 { · 18 unmodified lines | ||
| 1133 | 1166 | struct iwl_scan_req_params_v17 scan_params; |
| 1134 | 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 | 1182 | * struct iwl_umac_scan_abort - scan abort command |
| 1138 | 1183 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets |
| @@ -598,7 +598,6 @@ struct iwl_stats_ntfy_per_sta { · 597 unmodified lines | ||
| 598 | 598 | } __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ |
| 599 | 599 | |
| 600 | 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 | 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 | 610 | struct iwl_system_statistics_notif_oper { |
| 612 | 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 | 613 | struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; |
| 615 | 614 | struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; |
| 616 | 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 | 624 | struct iwl_system_statistics_part1_notif_oper { |
| 626 | 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 | 627 | __le32 per_phy_crc_error_stats[IWL_STATS_MAX_PHY_OPERATIONAL]; |
| 629 | 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 | 2933 | IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", |
| 2934 | 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 | 2937 | usecs_to_jiffies(delay)); |
| 2938 | 2938 | |
| 2939 | 2939 | return 0; |
| @@ -3236,7 +3236,7 @@ int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, · 296 unmodified lines | ||
| 3236 | 3236 | if (sync) |
| 3237 | 3237 | iwl_fw_dbg_collect_sync(fwrt, idx); |
| 3238 | 3238 | else |
| 3239 | − queue_delayed_work(system_unbound_wq, | |
| 3239 | + queue_delayed_work(system_dfl_wq, | |
| 3240 | 3240 | &fwrt->dump.wks[idx].wk, |
| 3241 | 3241 | usecs_to_jiffies(delay)); |
| 3242 | 3242 | |
| @@ -1,6 +1,6 @@ | ||
| 1 | 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 | 4 | * Copyright (C) 2013-2014 Intel Mobile Communications GmbH |
| 5 | 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 | 129 | IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id, |
| 130 | 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 | 131 | IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2); |
| 135 | 132 | IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1); |
| 136 | 133 | IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2); |
| 137 | 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 | 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 | 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 | 193 | IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id, |
| 202 | 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 | 195 | IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2); |
| 208 | 196 | IWL_ERR(fwrt, "0x%08X | data1\n", table.data1); |
| 209 | 197 | IWL_ERR(fwrt, "0x%08X | data2\n", table.data2); |
| 210 | 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 | 227 | struct iwl_trans *trans = fwrt->trans; |
| 265 | 228 | struct iwl_tcm_error_event_table table = {}; |
| 266 | 229 | u32 base = fwrt->trans->dbg.tcm_error_event_table[idx]; |
| 267 | − int i; | |
| 268 | 230 | u32 flag = idx ? IWL_ERROR_EVENT_TABLE_TCM2 : |
| 269 | 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 | 238 | IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); |
| 277 | 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 | 240 | IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2); |
| 281 | 241 | IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1); |
| 282 | 242 | IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2); |
| 283 | 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 | 288 | IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); |
| 340 | 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 | 290 | IWL_ERR(fwrt, "0x%08X | rcm interruptlink2\n", table.ilink2); |
| 344 | 291 | IWL_ERR(fwrt, "0x%08X | rcm data1\n", table.data1); |
| 345 | 292 | IWL_ERR(fwrt, "0x%08X | rcm data2\n", table.data2); |
| 346 | 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 | 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 | 103 | IWL_UCODE_TLV_D3_KEK_KCK_ADDR = 67, |
| 104 | 104 | IWL_UCODE_TLV_CURRENT_PC = 68, |
| 105 | 105 | IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72, |
| 106 | + IWL_UCODE_TLV_CMD_BIOS_TABLE = 73, | |
| 106 | 107 | |
| 107 | 108 | /* contains sub-sections like PNVM file does (did) */ |
| 108 | 109 | IWL_UCODE_TLV_PNVM_DATA = 74, |
| @@ -1040,6 +1041,20 @@ struct iwl_fw_cmd_version { · 931 unmodified lines | ||
| 1040 | 1041 | u8 notif_ver; |
| 1041 | 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 | 1058 | struct iwl_fw_tcm_error_addr { |
| 1044 | 1059 | __le32 addr; |
| 1045 | 1060 | }; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */ |
| @@ -1,11 +1,41 @@ | ||
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
| 2 | 2 | /* |
| 3 | 3 | * Copyright(c) 2019 - 2021 Intel Corporation |
| 4 | − * Copyright(c) 2024 Intel Corporation | |
| 4 | + * Copyright(c) 2024 - 2025 Intel Corporation | |
| 5 | 5 | */ |
| 6 | 6 | #include <fw/api/commands.h> |
| 7 | 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 | 39 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def) |
| 10 | 40 | { |
| 11 | 41 | const struct iwl_fw_cmd_version *entry; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/types.h> |
| 10 | 10 | |
| 11 | 11 | #include "api/dbg-tlv.h" |
| 12 | +#include "api/nvm-reg.h" | |
| 12 | 13 | |
| 13 | 14 | #include "file.h" |
| 14 | 15 | #include "error-dump.h" |
| @@ -57,6 +58,9 @@ struct iwl_ucode_capabilities { · 42 unmodified lines | ||
| 57 | 58 | |
| 58 | 59 | const struct iwl_fw_cmd_version *cmd_versions; |
| 59 | 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 | 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 | 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 | 285 | u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def); |
| 278 | 286 | |
| 279 | 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 | 241 | int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; |
| 242 | 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 | 248 | for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { |
| 245 | 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 | 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 | 307 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) |
| 430 | 308 | { |
| 431 | 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 | 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 | 342 | bool iwl_is_tas_approved(void) |
| 444 | 343 | { |
| 445 | 344 | return dmi_check_system(dmi_tas_approved_list); |
| @@ -21,10 +21,11 @@ · 20 unmodified lines | ||
| 21 | 21 | */ |
| 22 | 22 | #define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 |
| 23 | 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 | 27 | #define BIOS_GEO_NUM_CHAINS 2 |
| 27 | −#define BIOS_GEO_MAX_NUM_BANDS 3 | |
| 28 | +#define BIOS_GEO_MAX_NUM_BANDS 4 | |
| 28 | 29 | #define BIOS_GEO_MAX_PROFILE_NUM 8 |
| 29 | 30 | #define BIOS_GEO_MIN_PROFILE_NUM 3 |
| 30 | 31 | |
| @@ -100,7 +101,7 @@ struct iwl_geo_profile { · 69 unmodified lines | ||
| 100 | 101 | |
| 101 | 102 | /* Same thing as with SAR, all revisions fit in revision 2 */ |
| 102 | 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 | 107 | struct iwl_tas_data { |
| @@ -180,6 +181,9 @@ enum iwl_dsm_masks_reg { · 73 unmodified lines | ||
| 180 | 181 | |
| 181 | 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 | 187 | bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); |
| 184 | 188 | |
| 185 | 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 | 194 | __le16 *per_chain, u32 n_tables, u32 n_subbands, |
| 191 | 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 | 197 | bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); |
| 198 | 198 | |
| 199 | 199 | bool iwl_is_tas_approved(void); |
| @@ -106,13 +106,14 @@ struct iwl_txf_iter_data { · 105 unmodified lines | ||
| 106 | 106 | * @cur_fw_img: current firmware image, must be maintained by |
| 107 | 107 | * the driver by calling &iwl_fw_set_current_image() |
| 108 | 108 | * @dump: debug dump data |
| 109 | − * @uats_table: AP type table | |
| 110 | − * @uats_valid: is AP type table valid | |
| 109 | + * @ap_type_cmd: AP type tables (for enablement on 6 GHz) | |
| 110 | + * @ap_type_cmd_valid: if &ap_type_cmd is valid | |
| 111 | 111 | * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: |
| 112 | 112 | * 0: Unlocked, 1 and 2: Locked. |
| 113 | 113 | * Only read the UEFI variables if locked. |
| 114 | 114 | * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables |
| 115 | 115 | * @geo_profiles: geographic profiles as read from WGDS BIOS table |
| 116 | + * @geo_bios_source: see &enum bios_source | |
| 116 | 117 | * @phy_filters: specific phy filters as read from WPFC BIOS table |
| 117 | 118 | * @ppag_bios_rev: PPAG BIOS revision |
| 118 | 119 | * @ppag_bios_source: see &enum bios_source |
| @@ -204,6 +205,7 @@ struct iwl_fw_runtime { · 85 unmodified lines | ||
| 204 | 205 | u8 sar_chain_b_profile; |
| 205 | 206 | u8 reduced_power_flags; |
| 206 | 207 | struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; |
| 208 | + enum bios_source geo_bios_source; | |
| 207 | 209 | u32 geo_rev; |
| 208 | 210 | u32 geo_num_profiles; |
| 209 | 211 | bool geo_enabled; |
| @@ -213,8 +215,8 @@ struct iwl_fw_runtime { · 3 unmodified lines | ||
| 213 | 215 | u8 ppag_bios_source; |
| 214 | 216 | struct iwl_sar_offset_mapping_cmd sgom_table; |
| 215 | 217 | bool sgom_enabled; |
| 216 | − struct iwl_mcc_allowed_ap_type_cmd uats_table; | |
| 217 | − bool uats_valid; | |
| 218 | + struct iwl_mcc_allowed_ap_type_cmd ap_type_cmd; | |
| 219 | + bool ap_type_cmd_valid; | |
| 218 | 220 | u8 uefi_tables_lock_status; |
| 219 | 221 | struct iwl_phy_specific_cfg phy_filters; |
| 220 | 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 | 402 | if (uats_data->revision != 1) |
| 403 | 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 | 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 | 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 | 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 | 462 | static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, |
| 433 | − struct uefi_sar_profile *uefi_sar_prof, | |
| 434 | − u8 prof_index, bool enabled) | |
| 463 | + const u8 *vals, u8 prof_index, | |
| 464 | + u8 num_subbands, bool enabled) | |
| 435 | 465 | { |
| 436 | − memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, | |
| 437 | − sizeof(struct uefi_sar_profile)); | |
| 466 | + struct iwl_sar_profile *sar_prof = &fwrt->sar_profiles[prof_index]; | |
| 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 | 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 | 491 | int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) |
| 443 | 492 | { |
| 444 | 493 | struct uefi_cnv_var_wrds *data; |
| 494 | + unsigned long size; | |
| 495 | + unsigned long expected_size; | |
| 496 | + int num_subbands; | |
| 445 | 497 | int ret = 0; |
| 446 | 498 | |
| 447 | 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 | 504 | if (IS_ERR(data)) |
| 450 | 505 | return -EINVAL; |
| 451 | 506 | |
| 452 | − if (data->revision != IWL_UEFI_WRDS_REVISION) { | |
| 453 | − ret = -EINVAL; | |
| 454 | − IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", | |
| 507 | + switch (data->revision) { | |
| 508 | + case 2: | |
| 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 | 519 | data->revision); |
| 520 | + ret = -EINVAL; | |
| 521 | + goto out; | |
| 522 | + } | |
| 523 | + | |
| 524 | + if (size != expected_size) { | |
| 525 | + ret = -EINVAL; | |
| 456 | 526 | goto out; |
| 457 | 527 | } |
| 458 | 528 | |
| 459 | 529 | /* The profile from WRDS is officially profile 1, but goes |
| 460 | 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 | 534 | out: |
| 464 | 535 | kfree(data); |
| 465 | 536 | return ret; |
| @@ -468,21 +539,40 @@ out: · 2 unmodified lines | ||
| 468 | 539 | int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) |
| 469 | 540 | { |
| 470 | 541 | struct uefi_cnv_var_ewrd *data; |
| 542 | + unsigned long expected_size; | |
| 471 | 543 | int i, ret = 0; |
| 544 | + unsigned long size; | |
| 545 | + int num_subbands; | |
| 546 | + int profile_size; | |
| 472 | 547 | |
| 473 | 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 | 552 | if (IS_ERR(data)) |
| 476 | 553 | return -EINVAL; |
| 477 | 554 | |
| 478 | − if (data->revision != IWL_UEFI_EWRD_REVISION) { | |
| 479 | − ret = -EINVAL; | |
| 480 | − IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", | |
| 555 | + switch (data->revision) { | |
| 556 | + case 2: | |
| 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 | 569 | data->revision); |
| 570 | + ret = -EINVAL; | |
| 482 | 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 | 576 | ret = -EINVAL; |
| 487 | 577 | goto out; |
| 488 | 578 | } |
| @@ -492,8 +582,8 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) · 3 unmodified lines | ||
| 492 | 582 | * save them in sar_profiles[1-3] (because we don't |
| 493 | 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, | |
| 496 | − data->mode); | |
| 585 | + iwl_uefi_set_sar_profile(fwrt, &data->vals[i * profile_size], | |
| 586 | + i + 1, num_subbands, data->mode); | |
| 497 | 587 | |
| 498 | 588 | out: |
| 499 | 589 | kfree(data); |
| @@ -503,20 +593,39 @@ out: · 3 unmodified lines | ||
| 503 | 593 | int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) |
| 504 | 594 | { |
| 505 | 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 | 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 | 605 | if (IS_ERR(data)) |
| 511 | 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 | 618 | ret = -EINVAL; |
| 515 | 619 | IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", |
| 516 | 620 | data->revision); |
| 517 | 621 | goto out; |
| 518 | 622 | } |
| 519 | 623 | |
| 624 | + if (size != expected_size) { | |
| 625 | + ret = -EINVAL; | |
| 626 | + goto out; | |
| 627 | + } | |
| 628 | + | |
| 520 | 629 | if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || |
| 521 | 630 | data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { |
| 522 | 631 | ret = -EINVAL; |
| @@ -525,10 +634,31 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) · 2 unmodified lines | ||
| 525 | 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 | 646 | fwrt->geo_rev = data->revision; |
| 529 | − for (i = 0; i < data->num_profiles; i++) | |
| 530 | − memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], | |
| 531 | − sizeof(struct iwl_geo_profile)); | |
| 647 | + fwrt->geo_bios_source = BIOS_SOURCE_UEFI; | |
| 648 | + profile_size = 3 * n_subbands; | |
| 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 | 663 | fwrt->geo_num_profiles = data->num_profiles; |
| 534 | 664 | fwrt->geo_enabled = true; |
| @@ -540,28 +670,66 @@ out: · 5 unmodified lines | ||
| 540 | 670 | int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) |
| 541 | 671 | { |
| 542 | 672 | struct uefi_cnv_var_ppag *data; |
| 673 | + int n_subbands; | |
| 674 | + u32 valid_rev; | |
| 543 | 675 | int ret = 0; |
| 544 | 676 | |
| 545 | 677 | data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, |
| 546 | − "PPAG", sizeof(*data), NULL); | |
| 547 | − if (IS_ERR(data)) | |
| 548 | − return -EINVAL; | |
| 678 | + "PPAG", UEFI_PPAG_DATA_SIZE_V5, | |
| 679 | + NULL); | |
| 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 || | |
| 551 | − data->revision > IWL_UEFI_MAX_PPAG_REV) { | |
| 700 | + return -EINVAL; | |
| 701 | + | |
| 702 | +parse_table: | |
| 703 | + if (!(BIT(data->revision) & valid_rev)) { | |
| 552 | 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 | 707 | data->revision); |
| 555 | 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 | 722 | fwrt->ppag_bios_rev = data->revision; |
| 559 | 723 | fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, |
| 560 | 724 | fwrt->ppag_bios_rev); |
| 561 | 725 | |
| 562 | − BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); | |
| 563 | − memcpy(&fwrt->ppag_chains, &data->ppag_chains, | |
| 564 | − sizeof(data->ppag_chains)); | |
| 726 | + for (int chain = 0; chain < UEFI_PPAG_NUM_CHAINS; chain++) { | |
| 727 | + for (int subband = 0; subband < n_subbands; subband++) | |
| 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 | 733 | fwrt->ppag_bios_source = BIOS_SOURCE_UEFI; |
| 566 | 734 | out: |
| 567 | 735 | kfree(data); |
| @@ -25,16 +25,12 @@ · 24 unmodified lines | ||
| 25 | 25 | #define IWL_UEFI_PUNCTURING_NAME L"UefiCnvWlanPuncturing" |
| 26 | 26 | #define IWL_UEFI_DSBR_NAME L"UefiCnvCommonDSBR" |
| 27 | 27 | #define IWL_UEFI_WPFC_NAME L"WPFC" |
| 28 | +#define IWL_UEFI_UNEB_NAME L"CnvUefiWlanUNEB" | |
| 28 | 29 | |
| 29 | 30 | |
| 30 | 31 | #define IWL_SGOM_MAP_SIZE 339 |
| 31 | 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 | 34 | #define IWL_UEFI_MIN_WTAS_REVISION 1 |
| 39 | 35 | #define IWL_UEFI_MAX_WTAS_REVISION 2 |
| 40 | 36 | #define IWL_UEFI_SPLC_REVISION 0 |
| @@ -63,6 +59,9 @@ struct uefi_cnv_wlan_uats_data { · 22 unmodified lines | ||
| 63 | 59 | u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; |
| 64 | 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 | 65 | struct uefi_cnv_common_step_data { |
| 67 | 66 | u8 revision; |
| 68 | 67 | u8 step_mode; |
| @@ -72,68 +71,135 @@ struct uefi_cnv_common_step_data { · 3 unmodified lines | ||
| 72 | 71 | u8 radio2; |
| 73 | 72 | } __packed; |
| 74 | 73 | |
| 75 | −/* | |
| 76 | − * struct uefi_sar_profile - a SAR profile as defined in UEFI | |
| 77 | − * | |
| 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; | |
| 74 | +#define UEFI_PPAG_SUB_BANDS_NUM_REV4 11 | |
| 75 | +#define UEFI_PPAG_SUB_BANDS_NUM_REV5 12 | |
| 76 | +#define UEFI_PPAG_NUM_CHAINS 2 | |
| 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 | 87 | * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI |
| 86 | 88 | * |
| 87 | 89 | * @revision: the revision of the table |
| 88 | 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 | 98 | struct uefi_cnv_var_wrds { |
| 92 | 99 | u8 revision; |
| 93 | 100 | u32 mode; |
| 94 | − struct uefi_sar_profile sar_profile; | |
| 101 | + u8 vals[]; | |
| 95 | 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 | 121 | * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI |
| 99 | 122 | * @revision: the revision of the table |
| 100 | 123 | * @mode: is WRDS enbaled/disabled |
| 101 | 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 | 130 | struct uefi_cnv_var_ewrd { |
| 105 | 131 | u8 revision; |
| 106 | 132 | u32 mode; |
| 107 | 133 | u32 num_profiles; |
| 108 | − struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1]; | |
| 134 | + u8 vals[]; | |
| 109 | 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 | 146 | * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI |
| 113 | 147 | * @revision: the revision of the table |
| 114 | 148 | * @num_profiles: the number of geo profiles we have in the table. |
| 115 | 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 | 156 | struct uefi_cnv_var_wgds { |
| 119 | 157 | u8 revision; |
| 120 | 158 | u8 num_profiles; |
| 121 | − struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; | |
| 159 | + u8 vals[]; | |
| 122 | 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 | 178 | * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI |
| 126 | 179 | * @revision: the revision of the table |
| 127 | 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 | 188 | struct uefi_cnv_var_ppag { |
| 131 | 189 | u8 revision; |
| 132 | 190 | u32 ppag_modes; |
| 133 | − struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; | |
| 191 | + s8 vals[]; | |
| 134 | 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 | 203 | * @revision: the revision of the table |
| 138 | 204 | * @tas_selection: different options of TAS enablement. |
| 139 | 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 | 212 | u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; |
| 147 | 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 | 217 | * @revision: the revision of the table |
| 151 | 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 | 222 | u32 default_pwr_limit; |
| 156 | 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 | 227 | * @revision: the revision of the table |
| 160 | 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 | 232 | u32 mcc; |
| 165 | 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 | 237 | * @revision: the revision of the table |
| 169 | 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 | 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 | 249 | * @revision: the revision of the table |
| 180 | 250 | * @functions: payload of the different DSM functions |
| 181 | 251 | */ |
| @@ -185,7 +255,9 @@ struct uefi_cnv_var_general_cfg { · 3 unmodified lines | ||
| 185 | 255 | } __packed; |
| 186 | 256 | |
| 187 | 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 | 261 | * in UEFI |
| 190 | 262 | * @revision: the revision of the table |
| 191 | 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 | 346 | void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); |
| 275 | 347 | void iwl_uefi_get_uats_table(struct iwl_trans *trans, |
| 276 | 348 | struct iwl_fw_runtime *fwrt); |
| 349 | +void iwl_uefi_get_uneb_table(struct iwl_trans *trans, | |
| 350 | + struct iwl_fw_runtime *fwrt); | |
| 277 | 351 | int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt); |
| 278 | 352 | int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value); |
| 279 | 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 | 455 | static inline |
| 377 | 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 | 85 | #define IWL_WATCHDOG_DISABLED 0 |
| 86 | 86 | #define IWL_DEF_WD_TIMEOUT 2500 |
| 87 | 87 | #define IWL_LONG_WD_TIMEOUT 10000 |
| 88 | −#define IWL_MAX_WD_TIMEOUT 120000 | |
| 89 | 88 | |
| 90 | 89 | #define IWL_DEFAULT_MAX_TX_POWER 22 |
| 91 | 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 | 133 | kfree(drv->fw.dbg.mem_tlv); |
| 134 | 134 | kfree(drv->fw.iml); |
| 135 | 135 | kfree(drv->fw.ucode_capa.cmd_versions); |
| 136 | + kfree(drv->fw.ucode_capa.cmd_bios_tables); | |
| 136 | 137 | kfree(drv->fw.phy_integration_ver); |
| 137 | 138 | kfree(drv->trans->dbg.pc_data); |
| 138 | 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 | 1315 | if (tlv_len != sizeof(u32)) |
| 1315 | 1316 | goto invalid_tlv_len; |
| 1316 | 1317 | if (le32_to_cpup((const __le32 *)tlv_data) > |
| 1317 | − IWL_FW_MAX_LINK_ID + 1) { | |
| 1318 | + IWL_FW_MAX_LINKS) { | |
| 1318 | 1319 | IWL_ERR(drv, |
| 1319 | 1320 | "%d is an invalid number of links\n", |
| 1320 | 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 | 1427 | return -ENOMEM; |
| 1427 | 1428 | drv->fw.pnvm_size = tlv_len; |
| 1428 | 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 | 1450 | default: |
| 1430 | 1451 | IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); |
| 1431 | 1452 | break; |
| @@ -23,6 +23,8 @@ · 22 unmodified lines | ||
| 23 | 23 | #include "fw/api/commands.h" |
| 24 | 24 | #include "fw/api/cmdhdr.h" |
| 25 | 25 | #include "fw/img.h" |
| 26 | +#include "fw/dbg.h" | |
| 27 | + | |
| 26 | 28 | #include "mei/iwl-mei.h" |
| 27 | 29 | |
| 28 | 30 | /* NVM offsets (in words) definitions */ |
| @@ -1702,6 +1704,11 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans, · 1673 unmodified lines | ||
| 1702 | 1704 | band); |
| 1703 | 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 | 1712 | if (!(ch_flags & NVM_CHANNEL_VALID)) { |
| 1706 | 1713 | iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, |
| 1707 | 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 | 2038 | if (empty_otp) |
| 2032 | 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 | 2042 | if (!nvm) { |
| 2036 | 2043 | ret = -ENOMEM; |
| 2037 | 2044 | goto out; |
| @@ -138,7 +138,7 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) · 137 unmodified lines | ||
| 138 | 138 | IWL_RESET_MODE_FUNC_RESET, |
| 139 | 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 | 142 | IWL_RESET_MODE_SW_RESET, |
| 143 | 143 | IWL_RESET_MODE_REPROBE, |
| 144 | 144 | IWL_RESET_MODE_REPROBE, |
| @@ -159,14 +159,14 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans) · 14 unmodified lines | ||
| 159 | 159 | |
| 160 | 160 | if (trans->request_top_reset) { |
| 161 | 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 | 163 | return IWL_RESET_MODE_TOP_RESET; |
| 164 | 164 | return IWL_RESET_MODE_PROD_RESET; |
| 165 | 165 | } |
| 166 | 166 | |
| 167 | − if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { | |
| 168 | − escalation_list = escalation_list_sc; | |
| 169 | − escalation_list_size = ARRAY_SIZE(escalation_list_sc); | |
| 167 | + if (iwl_trans_is_top_reset_supported(trans)) { | |
| 168 | + escalation_list = escalation_list_top; | |
| 169 | + escalation_list_size = ARRAY_SIZE(escalation_list_top); | |
| 170 | 170 | } else { |
| 171 | 171 | escalation_list = escalation_list_old; |
| 172 | 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 | 1089 | trans->restart.during_reset = test_bit(STATUS_IN_SW_RESET, |
| 1090 | 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 | 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 | 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 | 1279 | #endif /* __iwl_trans_h__ */ |
| @@ -36,7 +36,6 @@ · 35 unmodified lines | ||
| 36 | 36 | #define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8 |
| 37 | 37 | |
| 38 | 38 | #define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30 |
| 39 | −#define IWL_MLD_SCAN_EXPIRE_TIME_SEC 20 | |
| 40 | 39 | |
| 41 | 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 | 513 | return ret; |
| 514 | 514 | |
| 515 | 515 | iwl_mld_init_tas(mld); |
| 516 | − iwl_mld_init_uats(mld); | |
| 516 | + iwl_mld_init_ap_type_tables(mld); | |
| 517 | 517 | |
| 518 | 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 | 61 | static int iwl_mld_send_mac_cmd(struct iwl_mld *mld, |
| 62 | 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 | 66 | int ret; |
| 65 | 67 | |
| 66 | 68 | lockdep_assert_wiphy(mld->wiphy); |
| 67 | 69 | |
| 68 | − ret = iwl_mld_send_cmd_pdu(mld, | |
| 69 | − WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), | |
| 70 | − cmd); | |
| 70 | + if (iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0) < 4) { | |
| 71 | + if (WARN_ON(cmd->mac_type == cpu_to_le32(FW_MAC_TYPE_NAN))) | |
| 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 | 78 | if (ret) |
| 72 | 79 | IWL_ERR(mld, "Failed to send MAC_CONFIG_CMD ret = %d\n", ret); |
| 73 | 80 | |
| 74 | 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 | 86 | switch (vif->type) { |
| 80 | 87 | case NL80211_IFTYPE_STATION: |
| @@ -386,7 +393,7 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy, · 305 unmodified lines | ||
| 386 | 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 | 398 | /* Constructor function for struct iwl_mld_vif */ |
| 392 | 399 | static void |
| @@ -397,6 +404,7 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) · 4 unmodified lines | ||
| 397 | 404 | lockdep_assert_wiphy(mld->wiphy); |
| 398 | 405 | |
| 399 | 406 | mld_vif->mld = mld; |
| 407 | + mld_vif->fw_id = IWL_MLD_INVALID_FW_ID; | |
| 400 | 408 | mld_vif->roc_activity = ROC_NUM_ACTIVITIES; |
| 401 | 409 | |
| 402 | 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 | 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 | 459 | iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); |
| 448 | 460 | |
| 449 | 461 | if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) |
| @@ -1,6 +1,6 @@ | ||
| 1 | 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 | #ifndef __iwl_mld_iface_h__ |
| 6 | 6 | #define __iwl_mld_iface_h__ |
| @@ -33,6 +33,7 @@ enum iwl_mld_cca_40mhz_wa_status { · 26 unmodified lines | ||
| 33 | 33 | * there is an indication that a non-BSS interface is to be added. |
| 34 | 34 | * @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile |
| 35 | 35 | * @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR. |
| 36 | + * @IWL_MLD_EMLSR_BLOCKED_TDLS: TDLS connection is preventing EMLSR. | |
| 36 | 37 | */ |
| 37 | 38 | enum iwl_mld_emlsr_blocked { |
| 38 | 39 | IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1, |
| @@ -42,6 +43,7 @@ enum iwl_mld_emlsr_blocked { · 3 unmodified lines | ||
| 42 | 43 | IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10, |
| 43 | 44 | IWL_MLD_EMLSR_BLOCKED_TPT = 0x20, |
| 44 | 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 | 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 | 215 | #define iwl_mld_link_dereference_check(mld_vif, link_id) \ |
| 205 | 216 | rcu_dereference_check((mld_vif)->link[link_id], \ |
| 206 | 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 | 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 | 233 | /* Cleanup function for struct iwl_mld_vif, will be called in restart */ |
| 225 | 234 | void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); |
| 226 | 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 | 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 | 442 | /* Constructor function for struct iwl_mld_link */ |
| 443 | 443 | static int |
| @@ -40,6 +40,7 @@ struct iwl_probe_resp_data { · 39 unmodified lines | ||
| 40 | 40 | * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. |
| 41 | 41 | * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. |
| 42 | 42 | * @mon_sta: station used for TX injection in monitor interface. |
| 43 | + * @last_cqm_rssi_event: rssi of the last cqm rssi event | |
| 43 | 44 | * @average_beacon_energy: average beacon energy for beacons received during |
| 44 | 45 | * client connections |
| 45 | 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 | 67 | struct iwl_mld_int_sta bcast_sta; |
| 67 | 68 | struct iwl_mld_int_sta mcast_sta; |
| 68 | 69 | struct iwl_mld_int_sta mon_sta; |
| 70 | + int last_cqm_rssi_event; | |
| 69 | 71 | |
| 70 | 72 | /* we can only have 2 GTK + 2 IGTK + 2 BIGTK active at a time */ |
| 71 | 73 | struct ieee80211_key_conf *ap_early_keys[6]; |
| @@ -1,6 +1,6 @@ | ||
| 1 | 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 | #include "mld.h" |
| 6 | 6 | #include "iface.h" |
| @@ -77,9 +77,12 @@ static void iwl_mld_low_latency_iter(void *_data, u8 *mac, · 70 unmodified lines | ||
| 77 | 77 | bool prev = mld_vif->low_latency_causes & LOW_LATENCY_TRAFFIC; |
| 78 | 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 | 81 | return; |
| 82 | 82 | |
| 83 | + BUILD_BUG_ON(ARRAY_SIZE(mld->fw_id_to_vif) != | |
| 84 | + ARRAY_SIZE(mld->low_latency.result)); | |
| 85 | + | |
| 83 | 86 | low_latency = mld->low_latency.result[mld_vif->fw_id]; |
| 84 | 87 | |
| 85 | 88 | if (prev != low_latency) |
| @@ -272,8 +275,10 @@ void iwl_mld_low_latency_update_counters(struct iwl_mld *mld, · 186 unmodified lines | ||
| 272 | 275 | if (WARN_ON_ONCE(!mld->low_latency.pkts_counters)) |
| 273 | 276 | return; |
| 274 | 277 | |
| 275 | − if (WARN_ON_ONCE(fw_id >= ARRAY_SIZE(counters->vo_vi) || | |
| 276 | − queue >= mld->trans->info.num_rxqs)) | |
| 278 | + if (!iwl_mld_vif_fw_id_valid(mld_vif)) | |
| 279 | + return; | |
| 280 | + | |
| 281 | + if (WARN_ON_ONCE(queue >= mld->trans->info.num_rxqs)) | |
| 277 | 282 | return; |
| 278 | 283 | |
| 279 | 284 | if (mld->low_latency.stopped) |
| @@ -754,6 +754,30 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, · 753 unmodified lines | ||
| 754 | 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 | 781 | struct iwl_mld_mc_iter_data { |
| 758 | 782 | struct iwl_mld *mld; |
| 759 | 783 | int port_id; |
| @@ -1124,6 +1148,8 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, · 364 unmodified lines | ||
| 1124 | 1148 | |
| 1125 | 1149 | /* Now activate the link */ |
| 1126 | 1150 | if (iwl_mld_can_activate_link(mld, vif, link)) { |
| 1151 | + iwl_mld_tlc_update_phy(mld, vif, link); | |
| 1152 | + | |
| 1127 | 1153 | ret = iwl_mld_activate_link(mld, link); |
| 1128 | 1154 | if (ret) |
| 1129 | 1155 | goto err; |
| @@ -1185,6 +1211,8 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, · 55 unmodified lines | ||
| 1185 | 1211 | |
| 1186 | 1212 | RCU_INIT_POINTER(mld_link->chan_ctx, NULL); |
| 1187 | 1213 | |
| 1214 | + iwl_mld_tlc_update_phy(mld, vif, link); | |
| 1215 | + | |
| 1188 | 1216 | /* in the non-MLO case, remove/re-add the link to clean up FW state. |
| 1189 | 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 | 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 | 1759 | if (ret) |
| 1732 | 1760 | return ret; |
| 1733 | 1761 | |
| 1734 | − /* just added first TDLS STA, so disable PM */ | |
| 1735 | − if (sta->tdls && tdls_count == 0) | |
| 1762 | + /* just added first TDLS STA, so disable PM and block EMLSR */ | |
| 1763 | + if (sta->tdls && tdls_count == 0) { | |
| 1736 | 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 | 1775 | if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) |
| 1739 | 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 | 1907 | iwl_mld_remove_sta(mld, sta); |
| 1871 | 1908 | |
| 1872 | 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 | 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 | 1919 | } else { |
| 1877 | 1920 | return -EINVAL; |
| @@ -2716,6 +2759,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { · 838 unmodified lines | ||
| 2716 | 2759 | .get_antenna = iwl_mld_get_antenna, |
| 2717 | 2760 | .set_antenna = iwl_mld_set_antenna, |
| 2718 | 2761 | .add_interface = iwl_mld_mac80211_add_interface, |
| 2762 | + .change_interface = iwl_mld_mac80211_change_interface, | |
| 2719 | 2763 | .remove_interface = iwl_mld_mac80211_remove_interface, |
| 2720 | 2764 | .conf_tx = iwl_mld_mac80211_conf_tx, |
| 2721 | 2765 | .prepare_multicast = iwl_mld_mac80211_prepare_multicast, |
| @@ -205,7 +205,7 @@ · 204 unmodified lines | ||
| 205 | 205 | struct iwl_mld { |
| 206 | 206 | /* Add here fields that need clean up on restart */ |
| 207 | 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 | 209 | struct ieee80211_vif __rcu *fw_id_to_vif[NUM_MAC_INDEX_DRIVER]; |
| 210 | 210 | struct ieee80211_txq __rcu *fw_id_to_txq[IWL_MAX_TVQM_QUEUES]; |
| 211 | 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 | 530 | #define IWL_MLD_INVALID_FW_ID 0xff |
| 531 | 531 | |
| 532 | 532 | #define IWL_MLD_ALLOC_FN(_type, _mac80211_type) \ |
| 533 | −static int \ | |
| 533 | +int \ | |
| 534 | 534 | iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld, \ |
| 535 | − u8 *fw_id, \ | |
| 535 | + u8 *fw_id, \ | |
| 536 | 536 | struct ieee80211_##_mac80211_type *mac80211_ptr) \ |
| 537 | 537 | { \ |
| 538 | 538 | u8 rand = IWL_MLD_DIS_RANDOM_FW_ID ? 0 : get_random_u8(); \ |
| @@ -13,7 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | HOW(NON_BSS) \ |
| 14 | 14 | HOW(TMP_NON_BSS) \ |
| 15 | 15 | HOW(TPT) \ |
| 16 | − HOW(NAN) | |
| 16 | + HOW(NAN) \ | |
| 17 | + HOW(TDLS) | |
| 17 | 18 | |
| 18 | 19 | static const char * |
| 19 | 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 | 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 | 115 | /* Exit reasons that can cause longer EMLSR prevention */ |
| 116 | 116 | #define IWL_MLD_PREVENT_EMLSR_REASONS (IWL_MLD_EMLSR_EXIT_MISSED_BEACON | \ |
| @@ -2,7 +2,8 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Copyright (C) 2025 Intel Corporation |
| 4 | 4 | */ |
| 5 | − | |
| 5 | +#ifndef __iwl_mld_nan_h__ | |
| 6 | +#define __iwl_mld_nan_h__ | |
| 6 | 7 | #include <net/cfg80211.h> |
| 7 | 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 | 27 | bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, |
| 27 | 28 | struct iwl_rx_packet *pkt, |
| 28 | 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 | 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 | 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 | 405 | .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), |
| 406 | 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 | 413 | if (WARN_ON(!mld_link)) |
| 411 | 414 | return -ENODEV; |
| @@ -301,10 +301,12 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) · 300 unmodified lines | ||
| 301 | 301 | mld->ptp_data.ptp_clock = |
| 302 | 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 | 305 | IWL_ERR(mld, "Failed to register PHC clock (%ld)\n", |
| 306 | 306 | PTR_ERR(mld->ptp_data.ptp_clock)); |
| 307 | 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 | 310 | } else { |
| 309 | 311 | IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n", |
| 310 | 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 | 66 | iwl_uefi_get_uats_table(mld->trans, &mld->fwrt); |
| 67 | + iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt); | |
| 67 | 68 | |
| 68 | 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 | 74 | u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); |
| 74 | 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 | 77 | union iwl_geo_tx_power_profiles_cmd cmd = { |
| 77 | 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 | 83 | int ret; |
| 81 | 84 | |
| 82 | − ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v5.table[0][0], | |
| 83 | − ARRAY_SIZE(cmd.v5.table[0]), | |
| 84 | − BIOS_GEO_MAX_PROFILE_NUM); | |
| 85 | + switch (cmd_ver) { | |
| 86 | + case 5: | |
| 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 | 107 | /* It is a valid scenario to not support SAR, or miss wgds table, |
| 87 | 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 | 110 | if (ret) |
| 90 | 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 | 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 | 118 | struct iwl_dev_tx_power_cmd cmd = { |
| 99 | 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 | 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 | 143 | /* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */ |
| 105 | − ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v10.per_chain[0][0][0], | |
| 106 | − IWL_NUM_CHAIN_TABLES, IWL_NUM_SUB_BANDS_V2, | |
| 144 | + /* v10 and v11 have the same position for per_chain */ | |
| 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 | 149 | prof_a, prof_b); |
| 108 | 150 | /* return on error or if the profile is disabled (positive number) */ |
| 109 | 151 | if (ret) |
| 110 | 152 | return ret; |
| 111 | 153 | |
| 112 | − return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, | |
| 113 | − sizeof(cmd.common) + sizeof(cmd.v10)); | |
| 154 | + return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd, cmd_size); | |
| 114 | 155 | } |
| 115 | 156 | |
| 116 | 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 | 207 | struct iwl_fw_runtime *fwrt = &mld->fwrt; |
| 167 | 208 | union iwl_ppag_table_cmd cmd = { |
| 168 | − .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, | |
| 169 | − .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev, | |
| 170 | − .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), | |
| 209 | + /* v7 and v8 have the same layout for the ppag_config_info */ | |
| 210 | + .v8.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, | |
| 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 | 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 | 232 | IWL_DEBUG_RADIO(fwrt, |
| 175 | 233 | "PPAG MODE bits going to be sent: %d\n", |
| 176 | 234 | fwrt->ppag_flags); |
| 177 | 235 | |
| 178 | − for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) { | |
| 179 | − for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) { | |
| 180 | − cmd.v7.gain[chain][subband] = | |
| 181 | − fwrt->ppag_chains[chain].subbands[subband]; | |
| 182 | − IWL_DEBUG_RADIO(fwrt, | |
| 183 | − "PPAG table: chain[%d] band[%d]: gain = %d\n", | |
| 184 | − chain, subband, cmd.v7.gain[chain][subband]); | |
| 236 | + /* Since ver 7 will be deprecated at some point, don't bother making | |
| 237 | + * this code generic for both ver 7 and ver 8: duplicate the code. | |
| 238 | + */ | |
| 239 | + if (cmd_ver == 7) { | |
| 240 | + for (int chain = 0; chain < ARRAY_SIZE(cmd.v7.gain); chain++) { | |
| 241 | + for (int subband = 0; | |
| 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 | 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, | |
| 190 | − PER_PLATFORM_ANT_GAIN_CMD), | |
| 191 | − &cmd, sizeof(cmd.v7)); | |
| 288 | + ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, cmd_len); | |
| 192 | 289 | if (ret < 0) |
| 193 | 290 | IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", |
| 194 | 291 | ret); |
| @@ -352,21 +449,42 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) · 157 unmodified lines | ||
| 352 | 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 | 454 | int ret; |
| 358 | 455 | struct iwl_host_cmd cmd = { |
| 359 | 456 | .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, |
| 360 | 457 | MCC_ALLOWED_AP_TYPE_CMD), |
| 361 | − .data[0] = &mld->fwrt.uats_table, | |
| 362 | − .len[0] = sizeof(mld->fwrt.uats_table), | |
| 458 | + .data[0] = &mld->fwrt.ap_type_cmd, | |
| 459 | + .len[0] = sizeof(mld->fwrt.ap_type_cmd), | |
| 363 | 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 | 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 | 488 | if (ret) |
| 371 | 489 | IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", |
| 372 | 490 | ret); |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | void iwl_mld_get_bios_tables(struct iwl_mld *mld); |
| 11 | 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 | 13 | void iwl_mld_init_tas(struct iwl_mld *mld); |
| 14 | 14 | |
| 15 | 15 | int iwl_mld_init_ppag(struct iwl_mld *mld); |
| @@ -1,6 +1,6 @@ | ||
| 1 | 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 | 6 | #include <net/mac80211.h> |
| @@ -791,6 +791,9 @@ static void * · 784 unmodified lines | ||
| 791 | 791 | iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) |
| 792 | 792 | { |
| 793 | 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 | 798 | tlv = skb_put(skb, sizeof(*tlv)); |
| 796 | 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 | 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 | 1240 | switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { |
| 1240 | 1241 | case 0: |
| 1241 | 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 | 1330 | static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, |
| 1330 | 1331 | struct sk_buff *skb) |
| 1331 | 1332 | { |
| 1332 | − struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | |
| 1333 | 1333 | struct ieee80211_radiotap_vendor_content *radiotap; |
| 1334 | 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 | 1353 | /* fill the data now */ |
| 1354 | 1354 | memcpy(radiotap->data, &mld->monitor.cur_aid, |
| 1355 | 1355 | sizeof(mld->monitor.cur_aid)); |
| 1356 | − | |
| 1357 | − rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | |
| 1358 | 1356 | } |
| 1359 | 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 | 1360 | struct sk_buff *skb, |
| 1363 | 1361 | struct iwl_rx_phy_air_sniffer_ntfy *ntfy) |
| 1364 | 1362 | { |
| 1365 | − struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | |
| 1366 | 1363 | struct ieee80211_radiotap_vendor_content *radiotap; |
| 1367 | 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 | 1380 | /* fill the data now */ |
| 1384 | 1381 | memcpy(radiotap->data, ntfy, vendor_data_len); |
| 1385 | − | |
| 1386 | − rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; | |
| 1387 | 1382 | } |
| 1388 | 1383 | |
| 1389 | 1384 | static void |
| @@ -1407,6 +1402,7 @@ static void iwl_mld_set_rx_rate(struct iwl_mld *mld, · 17 unmodified lines | ||
| 1407 | 1402 | u32 rate_n_flags = phy_data->rate_n_flags; |
| 1408 | 1403 | u8 stbc = u32_get_bits(rate_n_flags, RATE_MCS_STBC_MSK); |
| 1409 | 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 | 1406 | bool is_sgi = rate_n_flags & RATE_MCS_SGI_MSK; |
| 1411 | 1407 | |
| 1412 | 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 | 1477 | rx_status->encoding = RX_ENC_EHT; |
| 1482 | 1478 | iwl_mld_set_rx_nonlegacy_rate_info(rate_n_flags, rx_status); |
| 1483 | 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 | 1486 | default: |
| 1485 | 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 | 2206 | ret = wait_event_timeout(mld->rxq_sync.waitq, |
| 2205 | 2207 | READ_ONCE(mld->rxq_sync.state) == 0, |
| 2206 | 2208 | SYNC_RX_QUEUE_TIMEOUT); |
| 2207 | − WARN_ONCE(!ret, "RXQ sync failed: state=0x%lx, cookie=%d\n", | |
| 2208 | − mld->rxq_sync.state, mld->rxq_sync.cookie); | |
| 2209 | + IWL_FW_CHECK(mld, !ret, | |
| 2210 | + "RXQ sync failed: state=0x%lx, cookie=%d\n", | |
| 2211 | + mld->rxq_sync.state, mld->rxq_sync.cookie); | |
| 2209 | 2212 | |
| 2210 | 2213 | out: |
| 2211 | 2214 | mld->rxq_sync.state = 0; |
| @@ -47,8 +47,6 @@ · 46 unmodified lines | ||
| 47 | 47 | /* adaptive dwell number of APs override mask for social channels */ |
| 48 | 48 | #define IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS_BIT BIT(21) |
| 49 | 49 | |
| 50 | −#define SCAN_TIMEOUT_MSEC (30000 * HZ) | |
| 51 | − | |
| 52 | 50 | /* minimal number of 2GHz and 5GHz channels in the regular scan request */ |
| 53 | 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 | 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 | 124 | struct iwl_mld_scan_respect_p2p_go_iter_data { |
| 120 | 125 | struct ieee80211_vif *current_vif; |
| 121 | 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 | 518 | static void |
| 514 | 519 | iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld, |
| 515 | − struct iwl_scan_general_params_v11 *gp, | |
| 516 | − struct iwl_mld_scan_params *params) | |
| 520 | + 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 | 524 | const struct iwl_mld_scan_timing_params *timing = |
| 519 | 525 | &scan_timing[params->type]; |
| 520 | 526 | |
| @@ -551,9 +557,10 @@ static void · 30 unmodified lines | ||
| 551 | 557 | iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, |
| 552 | 558 | struct iwl_mld_scan_params *params, |
| 553 | 559 | struct ieee80211_vif *vif, |
| 554 | − struct iwl_scan_general_params_v11 *gp, | |
| 560 | + struct iwl_scan_req_params_ptrs *scan_ptrs, | |
| 555 | 561 | enum iwl_mld_scan_status scan_status) |
| 556 | 562 | { |
| 563 | + struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params; | |
| 557 | 564 | u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, |
| 558 | 565 | scan_status); |
| 559 | 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 | 573 | gp->flags = cpu_to_le16(gen_flags); |
| 567 | 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 | 578 | if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) |
| 572 | 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 | 585 | static int |
| 579 | 586 | iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params, |
| 580 | − struct iwl_scan_umac_schedule *schedule, | |
| 581 | − __le16 *delay) | |
| 587 | + struct iwl_scan_req_params_ptrs *scan_ptrs) | |
| 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 | 593 | if (WARN_ON(!params->n_scan_plans || |
| 584 | 594 | params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) |
| 585 | 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 | 668 | static void |
| 659 | 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 | 672 | int j, idex_s = 0, idex_b = 0; |
| 663 | 673 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = |
| 664 | 674 | params->scan_6ghz_params; |
| 675 | + struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params; | |
| 665 | 676 | |
| 666 | 677 | for (j = 0; |
| 667 | 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 | 737 | static void |
| 727 | 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 | 740 | u32 *bitmap_ssid) |
| 730 | 741 | { |
| 742 | + struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params; | |
| 743 | + | |
| 731 | 744 | pp->preq = params->preq; |
| 732 | 745 | |
| 733 | 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 | 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 | 834 | static void |
| 822 | 835 | iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld, |
| 823 | 836 | struct ieee80211_channel **channels, |
| 824 | − struct iwl_scan_channel_params_v7 *cp, | |
| 837 | + struct iwl_scan_req_params_ptrs *scan_ptrs, | |
| 825 | 838 | int n_channels, u32 flags, |
| 826 | 839 | enum nl80211_iftype vif_type) |
| 827 | 840 | { |
| 841 | + struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; | |
| 842 | + | |
| 828 | 843 | for (int i = 0; i < n_channels; i++) { |
| 829 | 844 | enum nl80211_band band = channels[i]->band; |
| 830 | 845 | struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i]; |
| @@ -862,10 +877,11 @@ static u8 · 31 unmodified lines | ||
| 862 | 877 | iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld, |
| 863 | 878 | struct iwl_mld_scan_params *params, |
| 864 | 879 | u32 n_channels, |
| 865 | − struct iwl_scan_probe_params_v4 *pp, | |
| 866 | − struct iwl_scan_channel_params_v7 *cp, | |
| 880 | + struct iwl_scan_req_params_ptrs *scan_ptrs, | |
| 867 | 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 | 885 | struct cfg80211_scan_6ghz_params *scan_6ghz_params = |
| 870 | 886 | params->scan_6ghz_params; |
| 871 | 887 | u32 i; |
| @@ -1063,25 +1079,23 @@ static int · 191 unmodified lines | ||
| 1063 | 1079 | iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld, |
| 1064 | 1080 | struct iwl_mld_scan_params *params, |
| 1065 | 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; | |
| 1069 | − struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params; | |
| 1084 | + struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params; | |
| 1070 | 1085 | |
| 1071 | 1086 | /* Explicitly clear the flags since most of them are not |
| 1072 | 1087 | * relevant for 6 GHz scan. |
| 1073 | 1088 | */ |
| 1074 | − chan_p->flags = 0; | |
| 1075 | − chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params, | |
| 1076 | − params->n_channels, | |
| 1077 | − probe_p, chan_p, | |
| 1078 | − vif->type); | |
| 1079 | − if (!chan_p->count) | |
| 1089 | + cp->flags = 0; | |
| 1090 | + cp->count = iwl_mld_scan_cfg_channels_6g(mld, params, | |
| 1091 | + params->n_channels, | |
| 1092 | + scan_ptrs, vif->type); | |
| 1093 | + if (!cp->count) | |
| 1080 | 1094 | return -EINVAL; |
| 1081 | 1095 | |
| 1082 | 1096 | if (!params->n_ssids || |
| 1083 | 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 | 1100 | return 0; |
| 1087 | 1101 | } |
| @@ -1090,12 +1104,12 @@ static int · 2 unmodified lines | ||
| 1090 | 1104 | iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, |
| 1091 | 1105 | struct iwl_mld_scan_params *params, |
| 1092 | 1106 | struct ieee80211_vif *vif, |
| 1093 | − struct iwl_scan_req_params_v17 *scan_p, | |
| 1107 | + struct iwl_scan_req_params_ptrs *scan_ptrs, | |
| 1094 | 1108 | bool low_latency, |
| 1095 | 1109 | enum iwl_mld_scan_status scan_status, |
| 1096 | 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 | 1113 | struct ieee80211_supported_band *sband = |
| 1100 | 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 | 1122 | if (params->scan_6ghz) |
| 1109 | 1123 | return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params, |
| 1110 | − vif, scan_p); | |
| 1124 | + vif, scan_ptrs); | |
| 1111 | 1125 | |
| 1112 | 1126 | /* relevant only for 2.4 GHz/5 GHz scan */ |
| 1113 | 1127 | cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif, |
| 1114 | 1128 | low_latency); |
| 1115 | 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 | 1132 | params->n_channels, channel_cfg_flags, |
| 1119 | 1133 | vif->type); |
| 1120 | 1134 | |
| @@ -1144,49 +1158,148 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, · 23 unmodified lines | ||
| 1144 | 1158 | return 0; |
| 1145 | 1159 | } |
| 1146 | 1160 | |
| 1147 | −static int | |
| 1148 | −iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, | |
| 1161 | +struct iwl_scan_umac_handler { | |
| 1162 | + u8 version; | |
| 1163 | + int (*handler)(struct iwl_mld *mld, struct ieee80211_vif *vif, | |
| 1149 | 1164 | struct iwl_mld_scan_params *params, |
| 1150 | 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 | 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 */ | |
| 1161 | − uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE); | |
| 1162 | − if (uid < 0) | |
| 1163 | − return uid; | |
| 1187 | + ret = iwl_mld_scan_cmd_set_sched_params(params, scan_ptrs); | |
| 1188 | + if (ret) | |
| 1189 | + return ret; | |
| 1164 | 1190 | |
| 1165 | − cmd->uid = cpu_to_le32(uid); | |
| 1166 | − cmd->ooc_priority = | |
| 1167 | − cpu_to_le32(iwl_mld_scan_ooc_priority(scan_status)); | |
| 1191 | + iwl_mld_scan_cmd_set_probe_params(params, scan_ptrs, &bitmap_ssid); | |
| 1192 | + | |
| 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, | |
| 1170 | − &scan_p->general_params, scan_status); | |
| 1212 | + if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V4)) | |
| 1213 | + return -EINVAL; | |
| 1171 | 1214 | |
| 1172 | − ret = iwl_mld_scan_cmd_set_sched_params(params, | |
| 1173 | − scan_p->periodic_params.schedule, | |
| 1174 | − &scan_p->periodic_params.delay); | |
| 1215 | + cmd->uid = cpu_to_le32(uid); | |
| 1216 | + cmd->ooc_priority = cpu_to_le32(ooc_priority); | |
| 1217 | + | |
| 1218 | + ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs, | |
| 1219 | + scan_status, low_latency); | |
| 1175 | 1220 | if (ret) |
| 1176 | 1221 | return ret; |
| 1177 | 1222 | |
| 1178 | − iwl_mld_scan_cmd_set_probe_params(params, &scan_p->probe_params, | |
| 1179 | − &bitmap_ssid); | |
| 1223 | + return uid; | |
| 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, | |
| 1182 | − low_latency, scan_status, | |
| 1183 | − bitmap_ssid); | |
| 1255 | + ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs, | |
| 1256 | + scan_status, low_latency); | |
| 1184 | 1257 | if (ret) |
| 1185 | 1258 | return ret; |
| 1186 | 1259 | |
| 1187 | 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 | 1303 | static bool |
| 1191 | 1304 | iwl_mld_scan_pass_all(struct iwl_mld *mld, |
| 1192 | 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 | 2055 | struct ieee80211_bss_conf *link_conf = NULL; |
| 1943 | 2056 | |
| 1944 | 2057 | if (fw_link_id != IWL_MLD_INVALID_FW_ID) |
| 1945 | − link_conf = | |
| 1946 | − wiphy_dereference(mld->wiphy, | |
| 1947 | − mld->fw_id_to_bss_conf[fw_link_id]); | |
| 2058 | + link_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id); | |
| 1948 | 2059 | |
| 1949 | 2060 | /* It is possible that by the time the scan is complete the |
| 1950 | 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 | 2143 | if (scan_cmd_ver == 17) { |
| 2033 | 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 | 2147 | } else { |
| 2035 | 2148 | IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver); |
| 2036 | 2149 | return -EINVAL; |
| @@ -2041,6 +2154,7 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld) · 4 unmodified lines | ||
| 2041 | 2154 | return -ENOMEM; |
| 2042 | 2155 | |
| 2043 | 2156 | mld->scan.cmd_size = scan_cmd_size; |
| 2157 | + mld->scan.cmd_ver = scan_cmd_ver; | |
| 2044 | 2158 | |
| 2045 | 2159 | return 0; |
| 2046 | 2160 | } |
| @@ -109,6 +109,7 @@ enum iwl_mld_traffic_load { · 108 unmodified lines | ||
| 109 | 109 | * @traffic_load.status: The current traffic load status, see |
| 110 | 110 | * &enum iwl_mld_traffic_load |
| 111 | 111 | * @cmd_size: size of %cmd. |
| 112 | + * @cmd_ver: version of the scan command format. | |
| 112 | 113 | * @cmd: pointer to scan cmd buffer (allocated once in op mode start). |
| 113 | 114 | * @last_6ghz_passive_jiffies: stores the last 6GHz passive scan time |
| 114 | 115 | * in jiffies. |
| @@ -134,6 +135,7 @@ struct iwl_mld_scan { · 19 unmodified lines | ||
| 134 | 135 | /* And here fields that survive a fw restart */ |
| 135 | 136 | size_t cmd_size; |
| 136 | 137 | void *cmd; |
| 138 | + u8 cmd_ver; | |
| 137 | 139 | unsigned long last_6ghz_passive_jiffies; |
| 138 | 140 | unsigned long last_start_time_jiffies; |
| 139 | 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 | 398 | return htc_flags; |
| 399 | 399 | } |
| 400 | 400 | |
| 401 | +/* Note: modifies the command depending on FW command version */ | |
| 401 | 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 | − WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), | |
| 406 | − cmd); | |
| 405 | + int cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); | |
| 406 | + int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); | |
| 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 | 437 | if (ret) |
| 408 | 438 | IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); |
| 409 | 439 | return ret; |
| @@ -431,8 +461,8 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, · 21 unmodified lines | ||
| 431 | 461 | return -EINVAL; |
| 432 | 462 | |
| 433 | 463 | cmd.sta_id = cpu_to_le32(fw_id); |
| 464 | + cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id)); | |
| 434 | 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 | 467 | memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN); |
| 438 | 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 | 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 | 533 | static int |
| 504 | 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 | 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 | 760 | struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); |
| 731 | 761 | struct ieee80211_link_sta *link_sta; |
| 732 | 762 | int link_id; |
| 733 | 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 | 766 | if (ret) |
| 737 | 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 | 938 | if (!(mld_vif->emlsr.blocked_reasons & IWL_MLD_EMLSR_BLOCKED_TPT)) |
| 909 | 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 | 942 | total_mpdus += tx ? queue_counter->per_link[i].tx : |
| 913 | 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 | 1012 | return iwl_mld_send_aux_sta_cmd(mld, internal_sta); |
| 983 | 1013 | |
| 984 | 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 | 1016 | cmd.station_type = cpu_to_le32(internal_sta->sta_type); |
| 987 | 1017 | |
| 988 | 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 | 90 | struct iwl_mld_per_q_mpdu_counter { |
| 91 | 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 | 93 | unsigned long window_start_time; |
| 94 | 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 | 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 | 194 | void iwl_mld_remove_sta(struct iwl_mld *mld, struct ieee80211_sta *sta); |
| 195 | 195 | int iwl_mld_fw_sta_id_from_link_sta(struct iwl_mld *mld, |
| 196 | 196 | struct ieee80211_link_sta *link_sta); |
| @@ -369,15 +369,39 @@ out: · 368 unmodified lines | ||
| 369 | 369 | static void iwl_mld_update_link_sig(struct ieee80211_vif *vif, int sig, |
| 370 | 370 | struct ieee80211_bss_conf *bss_conf) |
| 371 | 371 | { |
| 372 | + struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf); | |
| 372 | 373 | struct iwl_mld *mld = iwl_mld_vif_from_mac80211(vif)->mld; |
| 373 | 374 | int exit_emlsr_thresh; |
| 375 | + int last_event; | |
| 374 | 376 | |
| 375 | 377 | if (sig == 0) { |
| 376 | 378 | IWL_DEBUG_RX(mld, "RSSI is 0 - skip signal based decision\n"); |
| 377 | 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 | 406 | if (!iwl_mld_emlsr_active(vif)) { |
| 383 | 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 | 431 | u32 total_airtime_usec = 0; |
| 408 | 432 | |
| 409 | 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 | 435 | fw_id++) { |
| 412 | 436 | const struct iwl_stats_ntfy_per_link *link_stats; |
| 413 | 437 | struct ieee80211_bss_conf *bss_conf; |
| 414 | 438 | int sig; |
| 415 | 439 | |
| 416 | − bss_conf = wiphy_dereference(mld->wiphy, | |
| 417 | − mld->fw_id_to_bss_conf[fw_id]); | |
| 440 | + bss_conf = iwl_mld_fw_id_to_link_conf(mld, fw_id); | |
| 418 | 441 | if (!bss_conf || bss_conf->vif->type != NL80211_IFTYPE_STATION) |
| 419 | 442 | continue; |
| 420 | 443 | |
| @@ -42,7 +42,7 @@ int iwlmld_kunit_test_init(struct kunit *test) · 41 unmodified lines | ||
| 42 | 42 | iwl_construct_mld(mld, trans, cfg, fw, hw, NULL); |
| 43 | 43 | |
| 44 | 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 | 47 | mld->fwrt.trans = trans; |
| 48 | 48 | mld->fwrt.fw = fw; |
| @@ -68,7 +68,7 @@ int iwlmld_kunit_test_init(struct kunit *test) · 19 unmodified lines | ||
| 68 | 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 | 73 | static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, |
| 74 | 74 | struct ieee80211_bss_conf *link, |
| @@ -94,7 +94,7 @@ static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, · 19 unmodified lines | ||
| 94 | 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 | 99 | /* Helper function to add and initialize a VIF for KUnit tests */ |
| 100 | 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 | 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 | 204 | static void iwlmld_kunit_add_link_sta(struct ieee80211_sta *sta, |
| 205 | 205 | struct ieee80211_link_sta *link_sta, |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "hcmd.h" |
| 10 | 10 | #include "sta.h" |
| 11 | 11 | #include "phy.h" |
| 12 | +#include "iface.h" | |
| 12 | 13 | |
| 13 | 14 | #include "fw/api/rs.h" |
| 14 | 15 | #include "fw/api/context.h" |
| @@ -36,7 +37,8 @@ iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld, · 21 unmodified lines | ||
| 36 | 37 | struct ieee80211_vif *vif, |
| 37 | 38 | struct ieee80211_link_sta *link_sta, |
| 38 | 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 | 43 | struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; |
| 42 | 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 | 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 | 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 | 414 | struct ieee80211_supported_band *sband, |
| 407 | 415 | const struct ieee80211_sta_he_cap *own_he_cap, |
| 408 | 416 | const struct ieee80211_sta_eht_cap *own_eht_cap, |
| 417 | + const struct ieee80211_sta_uhr_cap *own_uhr_cap, | |
| 409 | 418 | struct iwl_tlc_config_cmd *cmd) |
| 410 | 419 | { |
| 411 | 420 | int i; |
| @@ -423,7 +432,16 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, · 11 unmodified lines | ||
| 423 | 432 | cmd->non_ht_rates = cpu_to_le16(non_ht_rates); |
| 424 | 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 | 445 | cmd->mode = IWL_TLC_MNG_MODE_EHT; |
| 428 | 446 | iwl_mld_fill_eht_rates(vif, link_sta, own_he_cap, |
| 429 | 447 | own_eht_cap, cmd); |
| @@ -513,19 +531,23 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, · 83 unmodified lines | ||
| 513 | 531 | struct ieee80211_bss_conf *link) |
| 514 | 532 | { |
| 515 | 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 | 535 | enum nl80211_band band = link->chanreq.oper.chan->band; |
| 517 | 536 | struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; |
| 518 | 537 | const struct ieee80211_sta_he_cap *own_he_cap = |
| 519 | 538 | ieee80211_get_he_iftype_cap_vif(sband, vif); |
| 520 | 539 | const struct ieee80211_sta_eht_cap *own_eht_cap = |
| 521 | 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 | 543 | struct iwl_tlc_config_cmd cmd = { |
| 523 | 544 | /* For AP mode, use 20 MHz until the STA is authorized */ |
| 524 | 545 | .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? |
| 525 | 546 | iwl_mld_fw_bw_from_sta_bw(link_sta) : |
| 526 | 547 | IWL_TLC_MNG_CH_WIDTH_20MHZ, |
| 527 | 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 | 551 | .chains = iwl_mld_get_fw_chains(mld), |
| 530 | 552 | .sgi_ch_width_supp = iwl_mld_get_fw_sgi(link_sta), |
| 531 | 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 | 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 | 575 | if (WARN_ON(!chan_ctx)) |
| 551 | 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 | 581 | iwl_mld_fill_supp_rates(mld, vif, link_sta, sband, |
| 557 | 582 | own_he_cap, own_eht_cap, |
| 558 | − &cmd); | |
| 583 | + own_uhr_cap, &cmd); | |
| 559 | 584 | |
| 560 | 585 | if (cmd_ver == 6) { |
| 561 | 586 | cmd_ptr = &cmd; |
| @@ -638,6 +663,49 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, · 76 unmodified lines | ||
| 638 | 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 | 709 | void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, |
| 642 | 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 | 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 | 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 | 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 | 465 | u8 cmd_ver; |
| 463 | 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 | 468 | if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { |
| 474 | 469 | IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n"); |
| 475 | 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 | 474 | IWL_FW_CMD_VER_UNKNOWN); |
| 480 | 475 | if (cmd_ver != 1) { |
| 481 | 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 | 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 | 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 | 495 | if (ret < 0) |
| 494 | 496 | IWL_ERR(mvm, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", |
| 495 | 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 | 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 | 912 | struct iwl_geo_tx_power_profiles_resp *resp; |
| 911 | 913 | u16 len; |
| 912 | 914 | int ret; |
| @@ -958,7 +960,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) · 45 unmodified lines | ||
| 958 | 960 | static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) |
| 959 | 961 | { |
| 960 | 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 | 964 | u16 len; |
| 963 | 965 | u32 n_bands; |
| 964 | 966 | u32 n_profiles; |
| @@ -1032,12 +1034,139 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) · 67 unmodified lines | ||
| 1032 | 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 | 1164 | int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) |
| 1036 | 1165 | { |
| 1037 | 1166 | union iwl_ppag_table_cmd cmd; |
| 1038 | 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 | 1170 | /* Not supporting PPAG table is a valid scenario */ |
| 1042 | 1171 | if (ret < 0) |
| 1043 | 1172 | return 0; |
| @@ -6229,9 +6229,10 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, · 6228 unmodified lines | ||
| 6229 | 6229 | ret = wait_event_timeout(mvm->rx_sync_waitq, |
| 6230 | 6230 | READ_ONCE(mvm->queue_sync_state) == 0, |
| 6231 | 6231 | SYNC_RX_QUEUE_TIMEOUT); |
| 6232 | − WARN_ONCE(!ret, "queue sync: failed to sync, state is 0x%lx, cookie %d\n", | |
| 6233 | − mvm->queue_sync_state, | |
| 6234 | − mvm->queue_sync_cookie); | |
| 6232 | + IWL_FW_CHECK(mvm, !ret, | |
| 6233 | + "queue sync: failed to sync, state is 0x%lx, cookie %d\n", | |
| 6234 | + mvm->queue_sync_state, | |
| 6235 | + mvm->queue_sync_cookie); | |
| 6235 | 6236 | } |
| 6236 | 6237 | |
| 6237 | 6238 | out: |
| @@ -121,52 +121,6 @@ struct iwl_mvm_sta_key_update_data { · 120 unmodified lines | ||
| 121 | 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 | 124 | static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, |
| 171 | 125 | u32 key_flags, u32 keyidx, u32 flags) |
| 172 | 126 | { |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm, |
| 8 | 8 | struct ieee80211_vif *vif, |
| 9 | − struct iwl_mac_config_cmd *cmd, | |
| 9 | + struct iwl_mac_config_cmd_v3 *cmd, | |
| 10 | 10 | int cmd_ver) |
| 11 | 11 | { |
| 12 | 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 | 25 | static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, |
| 26 | 26 | struct ieee80211_vif *vif, |
| 27 | − struct iwl_mac_config_cmd *cmd, | |
| 27 | + struct iwl_mac_config_cmd_v3 *cmd, | |
| 28 | 28 | u32 action) |
| 29 | 29 | { |
| 30 | 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 | 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 | 88 | int ret = iwl_mvm_send_cmd_pdu(mvm, |
| 89 | 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 | 98 | struct ieee80211_vif *vif, |
| 99 | 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 | 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 | 151 | struct ieee80211_vif *vif, |
| 152 | 152 | u32 action) |
| 153 | 153 | { |
| 154 | − struct iwl_mac_config_cmd cmd = {}; | |
| 154 | + struct iwl_mac_config_cmd_v3 cmd = {}; | |
| 155 | 155 | |
| 156 | 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 | 170 | struct ieee80211_vif *vif, |
| 171 | 171 | u32 action) |
| 172 | 172 | { |
| 173 | − struct iwl_mac_config_cmd cmd = {}; | |
| 173 | + struct iwl_mac_config_cmd_v3 cmd = {}; | |
| 174 | 174 | |
| 175 | 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 | 187 | struct ieee80211_vif *vif, |
| 188 | 188 | u32 action) |
| 189 | 189 | { |
| 190 | − struct iwl_mac_config_cmd cmd = {}; | |
| 190 | + struct iwl_mac_config_cmd_v3 cmd = {}; | |
| 191 | 191 | |
| 192 | 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 | 210 | u32 action) |
| 211 | 211 | { |
| 212 | 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 | 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 | 286 | int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
| 287 | 287 | { |
| 288 | 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 | 290 | .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), |
| 291 | 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 | 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 | 889 | const struct ieee80211_ops iwl_mvm_mld_hw_ops = { |
| 1017 | 890 | .tx = iwl_mvm_mac_tx, |
| 1018 | 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 | 975 | .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, |
| 1103 | 976 | #endif |
| 1104 | 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 | 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 | 25 | u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); |
| 26 | 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 | 41 | struct iwl_mvm_int_sta *sta, |
| 42 | 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 | 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 | 416 | struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif); |
| 417 | 417 | struct iwl_mvm_vif_link_info *link_info = |
| 418 | 418 | mvm_vif->link[link_conf->link_id]; |
| 419 | − struct iwl_sta_cfg_cmd cmd = { | |
| 419 | + struct iwl_sta_cfg_cmd_v2 cmd = { | |
| 420 | 420 | .sta_id = cpu_to_le32(mvm_link_sta->sta_id), |
| 421 | 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 | 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 | 2450 | struct ieee80211_vif *vif, |
| 2451 | 2451 | struct iwl_mvm_vif_link_info *link, |
| 2452 | 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 | 2453 | int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, |
| 2459 | 2454 | struct ieee80211_key_conf *keyconf); |
| 2460 | 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 | 304 | IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n", |
| 305 | 305 | PTR_ERR(mvm->ptp_data.ptp_clock)); |
| 306 | 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 | 310 | IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", |
| 309 | 311 | mvm->ptp_data.ptp_clock_info.name, |
| 310 | 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 | 637 | struct iwl_mvm_link_sta *mvm_sta_link, |
| 638 | 638 | unsigned int link_id); |
| 639 | 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 | 640 | u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
| 645 | 641 | int filter_link_id); |
| 646 | 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 | 234 | * Also convert TU to msec. |
| 235 | 235 | */ |
| 236 | 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 | 238 | msecs_to_jiffies(delay)); |
| 239 | 239 | |
| 240 | 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 | 549 | delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period * |
| 550 | 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 | 552 | msecs_to_jiffies(delay)); |
| 553 | 553 | return 0; |
| 554 | 554 | } |
| @@ -659,6 +659,6 @@ retry: · 104 unmodified lines | ||
| 659 | 659 | /* register a timeout in case we don't succeed in switching */ |
| 660 | 660 | delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int * |
| 661 | 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 | 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 | 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 | 102 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 101 | 103 | int ret; |
| @@ -133,7 +135,7 @@ void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) · 31 unmodified lines | ||
| 133 | 135 | "timeout waiting for FW reset ACK (inta_hw=0x%x, reset_done %d)\n", |
| 134 | 136 | inta_hw, reset_done); |
| 135 | 137 | |
| 136 | − if (!reset_done) { | |
| 138 | + if (!reset_done && dump_on_timeout) { | |
| 137 | 139 | struct iwl_fw_error_dump_mode mode = { |
| 138 | 140 | .type = IWL_ERR_TYPE_RESET_HS_TIMEOUT, |
| 139 | 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 | 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 | 157 | static void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) |
| 151 | 158 | { |
| 152 | 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 | 170 | * should assume that the firmware is already dead. |
| 164 | 171 | */ |
| 165 | 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 | 176 | trans_pcie->is_down = true; |
| @@ -3197,7 +3197,7 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file, · 3196 unmodified lines | ||
| 3197 | 3197 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) |
| 3198 | 3198 | return -EINVAL; |
| 3199 | 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 | 3201 | return -EINVAL; |
| 3202 | 3202 | trans->request_top_reset = 1; |
| 3203 | 3203 | } |
| @@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw, · 87 unmodified lines | ||
| 88 | 88 | IEEE80211_CHANCTX_CHANGE_RADAR))) |
| 89 | 89 | return; |
| 90 | 90 | |
| 91 | + if (phy->roc_vif) | |
| 92 | + mt76_abort_roc(phy); | |
| 93 | + | |
| 91 | 94 | cancel_delayed_work_sync(&phy->mac_work); |
| 92 | 95 | |
| 93 | 96 | mutex_lock(&dev->mutex); |
| @@ -155,8 +158,6 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, · 61 unmodified lines | ||
| 155 | 158 | { |
| 156 | 159 | struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; |
| 157 | 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 | 161 | struct mt76_phy *phy = ctx->phy; |
| 161 | 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 | 174 | if (!mlink) |
| 174 | 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 | 177 | dev->drv->vif_link_remove(phy, vif, link_conf, mlink); |
| 180 | 178 | mlink->ctx = NULL; |
| 181 | − | |
| 182 | − if (mlink != (struct mt76_vif_link *)vif->drv_priv) | |
| 183 | − kfree_rcu(mlink, rcu_head); | |
| 184 | − | |
| 185 | 179 | out: |
| 186 | 180 | mutex_unlock(&dev->mutex); |
| 187 | 181 | } |
| @@ -254,6 +248,8 @@ skip_link_replace: · 66 unmodified lines | ||
| 254 | 248 | continue; |
| 255 | 249 | |
| 256 | 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 | 255 | out: |
| @@ -324,9 +320,11 @@ void mt76_roc_complete(struct mt76_phy *phy) · 64 unmodified lines | ||
| 324 | 320 | |
| 325 | 321 | if (mlink) |
| 326 | 322 | mlink->mvif->roc_phy = NULL; |
| 327 | − if (phy->main_chandef.chan && | |
| 328 | − !test_bit(MT76_MCU_RESET, &dev->phy.state)) | |
| 329 | − mt76_set_channel(phy, &phy->main_chandef, false); | |
| 323 | + if (phy->chanctx && phy->main_chandef.chan && phy->offchannel && | |
| 324 | + !test_bit(MT76_MCU_RESET, &dev->phy.state)) { | |
| 325 | + __mt76_set_channel(phy, &phy->main_chandef, false); | |
| 326 | + mt76_offchannel_notify(phy, false); | |
| 327 | + } | |
| 330 | 328 | mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); |
| 331 | 329 | phy->roc_vif = NULL; |
| 332 | 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 | 362 | struct mt76_phy *phy = hw->priv; |
| 365 | 363 | struct mt76_dev *dev = phy->dev; |
| 366 | 364 | struct mt76_vif_link *mlink; |
| 365 | + bool offchannel; | |
| 367 | 366 | int ret = 0; |
| 368 | 367 | |
| 369 | 368 | phy = dev->band_phys[chan->band]; |
| 370 | 369 | if (!phy) |
| 371 | 370 | return -EINVAL; |
| 372 | 371 | |
| 372 | + cancel_delayed_work_sync(&phy->mac_work); | |
| 373 | + | |
| 373 | 374 | mutex_lock(&dev->mutex); |
| 374 | 375 | |
| 375 | 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 | 388 | mlink->mvif->roc_phy = phy; |
| 388 | 389 | phy->roc_vif = vif; |
| 389 | 390 | phy->roc_link = mlink; |
| 390 | − cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); | |
| 391 | − mt76_set_channel(phy, &chandef, true); | |
| 391 | + | |
| 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 | 403 | ieee80211_ready_on_channel(hw); |
| 393 | 404 | ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, |
| 394 | 405 | msecs_to_jiffies(duration)); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <linux/dma-mapping.h> |
| 7 | 7 | #include "mt76.h" |
| 8 | 8 | #include "dma.h" |
| 9 | +#include "mt76_connac.h" | |
| 9 | 10 | |
| 10 | 11 | static struct mt76_txwi_cache * |
| 11 | 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 | 189 | static void |
| 189 | 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) && !mt76_npu_device_active(dev)) | |
| 192 | + if ((q->flags & MT_QFLAG_WED_RRO_EN) && | |
| 193 | + (!is_mt7992(dev) || !mt76_npu_device_active(dev))) | |
| 193 | 194 | Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); |
| 194 | 195 | else |
| 195 | 196 | Q_WRITE(q, ring_size, q->ndesc); |
| 196 | 197 | |
| 197 | 198 | if (mt76_queue_is_npu_tx(q)) { |
| 198 | − writel(q->desc_dma, &q->regs->desc_base); | |
| 199 | 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 | 204 | q->head = Q_READ(q, dma_idx); |
| 202 | 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 | 666 | if (!t) |
| 664 | 667 | goto free_skb; |
| 665 | 668 | |
| 669 | + t->phy_idx = phy->band_idx; | |
| 670 | + t->qid = qid; | |
| 666 | 671 | txwi = mt76_get_txwi_ptr(dev, t); |
| 667 | 672 | |
| 668 | 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 | 879 | if (!buf) |
| 875 | 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 | 892 | mt76_put_page_pool_buf(buf, false); |
| 879 | 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 | 929 | mt76_queue_is_wed_rro(q)) |
| 916 | 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 | 939 | mt76_dma_sync_idx(dev, q); |
| 919 | 940 | if (mt76_queue_is_npu(q)) |
| 920 | 941 | mt76_npu_fill_rx_queue(dev, q); |
| @@ -1168,10 +1189,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev) · 247 unmodified lines | ||
| 1168 | 1189 | mt76_for_each_q_rx(dev, i) { |
| 1169 | 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 | 1192 | netif_napi_del(&dev->napi[i]); |
| 1176 | 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 | 174 | static inline void |
| 175 | 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 | 180 | if (mtk_wed_device_active(&dev->mmio.wed)) |
| 179 | 181 | mt76_wed_dma_setup(dev, q, true); |
| 180 | 182 | } |
| @@ -9,6 +9,13 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/nvmem-consumer.h> |
| 10 | 10 | #include <linux/etherdevice.h> |
| 11 | 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 | 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 | 300 | EXPORT_SYMBOL_GPL(mt76_find_channel_node); |
| 294 | 301 | |
| 295 | − | |
| 296 | 302 | static s8 |
| 297 | 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 | 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 | 329 | static void |
| 310 | −mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, | |
| 311 | − s8 target_power, s8 nss_delta, s8 *max_power) | |
| 330 | +mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, | |
| 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 | 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 | 337 | return; |
| 317 | 338 | |
| 318 | 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 | 373 | *max_power = max(*max_power, pwr[i]); |
| 321 | 374 | } |
| 322 | 375 | } |
| 323 | 376 | |
| 324 | 377 | static void |
| 325 | −mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, | |
| 326 | − const s8 *data, size_t len, s8 target_power, | |
| 327 | − s8 nss_delta) | |
| 378 | +mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, | |
| 379 | + s8 pwr_num, const s8 *data, size_t len, | |
| 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 | 384 | int i, cur; |
| 330 | − s8 max_power = -128; | |
| 331 | 385 | |
| 332 | 386 | if (!data) |
| 333 | 387 | return; |
| @@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, · 3 unmodified lines | ||
| 337 | 391 | if (len < pwr_len + 1) |
| 338 | 392 | break; |
| 339 | 393 | |
| 340 | − mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1, | |
| 341 | − target_power, nss_delta, &max_power); | |
| 394 | + /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS | |
| 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 | 414 | if (--cur > 0) |
| 343 | 415 | continue; |
| 344 | 416 | |
| @@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, · 15 unmodified lines | ||
| 360 | 432 | struct device_node *np; |
| 361 | 433 | const s8 *val; |
| 362 | 434 | char name[16]; |
| 363 | − u32 mcs_rates = dev->drv->mcs_rates; | |
| 364 | − u32 ru_rates = ARRAY_SIZE(dest->ru[0]); | |
| 365 | 435 | char band; |
| 366 | 436 | size_t len; |
| 367 | − s8 max_power = 0; | |
| 368 | − s8 max_power_backoff = -127; | |
| 437 | + s8 max_power = -127; | |
| 369 | 438 | s8 txs_delta; |
| 370 | 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 | 441 | memset(dest, target_power, sizeof(*dest) - sizeof(dest->path)); |
| 377 | 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 | 474 | txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); |
| 410 | 475 | |
| 411 | 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, | |
| 413 | − target_power, txs_delta, &max_power); | |
| 477 | + mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val, | |
| 478 | + target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); | |
| 414 | 479 | |
| 415 | − val = mt76_get_of_array_s8(np, "rates-ofdm", | |
| 416 | − &len, ARRAY_SIZE(dest->ofdm)); | |
| 417 | − mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, | |
| 418 | − target_power, txs_delta, &max_power); | |
| 480 | + val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm)); | |
| 481 | + mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val, | |
| 482 | + target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); | |
| 419 | 483 | |
| 420 | − val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); | |
| 421 | − mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), | |
| 422 | − ARRAY_SIZE(dest->mcs), val, len, | |
| 423 | − target_power, txs_delta); | |
| 484 | + val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1); | |
| 485 | + mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), | |
| 486 | + ARRAY_SIZE(dest->mcs), val, len, target_power, | |
| 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); | |
| 426 | − mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), | |
| 427 | − ARRAY_SIZE(dest->ru), val, len, | |
| 428 | − target_power, txs_delta); | |
| 489 | + val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1); | |
| 490 | + mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]), | |
| 491 | + ARRAY_SIZE(dest->ru), val, len, target_power, | |
| 492 | + txs_delta, &max_power, n_chains, MT76_SKU_RATE); | |
| 429 | 493 | |
| 430 | − max_power_backoff = max_power; | |
| 431 | 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, | |
| 433 | − target_power_combine, txs_delta, &max_power_backoff); | |
| 495 | + mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val, | |
| 496 | + target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); | |
| 434 | 497 | |
| 435 | 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, | |
| 437 | − target_power_combine, txs_delta, &max_power_backoff); | |
| 499 | + mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, | |
| 500 | + target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); | |
| 438 | 501 | |
| 439 | 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, | |
| 441 | − target_power_combine, txs_delta, &max_power_backoff); | |
| 503 | + mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, | |
| 504 | + target_power, txs_delta, &max_power, n_chains, | |
| 505 | + MT76_SKU_BACKOFF_BF_OFFSET); | |
| 442 | 506 | |
| 443 | 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]), | |
| 445 | − ARRAY_SIZE(dest->path.ru), val, len, | |
| 446 | − target_power_combine, txs_delta); | |
| 508 | + mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), | |
| 509 | + ARRAY_SIZE(dest->path.ru), val, len, target_power, | |
| 510 | + txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); | |
| 447 | 511 | |
| 448 | 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]), | |
| 450 | − ARRAY_SIZE(dest->path.ru_bf), val, len, | |
| 451 | − target_power_combine, txs_delta); | |
| 513 | + mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), | |
| 514 | + ARRAY_SIZE(dest->path.ru_bf), val, len, target_power, | |
| 515 | + txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); | |
| 452 | 516 | |
| 453 | 517 | return max_power; |
| 454 | 518 | } |
| @@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, · 725 unmodified lines | ||
| 726 | 726 | INIT_LIST_HEAD(&dev->rxwi_cache); |
| 727 | 727 | dev->token_size = dev->drv->token_size; |
| 728 | 728 | INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); |
| 729 | + spin_lock_init(&dev->scan_lock); | |
| 729 | 730 | |
| 730 | 731 | for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) |
| 731 | 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 | 971 | return true; |
| 971 | 972 | } |
| 972 | 973 | |
| 974 | + if (atomic_read(&phy->mgmt_tx_pending)) | |
| 975 | + return true; | |
| 976 | + | |
| 973 | 977 | return false; |
| 974 | 978 | } |
| 975 | 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 | 1034 | int timeout = HZ / 5; |
| 1031 | 1035 | int ret; |
| 1032 | 1036 | |
| 1033 | − set_bit(MT76_RESET, &phy->state); | |
| 1034 | − | |
| 1035 | 1037 | mt76_worker_disable(&dev->tx_worker); |
| 1038 | + mt76_txq_schedule_pending(phy); | |
| 1039 | + | |
| 1040 | + set_bit(MT76_RESET, &phy->state); | |
| 1036 | 1041 | wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); |
| 1037 | 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 | 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 | 1734 | spin_lock_bh(&phy->tx_lock); |
| 1720 | 1735 | |
| 1721 | 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 | 2136 | return sel_links; |
| 2122 | 2137 | } |
| 2123 | 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 | 98 | /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ |
| 99 | 99 | if (orig_skb) |
| 100 | 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 | 102 | if (ret < 0) |
| 103 | 103 | goto out; |
| 104 | 104 | |
| @@ -55,6 +55,8 @@ · 54 unmodified lines | ||
| 55 | 55 | FIELD_PREP(MT_QFLAG_WED_RING, _n)) |
| 56 | 56 | #define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n) |
| 57 | 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 | 61 | struct mt76_dev; |
| 60 | 62 | struct mt76_phy; |
| @@ -362,6 +364,7 @@ enum mt76_wcid_flags { · 301 unmodified lines | ||
| 362 | 364 | }; |
| 363 | 365 | |
| 364 | 366 | #define MT76_N_WCIDS 1088 |
| 367 | +#define MT76_BEACON_MON_MAX_MISS 7 | |
| 365 | 368 | |
| 366 | 369 | /* stored in ieee80211_tx_info::hw_queue */ |
| 367 | 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 | 453 | u8 qid; |
| 454 | + u8 phy_idx; | |
| 451 | 455 | }; |
| 452 | 456 | |
| 453 | 457 | struct mt76_rx_tid { |
| @@ -540,7 +544,6 @@ struct mt76_driver_ops { · 86 unmodified lines | ||
| 540 | 544 | u32 survey_flags; |
| 541 | 545 | u16 txwi_size; |
| 542 | 546 | u16 token_size; |
| 543 | − u8 mcs_rates; | |
| 544 | 547 | |
| 545 | 548 | unsigned int link_data_size; |
| 546 | 549 | |
| @@ -831,6 +834,8 @@ struct mt76_vif_link { · 284 unmodified lines | ||
| 831 | 834 | u8 mcast_rates_idx; |
| 832 | 835 | u8 beacon_rates_idx; |
| 833 | 836 | bool offchannel; |
| 837 | + unsigned long beacon_mon_last; | |
| 838 | + u16 beacon_mon_interval; | |
| 834 | 839 | struct ieee80211_chanctx_conf *ctx; |
| 835 | 840 | struct mt76_wcid *wcid; |
| 836 | 841 | struct mt76_vif_data *mvif; |
| @@ -859,6 +864,8 @@ struct mt76_phy { · 22 unmodified lines | ||
| 859 | 864 | struct list_head tx_list; |
| 860 | 865 | struct mt76_queue *q_tx[__MT_TXQ_MAX]; |
| 861 | 866 | |
| 867 | + atomic_t mgmt_tx_pending; | |
| 868 | + | |
| 862 | 869 | struct cfg80211_chan_def chandef; |
| 863 | 870 | struct cfg80211_chan_def main_chandef; |
| 864 | 871 | bool offchannel; |
| @@ -1002,6 +1009,7 @@ struct mt76_dev { · 137 unmodified lines | ||
| 1002 | 1009 | u32 rxfilter; |
| 1003 | 1010 | |
| 1004 | 1011 | struct delayed_work scan_work; |
| 1012 | + spinlock_t scan_lock; | |
| 1005 | 1013 | struct { |
| 1006 | 1014 | struct cfg80211_scan_request *req; |
| 1007 | 1015 | struct ieee80211_channel *chan; |
| @@ -1009,6 +1017,8 @@ struct mt76_dev { · 1 unmodified line | ||
| 1009 | 1017 | struct mt76_vif_link *mlink; |
| 1010 | 1018 | struct mt76_phy *phy; |
| 1011 | 1019 | int chan_idx; |
| 1020 | + bool beacon_wait; | |
| 1021 | + bool beacon_received; | |
| 1012 | 1022 | } scan; |
| 1013 | 1023 | |
| 1014 | 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 | 1528 | void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); |
| 1519 | 1529 | void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); |
| 1520 | 1530 | void mt76_txq_schedule_all(struct mt76_phy *phy); |
| 1531 | +void mt76_txq_schedule_pending(struct mt76_phy *phy); | |
| 1521 | 1532 | void mt76_tx_worker_run(struct mt76_dev *dev); |
| 1522 | 1533 | void mt76_tx_worker(struct mt76_worker *w); |
| 1523 | 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 | 1607 | int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1597 | 1608 | struct ieee80211_scan_request *hw_req); |
| 1598 | 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 | 1613 | void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1600 | 1614 | const u8 *mac); |
| 1601 | 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 | 1663 | int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1650 | 1664 | struct net_device *dev, enum tc_setup_type type, |
| 1651 | 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 | 1669 | #else |
| 1653 | 1670 | static inline void mt76_npu_check_ppe(struct mt76_dev *dev, |
| 1654 | 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 | 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 | 1734 | #endif /* CONFIG_MT76_NPU */ |
| 1711 | 1735 | |
| 1712 | 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 | 1799 | struct mt76_queue_entry *e); |
| 1776 | 1800 | int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, |
| 1777 | 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 | 1814 | int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, |
| 1779 | 1815 | bool offchannel); |
| 1780 | 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 | 1822 | struct ieee80211_vif *vif); |
| 1787 | 1823 | void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, |
| 1788 | 1824 | struct mt76_vif_link *mlink); |
| 1825 | +void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel); | |
| 1789 | 1826 | |
| 1790 | 1827 | /* usb */ |
| 1791 | 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 | 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 | 2041 | struct mt76_txwi_cache * |
| 1997 | 2042 | mt76_token_release(struct mt76_dev *dev, int token, bool *wake); |
| 1998 | 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 | 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 | 1170 | static int |
| 1186 | 1171 | mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, |
| 1187 | 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 | 586 | if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { |
| 590 | 587 | mt7615_mcu_add_bss_info(phy, vif, NULL, true); |
| 591 | 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 | 595 | BSS_CHANGED_BEACON_ENABLED)) |
| 599 | 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 | 602 | if (changed & BSS_CHANGED_PS) |
| 602 | 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 | 2564 | return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), |
| 2565 | 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 | 467 | void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); |
| 468 | 468 | void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); |
| 469 | 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 | 470 | void mt7615_mac_sta_poll(struct mt7615_dev *dev); |
| 473 | 471 | int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, |
| 474 | 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 | 521 | int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); |
| 524 | 522 | int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); |
| 525 | 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 | 526 | int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, |
| 528 | 527 | struct ieee80211_channel *chan, int duration); |
| 529 | 528 | |
| @@ -455,8 +455,6 @@ enum mt7615_reg_base { · 454 unmodified lines | ||
| 455 | 455 | #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) |
| 456 | 456 | #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) |
| 457 | 457 | |
| 458 | −#define MT_WTBL_W3_RTS BIT(22) | |
| 459 | − | |
| 460 | 458 | #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) |
| 461 | 459 | #define MT_WTBL_W5_SHORT_GI_20 BIT(8) |
| 462 | 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 | 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 | 190 | static inline bool is_mt7922(struct mt76_dev *dev) |
| 186 | 191 | { |
| 187 | 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 | 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 | 277 | case 0x7961: |
| 272 | 278 | case 0x7920: |
| 273 | 279 | case 0x7922: |
| 280 | + case 0x7902: | |
| 274 | 281 | case 0x7925: |
| 275 | 282 | case 0x7663: |
| 276 | 283 | case 0x7622: |
| @@ -173,7 +173,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev, · 172 unmodified lines | ||
| 173 | 173 | |
| 174 | 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 | 177 | last_mask = MT_TXD_LEN_LAST; |
| 178 | 178 | else |
| 179 | 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 | 217 | u32 last_mask; |
| 218 | 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 | 221 | last_mask = MT_TXD_LEN_LAST; |
| 222 | 222 | else |
| 223 | 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 | 309 | chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef; |
| 310 | 310 | band = chandef->chan->band; |
| 311 | 311 | |
| 312 | − if (is_mt7921(mphy->dev)) { | |
| 312 | + if (is_connac2(mphy->dev)) { | |
| 313 | 313 | rateidx = ffs(conf->basic_rates) - 1; |
| 314 | 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 | 548 | val = MT_TXD1_LONG_FORMAT | |
| 549 | 549 | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | |
| 550 | 550 | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); |
| 551 | − if (!is_mt7921(dev)) | |
| 551 | + if (!is_connac2(dev)) | |
| 552 | 552 | val |= MT_TXD1_VTA; |
| 553 | 553 | if (phy_idx || band_idx) |
| 554 | 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 | 557 | txwi[2] = 0; |
| 558 | 558 | |
| 559 | 559 | val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); |
| 560 | − if (!is_mt7921(dev)) | |
| 560 | + if (!is_connac2(dev)) | |
| 561 | 561 | val |= MT_TXD3_SW_POWER_MGMT; |
| 562 | 562 | if (key) |
| 563 | 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 | 599 | txwi[6] |= cpu_to_le32(val); |
| 600 | 600 | txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); |
| 601 | 601 | |
| 602 | − if (!is_mt7921(dev)) { | |
| 602 | + if (!is_connac2(dev)) { | |
| 603 | 603 | u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); |
| 604 | 604 | |
| 605 | 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 | 832 | struct ieee80211_radiotap_he_mu *he_mu; |
| 833 | 833 | |
| 834 | − if (is_mt7921(dev)) { | |
| 834 | + if (is_connac2(dev)) { | |
| 835 | 835 | mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); |
| 836 | 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 | 1047 | stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); |
| 1048 | 1048 | gi = FIELD_GET(MT_PRXV_HT_SGI, v0); |
| 1049 | 1049 | *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); |
| 1050 | − if (is_mt7921(dev)) | |
| 1050 | + if (is_connac2(dev)) | |
| 1051 | 1051 | dcm = !!(idx & MT_PRXV_TX_DCM); |
| 1052 | 1052 | else |
| 1053 | 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 | 1153 | return; |
| 1154 | 1154 | |
| 1155 | 1155 | wcid = (struct mt76_wcid *)sta->drv_priv; |
| 1156 | − if (!test_and_set_bit(tid, &wcid->ampdu_state)) | |
| 1157 | − ieee80211_start_tx_ba_session(sta, tid, 0); | |
| 1156 | + if (!test_and_set_bit(tid, &wcid->ampdu_state)) { | |
| 1157 | + if (ieee80211_start_tx_ba_session(sta, tid, 0)) | |
| 1158 | + clear_bit(tid, &wcid->ampdu_state); | |
| 1159 | + } | |
| 1158 | 1160 | } |
| 1159 | 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 | 1210 | spin_unlock_bh(&dev->token_lock); |
| 1209 | 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 | 1219 | EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put); |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | #include <linux/firmware.h> |
| 5 | 5 | #include "mt76_connac2_mac.h" |
| 6 | 6 | #include "mt76_connac_mcu.h" |
| 7 | +#include "mt792x_regs.h" | |
| 7 | 8 | |
| 8 | 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 | 66 | int cmd; |
| 66 | 67 | |
| 67 | 68 | if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || |
| 68 | − (is_mt7921(dev) && addr == 0x900000) || | |
| 69 | + (is_connac2(dev) && addr == 0x900000) || | |
| 69 | 70 | (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || |
| 70 | 71 | (is_mt799x(dev) && addr == 0x900000)) |
| 71 | 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 | 403 | switch (vif->type) { |
| 403 | 404 | case NL80211_IFTYPE_MESH_POINT: |
| 404 | 405 | case NL80211_IFTYPE_AP: |
| 405 | − if (vif->p2p && !is_mt7921(dev)) | |
| 406 | + if (vif->p2p && !is_connac2(dev)) | |
| 406 | 407 | conn_type = CONNECTION_P2P_GC; |
| 407 | 408 | else |
| 408 | 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 | 411 | basic->aid = cpu_to_le16(link_sta->sta->aid); |
| 411 | 412 | break; |
| 412 | 413 | case NL80211_IFTYPE_STATION: |
| 413 | − if (vif->p2p && !is_mt7921(dev)) | |
| 414 | + if (vif->p2p && !is_connac2(dev)) | |
| 414 | 415 | conn_type = CONNECTION_P2P_GO; |
| 415 | 416 | else |
| 416 | 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 | 875 | struct sta_rec_vht *vht; |
| 875 | 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 | 879 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); |
| 879 | 880 | vht = (struct sta_rec_vht *)tlv; |
| 880 | 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 | 886 | /* starec uapsd */ |
| 886 | 887 | mt76_connac_mcu_sta_uapsd(skb, vif, sta); |
| 887 | 888 | |
| 888 | − if (!is_mt7921(dev)) | |
| 889 | + if (!is_connac2(dev)) | |
| 889 | 890 | return; |
| 890 | 891 | |
| 891 | 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 | 1296 | wtbl_hdr); |
| 1296 | 1297 | |
| 1297 | 1298 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 1298 | − if (ret) | |
| 1299 | + if (ret) { | |
| 1300 | + dev_kfree_skb(skb); | |
| 1299 | 1301 | return ret; |
| 1302 | + } | |
| 1300 | 1303 | |
| 1301 | 1304 | ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); |
| 1302 | 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 | 1312 | mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); |
| 1310 | 1313 | |
| 1311 | 1314 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 1312 | − if (ret) | |
| 1315 | + if (ret) { | |
| 1316 | + dev_kfree_skb(skb); | |
| 1313 | 1317 | return ret; |
| 1318 | + } | |
| 1314 | 1319 | |
| 1315 | 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 | 1779 | req->ssid_type_ext = n_ssids ? BIT(0) : 0; |
| 1775 | 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 | 1783 | /* increase channel time for passive scan */ |
| 1779 | 1784 | if (!sreq->n_ssids) |
| 1780 | 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 | 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 | 1826 | req->scan_func |= SCAN_FUNC_SPLIT_SCAN; |
| 1822 | 1827 | |
| 1823 | 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 | 1898 | get_random_mask_addr(addr, sreq->mac_addr, |
| 1894 | 1899 | sreq->mac_addr_mask); |
| 1895 | 1900 | } |
| 1896 | − if (is_mt7921(phy->dev)) { | |
| 1901 | + if (is_connac2(phy->dev)) { | |
| 1897 | 1902 | req->mt7921.bss_idx = mvif->idx; |
| 1898 | 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 | 2038 | struct mt76_power_limits *limits, |
| 2034 | 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 | 2042 | int i, offset = sizeof(limits->cck); |
| 2038 | 2043 | |
| 2039 | 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 | 2066 | offset += 12; |
| 2062 | 2067 | } |
| 2063 | 2068 | |
| 2064 | − if (!is_mt7921(dev)) | |
| 2069 | + if (!is_connac2(dev)) | |
| 2065 | 2070 | return; |
| 2066 | 2071 | |
| 2067 | 2072 | /* he */ |
| @@ -2117,7 +2122,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, · 49 unmodified lines | ||
| 2117 | 2122 | enum nl80211_band band) |
| 2118 | 2123 | { |
| 2119 | 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 | 2126 | static const u8 chan_list_2ghz[] = { |
| 2122 | 2127 | 1, 2, 3, 4, 5, 6, 7, |
| 2123 | 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 | 2163 | if (!limits) |
| 2159 | 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 | 2167 | tx_power = 2 * phy->hw->conf.power_level; |
| 2163 | 2168 | if (!tx_power) |
| 2164 | 2169 | tx_power = 127; |
| @@ -2242,6 +2247,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, · 77 unmodified lines | ||
| 2242 | 2247 | false); |
| 2243 | 2248 | if (err < 0) |
| 2244 | 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 | 2255 | out: |
| @@ -2764,12 +2772,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, · 516 unmodified lines | ||
| 2764 | 2772 | return PTR_ERR(skb); |
| 2765 | 2773 | |
| 2766 | 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 | 2777 | return ret; |
| 2778 | + } | |
| 2769 | 2779 | |
| 2770 | 2780 | ret = mt76_connac_mcu_sta_wed_update(dev, skb); |
| 2771 | − if (ret) | |
| 2781 | + if (ret) { | |
| 2782 | + dev_kfree_skb(skb); | |
| 2772 | 2783 | return ret; |
| 2784 | + } | |
| 2773 | 2785 | |
| 2774 | 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 | 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 | 3088 | return mode; |
| 3077 | 3089 | |
| 3078 | 3090 | switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { |
| @@ -628,6 +628,13 @@ struct sta_rec_tx_proc { · 627 unmodified lines | ||
| 628 | 628 | __le32 flag; |
| 629 | 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 | 638 | /* wtbl_rec */ |
| 632 | 639 | |
| 633 | 640 | struct wtbl_req_hdr { |
| @@ -796,6 +803,7 @@ struct wtbl_raw { · 162 unmodified lines | ||
| 796 | 803 | sizeof(struct sta_rec_he_6g_capa) + \ |
| 797 | 804 | sizeof(struct sta_rec_pn_info) + \ |
| 798 | 805 | sizeof(struct sta_rec_tx_proc) + \ |
| 806 | + sizeof(struct sta_rec_eml_op) + \ | |
| 799 | 807 | sizeof(struct tlv) + \ |
| 800 | 808 | MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) |
| 801 | 809 | |
| @@ -832,6 +840,7 @@ enum { · 30 unmodified lines | ||
| 832 | 840 | STA_REC_PN_INFO = 0x26, |
| 833 | 841 | STA_REC_KEY_V3 = 0x27, |
| 834 | 842 | STA_REC_HDRT = 0x28, |
| 843 | + STA_REC_EML_OP = 0x29, | |
| 835 | 844 | STA_REC_HDR_TRANS = 0x2B, |
| 836 | 845 | STA_REC_MAX_NUM |
| 837 | 846 | }; |
| @@ -1308,7 +1317,9 @@ enum { · 470 unmodified lines | ||
| 1308 | 1317 | MCU_UNI_CMD_PER_STA_INFO = 0x6d, |
| 1309 | 1318 | MCU_UNI_CMD_ALL_STA_INFO = 0x6e, |
| 1310 | 1319 | MCU_UNI_CMD_ASSERT_DUMP = 0x6f, |
| 1320 | + MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74, | |
| 1311 | 1321 | MCU_UNI_CMD_RADIO_STATUS = 0x80, |
| 1322 | + MCU_UNI_CMD_MLD = 0x82, | |
| 1312 | 1323 | MCU_UNI_CMD_SDO = 0x88, |
| 1313 | 1324 | }; |
| 1314 | 1325 | |
| @@ -1363,6 +1374,7 @@ enum { · 48 unmodified lines | ||
| 1363 | 1374 | UNI_BSS_INFO_BASIC = 0, |
| 1364 | 1375 | UNI_BSS_INFO_RA = 1, |
| 1365 | 1376 | UNI_BSS_INFO_RLM = 2, |
| 1377 | + UNI_BSS_INFO_PROTECT_INFO = 3, | |
| 1366 | 1378 | UNI_BSS_INFO_BSS_COLOR = 4, |
| 1367 | 1379 | UNI_BSS_INFO_HE_BASIC = 5, |
| 1368 | 1380 | UNI_BSS_INFO_11V_MBSSID = 6, |
| @@ -1383,6 +1395,7 @@ enum { · 14 unmodified lines | ||
| 1383 | 1395 | UNI_BSS_INFO_MLD = 26, |
| 1384 | 1396 | UNI_BSS_INFO_PM_DISABLE = 27, |
| 1385 | 1397 | UNI_BSS_INFO_EHT = 30, |
| 1398 | + UNI_BSS_INFO_MLD_LINK_OP = 36, | |
| 1386 | 1399 | }; |
| 1387 | 1400 | |
| 1388 | 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 | 1879 | ret |= feature_set & FW_FEATURE_SET_ENCRYPT ? |
| 1867 | 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 | 1882 | ret |= feature_set & FW_FEATURE_ENCRY_MODE ? |
| 1870 | 1883 | DL_CONFIG_ENCRY_MODE_SEL : 0; |
| 1871 | 1884 | ret |= FIELD_PREP(DL_MODE_KEY_IDX, |
| @@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, · 533 unmodified lines | ||
| 534 | 534 | return; |
| 535 | 535 | |
| 536 | 536 | clear_bit(MT76_RESTART, &dev->mphy.state); |
| 537 | + ieee80211_wake_queues(hw); | |
| 537 | 538 | } |
| 538 | 539 | EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); |
| 539 | 540 | |
| @@ -1294,6 +1294,7 @@ free_phy2: · 1293 unmodified lines | ||
| 1294 | 1294 | |
| 1295 | 1295 | void mt7915_unregister_device(struct mt7915_dev *dev) |
| 1296 | 1296 | { |
| 1297 | + cancel_work_sync(&dev->dump_work); | |
| 1297 | 1298 | mt7915_unregister_ext_phy(dev); |
| 1298 | 1299 | mt7915_coredump_unregister(dev); |
| 1299 | 1300 | mt7915_unregister_thermal(&dev->phy); |
| @@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) · 231 unmodified lines | ||
| 232 | 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 | 235 | static void |
| 249 | 236 | mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, |
| 250 | 237 | struct mt7915_sta *msta, struct sk_buff *skb, |
| @@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) · 67 unmodified lines | ||
| 68 | 68 | if (ret) |
| 69 | 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 | 72 | phy->mt76->band_idx); |
| 73 | 73 | if (ret) |
| 74 | 74 | goto out; |
| @@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, · 558 unmodified lines | ||
| 633 | 633 | if (set_sta == 1) |
| 634 | 634 | mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); |
| 635 | 635 | |
| 636 | − if (changed & BSS_CHANGED_ERP_CTS_PROT) | |
| 637 | − mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); | |
| 636 | + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) | |
| 637 | + mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, | |
| 638 | + info->use_cts_prot); | |
| 638 | 639 | |
| 639 | 640 | if (changed & BSS_CHANGED_ERP_SLOT) { |
| 640 | 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 | 852 | return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); |
| 852 | 853 | |
| 853 | 854 | case MT76_STA_EVENT_DISASSOC: |
| 855 | + mutex_lock(&dev->mt76.mutex); | |
| 854 | 856 | for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) |
| 855 | 857 | mt7915_mac_twt_teardown_flow(dev, msta, i); |
| 858 | + mutex_unlock(&dev->mt76.mutex); | |
| 856 | 859 | |
| 857 | 860 | mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); |
| 858 | 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 | 1766 | out: |
| 1767 | 1767 | ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); |
| 1768 | − if (ret) | |
| 1768 | + if (ret) { | |
| 1769 | + dev_kfree_skb(skb); | |
| 1769 | 1770 | return ret; |
| 1771 | + } | |
| 1770 | 1772 | |
| 1771 | 1773 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| 1772 | 1774 | MCU_EXT_CMD(STA_REC_UPDATE), true); |
| @@ -3954,6 +3956,68 @@ out: · 2181 unmodified lines | ||
| 3954 | 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 | 4021 | int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, |
| 3958 | 4022 | struct cfg80211_he_bss_color *he_bss_color) |
| 3959 | 4023 | { |
| @@ -399,6 +399,17 @@ struct bss_info_inband_discovery { · 398 unmodified lines | ||
| 399 | 399 | __le16 prob_rsp_len; |
| 400 | 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 | 413 | enum { |
| 403 | 414 | BSS_INFO_BCN_CSA, |
| 404 | 415 | BSS_INFO_BCN_BCC, |
| @@ -84,6 +84,8 @@ · 83 unmodified lines | ||
| 84 | 84 | #define MT7915_CRIT_TEMP 110 |
| 85 | 85 | #define MT7915_MAX_TEMP 120 |
| 86 | 86 | |
| 87 | +#define MT7915_RTS_LEN_THRES 0x92b | |
| 88 | + | |
| 87 | 89 | struct mt7915_vif; |
| 88 | 90 | struct mt7915_sta; |
| 89 | 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 | 475 | u32 changed); |
| 474 | 476 | int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 475 | 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 | 480 | int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, |
| 477 | 481 | struct ieee80211_he_obss_pd *he_obss_pd); |
| 478 | 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 | 302 | dev->pm.idle_timeout = MT792x_PM_TIMEOUT; |
| 303 | 303 | dev->pm.stats.last_wake_event = jiffies; |
| 304 | 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 | 308 | dev->pm.enable_user = true; |
| 307 | 309 | dev->pm.enable = true; |
| 308 | 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 | 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 | 377 | timer_delete_sync(&phy->roc_timer); |
| 375 | − cancel_work_sync(&phy->roc_work); | |
| 376 | − if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | |
| 377 | − ieee80211_iterate_interfaces(mt76_hw(dev), | |
| 378 | − IEEE80211_IFACE_ITER_RESUME_ALL, | |
| 379 | − mt7921_roc_iter, (void *)phy); | |
| 378 | + cancel_work(&phy->roc_work); | |
| 379 | + | |
| 380 | + ieee80211_iterate_interfaces(mt76_hw(dev), | |
| 381 | + IEEE80211_IFACE_ITER_RESUME_ALL, | |
| 382 | + mt7921_roc_iter, (void *)phy); | |
| 380 | 383 | } |
| 381 | 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 | 390 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, |
| 388 | 391 | roc_work); |
| 389 | 392 | |
| 390 | − if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | |
| 391 | − return; | |
| 392 | − | |
| 393 | 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 | 398 | ieee80211_iterate_active_interfaces(phy->mt76->hw, |
| 395 | 399 | IEEE80211_IFACE_ITER_RESUME_ALL, |
| 396 | 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 | 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 | 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 | 812 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 808 | 813 | int ret, idx; |
| 809 | 814 | |
| 815 | + if (sta->aid > MT7921_MAX_AID) | |
| 816 | + return -ENOENT; | |
| 817 | + | |
| 810 | 818 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); |
| 811 | 819 | if (idx < 0) |
| 812 | 820 | return -ENOSPC; |
| @@ -850,6 +858,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, · 37 unmodified lines | ||
| 850 | 858 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 851 | 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 | 864 | if (ev != MT76_STA_EVENT_ASSOC) |
| 854 | 865 | return 0; |
| 855 | 866 | |
| @@ -1353,6 +1353,9 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, · 1352 unmodified lines | ||
| 1353 | 1353 | u16 len = le16_to_cpu(rule->len); |
| 1354 | 1354 | u16 offset = len + sizeof(*rule); |
| 1355 | 1355 | |
| 1356 | + if (buf_len < offset) | |
| 1357 | + break; | |
| 1358 | + | |
| 1356 | 1359 | pos += offset; |
| 1357 | 1360 | buf_len -= offset; |
| 1358 | 1361 | if (rule->alpha2[0] != alpha2[0] || |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #include "../mt792x.h" |
| 8 | 8 | #include "regs.h" |
| 9 | 9 | |
| 10 | +#define MT7921_MAX_AID 20 | |
| 11 | + | |
| 10 | 12 | #define MT7921_TX_RING_SIZE 2048 |
| 11 | 13 | #define MT7921_TX_MCU_RING_SIZE 256 |
| 12 | 14 | #define MT7921_TX_FWDL_RING_SIZE 128 |
| @@ -15,6 +17,9 @@ · 2 unmodified lines | ||
| 15 | 17 | #define MT7921_RX_MCU_RING_SIZE 8 |
| 16 | 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 | 23 | #define MT7921_EEPROM_SIZE 3584 |
| 19 | 24 | #define MT7921_TOKEN_SIZE 8192 |
| 20 | 25 | |
| @@ -117,6 +122,17 @@ enum mt7921_rxq_id { · 96 unmodified lines | ||
| 117 | 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 | 136 | enum { |
| 121 | 137 | MT7921_CLC_POWER, |
| 122 | 138 | MT7921_CLC_CHAN, |
| @@ -26,6 +26,8 @@ static const struct pci_device_id mt7921_pci_device_table[] = { · 25 unmodified lines | ||
| 26 | 26 | .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, |
| 27 | 27 | { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920), |
| 28 | 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 | 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 | 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 | 195 | mt76_dma_attach(&dev->mt76); |
| 173 | 196 | |
| 174 | 197 | ret = mt792x_dma_disable(dev, true); |
| @@ -185,7 +208,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) · 10 unmodified lines | ||
| 185 | 208 | mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); |
| 186 | 209 | |
| 187 | 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 | 212 | MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); |
| 190 | 213 | if (ret) |
| 191 | 214 | return ret; |
| @@ -199,18 +222,20 @@ static int mt7921_dma_init(struct mt792x_dev *dev) · 7 unmodified lines | ||
| 199 | 222 | /* event from WM before firmware download */ |
| 200 | 223 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], |
| 201 | 224 | MT7921_RXQ_MCU_WM, |
| 202 | − MT7921_RX_MCU_RING_SIZE, | |
| 225 | + layout.mcu_rxdone_ring_size, | |
| 203 | 226 | MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); |
| 204 | 227 | if (ret) |
| 205 | 228 | return ret; |
| 206 | 229 | |
| 207 | − /* Change mcu queue after firmware download */ | |
| 208 | − ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], | |
| 209 | − MT7921_RXQ_MCU_WM, | |
| 210 | − MT7921_RX_MCU_WA_RING_SIZE, | |
| 211 | − MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); | |
| 212 | − if (ret) | |
| 213 | − return ret; | |
| 230 | + if (layout.has_mcu_wa) { | |
| 231 | + /* Change mcu queue after firmware download */ | |
| 232 | + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], | |
| 233 | + MT7921_RXQ_MCU_WM, | |
| 234 | + MT7921_RX_MCU_WA_RING_SIZE, | |
| 235 | + MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); | |
| 236 | + if (ret) | |
| 237 | + return ret; | |
| 238 | + } | |
| 214 | 239 | |
| 215 | 240 | /* rx data */ |
| 216 | 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 | 301 | struct mt76_bus_ops *bus_ops; |
| 277 | 302 | struct mt792x_dev *dev; |
| 278 | 303 | struct mt76_dev *mdev; |
| 304 | + void __iomem *regs; | |
| 279 | 305 | u16 cmd, chipid; |
| 280 | 306 | u8 features; |
| 281 | 307 | int ret; |
| @@ -284,10 +310,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev, · 2 unmodified lines | ||
| 284 | 310 | if (ret) |
| 285 | 311 | return ret; |
| 286 | 312 | |
| 287 | − ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); | |
| 288 | − if (ret) | |
| 289 | − return ret; | |
| 290 | − | |
| 291 | 313 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
| 292 | 314 | if (!(cmd & PCI_COMMAND_MEMORY)) { |
| 293 | 315 | cmd |= PCI_COMMAND_MEMORY; |
| @@ -321,11 +343,29 @@ static int mt7921_pci_probe(struct pci_dev *pdev, · 27 unmodified lines | ||
| 321 | 343 | |
| 322 | 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 | 350 | dev = container_of(mdev, struct mt792x_dev, mt76); |
| 325 | 351 | dev->fw_features = features; |
| 326 | 352 | dev->hif_ops = &mt7921_pcie_ops; |
| 327 | 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 | 369 | tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); |
| 330 | 370 | |
| 331 | 371 | dev->phy.dev = dev; |
| @@ -579,6 +619,8 @@ MODULE_FIRMWARE(MT7921_FIRMWARE_WM); · 247 unmodified lines | ||
| 579 | 619 | MODULE_FIRMWARE(MT7921_ROM_PATCH); |
| 580 | 620 | MODULE_FIRMWARE(MT7922_FIRMWARE_WM); |
| 581 | 621 | MODULE_FIRMWARE(MT7922_ROM_PATCH); |
| 622 | +MODULE_FIRMWARE(MT7902_FIRMWARE_WM); | |
| 623 | +MODULE_FIRMWARE(MT7902_ROM_PATCH); | |
| 582 | 624 | MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); |
| 583 | 625 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); |
| 584 | 626 | MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); |
| @@ -71,9 +71,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev) · 70 unmodified lines | ||
| 71 | 71 | mt76_txq_schedule_all(&dev->mphy); |
| 72 | 72 | |
| 73 | 73 | mt76_worker_disable(&dev->mt76.tx_worker); |
| 74 | − napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); | |
| 75 | − napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); | |
| 76 | − napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); | |
| 74 | + mt76_for_each_q_rx(&dev->mt76, i) { | |
| 75 | + napi_disable(&dev->mt76.napi[i]); | |
| 76 | + } | |
| 77 | 77 | napi_disable(&dev->mt76.tx_napi); |
| 78 | 78 | |
| 79 | 79 | mt76_connac2_tx_token_put(&dev->mt76); |
| @@ -19,6 +19,8 @@ · 18 unmodified lines | ||
| 19 | 19 | static const struct sdio_device_id mt7921s_table[] = { |
| 20 | 20 | { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901), |
| 21 | 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 | 24 | { } /* Terminating entry */ |
| 23 | 25 | }; |
| 24 | 26 | |
| @@ -317,6 +319,8 @@ failed: · 292 unmodified lines | ||
| 317 | 319 | MODULE_DEVICE_TABLE(sdio, mt7921s_table); |
| 318 | 320 | MODULE_FIRMWARE(MT7921_FIRMWARE_WM); |
| 319 | 321 | MODULE_FIRMWARE(MT7921_ROM_PATCH); |
| 322 | +MODULE_FIRMWARE(MT7902_FIRMWARE_WM); | |
| 323 | +MODULE_FIRMWARE(MT7902_ROM_PATCH); | |
| 320 | 324 | |
| 321 | 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 | 92 | mt7925_mac_init_basic_rates(dev); |
| 93 | 93 | |
| 94 | + memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); | |
| 95 | + | |
| 94 | 96 | return 0; |
| 95 | 97 | } |
| 96 | 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 | 804 | txwi[5] = cpu_to_le32(val); |
| 805 | 805 | |
| 806 | 806 | val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); |
| 807 | − if (!ieee80211_vif_is_mld(vif) || | |
| 808 | − (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) | |
| 807 | + if (vif && (!ieee80211_vif_is_mld(vif) || | |
| 808 | + (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) | |
| 809 | 809 | val |= MT_TXD6_DIS_MAT; |
| 810 | 810 | txwi[6] = cpu_to_le32(val); |
| 811 | 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 | 846 | bool is_8023; |
| 847 | 847 | u16 fc, tid; |
| 848 | 848 | |
| 849 | + if (!sta) | |
| 850 | + return; | |
| 851 | + | |
| 849 | 852 | link_sta = rcu_dereference(sta->link[wcid->link_id]); |
| 850 | 853 | if (!link_sta) |
| 851 | 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 | 857 | return; |
| 855 | 858 | |
| 856 | 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 | 885 | else |
| 883 | 886 | mlink = &msta->deflink; |
| 884 | 887 | |
| 885 | − if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) | |
| 886 | − ieee80211_start_tx_ba_session(sta, tid, 0); | |
| 888 | + if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) { | |
| 889 | + if (ieee80211_start_tx_ba_session(sta, tid, 0)) | |
| 890 | + clear_bit(tid, &mlink->wcid.ampdu_state); | |
| 891 | + } | |
| 887 | 892 | } |
| 888 | 893 | |
| 889 | 894 | static bool |
| @@ -1280,7 +1285,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, · 390 unmodified lines | ||
| 1280 | 1285 | if (vif->type == NL80211_IFTYPE_AP) { |
| 1281 | 1286 | mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, |
| 1282 | 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 | 1290 | MT76_STA_INFO_STATE_NONE); |
| 1285 | 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 | 246 | struct wiphy *wiphy = phy->mt76->hw->wiphy; |
| 247 | 247 | static const u8 ext_capa_sta[] = { |
| 248 | + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, | |
| 248 | 249 | [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, |
| 249 | 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 | 439 | if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) |
| 439 | 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 | 445 | out: |
| 442 | 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 | 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 | 467 | timer_delete_sync(&phy->roc_timer); |
| 461 | − cancel_work_sync(&phy->roc_work); | |
| 462 | − if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) | |
| 463 | − ieee80211_iterate_interfaces(mt76_hw(dev), | |
| 464 | − IEEE80211_IFACE_ITER_RESUME_ALL, | |
| 465 | − mt7925_roc_iter, (void *)phy); | |
| 468 | + | |
| 469 | + cancel_work(&phy->roc_work); | |
| 470 | + | |
| 471 | + ieee80211_iterate_interfaces(mt76_hw(dev), | |
| 472 | + IEEE80211_IFACE_ITER_RESUME_ALL, | |
| 473 | + mt7925_roc_iter, (void *)phy); | |
| 466 | 474 | } |
| 467 | 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 | 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 | 553 | if (err < 0) { |
| 546 | 554 | clear_bit(MT76_STATE_ROC, &phy->mt76->state); |
| 547 | 555 | goto out; |
| @@ -586,7 +594,8 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, · 38 unmodified lines | ||
| 586 | 594 | |
| 587 | 595 | static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
| 588 | 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 | 600 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
| 592 | 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 | 604 | struct ieee80211_bss_conf *link_conf; |
| 596 | 605 | struct ieee80211_link_sta *link_sta; |
| 597 | 606 | int idx = key->keyidx, err = 0; |
| 598 | − struct mt792x_link_sta *mlink; | |
| 599 | 607 | struct mt792x_bss_conf *mconf; |
| 600 | 608 | struct mt76_wcid *wcid; |
| 601 | 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 | 611 | link_conf = mt792x_vif_to_bss_conf(vif, link_id); |
| 604 | 612 | link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; |
| 605 | 613 | mconf = mt792x_vif_to_link(mvif, link_id); |
| 606 | − mlink = mt792x_sta_to_link(msta, link_id); | |
| 607 | 614 | wcid = &mlink->wcid; |
| 608 | 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 | 678 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 672 | 679 | struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : |
| 673 | 680 | &mvif->sta; |
| 681 | + struct mt792x_link_sta *mlink; | |
| 674 | 682 | int err; |
| 675 | 683 | |
| 676 | 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 | 700 | add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; |
| 693 | 701 | |
| 694 | 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 | 706 | if (err < 0) |
| 697 | 707 | break; |
| 698 | 708 | } |
| 699 | 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 | 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 | 855 | static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, |
| 844 | 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 | 860 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
| 848 | 861 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 849 | 862 | struct ieee80211_bss_conf *link_conf; |
| 850 | 863 | struct mt792x_bss_conf *mconf; |
| 851 | 864 | u8 link_id = link_sta->link_id; |
| 852 | − struct mt792x_link_sta *mlink; | |
| 865 | + bool wcid_published = false; | |
| 853 | 866 | struct mt792x_sta *msta; |
| 854 | 867 | struct mt76_wcid *wcid; |
| 868 | + bool pm_woken = false; | |
| 855 | 869 | int ret, idx; |
| 856 | 870 | |
| 857 | 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 | 876 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); |
| 861 | 877 | if (idx < 0) |
| @@ -874,14 +890,15 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, · 12 unmodified lines | ||
| 874 | 890 | wcid = &mlink->wcid; |
| 875 | 891 | ewma_signal_init(&wcid->rssi); |
| 876 | 892 | rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); |
| 877 | − mt76_wcid_init(wcid, 0); | |
| 893 | + wcid_published = true; | |
| 878 | 894 | ewma_avg_signal_init(&mlink->avg_ack_signal); |
| 879 | 895 | memset(mlink->airtime_ac, 0, |
| 880 | 896 | sizeof(msta->deflink.airtime_ac)); |
| 881 | 897 | |
| 882 | 898 | ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); |
| 883 | 899 | if (ret) |
| 884 | − return ret; | |
| 900 | + goto out_wcid; | |
| 901 | + pm_woken = true; | |
| 885 | 902 | |
| 886 | 903 | mt7925_mac_wtbl_update(dev, idx, |
| 887 | 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 | 908 | /* should update bss info before STA add */ |
| 892 | 909 | if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { |
| 893 | − if (ieee80211_vif_is_mld(vif)) | |
| 894 | − mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, | |
| 895 | − link_conf, link_sta, link_sta != mlink->pri_link); | |
| 896 | − else | |
| 897 | − mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, | |
| 898 | − link_conf, link_sta, false); | |
| 910 | + struct mt792x_link_sta *mlink_bc; | |
| 911 | + | |
| 912 | + mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); | |
| 913 | + | |
| 914 | + if (ieee80211_vif_is_mld(vif)) { | |
| 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 | 931 | if (ieee80211_vif_is_mld(vif) && |
| 902 | 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 | 935 | MT76_STA_INFO_STATE_NONE); |
| 905 | 936 | if (ret) |
| 906 | − return ret; | |
| 937 | + goto out_pm; | |
| 907 | 938 | } else if (ieee80211_vif_is_mld(vif) && |
| 908 | 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 | 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 | 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 | 963 | MT76_STA_INFO_STATE_ASSOC); |
| 916 | 964 | if (ret) |
| 917 | − return ret; | |
| 965 | + goto out_pm; | |
| 918 | 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 | 969 | MT76_STA_INFO_STATE_NONE); |
| 921 | 970 | if (ret) |
| 922 | − return ret; | |
| 971 | + goto out_pm; | |
| 923 | 972 | } |
| 924 | 973 | |
| 925 | 974 | mt76_connac_power_save_sched(&dev->mphy, &dev->pm); |
| 926 | 975 | |
| 927 | 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 | 1031 | static int |
| @@ -932,34 +1033,50 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, · 1 unmodified line | ||
| 932 | 1033 | struct ieee80211_sta *sta, unsigned long new_links) |
| 933 | 1034 | { |
| 934 | 1035 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1036 | + unsigned long added_links = 0; | |
| 935 | 1037 | unsigned int link_id; |
| 936 | 1038 | int err = 0; |
| 937 | 1039 | |
| 938 | 1040 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 939 | 1041 | struct ieee80211_link_sta *link_sta; |
| 940 | 1042 | struct mt792x_link_sta *mlink; |
| 1043 | + bool is_deflink = false; | |
| 941 | 1044 | |
| 942 | 1045 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { |
| 943 | 1046 | mlink = &msta->deflink; |
| 944 | − msta->deflink_id = link_id; | |
| 1047 | + is_deflink = true; | |
| 945 | 1048 | } else { |
| 946 | − mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); | |
| 1049 | + mlink = kzalloc(sizeof(*mlink), GFP_KERNEL); | |
| 947 | 1050 | if (!mlink) { |
| 948 | 1051 | err = -ENOMEM; |
| 949 | 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 | 1056 | mlink->sta = msta; |
| 956 | 1057 | mlink->pri_link = &sta->deflink; |
| 957 | 1058 | mlink->wcid.def_wcid = &msta->deflink.wcid; |
| 958 | 1059 | |
| 959 | 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 | 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 | 1099 | err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); |
| 983 | 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 | 1105 | return err; |
| @@ -1030,11 +1148,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, · 42 unmodified lines | ||
| 1030 | 1148 | struct mt792x_link_sta *mlink; |
| 1031 | 1149 | struct mt792x_sta *msta; |
| 1032 | 1150 | |
| 1151 | + mt792x_mutex_acquire(dev); | |
| 1152 | + | |
| 1033 | 1153 | msta = (struct mt792x_sta *)link_sta->sta->drv_priv; |
| 1034 | 1154 | mlink = mt792x_sta_to_link(msta, link_sta->link_id); |
| 1035 | 1155 | |
| 1036 | − mt792x_mutex_acquire(dev); | |
| 1037 | − | |
| 1038 | 1156 | if (ieee80211_vif_is_mld(vif)) { |
| 1039 | 1157 | link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); |
| 1040 | 1158 | } else { |
| @@ -1055,7 +1173,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, · 14 unmodified lines | ||
| 1055 | 1173 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 1056 | 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 | 1179 | mt792x_mutex_release(dev); |
| 1061 | 1180 | } |
| @@ -1083,23 +1202,21 @@ EXPORT_SYMBOL_GPL(mt7925_mac_sta_event); · 21 unmodified lines | ||
| 1083 | 1202 | |
| 1084 | 1203 | static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, |
| 1085 | 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 | 1208 | struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); |
| 1209 | + struct mt76_wcid *wcid = &mlink->wcid; | |
| 1089 | 1210 | struct ieee80211_bss_conf *link_conf; |
| 1090 | 1211 | u8 link_id = link_sta->link_id; |
| 1091 | − struct mt792x_link_sta *mlink; | |
| 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); | |
| 1212 | + u16 idx = wcid->idx; | |
| 1096 | 1213 | |
| 1097 | 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 | 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 | 1220 | MT76_STA_INFO_STATE_NONE); |
| 1104 | 1221 | mt7925_mac_wtbl_update(dev, mlink->wcid.idx, |
| 1105 | 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 | 1240 | list_del_init(&mlink->wcid.poll_list); |
| 1124 | 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 | 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 | 1254 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1134 | 1255 | struct mt76_dev *mdev = &dev->mt76; |
| 1135 | − struct mt76_wcid *wcid; | |
| 1136 | 1256 | unsigned int link_id; |
| 1137 | 1257 | |
| 1138 | 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 | 1291 | if (!link_sta) |
| 1172 | 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 | 1296 | if (!mlink) |
| 1176 | 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 | 1299 | msta->valid_links &= ~BIT(link_id); |
| 1183 | 1300 | mlink->sta = NULL; |
| 1184 | 1301 | mlink->pri_link = NULL; |
| 1185 | 1302 | |
| 1186 | − if (link_sta != mlink->pri_link) { | |
| 1187 | − mt76_wcid_cleanup(mdev, wcid); | |
| 1188 | − mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); | |
| 1189 | − } | |
| 1303 | + mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink); | |
| 1304 | + | |
| 1305 | + if (mlink != &msta->deflink) | |
| 1306 | + kfree_rcu(mlink, rcu_head); | |
| 1190 | 1307 | |
| 1191 | 1308 | if (msta->deflink_id == link_id) |
| 1192 | 1309 | msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; |
| @@ -1323,10 +1440,18 @@ void mt7925_mlo_pm_work(struct work_struct *work) · 130 unmodified lines | ||
| 1323 | 1440 | void mt7925_scan_work(struct work_struct *work) |
| 1324 | 1441 | { |
| 1325 | 1442 | struct mt792x_phy *phy; |
| 1443 | + struct mt792x_dev *dev; | |
| 1444 | + struct mt76_connac_pm *pm; | |
| 1326 | 1445 | |
| 1327 | 1446 | phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, |
| 1328 | 1447 | scan_work.work); |
| 1329 | 1448 | |
| 1449 | + dev = phy->dev; | |
| 1450 | + pm = &dev->pm; | |
| 1451 | + | |
| 1452 | + if (pm->suspended) | |
| 1453 | + return; | |
| 1454 | + | |
| 1330 | 1455 | while (true) { |
| 1331 | 1456 | struct sk_buff *skb; |
| 1332 | 1457 | struct tlv *tlv; |
| @@ -1544,8 +1669,10 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, · 211 unmodified lines | ||
| 1544 | 1669 | valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); |
| 1545 | 1670 | |
| 1546 | 1671 | for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 1672 | + struct mt792x_bss_conf *mconf; | |
| 1547 | 1673 | struct mt792x_link_sta *mlink; |
| 1548 | 1674 | |
| 1675 | + mconf = mt792x_vif_to_link(mvif, i); | |
| 1549 | 1676 | mlink = mt792x_sta_to_link(msta, i); |
| 1550 | 1677 | |
| 1551 | 1678 | if (enabled) |
| @@ -1556,7 +1683,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, · 4 unmodified lines | ||
| 1556 | 1683 | if (!mlink->wcid.sta) |
| 1557 | 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 | 1689 | mt792x_mutex_release(dev); |
| @@ -1716,7 +1843,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 153 unmodified lines | ||
| 1716 | 1843 | if (err) |
| 1717 | 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 | 1848 | MT76_STA_INFO_STATE_NONE); |
| 1721 | 1849 | out: |
| 1722 | 1850 | mt792x_mutex_release(dev); |
| @@ -1749,6 +1877,10 @@ static int · 26 unmodified lines | ||
| 1749 | 1877 | mt7925_add_chanctx(struct ieee80211_hw *hw, |
| 1750 | 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 | 1884 | return 0; |
| 1753 | 1885 | } |
| 1754 | 1886 | |
| @@ -1756,6 +1888,11 @@ static void · 1 unmodified line | ||
| 1756 | 1888 | mt7925_remove_chanctx(struct ieee80211_hw *hw, |
| 1757 | 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 | 1898 | static void |
| @@ -1850,7 +1987,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, · 88 unmodified lines | ||
| 1850 | 1987 | mt792x_mutex_acquire(dev); |
| 1851 | 1988 | |
| 1852 | 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 | 1992 | MT76_STA_INFO_STATE_ASSOC); |
| 1855 | 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 | 2032 | struct mt792x_phy *phy = mt792x_hw_phy(hw); |
| 1895 | 2033 | struct mt792x_dev *dev = mt792x_hw_dev(hw); |
| 1896 | 2034 | struct mt792x_bss_conf *mconf; |
| 1897 | − struct ieee80211_bss_conf *link_conf; | |
| 1898 | 2035 | |
| 1899 | 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 | 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 | 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 | 2078 | if (changed & BSS_CHANGED_CQM) |
| 1947 | 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 | 2276 | mctx->bss_conf = NULL; |
| 2145 | 2277 | mconf->mt76.ctx = NULL; |
| 2146 | 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 | 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 | 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 | 2413 | const struct ieee80211_ops mt7925_ops = { |
| 2162 | 2414 | .tx = mt792x_tx, |
| 2163 | 2415 | .start = mt7925_start, |
| @@ -2221,6 +2473,12 @@ const struct ieee80211_ops mt7925_ops = { · 57 unmodified lines | ||
| 2221 | 2473 | .change_vif_links = mt7925_change_vif_links, |
| 2222 | 2474 | .change_sta_links = mt7925_change_sta_links, |
| 2223 | 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 | 2483 | EXPORT_SYMBOL_GPL(mt7925_ops); |
| 2226 | 2484 | |
| @@ -1066,9 +1066,8 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware); · 1065 unmodified lines | ||
| 1066 | 1066 | static void |
| 1067 | 1067 | mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, |
| 1068 | 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 | 1071 | struct sta_rec_hdr_trans *hdr_trans; |
| 1073 | 1072 | struct mt76_wcid *wcid; |
| 1074 | 1073 | struct tlv *tlv; |
| @@ -1082,19 +1081,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, · 7 unmodified lines | ||
| 1082 | 1081 | else |
| 1083 | 1082 | hdr_trans->from_ds = true; |
| 1084 | 1083 | |
| 1085 | − if (link_sta) { | |
| 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) | |
| 1084 | + if (WARN_ON_ONCE(!mlink)) | |
| 1096 | 1085 | return; |
| 1097 | 1086 | |
| 1087 | + wcid = &mlink->wcid; | |
| 1088 | + | |
| 1098 | 1089 | hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); |
| 1099 | 1090 | if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { |
| 1100 | 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 | 1096 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, |
| 1106 | 1097 | struct ieee80211_vif *vif, |
| 1107 | − struct ieee80211_sta *sta, | |
| 1108 | − int link_id) | |
| 1098 | + struct mt792x_bss_conf *mconf, | |
| 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 | 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 | 1103 | skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, |
| 1124 | 1104 | &mlink->wcid, |
| 1125 | 1105 | MT7925_STA_UPDATE_MAX_SIZE); |
| 1126 | 1106 | if (IS_ERR(skb)) |
| 1127 | 1107 | return PTR_ERR(skb); |
| 1128 | 1108 | |
| 1129 | − /* starec hdr trans */ | |
| 1130 | − mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta); | |
| 1109 | + mt7925_mcu_sta_hdr_trans_tlv(skb, vif, mlink); | |
| 1131 | 1110 | return mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| 1132 | 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 | 1267 | return PTR_ERR(skb); |
| 1289 | 1268 | |
| 1290 | 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 | 1272 | return ret; |
| 1273 | + } | |
| 1293 | 1274 | |
| 1294 | 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, | |
| 1298 | − int duration, u8 token_id) | |
| 1278 | +int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, | |
| 1279 | + u16 sel_links, int duration, u8 token_id) | |
| 1299 | 1280 | { |
| 1300 | 1281 | struct mt792x_vif *mvif = mconf->vif; |
| 1301 | 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 | 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 | 1316 | if (!mconf || hweight16(vif->valid_links) < 2 || |
| 1334 | 1317 | hweight16(sel_links) != 2) |
| 1335 | 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 | 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 | 1340 | type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : |
| 1357 | 1341 | MT7925_ROC_REQ_MLSR_AA; |
| 1358 | 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 | 1705 | static void |
| 1722 | 1706 | mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, |
| 1723 | 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 | 1711 | struct sta_rec_amsdu *amsdu; |
| 1729 | 1712 | struct tlv *tlv; |
| 1730 | 1713 | |
| @@ -1740,7 +1723,6 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, · 9 unmodified lines | ||
| 1740 | 1723 | amsdu->max_amsdu_num = 8; |
| 1741 | 1724 | amsdu->amsdu_en = true; |
| 1742 | 1725 | |
| 1743 | − mlink = mt792x_sta_to_link(msta, link_sta->link_id); | |
| 1744 | 1726 | mlink->wcid.amsdu = true; |
| 1745 | 1727 | |
| 1746 | 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 | 1894 | static void |
| 1913 | 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 | 1901 | struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; |
| 1917 | 1902 | struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; |
| 1918 | − unsigned long valid = mvif->valid_links; | |
| 1919 | − struct mt792x_bss_conf *mconf; | |
| 1920 | − struct mt792x_link_sta *mlink; | |
| 1903 | + struct mt792x_dev *dev = mvif->phy->dev; | |
| 1904 | + struct mt792x_bss_conf *mconf_pri; | |
| 1921 | 1905 | struct sta_rec_mld *mld; |
| 1922 | 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 | 1924 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); |
| 1926 | 1925 | mld = (struct sta_rec_mld *)tlv; |
| 1927 | 1926 | memcpy(mld->mac_addr, sta->addr, ETH_ALEN); |
| 1927 | + | |
| 1928 | 1928 | mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); |
| 1929 | 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) { | |
| 1933 | − if (cnt == mld->link_num) | |
| 1934 | − break; | |
| 1931 | + /* Always encode primary link first. */ | |
| 1932 | + mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx); | |
| 1933 | + mld->link[cnt++].bss_idx = mconf_pri->mt76.idx; | |
| 1935 | 1934 | |
| 1936 | − mconf = mt792x_vif_to_link(mvif, i); | |
| 1937 | − mlink = mt792x_sta_to_link(msta, i); | |
| 1935 | + /* Optionally encode the currently-updated secondary link. */ | |
| 1936 | + if (mlink && mlink != &msta->deflink && mconf) { | |
| 1937 | + mld->secondary_id = cpu_to_le16(mlink->wcid.idx); | |
| 1938 | 1938 | mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); |
| 1939 | 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 | 1945 | static void |
| @@ -1961,10 +1960,12 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 14 unmodified lines | ||
| 1961 | 1960 | struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; |
| 1962 | 1961 | struct mt76_dev *dev = phy->dev; |
| 1963 | 1962 | struct mt792x_bss_conf *mconf; |
| 1963 | + struct mt792x_link_sta *mlink; | |
| 1964 | 1964 | struct sk_buff *skb; |
| 1965 | 1965 | int conn_state; |
| 1966 | 1966 | |
| 1967 | 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 | 1970 | skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, |
| 1970 | 1971 | MT7925_STA_UPDATE_MAX_SIZE); |
| @@ -1982,7 +1983,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, · 11 unmodified lines | ||
| 1982 | 1983 | mt7925_mcu_sta_ht_tlv(skb, info->link_sta); |
| 1983 | 1984 | mt7925_mcu_sta_vht_tlv(skb, info->link_sta); |
| 1984 | 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 | 1987 | mt7925_mcu_sta_he_tlv(skb, info->link_sta); |
| 1987 | 1988 | mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); |
| 1988 | 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 | 1994 | info->state); |
| 1994 | 1995 | |
| 1995 | 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 | 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 | 2007 | mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, |
| 2004 | 2008 | sizeof(struct tlv)); |
| 2005 | 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 | 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 | 2019 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, |
| 2013 | 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 | 2024 | enum mt76_sta_info_state state) |
| 2016 | 2025 | { |
| 2017 | 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 | 2035 | .offload_fw = true, |
| 2027 | 2036 | .rcpi = to_rcpi(rssi), |
| 2028 | 2037 | }; |
| 2029 | − struct mt792x_sta *msta; | |
| 2030 | − struct mt792x_link_sta *mlink; | |
| 2031 | 2038 | |
| 2032 | − if (link_sta) { | |
| 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; | |
| 2039 | + info.wcid = &mlink->wcid; | |
| 2037 | 2040 | info.newly = state != MT76_STA_INFO_STATE_ASSOC; |
| 2038 | 2041 | |
| 2039 | 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 | 2473 | struct ieee80211_bss_conf *link_conf, |
| 2471 | 2474 | struct ieee80211_link_sta *link_sta, |
| 2472 | 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 | 2479 | bool enable) |
| 2475 | 2480 | { |
| 2476 | 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 | 2484 | &link_conf->chanreq.oper; |
| 2480 | 2485 | enum nl80211_band band = chandef->chan->band; |
| 2481 | 2486 | struct mt76_connac_bss_basic_tlv *basic_req; |
| 2482 | − struct mt792x_link_sta *mlink; | |
| 2483 | 2487 | struct tlv *tlv; |
| 2484 | 2488 | int conn_type; |
| 2485 | 2489 | u8 idx; |
| @@ -2503,20 +2507,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, · 17 unmodified lines | ||
| 2503 | 2507 | basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); |
| 2504 | 2508 | basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); |
| 2505 | 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 | 2511 | basic_req->link_idx = mconf->mt76.idx; |
| 2508 | − | |
| 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); | |
| 2512 | + basic_req->sta_idx = cpu_to_le16(sta_wlan_idx); | |
| 2520 | 2513 | basic_req->omac_idx = mconf->mt76.omac_idx; |
| 2521 | 2514 | basic_req->band_idx = mconf->mt76.band_idx; |
| 2522 | 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 | 2816 | &dev_req, sizeof(dev_req), true); |
| 2824 | 2817 | } |
| 2825 | 2818 | |
| 2826 | −int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, | |
| 2827 | − struct ieee80211_chanctx_conf *ctx, | |
| 2828 | − struct ieee80211_bss_conf *link_conf, | |
| 2829 | − struct ieee80211_link_sta *link_sta, | |
| 2830 | − int enable) | |
| 2819 | +int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy, | |
| 2820 | + struct ieee80211_chanctx_conf *ctx, | |
| 2821 | + struct ieee80211_bss_conf *link_conf, | |
| 2822 | + struct ieee80211_link_sta *link_sta, | |
| 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 | 2827 | struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); |
| 2834 | 2828 | struct mt792x_dev *dev = phy->dev; |
| 2835 | − struct mt792x_link_sta *mlink_bc; | |
| 2836 | 2829 | struct sk_buff *skb; |
| 2837 | 2830 | |
| 2838 | 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 | 2833 | if (IS_ERR(skb)) |
| 2841 | 2834 | return PTR_ERR(skb); |
| 2842 | 2835 | |
| 2843 | − mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); | |
| 2844 | − | |
| 2845 | 2836 | /* bss_basic must be first */ |
| 2846 | 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 | 2839 | mt7925_mcu_bss_sec_tlv(skb, link_conf); |
| 2849 | 2840 | mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); |
| 2850 | 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 | 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 | 2886 | int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) |
| 2869 | 2887 | { |
| 2870 | 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 | 3393 | u8 rsvd[64]; |
| 3376 | 3394 | } __packed req = { |
| 3377 | 3395 | .tag = cpu_to_le16(0x3), |
| 3378 | − .len = cpu_to_le16(sizeof(req) - 4), | |
| 3379 | 3396 | |
| 3380 | 3397 | .idx = idx, |
| 3381 | 3398 | .env = env_cap, |
| @@ -3404,6 +3421,7 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, · 22 unmodified lines | ||
| 3404 | 3421 | memcpy(req.type, rule->type, 2); |
| 3405 | 3422 | |
| 3406 | 3423 | req.size = cpu_to_le16(seg->len); |
| 3424 | + req.len = cpu_to_le16(sizeof(req) + seg->len - 4); | |
| 3407 | 3425 | dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag; |
| 3408 | 3426 | skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, |
| 3409 | 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 | 3745 | memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2)); |
| 3728 | 3746 | tx_power_tlv->n_chan = num_ch; |
| 3729 | 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 | 3750 | switch (band) { |
| 3733 | 3751 | case NL80211_BAND_2GHZ: |
| @@ -693,6 +693,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, · 692 unmodified lines | ||
| 693 | 693 | struct ieee80211_bss_conf *link_conf, |
| 694 | 694 | struct ieee80211_link_sta *link_sta, |
| 695 | 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 | 703 | int mt7925_mcu_set_timing(struct mt792x_phy *phy, |
| 697 | 704 | struct ieee80211_bss_conf *link_conf); |
| 698 | 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 | 250 | bool enable); |
| 251 | 251 | int mt7925_mcu_sta_update(struct mt792x_dev *dev, |
| 252 | 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 | 256 | enum mt76_sta_info_state state); |
| 255 | 257 | int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); |
| 256 | 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 | 300 | void mt7925_mlo_pm_work(struct work_struct *work); |
| 299 | 301 | void mt7925_scan_work(struct work_struct *work); |
| 300 | 302 | void mt7925_roc_work(struct work_struct *work); |
| 303 | +void mt7925_csa_work(struct work_struct *work); | |
| 301 | 304 | int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, |
| 302 | 305 | struct ieee80211_bss_conf *link_conf); |
| 303 | 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 | 352 | int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); |
| 350 | 353 | int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, |
| 351 | 354 | enum environment_cap env_cap); |
| 352 | −int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, | |
| 353 | − int duration, u8 token_id); | |
| 355 | +int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, | |
| 356 | + u16 sel_links, int duration, u8 token_id); | |
| 354 | 357 | int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, |
| 355 | 358 | struct ieee80211_channel *chan, int duration, |
| 356 | 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 | 370 | int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); |
| 368 | 371 | int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, |
| 369 | 372 | struct ieee80211_vif *vif, |
| 370 | − struct ieee80211_sta *sta, | |
| 371 | − int link_id); | |
| 373 | + struct mt792x_bss_conf *mconf, | |
| 374 | + struct mt792x_link_sta *mlink); | |
| 372 | 375 | int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy); |
| 373 | 376 | |
| 374 | 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 | 232 | dev->regd_user) |
| 233 | 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 | 237 | return 0; |
| 237 | 238 | |
| 238 | 239 | /* do not need to update the same country twice */ |
| @@ -41,11 +41,13 @@ · 40 unmodified lines | ||
| 41 | 41 | #define MT792x_MCU_INIT_RETRY_COUNT 10 |
| 42 | 42 | #define MT792x_WFSYS_INIT_RETRY_COUNT 2 |
| 43 | 43 | |
| 44 | +#define MT7902_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7902_1.bin" | |
| 44 | 45 | #define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin" |
| 45 | 46 | #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" |
| 46 | 47 | #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" |
| 47 | 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 | 51 | #define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" |
| 50 | 52 | #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" |
| 51 | 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 | 98 | struct mt792x_link_sta { |
| 97 | 99 | struct mt76_wcid wcid; /* must be first */ |
| 100 | + struct rcu_head rcu_head; | |
| 98 | 101 | |
| 99 | 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 | 451 | static inline char *mt792x_ram_name(struct mt792x_dev *dev) |
| 449 | 452 | { |
| 450 | 453 | switch (mt76_chip(&dev->mt76)) { |
| 454 | + case 0x7902: | |
| 455 | + return MT7902_FIRMWARE_WM; | |
| 451 | 456 | case 0x7920: |
| 452 | 457 | return MT7920_FIRMWARE_WM; |
| 453 | 458 | case 0x7922: |
| @@ -462,6 +467,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev) · 8 unmodified lines | ||
| 462 | 467 | static inline char *mt792x_patch_name(struct mt792x_dev *dev) |
| 463 | 468 | { |
| 464 | 469 | switch (mt76_chip(&dev->mt76)) { |
| 470 | + case 0x7902: | |
| 471 | + return MT7902_ROM_PATCH; | |
| 465 | 472 | case 0x7920: |
| 466 | 473 | return MT7920_ROM_PATCH; |
| 467 | 474 | case 0x7922: |
| @@ -151,7 +151,7 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend) · 150 unmodified lines | ||
| 151 | 151 | cancel_work_sync(&dev->reset_work); |
| 152 | 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 | 155 | mt792x_mutex_acquire(dev); |
| 156 | 156 | mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); |
| 157 | 157 | mt792x_mutex_release(dev); |
| @@ -691,9 +691,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) · 533 unmodified lines | ||
| 691 | 691 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); |
| 692 | 692 | ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); |
| 693 | 693 | |
| 694 | − if (is_mt7921(&dev->mt76)) { | |
| 695 | − ieee80211_hw_set(hw, CHANCTX_STA_CSA); | |
| 696 | − } | |
| 694 | + ieee80211_hw_set(hw, CHANCTX_STA_CSA); | |
| 695 | + | |
| 697 | 696 | |
| 698 | 697 | if (dev->pm.enable) |
| 699 | 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 | 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 | 936 | ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); |
| 931 | 937 | if (ret) |
| 932 | 938 | return ret; |
| @@ -103,6 +103,22 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) · 102 unmodified lines | ||
| 103 | 103 | mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10)); |
| 104 | 104 | mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4)); |
| 105 | 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 | 122 | } else { |
| 107 | 123 | /* rx ring */ |
| 108 | 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 | 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 | 377 | mt76_clear(dev, addr, WFSYS_SW_RST_B); |
| 362 | 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 | 377 | if (!mt792x_mcu_fw_pmctrl(dev)) { |
| 378 | − cancel_delayed_work_sync(&mphy->mac_work); | |
| 378 | + cancel_delayed_work(&mphy->mac_work); | |
| 379 | 379 | return; |
| 380 | 380 | } |
| 381 | 381 | out: |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | ||
| 25 | 25 | #define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) |
| 26 | 26 | #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) |
| 27 | 27 | |
| 28 | +#define MT_PSE_BASE 0x820c8000 | |
| 29 | + | |
| 28 | 30 | /* TMAC: band 0(0x21000), band 1(0xa1000) */ |
| 29 | 31 | #define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) |
| 30 | 32 | #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) |
| @@ -390,6 +392,10 @@ · 359 unmodified lines | ||
| 390 | 392 | #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600) |
| 391 | 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 | 399 | #define MT_HW_BOUND 0x70010020 |
| 394 | 400 | #define MT_HW_CHIPID 0x70010200 |
| 395 | 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 | 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 | 236 | int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) |
| 210 | 237 | { |
| 211 | 238 | int err; |
| @@ -236,25 +263,33 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init); · 24 unmodified lines | ||
| 236 | 263 | |
| 237 | 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 | 269 | u32 val; |
| 240 | 270 | int i; |
| 241 | 271 | |
| 242 | 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 | 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 | 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 | 290 | for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) { |
| 256 | − val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS); | |
| 257 | − if (val & MT_UDMA_CONN_WFSYS_INIT_DONE) | |
| 291 | + val = mt792xu_uhw_rr(&dev->mt76, desc->done_reg); | |
| 292 | + if ((val & desc->done_mask) == desc->done_val) | |
| 258 | 293 | break; |
| 259 | 294 | |
| 260 | 295 | msleep(100); |
| @@ -226,14 +226,23 @@ mt7996_radar_trigger(void *data, u64 val) · 225 unmodified lines | ||
| 226 | 226 | #define RADAR_BACKGROUND 2 |
| 227 | 227 | struct mt7996_dev *dev = data; |
| 228 | 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 | 232 | if (!phy || !val || val > RADAR_BACKGROUND) |
| 232 | 233 | return -EINVAL; |
| 233 | 234 | |
| 234 | − if (val == RADAR_BACKGROUND && !dev->rdd2_phy) { | |
| 235 | − dev_err(dev->mt76.dev, "Background radar is not enabled\n"); | |
| 236 | − return -EINVAL; | |
| 235 | + if (test_bit(MT76_SCANNING, &phy->mt76->state)) | |
| 236 | + return -EBUSY; | |
| 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 | 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 | 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 | 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 | 641 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 628 | 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 | 644 | struct ieee80211_link_sta *link_sta; |
| 631 | 645 | struct seq_file *s = data; |
| 632 | 646 | struct ieee80211_vif *vif; |
| 647 | + struct mt7996_dev *dev; | |
| 633 | 648 | unsigned int link_id; |
| 634 | 649 | |
| 650 | + if (!phy) | |
| 651 | + return; | |
| 652 | + | |
| 635 | 653 | vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); |
| 654 | + dev = phy->dev; | |
| 636 | 655 | |
| 637 | 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 | 998 | #define LONG_PREAMBLE 1 |
| 980 | 999 | struct ieee80211_link_sta *link_sta = file->private_data; |
| 981 | 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 | 1002 | struct mt7996_sta_link *msta_link; |
| 984 | 1003 | struct ra_rate phy = {}; |
| 1004 | + struct mt7996_dev *dev; | |
| 985 | 1005 | char buf[100]; |
| 986 | 1006 | int ret; |
| 987 | 1007 | u16 gi, ltf; |
| 988 | 1008 | |
| 1009 | + if (!link_phy) | |
| 1010 | + return -EINVAL; | |
| 1011 | + | |
| 989 | 1012 | if (count >= sizeof(buf)) |
| 990 | 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 | 1031 | * spe - off: 0, on: 1 |
| 1009 | 1032 | * ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 |
| 1010 | 1033 | */ |
| 1034 | + dev = link_phy->dev; | |
| 1011 | 1035 | if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu", |
| 1012 | 1036 | &phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi, |
| 1013 | 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 | 129 | /* data tx queue */ |
| 130 | 130 | if (is_mt7996(&dev->mt76)) { |
| 131 | − TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); | |
| 132 | 131 | if (dev->hif2) { |
| 133 | − /* default bn1:ring19 bn2:ring21 */ | |
| 134 | − TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, | |
| 135 | − MT7996_TXQ_BAND1); | |
| 136 | − TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, | |
| 137 | − MT7996_TXQ_BAND2); | |
| 132 | + if (mt76_npu_device_active(&dev->mt76)) { | |
| 133 | + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND2, | |
| 134 | + MT7996_TXQ_BAND2); | |
| 135 | + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND0, | |
| 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 | 148 | } else { |
| 139 | 149 | /* single pcie bn0/1:ring18 bn2:ring19 */ |
| 150 | + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, | |
| 151 | + MT7996_TXQ_BAND0); | |
| 140 | 152 | TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, |
| 141 | 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 | 362 | if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76)) |
| 351 | 363 | irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) | |
| 352 | 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 | 368 | irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; |
| 354 | 369 | |
| 355 | 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 | 445 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 | |
| 431 | 446 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); |
| 432 | 447 | |
| 433 | − if (is_mt7996(&dev->mt76)) | |
| 434 | − mt76_set(dev, MT_WFDMA_HOST_CONFIG, | |
| 435 | − MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); | |
| 436 | − else | |
| 448 | + if (is_mt7996(&dev->mt76)) { | |
| 449 | + if (mt76_npu_device_active(&dev->mt76)) | |
| 450 | + mt76_set(dev, MT_WFDMA_HOST_CONFIG, | |
| 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 | 456 | mt76_set(dev, MT_WFDMA_HOST_CONFIG, |
| 438 | 457 | MT_WFDMA_HOST_CONFIG_BAND1_PCIE1); |
| 458 | + } | |
| 439 | 459 | |
| 440 | 460 | /* AXI read outstanding number */ |
| 441 | 461 | mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, |
| 442 | 462 | MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); |
| 443 | 463 | |
| 444 | − if (dev->hif2->speed < PCIE_SPEED_5_0GT || | |
| 445 | − (dev->hif2->speed == PCIE_SPEED_5_0GT && | |
| 446 | − dev->hif2->width < PCIE_LNK_X2)) { | |
| 447 | − mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | |
| 448 | − WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 449 | − FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 450 | − 0x1)); | |
| 451 | − mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, | |
| 452 | − MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 453 | − FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 454 | − 0x1)); | |
| 455 | − } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || | |
| 456 | − (dev->hif2->speed == PCIE_SPEED_8_0GT && | |
| 457 | − dev->hif2->width < PCIE_LNK_X2)) { | |
| 458 | − mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | |
| 459 | − WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 460 | − FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 461 | − 0x2)); | |
| 462 | − mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, | |
| 463 | − MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 464 | − FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 465 | − 0x2)); | |
| 464 | + if (!is_mt7996(&dev->mt76) || | |
| 465 | + !mt76_npu_device_active(&dev->mt76)) { | |
| 466 | + if (dev->hif2->speed < PCIE_SPEED_5_0GT || | |
| 467 | + (dev->hif2->speed == PCIE_SPEED_5_0GT && | |
| 468 | + dev->hif2->width < PCIE_LNK_X2)) { | |
| 469 | + mt76_rmw(dev, | |
| 470 | + WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | |
| 471 | + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 472 | + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 473 | + 0x1)); | |
| 474 | + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, | |
| 475 | + MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 476 | + FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, | |
| 477 | + 0x1)); | |
| 478 | + } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || | |
| 479 | + (dev->hif2->speed == PCIE_SPEED_8_0GT && | |
| 480 | + dev->hif2->width < PCIE_LNK_X2)) { | |
| 481 | + mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, | |
| 482 | + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 483 | + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, | |
| 484 | + 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 | 492 | /* WFDMA rx threshold */ |
| @@ -497,7 +521,7 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) · 28 unmodified lines | ||
| 497 | 521 | int mt7996_dma_rro_init(struct mt7996_dev *dev) |
| 498 | 522 | { |
| 499 | 523 | struct mt76_dev *mdev = &dev->mt76; |
| 500 | − u32 irq_mask; | |
| 524 | + u32 size; | |
| 501 | 525 | int ret; |
| 502 | 526 | |
| 503 | 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 | 548 | mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], |
| 525 | 549 | true); |
| 526 | 550 | } |
| 527 | − goto start_hw_rro; | |
| 551 | + | |
| 552 | + return 0; | |
| 528 | 553 | } |
| 529 | 554 | |
| 530 | 555 | /* ind cmd */ |
| @@ -545,10 +570,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 14 unmodified lines | ||
| 545 | 570 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 546 | 571 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 547 | 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 | 576 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], |
| 549 | 577 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), |
| 550 | − MT7996_RX_RING_SIZE, | |
| 551 | − MT7996_RX_MSDU_PAGE_SIZE, | |
| 578 | + size, MT7996_RX_MSDU_PAGE_SIZE, | |
| 552 | 579 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); |
| 553 | 580 | if (ret) |
| 554 | 581 | return ret; |
| @@ -560,10 +587,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 5 unmodified lines | ||
| 560 | 587 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 561 | 588 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 562 | 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 | 593 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], |
| 564 | 594 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), |
| 565 | − MT7996_RX_RING_SIZE, | |
| 566 | − MT7996_RX_MSDU_PAGE_SIZE, | |
| 595 | + size, MT7996_RX_MSDU_PAGE_SIZE, | |
| 567 | 596 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); |
| 568 | 597 | if (ret) |
| 569 | 598 | return ret; |
| @@ -576,52 +605,60 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) · 6 unmodified lines | ||
| 576 | 605 | if (mtk_wed_device_active(&mdev->mmio.wed) && |
| 577 | 606 | mtk_wed_get_rx_capa(&mdev->mmio.wed)) |
| 578 | 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 | 611 | ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], |
| 580 | 612 | MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), |
| 581 | − MT7996_RX_RING_SIZE, | |
| 582 | − MT7996_RX_MSDU_PAGE_SIZE, | |
| 613 | + size, MT7996_RX_MSDU_PAGE_SIZE, | |
| 583 | 614 | MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); |
| 584 | 615 | if (ret) |
| 585 | 616 | return ret; |
| 586 | 617 | } |
| 587 | 618 | |
| 588 | −start_hw_rro: | |
| 589 | − if (mtk_wed_device_active(&mdev->mmio.wed)) { | |
| 590 | − irq_mask = mdev->mmio.irqmask | | |
| 619 | + return 0; | |
| 620 | +} | |
| 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 | 628 | MT_INT_TX_DONE_BAND2; |
| 592 | 629 | |
| 593 | 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 | 633 | mt7996_irq_enable(dev, irq_mask); |
| 596 | − } else { | |
| 597 | − if (is_mt7996(&dev->mt76)) { | |
| 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 | − } | |
| 634 | + return; | |
| 635 | + } | |
| 608 | 636 | |
| 609 | − mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); | |
| 610 | − if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { | |
| 611 | − mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, | |
| 612 | − mt76_dma_rx_poll); | |
| 613 | − } else { | |
| 614 | − mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, | |
| 615 | − mt76_dma_rx_poll); | |
| 616 | − mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, | |
| 617 | − mt76_dma_rx_poll); | |
| 618 | − } | |
| 637 | + if (is_mt7996(&dev->mt76)) { | |
| 638 | + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, | |
| 639 | + mt76_dma_rx_poll); | |
| 640 | + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, | |
| 641 | + mt76_dma_rx_poll); | |
| 642 | + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, | |
| 643 | + mt76_dma_rx_poll); | |
| 644 | + } else { | |
| 645 | + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, | |
| 646 | + mt76_dma_rx_poll); | |
| 647 | + } | |
| 619 | 648 | |
| 620 | − if (!mt76_npu_device_active(&dev->mt76)) | |
| 621 | − mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); | |
| 649 | + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); | |
| 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 | 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 | 679 | mt7996_dma_disable(dev, true); |
| 643 | 680 | |
| 644 | 681 | /* init tx queue */ |
| 645 | − ret = mt7996_init_tx_queues(&dev->phy, | |
| 646 | − MT_TXQ_ID(dev->mphy.band_idx), | |
| 647 | − MT7996_TX_RING_SIZE, | |
| 648 | − MT_TXQ_RING_BASE(0), | |
| 649 | − wed); | |
| 682 | + if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) | |
| 683 | + ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0), | |
| 684 | + MT7996_NPU_TX_RING_SIZE, | |
| 685 | + MT_TXQ_RING_BASE(0) + hif1_ofs, | |
| 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 | 692 | if (ret) |
| 651 | 693 | return ret; |
| 652 | 694 | |
| @@ -714,6 +756,9 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 61 unmodified lines | ||
| 714 | 756 | (is_mt7992(&dev->mt76)))) { |
| 715 | 757 | dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; |
| 716 | 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 | 764 | if (mt7996_has_wa(dev)) { |
| @@ -846,6 +891,8 @@ int mt7996_dma_init(struct mt7996_dev *dev) · 126 unmodified lines | ||
| 846 | 891 | /* tx free notify event from WA for band0 */ |
| 847 | 892 | dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; |
| 848 | 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 | 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 | 908 | if (mt7996_band_valid(dev, MT_BAND2)) { |
| 909 | + u32 size; | |
| 910 | + | |
| 862 | 911 | /* rx rro data queue for band2 */ |
| 863 | 912 | dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = |
| 864 | 913 | MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; |
| 865 | 914 | if (mtk_wed_device_active(wed) && |
| 866 | 915 | mtk_wed_get_rx_capa(wed)) |
| 867 | 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 | 921 | ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], |
| 869 | 922 | MT_RXQ_ID(MT_RXQ_RRO_BAND2), |
| 870 | − MT7996_RX_RING_SIZE, | |
| 871 | − MT7996_RX_BUF_SIZE, | |
| 923 | + size, MT7996_RX_BUF_SIZE, | |
| 872 | 924 | MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); |
| 873 | 925 | if (ret) |
| 874 | 926 | return ret; |
| @@ -33,6 +33,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) · 32 unmodified lines | ||
| 33 | 33 | if (dev->var.fem == MT7996_FEM_INT) |
| 34 | 34 | return MT7992_EEPROM_DEFAULT_23_INT; |
| 35 | 35 | return MT7992_EEPROM_DEFAULT_23; |
| 36 | + case MT7992_VAR_TYPE_24: | |
| 37 | + return MT7992_EEPROM_DEFAULT_24; | |
| 36 | 38 | case MT7992_VAR_TYPE_44: |
| 37 | 39 | default: |
| 38 | 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 | 156 | dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); |
| 155 | 157 | memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); |
| 156 | − dev->flash_mode = true; | |
| 158 | + dev->eeprom_mode = EEPROM_MODE_DEFAULT_BIN; | |
| 157 | 159 | |
| 158 | 160 | out: |
| 159 | 161 | release_firmware(fw); |
| @@ -163,26 +165,31 @@ out: · 3 unmodified lines | ||
| 163 | 165 | |
| 164 | 166 | static int mt7996_eeprom_load(struct mt7996_dev *dev) |
| 165 | 167 | { |
| 168 | + u32 eeprom_blk_size, block_num; | |
| 166 | 169 | bool use_default = false; |
| 167 | − int ret; | |
| 170 | + int ret, i; | |
| 168 | 171 | |
| 169 | 172 | ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); |
| 170 | 173 | if (ret < 0) |
| 171 | 174 | return ret; |
| 172 | 175 | |
| 173 | 176 | if (ret && !mt7996_check_eeprom(dev)) { |
| 174 | − dev->flash_mode = true; | |
| 177 | + dev->eeprom_mode = EEPROM_MODE_FLASH; | |
| 175 | 178 | goto out; |
| 176 | 179 | } |
| 177 | 180 | |
| 178 | − if (!dev->flash_mode) { | |
| 179 | − u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; | |
| 180 | − u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); | |
| 181 | + memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); | |
| 182 | + if (mt7996_has_ext_eeprom(dev)) { | |
| 183 | + /* external eeprom mode */ | |
| 184 | + dev->eeprom_mode = EEPROM_MODE_EXT; | |
| 185 | + eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE; | |
| 186 | + } else { | |
| 181 | 187 | u8 free_block_num; |
| 182 | − int i; | |
| 183 | 188 | |
| 184 | − memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); | |
| 185 | − ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); | |
| 189 | + /* efuse mode */ | |
| 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 | 193 | if (ret < 0) |
| 187 | 194 | return ret; |
| 188 | 195 | |
| @@ -191,27 +198,29 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) · 2 unmodified lines | ||
| 191 | 198 | use_default = true; |
| 192 | 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 */ | |
| 196 | − if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || | |
| 197 | − mt7996_check_eeprom(dev)) { | |
| 216 | + if (i == block_num - 1) | |
| 217 | + len = MT7996_EEPROM_SIZE % eeprom_blk_size; | |
| 218 | + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, | |
| 219 | + NULL, len, dev->eeprom_mode); | |
| 220 | + if (ret && ret != -EINVAL) { | |
| 198 | 221 | use_default = true; |
| 199 | 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 | 226 | out: |
| @@ -385,7 +394,8 @@ bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev) · 167 unmodified lines | ||
| 385 | 394 | return false; |
| 386 | 395 | break; |
| 387 | 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 | 399 | return false; |
| 390 | 400 | break; |
| 391 | 401 | case MT7990_DEVICE_ID: { |
| @@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = { · 33 unmodified lines | ||
| 34 | 34 | BIT(NL80211_CHAN_WIDTH_40) | |
| 35 | 35 | BIT(NL80211_CHAN_WIDTH_80) | |
| 36 | 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 | 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 | 99 | .extended_capabilities_mask = if_types_ext_capa_ap, |
| 86 | 100 | .extended_capabilities_len = sizeof(if_types_ext_capa_ap), |
| 87 | 101 | .mld_capa_and_ops = |
| 102 | + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) | | |
| 88 | 103 | FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, |
| 89 | 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 | 500 | hw->vif_data_size = sizeof(struct mt7996_vif); |
| 486 | 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 | 505 | wiphy->n_iface_combinations = 1; |
| 490 | 506 | |
| 491 | 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 | 537 | ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); |
| 522 | 538 | ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); |
| 523 | 539 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); |
| 540 | + ieee80211_hw_set(hw, CHANCTX_STA_CSA); | |
| 524 | 541 | |
| 525 | 542 | hw->max_tx_fragments = 4; |
| 543 | + wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */ | |
| 526 | 544 | |
| 527 | 545 | /* init led callbacks */ |
| 528 | 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 | 610 | void mt7996_mac_init(struct mt7996_dev *dev) |
| 593 | 611 | { |
| 594 | 612 | #define HIF_TXD_V2_1 0x21 |
| 595 | − int i; | |
| 613 | + int i, rx_path_type; | |
| 596 | 614 | |
| 597 | 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 | 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 | 632 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, |
| 611 | − is_mt7996(&dev->mt76) ? 2 : 7); | |
| 612 | − else | |
| 633 | + rx_path_type); | |
| 634 | + } else { | |
| 613 | 635 | mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0); |
| 636 | + } | |
| 614 | 637 | |
| 615 | 638 | if (mt7996_has_hwrro(dev)) { |
| 616 | 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 | 691 | return 0; |
| 669 | 692 | |
| 670 | 693 | if (dev->hif2 && |
| 671 | − ((is_mt7996(&dev->mt76) && band == MT_BAND2) || | |
| 672 | − (is_mt7992(&dev->mt76) && band == MT_BAND1))) { | |
| 694 | + ((is_mt7992(&dev->mt76) && band == MT_BAND1) || | |
| 695 | + (is_mt7996(&dev->mt76) && band == MT_BAND2 && | |
| 696 | + !mt76_npu_device_active(&dev->mt76)))) { | |
| 673 | 697 | hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); |
| 674 | 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 | 733 | /* init wiphy according to mphy and phy */ |
| 710 | 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 | 739 | int i; |
| 714 | 740 | |
| 715 | 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 | 743 | } else { |
| 718 | − ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), | |
| 719 | − MT7996_TX_RING_SIZE, | |
| 744 | + int size = is_mt7996(&dev->mt76) && | |
| 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 | 749 | MT_TXQ_RING_BASE(band) + hif1_ofs, |
| 721 | 750 | wed); |
| 722 | 751 | if (ret) |
| @@ -756,15 +785,41 @@ static void mt7996_init_work(struct work_struct *work) · 33 unmodified lines | ||
| 756 | 785 | mt7996_mcu_set_eeprom(dev); |
| 757 | 786 | mt7996_mac_init(dev); |
| 758 | 787 | mt7996_txbf_init(dev); |
| 788 | + | |
| 789 | + if (!is_mt7990(&dev->mt76)) | |
| 790 | + mt7996_mcu_set_dup_wtbl(dev); | |
| 759 | 791 | } |
| 760 | 792 | |
| 761 | 793 | void mt7996_wfsys_reset(struct mt7996_dev *dev) |
| 762 | 794 | { |
| 763 | − mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); | |
| 764 | − msleep(20); | |
| 795 | + if (!is_mt7990(&dev->mt76)) { | |
| 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 | 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 | 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 | 898 | } else { |
| 844 | 899 | /* set emul 3.0 function */ |
| 845 | − mt76_wr(dev, MT_RRO_3_0_EMU_CONF, | |
| 846 | − MT_RRO_3_0_EMU_CONF_EN_MASK); | |
| 900 | + mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); | |
| 847 | 901 | |
| 848 | 902 | mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, |
| 849 | 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 | 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 | 998 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 939 | 999 | if (mtk_wed_device_active(&dev->mt76.mmio.wed) && |
| 940 | 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 | 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 | 1062 | mt7996_rro_hw_init(dev); |
| 999 | 1063 | |
| 1000 | 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 | 1145 | list); |
| 1082 | 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 | 1152 | goto reset_session; |
| 1153 | + } | |
| 1086 | 1154 | |
| 1087 | 1155 | for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { |
| 1088 | 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 | 1197 | else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) |
| 1130 | 1198 | var_type = MT7992_VAR_TYPE_44; |
| 1131 | 1199 | else |
| 1132 | − return -EINVAL; | |
| 1200 | + var_type = MT7992_VAR_TYPE_24; | |
| 1133 | 1201 | break; |
| 1134 | 1202 | case MT7990_DEVICE_ID: |
| 1135 | 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 | 1231 | if (ret) |
| 1164 | 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 | 1236 | if (ret && ret != -EINVAL) |
| 1168 | 1237 | return ret; |
| 1169 | 1238 | |
| @@ -1696,6 +1765,8 @@ int mt7996_register_device(struct mt7996_dev *dev) · 526 unmodified lines | ||
| 1696 | 1765 | if (ret) |
| 1697 | 1766 | return ret; |
| 1698 | 1767 | |
| 1768 | + mt7996_dma_rro_start(dev); | |
| 1769 | + | |
| 1699 | 1770 | ret = mt76_register_device(&dev->mt76, true, mt76_rates, |
| 1700 | 1771 | ARRAY_SIZE(mt76_rates)); |
| 1701 | 1772 | if (ret) |
| @@ -1726,6 +1797,7 @@ error: · 24 unmodified lines | ||
| 1726 | 1797 | |
| 1727 | 1798 | void mt7996_unregister_device(struct mt7996_dev *dev) |
| 1728 | 1799 | { |
| 1800 | + cancel_work_sync(&dev->dump_work); | |
| 1729 | 1801 | cancel_work_sync(&dev->wed_rro.work); |
| 1730 | 1802 | mt7996_unregister_phy(mt7996_phy3(dev)); |
| 1731 | 1803 | mt7996_unregister_phy(mt7996_phy2(dev)); |
| @@ -13,45 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 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 | 16 | static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, |
| 56 | 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 | 488 | !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) |
| 528 | 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 | 492 | status->flag |= RX_FLAG_FAILED_FCS_CRC; |
| 532 | 493 | |
| 533 | 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 | 662 | hdr = mt76_skb_get_hdr(skb); |
| 702 | 663 | fc = hdr->frame_control; |
| 664 | + if (ieee80211_is_beacon(fc)) | |
| 665 | + mt76_rx_beacon(mphy, skb); | |
| 703 | 666 | if (ieee80211_is_data_qos(fc)) { |
| 704 | 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 | 1102 | * req |
| 1140 | 1103 | */ |
| 1141 | 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 | 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 | 1110 | val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | |
| 1148 | 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 | 1124 | tx_info->buf[1].addr >> 32); |
| 1162 | 1125 | #endif |
| 1163 | 1126 | ptr[3] = cpu_to_le32(val); |
| 1127 | + | |
| 1128 | + tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size; | |
| 1164 | 1129 | } else { |
| 1165 | 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 | 1235 | if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) |
| 1271 | 1236 | return; |
| 1272 | 1237 | |
| 1273 | − if (!test_and_set_bit(tid, &wcid->ampdu_state)) | |
| 1274 | − ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); | |
| 1238 | + if (!test_and_set_bit(tid, &wcid->ampdu_state) && | |
| 1239 | + ieee80211_start_tx_ba_session(link_sta->sta, tid, 0)) | |
| 1240 | + clear_bit(tid, &wcid->ampdu_state); | |
| 1275 | 1241 | } |
| 1276 | 1242 | |
| 1277 | 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 | 2170 | for_each_vif_active_link(vif, link_conf, link_id) { |
| 2205 | 2171 | struct mt7996_vif_link *link; |
| 2172 | + struct mt7996_phy *link_phy; | |
| 2206 | 2173 | |
| 2207 | 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 | 2180 | continue; |
| 2210 | 2181 | |
| 2211 | 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 | 2220 | spin_unlock_bh(&dev->mt76.token_lock); |
| 2250 | 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 | 2230 | static int |
| @@ -2395,23 +2372,8 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) · 141 unmodified lines | ||
| 2395 | 2372 | struct mt7996_dev *dev = data; |
| 2396 | 2373 | int i; |
| 2397 | 2374 | |
| 2398 | − for (i = 0; i < ARRAY_SIZE(msta->link); i++) { | |
| 2399 | − struct mt7996_sta_link *msta_link = NULL; | |
| 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 | − } | |
| 2375 | + for (i = 0; i < ARRAY_SIZE(msta->link); i++) | |
| 2376 | + mt7996_mac_sta_remove_link(dev, sta, i, true); | |
| 2415 | 2377 | } |
| 2416 | 2378 | |
| 2417 | 2379 | static void |
| @@ -2544,6 +2506,7 @@ void mt7996_mac_reset_work(struct work_struct *work) · 126 unmodified lines | ||
| 2544 | 2506 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) |
| 2545 | 2507 | mtk_wed_device_stop(&dev->mt76.mmio.wed); |
| 2546 | 2508 | |
| 2509 | + mt7996_npu_hw_stop(dev); | |
| 2547 | 2510 | ieee80211_stop_queues(mt76_hw(dev)); |
| 2548 | 2511 | |
| 2549 | 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 | 2527 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) |
| 2565 | 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 | 2537 | napi_disable(&dev->mt76.napi[i]); |
| 2568 | 2538 | } |
| 2569 | 2539 | napi_disable(&dev->mt76.tx_napi); |
| 2570 | 2540 | |
| 2571 | 2541 | mutex_lock(&dev->mt76.mutex); |
| 2572 | 2542 | |
| 2573 | − mt7996_npu_hw_stop(dev); | |
| 2574 | − | |
| 2575 | 2543 | mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); |
| 2576 | 2544 | |
| 2577 | 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 | 2559 | mt7996_dma_start(dev, false, false); |
| 2592 | 2560 | |
| 2593 | 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 | 2564 | if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { |
| 2597 | 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 | 2578 | MT_INT_TX_RX_DONE_EXT); |
| 2611 | 2579 | } |
| 2612 | 2580 | |
| 2581 | + __mt7996_npu_hw_init(dev); | |
| 2582 | + | |
| 2613 | 2583 | clear_bit(MT76_MCU_RESET, &dev->mphy.state); |
| 2614 | 2584 | mt7996_for_each_phy(dev, phy) |
| 2615 | 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 | 2589 | mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) |
| 2620 | 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 | 2599 | napi_enable(&dev->mt76.napi[i]); |
| 2623 | 2600 | local_bh_disable(); |
| 2624 | 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 | 2617 | mutex_unlock(&dev->mt76.mutex); |
| 2641 | 2618 | |
| 2642 | − mt7996_npu_hw_init(dev); | |
| 2643 | − | |
| 2644 | 2619 | mt7996_for_each_phy(dev, phy) |
| 2645 | 2620 | ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, |
| 2646 | 2621 | MT7996_WATCHDOG_TIME); |
| @@ -2737,6 +2712,11 @@ void mt7996_reset(struct mt7996_dev *dev) · 90 unmodified lines | ||
| 2737 | 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 | 2720 | queue_work(dev->mt76.wq, &dev->reset_work); |
| 2741 | 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 | 2936 | mutex_unlock(&mphy->dev->mutex); |
| 2957 | 2937 | |
| 2938 | + mt76_beacon_mon_check(mphy); | |
| 2958 | 2939 | mt76_tx_status_check(mphy->dev, false); |
| 2959 | 2940 | |
| 2960 | 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 | 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 | 2960 | switch (dev->mt76.region) { |
| 2980 | 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 | 2970 | break; |
| 2990 | 2971 | } |
| 2991 | 2972 | |
| 2992 | − err = 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); | |
| 2973 | + return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); | |
| 2997 | 2974 | } |
| 2998 | 2975 | |
| 2999 | 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 | 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 | 2995 | int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) |
| 3053 | 2996 | { |
| 3054 | 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 | 3011 | goto stop; |
| 3069 | 3012 | |
| 3070 | 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 | 3014 | err = mt7996_dfs_start_radar_detector(phy); |
| 3076 | 3015 | if (err < 0) |
| 3077 | 3016 | return err; |
| @@ -37,9 +37,4 @@ struct mt7996_dfs_pattern { · 36 unmodified lines | ||
| 37 | 37 | u32 min_stgpr_diff; |
| 38 | 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 | 40 | #endif |
| @@ -56,7 +56,7 @@ static int mt7996_start(struct ieee80211_hw *hw) · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | mutex_lock(&dev->mt76.mutex); |
| 58 | 58 | ret = mt7996_mcu_set_hdr_trans(dev, true); |
| 59 | − if (!ret && is_mt7992(&dev->mt76)) { | |
| 59 | + if (!ret && !is_mt7996(&dev->mt76)) { | |
| 60 | 60 | u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); |
| 61 | 61 | |
| 62 | 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 | 80 | mutex_lock(&dev->mt76.mutex); |
| 81 | 81 | |
| 82 | + mt7996_mcu_rdd_resume_tx(phy); | |
| 82 | 83 | mt7996_mcu_set_radio_en(phy, false); |
| 83 | 84 | |
| 84 | 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 | 239 | link_conf = &vif->bss_conf; |
| 239 | 240 | |
| 240 | 241 | if (cmd == SET_KEY && !sta && !link->mt76.cipher) { |
| 242 | + struct mt7996_phy *phy = mt7996_vif_link_phy(link); | |
| 243 | + | |
| 241 | 244 | link->mt76.cipher = |
| 242 | 245 | mt76_connac_mcu_get_cipher(key->cipher); |
| 243 | − mt7996_mcu_add_bss_info(link->phy, vif, link_conf, | |
| 244 | − &link->mt76, msta_link, true); | |
| 246 | + if (phy) | |
| 247 | + mt7996_mcu_add_bss_info(phy, vif, link_conf, | |
| 248 | + &link->mt76, msta_link, true); | |
| 245 | 249 | } |
| 246 | 250 | |
| 247 | 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 | 304 | .cmd = SET_KEY, |
| 301 | 305 | .link_id = link_conf->link_id, |
| 302 | 306 | }; |
| 303 | − struct mt76_txq *mtxq; | |
| 304 | 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 | 317 | mlink->idx = __ffs64(~dev->mt76.vif_mask); |
| 307 | 318 | if (mlink->idx >= mt7996_max_interface_num(dev)) |
| 308 | 319 | return -ENOSPC; |
| @@ -316,7 +327,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, · 7 unmodified lines | ||
| 316 | 327 | return -ENOSPC; |
| 317 | 328 | |
| 318 | 329 | link->mld_idx = mld_idx; |
| 319 | − link->phy = phy; | |
| 320 | 330 | mlink->omac_idx = idx; |
| 321 | 331 | mlink->band_idx = band_idx; |
| 322 | 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 | 353 | mt7996_mac_wtbl_update(dev, idx, |
| 344 | 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 | 356 | if (vif->type != NL80211_IFTYPE_AP && |
| 352 | 357 | (!mlink->omac_idx || mlink->omac_idx > 3)) |
| 353 | 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 | 376 | ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); |
| 372 | 377 | |
| 373 | − if (!mlink->wcid->offchannel && | |
| 374 | − mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) | |
| 375 | − mvif->mt76.deflink_id = link_conf->link_id; | |
| 378 | + if (!mlink->wcid->offchannel) { | |
| 379 | + if (vif->txq && | |
| 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 | 401 | return 0; |
| 378 | 402 | } |
| 379 | 403 | |
| 380 | −void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, | |
| 381 | − struct ieee80211_bss_conf *link_conf, | |
| 382 | − struct mt76_vif_link *mlink) | |
| 404 | +static void mt7996_vif_link_destroy(struct mt7996_phy *phy, | |
| 405 | + struct mt7996_vif_link *link, | |
| 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 | 409 | struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| 386 | 410 | struct mt7996_sta_link *msta_link = &link->msta_link; |
| 387 | − struct mt7996_phy *phy = mphy->priv; | |
| 388 | − struct mt7996_dev *dev = phy->dev; | |
| 411 | + unsigned int link_id = msta_link->wcid.link_id; | |
| 412 | + struct mt76_vif_link *mlink = &link->mt76; | |
| 389 | 413 | struct mt7996_key_iter_data it = { |
| 390 | 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 | 418 | int idx = msta_link->wcid.idx; |
| 394 | 419 | |
| 420 | + if (!link_conf) | |
| 421 | + link_conf = &vif->bss_conf; | |
| 422 | + | |
| 395 | 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 | 426 | mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, |
| 399 | 427 | CONN_STATE_DISCONNECT, false); |
| 400 | 428 | mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false); |
| 401 | − | |
| 402 | 429 | mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); |
| 403 | 430 | |
| 404 | 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 | 433 | dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); |
| 421 | 434 | dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); |
| 422 | 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 | 439 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 425 | 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 | 442 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 428 | 443 | |
| 429 | 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 | 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 | 540 | mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), |
| 474 | 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 | 544 | mt7996_phy_set_rxfilter(phy); |
| 476 | 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 | 599 | static void mt7996_remove_interface(struct ieee80211_hw *hw, |
| 531 | 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 | 604 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 534 | 605 | struct mt7996_radio_data rdata = {}; |
| 606 | + unsigned int link_id; | |
| 535 | 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 | 625 | ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, |
| 538 | 626 | &rdata); |
| 539 | 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 | 900 | for_each_vif_active_link(vif, link_conf, link_id) { |
| 813 | 901 | struct mt7996_vif_link *link; |
| 902 | + struct mt7996_phy *phy; | |
| 814 | 903 | |
| 815 | 904 | link = mt7996_vif_link(dev, vif, link_id); |
| 816 | 905 | if (!link) |
| 817 | 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 | 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 | 920 | &link->mt76, &link->msta_link, |
| 824 | 921 | true); |
| 825 | 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 | 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 | 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 | 982 | if (changed & BSS_CHANGED_ERP_SLOT) { |
| 868 | 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 | 1042 | struct cfg80211_chan_def *chandef) |
| 928 | 1043 | { |
| 929 | 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 | 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 | 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 | 1123 | static int |
| @@ -941,30 +1128,22 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, · 4 unmodified lines | ||
| 941 | 1128 | { |
| 942 | 1129 | struct ieee80211_sta *sta = link_sta->sta; |
| 943 | 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 | 1132 | struct mt7996_sta_link *msta_link; |
| 946 | 1133 | int idx; |
| 947 | 1134 | |
| 1135 | + if (!phy) | |
| 1136 | + return -EINVAL; | |
| 1137 | + | |
| 948 | 1138 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); |
| 949 | 1139 | if (idx < 0) |
| 950 | 1140 | return -ENOSPC; |
| 951 | 1141 | |
| 952 | 1142 | if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { |
| 953 | − int i; | |
| 954 | − | |
| 955 | 1143 | msta_link = &msta->deflink; |
| 956 | 1144 | msta->deflink_id = link_id; |
| 957 | 1145 | msta->seclink_id = msta->deflink_id; |
| 958 | − | |
| 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 | − } | |
| 1146 | + mt7996_sta_init_txq_wcid(sta, idx); | |
| 968 | 1147 | } else { |
| 969 | 1148 | msta_link = kzalloc_obj(*msta_link); |
| 970 | 1149 | if (!msta_link) |
| @@ -1000,9 +1179,17 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, · 29 unmodified lines | ||
| 1000 | 1179 | return 0; |
| 1001 | 1180 | } |
| 1002 | 1181 | |
| 1003 | −void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, | |
| 1004 | − struct mt7996_sta_link *msta_link) | |
| 1182 | +void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, | |
| 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 | 1193 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 1007 | 1194 | if (!list_empty(&msta_link->wcid.poll_list)) |
| 1008 | 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 | 1198 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 1012 | 1199 | |
| 1013 | 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) { | |
| 1026 | − struct mt7996_sta_link *msta_link = NULL; | |
| 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; | |
| 1202 | + if (msta_link->wcid.link_valid) { | |
| 1203 | + struct mt7996_phy *phy; | |
| 1034 | 1204 | |
| 1035 | 1205 | mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, |
| 1036 | 1206 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 1037 | 1207 | |
| 1038 | − mt7996_mac_sta_deinit_link(dev, msta_link); | |
| 1039 | − link = mt7996_vif_link(dev, vif, link_id); | |
| 1040 | − if (!link) | |
| 1041 | − continue; | |
| 1208 | + phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); | |
| 1209 | + if (phy) | |
| 1210 | + phy->mt76->num_sta--; | |
| 1042 | 1211 | |
| 1043 | − mphy = mt76_vif_link_phy(&link->mt76); | |
| 1044 | − if (!mphy) | |
| 1045 | − continue; | |
| 1046 | − | |
| 1047 | − mphy->num_sta--; | |
| 1048 | 1212 | if (msta->deflink_id == link_id) { |
| 1049 | 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 | 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 | 1256 | static int |
| 1060 | 1257 | mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 1061 | 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 | 1264 | for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 1068 | 1265 | struct ieee80211_bss_conf *link_conf; |
| 1069 | 1266 | struct ieee80211_link_sta *link_sta; |
| 1267 | + struct mt7996_sta_link *msta_link; | |
| 1070 | 1268 | struct mt7996_vif_link *link; |
| 1071 | 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 | 1274 | continue; |
| 1275 | + } | |
| 1075 | 1276 | |
| 1076 | 1277 | link_conf = link_conf_dereference_protected(vif, link_id); |
| 1077 | 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 | 1309 | return 0; |
| 1109 | 1310 | |
| 1110 | 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 | 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 | 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 | 1330 | ret = mt7996_mac_sta_add_links(dev, vif, sta, add); |
| 1130 | 1331 | |
| 1131 | 1332 | mutex_unlock(&dev->mt76.mutex); |
| @@ -1234,10 +1435,12 @@ static void · 102 unmodified lines | ||
| 1234 | 1435 | mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 1235 | 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 | 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 | 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 | 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 | 1696 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 1493 | − struct mt7996_phy *phy = link->phy; | |
| 1494 | 1697 | union { |
| 1495 | 1698 | u64 t64; |
| 1496 | 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 | 1753 | n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 |
| 1551 | 1754 | : link->mt76.omac_idx; |
| 1552 | − phy = link->phy; | |
| 1755 | + phy = mt7996_vif_link_phy(link); | |
| 1553 | 1756 | if (!phy) |
| 1554 | 1757 | goto unlock; |
| 1555 | 1758 | |
| @@ -1583,7 +1786,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, · 27 unmodified lines | ||
| 1583 | 1786 | if (!link) |
| 1584 | 1787 | goto unlock; |
| 1585 | 1788 | |
| 1586 | − phy = link->phy; | |
| 1789 | + phy = mt7996_vif_link_phy(link); | |
| 1587 | 1790 | if (!phy) |
| 1588 | 1791 | goto unlock; |
| 1589 | 1792 | |
| @@ -1713,9 +1916,14 @@ static void mt7996_link_rate_ctrl_update(void *data, · 123 unmodified lines | ||
| 1713 | 1916 | struct mt7996_sta_link *msta_link) |
| 1714 | 1917 | { |
| 1715 | 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 | 1921 | u32 *changed = data; |
| 1718 | 1922 | |
| 1923 | + if (!phy) | |
| 1924 | + return; | |
| 1925 | + | |
| 1926 | + dev = phy->dev; | |
| 1719 | 1927 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 1720 | 1928 | |
| 1721 | 1929 | msta_link->changed |= *changed; |
| @@ -2204,6 +2412,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, · 482 unmodified lines | ||
| 2204 | 2412 | path->mtk_wdma.wdma_idx = wed->wdma_idx; |
| 2205 | 2413 | else |
| 2206 | 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 | 2419 | path->mtk_wdma.wdma_idx = link->mt76.band_idx; |
| 2208 | 2420 | path->mtk_wdma.bss = link->mt76.idx; |
| 2209 | 2421 | path->mtk_wdma.queue = 0; |
| @@ -2275,6 +2487,21 @@ mt7996_reconfig_complete(struct ieee80211_hw *hw, · 65 unmodified lines | ||
| 2275 | 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 | 2505 | const struct ieee80211_ops mt7996_ops = { |
| 2279 | 2506 | .add_chanctx = mt76_add_chanctx, |
| 2280 | 2507 | .remove_chanctx = mt76_remove_chanctx, |
| @@ -2306,6 +2533,7 @@ const struct ieee80211_ops mt7996_ops = { · 25 unmodified lines | ||
| 2306 | 2533 | .release_buffered_frames = mt76_release_buffered_frames, |
| 2307 | 2534 | .get_txpower = mt7996_get_txpower, |
| 2308 | 2535 | .channel_switch_beacon = mt7996_channel_switch_beacon, |
| 2536 | + .post_channel_switch = mt7996_post_channel_switch, | |
| 2309 | 2537 | .get_stats = mt7996_get_stats, |
| 2310 | 2538 | .get_et_sset_count = mt7996_get_et_sset_count, |
| 2311 | 2539 | .get_et_stats = mt7996_get_et_stats, |
| @@ -2337,4 +2565,5 @@ const struct ieee80211_ops mt7996_ops = { · 25 unmodified lines | ||
| 2337 | 2565 | .change_vif_links = mt7996_change_vif_links, |
| 2338 | 2566 | .change_sta_links = mt7996_mac_sta_change_links, |
| 2339 | 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 | 18 | case MT7992_VAR_TYPE_23: \ |
| 19 | 19 | _fw = MT7992_##name##_23; \ |
| 20 | 20 | break; \ |
| 21 | + case MT7992_VAR_TYPE_24: \ | |
| 22 | + _fw = MT7992_##name##_24; \ | |
| 23 | + break; \ | |
| 21 | 24 | default: \ |
| 22 | 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 | 128 | struct mt7996_vif_link *link, |
| 126 | 129 | __le16 *he_mcs, u16 mcs_map) |
| 127 | 130 | { |
| 131 | + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); | |
| 128 | 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; | |
| 130 | − const u16 *mask = link->bitrate_mask.control[band].he_mcs; | |
| 133 | + enum nl80211_band band; | |
| 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 | 142 | for (nss = 0; nss < max_nss; nss++) { |
| 133 | 143 | int mcs; |
| @@ -209,6 +219,7 @@ static int · 75 unmodified lines | ||
| 209 | 219 | mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, |
| 210 | 220 | struct sk_buff *skb, int seq) |
| 211 | 221 | { |
| 222 | + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); | |
| 212 | 223 | struct mt7996_mcu_rxd *rxd; |
| 213 | 224 | struct mt7996_mcu_uni_event *event; |
| 214 | 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 | 228 | if (!skb) { |
| 218 | 229 | dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", |
| 219 | 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 | 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 | 252 | event = (struct mt7996_mcu_uni_event *)skb->data; |
| 234 | 253 | ret = le32_to_cpu(event->status); |
| 235 | 254 | /* skip invalid event */ |
| 236 | − if (mcu_cmd != event->cid) | |
| 255 | + if (mcu_cmd != le16_to_cpu(event->cid)) | |
| 237 | 256 | ret = -EAGAIN; |
| 238 | 257 | } else { |
| 239 | 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 | 278 | mdev->mcu.timeout = 2 * HZ; |
| 260 | 279 | return; |
| 261 | 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 | 283 | return; |
| 264 | 284 | default: |
| 265 | 285 | break; |
| @@ -313,13 +333,12 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, · 47 unmodified lines | ||
| 313 | 333 | uni_txd->pkt_type = MCU_PKT_ID; |
| 314 | 334 | uni_txd->seq = seq; |
| 315 | 335 | |
| 316 | − if (cmd & __MCU_CMD_FIELD_QUERY) | |
| 317 | − uni_txd->option = MCU_CMD_UNI_QUERY_ACK; | |
| 318 | − else | |
| 319 | − uni_txd->option = MCU_CMD_UNI_EXT_ACK; | |
| 336 | + uni_txd->option = MCU_CMD_UNI; | |
| 337 | + if (!(cmd & __MCU_CMD_FIELD_QUERY)) | |
| 338 | + uni_txd->option |= MCU_CMD_SET; | |
| 320 | 339 | |
| 321 | − if (mcu_cmd == MCU_UNI_CMD_SDO) | |
| 322 | − uni_txd->option &= ~MCU_CMD_ACK; | |
| 340 | + if (wait_seq) | |
| 341 | + uni_txd->option |= MCU_CMD_ACK; | |
| 323 | 342 | |
| 324 | 343 | if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) |
| 325 | 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 | 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 | 417 | static void |
| 394 | 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 | 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 | 525 | static void |
| @@ -416,24 +539,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) · 13 unmodified lines | ||
| 416 | 539 | break; |
| 417 | 540 | case MT_RDD_IDX_BACKGROUND: |
| 418 | 541 | if (!dev->rdd2_phy) |
| 419 | − return; | |
| 542 | + goto err; | |
| 420 | 543 | mphy = dev->rdd2_phy->mt76; |
| 421 | 544 | break; |
| 422 | 545 | default: |
| 423 | − dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); | |
| 424 | − return; | |
| 546 | + goto err; | |
| 425 | 547 | } |
| 426 | 548 | |
| 427 | 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 | 553 | cfg80211_background_radar_event(mphy->hw->wiphy, |
| 432 | 554 | &dev->rdd2_chandef, |
| 433 | 555 | GFP_ATOMIC); |
| 434 | − else | |
| 556 | + } else { | |
| 557 | + struct mt7996_phy *phy = mphy->priv; | |
| 558 | + | |
| 559 | + phy->rdd_tx_paused = true; | |
| 435 | 560 | ieee80211_radar_detected(mphy->hw, NULL); |
| 561 | + } | |
| 436 | 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 | 570 | static void |
| @@ -476,57 +607,6 @@ out: · 36 unmodified lines | ||
| 476 | 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 | 610 | static int |
| 531 | 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 | 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 | 1370 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, |
| 1174 | 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 | 1976 | #define EBF_MODE BIT(0) |
| 1780 | 1977 | #define IBF_MODE BIT(1) |
| 1781 | 1978 | #define BF_MAT_ORDER 4 |
| 1979 | + struct mt7996_phy *phy = mt7996_vif_link_phy(link); | |
| 1782 | 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 | 1981 | struct sta_rec_bf *bf; |
| 1786 | 1982 | struct tlv *tlv; |
| 1787 | 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 | 1986 | {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ |
| 1791 | 1987 | {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ |
| 1792 | 1988 | }; |
| 1989 | + int tx_ant; | |
| 1793 | 1990 | bool ebf; |
| 1794 | 1991 | |
| 1992 | + if (!phy) | |
| 1993 | + return; | |
| 1994 | + | |
| 1795 | 1995 | if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) |
| 1796 | 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 | 2007 | * ht: iBF only, since mac80211 lacks of eBF support |
| 1808 | 2008 | */ |
| 1809 | 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 | 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 | 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 | 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 | 2017 | else |
| 1818 | 2018 | return; |
| 1819 | 2019 | |
| 1820 | 2020 | bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0); |
| 2021 | + tx_ant = hweight16(phy->mt76->chainmask) - 1; | |
| 1821 | 2022 | if (is_mt7992(&dev->mt76) && tx_ant == 4) |
| 1822 | 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 | 2050 | struct ieee80211_link_sta *link_sta, |
| 1850 | 2051 | struct mt7996_vif_link *link) |
| 1851 | 2052 | { |
| 1852 | − struct mt7996_phy *phy = link->phy; | |
| 1853 | − int tx_ant = hweight8(phy->mt76->antenna_mask) - 1; | |
| 2053 | + struct mt7996_phy *phy = mt7996_vif_link_phy(link); | |
| 1854 | 2054 | struct sta_rec_bfee *bfee; |
| 1855 | 2055 | struct tlv *tlv; |
| 1856 | 2056 | u8 nrow = 0; |
| 2057 | + int tx_ant; | |
| 2058 | + | |
| 2059 | + if (!phy) | |
| 2060 | + return; | |
| 1857 | 2061 | |
| 1858 | 2062 | if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he)) |
| 1859 | 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 | 2083 | /* reply with identity matrix to avoid 2x2 BF negative gain */ |
| 2084 | + tx_ant = hweight8(phy->mt76->antenna_mask) - 1; | |
| 1880 | 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 | 2265 | struct ieee80211_sta *sta; |
| 2061 | 2266 | int ret, nrates = 0, idx; |
| 2062 | 2267 | enum nl80211_band band; |
| 2268 | + struct mt76_phy *mphy; | |
| 2063 | 2269 | bool has_he; |
| 2064 | 2270 | |
| 2065 | 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 | 2299 | if (!link_sta) |
| 2094 | 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 | 2307 | has_he = link_sta->he_cap.has_he; |
| 2098 | 2308 | mask = link->bitrate_mask; |
| 2099 | 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 | 2383 | struct mt7996_vif_link *link) |
| 2174 | 2384 | { |
| 2175 | 2385 | #define INIT_RCPI 180 |
| 2176 | − struct mt76_phy *mphy = link->phy->mt76; | |
| 2177 | − struct cfg80211_chan_def *chandef = &mphy->chandef; | |
| 2386 | + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); | |
| 2178 | 2387 | struct cfg80211_bitrate_mask *mask = &link->bitrate_mask; |
| 2179 | 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 | 2390 | struct sta_rec_ra_uni *ra; |
| 2391 | + enum nl80211_band band; | |
| 2182 | 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 | 2398 | tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); |
| 2186 | 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 | 2405 | ra->valid = true; |
| 2189 | 2406 | ra->auto_rate = true; |
| 2190 | 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 | 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 | 2652 | static void |
| 2370 | 2653 | mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, |
| 2371 | 2654 | struct ieee80211_vif *vif, |
| @@ -2529,6 +2812,53 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, · 157 unmodified lines | ||
| 2529 | 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 | 2862 | static int |
| 2533 | 2863 | mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid, |
| 2534 | 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 | 3007 | info = (struct bss_bcn_cntdwn_tlv *)tlv; |
| 2678 | 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 | 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 | 3109 | struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| 2770 | 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 | 3112 | struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; |
| 2772 | 3113 | struct ieee80211_mutable_offsets offs; |
| 2773 | 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 | 3123 | if (!mlink) |
| 2783 | 3124 | return -EINVAL; |
| 2784 | 3125 | |
| 2785 | − if (link->phy && link->phy->mt76->offchannel) | |
| 3126 | + if (mphy && mphy->offchannel) | |
| 2786 | 3127 | enabled = false; |
| 2787 | 3128 | |
| 2788 | 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 | 3175 | #define OFFLOAD_TX_MODE_SU BIT(0) |
| 2835 | 3176 | #define OFFLOAD_TX_MODE_MU BIT(1) |
| 3177 | + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); | |
| 2836 | 3178 | struct ieee80211_vif *vif = link_conf->vif; |
| 2837 | 3179 | struct ieee80211_hw *hw = mt76_hw(dev); |
| 2838 | − struct mt7996_phy *phy = link->phy; | |
| 2839 | 3180 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; |
| 2840 | 3181 | struct bss_inband_discovery_tlv *discov; |
| 2841 | 3182 | struct ieee80211_tx_info *info; |
| @@ -2846,10 +3187,10 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, · 4 unmodified lines | ||
| 2846 | 3187 | u8 *buf, interval; |
| 2847 | 3188 | int len; |
| 2848 | 3189 | |
| 2849 | − if (!phy) | |
| 3190 | + if (!mphy) | |
| 2850 | 3191 | return -EINVAL; |
| 2851 | 3192 | |
| 2852 | − chandef = &phy->mt76->chandef; | |
| 3193 | + chandef = &mphy->chandef; | |
| 2853 | 3194 | band = chandef->chan->band; |
| 2854 | 3195 | |
| 2855 | 3196 | if (link_conf->nontransmitted) |
| @@ -2887,7 +3228,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, · 31 unmodified lines | ||
| 2887 | 3228 | info = IEEE80211_SKB_CB(skb); |
| 2888 | 3229 | info->control.vif = vif; |
| 2889 | 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 | 3233 | len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); |
| 2893 | 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 | 4084 | if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) |
| 3744 | 4085 | req.switch_reason = CH_SWITCH_NORMAL; |
| 3745 | − else if (phy->mt76->offchannel || | |
| 3746 | − phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) | |
| 4086 | + else if (phy->mt76->offchannel || !phy->mt76->chanctx) | |
| 3747 | 4087 | req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; |
| 3748 | 4088 | else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, |
| 3749 | 4089 | NL80211_IFTYPE_AP)) |
| @@ -3764,23 +4104,173 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) · 14 unmodified lines | ||
| 3764 | 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 | 4255 | #define MAX_PAGE_IDX_MASK GENMASK(7, 5) |
| 3770 | 4256 | #define PAGE_IDX_MASK GENMASK(4, 2) |
| 3771 | 4257 | #define PER_PAGE_SIZE 0x400 |
| 3772 | − struct mt7996_mcu_eeprom req = { | |
| 4258 | + struct mt7996_mcu_eeprom_update req = { | |
| 3773 | 4259 | .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), |
| 3774 | 4260 | .buffer_mode = EE_MODE_BUFFER |
| 3775 | 4261 | }; |
| 3776 | 4262 | u16 eeprom_size = MT7996_EEPROM_SIZE; |
| 3777 | 4263 | u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); |
| 3778 | 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 | 4271 | for (i = 0; i < total; i++, eep += eep_len) { |
| 3782 | 4272 | struct sk_buff *skb; |
| 3783 | − int ret, msg_len; | |
| 4273 | + int msg_len; | |
| 3784 | 4274 | |
| 3785 | 4275 | if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) |
| 3786 | 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 | 4299 | return 0; |
| 3810 | 4300 | } |
| 3811 | 4301 | |
| 3812 | −int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) | |
| 3813 | −{ | |
| 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) | |
| 4302 | +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, | |
| 4303 | + enum mt7996_eeprom_mode mode) | |
| 3829 | 4304 | { |
| 3830 | − struct { | |
| 3831 | − u8 _rsv[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)), | |
| 4305 | + struct mt7996_mcu_eeprom_access req = { | |
| 4306 | + .info.len = cpu_to_le16(sizeof(req) - 4), | |
| 3843 | 4307 | }; |
| 4308 | + struct mt7996_mcu_eeprom_access_event *event; | |
| 3844 | 4309 | struct sk_buff *skb; |
| 3845 | − bool valid; | |
| 3846 | − int ret; | |
| 4310 | + int ret, cmd; | |
| 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, | |
| 3849 | − MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), | |
| 3850 | − &req, sizeof(req), true, &skb); | |
| 4329 | + req.info.addr = cpu_to_le32(addr); | |
| 4330 | + ret = mt76_mcu_send_and_get_msg(&dev->mt76, cmd, &req, sizeof(req), | |
| 4331 | + true, &skb); | |
| 3851 | 4332 | if (ret) |
| 3852 | 4333 | return ret; |
| 3853 | 4334 | |
| 3854 | − valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); | |
| 3855 | − if (valid) { | |
| 3856 | − u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); | |
| 4335 | + event = (struct mt7996_mcu_eeprom_access_event *)skb->data; | |
| 4336 | + if (event->valid) { | |
| 4337 | + u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len); | |
| 4338 | + | |
| 4339 | + addr = le32_to_cpu(event->addr); | |
| 3857 | 4340 | |
| 3858 | 4341 | if (!buf) |
| 3859 | 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); | |
| 3864 | − memcpy(buf, skb->data, buf_len); | |
| 4344 | + switch (mode) { | |
| 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 | 4362 | } else { |
| 3866 | 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 | 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 | 4373 | struct { |
| 3877 | 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 | 4401 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) |
| 3905 | 4402 | { |
| 3906 | −#define NIC_CAP 3 | |
| 3907 | 4403 | #define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21 |
| 3908 | 4404 | struct { |
| 3909 | 4405 | u8 _rsv[4]; |
| @@ -3911,7 +4407,7 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) · 1 unmodified line | ||
| 3911 | 4407 | __le16 tag; |
| 3912 | 4408 | __le16 len; |
| 3913 | 4409 | } __packed req = { |
| 3914 | − .tag = cpu_to_le16(NIC_CAP), | |
| 4410 | + .tag = cpu_to_le16(UNI_CHIP_CONFIG_NIC_CAPA), | |
| 3915 | 4411 | .len = cpu_to_le16(sizeof(req) - 4), |
| 3916 | 4412 | }; |
| 3917 | 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 | 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 | 5087 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) |
| 4563 | 5088 | { |
| 4564 | 5089 | struct { |
| @@ -4889,3 +5414,25 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode) · 324 unmodified lines | ||
| 4889 | 5414 | return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), |
| 4890 | 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 | 27 | struct mt7996_mcu_uni_event { |
| 28 | − u8 cid; | |
| 29 | − u8 __rsv[3]; | |
| 28 | + __le16 cid; | |
| 29 | + u8 __rsv[2]; | |
| 30 | 30 | __le32 status; /* 0: success, others: fail */ |
| 31 | 31 | } __packed; |
| 32 | 32 | |
| @@ -52,12 +52,10 @@ struct mt7996_mcu_thermal_enable { · 19 unmodified lines | ||
| 52 | 52 | u8 rsv[2]; |
| 53 | 53 | } __packed; |
| 54 | 54 | |
| 55 | −struct mt7996_mcu_csa_notify { | |
| 56 | − struct mt7996_mcu_rxd rxd; | |
| 57 | − | |
| 55 | +struct mt7996_mcu_countdown_notify { | |
| 58 | 56 | u8 omac_idx; |
| 59 | − u8 csa_count; | |
| 60 | − u8 band_idx; | |
| 57 | + u8 count; | |
| 58 | + u8 csa_failure_reason; /* 0: success, 1: beacon disabled */ | |
| 61 | 59 | u8 rsv; |
| 62 | 60 | } __packed; |
| 63 | 61 | |
| @@ -147,7 +145,7 @@ struct mt7996_mcu_background_chain_ctrl { · 83 unmodified lines | ||
| 147 | 145 | u8 rsv[2]; |
| 148 | 146 | } __packed; |
| 149 | 147 | |
| 150 | −struct mt7996_mcu_eeprom { | |
| 148 | +struct mt7996_mcu_eeprom_update { | |
| 151 | 149 | u8 _rsv[4]; |
| 152 | 150 | |
| 153 | 151 | __le16 tag; |
| @@ -157,6 +155,43 @@ struct mt7996_mcu_eeprom { · 3 unmodified lines | ||
| 157 | 155 | __le16 buf_len; |
| 158 | 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 | 195 | struct mt7996_mcu_phy_rx_info { |
| 161 | 196 | u8 category; |
| 162 | 197 | u8 rate; |
| @@ -414,7 +449,16 @@ struct bss_bcn_cntdwn_tlv { · 251 unmodified lines | ||
| 414 | 449 | __le16 tag; |
| 415 | 450 | __le16 len; |
| 416 | 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 | 462 | } __packed; |
| 419 | 463 | |
| 420 | 464 | struct bss_bcn_mbss_tlv { |
| @@ -474,6 +518,24 @@ struct bss_mld_tlv { · 53 unmodified lines | ||
| 474 | 518 | u8 __rsv[2]; |
| 475 | 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 | 539 | struct sta_rec_ht_uni { |
| 478 | 540 | __le16 tag; |
| 479 | 541 | __le16 len; |
| @@ -647,6 +709,28 @@ struct mld_setup_link { · 167 unmodified lines | ||
| 647 | 709 | u8 __rsv; |
| 648 | 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 | 734 | struct hdr_trans_en { |
| 651 | 735 | __le16 tag; |
| 652 | 736 | __le16 len; |
| @@ -791,6 +875,11 @@ enum { · 138 unmodified lines | ||
| 791 | 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 | 883 | #define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ |
| 795 | 884 | sizeof(struct mt76_connac_bss_basic_tlv) + \ |
| 796 | 885 | sizeof(struct bss_rlm_tlv) + \ |
| @@ -837,6 +926,7 @@ enum { · 40 unmodified lines | ||
| 837 | 926 | enum { |
| 838 | 927 | UNI_BAND_CONFIG_RADIO_ENABLE, |
| 839 | 928 | UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, |
| 929 | + UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, | |
| 840 | 930 | }; |
| 841 | 931 | |
| 842 | 932 | enum { |
| @@ -856,6 +946,10 @@ enum { · 13 unmodified lines | ||
| 856 | 946 | UNI_EFUSE_BUFFER_RD, |
| 857 | 947 | }; |
| 858 | 948 | |
| 949 | +enum { | |
| 950 | + UNI_EXT_EEPROM_ACCESS = 1, | |
| 951 | +}; | |
| 952 | + | |
| 859 | 953 | enum { |
| 860 | 954 | UNI_VOW_DRR_CTRL, |
| 861 | 955 | UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, |
| @@ -29,6 +29,10 @@ · 28 unmodified lines | ||
| 29 | 29 | #define MT7996_RX_RING_SIZE 1536 |
| 30 | 30 | #define MT7996_RX_MCU_RING_SIZE 512 |
| 31 | 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 | 36 | /* scatter-gather of mcu event is not supported in connac3 */ |
| 33 | 37 | #define MT7996_RX_MCU_BUF_SIZE (2048 + \ |
| 34 | 38 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
| @@ -60,6 +64,11 @@ · 25 unmodified lines | ||
| 60 | 64 | #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" |
| 61 | 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 | 72 | #define MT7990_FIRMWARE_WA "" |
| 64 | 73 | #define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" |
| 65 | 74 | #define MT7990_FIRMWARE_DSP "" |
| @@ -75,12 +84,14 @@ · 9 unmodified lines | ||
| 75 | 84 | #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" |
| 76 | 85 | #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" |
| 77 | 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 | 89 | #define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" |
| 80 | 90 | #define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" |
| 81 | 91 | |
| 82 | 92 | #define MT7996_EEPROM_SIZE 7680 |
| 83 | 93 | #define MT7996_EEPROM_BLOCK_SIZE 16 |
| 94 | +#define MT7996_EXT_EEPROM_BLOCK_SIZE 1024 | |
| 84 | 95 | #define MT7996_TOKEN_SIZE 16384 |
| 85 | 96 | #define MT7996_HW_TOKEN_SIZE 8192 |
| 86 | 97 | |
| @@ -153,6 +164,7 @@ enum mt7996_var_type { · 66 unmodified lines | ||
| 153 | 164 | enum mt7992_var_type { |
| 154 | 165 | MT7992_VAR_TYPE_44, |
| 155 | 166 | MT7992_VAR_TYPE_23, |
| 167 | + MT7992_VAR_TYPE_24, | |
| 156 | 168 | }; |
| 157 | 169 | |
| 158 | 170 | enum mt7990_var_type { |
| @@ -165,6 +177,18 @@ enum mt7996_fem_type { · 6 unmodified lines | ||
| 165 | 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 | 192 | enum mt7996_txq_id { |
| 169 | 193 | MT7996_TXQ_FWDL = 16, |
| 170 | 194 | MT7996_TXQ_MCU_WM, |
| @@ -252,8 +276,6 @@ struct mt7996_vif_link { · 81 unmodified lines | ||
| 252 | 276 | struct mt76_vif_link mt76; /* must be first */ |
| 253 | 277 | |
| 254 | 278 | struct mt7996_sta_link msta_link; |
| 255 | − struct mt7996_phy *phy; | |
| 256 | − | |
| 257 | 279 | struct cfg80211_bitrate_mask bitrate_mask; |
| 258 | 280 | |
| 259 | 281 | u8 mld_idx; |
| @@ -377,6 +399,7 @@ struct mt7996_phy { · 117 unmodified lines | ||
| 377 | 399 | |
| 378 | 400 | bool has_aux_rx; |
| 379 | 401 | bool counter_reset; |
| 402 | + bool rdd_tx_paused; | |
| 380 | 403 | }; |
| 381 | 404 | |
| 382 | 405 | struct mt7996_dev { |
| @@ -436,7 +459,7 @@ struct mt7996_dev { · 53 unmodified lines | ||
| 436 | 459 | |
| 437 | 460 | u32 hw_pattern; |
| 438 | 461 | |
| 439 | − bool flash_mode:1; | |
| 462 | + u8 eeprom_mode; | |
| 440 | 463 | bool has_eht:1; |
| 441 | 464 | |
| 442 | 465 | struct { |
| @@ -473,6 +496,8 @@ struct mt7996_dev { · 30 unmodified lines | ||
| 473 | 496 | struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE]; |
| 474 | 497 | } wed_rro; |
| 475 | 498 | |
| 499 | + dma_addr_t npu_txd_addr[2 * MT7996_NPU_TXD_SIZE]; | |
| 500 | + | |
| 476 | 501 | bool ibf; |
| 477 | 502 | u8 fw_debug_wm; |
| 478 | 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 | 694 | struct ieee80211_bss_conf *link_conf, |
| 670 | 695 | struct mt76_vif_link *mlink, |
| 671 | 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 | 699 | int mt7996_mcu_add_sta(struct mt7996_dev *dev, |
| 673 | 700 | struct ieee80211_bss_conf *link_conf, |
| 674 | 701 | struct ieee80211_link_sta *link_sta, |
| @@ -678,6 +705,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, · 3 unmodified lines | ||
| 678 | 705 | int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, |
| 679 | 706 | struct mt7996_vif_link *link, |
| 680 | 707 | struct mt7996_sta_link *msta_link); |
| 708 | +void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta); | |
| 681 | 709 | int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, |
| 682 | 710 | struct ieee80211_ampdu_params *params, |
| 683 | 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 | 735 | int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, |
| 708 | 736 | void *data, u8 link_id, u32 field); |
| 709 | 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); | |
| 711 | −int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); | |
| 738 | +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, | |
| 739 | + enum mt7996_eeprom_mode mode); | |
| 740 | +int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num); | |
| 712 | 741 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); |
| 713 | 742 | int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); |
| 714 | 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 | 748 | const struct mt7996_dfs_pattern *pattern); |
| 720 | 749 | int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); |
| 721 | 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 | 753 | int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, |
| 723 | 754 | struct ieee80211_bss_conf *link_conf); |
| 724 | 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 | 757 | int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); |
| 727 | 758 | int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); |
| 728 | 759 | int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); |
| 760 | +int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); | |
| 729 | 761 | int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); |
| 730 | 762 | int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, |
| 731 | 763 | struct cfg80211_chan_def *chandef); |
| @@ -743,6 +775,13 @@ void mt7996_mcu_exit(struct mt7996_dev *dev); · 11 unmodified lines | ||
| 743 | 775 | int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); |
| 744 | 776 | int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); |
| 745 | 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 | 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 | 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 | 849 | void mt7996_mac_init(struct mt7996_dev *dev); |
| 806 | 850 | u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); |
| 807 | 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 | 867 | struct mt7996_vif_link *link, |
| 824 | 868 | struct mt7996_sta_link *msta_link, |
| 825 | 869 | u8 flowid); |
| 826 | −void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, | |
| 827 | − struct mt7996_sta_link *msta_link); | |
| 870 | +void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, | |
| 871 | + struct ieee80211_sta *sta, | |
| 872 | + unsigned int link_id, bool flush); | |
| 828 | 873 | void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, |
| 829 | 874 | struct ieee80211_sta *sta, |
| 830 | 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 | 906 | struct mt7996_vif_link *link, |
| 862 | 907 | struct mt7996_sta_link *msta_link); |
| 863 | 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 | 913 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 865 | 914 | void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 866 | 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 | 926 | #endif |
| 878 | 927 | |
| 879 | 928 | int mt7996_dma_rro_init(struct mt7996_dev *dev); |
| 929 | +void mt7996_dma_rro_start(struct mt7996_dev *dev); | |
| 880 | 930 | |
| 881 | 931 | #ifdef CONFIG_MT7996_NPU |
| 932 | +int __mt7996_npu_hw_init(struct mt7996_dev *dev); | |
| 882 | 933 | int mt7996_npu_hw_init(struct mt7996_dev *dev); |
| 883 | 934 | int mt7996_npu_hw_stop(struct mt7996_dev *dev); |
| 884 | 935 | int mt7996_npu_rx_queues_init(struct mt7996_dev *dev); |
| 885 | 936 | #else |
| 937 | +static inline int __mt7996_npu_hw_init(struct mt7996_dev *dev) | |
| 938 | +{ | |
| 939 | + return 0; | |
| 940 | +} | |
| 941 | + | |
| 886 | 942 | static inline int mt7996_npu_hw_init(struct mt7996_dev *dev) |
| 887 | 943 | { |
| 888 | 944 | return 0; |
| @@ -8,55 +8,20 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include "mt7996.h" |
| 10 | 10 | |
| 11 | −static int mt7996_npu_offload_init(struct mt7996_dev *dev, | |
| 12 | − struct airoha_npu *npu) | |
| 11 | +static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev, | |
| 12 | + struct airoha_npu *npu) | |
| 13 | 13 | { |
| 14 | + u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; | |
| 14 | 15 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; |
| 15 | − u32 val, hif1_ofs = 0, dma_addr; | |
| 16 | + u32 dma_addr; | |
| 16 | 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 | 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 | 20 | err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC, |
| 56 | 21 | MT7996_RX_RING_SIZE, GFP_KERNEL); |
| 57 | 22 | if (err) { |
| 58 | 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 | 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 | 62 | phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); |
| 98 | 63 | if (err) { |
| 99 | 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 | 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 | 232 | err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, |
| 105 | 233 | MT7996_HW_TOKEN_SIZE, GFP_KERNEL); |
| 106 | 234 | if (err) |
| @@ -111,7 +239,7 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev, · 4 unmodified lines | ||
| 111 | 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 | 244 | u32 val; |
| 117 | 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 | 248 | &val, GFP_KERNEL); |
| 121 | 249 | if (err) { |
| 122 | 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 | 252 | return err; |
| 125 | 253 | } |
| 126 | 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 | 257 | &val, GFP_KERNEL); |
| 130 | 258 | if (err) { |
| 131 | 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 | 261 | return err; |
| 134 | 262 | } |
| 135 | 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 | 266 | &val, GFP_KERNEL); |
| 139 | 267 | if (err) { |
| 140 | 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 | 270 | return err; |
| 143 | 271 | } |
| 144 | 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 | 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 | 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++) { | |
| 154 | − dma_addr_t dma_addr; | |
| 349 | + BUILD_BUG_ON(ARRAY_SIZE(band_list) * 3 != | |
| 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 | 354 | u32 val; |
| 156 | 355 | |
| 157 | − err = mt76_npu_get_msg(npu, i + 5, | |
| 356 | + err = mt76_npu_get_msg(npu, band + 5, | |
| 158 | 357 | WLAN_FUNC_GET_WAIT_RXDESC_BASE, |
| 159 | 358 | &val, GFP_KERNEL); |
| 160 | 359 | if (err) { |
| 161 | 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 | 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, | |
| 168 | − 256 * MT7996_TX_RING_SIZE, | |
| 169 | − &dma_addr, GFP_KERNEL)) | |
| 170 | − return -ENOMEM; | |
| 365 | + phy_id = is_mt7996(&dev->mt76) ? band == MT_BAND0 ? 1 : 0 | |
| 366 | + : band; | |
| 367 | + writel(val, &dev->mt76.phys[phy_id]->q_tx[0]->regs->desc_base); | |
| 171 | 368 | |
| 172 | − err = mt76_npu_send_msg(npu, i, | |
| 369 | + err = mt76_npu_send_msg(npu, band, | |
| 173 | 370 | WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, |
| 174 | − dma_addr, GFP_KERNEL); | |
| 371 | + dev->npu_txd_addr[index++], GFP_KERNEL); | |
| 175 | 372 | if (err) { |
| 176 | 373 | dev_warn(dev->mt76.dev, |
| 177 | 374 | "failed setting NPU wlan queue buf addr\n"); |
| 178 | 375 | return err; |
| 179 | 376 | } |
| 180 | 377 | |
| 181 | − if (!dmam_alloc_coherent(dev->mt76.dma_dev, | |
| 182 | − 256 * MT7996_TX_RING_SIZE, | |
| 183 | − &dma_addr, GFP_KERNEL)) | |
| 184 | − return -ENOMEM; | |
| 185 | − | |
| 186 | − err = mt76_npu_send_msg(npu, i + 5, | |
| 378 | + err = mt76_npu_send_msg(npu, band + 5, | |
| 187 | 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 | 382 | if (err) { |
| 190 | 383 | dev_warn(dev->mt76.dev, |
| 191 | 384 | "failed setting NPU wlan tx buf addr\n"); |
| 192 | 385 | return err; |
| 193 | 386 | } |
| 194 | 387 | |
| 195 | − if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024, | |
| 196 | − &dma_addr, GFP_KERNEL)) | |
| 197 | − return -ENOMEM; | |
| 198 | − | |
| 199 | − err = mt76_npu_send_msg(npu, i + 10, | |
| 388 | + err = mt76_npu_send_msg(npu, band + 10, | |
| 200 | 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 | 392 | if (err) { |
| 203 | 393 | dev_warn(dev->mt76.dev, |
| 204 | 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 | 402 | static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, |
| 213 | 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 | 406 | phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; |
| 407 | + struct mt76_queue *q = &dev->mt76.q_rx[qid]; | |
| 217 | 408 | int err; |
| 218 | 409 | |
| 219 | 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 | 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 | 429 | err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR, |
| 238 | 430 | phy_addr, GFP_KERNEL); |
| 239 | 431 | if (err) |
| @@ -242,11 +434,54 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, · 2 unmodified lines | ||
| 242 | 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 | 471 | static int mt7996_npu_tx_done_init(struct mt7996_dev *dev, |
| 246 | 472 | struct airoha_npu *npu) |
| 247 | 473 | { |
| 248 | 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 | 485 | err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 251 | 486 | 0, GFP_KERNEL); |
| 252 | 487 | if (err) { |
| @@ -278,40 +513,79 @@ int mt7996_npu_rx_queues_init(struct mt7996_dev *dev) · 25 unmodified lines | ||
| 278 | 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 | 518 | struct airoha_npu *npu; |
| 284 | − int i, err = 0; | |
| 285 | − | |
| 286 | − mutex_lock(&dev->mt76.mutex); | |
| 519 | + int i, err; | |
| 287 | 520 | |
| 288 | 521 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); |
| 289 | 522 | if (!npu) |
| 290 | − goto unlock; | |
| 523 | + return 0; | |
| 291 | 524 | |
| 292 | 525 | err = mt7996_npu_offload_init(dev, npu); |
| 293 | 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 | 534 | if (err) |
| 298 | − goto unlock; | |
| 535 | + return err; | |
| 299 | 536 | |
| 300 | 537 | err = mt7996_npu_txd_init(dev, npu); |
| 301 | 538 | if (err) |
| 302 | − goto unlock; | |
| 539 | + return err; | |
| 303 | 540 | |
| 304 | 541 | err = mt7996_npu_rx_event_init(dev, npu); |
| 305 | 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 | 549 | err = mt7996_npu_tx_done_init(dev, npu); |
| 309 | 550 | if (err) |
| 310 | − goto unlock; | |
| 551 | + return err; | |
| 311 | 552 | |
| 312 | 553 | for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) |
| 313 | 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 | 589 | mutex_unlock(&dev->mt76.mutex); |
| 316 | 590 | |
| 317 | 591 | return err; |
| @@ -320,33 +594,38 @@ unlock: · 2 unmodified lines | ||
| 320 | 594 | int mt7996_npu_hw_stop(struct mt7996_dev *dev) |
| 321 | 595 | { |
| 322 | 596 | struct airoha_npu *npu; |
| 323 | − int i, err; | |
| 597 | + int i, err = 0; | |
| 324 | 598 | u32 info; |
| 325 | 599 | |
| 600 | + mutex_lock(&dev->mt76.mutex); | |
| 601 | + | |
| 326 | 602 | npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); |
| 327 | 603 | if (!npu) |
| 328 | − return 0; | |
| 604 | + goto unlock; | |
| 329 | 605 | |
| 330 | 606 | err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 331 | 607 | 0, GFP_KERNEL); |
| 332 | 608 | if (err) |
| 333 | − return err; | |
| 609 | + goto unlock; | |
| 334 | 610 | |
| 335 | 611 | for (i = 0; i < 10; i++) { |
| 336 | 612 | err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO, |
| 337 | 613 | &info, GFP_KERNEL); |
| 338 | − if (err) | |
| 339 | − continue; | |
| 614 | + if (!err && !info) | |
| 615 | + break; | |
| 340 | 616 | |
| 341 | − if (info) { | |
| 342 | − err = -ETIMEDOUT; | |
| 343 | − continue; | |
| 344 | − } | |
| 617 | + err = -ETIMEDOUT; | |
| 618 | + usleep_range(10000, 15000); | |
| 345 | 619 | } |
| 346 | 620 | |
| 347 | 621 | if (!err) |
| 348 | 622 | err = mt76_npu_send_msg(npu, 6, |
| 349 | 623 | WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, |
| 350 | 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 | 630 | return err; |
| 352 | 631 | } |
| @@ -159,6 +159,9 @@ enum offs_rev { · 158 unmodified lines | ||
| 159 | 159 | #define MT_MDP_BASE 0x820cc000 |
| 160 | 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 | 165 | #define MT_MDP_DCR2 MT_MDP(0x8e8) |
| 163 | 166 | #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) |
| 164 | 167 | |
| @@ -733,7 +736,15 @@ enum offs_rev { · 568 unmodified lines | ||
| 733 | 736 | #define MT_HW_REV 0x70010204 |
| 734 | 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 | 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 | 749 | /* PCIE MAC */ |
| 739 | 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 | 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 | 423 | void mt76_npu_disable_irqs(struct mt76_dev *dev) |
| 394 | 424 | { |
| 395 | 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 | 450 | struct airoha_npu *npu; |
| 421 | 451 | int err = 0; |
| 422 | 452 | |
| 423 | − /* NPU offloading is only supported by MT7992 */ | |
| 424 | − if (!is_mt7992(dev)) | |
| 425 | − return 0; | |
| 426 | − | |
| 427 | 453 | mutex_lock(&dev->mutex); |
| 428 | 454 | |
| 429 | 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 | 482 | dev->mmio.phy_addr = phy_addr; |
| 457 | 483 | dev->mmio.npu_type = type; |
| 458 | 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 | 488 | rcu_assign_pointer(dev->mmio.npu, npu); |
| 462 | 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 | 17 | clear_bit(MT76_SCANNING, &phy->state); |
| 18 | 18 | |
| 19 | − if (dev->scan.chan && phy->main_chandef.chan && | |
| 20 | − !test_bit(MT76_MCU_RESET, &dev->phy.state)) | |
| 19 | + if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && | |
| 20 | + !test_bit(MT76_MCU_RESET, &dev->phy.state)) { | |
| 21 | 21 | mt76_set_channel(phy, &phy->main_chandef, false); |
| 22 | + mt76_offchannel_notify(phy, false); | |
| 23 | + } | |
| 22 | 24 | mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); |
| 23 | 25 | memset(&dev->scan, 0, sizeof(dev->scan)); |
| 24 | 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 | 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 | 36 | cancel_delayed_work_sync(&dev->scan_work); |
| 31 | 37 | mt76_scan_complete(dev, true); |
| 32 | 38 | } |
| @@ -77,6 +83,27 @@ out: · 44 unmodified lines | ||
| 77 | 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 | 107 | void mt76_scan_work(struct work_struct *work) |
| 81 | 108 | { |
| 82 | 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 | 112 | struct cfg80211_chan_def chandef = {}; |
| 86 | 113 | struct mt76_phy *phy = dev->scan.phy; |
| 87 | 114 | int duration = HZ / 9; /* ~110 ms */ |
| 115 | + bool beacon_rx, offchannel = true; | |
| 88 | 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 | 129 | if (dev->scan.chan_idx >= req->n_channels) { |
| 91 | 130 | mt76_scan_complete(dev, false); |
| 92 | 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 | 135 | dev->scan.chan = NULL; |
| 97 | 136 | mt76_set_channel(phy, &phy->main_chandef, false); |
| 137 | + mt76_offchannel_notify(phy, false); | |
| 98 | 138 | goto out; |
| 99 | 139 | } |
| 100 | 140 | |
| 101 | 141 | dev->scan.chan = req->channels[dev->scan.chan_idx++]; |
| 102 | − cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); | |
| 103 | − mt76_set_channel(phy, &chandef, true); | |
| 142 | + offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef); | |
| 143 | + | |
| 144 | + if (offchannel) | |
| 145 | + mt76_offchannel_notify(phy, true); | |
| 146 | + mt76_set_channel(phy, &chandef, offchannel); | |
| 104 | 147 | |
| 105 | − if (!req->n_ssids || | |
| 106 | − chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) | |
| 148 | + if (!req->n_ssids) | |
| 107 | 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 | 162 | local_bh_disable(); |
| 111 | 163 | for (i = 0; i < req->n_ssids; i++) |
| 112 | 164 | mt76_scan_send_probe(dev, &req->ssids[i]); |
| 113 | 165 | local_bh_enable(); |
| 114 | 166 | |
| 115 | 167 | out: |
| 116 | − if (dev->scan.chan) | |
| 168 | + if (dev->scan.chan && phy->offchannel) | |
| 117 | 169 | duration = max_t(int, duration, |
| 118 | 170 | msecs_to_jiffies(req->duration + |
| 119 | 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 | 227 | struct sk_buff *skb) |
| 228 | 228 | { |
| 229 | 229 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 230 | + struct ieee80211_sta *sta; | |
| 230 | 231 | int pending; |
| 232 | + int i; | |
| 231 | 233 | |
| 232 | 234 | if (!wcid || info->tx_time_est) |
| 233 | 235 | return; |
| @@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, · 1 unmodified line | ||
| 235 | 237 | pending = atomic_dec_return(&wcid->non_aql_packets); |
| 236 | 238 | if (pending < 0) |
| 237 | 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 | 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 | 555 | if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) |
| 543 | 556 | continue; |
| 544 | 557 | |
| 558 | + if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) | |
| 559 | + continue; | |
| 560 | + | |
| 545 | 561 | phy = mt76_dev_phy(dev, wcid->phy_idx); |
| 546 | 562 | if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) |
| 547 | 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 | 633 | if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && |
| 618 | 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 | 636 | (!ieee80211_is_bufferable_mmpdu(skb) || |
| 621 | 637 | ieee80211_is_deauth(hdr->frame_control) || |
| 622 | 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 | 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 | 665 | LIST_HEAD(tx_list); |
| 650 | 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 | 866 | token = idr_alloc(&dev->token, *ptxwi, dev->token_start, |
| 851 | 867 | dev->token_start + dev->token_size, |
| 852 | 868 | GFP_ATOMIC); |
| 853 | − if (token >= dev->token_start) | |
| 869 | + if (token >= dev->token_start) { | |
| 854 | 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 | 878 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 857 | 879 | if (mtk_wed_device_active(&dev->mmio.wed) && |
| 858 | 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 | 919 | if (txwi) { |
| 898 | 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 | 928 | #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| 901 | 929 | if (mtk_wed_device_active(&dev->mmio.wed) && |
| 902 | 930 | token >= dev->mmio.wed.wlan.token_start && |
| @@ -403,12 +403,18 @@ error: · 402 unmodified lines | ||
| 403 | 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 | 411 | static int mt7601u_load_firmware(struct mt7601u_dev *dev) |
| 407 | 412 | { |
| 408 | 413 | const struct firmware *fw; |
| 409 | 414 | const struct mt76_fw_header *hdr; |
| 410 | 415 | int len, ret; |
| 411 | 416 | u32 val; |
| 417 | + int i; | |
| 412 | 418 | |
| 413 | 419 | mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | |
| 414 | 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 | 422 | if (firmware_running(dev)) |
| 417 | 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 | 433 | if (ret) |
| 421 | 434 | return ret; |
| 422 | 435 | |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "mt7601u.h" |
| 10 | 10 | |
| 11 | 11 | #define MT7601U_FIRMWARE "mt7601u.bin" |
| 12 | +#define MT7601U_FIRMWARE_PATHS ARRAY_SIZE(mt7601u_fw_paths) | |
| 12 | 13 | |
| 13 | 14 | #define MT_VEND_REQ_MAX_RETRY 10 |
| 14 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 5511 | #endif |
| 5477 | 5512 | }; |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
| 10 | 10 | * Copyright (c) 2013 - 2014 Intel Mobile Communications GmbH |
| 11 | 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 | 15 | #ifndef LINUX_IEEE80211_NAN_H |
| @@ -23,6 +23,11 @@ · 7 unmodified lines | ||
| 23 | 23 | #define NAN_OP_MODE_160MHZ 0x04 |
| 24 | 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 | 31 | /* NAN Device capabilities, as defined in Wi-Fi Aware (TM) specification |
| 27 | 32 | * Table 79 |
| 28 | 33 | */ |
| @@ -1194,6 +1194,13 @@ struct ieee80211_mgmt { · 1193 unmodified lines | ||
| 1194 | 1194 | |
| 1195 | 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 | 1205 | /* Management MIC information element (IEEE 802.11w) for CMAC */ |
| 1199 | 1206 | struct ieee80211_mmie { |
| @@ -1831,6 +1831,7 @@ struct cfg80211_ttlm_params { · 1830 unmodified lines | ||
| 1831 | 1831 | * @eml_cap: EML capabilities of this station |
| 1832 | 1832 | * @link_sta_params: link related params. |
| 1833 | 1833 | * @epp_peer: EPP peer indication |
| 1834 | + * @nmi_mac: MAC address of the NMI station of the NAN peer | |
| 1834 | 1835 | */ |
| 1835 | 1836 | struct station_parameters { |
| 1836 | 1837 | struct net_device *vlan; |
| @@ -1858,6 +1859,7 @@ struct station_parameters { · 21 unmodified lines | ||
| 1858 | 1859 | u16 eml_cap; |
| 1859 | 1860 | struct link_station_parameters link_sta_params; |
| 1860 | 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 | 1899 | * entry that is operating, has been marked authorized by userspace) |
| 1898 | 1900 | * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed) |
| 1899 | 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 | 1905 | enum cfg80211_station_type { |
| 1902 | 1906 | CFG80211_STA_AP_CLIENT, |
| @@ -1908,6 +1912,8 @@ enum cfg80211_station_type { · 5 unmodified lines | ||
| 1908 | 1912 | CFG80211_STA_TDLS_PEER_ACTIVE, |
| 1909 | 1913 | CFG80211_STA_MESH_PEER_KERNEL, |
| 1910 | 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 | 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 | 4061 | * struct cfg80211_nan_band_config - NAN band specific configuration |
| 3985 | 4062 | * |
| @@ -4050,6 +4127,102 @@ struct cfg80211_nan_conf { · 64 unmodified lines | ||
| 4050 | 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 | 4227 | * enum cfg80211_nan_conf_changes - indicates changed fields in NAN |
| 4055 | 4228 | * configuration |
| @@ -4830,6 +5003,19 @@ struct mgmt_frame_regs { · 774 unmodified lines | ||
| 4830 | 5003 | * @nan_change_conf: changes NAN configuration. The changed parameters must |
| 4831 | 5004 | * be specified in @changes (using &enum cfg80211_nan_conf_changes); |
| 4832 | 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 | 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 | 5393 | struct wireless_dev *wdev, |
| 5208 | 5394 | struct cfg80211_nan_conf *conf, |
| 5209 | 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 | 5402 | int (*set_multicast_to_unicast)(struct wiphy *wiphy, |
| 5212 | 5403 | struct net_device *dev, |
| 5213 | 5404 | const bool enabled); |
| @@ -5836,6 +6027,12 @@ enum wiphy_nan_flags { · 622 unmodified lines | ||
| 5836 | 6027 | * @max_channel_switch_time: maximum channel switch time in milliseconds. |
| 5837 | 6028 | * @dev_capabilities: NAN device capabilities as defined in Wi-Fi Aware (TM) |
| 5838 | 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 | 6037 | struct wiphy_nan_capa { |
| 5841 | 6038 | u32 flags; |
| @@ -5843,6 +6040,11 @@ struct wiphy_nan_capa { · 1 unmodified line | ||
| 5843 | 6040 | u8 n_antennas; |
| 5844 | 6041 | u16 max_channel_switch_time; |
| 5845 | 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 | 6050 | #define CFG80211_HW_TIMESTAMP_ALL_PEERS 0xffff |
| @@ -6736,8 +6938,8 @@ enum ieee80211_ap_reg_power { · 887 unmodified lines | ||
| 6736 | 6938 | * the P2P Device. |
| 6737 | 6939 | * @ps: powersave mode is enabled |
| 6738 | 6940 | * @ps_timeout: dynamic powersave timeout |
| 6739 | − * @ap_unexpected_nlportid: (private) netlink port ID of application | |
| 6740 | − * registered for unexpected class 3 frames (AP mode) | |
| 6941 | + * @unexpected_nlportid: (private) netlink port ID of application | |
| 6942 | + * registered for unexpected frames (AP mode or NAN_DATA mode) | |
| 6741 | 6943 | * @conn: (private) cfg80211 software SME connection state machine data |
| 6742 | 6944 | * @connect_keys: (private) keys to set after connection is established |
| 6743 | 6945 | * @conn_bss_type: connecting/connected BSS type |
| @@ -6799,7 +7001,7 @@ struct wireless_dev { · 55 unmodified lines | ||
| 6799 | 7001 | bool ps; |
| 6800 | 7002 | int ps_timeout; |
| 6801 | 7003 | |
| 6802 | − u32 ap_unexpected_nlportid; | |
| 7004 | + u32 unexpected_nlportid; | |
| 6803 | 7005 | |
| 6804 | 7006 | u32 owner_nlportid; |
| 6805 | 7007 | bool nl_owner_dead; |
| @@ -6859,6 +7061,9 @@ struct wireless_dev { · 53 unmodified lines | ||
| 6859 | 7061 | } ocb; |
| 6860 | 7062 | struct { |
| 6861 | 7063 | u8 cluster_id[ETH_ALEN] __aligned(2); |
| 7064 | + u8 n_channels; | |
| 7065 | + struct cfg80211_chan_def *chandefs; | |
| 7066 | + bool sched_update_pending; | |
| 6862 | 7067 | } nan; |
| 6863 | 7068 | } u; |
| 6864 | 7069 | |
| @@ -9367,9 +9572,10 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, · 2502 unmodified lines | ||
| 9367 | 9572 | * @addr: the transmitter address |
| 9368 | 9573 | * @gfp: context flags |
| 9369 | 9574 | * |
| 9370 | − * This function is used in AP mode (only!) to inform userspace that | |
| 9371 | − * a spurious class 3 frame was received, to be able to deauth the | |
| 9372 | − * sender. | |
| 9575 | + * This function is used in AP mode to inform userspace that a spurious | |
| 9576 | + * class 3 frame was received, to be able to deauth the 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 | 9579 | * Return: %true if the frame was passed to userspace (or this failed |
| 9374 | 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 | 10222 | enum nl80211_nan_func_term_reason reason, |
| 10017 | 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 | 10237 | /* ethtool helper */ |
| 10020 | 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 | 10574 | const u8 *cluster_id, bool new_cluster, |
| 10357 | 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 | 10610 | #ifdef CONFIG_CFG80211_DEBUGFS |
| 10360 | 10611 | /** |
| 10361 | 10612 | * wiphy_locked_debugfs_read - do a locked read in debugfs |
| @@ -906,8 +906,9 @@ · 905 unmodified lines | ||
| 906 | 906 | * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP |
| 907 | 907 | * (or GO) interface (i.e. hostapd) to ask for unexpected frames to |
| 908 | 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 | |
| 910 | − * is received. | |
| 909 | + * frames. For NAN_DATA interfaces, this is used to report frames from | |
| 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 | 912 | * For the event, the %NL80211_ATTR_MAC attribute carries the TA and |
| 912 | 913 | * other attributes like the interface index are present. |
| 913 | 914 | * If used as the command it must have an interface index and you can |
| @@ -1367,6 +1368,53 @@ · 453 unmodified lines | ||
| 1367 | 1368 | * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel |
| 1368 | 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 | 1418 | * @NL80211_CMD_MAX: highest used command number |
| 1371 | 1419 | * @__NL80211_CMD_AFTER_LAST: internal use |
| 1372 | 1420 | */ |
| @@ -1632,6 +1680,16 @@ enum nl80211_commands { · 259 unmodified lines | ||
| 1632 | 1680 | |
| 1633 | 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 | 1693 | /* add new commands above here */ |
| 1636 | 1694 | |
| 1637 | 1695 | /* used to define NL80211_CMD_MAX below */ |
| @@ -2659,7 +2717,8 @@ enum nl80211_commands { · 1021 unmodified lines | ||
| 2659 | 2717 | * a flow is assigned on each round of the DRR scheduler. |
| 2660 | 2718 | * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from |
| 2661 | 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 | 2723 | * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include |
| 2665 | 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 | 3050 | * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable |
| 2992 | 3051 | * this feature during association. This is a flag attribute. |
| 2993 | 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 | 3130 | * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying |
| 2996 | 3131 | * the signal interference bitmap detected on the operating bandwidth for |
| @@ -3582,6 +3717,22 @@ enum nl80211_attrs { · 585 unmodified lines | ||
| 3582 | 3717 | |
| 3583 | 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 | 3736 | /* add attributes here, update the policy in nl80211.c */ |
| 3586 | 3737 | |
| 3587 | 3738 | __NL80211_ATTR_AFTER_LAST, |
| @@ -3675,6 +3826,9 @@ enum nl80211_attrs { · 87 unmodified lines | ||
| 3675 | 3826 | * @NL80211_IFTYPE_OCB: Outside Context of a BSS |
| 3676 | 3827 | * This mode corresponds to the MIB variable dot11OCBActivated=true |
| 3677 | 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 | 3832 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
| 3679 | 3833 | * @NUM_NL80211_IFTYPES: number of defined interface types |
| 3680 | 3834 | * |
| @@ -3696,6 +3850,7 @@ enum nl80211_iftype { · 15 unmodified lines | ||
| 3696 | 3850 | NL80211_IFTYPE_P2P_DEVICE, |
| 3697 | 3851 | NL80211_IFTYPE_OCB, |
| 3698 | 3852 | NL80211_IFTYPE_NAN, |
| 3853 | + NL80211_IFTYPE_NAN_DATA, | |
| 3699 | 3854 | |
| 3700 | 3855 | /* keep last */ |
| 3701 | 3856 | NUM_NL80211_IFTYPES, |
| @@ -4384,6 +4539,46 @@ enum nl80211_band_attr { · 682 unmodified lines | ||
| 4384 | 4539 | |
| 4385 | 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 | 4583 | * enum nl80211_wmm_rule - regulatory wmm rule |
| 4389 | 4584 | * |
| @@ -8557,6 +8752,8 @@ enum nl80211_s1g_short_beacon_attrs { · 4167 unmodified lines | ||
| 8557 | 8752 | * @NL80211_NAN_CAPA_CAPABILITIES: u8 attribute containing the |
| 8558 | 8753 | * capabilities of the device as defined in Wi-Fi Aware (TM) |
| 8559 | 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 | 8757 | * @__NL80211_NAN_CAPABILITIES_LAST: Internal |
| 8561 | 8758 | * @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute. |
| 8562 | 8759 | */ |
| @@ -8569,9 +8766,38 @@ enum nl80211_nan_capabilities { · 6 unmodified lines | ||
| 8569 | 8766 | NL80211_NAN_CAPA_NUM_ANTENNAS, |
| 8570 | 8767 | NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME, |
| 8571 | 8768 | NL80211_NAN_CAPA_CAPABILITIES, |
| 8769 | + NL80211_NAN_CAPA_PHY, | |
| 8572 | 8770 | /* keep last */ |
| 8573 | 8771 | __NL80211_NAN_CAPABILITIES_LAST, |
| 8574 | 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 | 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 | 718 | case NL80211_IFTYPE_P2P_CLIENT: |
| 719 | 719 | case NL80211_IFTYPE_P2P_GO: |
| 720 | 720 | case NL80211_IFTYPE_OCB: |
| 721 | + case NL80211_IFTYPE_NAN_DATA: | |
| 721 | 722 | /* shouldn't happen */ |
| 722 | 723 | WARN_ON_ONCE(1); |
| 723 | 724 | break; |
| @@ -2140,12 +2141,13 @@ static int sta_link_apply_parameters(struct ieee80211_local *local, · 1416 unmodified lines | ||
| 2140 | 2141 | return -EINVAL; |
| 2141 | 2142 | |
| 2142 | 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 | 2145 | params->ht_capa, link_sta); |
| 2145 | 2146 | |
| 2146 | 2147 | /* VHT can override some HT caps such as the A-MSDU max length */ |
| 2147 | 2148 | if (params->vht_capa) |
| 2148 | 2149 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 2150 | + &sband->vht_cap, | |
| 2149 | 2151 | params->vht_capa, NULL, |
| 2150 | 2152 | link_sta); |
| 2151 | 2153 | |
| @@ -166,6 +166,13 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local, · 165 unmodified lines | ||
| 166 | 166 | for_each_chanctx_user_all(local, ctx, &iter) |
| 167 | 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 | 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 | 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 | 507 | static enum nl80211_chan_width |
| 451 | 508 | ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, |
| 452 | 509 | struct ieee80211_chanctx *ctx, |
| 453 | 510 | struct ieee80211_link_data *rsvd_for, |
| 454 | 511 | bool check_reserved) |
| 455 | 512 | { |
| 456 | − struct ieee80211_sub_if_data *sdata; | |
| 457 | − struct ieee80211_link_data *link; | |
| 458 | 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 | 518 | if (WARN_ON(check_reserved && rsvd_for)) |
| 461 | 519 | return ctx->conf.def.width; |
| 462 | 520 | |
| 463 | − for_each_sdata_link(local, link) { | |
| 464 | − enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT; | |
| 465 | − | |
| 466 | − if (check_reserved) { | |
| 467 | − if (link->reserved_chanctx != ctx) | |
| 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); | |
| 521 | + /* When this is true we only care about the reserving links */ | |
| 522 | + if (check_reserved) { | |
| 523 | + for_each_chanctx_user_reserved(local, ctx, &iter) { | |
| 524 | + width = ieee80211_get_width_of_link(iter.link); | |
| 525 | + max_bw = max(max_bw, width); | |
| 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 | 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 | 545 | /* use the configured bandwidth in case of monitor interface */ |
| 519 | 546 | sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); |
| 520 | 547 | if (sdata && |
| @@ -752,10 +779,9 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local, · 231 unmodified lines | ||
| 752 | 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 | 783 | static struct ieee80211_chanctx * |
| 757 | 784 | ieee80211_find_chanctx(struct ieee80211_local *local, |
| 758 | − struct ieee80211_link_data *link, | |
| 759 | 785 | const struct ieee80211_chan_req *chanreq, |
| 760 | 786 | enum ieee80211_chanctx_mode mode) |
| 761 | 787 | { |
| @@ -767,9 +793,6 @@ ieee80211_find_chanctx(struct ieee80211_local *local, · 5 unmodified lines | ||
| 767 | 793 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) |
| 768 | 794 | return NULL; |
| 769 | 795 | |
| 770 | − if (WARN_ON(link->reserved_chanctx)) | |
| 771 | − return NULL; | |
| 772 | − | |
| 773 | 796 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
| 774 | 797 | const struct ieee80211_chan_req *compat; |
| 775 | 798 | |
| @@ -790,12 +813,12 @@ ieee80211_find_chanctx(struct ieee80211_local *local, · 14 unmodified lines | ||
| 790 | 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 | 817 | * active links during callbacks we make into it below and/or |
| 795 | 818 | * later during assignment, which could (otherwise) cause the |
| 796 | 819 | * context to actually be removed. |
| 797 | 820 | */ |
| 798 | − link->reserved_chanctx = ctx; | |
| 821 | + ctx->will_be_used = true; | |
| 799 | 822 | |
| 800 | 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 | 1461 | case NL80211_IFTYPE_P2P_GO: |
| 1439 | 1462 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1440 | 1463 | case NL80211_IFTYPE_NAN: |
| 1464 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1441 | 1465 | case NUM_NL80211_IFTYPES: |
| 1442 | 1466 | WARN_ON(1); |
| 1443 | 1467 | break; |
| @@ -2011,6 +2035,36 @@ void __ieee80211_link_release_channel(struct ieee80211_link_data *link, · 567 unmodified lines | ||
| 2011 | 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 | 2068 | int _ieee80211_link_use_channel(struct ieee80211_link_data *link, |
| 2015 | 2069 | const struct ieee80211_chan_req *chanreq, |
| 2016 | 2070 | enum ieee80211_chanctx_mode mode, |
| @@ -2020,8 +2074,7 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, · 3 unmodified lines | ||
| 2020 | 2074 | struct ieee80211_local *local = sdata->local; |
| 2021 | 2075 | struct ieee80211_chanctx *ctx; |
| 2022 | 2076 | u8 radar_detect_width = 0; |
| 2023 | − bool reserved = false; | |
| 2024 | − int radio_idx; | |
| 2077 | + bool reused_ctx = false; | |
| 2025 | 2078 | int ret; |
| 2026 | 2079 | |
| 2027 | 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 | 2102 | if (!local->in_reconfig) |
| 2050 | 2103 | __ieee80211_link_release_channel(link, false); |
| 2051 | 2104 | |
| 2052 | − ctx = ieee80211_find_chanctx(local, link, chanreq, mode); | |
| 2053 | − /* Note: context is now reserved */ | |
| 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); | |
| 2105 | + ctx = ieee80211_find_or_create_chanctx(sdata, chanreq, mode, | |
| 2106 | + assign_on_failure, &reused_ctx); | |
| 2063 | 2107 | if (IS_ERR(ctx)) { |
| 2064 | 2108 | ret = PTR_ERR(ctx); |
| 2065 | 2109 | goto out; |
| @@ -2069,10 +2113,13 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link, · 3 unmodified lines | ||
| 2069 | 2113 | |
| 2070 | 2114 | ret = ieee80211_assign_link_chanctx(link, ctx, assign_on_failure); |
| 2071 | 2115 | |
| 2072 | − if (reserved) { | |
| 2073 | − /* remove reservation */ | |
| 2074 | − WARN_ON(link->reserved_chanctx != ctx); | |
| 2075 | − link->reserved_chanctx = NULL; | |
| 2116 | + /* | |
| 2117 | + * In case an existing channel context is being used, we marked it as | |
| 2118 | + * will_be_used, now that it is assigned - clear this indication | |
| 2119 | + */ | |
| 2120 | + if (reused_ctx) { | |
| 2121 | + WARN_ON(!ctx->will_be_used); | |
| 2122 | + ctx->will_be_used = false; | |
| 2076 | 2123 | } |
| 2077 | 2124 | |
| 2078 | 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 | 110 | void |
| 111 | −ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | |
| 112 | − struct ieee80211_supported_band *sband, | |
| 113 | − const u8 *he_cap_ie, u8 he_cap_len, | |
| 114 | − const struct ieee80211_he_6ghz_capa *he_6ghz_capa, | |
| 115 | − struct link_sta_info *link_sta) | |
| 111 | +_ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, | |
| 112 | + const struct ieee80211_sta_he_cap *own_he_cap_ptr, | |
| 113 | + const u8 *he_cap_ie, u8 he_cap_len, | |
| 114 | + const struct ieee80211_he_6ghz_capa *he_6ghz_capa, | |
| 115 | + struct link_sta_info *link_sta) | |
| 116 | 116 | { |
| 117 | 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 | 118 | struct ieee80211_sta_he_cap own_he_cap; |
| 120 | 119 | struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie; |
| 121 | 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 | 125 | memset(he_cap, 0, sizeof(*he_cap)); |
| 127 | 126 | |
| 128 | − if (!he_cap_ie) | |
| 129 | − return; | |
| 130 | − | |
| 131 | − own_he_cap_ptr = | |
| 132 | − ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); | |
| 133 | − if (!own_he_cap_ptr) | |
| 127 | + if (!he_cap_ie || !own_he_cap_ptr || !own_he_cap_ptr->has_he) | |
| 134 | 128 | return; |
| 135 | 129 | |
| 136 | 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 | 158 | link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta); |
| 165 | 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 | 162 | ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta); |
| 169 | 163 | |
| 170 | 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 | 221 | void |
| 211 | 222 | ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, |
| 212 | 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 | 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 | 140 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 141 | 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 | 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 | 155 | goto apply; |
| 156 | 156 | |
| 157 | 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 | 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 | 1014 | ieee80211_chandef_ht_oper(elems->ht_operation, &chandef); |
| 1015 | 1015 | |
| 1016 | 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 | 1019 | &htcap_ie, |
| 1019 | 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 | 1034 | &chandef); |
| 1034 | 1035 | memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie)); |
| 1035 | 1036 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 1037 | + &sband->vht_cap, | |
| 1036 | 1038 | &cap_ie, NULL, |
| 1037 | 1039 | &sta->deflink); |
| 1038 | 1040 | if (memcmp(&cap, &sta->sta.deflink.vht_cap, sizeof(cap))) |
| @@ -928,6 +928,9 @@ struct ieee80211_chanctx { · 927 unmodified lines | ||
| 928 | 928 | |
| 929 | 929 | bool radar_detected; |
| 930 | 930 | |
| 931 | + /* This chanctx is in process of getting used */ | |
| 932 | + bool will_be_used; | |
| 933 | + | |
| 931 | 934 | /* MUST be last - ends in a flexible-array member. */ |
| 932 | 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 | 2188 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
| 2186 | 2189 | struct ieee80211_sta_ht_cap *ht_cap); |
| 2187 | 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 | 2192 | const struct ieee80211_ht_cap *ht_cap_ie, |
| 2190 | 2193 | struct link_sta_info *link_sta); |
| 2191 | 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 | 2273 | void |
| 2271 | 2274 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 2272 | 2275 | struct ieee80211_supported_band *sband, |
| 2276 | + const struct ieee80211_sta_vht_cap *own_vht_cap, | |
| 2273 | 2277 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 2274 | 2278 | const struct ieee80211_vht_cap *vht_cap_ie2, |
| 2275 | 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 | 2315 | /* HE */ |
| 2312 | 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 | 2323 | ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, |
| 2314 | 2324 | struct ieee80211_supported_band *sband, |
| 2315 | 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 | 1225 | ret = ieee80211_check_queues(sdata, NL80211_IFTYPE_MONITOR); |
| 1228 | 1226 | if (ret) { |
| 1229 | 1227 | kfree(sdata); |
| 1230 | 1228 | return ret; |
| 1231 | 1229 | } |
| 1232 | 1230 | |
| 1231 | + set_bit(SDATA_STATE_RUNNING, &sdata->state); | |
| 1232 | + | |
| 1233 | 1233 | mutex_lock(&local->iflist_mtx); |
| 1234 | 1234 | rcu_assign_pointer(local->monitor_sdata, sdata); |
| 1235 | 1235 | mutex_unlock(&local->iflist_mtx); |
| @@ -1242,6 +1242,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local, · 6 unmodified lines | ||
| 1242 | 1242 | mutex_unlock(&local->iflist_mtx); |
| 1243 | 1243 | synchronize_net(); |
| 1244 | 1244 | drv_remove_interface(local, sdata); |
| 1245 | + clear_bit(SDATA_STATE_RUNNING, &sdata->state); | |
| 1245 | 1246 | kfree(sdata); |
| 1246 | 1247 | return ret; |
| 1247 | 1248 | } |
| @@ -1360,8 +1361,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 112 unmodified lines | ||
| 1360 | 1361 | break; |
| 1361 | 1362 | } |
| 1362 | 1363 | case NL80211_IFTYPE_AP: |
| 1363 | − sdata->bss = &sdata->u.ap; | |
| 1364 | − break; | |
| 1365 | 1364 | case NL80211_IFTYPE_MESH_POINT: |
| 1366 | 1365 | case NL80211_IFTYPE_STATION: |
| 1367 | 1366 | case NL80211_IFTYPE_MONITOR: |
| @@ -1369,6 +1368,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 1 unmodified line | ||
| 1369 | 1368 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1370 | 1369 | case NL80211_IFTYPE_OCB: |
| 1371 | 1370 | case NL80211_IFTYPE_NAN: |
| 1371 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1372 | 1372 | /* no special treatment */ |
| 1373 | 1373 | break; |
| 1374 | 1374 | case NL80211_IFTYPE_UNSPECIFIED: |
| @@ -1386,8 +1386,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 11 unmodified lines | ||
| 1386 | 1386 | local->reconfig_failure = false; |
| 1387 | 1387 | |
| 1388 | 1388 | res = drv_start(local); |
| 1389 | − if (res) | |
| 1390 | − goto err_del_bss; | |
| 1389 | + if (res) { | |
| 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 | 1396 | ieee80211_led_radio(local, true); |
| 1392 | 1397 | ieee80211_mod_tpt_led_trig(local, |
| 1393 | 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 | 1463 | netif_carrier_on(dev); |
| 1459 | 1464 | list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); |
| 1460 | 1465 | break; |
| 1466 | + case NL80211_IFTYPE_AP: | |
| 1467 | + sdata->bss = &sdata->u.ap; | |
| 1468 | + fallthrough; | |
| 1461 | 1469 | default: |
| 1462 | 1470 | if (coming_up) { |
| 1463 | 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 | 1554 | err_stop: |
| 1547 | 1555 | if (!local->open_count) |
| 1548 | 1556 | drv_stop(local, false); |
| 1549 | − err_del_bss: | |
| 1550 | − sdata->bss = NULL; | |
| 1551 | 1557 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
| 1552 | 1558 | list_del(&sdata->u.vlan.list); |
| 1553 | − /* might already be clear but that doesn't matter */ | |
| 1554 | − clear_bit(SDATA_STATE_RUNNING, &sdata->state); | |
| 1559 | + /* Might not be initialized yet, but it is harmless */ | |
| 1560 | + sdata->bss = NULL; | |
| 1555 | 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 | 1946 | case NL80211_IFTYPE_P2P_DEVICE: |
| 1941 | 1947 | sdata->vif.bss_conf.bssid = sdata->vif.addr; |
| 1942 | 1948 | break; |
| 1949 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1950 | + break; | |
| 1943 | 1951 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1944 | 1952 | case NL80211_IFTYPE_WDS: |
| 1945 | 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 | 450 | changed |= IEEE80211_RC_SUPP_RATES_CHANGED; |
| 451 | 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 | 454 | elems->ht_cap_elem, |
| 455 | 455 | &sta->deflink)) |
| 456 | 456 | changed |= IEEE80211_RC_BW_CHANGED; |
| 457 | 457 | |
| 458 | 458 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 459 | + &sband->vht_cap, | |
| 459 | 460 | elems->vht_cap_elem, NULL, |
| 460 | 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 | 5587 | /* Set up internal HT/VHT capabilities */ |
| 5588 | 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 | 5590 | elems->ht_cap_elem, |
| 5591 | 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 | 5624 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
| 5625 | + &sband->vht_cap, | |
| 5625 | 5626 | elems->vht_cap_elem, |
| 5626 | 5627 | bss_vht_cap, link_sta); |
| 5627 | 5628 | rcu_read_unlock(); |
| @@ -10458,8 +10459,8 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, · 4830 unmodified lines | ||
| 10458 | 10459 | pos = mgmt->u.action.ml_reconf_resp.variable; |
| 10459 | 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 * 3) { | |
| 10462 | + if (len < mgmt->u.action.ml_reconf_resp.count * | |
| 10463 | + sizeof(struct ieee80211_ml_reconf_status)) { | |
| 10463 | 10464 | sdata_info(sdata, |
| 10464 | 10465 | "mlo: reconf: unexpected len=%zu, count=%u\n", |
| 10465 | 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 | 10470 | link_mask = sta_changed_links; |
| 10470 | 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 | 10478 | if (!(link_mask & BIT(link_id))) { |
| 10476 | 10479 | sdata_info(sdata, |
| @@ -10505,8 +10508,8 @@ void ieee80211_process_ml_reconf_resp(struct ieee80211_sub_if_data *sdata, · 28 unmodified lines | ||
| 10505 | 10508 | sdata->u.mgd.reconf.added_links &= ~BIT(link_id); |
| 10506 | 10509 | } |
| 10507 | 10510 | |
| 10508 | − pos += 3; | |
| 10509 | − len -= 3; | |
| 10511 | + pos += sizeof(*reconf_status); | |
| 10512 | + len -= sizeof(*reconf_status); | |
| 10510 | 10513 | } |
| 10511 | 10514 | |
| 10512 | 10515 | if (link_mask) { |
| @@ -4607,6 +4607,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) · 4606 unmodified lines | ||
| 4607 | 4607 | (ieee80211_is_public_action(hdr, skb->len) || |
| 4608 | 4608 | (ieee80211_is_auth(hdr->frame_control) && |
| 4609 | 4609 | ether_addr_equal(sdata->vif.addr, hdr->addr1))); |
| 4610 | + case NL80211_IFTYPE_NAN_DATA: | |
| 4611 | + return false; | |
| 4610 | 4612 | default: |
| 4611 | 4613 | break; |
| 4612 | 4614 | } |
| @@ -1778,9 +1778,8 @@ TRACE_EVENT(drv_switch_vif_chanctx, · 1777 unmodified lines | ||
| 1778 | 1778 | SWITCH_ENTRY_ASSIGN(vif.vif_type, vif->type); |
| 1779 | 1779 | SWITCH_ENTRY_ASSIGN(vif.p2p, vif->p2p); |
| 1780 | 1780 | SWITCH_ENTRY_ASSIGN(link_id, link_conf->link_id); |
| 1781 | − strncpy(local_vifs[i].vif.vif_name, | |
| 1782 | − sdata->name, | |
| 1783 | − sizeof(local_vifs[i].vif.vif_name)); | |
| 1781 | + strscpy_pad(local_vifs[i].vif.vif_name, | |
| 1782 | + sdata->name); | |
| 1784 | 1783 | SWITCH_ENTRY_ASSIGN(old_chandef.control_freq, |
| 1785 | 1784 | old_ctx->def.chan->center_freq); |
| 1786 | 1785 | SWITCH_ENTRY_ASSIGN(old_chandef.freq_offset, |
| @@ -2118,6 +2118,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) · 2117 unmodified lines | ||
| 2118 | 2118 | return res; |
| 2119 | 2119 | } |
| 2120 | 2120 | break; |
| 2121 | + case NL80211_IFTYPE_NAN_DATA: | |
| 2121 | 2122 | case NL80211_IFTYPE_AP_VLAN: |
| 2122 | 2123 | case NL80211_IFTYPE_MONITOR: |
| 2123 | 2124 | case NL80211_IFTYPE_P2P_DEVICE: |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | * |
| 5 | 5 | * Portions of this file |
| 6 | 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 | 10 | #include <linux/ieee80211.h> |
| @@ -115,6 +115,7 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata, · 104 unmodified lines | ||
| 115 | 115 | void |
| 116 | 116 | ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, |
| 117 | 117 | struct ieee80211_supported_band *sband, |
| 118 | + const struct ieee80211_sta_vht_cap *own_vht_cap, | |
| 118 | 119 | const struct ieee80211_vht_cap *vht_cap_ie, |
| 119 | 120 | const struct ieee80211_vht_cap *vht_cap_ie2, |
| 120 | 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 | 123 | struct ieee80211_sta_vht_cap *vht_cap = &link_sta->pub->vht_cap; |
| 123 | 124 | struct ieee80211_sta_vht_cap own_cap; |
| 124 | 125 | u32 cap_info, i; |
| 125 | − bool have_80mhz; | |
| 126 | 126 | u32 mpdu_len; |
| 127 | 127 | |
| 128 | 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 | 130 | if (!link_sta->pub->ht_cap.ht_supported) |
| 131 | 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 | 134 | return; |
| 135 | 135 | |
| 136 | − /* Allow VHT if at least one channel on the sband supports 80 MHz */ | |
| 137 | − have_80mhz = false; | |
| 138 | − for (i = 0; i < sband->n_channels; i++) { | |
| 139 | − if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | | |
| 140 | − IEEE80211_CHAN_NO_80MHZ)) | |
| 141 | − continue; | |
| 136 | + if (sband) { | |
| 137 | + /* Allow VHT if at least one channel on the sband supports 80 MHz */ | |
| 138 | + bool have_80mhz = false; | |
| 142 | 139 | |
| 143 | − have_80mhz = true; | |
| 144 | − break; | |
| 145 | − } | |
| 140 | + for (i = 0; i < sband->n_channels; i++) { | |
| 141 | + if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | | |
| 142 | + IEEE80211_CHAN_NO_80MHZ)) | |
| 143 | + continue; | |
| 146 | 144 | |
| 147 | − if (!have_80mhz) | |
| 148 | − return; | |
| 145 | + have_80mhz = true; | |
| 146 | + break; | |
| 147 | + } | |
| 148 | + | |
| 149 | + if (!have_80mhz) | |
| 150 | + return; | |
| 151 | + } | |
| 149 | 152 | |
| 150 | 153 | /* |
| 151 | 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 | 160 | vht_cap->vht_supported = true; |
| 158 | 161 | |
| 159 | − own_cap = sband->vht_cap; | |
| 162 | + own_cap = *own_vht_cap; | |
| 160 | 163 | /* |
| 161 | 164 | * If user has specified capability overrides, take care |
| 162 | 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 | 317 | int step; |
| 318 | 318 | |
| 319 | 319 | /* We only do strict verification on 6 GHz */ |
| 320 | − if (center < 5955 || center > 7115) | |
| 320 | + if (center < 5955 || center > 7215) | |
| 321 | 321 | return true; |
| 322 | 322 | |
| 323 | 323 | bw = nl80211_chan_width_to_mhz(width); |
| @@ -325,7 +325,7 @@ static bool cfg80211_valid_center_freq(u32 center, · 1 unmodified line | ||
| 325 | 325 | return false; |
| 326 | 326 | |
| 327 | 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 | 329 | return false; |
| 330 | 330 | |
| 331 | 331 | /* With 320 MHz the permitted channels overlap */ |
| @@ -816,6 +816,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, · 484 unmodified lines | ||
| 816 | 816 | case NL80211_IFTYPE_MONITOR: |
| 817 | 817 | case NL80211_IFTYPE_AP_VLAN: |
| 818 | 818 | case NL80211_IFTYPE_P2P_DEVICE: |
| 819 | + case NL80211_IFTYPE_NAN_DATA: | |
| 819 | 820 | break; |
| 820 | 821 | case NL80211_IFTYPE_WDS: |
| 821 | 822 | case NL80211_IFTYPE_UNSPECIFIED: |
| @@ -939,6 +940,7 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) · 117 unmodified lines | ||
| 939 | 940 | case NL80211_IFTYPE_P2P_DEVICE: |
| 940 | 941 | /* Can NAN type be considered as beaconing interface? */ |
| 941 | 942 | case NL80211_IFTYPE_NAN: |
| 943 | + case NL80211_IFTYPE_NAN_DATA: | |
| 942 | 944 | break; |
| 943 | 945 | case NL80211_IFTYPE_UNSPECIFIED: |
| 944 | 946 | case NL80211_IFTYPE_WDS: |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
| 6 | 6 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
| 7 | 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 | 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 | 254 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, |
| 255 | 255 | struct wireless_dev *wdev) |
| 256 | 256 | { |
| 257 | + struct cfg80211_nan_local_sched empty_sched = {}; | |
| 258 | + | |
| 257 | 259 | lockdep_assert_held(&rdev->wiphy.mtx); |
| 258 | 260 | |
| 259 | 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 | 264 | if (!wdev_running(wdev)) |
| 263 | 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 | 276 | rdev_stop_nan(rdev, wdev); |
| 266 | 277 | wdev->is_running = false; |
| 267 | 278 | |
| @@ -270,6 +281,47 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, · 2 unmodified lines | ||
| 270 | 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 | 325 | void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) |
| 274 | 326 | { |
| 275 | 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 | 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 | 337 | list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { |
| 281 | 338 | if (wdev->netdev) { |
| 282 | 339 | dev_close(wdev->netdev); |
| 283 | 340 | continue; |
| 284 | 341 | } |
| 342 | + } | |
| 285 | 343 | |
| 286 | − /* otherwise, check iftype */ | |
| 287 | − | |
| 288 | − guard(wiphy)(wiphy); | |
| 344 | + guard(wiphy)(wiphy); | |
| 289 | 345 | |
| 346 | + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { | |
| 290 | 347 | switch (wdev->iftype) { |
| 291 | 348 | case NL80211_IFTYPE_P2P_DEVICE: |
| 292 | 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 | 402 | list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { |
| 346 | 403 | if (wdev->nl_owner_dead) { |
| 404 | + cfg80211_close_dependents(rdev, wdev); | |
| 405 | + | |
| 347 | 406 | if (wdev->netdev) |
| 348 | 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 | 431 | static void cfg80211_destroy_iface_wk(struct work_struct *work) |
| 358 | 432 | { |
| 359 | 433 | struct cfg80211_registered_device *rdev; |
| @@ -761,6 +835,10 @@ int wiphy_register(struct wiphy *wiphy) · 401 unmodified lines | ||
| 761 | 835 | !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))))) |
| 762 | 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 | 842 | if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))) |
| 765 | 843 | return -EINVAL; |
| 766 | 844 | |
| @@ -1367,9 +1445,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, · 600 unmodified lines | ||
| 1367 | 1445 | rdev->num_running_monitor_ifaces += num; |
| 1368 | 1446 | } |
| 1369 | 1447 | |
| 1370 | −void cfg80211_leave(struct cfg80211_registered_device *rdev, | |
| 1371 | − struct wireless_dev *wdev, | |
| 1372 | − int link_id) | |
| 1448 | +void cfg80211_leave_locked(struct cfg80211_registered_device *rdev, | |
| 1449 | + struct wireless_dev *wdev, int link_id) | |
| 1373 | 1450 | { |
| 1374 | 1451 | struct net_device *dev = wdev->netdev; |
| 1375 | 1452 | struct cfg80211_sched_scan_request *pos, *tmp; |
| @@ -1420,6 +1497,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, · 44 unmodified lines | ||
| 1420 | 1497 | break; |
| 1421 | 1498 | case NL80211_IFTYPE_AP_VLAN: |
| 1422 | 1499 | case NL80211_IFTYPE_MONITOR: |
| 1500 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1423 | 1501 | /* nothing to do */ |
| 1424 | 1502 | break; |
| 1425 | 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 | 1524 | void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, |
| 1434 | 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 | 1537 | trace_cfg80211_stop_link(wiphy, wdev, link_id); |
| 1447 | 1538 | |
| 1539 | + if (wdev->iftype == NL80211_IFTYPE_NAN) | |
| 1540 | + return; | |
| 1541 | + | |
| 1448 | 1542 | ev = kzalloc_obj(*ev, gfp); |
| 1449 | 1543 | if (!ev) |
| 1450 | 1544 | return; |
| @@ -1595,10 +1689,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 144 unmodified lines | ||
| 1595 | 1689 | } |
| 1596 | 1690 | break; |
| 1597 | 1691 | case NETDEV_GOING_DOWN: |
| 1598 | − scoped_guard(wiphy, &rdev->wiphy) { | |
| 1599 | − cfg80211_leave(rdev, wdev, -1); | |
| 1692 | + cfg80211_leave(rdev, wdev, -1); | |
| 1693 | + scoped_guard(wiphy, &rdev->wiphy) | |
| 1600 | 1694 | cfg80211_remove_links(wdev); |
| 1601 | − } | |
| 1602 | 1695 | /* since we just did cfg80211_leave() nothing to do there */ |
| 1603 | 1696 | cancel_work_sync(&wdev->disconnect_wk); |
| 1604 | 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 | 1773 | if (rfkill_blocked(rdev->wiphy.rfkill)) |
| 1681 | 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 | 1792 | break; |
| 1683 | 1793 | default: |
| 1684 | 1794 | return NOTIFY_DONE; |
| @@ -318,6 +318,9 @@ void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, · 317 unmodified lines | ||
| 318 | 318 | |
| 319 | 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 | 324 | /* free object */ |
| 322 | 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 | 544 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
| 542 | 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 | 550 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
| 545 | 551 | struct wireless_dev *wdev, |
| 546 | 552 | int link_id); |
| @@ -551,6 +557,10 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, · 4 unmodified lines | ||
| 551 | 557 | void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, |
| 552 | 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 | 564 | struct cfg80211_internal_bss * |
| 555 | 565 | cfg80211_bss_update(struct cfg80211_registered_device *rdev, |
| 556 | 566 | struct cfg80211_internal_bss *tmp, |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | * |
| 5 | 5 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> |
| 6 | 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 | 10 | #include <linux/kernel.h> |
| @@ -782,8 +782,8 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) · 771 unmodified lines | ||
| 782 | 782 | rdev_crit_proto_stop(rdev, wdev); |
| 783 | 783 | } |
| 784 | 784 | |
| 785 | − if (nlportid == wdev->ap_unexpected_nlportid) | |
| 786 | − wdev->ap_unexpected_nlportid = 0; | |
| 785 | + if (nlportid == wdev->unexpected_nlportid) | |
| 786 | + wdev->unexpected_nlportid = 0; | |
| 787 | 787 | } |
| 788 | 788 | |
| 789 | 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 | 933 | * cfg80211 doesn't track the stations |
| 934 | 934 | */ |
| 935 | 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 | 942 | case NL80211_IFTYPE_P2P_DEVICE: |
| 937 | 943 | /* |
| 938 | 944 | * fall through, P2P device only supports |
| 939 | 945 | * public action frames |
| 940 | 946 | */ |
| 941 | − case NL80211_IFTYPE_NAN: | |
| 942 | 947 | default: |
| 943 | 948 | err = -EOPNOTSUPP; |
| 944 | 949 | break; |
| @@ -333,6 +333,97 @@ static int validate_nan_cluster_id(const struct nlattr *attr, · 332 unmodified lines | ||
| 333 | 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 | 427 | static int validate_uhr_capa(const struct nlattr *attr, |
| 337 | 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 | 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 | 656 | static const struct nla_policy |
| 559 | 657 | nl80211_nan_conf_policy[NL80211_NAN_CONF_ATTR_MAX + 1] = { |
| 560 | 658 | [NL80211_NAN_CONF_CLUSTER_ID] = |
| @@ -962,6 +1060,22 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 401 unmodified lines | ||
| 962 | 1060 | [NL80211_ATTR_DISABLE_UHR] = { .type = NLA_FLAG }, |
| 963 | 1061 | [NL80211_ATTR_UHR_OPERATION] = |
| 964 | 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 | 1081 | /* policy for the key attributes */ |
| @@ -1722,6 +1836,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) · 754 unmodified lines | ||
| 1722 | 1836 | return 0; |
| 1723 | 1837 | return -ENOLINK; |
| 1724 | 1838 | case NL80211_IFTYPE_NAN: |
| 1839 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1725 | 1840 | if (wiphy_ext_feature_isset(wdev->wiphy, |
| 1726 | 1841 | NL80211_EXT_FEATURE_SECURE_NAN)) |
| 1727 | 1842 | return 0; |
| @@ -2678,6 +2793,68 @@ fail: · 950 unmodified lines | ||
| 2678 | 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 | 2858 | static int nl80211_put_nan_capa(struct wiphy *wiphy, struct sk_buff *msg) |
| 2682 | 2859 | { |
| 2683 | 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 | 2881 | wiphy->nan_capa.dev_capabilities)) |
| 2705 | 2882 | goto fail; |
| 2706 | 2883 | |
| 2884 | + if (nl80211_put_nan_phy_cap(wiphy, msg)) | |
| 2885 | + goto fail; | |
| 2886 | + | |
| 2707 | 2887 | nla_nest_end(msg, nan_caps); |
| 2708 | 2888 | |
| 2709 | 2889 | return 0; |
| @@ -4879,6 +5059,8 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) · 2169 unmodified lines | ||
| 4879 | 5059 | else |
| 4880 | 5060 | dev_close(wdev->netdev); |
| 4881 | 5061 | |
| 5062 | + cfg80211_close_dependents(rdev, wdev); | |
| 5063 | + | |
| 4882 | 5064 | mutex_lock(&rdev->wiphy.mtx); |
| 4883 | 5065 | |
| 4884 | 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 | 7305 | if ((params->sta_flags_mask | |
| 7124 | 7306 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) |
| 7125 | 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 | 7328 | return 0; |
| 7127 | 7329 | } |
| 7128 | 7330 | |
| @@ -8005,7 +8207,7 @@ static int nl80211_dump_station(struct sk_buff *skb, · 876 unmodified lines | ||
| 8005 | 8207 | /* nl80211_prepare_wdev_dump acquired it in the successful case */ |
| 8006 | 8208 | __acquire(&rdev->wiphy.mtx); |
| 8007 | 8209 | |
| 8008 | − if (!wdev->netdev) { | |
| 8210 | + if (!wdev->netdev && wdev->iftype != NL80211_IFTYPE_NAN) { | |
| 8009 | 8211 | err = -EINVAL; |
| 8010 | 8212 | goto out_err; |
| 8011 | 8213 | } |
| @@ -8192,10 +8394,12 @@ int cfg80211_check_station_change(struct wiphy *wiphy, · 180 unmodified lines | ||
| 8192 | 8394 | return -EINVAL; |
| 8193 | 8395 | if (params->link_sta_params.supported_rates) |
| 8194 | 8396 | return -EINVAL; |
| 8195 | − if (params->ext_capab || params->link_sta_params.ht_capa || | |
| 8196 | − params->link_sta_params.vht_capa || | |
| 8197 | − params->link_sta_params.he_capa || | |
| 8198 | − params->link_sta_params.eht_capa || | |
| 8397 | + if (statype != CFG80211_STA_NAN_MGMT && | |
| 8398 | + (params->link_sta_params.ht_capa || | |
| 8399 | + params->link_sta_params.vht_capa || | |
| 8400 | + params->link_sta_params.he_capa)) | |
| 8401 | + return -EINVAL; | |
| 8402 | + if (params->ext_capab || params->link_sta_params.eht_capa || | |
| 8199 | 8403 | params->link_sta_params.uhr_capa) |
| 8200 | 8404 | return -EINVAL; |
| 8201 | 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 | 8471 | params->plink_action != NL80211_PLINK_ACTION_BLOCK) |
| 8268 | 8472 | return -EINVAL; |
| 8269 | 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 | 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 | 8703 | return -EINVAL; |
| 8486 | 8704 | |
| 8487 | 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 | 8842 | case NL80211_IFTYPE_STATION: |
| 8625 | 8843 | case NL80211_IFTYPE_ADHOC: |
| 8626 | 8844 | case NL80211_IFTYPE_MESH_POINT: |
| 8845 | + case NL80211_IFTYPE_NAN: | |
| 8846 | + case NL80211_IFTYPE_NAN_DATA: | |
| 8627 | 8847 | break; |
| 8628 | 8848 | default: |
| 8629 | 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 | 8873 | memset(¶ms, 0, sizeof(params)); |
| 8654 | 8874 | |
| 8655 | − if (!dev) | |
| 8875 | + if (!dev && wdev->iftype != NL80211_IFTYPE_NAN) | |
| 8656 | 8876 | return -EINVAL; |
| 8657 | 8877 | |
| 8658 | 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 | 8881 | if (!info->attrs[NL80211_ATTR_MAC]) |
| 8662 | 8882 | return -EINVAL; |
| 8663 | 8883 | |
| 8664 | − if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | |
| 8665 | − return -EINVAL; | |
| 8884 | + if (wdev->iftype == NL80211_IFTYPE_NAN || | |
| 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]) | |
| 8668 | − return -EINVAL; | |
| 8892 | + /* Only NMI stations receive the HT/VHT/HE capabilities */ | |
| 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] && | |
| 8671 | − !info->attrs[NL80211_ATTR_PEER_AID]) | |
| 8672 | − return -EINVAL; | |
| 8902 | + if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | |
| 8903 | + 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 | 8910 | params.link_sta_params.link_id = |
| 8675 | 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 | 8921 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
| 8686 | 8922 | } |
| 8687 | 8923 | |
| 8688 | − params.link_sta_params.supported_rates = | |
| 8689 | − nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | |
| 8690 | − params.link_sta_params.supported_rates_len = | |
| 8691 | − nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | |
| 8692 | − params.listen_interval = | |
| 8693 | − nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | |
| 8924 | + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { | |
| 8925 | + params.link_sta_params.supported_rates = | |
| 8926 | + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | |
| 8927 | + params.link_sta_params.supported_rates_len = | |
| 8928 | + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | |
| 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 | 8935 | if (info->attrs[NL80211_ATTR_VLAN_ID]) |
| 8696 | 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 | 8950 | if (info->attrs[NL80211_ATTR_PEER_AID]) |
| 8711 | 8951 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); |
| 8712 | − else | |
| 8952 | + else if (info->attrs[NL80211_ATTR_STA_AID]) | |
| 8713 | 8953 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
| 8714 | 8954 | |
| 8715 | 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 | 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 | 9083 | /* Ensure that HT/VHT capabilities are not set for 6 GHz HE STA */ |
| 8834 | 9084 | if (params.link_sta_params.he_6ghz_capa && |
| 8835 | 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 | 9173 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED); |
| 8924 | 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 | 9180 | default: |
| 8926 | 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 | 9219 | memset(¶ms, 0, sizeof(params)); |
| 8965 | 9220 | |
| 8966 | − if (!dev) | |
| 9221 | + if (!dev && wdev->iftype != NL80211_IFTYPE_NAN) | |
| 8967 | 9222 | return -EINVAL; |
| 8968 | 9223 | |
| 8969 | 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 | 9229 | case NL80211_IFTYPE_AP_VLAN: |
| 8975 | 9230 | case NL80211_IFTYPE_MESH_POINT: |
| 8976 | 9231 | case NL80211_IFTYPE_P2P_GO: |
| 9232 | + case NL80211_IFTYPE_NAN: | |
| 9233 | + case NL80211_IFTYPE_NAN_DATA: | |
| 8977 | 9234 | /* always accept these */ |
| 8978 | 9235 | break; |
| 8979 | 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 | 14207 | case NL80211_IFTYPE_P2P_DEVICE: |
| 13951 | 14208 | break; |
| 13952 | 14209 | case NL80211_IFTYPE_NAN: |
| 14210 | + case NL80211_IFTYPE_NAN_DATA: | |
| 13953 | 14211 | if (!wiphy_ext_feature_isset(wdev->wiphy, |
| 13954 | 14212 | NL80211_EXT_FEATURE_SECURE_NAN) && |
| 13955 | 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 | 14271 | case NL80211_IFTYPE_P2P_GO: |
| 14014 | 14272 | break; |
| 14015 | 14273 | case NL80211_IFTYPE_NAN: |
| 14274 | + case NL80211_IFTYPE_NAN_DATA: | |
| 14016 | 14275 | if (!wiphy_ext_feature_isset(wdev->wiphy, |
| 14017 | 14276 | NL80211_EXT_FEATURE_SECURE_NAN) && |
| 14018 | 14277 | !(wdev->wiphy->nan_capa.flags & |
| @@ -15520,13 +15779,14 @@ static int nl80211_register_unexpected_frame(struct sk_buff *skb, · 1501 unmodified lines | ||
| 15520 | 15779 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 15521 | 15780 | |
| 15522 | 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 | 15784 | return -EINVAL; |
| 15525 | 15785 | |
| 15526 | − if (wdev->ap_unexpected_nlportid) | |
| 15786 | + if (wdev->unexpected_nlportid) | |
| 15527 | 15787 | return -EBUSY; |
| 15528 | 15788 | |
| 15529 | − wdev->ap_unexpected_nlportid = info->snd_portid; | |
| 15789 | + wdev->unexpected_nlportid = info->snd_portid; | |
| 15530 | 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 | 16182 | if (wdev->iftype != NL80211_IFTYPE_NAN) |
| 15923 | 16183 | return -EOPNOTSUPP; |
| 15924 | 16184 | |
| 16185 | + cfg80211_close_dependents(rdev, wdev); | |
| 16186 | + | |
| 16187 | + guard(wiphy)(&rdev->wiphy); | |
| 16188 | + | |
| 15925 | 16189 | cfg80211_stop_nan(rdev, wdev); |
| 15926 | 16190 | |
| 15927 | 16191 | return 0; |
| @@ -16421,6 +16685,482 @@ nla_put_failure: · 493 unmodified lines | ||
| 16421 | 16685 | } |
| 16422 | 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 | 17164 | static int nl80211_get_protocol_features(struct sk_buff *skb, |
| 16425 | 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 | 18836 | NL80211_FLAG_NEED_RTNL) \ |
| 18097 | 18837 | SELECTOR(__sel, WIPHY_CLEAR, \ |
| 18098 | 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 | 18845 | enum nl80211_internal_flags_selector { |
| 18102 | 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 | 19677 | .doit = nl80211_stop_nan, |
| 18934 | 19678 | .flags = GENL_ADMIN_PERM, |
| 18935 | 19679 | .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | |
| 19680 | + NL80211_FLAG_NO_WIPHY_MTX | | |
| 18936 | 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 | 19972 | .flags = GENL_UNS_ADMIN_PERM, |
| 19228 | 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 | 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 | 21284 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
| 20528 | 21285 | struct sk_buff *msg; |
| 20529 | 21286 | void *hdr; |
| 20530 | − u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid); | |
| 21287 | + u32 nlportid = READ_ONCE(wdev->unexpected_nlportid); | |
| 20531 | 21288 | |
| 20532 | 21289 | if (!nlportid) |
| 20533 | 21290 | return false; |
| @@ -20567,7 +21324,8 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev, const u8 *addr, · 33 unmodified lines | ||
| 20567 | 21324 | trace_cfg80211_rx_spurious_frame(dev, addr, link_id); |
| 20568 | 21325 | |
| 20569 | 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 | 21329 | trace_cfg80211_return_bool(false); |
| 20572 | 21330 | return false; |
| 20573 | 21331 | } |
| @@ -22137,6 +22895,97 @@ void cfg80211_nan_cluster_joined(struct wireless_dev *wdev, · 1563 unmodified lines | ||
| 22137 | 22895 | } |
| 22138 | 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 | 22989 | /* initialisation/exit functions */ |
| 22141 | 22990 | |
| 22142 | 22991 | int __init nl80211_init(void) |
| @@ -1060,6 +1060,38 @@ rdev_nan_change_conf(struct cfg80211_registered_device *rdev, · 1059 unmodified lines | ||
| 1060 | 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 | 1095 | static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, |
| 1064 | 1096 | struct net_device *dev, |
| 1065 | 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 | 2348 | if (!wdev->netdev || !netif_running(wdev->netdev)) |
| 2349 | 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 | 2363 | for (link = 0; link < ARRAY_SIZE(wdev->links); link++) { |
| 2352 | 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 | 2409 | continue; |
| 2398 | 2410 | chandef = wdev->u.ocb.chandef; |
| 2399 | 2411 | break; |
| 2400 | − case NL80211_IFTYPE_NAN: | |
| 2401 | − /* we have no info, but NAN is also pretty universal */ | |
| 2402 | − continue; | |
| 2412 | + case NL80211_IFTYPE_NAN_DATA: | |
| 2413 | + /* NAN channels are checked in NL80211_IFTYPE_NAN interface */ | |
| 2414 | + break; | |
| 2403 | 2415 | default: |
| 2404 | 2416 | /* others not implemented for now */ |
| 2405 | 2417 | WARN_ON_ONCE(1); |
| @@ -2436,11 +2448,14 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy) · 30 unmodified lines | ||
| 2436 | 2448 | struct wireless_dev *wdev; |
| 2437 | 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) | |
| 2442 | − if (!reg_wdev_chan_valid(wiphy, wdev)) | |
| 2454 | + scoped_guard(wiphy, wiphy) | |
| 2455 | + valid = reg_wdev_chan_valid(wiphy, wdev); | |
| 2456 | + if (!valid) | |
| 2443 | 2457 | cfg80211_leave(rdev, wdev, -1); |
| 2458 | + } | |
| 2444 | 2459 | } |
| 2445 | 2460 | |
| 2446 | 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 | 102 | if (!rdev->wiphy.registered) |
| 103 | 103 | goto out_unlock_rtnl; |
| 104 | 104 | |
| 105 | − wiphy_lock(&rdev->wiphy); | |
| 106 | 105 | if (rdev->wiphy.wowlan_config) { |
| 107 | − cfg80211_process_wiphy_works(rdev, NULL); | |
| 108 | − if (rdev->ops->suspend) | |
| 109 | − ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); | |
| 110 | − if (ret <= 0) | |
| 111 | − goto out_unlock_wiphy; | |
| 106 | + scoped_guard(wiphy, &rdev->wiphy) { | |
| 107 | + cfg80211_process_wiphy_works(rdev, NULL); | |
| 108 | + if (rdev->ops->suspend) | |
| 109 | + ret = rdev_suspend(rdev, | |
| 110 | + rdev->wiphy.wowlan_config); | |
| 111 | + if (ret <= 0) | |
| 112 | + goto out_unlock_rtnl; | |
| 113 | + } | |
| 112 | 114 | } |
| 113 | 115 | |
| 114 | 116 | /* Driver refused to configure wowlan (ret = 1) or no wowlan */ |
| 115 | 117 | |
| 116 | 118 | cfg80211_leave_all(rdev); |
| 117 | − cfg80211_process_rdev_events(rdev); | |
| 118 | − cfg80211_process_wiphy_works(rdev, NULL); | |
| 119 | − if (rdev->ops->suspend) | |
| 120 | − ret = rdev_suspend(rdev, NULL); | |
| 121 | − | |
| 122 | −out_unlock_wiphy: | |
| 123 | − wiphy_unlock(&rdev->wiphy); | |
| 119 | + scoped_guard(wiphy, &rdev->wiphy) { | |
| 120 | + cfg80211_process_rdev_events(rdev); | |
| 121 | + cfg80211_process_wiphy_works(rdev, NULL); | |
| 122 | + if (rdev->ops->suspend) | |
| 123 | + ret = rdev_suspend(rdev, NULL); | |
| 124 | + } | |
| 124 | 125 | out_unlock_rtnl: |
| 125 | 126 | if (ret == 0) |
| 126 | 127 | rdev->suspended = true; |
| @@ -2410,6 +2410,55 @@ TRACE_EVENT(rdev_del_nan_func, · 2409 unmodified lines | ||
| 2410 | 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 | 2462 | TRACE_EVENT(rdev_set_mac_acl, |
| 2414 | 2463 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
| 2415 | 2464 | struct cfg80211_acl_data *params), |
| @@ -4276,6 +4325,62 @@ TRACE_EVENT(cfg80211_incumbent_signal_notify, · 1860 unmodified lines | ||
| 4276 | 4325 | TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", signal_interference_bitmap=0x%x", |
| 4277 | 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 | 4384 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
| 4280 | 4385 | |
| 4281 | 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 | 90 | /* see 802.11ax D6.1 27.3.23.2 */ |
| 91 | 91 | if (chan == 2) |
| 92 | 92 | return MHZ_TO_KHZ(5935); |
| 93 | − if (chan <= 233) | |
| 93 | + if (chan <= 253) | |
| 94 | 94 | return MHZ_TO_KHZ(5950 + chan * 5); |
| 95 | 95 | break; |
| 96 | 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 | 625 | case cpu_to_le16(0): |
| 626 | 626 | if (iftype != NL80211_IFTYPE_ADHOC && |
| 627 | 627 | iftype != NL80211_IFTYPE_STATION && |
| 628 | − iftype != NL80211_IFTYPE_OCB) | |
| 629 | − return -1; | |
| 628 | + iftype != NL80211_IFTYPE_OCB && | |
| 629 | + iftype != NL80211_IFTYPE_NAN_DATA) | |
| 630 | + return -1; | |
| 630 | 631 | break; |
| 631 | 632 | } |
| 632 | 633 | |
| @@ -1144,8 +1145,15 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) · 511 unmodified lines | ||
| 1144 | 1145 | ev->ij.channel); |
| 1145 | 1146 | break; |
| 1146 | 1147 | case EVENT_STOPPED: |
| 1147 | − cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev, | |
| 1148 | − ev->link_id); | |
| 1148 | + /* | |
| 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 | 1157 | break; |
| 1150 | 1158 | case EVENT_PORT_AUTHORIZED: |
| 1151 | 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 | 1192 | if (otype == NL80211_IFTYPE_AP_VLAN) |
| 1185 | 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 | 1202 | /* cannot change into P2P device or NAN */ |
| 1188 | 1203 | if (ntype == NL80211_IFTYPE_P2P_DEVICE || |
| 1189 | 1204 | ntype == NL80211_IFTYPE_NAN) |
| @@ -1204,7 +1219,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 14 unmodified lines | ||
| 1204 | 1219 | dev->ieee80211_ptr->use_4addr = false; |
| 1205 | 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 | 1224 | cfg80211_process_rdev_events(rdev); |
| 1210 | 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 | 1247 | case NL80211_IFTYPE_OCB: |
| 1233 | 1248 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1234 | 1249 | case NL80211_IFTYPE_ADHOC: |
| 1250 | + case NL80211_IFTYPE_NAN_DATA: | |
| 1235 | 1251 | dev->priv_flags |= IFF_DONT_BRIDGE; |
| 1236 | 1252 | break; |
| 1237 | 1253 | case NL80211_IFTYPE_P2P_GO: |