d370db104713a097daaab2bbe93b012769e35be6
[openwrt/staging/xback.git] /
1 From patchwork Thu Sep 5 02:35:08 2024
2 Content-Type: text/plain; charset="utf-8"
3 MIME-Version: 1.0
4 Content-Transfer-Encoding: 7bit
5 X-Patchwork-Submitter: Kang Yang <quic_kangyang@quicinc.com>
6 X-Patchwork-Id: 13791624
7 X-Patchwork-Delegate: kvalo@adurom.com
8 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com
9 [205.220.180.131])
10 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
11 (No client certificate requested)
12 by smtp.subspace.kernel.org (Postfix) with ESMTPS id D313D33CFC
13 for <linux-wireless@vger.kernel.org>; Thu, 5 Sep 2024 02:36:17 +0000 (UTC)
14 Authentication-Results: smtp.subspace.kernel.org;
15 arc=none smtp.client-ip=205.220.180.131
16 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
17 t=1725503779; cv=none;
18 b=blv4mH95IN2AR7Rt90gw/V7DnZRtr3upgAP50X6ew3jh0CusPG6/OTO9CSJVthJnqHU3Y3GT88jaeMzb9+f2xzqgl7+E35TmwN3uf6dFmbp7CD8LL0W6xu76ZZgFGxzRspv9YoVy/fydZY6I4JRc2faWqI540+n9bHEXdSJTZMM=
19 ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
20 s=arc-20240116; t=1725503779; c=relaxed/simple;
21 bh=vjzfDc6UXtw2Li6Q3bAgcW0K1rcTpi3dAxkQgbT5ogI=;
22 h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:
23 MIME-Version:Content-Type;
24 b=VMgF0PfIOoXmfB6EARb/O+dooXutjAm/cnemJ0RC7uc8TSIAusH1ffc6jF1XndEp+nPTWnuMQ5/d1cE/bPeIvSTxrtWaUepnKNjQDrNKm4NrqmjR446CT9t0VHG16RZ1cmCmU74qXnfgus4XfTqD093lc1N5Q/YRh/kwmcCzxhY=
25 ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
26 dmarc=pass (p=none dis=none) header.from=quicinc.com;
27 spf=pass smtp.mailfrom=quicinc.com;
28 dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com
29 header.b=E5hktrdm; arc=none smtp.client-ip=205.220.180.131
30 Authentication-Results: smtp.subspace.kernel.org;
31 dmarc=pass (p=none dis=none) header.from=quicinc.com
32 Authentication-Results: smtp.subspace.kernel.org;
33 spf=pass smtp.mailfrom=quicinc.com
34 Authentication-Results: smtp.subspace.kernel.org;
35 dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com
36 header.b="E5hktrdm"
37 Received: from pps.filterd (m0279869.ppops.net [127.0.0.1])
38 by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id
39 484MRZwS008193;
40 Thu, 5 Sep 2024 02:36:12 GMT
41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=
42 cc:content-transfer-encoding:content-type:date:from:in-reply-to
43 :message-id:mime-version:references:subject:to; s=qcppdkim1; bh=
44 No6X3gHpioHamjfMDccV8LJEZBGk/uDqbZ/fuGUTvJM=; b=E5hktrdmmOb3KcP6
45 Qi3M5Y06Yd8RxNJTps8WMEoXZ7xzROVuhmRmlG/mw21NjBMTTMgtjcaen/n8Anj3
46 Ash1VFK6s7PrLcwoUT/uui6hzleGE+X9Wh8DJXYnZKKWmeQ+8E0yEzNR0kt9FG0n
47 S+asFc8VYEJHid6QDNAfM9e4JqJgU3NGXYJBTBM2lpdbqeWU7LEYnVTGCqvOPaH2
48 K+QDwvNiNeXlqbaxnqCYimUrSDnTbSUoiVxSpTe9/muWWAB+6YuUbXRfTceqgcd1
49 xFIOE1KrtAowMOk5mO3tn6Tjl7nJzewVUm9hncBRfynP8k2jt1xosMezL42dmb56
50 a9VWLQ==
51 Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com
52 [129.46.96.20])
53 by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 41bt674mq1-1
54 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);
55 Thu, 05 Sep 2024 02:36:11 +0000 (GMT)
56 Received: from nalasex01b.na.qualcomm.com (nalasex01b.na.qualcomm.com
57 [10.47.209.197])
58 by NALASPPMTA03.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id
59 4852aAdV010181
60 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT);
61 Thu, 5 Sep 2024 02:36:10 GMT
62 Received: from kangyang.ap.qualcomm.com (10.80.80.8) by
63 nalasex01b.na.qualcomm.com (10.47.209.197) with Microsoft SMTP Server
64 (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id
65 15.2.1544.9; Wed, 4 Sep 2024 19:36:09 -0700
66 From: Kang Yang <quic_kangyang@quicinc.com>
67 To: <ath12k@lists.infradead.org>
68 CC: <linux-wireless@vger.kernel.org>, <quic_kangyang@quicinc.com>
69 Subject: [PATCH v3 1/4] wifi: ath12k: add configure country code for WCN7850
70 Date: Thu, 5 Sep 2024 10:35:08 +0800
71 Message-ID: <20240905023511.362-2-quic_kangyang@quicinc.com>
72 X-Mailer: git-send-email 2.34.1.windows.1
73 In-Reply-To: <20240905023511.362-1-quic_kangyang@quicinc.com>
74 References: <20240905023511.362-1-quic_kangyang@quicinc.com>
75 Precedence: bulk
76 X-Mailing-List: linux-wireless@vger.kernel.org
77 List-Id: <linux-wireless.vger.kernel.org>
78 List-Subscribe: <mailto:linux-wireless+subscribe@vger.kernel.org>
79 List-Unsubscribe: <mailto:linux-wireless+unsubscribe@vger.kernel.org>
80 MIME-Version: 1.0
81 X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To
82 nalasex01b.na.qualcomm.com (10.47.209.197)
83 X-QCInternal: smtphost
84 X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800
85 signatures=585085
86 X-Proofpoint-ORIG-GUID: FzfHe7cZy6IUVu8IKORVKLxkYG9f8WUl
87 X-Proofpoint-GUID: FzfHe7cZy6IUVu8IKORVKLxkYG9f8WUl
88 X-Proofpoint-Virus-Version: vendor=baseguard
89 engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29
90 definitions=2024-09-05_01,2024-09-04_01,2024-09-02_01
91 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0
92 malwarescore=0 adultscore=0
93 bulkscore=0 mlxscore=0 impostorscore=0 suspectscore=0 phishscore=0
94 mlxlogscore=999 lowpriorityscore=0 spamscore=0 clxscore=1015
95 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1
96 engine=8.19.0-2407110000 definitions=main-2409050018
97
98 From: Wen Gong <quic_wgong@quicinc.com>
99
100 Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware, which
101 is used for WCN7850 to update country code.
102
103 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
104
105 Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
106 Signed-off-by: Kang Yang <quic_kangyang@quicinc.com>
107 Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
108 ---
109 drivers/net/wireless/ath/ath12k/wmi.c | 36 +++++++++++++++++++++++++++
110 drivers/net/wireless/ath/ath12k/wmi.h | 13 ++++++++++
111 2 files changed, 49 insertions(+)
112
113 --- a/drivers/net/wireless/ath/ath12k/wmi.c
114 +++ b/drivers/net/wireless/ath/ath12k/wmi.c
115 @@ -171,6 +171,8 @@ static const struct ath12k_wmi_tlv_polic
116 .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) },
117 [WMI_TAG_P2P_NOA_EVENT] = {
118 .min_len = sizeof(struct wmi_p2p_noa_event) },
119 + [WMI_TAG_11D_NEW_COUNTRY_EVENT] = {
120 + .min_len = sizeof(struct wmi_11d_new_cc_event) },
121 };
122
123 static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
124 @@ -2363,7 +2365,10 @@ int ath12k_wmi_send_scan_start_cmd(struc
125 cmd->scan_id = cpu_to_le32(arg->scan_id);
126 cmd->scan_req_id = cpu_to_le32(arg->scan_req_id);
127 cmd->vdev_id = cpu_to_le32(arg->vdev_id);
128 - cmd->scan_priority = cpu_to_le32(arg->scan_priority);
129 + if (ar->state_11d == ATH12K_11D_PREPARING)
130 + arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM;
131 + else
132 + arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
133 cmd->notify_scan_events = cpu_to_le32(arg->notify_scan_events);
134
135 ath12k_wmi_copy_scan_event_cntrl_flags(cmd, arg);
136 @@ -3083,6 +3088,110 @@ out:
137 return ret;
138 }
139
140 +int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
141 + struct wmi_set_current_country_arg *arg)
142 +{
143 + struct ath12k_wmi_pdev *wmi = ar->wmi;
144 + struct wmi_set_current_country_cmd *cmd;
145 + struct sk_buff *skb;
146 + int ret;
147 +
148 + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
149 + if (!skb)
150 + return -ENOMEM;
151 +
152 + cmd = (struct wmi_set_current_country_cmd *)skb->data;
153 + cmd->tlv_header =
154 + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_CURRENT_COUNTRY_CMD,
155 + sizeof(*cmd));
156 +
157 + cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
158 + memcpy(&cmd->new_alpha2, &arg->alpha2, sizeof(arg->alpha2));
159 + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID);
160 +
161 + ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
162 + "set current country pdev id %d alpha2 %c%c\n",
163 + ar->pdev->pdev_id,
164 + arg->alpha2[0],
165 + arg->alpha2[1]);
166 +
167 + if (ret) {
168 + ath12k_warn(ar->ab,
169 + "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret);
170 + dev_kfree_skb(skb);
171 + }
172 +
173 + return ret;
174 +}
175 +
176 +int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
177 + struct wmi_11d_scan_start_arg *arg)
178 +{
179 + struct ath12k_wmi_pdev *wmi = ar->wmi;
180 + struct wmi_11d_scan_start_cmd *cmd;
181 + struct sk_buff *skb;
182 + int ret;
183 +
184 + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
185 + if (!skb)
186 + return -ENOMEM;
187 +
188 + cmd = (struct wmi_11d_scan_start_cmd *)skb->data;
189 + cmd->tlv_header =
190 + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_START_CMD,
191 + sizeof(*cmd));
192 +
193 + cmd->vdev_id = cpu_to_le32(arg->vdev_id);
194 + cmd->scan_period_msec = cpu_to_le32(arg->scan_period_msec);
195 + cmd->start_interval_msec = cpu_to_le32(arg->start_interval_msec);
196 + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID);
197 +
198 + ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
199 + "send 11d scan start vdev id %d period %d ms internal %d ms\n",
200 + arg->vdev_id, arg->scan_period_msec,
201 + arg->start_interval_msec);
202 +
203 + if (ret) {
204 + ath12k_warn(ar->ab,
205 + "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret);
206 + dev_kfree_skb(skb);
207 + }
208 +
209 + return ret;
210 +}
211 +
212 +int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id)
213 +{
214 + struct ath12k_wmi_pdev *wmi = ar->wmi;
215 + struct wmi_11d_scan_stop_cmd *cmd;
216 + struct sk_buff *skb;
217 + int ret;
218 +
219 + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
220 + if (!skb)
221 + return -ENOMEM;
222 +
223 + cmd = (struct wmi_11d_scan_stop_cmd *)skb->data;
224 + cmd->tlv_header =
225 + ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_STOP_CMD,
226 + sizeof(*cmd));
227 +
228 + cmd->vdev_id = cpu_to_le32(vdev_id);
229 + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID);
230 +
231 + ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
232 + "send 11d scan stop vdev id %d\n",
233 + cmd->vdev_id);
234 +
235 + if (ret) {
236 + ath12k_warn(ar->ab,
237 + "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret);
238 + dev_kfree_skb(skb);
239 + }
240 +
241 + return ret;
242 +}
243 +
244 int
245 ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
246 {
247 @@ -5668,6 +5777,50 @@ static void ath12k_wmi_op_ep_tx_credits(
248 wake_up(&ab->wmi_ab.tx_credits_wq);
249 }
250
251 +static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *skb)
252 +{
253 + const struct wmi_11d_new_cc_event *ev;
254 + struct ath12k *ar;
255 + struct ath12k_pdev *pdev;
256 + const void **tb;
257 + int ret, i;
258 +
259 + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
260 + if (IS_ERR(tb)) {
261 + ret = PTR_ERR(tb);
262 + ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
263 + return ret;
264 + }
265 +
266 + ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
267 + if (!ev) {
268 + kfree(tb);
269 + ath12k_warn(ab, "failed to fetch 11d new cc ev");
270 + return -EPROTO;
271 + }
272 +
273 + spin_lock_bh(&ab->base_lock);
274 + memcpy(&ab->new_alpha2, &ev->new_alpha2, REG_ALPHA2_LEN);
275 + spin_unlock_bh(&ab->base_lock);
276 +
277 + ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi 11d new cc %c%c\n",
278 + ab->new_alpha2[0],
279 + ab->new_alpha2[1]);
280 +
281 + kfree(tb);
282 +
283 + for (i = 0; i < ab->num_radios; i++) {
284 + pdev = &ab->pdevs[i];
285 + ar = pdev->ar;
286 + ar->state_11d = ATH12K_11D_IDLE;
287 + complete(&ar->completed_11d_scan);
288 + }
289 +
290 + queue_work(ab->workqueue, &ab->update_11d_work);
291 +
292 + return 0;
293 +}
294 +
295 static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
296 struct sk_buff *skb)
297 {
298 @@ -7269,6 +7422,9 @@ static void ath12k_wmi_op_rx(struct ath1
299 case WMI_GTK_OFFLOAD_STATUS_EVENTID:
300 ath12k_wmi_gtk_offload_status_event(ab, skb);
301 break;
302 + case WMI_11D_NEW_COUNTRY_EVENTID:
303 + ath12k_reg_11d_new_cc_event(ab, skb);
304 + break;
305 /* TODO: Add remaining events */
306 default:
307 ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
308 --- a/drivers/net/wireless/ath/ath12k/wmi.h
309 +++ b/drivers/net/wireless/ath/ath12k/wmi.h
310 @@ -3859,6 +3859,28 @@ struct wmi_init_country_cmd {
311 } cc_info;
312 } __packed;
313
314 +struct wmi_11d_scan_start_arg {
315 + u32 vdev_id;
316 + u32 scan_period_msec;
317 + u32 start_interval_msec;
318 +};
319 +
320 +struct wmi_11d_scan_start_cmd {
321 + __le32 tlv_header;
322 + __le32 vdev_id;
323 + __le32 scan_period_msec;
324 + __le32 start_interval_msec;
325 +} __packed;
326 +
327 +struct wmi_11d_scan_stop_cmd {
328 + __le32 tlv_header;
329 + __le32 vdev_id;
330 +} __packed;
331 +
332 +struct wmi_11d_new_cc_event {
333 + __le32 new_alpha2;
334 +} __packed;
335 +
336 struct wmi_delba_send_cmd {
337 __le32 tlv_header;
338 __le32 vdev_id;
339 @@ -3944,6 +3966,16 @@ struct ath12k_wmi_eht_rate_set_params {
340 #define MAX_6G_REG_RULES 5
341 #define REG_US_5G_NUM_REG_RULES 4
342
343 +struct wmi_set_current_country_arg {
344 + u8 alpha2[REG_ALPHA2_LEN];
345 +};
346 +
347 +struct wmi_set_current_country_cmd {
348 + __le32 tlv_header;
349 + __le32 pdev_id;
350 + __le32 new_alpha2;
351 +} __packed;
352 +
353 enum wmi_start_event_param {
354 WMI_VDEV_START_RESP_EVENT = 0,
355 WMI_VDEV_RESTART_RESP_EVENT,
356 @@ -5546,11 +5578,17 @@ int ath12k_wmi_send_bcn_offload_control_
357 u32 vdev_id, u32 bcn_ctrl_op);
358 int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
359 struct ath12k_wmi_init_country_arg *arg);
360 +int
361 +ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
362 + struct wmi_set_current_country_arg *arg);
363 int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
364 int vdev_id, const u8 *addr,
365 dma_addr_t paddr, u8 tid,
366 u8 ba_window_size_valid,
367 u32 ba_window_size);
368 +int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
369 + struct wmi_11d_scan_start_arg *arg);
370 +int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id);
371 int
372 ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar,
373 struct ath12k_wmi_rx_reorder_queue_remove_arg *arg);
374 --- a/drivers/net/wireless/ath/ath12k/core.c
375 +++ b/drivers/net/wireless/ath/ath12k/core.c
376 @@ -1014,6 +1014,7 @@ void ath12k_core_halt(struct ath12k *ar)
377 cancel_delayed_work_sync(&ar->scan.timeout);
378 cancel_work_sync(&ar->regd_update_work);
379 cancel_work_sync(&ab->rfkill_work);
380 + cancel_work_sync(&ab->update_11d_work);
381
382 rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
383 synchronize_rcu();
384 @@ -1021,6 +1022,34 @@ void ath12k_core_halt(struct ath12k *ar)
385 idr_init(&ar->txmgmt_idr);
386 }
387
388 +static void ath12k_update_11d(struct work_struct *work)
389 +{
390 + struct ath12k_base *ab = container_of(work, struct ath12k_base, update_11d_work);
391 + struct ath12k *ar;
392 + struct ath12k_pdev *pdev;
393 + struct wmi_set_current_country_arg arg = {};
394 + int ret, i;
395 +
396 + spin_lock_bh(&ab->base_lock);
397 + memcpy(&arg.alpha2, &ab->new_alpha2, 2);
398 + spin_unlock_bh(&ab->base_lock);
399 +
400 + ath12k_dbg(ab, ATH12K_DBG_WMI, "update 11d new cc %c%c\n",
401 + arg.alpha2[0], arg.alpha2[1]);
402 +
403 + for (i = 0; i < ab->num_radios; i++) {
404 + pdev = &ab->pdevs[i];
405 + ar = pdev->ar;
406 +
407 + memcpy(&ar->alpha2, &arg.alpha2, 2);
408 + ret = ath12k_wmi_send_set_current_country_cmd(ar, &arg);
409 + if (ret)
410 + ath12k_warn(ar->ab,
411 + "pdev id %d failed set current country code: %d\n",
412 + i, ret);
413 + }
414 +}
415 +
416 static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
417 {
418 struct ath12k *ar;
419 @@ -1045,8 +1074,10 @@ static void ath12k_core_pre_reconfigure_
420 ar = &ah->radio[j];
421
422 ath12k_mac_drain_tx(ar);
423 + ar->state_11d = ATH12K_11D_IDLE;
424 + complete(&ar->completed_11d_scan);
425 complete(&ar->scan.started);
426 - complete(&ar->scan.completed);
427 + complete_all(&ar->scan.completed);
428 complete(&ar->scan.on_channel);
429 complete(&ar->peer_assoc_done);
430 complete(&ar->peer_delete_done);
431 @@ -1312,6 +1343,7 @@ struct ath12k_base *ath12k_core_alloc(st
432 INIT_WORK(&ab->restart_work, ath12k_core_restart);
433 INIT_WORK(&ab->reset_work, ath12k_core_reset);
434 INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
435 + INIT_WORK(&ab->update_11d_work, ath12k_update_11d);
436
437 timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
438 init_completion(&ab->htc_suspend);
439 --- a/drivers/net/wireless/ath/ath12k/core.h
440 +++ b/drivers/net/wireless/ath/ath12k/core.h
441 @@ -199,6 +199,12 @@ enum ath12k_scan_state {
442 ATH12K_SCAN_ABORTING,
443 };
444
445 +enum ath12k_11d_state {
446 + ATH12K_11D_IDLE,
447 + ATH12K_11D_PREPARING,
448 + ATH12K_11D_RUNNING,
449 +};
450 +
451 enum ath12k_dev_flags {
452 ATH12K_CAC_RUNNING,
453 ATH12K_FLAG_CRASH_FLUSH,
454 @@ -313,6 +319,8 @@ struct ath12k_vif_iter {
455 #define ATH12K_RX_RATE_TABLE_11AX_NUM 576
456 #define ATH12K_RX_RATE_TABLE_NUM 320
457
458 +#define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ)
459 +
460 struct ath12k_rx_peer_rate_stats {
461 u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1];
462 u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1];
463 @@ -648,6 +656,13 @@ struct ath12k {
464 u32 freq_low;
465 u32 freq_high;
466
467 + /* Protected by wiphy::mtx lock. */
468 + u32 vdev_id_11d_scan;
469 + struct completion completed_11d_scan;
470 + enum ath12k_11d_state state_11d;
471 + u8 alpha2[REG_ALPHA2_LEN];
472 + bool regdom_set_by_user;
473 +
474 bool nlo_enabled;
475 };
476
477 @@ -880,6 +895,8 @@ struct ath12k_base {
478 /* continuous recovery fail count */
479 atomic_t fail_cont_count;
480 unsigned long reset_fail_timeout;
481 + struct work_struct update_11d_work;
482 + u8 new_alpha2[2];
483 struct {
484 /* protected by data_lock */
485 u32 fw_crash_counter;
486 --- a/drivers/net/wireless/ath/ath12k/mac.c
487 +++ b/drivers/net/wireless/ath/ath12k/mac.c
488 @@ -2947,6 +2947,11 @@ static void ath12k_bss_assoc(struct ath1
489 if (ret)
490 ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
491 arvif->vdev_id, ret);
492 +
493 + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) &&
494 + arvif->vdev_type == WMI_VDEV_TYPE_STA &&
495 + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
496 + ath12k_mac_11d_scan_stop_all(ar->ab);
497 }
498
499 static void ath12k_bss_disassoc(struct ath12k *ar,
500 @@ -3522,7 +3527,7 @@ void __ath12k_mac_scan_finish(struct ath
501 ar->scan_channel = NULL;
502 ar->scan.roc_freq = 0;
503 cancel_delayed_work(&ar->scan.timeout);
504 - complete(&ar->scan.completed);
505 + complete_all(&ar->scan.completed);
506 break;
507 }
508 }
509 @@ -3783,7 +3788,12 @@ scan:
510
511 ret = ath12k_start_scan(ar, &arg);
512 if (ret) {
513 - ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
514 + if (ret == -EBUSY)
515 + ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
516 + "scan engine is busy 11d state %d\n", ar->state_11d);
517 + else
518 + ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
519 +
520 spin_lock_bh(&ar->data_lock);
521 ar->scan.state = ATH12K_SCAN_IDLE;
522 spin_unlock_bh(&ar->data_lock);
523 @@ -3802,6 +3812,11 @@ exit:
524
525 mutex_unlock(&ar->conf_mutex);
526
527 + if (ar->state_11d == ATH12K_11D_PREPARING &&
528 + arvif->vdev_type == WMI_VDEV_TYPE_STA &&
529 + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
530 + ath12k_mac_11d_scan_start(ar, arvif->vdev_id);
531 +
532 return ret;
533 }
534
535 @@ -5986,7 +6001,7 @@ static int ath12k_mac_start(struct ath12
536
537 /* TODO: Do we need to enable ANI? */
538
539 - ath12k_reg_update_chan_list(ar);
540 + ath12k_reg_update_chan_list(ar, false);
541
542 ar->num_started_vdevs = 0;
543 ar->num_created_vdevs = 0;
544 @@ -6166,6 +6181,9 @@ static void ath12k_mac_stop(struct ath12
545 cancel_delayed_work_sync(&ar->scan.timeout);
546 cancel_work_sync(&ar->regd_update_work);
547 cancel_work_sync(&ar->ab->rfkill_work);
548 + cancel_work_sync(&ar->ab->update_11d_work);
549 + ar->state_11d = ATH12K_11D_IDLE;
550 + complete(&ar->completed_11d_scan);
551
552 spin_lock_bh(&ar->data_lock);
553 list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
554 @@ -6412,6 +6430,117 @@ static void ath12k_mac_op_update_vif_off
555 ath12k_mac_update_vif_offload(arvif);
556 }
557
558 +static bool ath12k_mac_vif_ap_active_any(struct ath12k_base *ab)
559 +{
560 + struct ath12k *ar;
561 + struct ath12k_pdev *pdev;
562 + struct ath12k_vif *arvif;
563 + int i;
564 +
565 + for (i = 0; i < ab->num_radios; i++) {
566 + pdev = &ab->pdevs[i];
567 + ar = pdev->ar;
568 + list_for_each_entry(arvif, &ar->arvifs, list) {
569 + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP)
570 + return true;
571 + }
572 + }
573 + return false;
574 +}
575 +
576 +void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id)
577 +{
578 + struct wmi_11d_scan_start_arg arg;
579 + int ret;
580 +
581 + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
582 +
583 + if (ar->regdom_set_by_user)
584 + goto fin;
585 +
586 + if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID)
587 + goto fin;
588 +
589 + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
590 + goto fin;
591 +
592 + if (ath12k_mac_vif_ap_active_any(ar->ab))
593 + goto fin;
594 +
595 + arg.vdev_id = vdev_id;
596 + arg.start_interval_msec = 0;
597 + arg.scan_period_msec = ATH12K_SCAN_11D_INTERVAL;
598 +
599 + ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
600 + "mac start 11d scan for vdev %d\n", vdev_id);
601 +
602 + ret = ath12k_wmi_send_11d_scan_start_cmd(ar, &arg);
603 + if (ret) {
604 + ath12k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n",
605 + vdev_id, ret);
606 + } else {
607 + ar->vdev_id_11d_scan = vdev_id;
608 + if (ar->state_11d == ATH12K_11D_PREPARING)
609 + ar->state_11d = ATH12K_11D_RUNNING;
610 + }
611 +
612 +fin:
613 + if (ar->state_11d == ATH12K_11D_PREPARING) {
614 + ar->state_11d = ATH12K_11D_IDLE;
615 + complete(&ar->completed_11d_scan);
616 + }
617 +}
618 +
619 +void ath12k_mac_11d_scan_stop(struct ath12k *ar)
620 +{
621 + int ret;
622 + u32 vdev_id;
623 +
624 + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
625 +
626 + if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
627 + return;
628 +
629 + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d for vdev %d\n",
630 + ar->vdev_id_11d_scan);
631 +
632 + if (ar->state_11d == ATH12K_11D_PREPARING) {
633 + ar->state_11d = ATH12K_11D_IDLE;
634 + complete(&ar->completed_11d_scan);
635 + }
636 +
637 + if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID) {
638 + vdev_id = ar->vdev_id_11d_scan;
639 +
640 + ret = ath12k_wmi_send_11d_scan_stop_cmd(ar, vdev_id);
641 + if (ret) {
642 + ath12k_warn(ar->ab,
643 + "failed to stopt 11d scan vdev %d ret: %d\n",
644 + vdev_id, ret);
645 + } else {
646 + ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
647 + ar->state_11d = ATH12K_11D_IDLE;
648 + complete(&ar->completed_11d_scan);
649 + }
650 + }
651 +}
652 +
653 +void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab)
654 +{
655 + struct ath12k *ar;
656 + struct ath12k_pdev *pdev;
657 + int i;
658 +
659 + ath12k_dbg(ab, ATH12K_DBG_MAC, "mac stop soc 11d scan\n");
660 +
661 + for (i = 0; i < ab->num_radios; i++) {
662 + pdev = &ab->pdevs[i];
663 + ar = pdev->ar;
664 +
665 + ath12k_mac_11d_scan_stop(ar);
666 + }
667 +}
668 +
669 static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
670 {
671 struct ath12k_hw *ah = ar->ah;
672 @@ -6526,6 +6655,7 @@ static int ath12k_mac_vdev_create(struct
673 arvif->vdev_id, ret);
674 goto err_peer_del;
675 }
676 + ath12k_mac_11d_scan_stop_all(ar->ab);
677 break;
678 case WMI_VDEV_TYPE_STA:
679 param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
680 @@ -6564,6 +6694,13 @@ static int ath12k_mac_vdev_create(struct
681 arvif->vdev_id, ret);
682 goto err_peer_del;
683 }
684 +
685 + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
686 + arvif->vdev_type == WMI_VDEV_TYPE_STA &&
687 + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
688 + reinit_completion(&ar->completed_11d_scan);
689 + ar->state_11d = ATH12K_11D_PREPARING;
690 + }
691 break;
692 default:
693 break;
694 @@ -6904,6 +7041,11 @@ static void ath12k_mac_op_remove_interfa
695 ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
696 arvif->vdev_id);
697
698 + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
699 + arvif->vdev_type == WMI_VDEV_TYPE_STA &&
700 + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
701 + ath12k_mac_11d_scan_stop(ar);
702 +
703 if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
704 ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr);
705 if (ret)
706 @@ -7744,6 +7886,14 @@ ath12k_mac_op_unassign_vif_chanctx(struc
707 ar->num_started_vdevs == 1 && ar->monitor_vdev_created)
708 ath12k_mac_monitor_stop(ar);
709
710 + if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
711 + arvif->vdev_type == WMI_VDEV_TYPE_STA &&
712 + arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE &&
713 + ar->state_11d != ATH12K_11D_PREPARING) {
714 + reinit_completion(&ar->completed_11d_scan);
715 + ar->state_11d = ATH12K_11D_PREPARING;
716 + }
717 +
718 mutex_unlock(&ar->conf_mutex);
719 }
720
721 @@ -8282,6 +8432,14 @@ ath12k_mac_op_reconfig_complete(struct i
722 ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
723 ar->pdev->pdev_id);
724
725 + if (ar->ab->hw_params->current_cc_support &&
726 + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {
727 + struct wmi_set_current_country_arg arg = {};
728 +
729 + memcpy(&arg.alpha2, ar->alpha2, 2);
730 + ath12k_wmi_send_set_current_country_cmd(ar, &arg);
731 + }
732 +
733 if (ab->is_reset) {
734 recovery_count = atomic_inc_return(&ab->recovery_count);
735
736 @@ -9331,6 +9489,9 @@ static void ath12k_mac_setup(struct ath1
737
738 INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work);
739 skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
740 +
741 + ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
742 + init_completion(&ar->completed_11d_scan);
743 }
744
745 int ath12k_mac_register(struct ath12k_base *ab)
746 --- a/drivers/net/wireless/ath/ath12k/mac.h
747 +++ b/drivers/net/wireless/ath/ath12k/mac.h
748 @@ -51,6 +51,13 @@ enum ath12k_supported_bw {
749
750 extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
751
752 +#define ATH12K_SCAN_11D_INTERVAL 600000
753 +#define ATH12K_11D_INVALID_VDEV_ID 0xFFFF
754 +
755 +void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id);
756 +void ath12k_mac_11d_scan_stop(struct ath12k *ar);
757 +void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab);
758 +
759 void ath12k_mac_destroy(struct ath12k_base *ab);
760 void ath12k_mac_unregister(struct ath12k_base *ab);
761 int ath12k_mac_register(struct ath12k_base *ab);
762 --- a/drivers/net/wireless/ath/ath12k/reg.c
763 +++ b/drivers/net/wireless/ath/ath12k/reg.c
764 @@ -48,6 +48,7 @@ ath12k_reg_notifier(struct wiphy *wiphy,
765 {
766 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
767 struct ath12k_wmi_init_country_arg arg;
768 + struct wmi_set_current_country_arg current_arg = {};
769 struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
770 struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
771 int ret, i;
772 @@ -77,27 +78,38 @@ ath12k_reg_notifier(struct wiphy *wiphy,
773 return;
774 }
775
776 - /* Set the country code to the firmware and wait for
777 - * the WMI_REG_CHAN_LIST_CC EVENT for updating the
778 - * reg info
779 - */
780 - arg.flags = ALPHA_IS_SET;
781 - memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
782 - arg.cc_info.alpha2[2] = 0;
783 -
784 /* Allow fresh updates to wiphy regd */
785 ah->regd_updated = false;
786
787 /* Send the reg change request to all the radios */
788 for_each_ar(ah, ar, i) {
789 - ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
790 - if (ret)
791 - ath12k_warn(ar->ab,
792 - "INIT Country code set to fw failed : %d\n", ret);
793 + if (ar->ab->hw_params->current_cc_support) {
794 + memcpy(&current_arg.alpha2, request->alpha2, 2);
795 + memcpy(&ar->alpha2, &current_arg.alpha2, 2);
796 + ret = ath12k_wmi_send_set_current_country_cmd(ar, &current_arg);
797 + if (ret)
798 + ath12k_warn(ar->ab,
799 + "failed set current country code: %d\n", ret);
800 + } else {
801 + arg.flags = ALPHA_IS_SET;
802 + memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
803 + arg.cc_info.alpha2[2] = 0;
804 +
805 + ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
806 + if (ret)
807 + ath12k_warn(ar->ab,
808 + "failed set INIT Country code: %d\n", ret);
809 + }
810 +
811 + wiphy_lock(wiphy);
812 + ath12k_mac_11d_scan_stop(ar);
813 + wiphy_unlock(wiphy);
814 +
815 + ar->regdom_set_by_user = true;
816 }
817 }
818
819 -int ath12k_reg_update_chan_list(struct ath12k *ar)
820 +int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
821 {
822 struct ieee80211_supported_band **bands;
823 struct ath12k_wmi_scan_chan_list_arg *arg;
824 @@ -106,7 +118,35 @@ int ath12k_reg_update_chan_list(struct a
825 struct ath12k_wmi_channel_arg *ch;
826 enum nl80211_band band;
827 int num_channels = 0;
828 - int i, ret;
829 + int i, ret, left;
830 +
831 + if (wait && ar->state_11d != ATH12K_11D_IDLE) {
832 + left = wait_for_completion_timeout(&ar->completed_11d_scan,
833 + ATH12K_SCAN_TIMEOUT_HZ);
834 + if (!left) {
835 + ath12k_dbg(ar->ab, ATH12K_DBG_REG,
836 + "failed to receive 11d scan complete: timed out\n");
837 + ar->state_11d = ATH12K_11D_IDLE;
838 + }
839 + ath12k_dbg(ar->ab, ATH12K_DBG_REG,
840 + "reg 11d scan wait left time %d\n", left);
841 + }
842 +
843 + if (wait &&
844 + (ar->scan.state == ATH12K_SCAN_STARTING ||
845 + ar->scan.state == ATH12K_SCAN_RUNNING)) {
846 + left = wait_for_completion_timeout(&ar->scan.completed,
847 + ATH12K_SCAN_TIMEOUT_HZ);
848 + if (!left)
849 + ath12k_dbg(ar->ab, ATH12K_DBG_REG,
850 + "failed to receive hw scan complete: timed out\n");
851 +
852 + ath12k_dbg(ar->ab, ATH12K_DBG_REG,
853 + "reg hw scan wait left time %d\n", left);
854 + }
855 +
856 + if (ar->ah->state == ATH12K_HW_STATE_RESTARTING)
857 + return 0;
858
859 bands = hw->wiphy->bands;
860 for (band = 0; band < NUM_NL80211_BANDS; band++) {
861 @@ -295,7 +335,7 @@ int ath12k_regd_update(struct ath12k *ar
862 */
863 for_each_ar(ah, ar, i) {
864 ab = ar->ab;
865 - ret = ath12k_reg_update_chan_list(ar);
866 + ret = ath12k_reg_update_chan_list(ar, true);
867 if (ret)
868 goto err;
869 }
870 --- a/drivers/net/wireless/ath/ath12k/reg.h
871 +++ b/drivers/net/wireless/ath/ath12k/reg.h
872 @@ -1,7 +1,7 @@
873 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
874 /*
875 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
876 - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
877 + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
878 */
879
880 #ifndef ATH12K_REG_H
881 @@ -96,6 +96,6 @@ struct ieee80211_regdomain *ath12k_reg_b
882 struct ath12k_reg_info *reg_info,
883 bool intersect);
884 int ath12k_regd_update(struct ath12k *ar, bool init);
885 -int ath12k_reg_update_chan_list(struct ath12k *ar);
886 +int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait);
887
888 #endif
889 --- a/drivers/net/wireless/ath/ath12k/hw.c
890 +++ b/drivers/net/wireless/ath/ath12k/hw.c
891 @@ -926,6 +926,7 @@ static const struct ath12k_hw_params ath
892 .supports_dynamic_smps_6ghz = true,
893
894 .iova_mask = 0,
895 + .current_cc_support = false,
896 },
897 {
898 .name = "wcn7850 hw2.0",
899 @@ -1004,6 +1005,7 @@ static const struct ath12k_hw_params ath
900 .supports_dynamic_smps_6ghz = false,
901
902 .iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1,
903 + .current_cc_support = true,
904 },
905 {
906 .name = "qcn9274 hw2.0",
907 @@ -1078,6 +1080,7 @@ static const struct ath12k_hw_params ath
908 .supports_dynamic_smps_6ghz = true,
909
910 .iova_mask = 0,
911 + .current_cc_support = false,
912 },
913 };
914
915 --- a/drivers/net/wireless/ath/ath12k/hw.h
916 +++ b/drivers/net/wireless/ath/ath12k/hw.h
917 @@ -189,6 +189,7 @@ struct ath12k_hw_params {
918 bool tcl_ring_retry:1;
919 bool reoq_lut_support:1;
920 bool supports_shadow_regs:1;
921 + bool current_cc_support:1;
922
923 u32 num_tcl_banks;
924 u32 max_tx_ring;