xref: /linux/drivers/net/wireless/mediatek/mt76/mt7921/regd.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: BSD-3-Clause-Clear
2 /* Copyright (C) 2025 MediaTek Inc. */
3 
4 #include <linux/of.h>
5 #include "mt7921.h"
6 #include "regd.h"
7 #include "mcu.h"
8 
9 static bool mt7921_disable_clc;
10 module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
11 MODULE_PARM_DESC(disable_clc, "disable CLC support");
12 
13 static struct ieee80211_regdomain mt7921_regd_ww = {
14 	.n_reg_rules = 1,
15 	.alpha2 =  "00",
16 	.reg_rules = {
17 		/* IEEE 802.11b/g, channels 1..11 */
18 		REG_RULE(2412 - 10, 2462 + 10, 40, 6, 20, 0),
19 	}
20 };
21 
mt7921_regd_clc_supported(struct mt792x_dev * dev)22 bool mt7921_regd_clc_supported(struct mt792x_dev *dev)
23 {
24 	if (mt7921_disable_clc ||
25 	    mt76_is_usb(&dev->mt76))
26 		return false;
27 
28 	return true;
29 }
30 
31 static void
mt7921_regd_channel_update(struct wiphy * wiphy,struct mt792x_dev * dev)32 mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
33 {
34 #define IS_UNII_INVALID(idx, sfreq, efreq) \
35 	(!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq))
36 	struct ieee80211_supported_band *sband;
37 	struct mt76_dev *mdev = &dev->mt76;
38 	struct device_node *np, *band_np;
39 	struct ieee80211_channel *ch;
40 	int i, cfreq;
41 
42 	np = mt76_find_power_limits_node(mdev);
43 
44 	sband = wiphy->bands[NL80211_BAND_5GHZ];
45 	if (!sband)
46 		return;
47 
48 	band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL;
49 	for (i = 0; i < sband->n_channels; i++) {
50 		ch = &sband->channels[i];
51 		cfreq = ch->center_freq;
52 
53 		if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
54 			ch->flags |= IEEE80211_CHAN_DISABLED;
55 			continue;
56 		}
57 
58 		/* UNII-4 */
59 		if (IS_UNII_INVALID(0, 5845, 5925))
60 			ch->flags |= IEEE80211_CHAN_DISABLED;
61 	}
62 
63 	sband = wiphy->bands[NL80211_BAND_6GHZ];
64 	if (!sband)
65 		return;
66 
67 	band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL;
68 	for (i = 0; i < sband->n_channels; i++) {
69 		ch = &sband->channels[i];
70 		cfreq = ch->center_freq;
71 
72 		if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
73 			ch->flags |= IEEE80211_CHAN_DISABLED;
74 			continue;
75 		}
76 
77 		/* UNII-5/6/7/8 */
78 		if (IS_UNII_INVALID(1, 5925, 6425) ||
79 		    IS_UNII_INVALID(2, 6425, 6525) ||
80 		    IS_UNII_INVALID(3, 6525, 6875) ||
81 		    IS_UNII_INVALID(4, 6875, 7125))
82 			ch->flags |= IEEE80211_CHAN_DISABLED;
83 	}
84 }
85 
__mt7921_mcu_regd_update(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap country_ie_env)86 int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
87 			     enum environment_cap country_ie_env)
88 {
89 	struct mt76_dev *mdev = &dev->mt76;
90 	struct ieee80211_hw *hw = mdev->hw;
91 	struct wiphy *wiphy = hw->wiphy;
92 	int ret;
93 
94 	lockdep_assert_held(&dev->mt76.mutex);
95 
96 	if (!dev->regd_change)
97 		return 0;
98 
99 	ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env);
100 	if (ret < 0)
101 		return ret;
102 
103 	mt7921_regd_channel_update(wiphy, dev);
104 
105 	ret = mt76_connac_mcu_set_channel_domain(hw->priv);
106 	if (ret < 0)
107 		return ret;
108 
109 	ret = mt7921_set_tx_sar_pwr(hw, NULL);
110 
111 	return ret;
112 }
113 
mt7921_mcu_regd_update(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap country_ie_env)114 int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
115 			   enum environment_cap country_ie_env)
116 {
117 	int ret;
118 
119 	dev->regd_in_progress = true;
120 
121 	mt792x_mutex_acquire(dev);
122 	ret = __mt7921_mcu_regd_update(dev, alpha2, country_ie_env);
123 	mt792x_mutex_release(dev);
124 
125 	dev->regd_change = false;
126 	dev->regd_in_progress = false;
127 	wake_up(&dev->wait);
128 
129 	return ret;
130 }
131 EXPORT_SYMBOL_GPL(mt7921_mcu_regd_update);
132 
mt7921_regd_notifier(struct wiphy * wiphy,struct regulatory_request * req)133 void mt7921_regd_notifier(struct wiphy *wiphy,
134 			  struct regulatory_request *req)
135 {
136 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
137 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
138 	struct mt76_connac_pm *pm = &dev->pm;
139 	struct mt76_dev *mdev = &dev->mt76;
140 
141 	if (req->initiator == NL80211_REGDOM_SET_BY_USER &&
142 	    !dev->regd_user)
143 		dev->regd_user = true;
144 
145 	/* do not need to update the same country twice */
146 	if (!memcmp(req->alpha2, mdev->alpha2, 2) &&
147 	    dev->country_ie_env == req->country_ie_env)
148 		return;
149 
150 	memcpy(mdev->alpha2, req->alpha2, 2);
151 	mdev->region = req->dfs_region;
152 	dev->country_ie_env = req->country_ie_env;
153 
154 	if (req->initiator == NL80211_REGDOM_SET_BY_USER) {
155 		if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0')
156 			wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
157 		else
158 			wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
159 	}
160 
161 	dev->regd_change = true;
162 
163 	if (pm->suspended)
164 		return;
165 
166 	if (MT7921_REGD_SUPPORTED(&dev->phy)) {
167 		mt7921_regd_update(&dev->phy, req->alpha2);
168 
169 		return;
170 	}
171 
172 	mt7921_mcu_regd_update(dev, req->alpha2,
173 			       req->country_ie_env);
174 }
175 
176 static struct sk_buff *
mt7921_regd_query_regdb(struct mt792x_phy * phy,char * alpha2)177 mt7921_regd_query_regdb(struct mt792x_phy *phy, char *alpha2)
178 {
179 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
180 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
181 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
182 	struct mt7921_clc *clc = phy->clc[MT792x_CLC_REGD];
183 	struct mt7921_regd_query_req *req;
184 	struct mt7921_regd_cc *regd_cc;
185 	struct sk_buff *ret_skb = NULL;
186 	u8 *pos, *last_pos;
187 	int ret = 0;
188 
189 	if (!clc)
190 		return NULL;
191 
192 	pos = clc->data;
193 	last_pos = pos + le32_to_cpu(clc->len) - sizeof(struct mt7921_clc);
194 	while (pos < last_pos) {
195 		u32 req_len = 0;
196 		u32 rules_len = 0;
197 		u32 sign_len = 4;
198 		u32 n_reg_rules;
199 
200 		if (pos + sizeof(*regd_cc) > last_pos)
201 			break;
202 
203 		regd_cc = (struct mt7921_regd_cc *)pos;
204 		n_reg_rules = le32_to_cpu(regd_cc->n_reg_rules);
205 		if (n_reg_rules > NL80211_MAX_SUPP_REG_RULES)
206 			break;
207 
208 		rules_len = sizeof(struct mt7921_regd_rule_header) +
209 			    sizeof(struct mt7921_regd_rule) * n_reg_rules;
210 
211 		if (pos + sizeof(*regd_cc) + rules_len + sign_len > last_pos)
212 			break;
213 
214 		pos += sizeof(*regd_cc) + rules_len + sign_len;
215 		if (memcmp(regd_cc->alpha2, alpha2, 2))
216 			continue;
217 
218 		req_len = sizeof(*req) + rules_len + sign_len;
219 		req = kzalloc(req_len, GFP_KERNEL);
220 
221 		if (!req)
222 			return NULL;
223 
224 		req->ver = regd_cc->ver;
225 		req->sign_type = regd_cc->sign_type;
226 		req->size = cpu_to_le32(rules_len + sign_len);
227 		req->n_reg_rules = regd_cc->n_reg_rules;
228 
229 		memcpy(req->alpha2, regd_cc->alpha2, 2);
230 		memcpy(req->data, regd_cc->data, rules_len + sign_len);
231 
232 		ret = mt76_mcu_send_and_get_msg(&dev->mt76,
233 						MCU_CE_CMD(SET_REGD_CH),
234 						req, req_len, true, &ret_skb);
235 
236 		kfree(req);
237 
238 		return ret < 0 ? NULL : ret_skb;
239 	}
240 
241 	return NULL;
242 }
243 
mt7921_regd_update(struct mt792x_phy * phy,char * alpha2)244 int mt7921_regd_update(struct mt792x_phy *phy, char *alpha2)
245 {
246 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
247 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
248 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
249 	struct mt7921_regd_rule *mt7921_rule;
250 	struct mt76_dev *mdev = &dev->mt76;
251 	struct ieee80211_regdomain *regd;
252 	struct ieee80211_reg_rule *rule;
253 	struct mt7921_regd_rule_ev *ev;
254 	int i, num_of_rules = 0;
255 	struct sk_buff *skb;
256 	int ret = 0;
257 
258 	if (dev->hw_full_reset)
259 		return 0;
260 
261 	if (!MT7921_REGD_SUPPORTED(phy))
262 		return -EOPNOTSUPP;
263 
264 	mt792x_mutex_acquire(dev);
265 	skb = mt7921_regd_query_regdb(phy, alpha2);
266 	mt792x_mutex_release(dev);
267 
268 	if (!skb) {
269 		ret = -EINVAL;
270 		goto err;
271 	}
272 
273 	if (skb->len < sizeof(*ev) + 4) {
274 		ret = -EINVAL;
275 		goto err;
276 	}
277 
278 	ev = (struct mt7921_regd_rule_ev *)(skb->data + 4);
279 	num_of_rules = le32_to_cpu(ev->n_reg_rules);
280 
281 	if (!num_of_rules ||
282 	    WARN_ON_ONCE(num_of_rules > NL80211_MAX_SUPP_REG_RULES)) {
283 		ret = -EINVAL;
284 		goto err;
285 	}
286 
287 	if (skb->len < struct_size(ev, reg_rule, num_of_rules) + 4) {
288 		ret = -EINVAL;
289 		goto err;
290 	}
291 
292 	regd = kzalloc(struct_size(regd, reg_rules, num_of_rules), GFP_KERNEL);
293 	if (!regd) {
294 		ret = -ENOMEM;
295 		goto err;
296 	}
297 
298 	for (i = 0; i < num_of_rules; i++) {
299 		mt7921_rule = &ev->reg_rule[i];
300 		rule = &regd->reg_rules[i];
301 
302 		rule->freq_range.start_freq_khz =
303 			MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->start_freq));
304 		rule->freq_range.end_freq_khz =
305 			MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->end_freq));
306 		rule->freq_range.max_bandwidth_khz =
307 			MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->max_bw));
308 		/* not used by fw */
309 		rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
310 		rule->power_rule.max_eirp = DBM_TO_MBM(22);
311 		rule->flags = le32_to_cpu(mt7921_rule->flags);
312 	}
313 
314 	regd->n_reg_rules = num_of_rules;
315 	regd->dfs_region = ev->dfs_region;
316 
317 	memcpy(regd->alpha2, alpha2, 2);
318 	memcpy(mdev->alpha2, alpha2, 2);
319 
320 	dev->regd_change = true;
321 	mt7921_mcu_regd_update(dev, alpha2, ENVIRON_ANY);
322 
323 	ret = regulatory_set_wiphy_regd(wiphy, regd);
324 
325 	kfree(regd);
326 err:
327 	dev_kfree_skb(skb);
328 
329 	if (ret < 0)
330 		return regulatory_set_wiphy_regd(wiphy, &mt7921_regd_ww);
331 
332 	return ret;
333 }
334 EXPORT_SYMBOL_GPL(mt7921_regd_update);
335 
336 static bool
mt7921_regd_is_valid_alpha2(const char * alpha2)337 mt7921_regd_is_valid_alpha2(const char *alpha2)
338 {
339 	if (!alpha2)
340 		return false;
341 
342 	if (alpha2[0] == '0' && alpha2[1] == '0')
343 		return true;
344 
345 	if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
346 		return true;
347 
348 	return false;
349 }
350 
mt7921_regd_change(struct mt792x_phy * phy,char * alpha2)351 int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2)
352 {
353 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
354 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
355 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
356 	struct mt76_dev *mdev = &dev->mt76;
357 
358 	if (dev->hw_full_reset)
359 		return 0;
360 
361 	if (!mt7921_regd_is_valid_alpha2(alpha2) ||
362 	    !mt7921_regd_clc_supported(dev) ||
363 	    dev->regd_user)
364 		return -EINVAL;
365 
366 	if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0')
367 		return 0;
368 
369 	/* do not need to update the same country twice */
370 	if (!memcmp(alpha2, mdev->alpha2, 2))
371 		return 0;
372 
373 	if (MT7921_REGD_SUPPORTED(phy))
374 		return mt7921_regd_update(phy, alpha2);
375 	else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
376 		return regulatory_hint(wiphy, alpha2);
377 	else
378 		return mt7921_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR);
379 }
380 
mt7921_regd_init(struct mt792x_phy * phy)381 int mt7921_regd_init(struct mt792x_phy *phy)
382 {
383 	struct wiphy *wiphy = phy->mt76->hw->wiphy;
384 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
385 	struct mt792x_dev *dev = mt792x_hw_dev(hw);
386 	struct mt76_dev *mdev = &dev->mt76;
387 
388 	if (MT7921_REGD_SUPPORTED(phy)) {
389 		wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
390 					   REGULATORY_DISABLE_BEACON_HINTS;
391 		return mt7921_regd_update(phy, "00");
392 	} else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
393 		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE |
394 					   REGULATORY_DISABLE_BEACON_HINTS;
395 	else
396 		memzero_explicit(&mdev->alpha2, sizeof(mdev->alpha2));
397 
398 	return 0;
399 }
400