Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/iwlwifi/mld/notif.c
48285 views
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) \
69
static 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
114
static 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
130
static 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
#if defined(__linux__)
160
(u8 *)&notif->membership_status,
161
(u8 *)&notif->user_position);
162
#elif defined(__FreeBSD__)
163
(const u8 *)&notif->membership_status,
164
(const u8 *)&notif->user_position);
165
#endif
166
}
167
}
168
169
/* This handler is called in SYNC mode because it needs to be serialized with
170
* Rx as specified in ieee80211_update_mu_groups()'s documentation.
171
*/
172
static void iwl_mld_handle_mu_mimo_grp_notif(struct iwl_mld *mld,
173
struct iwl_rx_packet *pkt)
174
{
175
struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;
176
177
ieee80211_iterate_active_interfaces_atomic(mld->hw,
178
IEEE80211_IFACE_ITER_NORMAL,
179
iwl_mld_mu_mimo_iface_iterator,
180
notif);
181
}
182
183
static void
184
iwl_mld_handle_channel_switch_start_notif(struct iwl_mld *mld,
185
struct iwl_rx_packet *pkt)
186
{
187
struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;
188
u32 link_id = le32_to_cpu(notif->link_id);
189
struct ieee80211_bss_conf *link_conf =
190
iwl_mld_fw_id_to_link_conf(mld, link_id);
191
struct ieee80211_vif *vif;
192
193
if (WARN_ON(!link_conf))
194
return;
195
196
vif = link_conf->vif;
197
198
IWL_DEBUG_INFO(mld,
199
"CSA Start Notification with vif type: %d, link_id: %d\n",
200
vif->type,
201
link_conf->link_id);
202
203
switch (vif->type) {
204
case NL80211_IFTYPE_AP:
205
/* We don't support canceling a CSA as it was advertised
206
* by the AP itself
207
*/
208
if (!link_conf->csa_active)
209
return;
210
211
ieee80211_csa_finish(vif, link_conf->link_id);
212
break;
213
case NL80211_IFTYPE_STATION:
214
if (!link_conf->csa_active) {
215
/* Either unexpected cs notif or mac80211 chose to
216
* ignore, for example in channel switch to same channel
217
*/
218
struct iwl_cancel_channel_switch_cmd cmd = {
219
.id = cpu_to_le32(link_id),
220
};
221
222
if (iwl_mld_send_cmd_pdu(mld,
223
WIDE_ID(MAC_CONF_GROUP,
224
CANCEL_CHANNEL_SWITCH_CMD),
225
&cmd))
226
IWL_ERR(mld,
227
"Failed to cancel the channel switch\n");
228
return;
229
}
230
231
ieee80211_chswitch_done(vif, true, link_conf->link_id);
232
break;
233
234
default:
235
WARN(1, "CSA on invalid vif type: %d", vif->type);
236
}
237
}
238
239
static void
240
iwl_mld_handle_channel_switch_error_notif(struct iwl_mld *mld,
241
struct iwl_rx_packet *pkt)
242
{
243
struct iwl_channel_switch_error_notif *notif = (void *)pkt->data;
244
struct ieee80211_bss_conf *link_conf;
245
struct ieee80211_vif *vif;
246
u32 link_id = le32_to_cpu(notif->link_id);
247
u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask);
248
249
link_conf = iwl_mld_fw_id_to_link_conf(mld, link_id);
250
if (WARN_ON(!link_conf))
251
return;
252
253
vif = link_conf->vif;
254
255
IWL_DEBUG_INFO(mld, "FW reports CSA error: id=%u, csa_err_mask=%u\n",
256
link_id, csa_err_mask);
257
258
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
259
CS_ERR_LONG_DELAY_AFTER_CS |
260
CS_ERR_TX_BLOCK_TIMER_EXPIRED))
261
ieee80211_channel_switch_disconnect(vif);
262
}
263
264
static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
265
struct iwl_rx_packet *pkt)
266
{
267
struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
268
269
mld->ibss_manager = !!beacon->ibss_mgr_status;
270
}
271
272
/**
273
* DOC: Notification versioning
274
*
275
* The firmware's notifications change from time to time. In order to
276
* differentiate between different versions of the same notification, the
277
* firmware advertises the version of each notification.
278
* Here are listed all the notifications that are supported. Several versions
279
* of the same notification can be allowed at the same time:
280
*
281
* CMD_VERSION(my_multi_version_notif,
282
* CMD_VER_ENTRY(1, iwl_my_multi_version_notif_ver1)
283
* CMD_VER_ENTRY(2, iwl_my_multi_version_notif_ver2)
284
*
285
* etc...
286
*
287
* The driver will enforce that the notification coming from the firmware
288
* has its version listed here and it'll also enforce that the firmware sent
289
* at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
290
*/
291
292
CMD_VERSIONS(scan_complete_notif,
293
CMD_VER_ENTRY(1, iwl_umac_scan_complete))
294
CMD_VERSIONS(scan_iter_complete_notif,
295
CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif))
296
CMD_VERSIONS(channel_survey_notif,
297
CMD_VER_ENTRY(1, iwl_umac_scan_channel_survey_notif))
298
CMD_VERSIONS(mfuart_notif,
299
CMD_VER_ENTRY(2, iwl_mfuart_load_notif))
300
CMD_VERSIONS(update_mcc,
301
CMD_VER_ENTRY(1, iwl_mcc_chub_notif))
302
CMD_VERSIONS(session_prot_notif,
303
CMD_VER_ENTRY(3, iwl_session_prot_notif))
304
CMD_VERSIONS(missed_beacon_notif,
305
CMD_VER_ENTRY(5, iwl_missed_beacons_notif))
306
CMD_VERSIONS(tx_resp_notif,
307
CMD_VER_ENTRY(8, iwl_tx_resp)
308
CMD_VER_ENTRY(9, iwl_tx_resp))
309
CMD_VERSIONS(compressed_ba_notif,
310
CMD_VER_ENTRY(5, iwl_compressed_ba_notif)
311
CMD_VER_ENTRY(6, iwl_compressed_ba_notif)
312
CMD_VER_ENTRY(7, iwl_compressed_ba_notif))
313
CMD_VERSIONS(tlc_notif,
314
CMD_VER_ENTRY(3, iwl_tlc_update_notif)
315
CMD_VER_ENTRY(4, iwl_tlc_update_notif))
316
CMD_VERSIONS(mu_mimo_grp_notif,
317
CMD_VER_ENTRY(1, iwl_mu_group_mgmt_notif))
318
CMD_VERSIONS(channel_switch_start_notif,
319
CMD_VER_ENTRY(3, iwl_channel_switch_start_notif))
320
CMD_VERSIONS(channel_switch_error_notif,
321
CMD_VER_ENTRY(2, iwl_channel_switch_error_notif))
322
CMD_VERSIONS(ct_kill_notif,
323
CMD_VER_ENTRY(2, ct_kill_notif))
324
CMD_VERSIONS(temp_notif,
325
CMD_VER_ENTRY(2, iwl_dts_measurement_notif))
326
CMD_VERSIONS(roc_notif,
327
CMD_VER_ENTRY(1, iwl_roc_notif))
328
CMD_VERSIONS(probe_resp_data_notif,
329
CMD_VER_ENTRY(1, iwl_probe_resp_data_notif))
330
CMD_VERSIONS(datapath_monitor_notif,
331
CMD_VER_ENTRY(1, iwl_datapath_monitor_notif))
332
CMD_VERSIONS(stats_oper_notif,
333
CMD_VER_ENTRY(3, iwl_system_statistics_notif_oper))
334
CMD_VERSIONS(stats_oper_part1_notif,
335
CMD_VER_ENTRY(4, iwl_system_statistics_part1_notif_oper))
336
CMD_VERSIONS(bt_coex_notif,
337
CMD_VER_ENTRY(1, iwl_bt_coex_profile_notif))
338
CMD_VERSIONS(beacon_notification,
339
CMD_VER_ENTRY(6, iwl_extended_beacon_notif))
340
CMD_VERSIONS(emlsr_mode_notif,
341
CMD_VER_ENTRY(1, iwl_esr_mode_notif_v1)
342
CMD_VER_ENTRY(2, iwl_esr_mode_notif))
343
CMD_VERSIONS(emlsr_trans_fail_notif,
344
CMD_VER_ENTRY(1, iwl_esr_trans_fail_notif))
345
CMD_VERSIONS(uapsd_misbehaving_ap_notif,
346
CMD_VER_ENTRY(1, iwl_uapsd_misbehaving_ap_notif))
347
CMD_VERSIONS(time_msmt_notif,
348
CMD_VER_ENTRY(1, iwl_time_msmt_notify))
349
CMD_VERSIONS(time_sync_confirm_notif,
350
CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify))
351
CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy))
352
CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif))
353
354
DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id)
355
DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id)
356
DEFINE_SIMPLE_CANCELLATION(channel_switch_start,
357
iwl_channel_switch_start_notif, link_id)
358
DEFINE_SIMPLE_CANCELLATION(channel_switch_error,
359
iwl_channel_switch_error_notif, link_id)
360
DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
361
link_id)
362
DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
363
DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
364
DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
365
mac_id)
366
DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
367
mac_id)
368
DEFINE_SIMPLE_CANCELLATION(ftm_resp, iwl_tof_range_rsp_ntfy, request_id)
369
DEFINE_SIMPLE_CANCELLATION(beacon_filter, iwl_beacon_filter_notif, link_id)
370
371
/**
372
* DOC: Handlers for fw notifications
373
*
374
* Here are listed the notifications IDs (including the group ID), the handler
375
* of the notification and how it should be called:
376
*
377
* - RX_HANDLER_SYNC: will be called as part of the Rx path
378
* - RX_HANDLER_ASYNC: will be handled in a working with the wiphy_lock held
379
*
380
* This means that if the firmware sends two notifications A and B in that
381
* order and notification A is RX_HANDLER_ASYNC and notification is
382
* RX_HANDLER_SYNC, the handler of B will likely be called before the handler
383
* of A.
384
*
385
* This list should be in order of frequency for performance purposes.
386
* The handler can be one from two contexts, see &iwl_rx_handler_context
387
*
388
* A handler can declare that it relies on a specific object in which case it
389
* can be cancelled in case the object is deleted. In order to use this
390
* mechanism, a cancellation function is needed. The cancellation function must
391
* receive an object id (the index of that object in the firmware) and a
392
* notification payload. It'll return true if that specific notification should
393
* be cancelled upon the obliteration of the specific instance of the object.
394
*
395
* DEFINE_SIMPLE_CANCELLATION allows to easily create a cancellation function
396
* that wills simply return true if a given object id matches the object id in
397
* the firmware notification.
398
*/
399
400
VISIBLE_IF_IWLWIFI_KUNIT
401
const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
402
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, TX_CMD, tx_resp_notif,
403
RX_HANDLER_SYNC)
404
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
405
RX_HANDLER_SYNC)
406
RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
407
scan_complete_notif)
408
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
409
scan_iter_complete_notif,
410
RX_HANDLER_SYNC)
411
RX_HANDLER_NO_VAL(LEGACY_GROUP, MATCH_FOUND_NOTIFICATION,
412
match_found_notif, RX_HANDLER_SYNC)
413
414
RX_HANDLER_NO_OBJECT(SCAN_GROUP, CHANNEL_SURVEY_NOTIF,
415
channel_survey_notif,
416
RX_HANDLER_ASYNC)
417
418
RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_NOTIF,
419
stats_oper_notif, RX_HANDLER_ASYNC)
420
RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_PART1_NOTIF,
421
stats_oper_part1_notif, RX_HANDLER_ASYNC)
422
423
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, MFUART_LOAD_NOTIFICATION,
424
mfuart_notif, RX_HANDLER_SYNC)
425
426
RX_HANDLER_NO_OBJECT(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE,
427
temp_notif, RX_HANDLER_ASYNC)
428
RX_HANDLER_OF_LINK(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF,
429
session_prot_notif)
430
RX_HANDLER_OF_LINK(MAC_CONF_GROUP, MISSED_BEACONS_NOTIF,
431
missed_beacon_notif)
432
RX_HANDLER_OF_STA(DATA_PATH_GROUP, TLC_MNG_UPDATE_NOTIF, tlc_notif)
433
RX_HANDLER_OF_LINK(MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF,
434
channel_switch_start_notif)
435
RX_HANDLER_OF_LINK(MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF,
436
channel_switch_error_notif)
437
RX_HANDLER_OF_ROC(MAC_CONF_GROUP, ROC_NOTIF, roc_notif)
438
RX_HANDLER_NO_OBJECT(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF,
439
mu_mimo_grp_notif, RX_HANDLER_SYNC)
440
RX_HANDLER_OF_VIF(MAC_CONF_GROUP, PROBE_RESPONSE_DATA_NOTIF,
441
probe_resp_data_notif)
442
RX_HANDLER_NO_OBJECT(PHY_OPS_GROUP, CT_KILL_NOTIFICATION,
443
ct_kill_notif, RX_HANDLER_ASYNC)
444
RX_HANDLER_OF_LINK(DATA_PATH_GROUP, MONITOR_NOTIF,
445
datapath_monitor_notif)
446
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, MCC_CHUB_UPDATE_CMD, update_mcc,
447
RX_HANDLER_ASYNC)
448
RX_HANDLER_NO_OBJECT(BT_COEX_GROUP, PROFILE_NOTIF,
449
bt_coex_notif, RX_HANDLER_ASYNC)
450
RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BEACON_NOTIFICATION,
451
beacon_notification, RX_HANDLER_ASYNC)
452
RX_HANDLER_NO_OBJECT(DATA_PATH_GROUP, ESR_MODE_NOTIF,
453
emlsr_mode_notif, RX_HANDLER_ASYNC)
454
RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, EMLSR_TRANS_FAIL_NOTIF,
455
emlsr_trans_fail_notif, RX_HANDLER_ASYNC)
456
RX_HANDLER_OF_VIF(LEGACY_GROUP, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
457
uapsd_misbehaving_ap_notif)
458
RX_HANDLER_NO_OBJECT(LEGACY_GROUP,
459
WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION,
460
time_msmt_notif, RX_HANDLER_SYNC)
461
RX_HANDLER_NO_OBJECT(LEGACY_GROUP,
462
WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION,
463
time_sync_confirm_notif, RX_HANDLER_ASYNC)
464
RX_HANDLER_OF_LINK(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF,
465
beacon_filter_notif)
466
RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF,
467
ftm_resp_notif)
468
};
469
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers);
470
471
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
472
const unsigned int iwl_mld_rx_handlers_num = ARRAY_SIZE(iwl_mld_rx_handlers);
473
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers_num);
474
#endif
475
476
static bool
477
iwl_mld_notif_is_valid(struct iwl_mld *mld, struct iwl_rx_packet *pkt,
478
const struct iwl_rx_handler *handler)
479
{
480
unsigned int size = iwl_rx_packet_payload_len(pkt);
481
size_t notif_ver;
482
483
/* If n_sizes == 0, it indicates that a validation function may be used
484
* or that no validation is required.
485
*/
486
if (!handler->n_sizes) {
487
if (handler->val_fn)
488
return handler->val_fn(mld, pkt);
489
return true;
490
}
491
492
notif_ver = iwl_fw_lookup_notif_ver(mld->fw,
493
iwl_cmd_groupid(handler->cmd_id),
494
iwl_cmd_opcode(handler->cmd_id),
495
IWL_FW_CMD_VER_UNKNOWN);
496
497
for (int i = 0; i < handler->n_sizes; i++) {
498
if (handler->sizes[i].ver != notif_ver)
499
continue;
500
501
if (IWL_FW_CHECK(mld, size < handler->sizes[i].size,
502
"unexpected notification 0x%04x size %d, need %d\n",
503
handler->cmd_id, size, handler->sizes[i].size))
504
return false;
505
return true;
506
}
507
508
IWL_FW_CHECK_FAILED(mld,
509
"notif 0x%04x ver %zu missing expected size, use version %u size\n",
510
handler->cmd_id, notif_ver,
511
handler->sizes[handler->n_sizes - 1].ver);
512
513
return size < handler->sizes[handler->n_sizes - 1].size;
514
}
515
516
struct iwl_async_handler_entry {
517
struct list_head list;
518
struct iwl_rx_cmd_buffer rxb;
519
const struct iwl_rx_handler *rx_h;
520
};
521
522
static void
523
iwl_mld_log_async_handler_op(struct iwl_mld *mld, const char *op,
524
struct iwl_rx_cmd_buffer *rxb)
525
{
526
struct iwl_rx_packet *pkt = rxb_addr(rxb);
527
528
IWL_DEBUG_HC(mld,
529
"%s async handler for notif %s (%.2x.%2x, seq 0x%x)\n",
530
op, iwl_get_cmd_string(mld->trans,
531
WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)),
532
pkt->hdr.group_id, pkt->hdr.cmd,
533
le16_to_cpu(pkt->hdr.sequence));
534
}
535
536
static void iwl_mld_rx_notif(struct iwl_mld *mld,
537
struct iwl_rx_cmd_buffer *rxb,
538
struct iwl_rx_packet *pkt)
539
{
540
for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) {
541
const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i];
542
struct iwl_async_handler_entry *entry;
543
544
if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd))
545
continue;
546
547
if (!iwl_mld_notif_is_valid(mld, pkt, rx_h))
548
return;
549
550
if (rx_h->context == RX_HANDLER_SYNC) {
551
rx_h->fn(mld, pkt);
552
break;
553
}
554
555
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
556
/* we can't do much... */
557
if (!entry)
558
return;
559
560
/* Set the async handler entry */
561
entry->rxb._page = rxb_steal_page(rxb);
562
entry->rxb._offset = rxb->_offset;
563
entry->rxb._rx_page_order = rxb->_rx_page_order;
564
565
entry->rx_h = rx_h;
566
567
/* Add it to the list and queue the work */
568
spin_lock(&mld->async_handlers_lock);
569
list_add_tail(&entry->list, &mld->async_handlers_list);
570
spin_unlock(&mld->async_handlers_lock);
571
572
wiphy_work_queue(mld->hw->wiphy,
573
&mld->async_handlers_wk);
574
575
iwl_mld_log_async_handler_op(mld, "Queued", rxb);
576
break;
577
}
578
579
iwl_notification_wait_notify(&mld->notif_wait, pkt);
580
}
581
582
void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi,
583
struct iwl_rx_cmd_buffer *rxb)
584
{
585
struct iwl_rx_packet *pkt = rxb_addr(rxb);
586
struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
587
u16 cmd_id = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
588
589
if (likely(cmd_id == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
590
iwl_mld_rx_mpdu(mld, napi, rxb, 0);
591
else if (cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))
592
iwl_mld_handle_frame_release_notif(mld, napi, pkt, 0);
593
else if (cmd_id == WIDE_ID(LEGACY_GROUP, BAR_FRAME_RELEASE))
594
iwl_mld_handle_bar_frame_release_notif(mld, napi, pkt, 0);
595
else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
596
RX_QUEUES_NOTIFICATION)))
597
iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0);
598
else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF))
599
iwl_mld_rx_monitor_no_data(mld, napi, pkt, 0);
600
else
601
iwl_mld_rx_notif(mld, rxb, pkt);
602
}
603
604
void iwl_mld_rx_rss(struct iwl_op_mode *op_mode, struct napi_struct *napi,
605
struct iwl_rx_cmd_buffer *rxb, unsigned int queue)
606
{
607
struct iwl_rx_packet *pkt = rxb_addr(rxb);
608
struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
609
u16 cmd_id = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
610
611
if (unlikely(queue >= mld->trans->info.num_rxqs))
612
return;
613
614
if (likely(cmd_id == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
615
iwl_mld_rx_mpdu(mld, napi, rxb, queue);
616
else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
617
RX_QUEUES_NOTIFICATION)))
618
iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, queue);
619
else if (unlikely(cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)))
620
iwl_mld_handle_frame_release_notif(mld, napi, pkt, queue);
621
}
622
623
void iwl_mld_delete_handlers(struct iwl_mld *mld, const u16 *cmds, int n_cmds)
624
{
625
struct iwl_async_handler_entry *entry, *tmp;
626
627
spin_lock_bh(&mld->async_handlers_lock);
628
list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) {
629
bool match = false;
630
631
for (int i = 0; i < n_cmds; i++) {
632
if (entry->rx_h->cmd_id == cmds[i]) {
633
match = true;
634
break;
635
}
636
}
637
638
if (!match)
639
continue;
640
641
iwl_mld_log_async_handler_op(mld, "Delete", &entry->rxb);
642
iwl_free_rxb(&entry->rxb);
643
list_del(&entry->list);
644
kfree(entry);
645
}
646
spin_unlock_bh(&mld->async_handlers_lock);
647
}
648
649
void iwl_mld_async_handlers_wk(struct wiphy *wiphy, struct wiphy_work *wk)
650
{
651
struct iwl_mld *mld =
652
container_of(wk, struct iwl_mld, async_handlers_wk);
653
struct iwl_async_handler_entry *entry, *tmp;
654
LIST_HEAD(local_list);
655
656
/* Sync with Rx path with a lock. Remove all the entries from this
657
* list, add them to a local one (lock free), and then handle them.
658
*/
659
spin_lock_bh(&mld->async_handlers_lock);
660
list_splice_init(&mld->async_handlers_list, &local_list);
661
spin_unlock_bh(&mld->async_handlers_lock);
662
663
list_for_each_entry_safe(entry, tmp, &local_list, list) {
664
iwl_mld_log_async_handler_op(mld, "Handle", &entry->rxb);
665
entry->rx_h->fn(mld, rxb_addr(&entry->rxb));
666
iwl_free_rxb(&entry->rxb);
667
list_del(&entry->list);
668
kfree(entry);
669
}
670
}
671
672
void iwl_mld_cancel_async_notifications(struct iwl_mld *mld)
673
{
674
struct iwl_async_handler_entry *entry, *tmp;
675
676
lockdep_assert_wiphy(mld->wiphy);
677
678
wiphy_work_cancel(mld->wiphy, &mld->async_handlers_wk);
679
680
spin_lock_bh(&mld->async_handlers_lock);
681
list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) {
682
iwl_mld_log_async_handler_op(mld, "Purged", &entry->rxb);
683
iwl_free_rxb(&entry->rxb);
684
list_del(&entry->list);
685
kfree(entry);
686
}
687
spin_unlock_bh(&mld->async_handlers_lock);
688
}
689
690
void iwl_mld_cancel_notifications_of_object(struct iwl_mld *mld,
691
enum iwl_mld_object_type obj_type,
692
u32 obj_id)
693
{
694
struct iwl_async_handler_entry *entry, *tmp;
695
LIST_HEAD(cancel_list);
696
697
lockdep_assert_wiphy(mld->wiphy);
698
699
if (WARN_ON(obj_type == IWL_MLD_OBJECT_TYPE_NONE))
700
return;
701
702
/* Sync with RX path and remove matching entries from the async list */
703
spin_lock_bh(&mld->async_handlers_lock);
704
list_for_each_entry_safe(entry, tmp, &mld->async_handlers_list, list) {
705
const struct iwl_rx_handler *rx_h = entry->rx_h;
706
707
if (rx_h->obj_type != obj_type || WARN_ON(!rx_h->cancel))
708
continue;
709
710
if (rx_h->cancel(mld, rxb_addr(&entry->rxb), obj_id)) {
711
iwl_mld_log_async_handler_op(mld, "Cancel", &entry->rxb);
712
list_del(&entry->list);
713
list_add_tail(&entry->list, &cancel_list);
714
}
715
}
716
717
spin_unlock_bh(&mld->async_handlers_lock);
718
719
/* Free the matching entries outside of the spinlock */
720
list_for_each_entry_safe(entry, tmp, &cancel_list, list) {
721
iwl_free_rxb(&entry->rxb);
722
list_del(&entry->list);
723
kfree(entry);
724
}
725
}
726
727