FILE
notif.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/notif.c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2/* 3 * Copyright (C) 2024-2025 Intel Corporation 4 */ 5 6#include "mld.h" 7#include "notif.h" 8#include "scan.h" 9#include "iface.h" 10#include "mlo.h" 11#include "iwl-trans.h" 12#include "fw/file.h" 13#include "fw/dbg.h" 14#include "fw/api/cmdhdr.h" 15#include "fw/api/mac-cfg.h" 16#include "session-protect.h" 17#include "fw/api/time-event.h" 18#include "fw/api/tx.h" 19#include "fw/api/rs.h" 20#include "fw/api/offload.h" 21#include "fw/api/stats.h" 22#include "fw/api/rfi.h" 23#include "fw/api/coex.h" 24 25#include "mcc.h" 26#include "link.h" 27#include "tx.h" 28#include "rx.h" 29#include "tlc.h" 30#include "agg.h" 31#include "mac80211.h" 32#include "thermal.h" 33#include "roc.h" 34#include "stats.h" 35#include "coex.h" 36#include "time_sync.h" 37#include "ftm-initiator.h" 38 39/* Please use this in an increasing order of the versions */ 40#define CMD_VER_ENTRY(_ver, _struct) \ 41 { .size = sizeof(struct _struct), .ver = _ver }, 42#define CMD_VERSIONS(name, ...) \ 43 static const struct iwl_notif_struct_size \ 44 iwl_notif_struct_sizes_##name[] = { __VA_ARGS__ }; 45 46#define RX_HANDLER_NO_OBJECT(_grp, _cmd, _name, _context) \ 47 {.cmd_id = WIDE_ID(_grp, _cmd), \ 48 .context = _context, \ 49 .fn = iwl_mld_handle_##_name, \ 50 .sizes = iwl_notif_struct_sizes_##_name, \ 51 .n_sizes = ARRAY_SIZE(iwl_notif_struct_sizes_##_name), \ 52 }, 53 54/* Use this for Rx handlers that do not need notification validation */ 55#define RX_HANDLER_NO_VAL(_grp, _cmd, _name, _context) \ 56 {.cmd_id = WIDE_ID(_grp, _cmd), \ 57 .context = _context, \ 58 .fn = iwl_mld_handle_##_name, \ 59 }, 60 61#define RX_HANDLER_VAL_FN(_grp, _cmd, _name, _context) \ 62 { .cmd_id = WIDE_ID(_grp, _cmd), \ 63 .context = _context, \ 64 .fn = iwl_mld_handle_##_name, \ 65 .val_fn = iwl_mld_validate_##_name, \ 66 }, 67 68#define DEFINE_SIMPLE_CANCELLATION(name, notif_struct, id_member) \ 69static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \ 70 struct iwl_rx_packet *pkt, \ 71 u32 obj_id) \ 72{ \ 73 const struct notif_struct *notif = (const void *)pkt->data; \ 74 \ 75 return obj_id == _Generic((notif)->id_member, \ 76 __le32: le32_to_cpu((notif)->id_member), \ 77 __le16: le16_to_cpu((notif)->id_member), \ 78 u8: (notif)->id_member); \ 79} 80 81/* Currently only defined for the RX_HANDLER_SIZES options. Use this for 82 * notifications that belong to a specific object, and that should be 83 * canceled when the object is removed 84 */ 85#define RX_HANDLER_OF_OBJ(_grp, _cmd, _name, _obj_type) \ 86 {.cmd_id = WIDE_ID(_grp, _cmd), \ 87 /* Only async handlers can be canceled */ \ 88 .context = RX_HANDLER_ASYNC, \ 89 .fn = iwl_mld_handle_##_name, \ 90 .sizes = iwl_notif_struct_sizes_##_name, \ 91 .n_sizes = ARRAY_SIZE(iwl_notif_struct_sizes_##_name), \ 92 .obj_type = IWL_MLD_OBJECT_TYPE_##_obj_type, \ 93 .cancel = iwl_mld_cancel_##_name, \ 94 }, 95 96#define RX_HANDLER_OF_LINK(_grp, _cmd, _name) \ 97 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, LINK) \ 98 99#define RX_HANDLER_OF_VIF(_grp, _cmd, _name) \ 100 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, VIF) \ 101 102#define RX_HANDLER_OF_STA(_grp, _cmd, _name) \ 103 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, STA) \ 104 105#define RX_HANDLER_OF_ROC(_grp, _cmd, _name) \ 106 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, ROC) 107 108#define RX_HANDLER_OF_SCAN(_grp, _cmd, _name) \ 109 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, SCAN) 110 111#define RX_HANDLER_OF_FTM_REQ(_grp, _cmd, _name) \ 112 RX_HANDLER_OF_OBJ(_grp, _cmd, _name, FTM_REQ) 113 114static void iwl_mld_handle_mfuart_notif(struct iwl_mld *mld, 115 struct iwl_rx_packet *pkt) 116{ 117 struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; 118 119 IWL_DEBUG_INFO(mld, 120 "MFUART: installed ver: 0x%08x, external ver: 0x%08x\n", 121 le32_to_cpu(mfuart_notif->installed_ver), 122 le32_to_cpu(mfuart_notif->external_ver)); 123 IWL_DEBUG_INFO(mld, 124 "MFUART: status: 0x%08x, duration: 0x%08x image size: 0x%08x\n", 125 le32_to_cpu(mfuart_notif->status), 126 le32_to_cpu(mfuart_notif->duration), 127 le32_to_cpu(mfuart_notif->image_size)); 128} 129 130static void iwl_mld_mu_mimo_iface_iterator(void *_data, u8 *mac, 131 struct ieee80211_vif *vif) 132{ 133 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; 134 unsigned int link_id = 0; 135 136 if (WARN(hweight16(vif->active_links) > 1, 137 "no support for this notif while in EMLSR 0x%x\n", 138 vif->active_links)) 139 return; 140 141 if (ieee80211_vif_is_mld(vif)) { 142 link_id = __ffs(vif->active_links); 143 bss_conf = link_conf_dereference_check(vif, link_id); 144 } 145 146 if (!WARN_ON(!bss_conf) && bss_conf->mu_mimo_owner) { 147 const struct iwl_mu_group_mgmt_notif *notif = _data; 148 149 BUILD_BUG_ON(sizeof(notif->membership_status) != 150 WLAN_MEMBERSHIP_LEN); 151 BUILD_BUG_ON(sizeof(notif->user_position) != 152 WLAN_USER_POSITION_LEN); 153 154 /* MU-MIMO Group Id action frame is little endian. We treat 155 * the data received from firmware as if it came from the 156 * action frame, so no conversion is needed. 157 */ 158 ieee80211_update_mu_groups(vif, link_id, 159 (u8 *)¬if->membership_status, 160 (u8 *)¬if->user_position); 161 } 162} 163 164/* This handler is called in SYNC mode because it needs to be serialized with 165 * Rx as specified in ieee80211_update_mu_groups()'s documentation. 166 */ 167static void iwl_mld_handle_mu_mimo_grp_notif(struct iwl_mld *mld, 168 struct iwl_rx_packet *pkt) 169{ 170 struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data; 171 172 ieee80211_iterate_active_interfaces_atomic(mld->hw, 173 IEEE80211_IFACE_ITER_NORMAL, 174 iwl_mld_mu_mimo_iface_iterator, 175 notif); 176} 177 178static void 179iwl_mld_handle_channel_switch_start_notif(struct iwl_mld *mld, 180 struct iwl_rx_packet *pkt) 181{ 182 struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; 183 u32 link_id = le32_to_cpu(notif->link_id); 184 struct ieee80211_bss_conf *link_conf = 185 iwl_mld_fw_id_to_link_conf(mld, link_id); 186 struct ieee80211_vif *vif; 187 188 if (WARN_ON(!link_conf)) 189 return; 190 191 vif = link_conf->vif; 192 193 IWL_DEBUG_INFO(mld, 194 "CSA Start Notification with vif type: %d, link_id: %d\n", 195 vif->type, 196 link_conf->link_id); 197 198 switch (vif->type) { 199 case NL80211_IFTYPE_AP: 200 /* We don't support canceling a CSA as it was advertised 201 * by the AP itself 202 */ 203 if (!link_conf->csa_active) 204 return; 205 206 ieee80211_csa_finish(vif, link_conf->link_id); 207 break; 208 case NL80211_IFTYPE_STATION: 209 if (!link_conf->csa_active) { 210 /* Either unexpected cs notif or mac80211 chose to 211 * ignore, for example in channel switch to same channel 212 */ 213 struct iwl_cancel_channel_switch_cmd cmd = { 214 .id = cpu_to_le32(link_id), 215 }; 216 217 if (iwl_mld_send_cmd_pdu(mld, 218 WIDE_ID(MAC_CONF_GROUP, 219 CANCEL_CHANNEL_SWITCH_CMD), 220 &cmd)) 221 IWL_ERR(mld, 222 "Failed to cancel the channel switch\n"); 223 return; 224 } 225 226 ieee80211_chswitch_done(vif, true, link_conf->link_id); 227 break; 228 229 default: 230 WARN(1, "CSA on invalid vif type: %d", vif->type); 231 } 232} 233 234static void 235iwl_mld_handle_channel_switch_error_notif(struct iwl_mld *mld, 236 struct iwl_rx_packet *pkt) 237{ 238 struct iwl_channel_switch_error_notif *notif = (void *)pkt->data; 239 struct ieee80211_bss_conf *link_conf; 240 struct ieee80211_vif *vif; 241 u32 link_id = le32_to_cpu(notif->link_id); 242 u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask); 243 244 link_conf = iwl_mld_fw_id_to_link_conf(mld, link_id); 245 if (WARN_ON(!link_conf)) 246 return; 247 248 vif = link_conf->vif; 249 250 IWL_DEBUG_INFO(mld, "FW reports CSA error: id=%u, csa_err_mask=%u\n", 251 link_id, csa_err_mask); 252 253 if (csa_err_mask & (CS_ERR_COUNT_ERROR | 254 CS_ERR_LONG_DELAY_AFTER_CS | 255 CS_ERR_TX_BLOCK_TIMER_EXPIRED)) 256 ieee80211_channel_switch_disconnect(vif); 257} 258 259static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld, 260 struct iwl_rx_packet *pkt) 261{ 262 struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; 263 264 mld->ibss_manager = !!beacon->ibss_mgr_status; 265} 266 267/** 268 * DOC: Notification versioning 269 * 270 * The firmware's notifications change from time to time. In order to 271 * differentiate between different versions of the same notification, the 272 * firmware advertises the version of each notification. 273 * Here are listed all the notifications that are supported. Several versions 274 * of the same notification can be allowed at the same time: 275 * 276 * CMD_VERSION(my_multi_version_notif, 277 * CMD_VER_ENTRY(1, iwl_my_multi_version_notif_ver1) 278 * CMD_VER_ENTRY(2, iwl_my_multi_version_notif_ver2) 279 * 280 * etc... 281 * 282 * The driver will enforce that the notification coming from the firmware 283 * has its version listed here and it'll also enforce that the firmware sent 284 * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY. 285 */ 286 287CMD_VERSIONS(scan_start_notif, 288 CMD_VER_ENTRY(1, iwl_umac_scan_start)) 289CMD_VERSIONS(scan_complete_notif, 290 CMD_VER_ENTRY(1, iwl_umac_scan_complete)) 291CMD_VERSIONS(scan_iter_complete_notif, 292 CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif)) 293CMD_VERSIONS(channel_survey_notif, 294 CMD_VER_ENTRY(1, iwl_umac_scan_channel_survey_notif)) 295CMD_VERSIONS(mfuart_notif, 296 CMD_VER_ENTRY(2, iwl_mfuart_load_notif)) 297CMD_VERSIONS(update_mcc, 298 CMD_VER_ENTRY(1, iwl_mcc_chub_notif)) 299CMD_VERSIONS(session_prot_notif, 300 CMD_VER_ENTRY(3, iwl_session_prot_notif)) 301CMD_VERSIONS(missed_beacon_notif, 302 CMD_VER_ENTRY(5, iwl_missed_beacons_notif)) 303CMD_VERSIONS(tx_resp_notif, 304 CMD_VER_ENTRY(8, iwl_tx_resp) 305 CMD_VER_ENTRY(9, iwl_tx_resp)) 306CMD_VERSIONS(compressed_ba_notif, 307 CMD_VER_ENTRY(5, iwl_compressed_ba_notif) 308 CMD_VER_ENTRY(6, iwl_compressed_ba_notif) 309 CMD_VER_ENTRY(7, iwl_compressed_ba_notif)) 310CMD_VERSIONS(tlc_notif, 311 CMD_VER_ENTRY(3, iwl_tlc_update_notif) 312 CMD_VER_ENTRY(4, iwl_tlc_update_notif)) 313CMD_VERSIONS(mu_mimo_grp_notif, 314 CMD_VER_ENTRY(1, iwl_mu_group_mgmt_notif)) 315CMD_VERSIONS(channel_switch_start_notif, 316 CMD_VER_ENTRY(3, iwl_channel_switch_start_notif)) 317CMD_VERSIONS(channel_switch_error_notif, 318 CMD_VER_ENTRY(2, iwl_channel_switch_error_notif)) 319CMD_VERSIONS(ct_kill_notif, 320 CMD_VER_ENTRY(2, ct_kill_notif)) 321CMD_VERSIONS(temp_notif, 322 CMD_VER_ENTRY(2, iwl_dts_measurement_notif)) 323CMD_VERSIONS(roc_notif, 324 CMD_VER_ENTRY(1, iwl_roc_notif)) 325CMD_VERSIONS(probe_resp_data_notif, 326 CMD_VER_ENTRY(1, iwl_probe_resp_data_notif)) 327CMD_VERSIONS(datapath_monitor_notif, 328 CMD_VER_ENTRY(1, iwl_datapath_monitor_notif)) 329CMD_VERSIONS(stats_oper_notif, 330 CMD_VER_ENTRY(3, iwl_system_statistics_notif_oper)) 331CMD_VERSIONS(stats_oper_part1_notif, 332 CMD_VER_ENTRY(4, iwl_system_statistics_part1_notif_oper)) 333CMD_VERSIONS(bt_coex_notif, 334 CMD_VER_ENTRY(1, iwl_bt_coex_profile_notif)) 335CMD_VERSIONS(beacon_notification, 336 CMD_VER_ENTRY(6, iwl_extended_beacon_notif)) 337CMD_VERSIONS(emlsr_mode_notif, 338 CMD_VER_ENTRY(2, iwl_esr_mode_notif)) 339CMD_VERSIONS(emlsr_trans_fail_notif, 340 CMD_VER_ENTRY(1, iwl_esr_trans_fail_notif)) 341CMD_VERSIONS(uapsd_misbehaving_ap_notif, 342 CMD_VER_ENTRY(1, iwl_uapsd_misbehaving_ap_notif)) 343CMD_VERSIONS(time_msmt_notif, 344 CMD_VER_ENTRY(1, iwl_time_msmt_notify)) 345CMD_VERSIONS(time_sync_confirm_notif, 346 CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) 347CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) 348CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) 349 350DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id) 351DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id) 352DEFINE_SIMPLE_CANCELLATION(channel_switch_start, 353 iwl_channel_switch_start_notif, link_id) 354DEFINE_SIMPLE_CANCELLATION(channel_switch_error, 355 iwl_channel_switch_error_notif, link_id) 356DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif, 357 link_id) 358DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity) 359DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid) 360DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid) 361DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif, 362 mac_id) 363DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif, 364 mac_id) 365DEFINE_SIMPLE_CANCELLATION(ftm_resp, iwl_tof_range_rsp_ntfy, request_id) 366DEFINE_SIMPLE_CANCELLATION(beacon_filter, iwl_beacon_filter_notif, link_id) 367 368/** 369 * DOC: Handlers for fw notifications 370 * 371 * Here are listed the notifications IDs (including the group ID), the handler 372 * of the notification and how it should be called: 373 * 374 * - RX_HANDLER_SYNC: will be called as part of the Rx path 375 * - RX_HANDLER_ASYNC: will be handled in a working with the wiphy_lock held 376 * 377 * This means that if the firmware sends two notifications A and B in that 378 * order and notification A is RX_HANDLER_ASYNC and notification is 379 * RX_HANDLER_SYNC, the handler of B will likely be called before the handler 380 * of A. 381 * 382 * This list should be in order of frequency for performance purposes. 383 * The handler can be one from two contexts, see &iwl_rx_handler_context 384 * 385 * A handler can declare that it relies on a specific object in which case it 386 * can be cancelled in case the object is deleted. In order to use this 387 * mechanism, a cancellation function is needed. The cancellation function must 388 * receive an object id (the index of that object in the firmware) and a 389 * notification payload. It'll return true if that specific notification should 390 * be cancelled upon the obliteration of the specific instance of the object. 391 * 392 * DEFINE_SIMPLE_CANCELLATION allows to easily create a cancellation function 393 * that wills simply return true if a given object id matches the object id in 394 * the firmware notification. 395 */ 396 397VISIBLE_IF_IWLWIFI_KUNIT 398const struct iwl_rx_handler iwl_mld_rx_handlers[] = { 399 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, TX_CMD, tx_resp_notif, 400 RX_HANDLER_SYNC) 401 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif, 402 RX_HANDLER_SYNC) 403 RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC, 404 scan_start_notif) 405 RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC, 406 scan_complete_notif) 407 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC, 408 scan_iter_complete_notif, 409 RX_HANDLER_SYNC) 410 RX_HANDLER_NO_VAL(LEGACY_GROUP, MATCH_FOUND_NOTIFICATION, 411 match_found_notif, RX_HANDLER_SYNC) 412 413 RX_HANDLER_NO_OBJECT(SCAN_GROUP, CHANNEL_SURVEY_NOTIF, 414 channel_survey_notif, 415 RX_HANDLER_ASYNC) 416 417 RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_NOTIF, 418 stats_oper_notif, RX_HANDLER_ASYNC) 419 RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_PART1_NOTIF, 420 stats_oper_part1_notif, RX_HANDLER_ASYNC) 421 422 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, MFUART_LOAD_NOTIFICATION, 423 mfuart_notif, RX_HANDLER_SYNC) 424 425 RX_HANDLER_NO_OBJECT(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE, 426 temp_notif, RX_HANDLER_ASYNC) 427 RX_HANDLER_OF_LINK(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF, 428 session_prot_notif) 429 RX_HANDLER_OF_LINK(MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, 430 missed_beacon_notif) 431 RX_HANDLER_OF_STA(DATA_PATH_GROUP, TLC_MNG_UPDATE_NOTIF, tlc_notif) 432 RX_HANDLER_OF_LINK(MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF, 433 channel_switch_start_notif) 434 RX_HANDLER_OF_LINK(MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF, 435 channel_switch_error_notif) 436 RX_HANDLER_OF_ROC(MAC_CONF_GROUP, ROC_NOTIF, roc_notif) 437 RX_HANDLER_NO_OBJECT(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF, 438 mu_mimo_grp_notif, RX_HANDLER_SYNC) 439 RX_HANDLER_OF_VIF(MAC_CONF_GROUP, PROBE_RESPONSE_DATA_NOTIF, 440 probe_resp_data_notif) 441 RX_HANDLER_NO_OBJECT(PHY_OPS_GROUP, CT_KILL_NOTIFICATION, 442 ct_kill_notif, RX_HANDLER_ASYNC) 443 RX_HANDLER_OF_LINK(DATA_PATH_GROUP, MONITOR_NOTIF, 444 datapath_monitor_notif) 445 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, MCC_CHUB_UPDATE_CMD, update_mcc, 446 RX_HANDLER_ASYNC) 447 RX_HANDLER_NO_OBJECT(BT_COEX_GROUP, PROFILE_NOTIF, 448 bt_coex_notif, RX_HANDLER_ASYNC) 449 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BEACON_NOTIFICATION, 450 beacon_notification, RX_HANDLER_ASYNC) 451 RX_HANDLER_NO_OBJECT(DATA_PATH_GROUP, ESR_MODE_NOTIF, 452 emlsr_mode_notif, RX_HANDLER_ASYNC) 453 RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, EMLSR_TRANS_FAIL_NOTIF, 454 emlsr_trans_fail_notif, RX_HANDLER_ASYNC) 455 RX_HANDLER_OF_VIF(LEGACY_GROUP, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, 456 uapsd_misbehaving_ap_notif) 457 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, 458 WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION, 459 time_msmt_notif, RX_HANDLER_SYNC) 460 RX_HANDLER_NO_OBJECT(LEGACY_GROUP, 461 WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION, 462 time_sync_confirm_notif, RX_HANDLER_ASYNC) 463 RX_HANDLER_OF_LINK(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, 464 beacon_filter_notif) 465 RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, 466 ftm_resp_notif) 467}; 468EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers); 469 470#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) 471const unsigned int iwl_mld_rx_handlers_num = ARRAY_SIZE(iwl_mld_rx_handlers); 472EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers_num); 473#endif 474 475static bool 476iwl_mld_notif_is_valid(struct iwl_mld *mld, struct iwl_rx_packet *pkt, 477 const struct iwl_rx_handler *handler) 478{ 479 unsigned int size = iwl_rx_packet_payload_len(pkt); 480 size_t notif_ver; 481 482 /* If n_sizes == 0, it indicates that a validation function may be used 483 * or that no validation is required. 484 */ 485 if (!handler->n_sizes) { 486 if (handler->val_fn) 487 return handler->val_fn(mld, pkt); 488 return true; 489 } 490 491 notif_ver = iwl_fw_lookup_notif_ver(mld->fw, 492 iwl_cmd_groupid(handler->cmd_id), 493 iwl_cmd_opcode(handler->cmd_id), 494 IWL_FW_CMD_VER_UNKNOWN); 495 496 for (int i = 0; i < handler->n_sizes; i++) { 497 if (handler->sizes[i].ver != notif_ver) 498 continue; 499 500 if (IWL_FW_CHECK(mld, size < handler->sizes[i].size, 501 "unexpected notification 0x%04x size %d, need %d\n", 502 handler->cmd_id, size, handler->sizes[i].size)) 503 return false; 504 return true; 505 } 506 507 IWL_FW_CHECK_FAILED(mld, 508 "notif 0x%04x ver %zu missing expected size, use version %u size\n", 509 handler->cmd_id, notif_ver, 510 handler->sizes[handler->n_sizes - 1].ver); 511 512 return size < handler->sizes[handler->n_sizes - 1].size; 513} 514 515struct iwl_async_handler_entry { 516 struct list_head list; 517 struct iwl_rx_cmd_buffer rxb; 518 const struct iwl_rx_handler *rx_h; 519}; 520 521static void 522iwl_mld_log_async_handler_op(struct iwl_mld *mld, const char *op, 523 struct iwl_rx_cmd_buffer *rxb) 524{ 525 struct iwl_rx_packet *pkt = rxb_addr(rxb); 526 527 IWL_DEBUG_HC(mld, 528 "%s async handler for notif %s (%.2x.%2x, seq 0x%x)\n", 529 op, iwl_get_cmd_string(mld->trans, 530 WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)), 531 pkt->hdr.group_id, pkt->hdr.cmd, 532 le16_to_cpu(pkt->hdr.sequence)); 533} 534 535static void iwl_mld_rx_notif(struct iwl_mld *mld, 536 struct iwl_rx_cmd_buffer *rxb, 537 struct iwl_rx_packet *pkt) 538{ 539 for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) { 540 const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i]; 541 struct iwl_async_handler_entry *entry; 542 543 if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) 544 continue; 545 546 if (!iwl_mld_notif_is_valid(mld, pkt, rx_h)) 547 return; 548 549 if (rx_h->context == RX_HANDLER_SYNC) { 550 rx_h->fn(mld, pkt); 551 break; 552 } 553 554 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 555 /* we can't do much... */ 556 if (!entry) 557 return; 558 559 /* Set the async handler entry */ 560 entry->rxb._page = rxb_steal_page(rxb); 561 entry->rxb._offset = rxb->_offset; 562 entry->rxb._rx_page_order = rxb->_rx_page_order; 563 564 entry->rx_h = rx_h; 565 566 /* Add it to the list and queue the work */ 567 spin_lock(&mld->async_handlers_lock); 568 list_add_tail(&entry->list, &mld->async_handlers_list); 569 spin_unlock(&mld->async_handlers_lock); 570 571 wiphy_work_queue(mld->hw->wiphy, 572 &mld->async_handlers_wk); 573 574 iwl_mld_log_async_handler_op(mld, "Queued", rxb); 575 break; 576 } 577 578 iwl_notification_wait_notify(&mld->notif_wait, pkt); 579} 580 581void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi, 582 struct iwl_rx_cmd_buffer *rxb) 583{ 584 struct iwl_rx_packet *pkt = rxb_addr(rxb); 585 struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode); 586 u16 cmd_id = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); 587 588 if (likely(cmd_id == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))) 589 iwl_mld_rx_mpdu(mld, napi, rxb, 0); 590 else if (cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)) 591 iwl_mld_handle_frame_release_notif(mld, napi, pkt, 0); 592 else if (cmd_id == WIDE_ID(LEGACY_GROUP, BAR_FRAME_RELEASE)) 593 iwl_mld_handle_bar_frame_release_notif(mld, napi, pkt, 0); 594 else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP, 595 RX_QUEUES_NOTIFICATION))) 596 iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0); 597 else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, PHY_AIR_SNIFFER_NOTIF)) 598 iwl_mld_handle_phy_air_sniffer_notif(mld, napi, pkt); 599 else 600 iwl_mld_rx_notif(mld, rxb, pkt); 601} 602 603void iwl_mld_rx_rss(struct iwl_op_mode *op_mode, struct napi_struct *napi, 604 struct iwl_rx_cmd_buffer *rxb, unsigned int queue) 605{ 606 struct iwl_rx_packet *pkt = rxb_addr(rxb); 607 struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode); 608 u16 cmd_id = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); 609 610 if (unlikely(queue >= mld->trans->info.num_rxqs)) 611 return; 612 613 if (likely(cmd_id == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))) 614 iwl_mld_rx_mpdu(mld, napi, rxb, queue); 615 else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP, 616 RX_QUEUES_NOTIFICATION))) 617 iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, queue); 618 else if (unlikely(cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))) 619 iwl_mld_handle_frame_release_notif(mld, napi, pkt, queue); 620} 621 622void iwl_mld_delete_handlers(struct iwl_mld *mld, const u16 *cmds, int n_cmds) 623{ 624 struct iwl_async_handler_entry *entry, *tmp; 625 626 spin_lock_bh(&mld->async_handlers_lock); 627 list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) { 628 bool match = false; 629 630 for (int i = 0; i < n_cmds; i++) { 631 if (entry->rx_h->cmd_id == cmds[i]) { 632 match = true; 633 break; 634 } 635 } 636 637 if (!match) 638 continue; 639 640 iwl_mld_log_async_handler_op(mld, "Delete", &entry->rxb); 641 iwl_free_rxb(&entry->rxb); 642 list_del(&entry->list); 643 kfree(entry); 644 } 645 spin_unlock_bh(&mld->async_handlers_lock); 646} 647 648void iwl_mld_async_handlers_wk(struct wiphy *wiphy, struct wiphy_work *wk) 649{ 650 struct iwl_mld *mld = 651 container_of(wk, struct iwl_mld, async_handlers_wk); 652 struct iwl_async_handler_entry *entry, *tmp; 653 LIST_HEAD(local_list); 654 655 /* Sync with Rx path with a lock. Remove all the entries from this 656 * list, add them to a local one (lock free), and then handle them. 657 */ 658 spin_lock_bh(&mld->async_handlers_lock); 659 list_splice_init(&mld->async_handlers_list, &local_list); 660 spin_unlock_bh(&mld->async_handlers_lock); 661 662 list_for_each_entry_safe(entry, tmp, &local_list, list) { 663 iwl_mld_log_async_handler_op(mld, "Handle", &entry->rxb); 664 entry->rx_h->fn(mld, rxb_addr(&entry->rxb)); 665 iwl_free_rxb(&entry->rxb); 666 list_del(&entry->list); 667 kfree(entry); 668 } 669} 670 671void iwl_mld_cancel_async_notifications(struct iwl_mld *mld) 672{ 673 struct iwl_async_handler_entry *entry, *tmp; 674 675 lockdep_assert_wiphy(mld->wiphy); 676 677 wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk); 678 679 spin_lock_bh(&mld->async_handlers_lock); 680 list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) { 681 iwl_mld_log_async_handler_op(mld, "Purged", &entry->rxb); 682 iwl_free_rxb(&entry->rxb); 683 list_del(&entry->list); 684 kfree(entry); 685 } 686 spin_unlock_bh(&mld->async_handlers_lock); 687} 688 689void iwl_mld_cancel_notifications_of_object(struct iwl_mld *mld, 690 enum iwl_mld_object_type obj_type, 691 u32 obj_id) 692{ 693 struct iwl_async_handler_entry *entry, *tmp; 694 LIST_HEAD(cancel_list); 695 696 lockdep_assert_wiphy(mld->wiphy); 697 698 if (WARN_ON(obj_type == IWL_MLD_OBJECT_TYPE_NONE)) 699 return; 700 701 /* Sync with RX path and remove matching entries from the async list */ 702 spin_lock_bh(&mld->async_handlers_lock); 703 list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) { 704 const struct iwl_rx_handler *rx_h = entry->rx_h; 705 706 if (rx_h->obj_type != obj_type || WARN_ON(!rx_h->cancel)) 707 continue; 708 709 if (rx_h->cancel(mld, rxb_addr(&entry->rxb), obj_id)) { 710 iwl_mld_log_async_handler_op(mld, "Cancel", &entry->rxb); 711 list_del(&entry->list); 712 list_add_tail(&entry->list, &cancel_list); 713 } 714 } 715 716 spin_unlock_bh(&mld->async_handlers_lock); 717 718 /* Free the matching entries outside of the spinlock */ 719 list_for_each_entry_safe(entry, tmp, &cancel_list, list) { 720 iwl_free_rxb(&entry->rxb); 721 list_del(&entry->list); 722 kfree(entry); 723 } 724}
~/
Read-only file preview.