File Index
Files and directories
Sign in
FILE

mld.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/mld.c C
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2024-2025 Intel Corporation
  4 */
  5#include <linux/rtnetlink.h>
  6#include <net/mac80211.h>
  7
  8#include "fw/api/rx.h"
  9#include "fw/api/datapath.h"
 10#include "fw/api/commands.h"
 11#include "fw/api/offload.h"
 12#include "fw/api/coex.h"
 13#include "fw/dbg.h"
 14#include "fw/uefi.h"
 15
 16#include "mld.h"
 17#include "mlo.h"
 18#include "mac80211.h"
 19#include "led.h"
 20#include "scan.h"
 21#include "tx.h"
 22#include "sta.h"
 23#include "regulatory.h"
 24#include "thermal.h"
 25#include "low_latency.h"
 26#include "hcmd.h"
 27#include "fw/api/location.h"
 28
 29#include "iwl-nvm-parse.h"
 30
 31#define DRV_DESCRIPTION "Intel(R) MLD wireless driver for Linux"
 32MODULE_DESCRIPTION(DRV_DESCRIPTION);
 33MODULE_LICENSE("GPL");
 34MODULE_IMPORT_NS("IWLWIFI");
 35
 36static const struct iwl_op_mode_ops iwl_mld_ops;
 37
 38static int __init iwl_mld_init(void)
 39{
 40	int ret = iwl_opmode_register("iwlmld", &iwl_mld_ops);
 41
 42	if (ret)
 43		pr_err("Unable to register MLD op_mode: %d\n", ret);
 44
 45	return ret;
 46}
 47module_init(iwl_mld_init);
 48
 49static void __exit iwl_mld_exit(void)
 50{
 51	iwl_opmode_deregister("iwlmld");
 52}
 53module_exit(iwl_mld_exit);
 54
 55static void iwl_mld_hw_set_regulatory(struct iwl_mld *mld)
 56{
 57	struct wiphy *wiphy = mld->wiphy;
 58
 59	wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
 60	wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR;
 61}
 62
 63VISIBLE_IF_IWLWIFI_KUNIT
 64void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans,
 65		       const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw,
 66		       struct ieee80211_hw *hw, struct dentry *dbgfs_dir)
 67{
 68	mld->dev = trans->dev;
 69	mld->trans = trans;
 70	mld->cfg = cfg;
 71	mld->fw = fw;
 72	mld->hw = hw;
 73	mld->wiphy = hw->wiphy;
 74	mld->debugfs_dir = dbgfs_dir;
 75
 76	iwl_notification_wait_init(&mld->notif_wait);
 77
 78	/* Setup async RX handling */
 79	spin_lock_init(&mld->async_handlers_lock);
 80	INIT_LIST_HEAD(&mld->async_handlers_list);
 81	wiphy_work_init(&mld->async_handlers_wk,
 82			iwl_mld_async_handlers_wk);
 83
 84	/* Dynamic Queue Allocation */
 85	spin_lock_init(&mld->add_txqs_lock);
 86	INIT_LIST_HEAD(&mld->txqs_to_add);
 87	wiphy_work_init(&mld->add_txqs_wk, iwl_mld_add_txqs_wk);
 88
 89	/* Setup RX queues sync wait queue */
 90	init_waitqueue_head(&mld->rxq_sync.waitq);
 91}
 92EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_construct_mld);
 93
 94static void __acquires(&mld->wiphy->mtx)
 95iwl_mld_fwrt_dump_start(void *ctx)
 96{
 97	struct iwl_mld *mld = ctx;
 98
 99	wiphy_lock(mld->wiphy);
100}
101
102static void __releases(&mld->wiphy->mtx)
103iwl_mld_fwrt_dump_end(void *ctx)
104{
105	struct iwl_mld *mld = ctx;
106
107	wiphy_unlock(mld->wiphy);
108}
109
110static bool iwl_mld_d3_debug_enable(void *ctx)
111{
112	return IWL_MLD_D3_DEBUG;
113}
114
115static int iwl_mld_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd)
116{
117	struct iwl_mld *mld = (struct iwl_mld *)ctx;
118	int ret;
119
120	wiphy_lock(mld->wiphy);
121	ret = iwl_mld_send_cmd(mld, host_cmd);
122	wiphy_unlock(mld->wiphy);
123
124	return ret;
125}
126
127static const struct iwl_fw_runtime_ops iwl_mld_fwrt_ops = {
128	.dump_start = iwl_mld_fwrt_dump_start,
129	.dump_end = iwl_mld_fwrt_dump_end,
130	.send_hcmd = iwl_mld_fwrt_send_hcmd,
131	.d3_debug_enable = iwl_mld_d3_debug_enable,
132};
133
134static void
135iwl_mld_construct_fw_runtime(struct iwl_mld *mld, struct iwl_trans *trans,
136			     const struct iwl_fw *fw,
137			     struct dentry *debugfs_dir)
138{
139	iwl_fw_runtime_init(&mld->fwrt, trans, fw, &iwl_mld_fwrt_ops, mld,
140			    NULL, NULL, debugfs_dir);
141
142	iwl_fw_set_current_image(&mld->fwrt, IWL_UCODE_REGULAR);
143}
144
145/* Please keep this array *SORTED* by hex value.
146 * Access is done through binary search
147 */
148static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
149	HCMD_NAME(UCODE_ALIVE_NTFY),
150	HCMD_NAME(REPLY_ERROR),
151	HCMD_NAME(INIT_COMPLETE_NOTIF),
152	HCMD_NAME(PHY_CONTEXT_CMD),
153	HCMD_NAME(SCAN_CFG_CMD),
154	HCMD_NAME(SCAN_REQ_UMAC),
155	HCMD_NAME(SCAN_ABORT_UMAC),
156	HCMD_NAME(SCAN_COMPLETE_UMAC),
157	HCMD_NAME(TX_CMD),
158	HCMD_NAME(TXPATH_FLUSH),
159	HCMD_NAME(LEDS_CMD),
160	HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION),
161	HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION),
162	HCMD_NAME(PHY_CONFIGURATION_CMD),
163	HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
164	HCMD_NAME(POWER_TABLE_CMD),
165	HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
166	HCMD_NAME(BEACON_NOTIFICATION),
167	HCMD_NAME(BEACON_TEMPLATE_CMD),
168	HCMD_NAME(TX_ANT_CONFIGURATION_CMD),
169	HCMD_NAME(BT_CONFIG),
170	HCMD_NAME(REDUCE_TX_POWER_CMD),
171	HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
172	HCMD_NAME(MAC_PM_POWER_TABLE),
173	HCMD_NAME(MFUART_LOAD_NOTIFICATION),
174	HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
175	HCMD_NAME(RSS_CONFIG_CMD),
176	HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
177	HCMD_NAME(REPLY_RX_MPDU_CMD),
178	HCMD_NAME(BA_NOTIF),
179	HCMD_NAME(MCC_UPDATE_CMD),
180	HCMD_NAME(MCC_CHUB_UPDATE_CMD),
181	HCMD_NAME(MCAST_FILTER_CMD),
182	HCMD_NAME(REPLY_BEACON_FILTERING_CMD),
183	HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD),
184	HCMD_NAME(MATCH_FOUND_NOTIFICATION),
185	HCMD_NAME(WOWLAN_PATTERNS),
186	HCMD_NAME(WOWLAN_CONFIGURATION),
187	HCMD_NAME(WOWLAN_TSC_RSC_PARAM),
188	HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL),
189	HCMD_NAME(DEBUG_HOST_COMMAND),
190	HCMD_NAME(LDBG_CONFIG_CMD),
191};
192
193/* Please keep this array *SORTED* by hex value.
194 * Access is done through binary search
195 */
196static const struct iwl_hcmd_names iwl_mld_system_names[] = {
197	HCMD_NAME(SHARED_MEM_CFG_CMD),
198	HCMD_NAME(SOC_CONFIGURATION_CMD),
199	HCMD_NAME(INIT_EXTENDED_CFG_CMD),
200	HCMD_NAME(FW_ERROR_RECOVERY_CMD),
201	HCMD_NAME(RFI_CONFIG_CMD),
202	HCMD_NAME(RFI_GET_FREQ_TABLE_CMD),
203	HCMD_NAME(SYSTEM_STATISTICS_CMD),
204	HCMD_NAME(SYSTEM_STATISTICS_END_NOTIF),
205};
206
207/* Please keep this array *SORTED* by hex value.
208 * Access is done through binary search
209 */
210static const struct iwl_hcmd_names iwl_mld_reg_and_nvm_names[] = {
211	HCMD_NAME(LARI_CONFIG_CHANGE),
212	HCMD_NAME(NVM_GET_INFO),
213	HCMD_NAME(TAS_CONFIG),
214	HCMD_NAME(SAR_OFFSET_MAPPING_TABLE_CMD),
215	HCMD_NAME(MCC_ALLOWED_AP_TYPE_CMD),
216};
217
218/* Please keep this array *SORTED* by hex value.
219 * Access is done through binary search
220 */
221static const struct iwl_hcmd_names iwl_mld_debug_names[] = {
222	HCMD_NAME(HOST_EVENT_CFG),
223	HCMD_NAME(DBGC_SUSPEND_RESUME),
224};
225
226/* Please keep this array *SORTED* by hex value.
227 * Access is done through binary search
228 */
229static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = {
230	HCMD_NAME(LOW_LATENCY_CMD),
231	HCMD_NAME(SESSION_PROTECTION_CMD),
232	HCMD_NAME(MAC_CONFIG_CMD),
233	HCMD_NAME(LINK_CONFIG_CMD),
234	HCMD_NAME(STA_CONFIG_CMD),
235	HCMD_NAME(AUX_STA_CMD),
236	HCMD_NAME(STA_REMOVE_CMD),
237	HCMD_NAME(ROC_CMD),
238	HCMD_NAME(MISSED_BEACONS_NOTIF),
239	HCMD_NAME(EMLSR_TRANS_FAIL_NOTIF),
240	HCMD_NAME(ROC_NOTIF),
241	HCMD_NAME(CHANNEL_SWITCH_ERROR_NOTIF),
242	HCMD_NAME(SESSION_PROTECTION_NOTIF),
243	HCMD_NAME(PROBE_RESPONSE_DATA_NOTIF),
244	HCMD_NAME(CHANNEL_SWITCH_START_NOTIF),
245};
246
247/* Please keep this array *SORTED* by hex value.
248 * Access is done through binary search
249 */
250static const struct iwl_hcmd_names iwl_mld_data_path_names[] = {
251	HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD),
252	HCMD_NAME(WNM_PLATFORM_PTM_REQUEST_CMD),
253	HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD),
254	HCMD_NAME(RFH_QUEUE_CONFIG_CMD),
255	HCMD_NAME(TLC_MNG_CONFIG_CMD),
256	HCMD_NAME(RX_BAID_ALLOCATION_CONFIG_CMD),
257	HCMD_NAME(SCD_QUEUE_CONFIG_CMD),
258	HCMD_NAME(SEC_KEY_CMD),
259	HCMD_NAME(ESR_MODE_NOTIF),
260	HCMD_NAME(MONITOR_NOTIF),
261	HCMD_NAME(TLC_MNG_UPDATE_NOTIF),
262	HCMD_NAME(BEACON_FILTER_IN_NOTIF),
263	HCMD_NAME(PHY_AIR_SNIFFER_NOTIF),
264	HCMD_NAME(MU_GROUP_MGMT_NOTIF),
265};
266
267/* Please keep this array *SORTED* by hex value.
268 * Access is done through binary search
269 */
270static const struct iwl_hcmd_names iwl_mld_scan_names[] = {
271	HCMD_NAME(CHANNEL_SURVEY_NOTIF),
272};
273
274/* Please keep this array *SORTED* by hex value.
275 * Access is done through binary search
276 */
277static const struct iwl_hcmd_names iwl_mld_location_names[] = {
278	HCMD_NAME(TOF_RANGE_REQ_CMD),
279	HCMD_NAME(TOF_RANGE_RESPONSE_NOTIF),
280};
281
282/* Please keep this array *SORTED* by hex value.
283 * Access is done through binary search
284 */
285static const struct iwl_hcmd_names iwl_mld_phy_names[] = {
286	HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
287	HCMD_NAME(CTDP_CONFIG_CMD),
288	HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD),
289	HCMD_NAME(PER_CHAIN_LIMIT_OFFSET_CMD),
290	HCMD_NAME(CT_KILL_NOTIFICATION),
291	HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
292};
293
294/* Please keep this array *SORTED* by hex value.
295 * Access is done through binary search
296 */
297static const struct iwl_hcmd_names iwl_mld_statistics_names[] = {
298	HCMD_NAME(STATISTICS_OPER_NOTIF),
299	HCMD_NAME(STATISTICS_OPER_PART1_NOTIF),
300};
301
302/* Please keep this array *SORTED* by hex value.
303 * Access is done through binary search
304 */
305static const struct iwl_hcmd_names iwl_mld_prot_offload_names[] = {
306	HCMD_NAME(WOWLAN_WAKE_PKT_NOTIFICATION),
307	HCMD_NAME(WOWLAN_INFO_NOTIFICATION),
308	HCMD_NAME(D3_END_NOTIFICATION),
309};
310
311/* Please keep this array *SORTED* by hex value.
312 * Access is done through binary search
313 */
314static const struct iwl_hcmd_names iwl_mld_coex_names[] = {
315	HCMD_NAME(PROFILE_NOTIF),
316};
317
318VISIBLE_IF_IWLWIFI_KUNIT
319const struct iwl_hcmd_arr iwl_mld_groups[] = {
320	[LEGACY_GROUP] = HCMD_ARR(iwl_mld_legacy_names),
321	[LONG_GROUP] = HCMD_ARR(iwl_mld_legacy_names),
322	[SYSTEM_GROUP] = HCMD_ARR(iwl_mld_system_names),
323	[MAC_CONF_GROUP] = HCMD_ARR(iwl_mld_mac_conf_names),
324	[DATA_PATH_GROUP] = HCMD_ARR(iwl_mld_data_path_names),
325	[SCAN_GROUP] = HCMD_ARR(iwl_mld_scan_names),
326	[LOCATION_GROUP] = HCMD_ARR(iwl_mld_location_names),
327	[REGULATORY_AND_NVM_GROUP] = HCMD_ARR(iwl_mld_reg_and_nvm_names),
328	[DEBUG_GROUP] = HCMD_ARR(iwl_mld_debug_names),
329	[PHY_OPS_GROUP] = HCMD_ARR(iwl_mld_phy_names),
330	[STATISTICS_GROUP] = HCMD_ARR(iwl_mld_statistics_names),
331	[PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mld_prot_offload_names),
332	[BT_COEX_GROUP] = HCMD_ARR(iwl_mld_coex_names),
333};
334EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_groups);
335
336#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
337const unsigned int global_iwl_mld_goups_size = ARRAY_SIZE(iwl_mld_groups);
338EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(global_iwl_mld_goups_size);
339#endif
340
341static void
342iwl_mld_configure_trans(struct iwl_op_mode *op_mode)
343{
344	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
345	static const u8 no_reclaim_cmds[] = {TX_CMD};
346	struct iwl_trans *trans = mld->trans;
347	u32 eckv_value;
348
349	iwl_bios_setup_step(trans, &mld->fwrt);
350	iwl_uefi_get_step_table(trans);
351
352	if (iwl_bios_get_eckv(&mld->fwrt, &eckv_value))
353		IWL_DEBUG_RADIO(mld, "ECKV table doesn't exist in BIOS\n");
354	else
355		trans->conf.ext_32khz_clock_valid = !!eckv_value;
356
357	trans->conf.rx_buf_size = iwl_amsdu_size_to_rxb_size();
358	trans->conf.command_groups = iwl_mld_groups;
359	trans->conf.command_groups_size = ARRAY_SIZE(iwl_mld_groups);
360	trans->conf.fw_reset_handshake = true;
361	trans->conf.queue_alloc_cmd_ver =
362		iwl_fw_lookup_cmd_ver(mld->fw, WIDE_ID(DATA_PATH_GROUP,
363						       SCD_QUEUE_CONFIG_CMD),
364				      0);
365	trans->conf.cb_data_offs = offsetof(struct ieee80211_tx_info,
366					    driver_data[2]);
367	BUILD_BUG_ON(sizeof(no_reclaim_cmds) >
368		     sizeof(trans->conf.no_reclaim_cmds));
369	memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds,
370	       sizeof(no_reclaim_cmds));
371	trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
372
373	trans->conf.rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
374	trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
375	trans->conf.wide_cmd_header = true;
376
377	iwl_trans_op_mode_enter(trans, op_mode);
378}
379
380/*
381 *****************************************************
382 * op mode ops functions
383 *****************************************************
384 */
385
386#define NUM_FW_LOAD_RETRIES	3
387static struct iwl_op_mode *
388iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
389		      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
390{
391	struct ieee80211_hw *hw;
392	struct iwl_op_mode *op_mode;
393	struct iwl_mld *mld;
394	int ret;
395
396	/* Allocate and initialize a new hardware device */
397	hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) +
398				sizeof(struct iwl_mld),
399				&iwl_mld_hw_ops);
400	if (!hw)
401		return ERR_PTR(-ENOMEM);
402
403	op_mode = hw->priv;
404
405	op_mode->ops = &iwl_mld_ops;
406
407	mld = IWL_OP_MODE_GET_MLD(op_mode);
408
409	iwl_construct_mld(mld, trans, cfg, fw, hw, dbgfs_dir);
410
411	/* we'll verify later it matches between commands */
412	mld->fw_rates_ver_3 = iwl_fw_lookup_cmd_ver(mld->fw, TX_CMD, 0) >= 11;
413
414	iwl_mld_construct_fw_runtime(mld, trans, fw, dbgfs_dir);
415
416	iwl_mld_get_bios_tables(mld);
417	iwl_uefi_get_sgom_table(trans, &mld->fwrt);
418	mld->bios_enable_puncturing = iwl_uefi_get_puncturing(&mld->fwrt);
419
420	iwl_mld_hw_set_regulatory(mld);
421
422	/* Configure transport layer with the opmode specific params */
423	iwl_mld_configure_trans(op_mode);
424
425	/* needed for regulatory init */
426	rtnl_lock();
427	/* Needed for sending commands */
428	wiphy_lock(mld->wiphy);
429
430	for (int i = 0; i < NUM_FW_LOAD_RETRIES; i++) {
431		ret = iwl_mld_load_fw(mld);
432		if (!ret)
433			break;
434	}
435
436	if (!ret) {
437		mld->nvm_data = iwl_get_nvm(mld->trans, mld->fw, 0, 0);
438		if (IS_ERR(mld->nvm_data)) {
439			IWL_ERR(mld, "Failed to read NVM: %d\n", ret);
440			ret = PTR_ERR(mld->nvm_data);
441		}
442	}
443
444	if (ret) {
445		wiphy_unlock(mld->wiphy);
446		rtnl_unlock();
447		goto err;
448	}
449
450	/* We are about to stop the FW. Notifications may require an
451	 * operational FW, so handle them all here before we stop.
452	 */
453	wiphy_work_flush(mld->wiphy, &mld->async_handlers_wk);
454
455	iwl_mld_stop_fw(mld);
456
457	wiphy_unlock(mld->wiphy);
458	rtnl_unlock();
459
460	ret = iwl_mld_leds_init(mld);
461	if (ret)
462		goto free_nvm;
463
464	ret = iwl_mld_alloc_scan_cmd(mld);
465	if (ret)
466		goto leds_exit;
467
468	ret = iwl_mld_low_latency_init(mld);
469	if (ret)
470		goto free_scan_cmd;
471
472	ret = iwl_mld_register_hw(mld);
473	if (ret)
474		goto low_latency_free;
475
476	iwl_mld_toggle_tx_ant(mld, &mld->mgmt_tx_ant);
477
478	iwl_mld_add_debugfs_files(mld, dbgfs_dir);
479	iwl_mld_thermal_initialize(mld);
480
481	iwl_mld_ptp_init(mld);
482
483	return op_mode;
484
485low_latency_free:
486	iwl_mld_low_latency_free(mld);
487free_scan_cmd:
488	kfree(mld->scan.cmd);
489leds_exit:
490	iwl_mld_leds_exit(mld);
491free_nvm:
492	kfree(mld->nvm_data);
493err:
494	iwl_trans_op_mode_leave(mld->trans);
495	ieee80211_free_hw(mld->hw);
496	return ERR_PTR(ret);
497}
498
499static void
500iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode)
501{
502	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
503
504	iwl_mld_ptp_remove(mld);
505	iwl_mld_leds_exit(mld);
506
507	iwl_mld_thermal_exit(mld);
508
509	wiphy_lock(mld->wiphy);
510	iwl_mld_low_latency_stop(mld);
511	iwl_mld_deinit_time_sync(mld);
512	wiphy_unlock(mld->wiphy);
513
514	ieee80211_unregister_hw(mld->hw);
515
516	iwl_fw_runtime_free(&mld->fwrt);
517	iwl_mld_low_latency_free(mld);
518
519	iwl_trans_op_mode_leave(mld->trans);
520
521	kfree(mld->nvm_data);
522	kfree(mld->scan.cmd);
523	kfree(mld->channel_survey);
524	kfree(mld->error_recovery_buf);
525	kfree(mld->mcast_filter_cmd);
526
527	ieee80211_free_hw(mld->hw);
528}
529
530static void iwl_mld_queue_state_change(struct iwl_op_mode *op_mode,
531				       int hw_queue, bool queue_full)
532{
533	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
534	struct ieee80211_txq *txq;
535	struct iwl_mld_sta *mld_sta;
536	struct iwl_mld_txq *mld_txq;
537
538	rcu_read_lock();
539
540	txq = rcu_dereference(mld->fw_id_to_txq[hw_queue]);
541	if (!txq) {
542		rcu_read_unlock();
543
544		if (queue_full) {
545			/* An internal queue is not expected to become full */
546			IWL_WARN(mld,
547				 "Internal hw_queue %d is full! stopping all queues\n",
548				 hw_queue);
549			/* Stop all queues, as an internal queue is not
550			 * mapped to a mac80211 one
551			 */
552			ieee80211_stop_queues(mld->hw);
553		} else {
554			ieee80211_wake_queues(mld->hw);
555		}
556
557		return;
558	}
559
560	mld_txq = iwl_mld_txq_from_mac80211(txq);
561	mld_sta = txq->sta ? iwl_mld_sta_from_mac80211(txq->sta) : NULL;
562
563	mld_txq->status.stop_full = queue_full;
564
565	if (!queue_full && mld_sta &&
566	    mld_sta->sta_state != IEEE80211_STA_NOTEXIST) {
567		local_bh_disable();
568		iwl_mld_tx_from_txq(mld, txq);
569		local_bh_enable();
570	}
571
572	rcu_read_unlock();
573}
574
575static void
576iwl_mld_queue_full(struct iwl_op_mode *op_mode, int hw_queue)
577{
578	iwl_mld_queue_state_change(op_mode, hw_queue, true);
579}
580
581static void
582iwl_mld_queue_not_full(struct iwl_op_mode *op_mode, int hw_queue)
583{
584	iwl_mld_queue_state_change(op_mode, hw_queue, false);
585}
586
587static bool
588iwl_mld_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
589{
590	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
591
592	iwl_mld_set_hwkill(mld, state);
593
594	return false;
595}
596
597static void
598iwl_mld_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
599{
600	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
601	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
602
603	iwl_trans_free_tx_cmd(mld->trans, info->driver_data[1]);
604	ieee80211_free_txskb(mld->hw, skb);
605}
606
607static void iwl_mld_read_error_recovery_buffer(struct iwl_mld *mld)
608{
609	u32 src_size = mld->fw->ucode_capa.error_log_size;
610	u32 src_addr = mld->fw->ucode_capa.error_log_addr;
611	u8 *recovery_buf;
612	int ret;
613
614	/* no recovery buffer size defined in a TLV */
615	if (!src_size)
616		return;
617
618	recovery_buf = kzalloc(src_size, GFP_ATOMIC);
619	if (!recovery_buf)
620		return;
621
622	ret = iwl_trans_read_mem_bytes(mld->trans, src_addr,
623				       recovery_buf, src_size);
624	if (ret) {
625		IWL_ERR(mld, "Failed to read error recovery buffer (%d)\n",
626			ret);
627		kfree(recovery_buf);
628		return;
629	}
630
631	mld->error_recovery_buf = recovery_buf;
632}
633
634static void iwl_mld_restart_nic(struct iwl_mld *mld)
635{
636	iwl_mld_read_error_recovery_buffer(mld);
637
638	mld->fwrt.trans->dbg.restart_required = false;
639
640	ieee80211_restart_hw(mld->hw);
641}
642
643static void
644iwl_mld_nic_error(struct iwl_op_mode *op_mode,
645		  enum iwl_fw_error_type type)
646{
647	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
648	bool trans_dead = iwl_trans_is_dead(mld->trans);
649
650	if (type == IWL_ERR_TYPE_CMD_QUEUE_FULL)
651		IWL_ERR(mld, "Command queue full!\n");
652	else if (!trans_dead && !mld->fw_status.do_not_dump_once)
653		iwl_fwrt_dump_error_logs(&mld->fwrt);
654
655	mld->fw_status.do_not_dump_once = false;
656
657	/* It is necessary to abort any os scan here because mac80211 requires
658	 * having the scan cleared before restarting.
659	 * We'll reset the scan_status to NONE in restart cleanup in
660	 * the next drv_start() call from mac80211. If ieee80211_hw_restart
661	 * isn't called scan status will stay busy.
662	 */
663	iwl_mld_report_scan_aborted(mld);
664
665	/*
666	 * This should be first thing before trying to collect any
667	 * data to avoid endless loops if any HW error happens while
668	 * collecting debug data.
669	 * It might not actually be true that we'll restart, but the
670	 * setting doesn't matter if we're going to be unbound either.
671	 */
672	if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT &&
673	    mld->fw_status.running)
674		mld->fw_status.in_hw_restart = true;
675}
676
677static void iwl_mld_dump_error(struct iwl_op_mode *op_mode,
678			       struct iwl_fw_error_dump_mode *mode)
679{
680	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
681
682	/* if we come in from opmode we have the mutex held */
683	if (mode->context == IWL_ERR_CONTEXT_FROM_OPMODE) {
684		lockdep_assert_wiphy(mld->wiphy);
685		iwl_fw_error_collect(&mld->fwrt);
686	} else {
687		wiphy_lock(mld->wiphy);
688		if (mode->context != IWL_ERR_CONTEXT_ABORT)
689			iwl_fw_error_collect(&mld->fwrt);
690		wiphy_unlock(mld->wiphy);
691	}
692}
693
694static bool iwl_mld_sw_reset(struct iwl_op_mode *op_mode,
695			     enum iwl_fw_error_type type)
696{
697	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
698
699	/* SW reset can happen for TOP error w/o NIC error, so
700	 * also abort scan here and set in_hw_restart, when we
701	 * had a NIC error both were already done.
702	 */
703	iwl_mld_report_scan_aborted(mld);
704	mld->fw_status.in_hw_restart = true;
705
706	/* Do restart only in the following conditions are met:
707	 * - we consider the FW as running
708	 * - The trigger that brought us here is defined as one that requires
709	 *   a restart (in the debug TLVs)
710	 */
711	if (!mld->fw_status.running || !mld->fwrt.trans->dbg.restart_required)
712		return false;
713
714	iwl_mld_restart_nic(mld);
715	return true;
716}
717
718static void
719iwl_mld_time_point(struct iwl_op_mode *op_mode,
720		   enum iwl_fw_ini_time_point tp_id,
721		   union iwl_dbg_tlv_tp_data *tp_data)
722{
723	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
724
725	iwl_dbg_tlv_time_point(&mld->fwrt, tp_id, tp_data);
726}
727
728#ifdef CONFIG_PM_SLEEP
729static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode)
730{
731	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
732
733	wiphy_lock(mld->wiphy);
734	iwl_mld_stop_fw(mld);
735	mld->fw_status.in_d3 = false;
736	wiphy_unlock(mld->wiphy);
737}
738#else
739static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode)
740{}
741#endif
742
743static void iwl_mld_dump(struct iwl_op_mode *op_mode)
744{
745	struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
746	struct iwl_fw_runtime *fwrt = &mld->fwrt;
747
748	if (!iwl_trans_fw_running(fwrt->trans))
749		return;
750
751	iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL);
752}
753
754static const struct iwl_op_mode_ops iwl_mld_ops = {
755	.start = iwl_op_mode_mld_start,
756	.stop = iwl_op_mode_mld_stop,
757	.rx = iwl_mld_rx,
758	.rx_rss = iwl_mld_rx_rss,
759	.queue_full = iwl_mld_queue_full,
760	.queue_not_full = iwl_mld_queue_not_full,
761	.hw_rf_kill = iwl_mld_set_hw_rfkill_state,
762	.free_skb = iwl_mld_free_skb,
763	.nic_error = iwl_mld_nic_error,
764	.dump_error = iwl_mld_dump_error,
765	.sw_reset = iwl_mld_sw_reset,
766	.time_point = iwl_mld_time_point,
767	.device_powered_off = pm_sleep_ptr(iwl_mld_device_powered_off),
768	.dump = iwl_mld_dump,
769};
770
771struct iwl_mld_mod_params iwlmld_mod_params = {
772	.power_scheme = IWL_POWER_SCHEME_BPS,
773};
774
775module_param_named(power_scheme, iwlmld_mod_params.power_scheme, int, 0444);
776MODULE_PARM_DESC(power_scheme,
777		 "power management scheme: 1-active, 2-balanced, default: 2");
~/ Read-only file preview.