xref: /linux/drivers/net/wireless/nxp/nxpwifi/11h.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen  * nxpwifi: 802.11h helpers
4*73b01e57SJeff Chen  *
5*73b01e57SJeff Chen  * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen  */
7*73b01e57SJeff Chen 
8*73b01e57SJeff Chen #include "main.h"
9*73b01e57SJeff Chen #include "cmdevt.h"
10*73b01e57SJeff Chen #include "fw.h"
11*73b01e57SJeff Chen #include "cfg80211.h"
12*73b01e57SJeff Chen 
nxpwifi_init_11h_params(struct nxpwifi_private * priv)13*73b01e57SJeff Chen void nxpwifi_init_11h_params(struct nxpwifi_private *priv)
14*73b01e57SJeff Chen {
15*73b01e57SJeff Chen 	priv->state_11h.is_11h_enabled = true;
16*73b01e57SJeff Chen 	priv->state_11h.is_11h_active = false;
17*73b01e57SJeff Chen }
18*73b01e57SJeff Chen 
nxpwifi_is_11h_active(struct nxpwifi_private * priv)19*73b01e57SJeff Chen int nxpwifi_is_11h_active(struct nxpwifi_private *priv)
20*73b01e57SJeff Chen {
21*73b01e57SJeff Chen 	return priv->state_11h.is_11h_active;
22*73b01e57SJeff Chen }
23*73b01e57SJeff Chen 
24*73b01e57SJeff Chen /* appends 11h info to a buffer while joining an infrastructure BSS */
25*73b01e57SJeff Chen static void
nxpwifi_11h_process_infra_join(struct nxpwifi_private * priv,u8 ** buffer,struct nxpwifi_bssdescriptor * bss_desc)26*73b01e57SJeff Chen nxpwifi_11h_process_infra_join(struct nxpwifi_private *priv, u8 **buffer,
27*73b01e57SJeff Chen 			       struct nxpwifi_bssdescriptor *bss_desc)
28*73b01e57SJeff Chen {
29*73b01e57SJeff Chen 	struct nxpwifi_ie_types_header *ie_header;
30*73b01e57SJeff Chen 	struct nxpwifi_ie_types_pwr_capability *cap;
31*73b01e57SJeff Chen 	struct nxpwifi_ie_types_local_pwr_constraint *constraint;
32*73b01e57SJeff Chen 	struct ieee80211_supported_band *sband;
33*73b01e57SJeff Chen 	u8 radio_type;
34*73b01e57SJeff Chen 	int i;
35*73b01e57SJeff Chen 
36*73b01e57SJeff Chen 	if (!buffer || !(*buffer))
37*73b01e57SJeff Chen 		return;
38*73b01e57SJeff Chen 
39*73b01e57SJeff Chen 	radio_type = nxpwifi_band_to_radio_type((u8)bss_desc->bss_band);
40*73b01e57SJeff Chen 	sband = priv->wdev.wiphy->bands[radio_type];
41*73b01e57SJeff Chen 
42*73b01e57SJeff Chen 	cap = (struct nxpwifi_ie_types_pwr_capability *)*buffer;
43*73b01e57SJeff Chen 	cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
44*73b01e57SJeff Chen 	cap->header.len = cpu_to_le16(2);
45*73b01e57SJeff Chen 	cap->min_pwr = 0;
46*73b01e57SJeff Chen 	cap->max_pwr = 0;
47*73b01e57SJeff Chen 	*buffer += sizeof(*cap);
48*73b01e57SJeff Chen 
49*73b01e57SJeff Chen 	constraint = (struct nxpwifi_ie_types_local_pwr_constraint *)*buffer;
50*73b01e57SJeff Chen 	constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT);
51*73b01e57SJeff Chen 	constraint->header.len = cpu_to_le16(2);
52*73b01e57SJeff Chen 	constraint->chan = bss_desc->channel;
53*73b01e57SJeff Chen 	constraint->constraint = bss_desc->local_constraint;
54*73b01e57SJeff Chen 	*buffer += sizeof(*constraint);
55*73b01e57SJeff Chen 
56*73b01e57SJeff Chen 	ie_header = (struct nxpwifi_ie_types_header *)*buffer;
57*73b01e57SJeff Chen 	ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
58*73b01e57SJeff Chen 	ie_header->len  = cpu_to_le16(2 * sband->n_channels + 2);
59*73b01e57SJeff Chen 	*buffer += sizeof(*ie_header);
60*73b01e57SJeff Chen 	*(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS;
61*73b01e57SJeff Chen 	*(*buffer)++ = 2 * sband->n_channels;
62*73b01e57SJeff Chen 	for (i = 0; i < sband->n_channels; i++) {
63*73b01e57SJeff Chen 		u32 center_freq;
64*73b01e57SJeff Chen 
65*73b01e57SJeff Chen 		center_freq = sband->channels[i].center_freq;
66*73b01e57SJeff Chen 		*(*buffer)++ = ieee80211_frequency_to_channel(center_freq);
67*73b01e57SJeff Chen 		*(*buffer)++ = 1; /* one channel in the subband */
68*73b01e57SJeff Chen 	}
69*73b01e57SJeff Chen }
70*73b01e57SJeff Chen 
71*73b01e57SJeff Chen /* Enable or disable the 11h extensions in the firmware */
nxpwifi_11h_activate(struct nxpwifi_private * priv,bool flag)72*73b01e57SJeff Chen int nxpwifi_11h_activate(struct nxpwifi_private *priv, bool flag)
73*73b01e57SJeff Chen {
74*73b01e57SJeff Chen 	u32 enable = flag;
75*73b01e57SJeff Chen 
76*73b01e57SJeff Chen 	/* enable master mode radar detection on AP interface */
77*73b01e57SJeff Chen 	if ((GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) && enable)
78*73b01e57SJeff Chen 		enable |= NXPWIFI_MASTER_RADAR_DET_MASK;
79*73b01e57SJeff Chen 
80*73b01e57SJeff Chen 	return nxpwifi_send_cmd(priv, HOST_CMD_802_11_SNMP_MIB,
81*73b01e57SJeff Chen 				HOST_ACT_GEN_SET, DOT11H_I, &enable, true);
82*73b01e57SJeff Chen }
83*73b01e57SJeff Chen 
84*73b01e57SJeff Chen /*
85*73b01e57SJeff Chen  * Process TLV buffer for a pending BSS join. Enable 11h in firmware when the
86*73b01e57SJeff Chen  * network advertises spectrum management, and add required TLVs based on the
87*73b01e57SJeff Chen  * BSS's 11h capability.
88*73b01e57SJeff Chen  */
nxpwifi_11h_process_join(struct nxpwifi_private * priv,u8 ** buffer,struct nxpwifi_bssdescriptor * bss_desc)89*73b01e57SJeff Chen void nxpwifi_11h_process_join(struct nxpwifi_private *priv, u8 **buffer,
90*73b01e57SJeff Chen 			      struct nxpwifi_bssdescriptor *bss_desc)
91*73b01e57SJeff Chen {
92*73b01e57SJeff Chen 	if (bss_desc->sensed_11h) {
93*73b01e57SJeff Chen 		/* Activate 11h functions in firmware, turns on capability bit */
94*73b01e57SJeff Chen 		nxpwifi_11h_activate(priv, true);
95*73b01e57SJeff Chen 		priv->state_11h.is_11h_active = true;
96*73b01e57SJeff Chen 		bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
97*73b01e57SJeff Chen 		nxpwifi_11h_process_infra_join(priv, buffer, bss_desc);
98*73b01e57SJeff Chen 	} else {
99*73b01e57SJeff Chen 		/* Deactivate 11h functions in the firmware */
100*73b01e57SJeff Chen 		nxpwifi_11h_activate(priv, false);
101*73b01e57SJeff Chen 		priv->state_11h.is_11h_active = false;
102*73b01e57SJeff Chen 		bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
103*73b01e57SJeff Chen 	}
104*73b01e57SJeff Chen }
105*73b01e57SJeff Chen 
106*73b01e57SJeff Chen /*
107*73b01e57SJeff Chen  * DFS CAC work function. This delayed work emits CAC finished event for cfg80211
108*73b01e57SJeff Chen  * if CAC was started earlier
109*73b01e57SJeff Chen  */
nxpwifi_dfs_cac_work(struct wiphy * wiphy,struct wiphy_work * work)110*73b01e57SJeff Chen void nxpwifi_dfs_cac_work(struct wiphy *wiphy, struct wiphy_work *work)
111*73b01e57SJeff Chen {
112*73b01e57SJeff Chen 	struct cfg80211_chan_def chandef;
113*73b01e57SJeff Chen 	struct wiphy_delayed_work *delayed_work =
114*73b01e57SJeff Chen 		container_of(work, struct wiphy_delayed_work, work);
115*73b01e57SJeff Chen 	struct nxpwifi_private *priv = container_of(delayed_work,
116*73b01e57SJeff Chen 						    struct nxpwifi_private,
117*73b01e57SJeff Chen 						    dfs_cac_work);
118*73b01e57SJeff Chen 
119*73b01e57SJeff Chen 	chandef = priv->dfs_chandef;
120*73b01e57SJeff Chen 	if (priv->wdev.links[0].cac_started) {
121*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, MSG,
122*73b01e57SJeff Chen 			    "CAC timer finished; No radar detected\n");
123*73b01e57SJeff Chen 		cfg80211_cac_event(priv->netdev, &chandef,
124*73b01e57SJeff Chen 				   NL80211_RADAR_CAC_FINISHED,
125*73b01e57SJeff Chen 				   GFP_KERNEL, 0);
126*73b01e57SJeff Chen 	}
127*73b01e57SJeff Chen }
128*73b01e57SJeff Chen 
129*73b01e57SJeff Chen /* prepares channel report request command to FW for starting radar detection */
nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private * priv,struct host_cmd_ds_command * cmd,void * data_buf)130*73b01e57SJeff Chen int nxpwifi_cmd_issue_chan_report_request(struct nxpwifi_private *priv,
131*73b01e57SJeff Chen 					  struct host_cmd_ds_command *cmd,
132*73b01e57SJeff Chen 					  void *data_buf)
133*73b01e57SJeff Chen {
134*73b01e57SJeff Chen 	struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
135*73b01e57SJeff Chen 	struct nxpwifi_radar_params *radar_params = (void *)data_buf;
136*73b01e57SJeff Chen 	u16 size;
137*73b01e57SJeff Chen 
138*73b01e57SJeff Chen 	cmd->command = cpu_to_le16(HOST_CMD_CHAN_REPORT_REQUEST);
139*73b01e57SJeff Chen 	size = S_DS_GEN;
140*73b01e57SJeff Chen 
141*73b01e57SJeff Chen 	cr_req->chan_desc.start_freq = cpu_to_le16(NXPWIFI_A_BAND_START_FREQ);
142*73b01e57SJeff Chen 	nxpwifi_convert_chan_to_band_cfg(priv,
143*73b01e57SJeff Chen 					 &cr_req->chan_desc.band_cfg,
144*73b01e57SJeff Chen 					 radar_params->chandef);
145*73b01e57SJeff Chen 	cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
146*73b01e57SJeff Chen 	cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
147*73b01e57SJeff Chen 	size += sizeof(*cr_req);
148*73b01e57SJeff Chen 
149*73b01e57SJeff Chen 	if (radar_params->cac_time_ms) {
150*73b01e57SJeff Chen 		struct nxpwifi_ie_types_chan_rpt_data *rpt;
151*73b01e57SJeff Chen 
152*73b01e57SJeff Chen 		rpt = (struct nxpwifi_ie_types_chan_rpt_data *)((u8 *)cmd + size);
153*73b01e57SJeff Chen 		rpt->header.type = cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
154*73b01e57SJeff Chen 		rpt->header.len = cpu_to_le16(sizeof(u8));
155*73b01e57SJeff Chen 		rpt->meas_rpt_map = 1 << MEAS_RPT_MAP_RADAR_SHIFT_BIT;
156*73b01e57SJeff Chen 		size += sizeof(*rpt);
157*73b01e57SJeff Chen 
158*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, MSG,
159*73b01e57SJeff Chen 			    "11h: issuing DFS Radar check for channel=%d\n",
160*73b01e57SJeff Chen 			    radar_params->chandef->chan->hw_value);
161*73b01e57SJeff Chen 	} else {
162*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, MSG, "cancelling CAC\n");
163*73b01e57SJeff Chen 	}
164*73b01e57SJeff Chen 
165*73b01e57SJeff Chen 	cmd->size = cpu_to_le16(size);
166*73b01e57SJeff Chen 
167*73b01e57SJeff Chen 	return 0;
168*73b01e57SJeff Chen }
169*73b01e57SJeff Chen 
nxpwifi_stop_radar_detection(struct nxpwifi_private * priv,struct cfg80211_chan_def * chandef)170*73b01e57SJeff Chen int nxpwifi_stop_radar_detection(struct nxpwifi_private *priv,
171*73b01e57SJeff Chen 				 struct cfg80211_chan_def *chandef)
172*73b01e57SJeff Chen {
173*73b01e57SJeff Chen 	struct nxpwifi_radar_params radar_params;
174*73b01e57SJeff Chen 
175*73b01e57SJeff Chen 	memset(&radar_params, 0, sizeof(struct nxpwifi_radar_params));
176*73b01e57SJeff Chen 	radar_params.chandef = chandef;
177*73b01e57SJeff Chen 	radar_params.cac_time_ms = 0;
178*73b01e57SJeff Chen 
179*73b01e57SJeff Chen 	return nxpwifi_send_cmd(priv, HOST_CMD_CHAN_REPORT_REQUEST,
180*73b01e57SJeff Chen 				HOST_ACT_GEN_SET, 0, &radar_params, true);
181*73b01e57SJeff Chen }
182*73b01e57SJeff Chen 
183*73b01e57SJeff Chen /* Abort ongoing CAC when stopping AP operations or during unload */
nxpwifi_abort_cac(struct nxpwifi_private * priv)184*73b01e57SJeff Chen void nxpwifi_abort_cac(struct nxpwifi_private *priv)
185*73b01e57SJeff Chen {
186*73b01e57SJeff Chen 	if (priv->wdev.links[0].cac_started) {
187*73b01e57SJeff Chen 		if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef))
188*73b01e57SJeff Chen 			nxpwifi_dbg(priv->adapter, ERROR,
189*73b01e57SJeff Chen 				    "failed to stop CAC in FW\n");
190*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, MSG,
191*73b01e57SJeff Chen 			    "Aborting delayed work for CAC.\n");
192*73b01e57SJeff Chen 		wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work);
193*73b01e57SJeff Chen 		cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
194*73b01e57SJeff Chen 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
195*73b01e57SJeff Chen 	}
196*73b01e57SJeff Chen }
197*73b01e57SJeff Chen 
198*73b01e57SJeff Chen /*
199*73b01e57SJeff Chen  * handles channel report event from FW during CAC period. If radar is detected
200*73b01e57SJeff Chen  * during CAC, driver indicates the same to cfg80211 and also cancels ongoing
201*73b01e57SJeff Chen  * delayed work
202*73b01e57SJeff Chen  */
nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private * priv,struct sk_buff * skb)203*73b01e57SJeff Chen int nxpwifi_11h_handle_chanrpt_ready(struct nxpwifi_private *priv,
204*73b01e57SJeff Chen 				     struct sk_buff *skb)
205*73b01e57SJeff Chen {
206*73b01e57SJeff Chen 	struct host_cmd_ds_chan_rpt_event *rpt_event;
207*73b01e57SJeff Chen 	struct nxpwifi_ie_types_chan_rpt_data *rpt;
208*73b01e57SJeff Chen 	u16 event_len, tlv_len;
209*73b01e57SJeff Chen 
210*73b01e57SJeff Chen 	rpt_event = (void *)(skb->data + sizeof(u32));
211*73b01e57SJeff Chen 	event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event) +
212*73b01e57SJeff Chen 				sizeof(u32));
213*73b01e57SJeff Chen 
214*73b01e57SJeff Chen 	if (le32_to_cpu(rpt_event->result) != HOST_RESULT_OK) {
215*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, ERROR,
216*73b01e57SJeff Chen 			    "Error in channel report event\n");
217*73b01e57SJeff Chen 		return -EINVAL;
218*73b01e57SJeff Chen 	}
219*73b01e57SJeff Chen 
220*73b01e57SJeff Chen 	while (event_len >= sizeof(struct nxpwifi_ie_types_header)) {
221*73b01e57SJeff Chen 		rpt = (void *)&rpt_event->tlvbuf;
222*73b01e57SJeff Chen 		tlv_len = le16_to_cpu(rpt->header.len);
223*73b01e57SJeff Chen 
224*73b01e57SJeff Chen 		switch (le16_to_cpu(rpt->header.type)) {
225*73b01e57SJeff Chen 		case TLV_TYPE_CHANRPT_11H_BASIC:
226*73b01e57SJeff Chen 			if (rpt->meas_rpt_map & MEAS_RPT_MAP_RADAR_MASK) {
227*73b01e57SJeff Chen 				nxpwifi_dbg(priv->adapter, MSG,
228*73b01e57SJeff Chen 					    "RADAR Detected on channel %d!\n",
229*73b01e57SJeff Chen 					    priv->dfs_chandef.chan->hw_value);
230*73b01e57SJeff Chen 
231*73b01e57SJeff Chen 				wiphy_delayed_work_cancel(priv->adapter->wiphy,
232*73b01e57SJeff Chen 							  &priv->dfs_cac_work);
233*73b01e57SJeff Chen 				cfg80211_cac_event(priv->netdev,
234*73b01e57SJeff Chen 						   &priv->dfs_chandef,
235*73b01e57SJeff Chen 						   NL80211_RADAR_CAC_ABORTED,
236*73b01e57SJeff Chen 						   GFP_KERNEL, 0);
237*73b01e57SJeff Chen 				cfg80211_radar_event(priv->adapter->wiphy,
238*73b01e57SJeff Chen 						     &priv->dfs_chandef,
239*73b01e57SJeff Chen 						     GFP_KERNEL);
240*73b01e57SJeff Chen 			}
241*73b01e57SJeff Chen 			break;
242*73b01e57SJeff Chen 		default:
243*73b01e57SJeff Chen 			break;
244*73b01e57SJeff Chen 		}
245*73b01e57SJeff Chen 
246*73b01e57SJeff Chen 		event_len -= (tlv_len + sizeof(rpt->header));
247*73b01e57SJeff Chen 	}
248*73b01e57SJeff Chen 
249*73b01e57SJeff Chen 	return 0;
250*73b01e57SJeff Chen }
251*73b01e57SJeff Chen 
252*73b01e57SJeff Chen /* Handler for radar detected event from FW */
nxpwifi_11h_handle_radar_detected(struct nxpwifi_private * priv,struct sk_buff * skb)253*73b01e57SJeff Chen int nxpwifi_11h_handle_radar_detected(struct nxpwifi_private *priv,
254*73b01e57SJeff Chen 				      struct sk_buff *skb)
255*73b01e57SJeff Chen {
256*73b01e57SJeff Chen 	struct nxpwifi_radar_det_event *rdr_event;
257*73b01e57SJeff Chen 
258*73b01e57SJeff Chen 	rdr_event = (void *)(skb->data + sizeof(u32));
259*73b01e57SJeff Chen 
260*73b01e57SJeff Chen 	nxpwifi_dbg(priv->adapter, MSG,
261*73b01e57SJeff Chen 		    "radar detected; indicating kernel\n");
262*73b01e57SJeff Chen 
263*73b01e57SJeff Chen 	if (priv->wdev.links[0].cac_started) {
264*73b01e57SJeff Chen 		if (nxpwifi_stop_radar_detection(priv, &priv->dfs_chandef))
265*73b01e57SJeff Chen 			nxpwifi_dbg(priv->adapter, ERROR,
266*73b01e57SJeff Chen 				    "Failed to stop CAC in FW\n");
267*73b01e57SJeff Chen 		wiphy_delayed_work_cancel(priv->adapter->wiphy, &priv->dfs_cac_work);
268*73b01e57SJeff Chen 		cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
269*73b01e57SJeff Chen 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, 0);
270*73b01e57SJeff Chen 	}
271*73b01e57SJeff Chen 	cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
272*73b01e57SJeff Chen 			     GFP_KERNEL);
273*73b01e57SJeff Chen 	nxpwifi_dbg(priv->adapter, MSG, "regdomain: %d\n",
274*73b01e57SJeff Chen 		    rdr_event->reg_domain);
275*73b01e57SJeff Chen 	nxpwifi_dbg(priv->adapter, MSG, "radar detection type: %d\n",
276*73b01e57SJeff Chen 		    rdr_event->det_type);
277*73b01e57SJeff Chen 
278*73b01e57SJeff Chen 	return 0;
279*73b01e57SJeff Chen }
280*73b01e57SJeff Chen 
281*73b01e57SJeff Chen /*
282*73b01e57SJeff Chen  * work function for channel switch handling. takes care of updating new channel
283*73b01e57SJeff Chen  * definitin to bss config structure, restart AP and indicate channel switch
284*73b01e57SJeff Chen  * success to cfg80211
285*73b01e57SJeff Chen  */
nxpwifi_dfs_chan_sw_work(struct wiphy * wiphy,struct wiphy_work * work)286*73b01e57SJeff Chen void nxpwifi_dfs_chan_sw_work(struct wiphy *wiphy, struct wiphy_work *work)
287*73b01e57SJeff Chen {
288*73b01e57SJeff Chen 	struct nxpwifi_uap_bss_param *bss_cfg;
289*73b01e57SJeff Chen 	struct wiphy_delayed_work *delayed_work =
290*73b01e57SJeff Chen 		container_of(work, struct wiphy_delayed_work, work);
291*73b01e57SJeff Chen 	struct nxpwifi_private *priv = container_of(delayed_work,
292*73b01e57SJeff Chen 						    struct nxpwifi_private,
293*73b01e57SJeff Chen 						    dfs_chan_sw_work);
294*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
295*73b01e57SJeff Chen 
296*73b01e57SJeff Chen 	if (nxpwifi_del_mgmt_ies(priv))
297*73b01e57SJeff Chen 		nxpwifi_dbg(priv->adapter, ERROR,
298*73b01e57SJeff Chen 			    "Failed to delete mgmt IEs!\n");
299*73b01e57SJeff Chen 
300*73b01e57SJeff Chen 	bss_cfg = &priv->bss_cfg;
301*73b01e57SJeff Chen 	if (!bss_cfg->beacon_period) {
302*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
303*73b01e57SJeff Chen 			    "channel switch: AP already stopped\n");
304*73b01e57SJeff Chen 		return;
305*73b01e57SJeff Chen 	}
306*73b01e57SJeff Chen 
307*73b01e57SJeff Chen 	if (nxpwifi_send_cmd(priv, HOST_CMD_UAP_BSS_STOP,
308*73b01e57SJeff Chen 			     HOST_ACT_GEN_SET, 0, NULL, true)) {
309*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
310*73b01e57SJeff Chen 			    "channel switch: Failed to stop the BSS\n");
311*73b01e57SJeff Chen 		return;
312*73b01e57SJeff Chen 	}
313*73b01e57SJeff Chen 
314*73b01e57SJeff Chen 	if (nxpwifi_cfg80211_change_beacon(adapter->wiphy, priv->netdev,
315*73b01e57SJeff Chen 					   &priv->ap_update_info)) {
316*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
317*73b01e57SJeff Chen 			    "channel switch: Failed to set beacon\n");
318*73b01e57SJeff Chen 		return;
319*73b01e57SJeff Chen 	}
320*73b01e57SJeff Chen 
321*73b01e57SJeff Chen 	nxpwifi_uap_set_channel(priv, bss_cfg, priv->dfs_chandef);
322*73b01e57SJeff Chen 
323*73b01e57SJeff Chen 	if (nxpwifi_config_start_uap(priv, bss_cfg)) {
324*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
325*73b01e57SJeff Chen 			    "Failed to start AP after channel switch\n");
326*73b01e57SJeff Chen 		return;
327*73b01e57SJeff Chen 	}
328*73b01e57SJeff Chen 
329*73b01e57SJeff Chen 	nxpwifi_dbg(adapter, MSG,
330*73b01e57SJeff Chen 		    "indicating channel switch completion to kernel\n");
331*73b01e57SJeff Chen 
332*73b01e57SJeff Chen 	cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0);
333*73b01e57SJeff Chen 
334*73b01e57SJeff Chen 	if (priv->uap_stop_tx) {
335*73b01e57SJeff Chen 		netif_carrier_on(priv->netdev);
336*73b01e57SJeff Chen 		nxpwifi_wake_up_net_dev_queue(priv->netdev, adapter);
337*73b01e57SJeff Chen 		priv->uap_stop_tx = false;
338*73b01e57SJeff Chen 	}
339*73b01e57SJeff Chen }
340