xref: /linux/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c (revision c771600c6af14749609b49565ffb4cac2959710d)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
27bc04215SFelix Fietkau /*
37bc04215SFelix Fietkau  * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
47bc04215SFelix Fietkau  */
57bc04215SFelix Fietkau 
6e6cb3291SLorenzo Bianconi #include "mt76x02.h"
77bc04215SFelix Fietkau 
87bc04215SFelix Fietkau #define RADAR_SPEC(m, len, el, eh, wl, wh,		\
97bc04215SFelix Fietkau 		   w_tolerance, tl, th, t_tolerance,	\
107bc04215SFelix Fietkau 		   bl, bh, event_exp, power_jmp)	\
117bc04215SFelix Fietkau {							\
127bc04215SFelix Fietkau 	.mode = m,					\
137bc04215SFelix Fietkau 	.avg_len = len,					\
147bc04215SFelix Fietkau 	.e_low = el,					\
157bc04215SFelix Fietkau 	.e_high = eh,					\
167bc04215SFelix Fietkau 	.w_low = wl,					\
177bc04215SFelix Fietkau 	.w_high = wh,					\
187bc04215SFelix Fietkau 	.w_margin = w_tolerance,			\
197bc04215SFelix Fietkau 	.t_low = tl,					\
207bc04215SFelix Fietkau 	.t_high = th,					\
217bc04215SFelix Fietkau 	.t_margin = t_tolerance,			\
227bc04215SFelix Fietkau 	.b_low = bl,					\
237bc04215SFelix Fietkau 	.b_high = bh,					\
247bc04215SFelix Fietkau 	.event_expiration = event_exp,			\
257bc04215SFelix Fietkau 	.pwr_jmp = power_jmp				\
267bc04215SFelix Fietkau }
277bc04215SFelix Fietkau 
28e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs etsi_radar_specs[] = {
297bc04215SFelix Fietkau 	/* 20MHz */
307bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
317bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
327bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
337bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
347bc04215SFelix Fietkau 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
357bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19dd),
367bc04215SFelix Fietkau 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
377bc04215SFelix Fietkau 		   0x7fffffff, 0x2191c0, 0x15cc),
387bc04215SFelix Fietkau 	/* 40MHz */
397bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
407bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
417bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
427bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
437bc04215SFelix Fietkau 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
447bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19dd),
457bc04215SFelix Fietkau 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
467bc04215SFelix Fietkau 		   0x7fffffff, 0x2191c0, 0x15cc),
477bc04215SFelix Fietkau 	/* 80MHz */
487bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
497bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
507bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
517bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19cc),
527bc04215SFelix Fietkau 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
537bc04215SFelix Fietkau 		   0x7fffffff, 0x155cc0, 0x19dd),
547bc04215SFelix Fietkau 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
557bc04215SFelix Fietkau 		   0x7fffffff, 0x2191c0, 0x15cc)
567bc04215SFelix Fietkau };
577bc04215SFelix Fietkau 
58e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs fcc_radar_specs[] = {
597bc04215SFelix Fietkau 	/* 20MHz */
607bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
617bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x13dc),
627bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
637bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x19dd),
647bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
657bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x12cc),
667bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
677bc04215SFelix Fietkau 		   0x3938700, 0x57bcf00, 0x1289),
687bc04215SFelix Fietkau 	/* 40MHz */
697bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
707bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x13dc),
717bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
727bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x19dd),
737bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
747bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x12cc),
757bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
767bc04215SFelix Fietkau 		   0x3938700, 0x57bcf00, 0x1289),
777bc04215SFelix Fietkau 	/* 80MHz */
787bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0,
797bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x16cc),
807bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
817bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x19dd),
827bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
837bc04215SFelix Fietkau 		   0x7fffffff, 0xfe808, 0x12cc),
847bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
857bc04215SFelix Fietkau 		   0x3938700, 0x57bcf00, 0x1289)
867bc04215SFelix Fietkau };
877bc04215SFelix Fietkau 
88e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w56_radar_specs[] = {
897bc04215SFelix Fietkau 	/* 20MHz */
907bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
917bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x13dc),
927bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
937bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x19dd),
947bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
957bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x12cc),
967bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
977bc04215SFelix Fietkau 		   0x3938700, 0X57bcf00, 0x1289),
987bc04215SFelix Fietkau 	/* 40MHz */
997bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
1007bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x13dc),
1017bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
1027bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x19dd),
1037bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
1047bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x12cc),
1057bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
1067bc04215SFelix Fietkau 		   0x3938700, 0X57bcf00, 0x1289),
1077bc04215SFelix Fietkau 	/* 80MHz */
1087bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0,
1097bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1107bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
1117bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x19dd),
1127bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
1137bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x12cc),
1147bc04215SFelix Fietkau 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
1157bc04215SFelix Fietkau 		   0x3938700, 0X57bcf00, 0x1289)
1167bc04215SFelix Fietkau };
1177bc04215SFelix Fietkau 
118e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w53_radar_specs[] = {
1197bc04215SFelix Fietkau 	/* 20MHz */
1207bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1217bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1227bc04215SFelix Fietkau 	{ 0 },
1237bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1247bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1257bc04215SFelix Fietkau 	{ 0 },
1267bc04215SFelix Fietkau 	/* 40MHz */
1277bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1287bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1297bc04215SFelix Fietkau 	{ 0 },
1307bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1317bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1327bc04215SFelix Fietkau 	{ 0 },
1337bc04215SFelix Fietkau 	/* 80MHz */
1347bc04215SFelix Fietkau 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1357bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1367bc04215SFelix Fietkau 	{ 0 },
1377bc04215SFelix Fietkau 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1387bc04215SFelix Fietkau 		   0x7fffffff, 0x14c080, 0x16cc),
1397bc04215SFelix Fietkau 	{ 0 }
1407bc04215SFelix Fietkau };
1417bc04215SFelix Fietkau 
142e40803f2SLorenzo Bianconi static void
mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev * dev,u8 enable)143e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable)
1447bc04215SFelix Fietkau {
1457bc04215SFelix Fietkau 	u32 data;
1467bc04215SFelix Fietkau 
1477bc04215SFelix Fietkau 	data = (1 << 1) | enable;
1487bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 36), data);
1497bc04215SFelix Fietkau }
1507bc04215SFelix Fietkau 
mt76x02_dfs_seq_pool_put(struct mt76x02_dev * dev,struct mt76x02_dfs_sequence * seq)151e6cb3291SLorenzo Bianconi static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev,
152e40803f2SLorenzo Bianconi 				     struct mt76x02_dfs_sequence *seq)
153b7384e4eSLorenzo Bianconi {
154e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
155b7384e4eSLorenzo Bianconi 
156b7384e4eSLorenzo Bianconi 	list_add(&seq->head, &dfs_pd->seq_pool);
1574a07ed51SLorenzo Bianconi 
1584a07ed51SLorenzo Bianconi 	dfs_pd->seq_stats.seq_pool_len++;
1594a07ed51SLorenzo Bianconi 	dfs_pd->seq_stats.seq_len--;
160b7384e4eSLorenzo Bianconi }
161b7384e4eSLorenzo Bianconi 
162e40803f2SLorenzo Bianconi static struct mt76x02_dfs_sequence *
mt76x02_dfs_seq_pool_get(struct mt76x02_dev * dev)163e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev)
164b7384e4eSLorenzo Bianconi {
165e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
166e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq;
167b7384e4eSLorenzo Bianconi 
168b7384e4eSLorenzo Bianconi 	if (list_empty(&dfs_pd->seq_pool)) {
169b7384e4eSLorenzo Bianconi 		seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC);
170b7384e4eSLorenzo Bianconi 	} else {
171b7384e4eSLorenzo Bianconi 		seq = list_first_entry(&dfs_pd->seq_pool,
172e40803f2SLorenzo Bianconi 				       struct mt76x02_dfs_sequence,
173b7384e4eSLorenzo Bianconi 				       head);
174b7384e4eSLorenzo Bianconi 		list_del(&seq->head);
1754a07ed51SLorenzo Bianconi 		dfs_pd->seq_stats.seq_pool_len--;
176b7384e4eSLorenzo Bianconi 	}
1774a07ed51SLorenzo Bianconi 	if (seq)
1784a07ed51SLorenzo Bianconi 		dfs_pd->seq_stats.seq_len++;
1794a07ed51SLorenzo Bianconi 
180b7384e4eSLorenzo Bianconi 	return seq;
181b7384e4eSLorenzo Bianconi }
182b7384e4eSLorenzo Bianconi 
mt76x02_dfs_get_multiple(int val,int frac,int margin)183e6cb3291SLorenzo Bianconi static int mt76x02_dfs_get_multiple(int val, int frac, int margin)
184b7384e4eSLorenzo Bianconi {
185b7384e4eSLorenzo Bianconi 	int remainder, factor;
186b7384e4eSLorenzo Bianconi 
187b7384e4eSLorenzo Bianconi 	if (!frac)
188b7384e4eSLorenzo Bianconi 		return 0;
189b7384e4eSLorenzo Bianconi 
190b7384e4eSLorenzo Bianconi 	if (abs(val - frac) <= margin)
191b7384e4eSLorenzo Bianconi 		return 1;
192b7384e4eSLorenzo Bianconi 
193b7384e4eSLorenzo Bianconi 	factor = val / frac;
194b7384e4eSLorenzo Bianconi 	remainder = val % frac;
195b7384e4eSLorenzo Bianconi 
196b7384e4eSLorenzo Bianconi 	if (remainder > margin) {
197b7384e4eSLorenzo Bianconi 		if ((frac - remainder) <= margin)
198b7384e4eSLorenzo Bianconi 			factor++;
199b7384e4eSLorenzo Bianconi 		else
200b7384e4eSLorenzo Bianconi 			factor = 0;
201b7384e4eSLorenzo Bianconi 	}
202b7384e4eSLorenzo Bianconi 	return factor;
203b7384e4eSLorenzo Bianconi }
204b7384e4eSLorenzo Bianconi 
mt76x02_dfs_detector_reset(struct mt76x02_dev * dev)205e6cb3291SLorenzo Bianconi static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev)
2061fc9bc9aSLorenzo Bianconi {
207e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
208e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq, *tmp_seq;
2091fc9bc9aSLorenzo Bianconi 	int i;
2101fc9bc9aSLorenzo Bianconi 
2111fc9bc9aSLorenzo Bianconi 	/* reset hw detector */
2121fc9bc9aSLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
2131fc9bc9aSLorenzo Bianconi 
2141fc9bc9aSLorenzo Bianconi 	/* reset sw detector */
2151fc9bc9aSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
2161fc9bc9aSLorenzo Bianconi 		dfs_pd->event_rb[i].h_rb = 0;
2171fc9bc9aSLorenzo Bianconi 		dfs_pd->event_rb[i].t_rb = 0;
2181fc9bc9aSLorenzo Bianconi 	}
219b7384e4eSLorenzo Bianconi 
220b7384e4eSLorenzo Bianconi 	list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
221b7384e4eSLorenzo Bianconi 		list_del_init(&seq->head);
222e6cb3291SLorenzo Bianconi 		mt76x02_dfs_seq_pool_put(dev, seq);
223b7384e4eSLorenzo Bianconi 	}
2241fc9bc9aSLorenzo Bianconi }
2251fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_check_chirp(struct mt76x02_dev * dev)226e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev)
2277bc04215SFelix Fietkau {
2287bc04215SFelix Fietkau 	bool ret = false;
2297bc04215SFelix Fietkau 	u32 current_ts, delta_ts;
230e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
2317bc04215SFelix Fietkau 
2327bc04215SFelix Fietkau 	current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER);
2337bc04215SFelix Fietkau 	delta_ts = current_ts - dfs_pd->chirp_pulse_ts;
2347bc04215SFelix Fietkau 	dfs_pd->chirp_pulse_ts = current_ts;
2357bc04215SFelix Fietkau 
2367bc04215SFelix Fietkau 	/* 12 sec */
2377bc04215SFelix Fietkau 	if (delta_ts <= (12 * (1 << 20))) {
2387bc04215SFelix Fietkau 		if (++dfs_pd->chirp_pulse_cnt > 8)
2397bc04215SFelix Fietkau 			ret = true;
2407bc04215SFelix Fietkau 	} else {
2417bc04215SFelix Fietkau 		dfs_pd->chirp_pulse_cnt = 1;
2427bc04215SFelix Fietkau 	}
2437bc04215SFelix Fietkau 
2447bc04215SFelix Fietkau 	return ret;
2457bc04215SFelix Fietkau }
2467bc04215SFelix Fietkau 
mt76x02_dfs_get_hw_pulse(struct mt76x02_dev * dev,struct mt76x02_dfs_hw_pulse * pulse)247e6cb3291SLorenzo Bianconi static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev,
248e40803f2SLorenzo Bianconi 				     struct mt76x02_dfs_hw_pulse *pulse)
2497bc04215SFelix Fietkau {
2507bc04215SFelix Fietkau 	u32 data;
2517bc04215SFelix Fietkau 
2527bc04215SFelix Fietkau 	/* select channel */
2537bc04215SFelix Fietkau 	data = (MT_DFS_CH_EN << 16) | pulse->engine;
2547bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 0), data);
2557bc04215SFelix Fietkau 
2567bc04215SFelix Fietkau 	/* reported period */
2577bc04215SFelix Fietkau 	pulse->period = mt76_rr(dev, MT_BBP(DFS, 19));
2587bc04215SFelix Fietkau 
2597bc04215SFelix Fietkau 	/* reported width */
2607bc04215SFelix Fietkau 	pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20));
2617bc04215SFelix Fietkau 	pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23));
2627bc04215SFelix Fietkau 
2637bc04215SFelix Fietkau 	/* reported burst number */
2647bc04215SFelix Fietkau 	pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22));
2657bc04215SFelix Fietkau }
2667bc04215SFelix Fietkau 
mt76x02_dfs_check_hw_pulse(struct mt76x02_dev * dev,struct mt76x02_dfs_hw_pulse * pulse)267e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev,
268e40803f2SLorenzo Bianconi 				       struct mt76x02_dfs_hw_pulse *pulse)
2697bc04215SFelix Fietkau {
2707bc04215SFelix Fietkau 	bool ret = false;
2717bc04215SFelix Fietkau 
2727bc04215SFelix Fietkau 	if (!pulse->period || !pulse->w1)
2737bc04215SFelix Fietkau 		return false;
2747bc04215SFelix Fietkau 
275d8b8890dSLorenzo Bianconi 	switch (dev->mt76.region) {
2767bc04215SFelix Fietkau 	case NL80211_DFS_FCC:
2777bc04215SFelix Fietkau 		if (pulse->engine > 3)
2787bc04215SFelix Fietkau 			break;
2797bc04215SFelix Fietkau 
2807bc04215SFelix Fietkau 		if (pulse->engine == 3) {
281e6cb3291SLorenzo Bianconi 			ret = mt76x02_dfs_check_chirp(dev);
2827bc04215SFelix Fietkau 			break;
2837bc04215SFelix Fietkau 		}
2847bc04215SFelix Fietkau 
2857bc04215SFelix Fietkau 		/* check short pulse*/
2867bc04215SFelix Fietkau 		if (pulse->w1 < 120)
2877bc04215SFelix Fietkau 			ret = (pulse->period >= 2900 &&
2887bc04215SFelix Fietkau 			       (pulse->period <= 4700 ||
2897bc04215SFelix Fietkau 				pulse->period >= 6400) &&
2907bc04215SFelix Fietkau 			       (pulse->period <= 6800 ||
2917bc04215SFelix Fietkau 				pulse->period >= 10200) &&
2927bc04215SFelix Fietkau 			       pulse->period <= 61600);
2937bc04215SFelix Fietkau 		else if (pulse->w1 < 130) /* 120 - 130 */
2947bc04215SFelix Fietkau 			ret = (pulse->period >= 2900 &&
2957bc04215SFelix Fietkau 			       pulse->period <= 61600);
2967bc04215SFelix Fietkau 		else
2977bc04215SFelix Fietkau 			ret = (pulse->period >= 3500 &&
2987bc04215SFelix Fietkau 			       pulse->period <= 10100);
2997bc04215SFelix Fietkau 		break;
3007bc04215SFelix Fietkau 	case NL80211_DFS_ETSI:
3017bc04215SFelix Fietkau 		if (pulse->engine >= 3)
3027bc04215SFelix Fietkau 			break;
3037bc04215SFelix Fietkau 
3047bc04215SFelix Fietkau 		ret = (pulse->period >= 4900 &&
3057bc04215SFelix Fietkau 		       (pulse->period <= 10200 ||
3067bc04215SFelix Fietkau 			pulse->period >= 12400) &&
3077bc04215SFelix Fietkau 		       pulse->period <= 100100);
3087bc04215SFelix Fietkau 		break;
3097bc04215SFelix Fietkau 	case NL80211_DFS_JP:
31096747a51SFelix Fietkau 		if (dev->mphy.chandef.chan->center_freq >= 5250 &&
31196747a51SFelix Fietkau 		    dev->mphy.chandef.chan->center_freq <= 5350) {
3127bc04215SFelix Fietkau 			/* JPW53 */
3137bc04215SFelix Fietkau 			if (pulse->w1 <= 130)
3147bc04215SFelix Fietkau 				ret = (pulse->period >= 28360 &&
3157bc04215SFelix Fietkau 				       (pulse->period <= 28700 ||
3167bc04215SFelix Fietkau 					pulse->period >= 76900) &&
3177bc04215SFelix Fietkau 				       pulse->period <= 76940);
3187bc04215SFelix Fietkau 			break;
3197bc04215SFelix Fietkau 		}
3207bc04215SFelix Fietkau 
3217bc04215SFelix Fietkau 		if (pulse->engine > 3)
3227bc04215SFelix Fietkau 			break;
3237bc04215SFelix Fietkau 
3247bc04215SFelix Fietkau 		if (pulse->engine == 3) {
325e6cb3291SLorenzo Bianconi 			ret = mt76x02_dfs_check_chirp(dev);
3267bc04215SFelix Fietkau 			break;
3277bc04215SFelix Fietkau 		}
3287bc04215SFelix Fietkau 
3297bc04215SFelix Fietkau 		/* check short pulse*/
3307bc04215SFelix Fietkau 		if (pulse->w1 < 120)
3317bc04215SFelix Fietkau 			ret = (pulse->period >= 2900 &&
3327bc04215SFelix Fietkau 			       (pulse->period <= 4700 ||
3337bc04215SFelix Fietkau 				pulse->period >= 6400) &&
3347bc04215SFelix Fietkau 			       (pulse->period <= 6800 ||
3357bc04215SFelix Fietkau 				pulse->period >= 27560) &&
3367bc04215SFelix Fietkau 			       (pulse->period <= 27960 ||
3377bc04215SFelix Fietkau 				pulse->period >= 28360) &&
3387bc04215SFelix Fietkau 			       (pulse->period <= 28700 ||
3397bc04215SFelix Fietkau 				pulse->period >= 79900) &&
3407bc04215SFelix Fietkau 			       pulse->period <= 80100);
3417bc04215SFelix Fietkau 		else if (pulse->w1 < 130) /* 120 - 130 */
3427bc04215SFelix Fietkau 			ret = (pulse->period >= 2900 &&
3437bc04215SFelix Fietkau 			       (pulse->period <= 10100 ||
3447bc04215SFelix Fietkau 				pulse->period >= 27560) &&
3457bc04215SFelix Fietkau 			       (pulse->period <= 27960 ||
3467bc04215SFelix Fietkau 				pulse->period >= 28360) &&
3477bc04215SFelix Fietkau 			       (pulse->period <= 28700 ||
3487bc04215SFelix Fietkau 				pulse->period >= 79900) &&
3497bc04215SFelix Fietkau 			       pulse->period <= 80100);
3507bc04215SFelix Fietkau 		else
3517bc04215SFelix Fietkau 			ret = (pulse->period >= 3900 &&
3527bc04215SFelix Fietkau 			       pulse->period <= 10100);
3537bc04215SFelix Fietkau 		break;
3547bc04215SFelix Fietkau 	case NL80211_DFS_UNSET:
3557bc04215SFelix Fietkau 	default:
3567bc04215SFelix Fietkau 		return false;
3577bc04215SFelix Fietkau 	}
3587bc04215SFelix Fietkau 
3597bc04215SFelix Fietkau 	return ret;
3607bc04215SFelix Fietkau }
3617bc04215SFelix Fietkau 
mt76x02_dfs_fetch_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)362e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev,
363e40803f2SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
3641fc9bc9aSLorenzo Bianconi {
3651fc9bc9aSLorenzo Bianconi 	u32 data;
3661fc9bc9aSLorenzo Bianconi 
3671fc9bc9aSLorenzo Bianconi 	/* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2)
3681fc9bc9aSLorenzo Bianconi 	 * 2nd: DFS_R37[21:0]: pulse time
3691fc9bc9aSLorenzo Bianconi 	 * 3rd: DFS_R37[11:0]: pulse width
3701fc9bc9aSLorenzo Bianconi 	 * 3rd: DFS_R37[25:16]: phase
3711fc9bc9aSLorenzo Bianconi 	 * 4th: DFS_R37[12:0]: current pwr
3721fc9bc9aSLorenzo Bianconi 	 * 4th: DFS_R37[21:16]: pwr stable counter
3731fc9bc9aSLorenzo Bianconi 	 *
3741fc9bc9aSLorenzo Bianconi 	 * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected
3751fc9bc9aSLorenzo Bianconi 	 */
3761fc9bc9aSLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
3771fc9bc9aSLorenzo Bianconi 	if (!MT_DFS_CHECK_EVENT(data))
3781fc9bc9aSLorenzo Bianconi 		return false;
3791fc9bc9aSLorenzo Bianconi 
3801fc9bc9aSLorenzo Bianconi 	event->engine = MT_DFS_EVENT_ENGINE(data);
3811fc9bc9aSLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
3821fc9bc9aSLorenzo Bianconi 	event->ts = MT_DFS_EVENT_TIMESTAMP(data);
3831fc9bc9aSLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
3841fc9bc9aSLorenzo Bianconi 	event->width = MT_DFS_EVENT_WIDTH(data);
3851fc9bc9aSLorenzo Bianconi 
3861fc9bc9aSLorenzo Bianconi 	return true;
3871fc9bc9aSLorenzo Bianconi }
3881fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_check_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)389e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev,
390e40803f2SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
3911fc9bc9aSLorenzo Bianconi {
3921fc9bc9aSLorenzo Bianconi 	if (event->engine == 2) {
393e40803f2SLorenzo Bianconi 		struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
394e40803f2SLorenzo Bianconi 		struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
3951fc9bc9aSLorenzo Bianconi 		u16 last_event_idx;
3961fc9bc9aSLorenzo Bianconi 		u32 delta_ts;
3971fc9bc9aSLorenzo Bianconi 
3981fc9bc9aSLorenzo Bianconi 		last_event_idx = mt76_decr(event_buff->t_rb,
3991fc9bc9aSLorenzo Bianconi 					   MT_DFS_EVENT_BUFLEN);
4001fc9bc9aSLorenzo Bianconi 		delta_ts = event->ts - event_buff->data[last_event_idx].ts;
4011fc9bc9aSLorenzo Bianconi 		if (delta_ts < MT_DFS_EVENT_TIME_MARGIN &&
4021fc9bc9aSLorenzo Bianconi 		    event_buff->data[last_event_idx].width >= 200)
4031fc9bc9aSLorenzo Bianconi 			return false;
4041fc9bc9aSLorenzo Bianconi 	}
4051fc9bc9aSLorenzo Bianconi 	return true;
4061fc9bc9aSLorenzo Bianconi }
4071fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_queue_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)408e6cb3291SLorenzo Bianconi static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev,
409e40803f2SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
4101fc9bc9aSLorenzo Bianconi {
411e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
412e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_buff;
4131fc9bc9aSLorenzo Bianconi 
4141fc9bc9aSLorenzo Bianconi 	/* add radar event to ring buffer */
4151fc9bc9aSLorenzo Bianconi 	event_buff = event->engine == 2 ? &dfs_pd->event_rb[1]
4161fc9bc9aSLorenzo Bianconi 					: &dfs_pd->event_rb[0];
4171fc9bc9aSLorenzo Bianconi 	event_buff->data[event_buff->t_rb] = *event;
4181fc9bc9aSLorenzo Bianconi 	event_buff->data[event_buff->t_rb].fetch_ts = jiffies;
4191fc9bc9aSLorenzo Bianconi 
4201fc9bc9aSLorenzo Bianconi 	event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN);
4211fc9bc9aSLorenzo Bianconi 	if (event_buff->t_rb == event_buff->h_rb)
4221fc9bc9aSLorenzo Bianconi 		event_buff->h_rb = mt76_incr(event_buff->h_rb,
4231fc9bc9aSLorenzo Bianconi 					     MT_DFS_EVENT_BUFLEN);
4241fc9bc9aSLorenzo Bianconi }
4251fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_create_sequence(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event,u16 cur_len)426e6cb3291SLorenzo Bianconi static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
427e40803f2SLorenzo Bianconi 				       struct mt76x02_dfs_event *event,
428b7384e4eSLorenzo Bianconi 				       u16 cur_len)
429b7384e4eSLorenzo Bianconi {
430e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
431e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sw_detector_params *sw_params;
43200257508SYe Bin 	u32 width_delta, with_sum;
433e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sequence seq, *seq_p;
434e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_rb;
435e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event *cur_event;
43600257508SYe Bin 	int i, j, end, pri, factor, cur_pri;
437b7384e4eSLorenzo Bianconi 
438b7384e4eSLorenzo Bianconi 	event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
439b7384e4eSLorenzo Bianconi 				      : &dfs_pd->event_rb[0];
440b7384e4eSLorenzo Bianconi 
441b7384e4eSLorenzo Bianconi 	i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN);
442b7384e4eSLorenzo Bianconi 	end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN);
443b7384e4eSLorenzo Bianconi 
444b7384e4eSLorenzo Bianconi 	while (i != end) {
445b7384e4eSLorenzo Bianconi 		cur_event = &event_rb->data[i];
446b7384e4eSLorenzo Bianconi 		with_sum = event->width + cur_event->width;
447b7384e4eSLorenzo Bianconi 
448b7384e4eSLorenzo Bianconi 		sw_params = &dfs_pd->sw_dpd_params;
449d8b8890dSLorenzo Bianconi 		switch (dev->mt76.region) {
450b7384e4eSLorenzo Bianconi 		case NL80211_DFS_FCC:
451b7384e4eSLorenzo Bianconi 		case NL80211_DFS_JP:
452b7384e4eSLorenzo Bianconi 			if (with_sum < 600)
453b7384e4eSLorenzo Bianconi 				width_delta = 8;
454b7384e4eSLorenzo Bianconi 			else
455b7384e4eSLorenzo Bianconi 				width_delta = with_sum >> 3;
456b7384e4eSLorenzo Bianconi 			break;
457b7384e4eSLorenzo Bianconi 		case NL80211_DFS_ETSI:
458b7384e4eSLorenzo Bianconi 			if (event->engine == 2)
459b7384e4eSLorenzo Bianconi 				width_delta = with_sum >> 6;
460b7384e4eSLorenzo Bianconi 			else if (with_sum < 620)
461b7384e4eSLorenzo Bianconi 				width_delta = 24;
462b7384e4eSLorenzo Bianconi 			else
463b7384e4eSLorenzo Bianconi 				width_delta = 8;
464b7384e4eSLorenzo Bianconi 			break;
465b7384e4eSLorenzo Bianconi 		case NL80211_DFS_UNSET:
466b7384e4eSLorenzo Bianconi 		default:
467b7384e4eSLorenzo Bianconi 			return -EINVAL;
468b7384e4eSLorenzo Bianconi 		}
469b7384e4eSLorenzo Bianconi 
470b7384e4eSLorenzo Bianconi 		pri = event->ts - cur_event->ts;
471b7384e4eSLorenzo Bianconi 		if (abs(event->width - cur_event->width) > width_delta ||
472b7384e4eSLorenzo Bianconi 		    pri < sw_params->min_pri)
473b7384e4eSLorenzo Bianconi 			goto next;
474b7384e4eSLorenzo Bianconi 
475b7384e4eSLorenzo Bianconi 		if (pri > sw_params->max_pri)
476b7384e4eSLorenzo Bianconi 			break;
477b7384e4eSLorenzo Bianconi 
478b7384e4eSLorenzo Bianconi 		seq.pri = event->ts - cur_event->ts;
479b7384e4eSLorenzo Bianconi 		seq.first_ts = cur_event->ts;
480b7384e4eSLorenzo Bianconi 		seq.last_ts = event->ts;
481b7384e4eSLorenzo Bianconi 		seq.engine = event->engine;
482b7384e4eSLorenzo Bianconi 		seq.count = 2;
483b7384e4eSLorenzo Bianconi 
484b7384e4eSLorenzo Bianconi 		j = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
485b7384e4eSLorenzo Bianconi 		while (j != end) {
486b7384e4eSLorenzo Bianconi 			cur_event = &event_rb->data[j];
487b7384e4eSLorenzo Bianconi 			cur_pri = event->ts - cur_event->ts;
488e6cb3291SLorenzo Bianconi 			factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri,
489b7384e4eSLorenzo Bianconi 						sw_params->pri_margin);
490b7384e4eSLorenzo Bianconi 			if (factor > 0) {
491b7384e4eSLorenzo Bianconi 				seq.first_ts = cur_event->ts;
492b7384e4eSLorenzo Bianconi 				seq.count++;
493b7384e4eSLorenzo Bianconi 			}
494b7384e4eSLorenzo Bianconi 
495b7384e4eSLorenzo Bianconi 			j = mt76_decr(j, MT_DFS_EVENT_BUFLEN);
496b7384e4eSLorenzo Bianconi 		}
497b7384e4eSLorenzo Bianconi 		if (seq.count <= cur_len)
498b7384e4eSLorenzo Bianconi 			goto next;
499b7384e4eSLorenzo Bianconi 
500e6cb3291SLorenzo Bianconi 		seq_p = mt76x02_dfs_seq_pool_get(dev);
501b7384e4eSLorenzo Bianconi 		if (!seq_p)
502b7384e4eSLorenzo Bianconi 			return -ENOMEM;
503b7384e4eSLorenzo Bianconi 
504b7384e4eSLorenzo Bianconi 		*seq_p = seq;
505b7384e4eSLorenzo Bianconi 		INIT_LIST_HEAD(&seq_p->head);
506b7384e4eSLorenzo Bianconi 		list_add(&seq_p->head, &dfs_pd->sequences);
507b7384e4eSLorenzo Bianconi next:
508b7384e4eSLorenzo Bianconi 		i = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
509b7384e4eSLorenzo Bianconi 	}
510b7384e4eSLorenzo Bianconi 	return 0;
511b7384e4eSLorenzo Bianconi }
512b7384e4eSLorenzo Bianconi 
mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)513e6cb3291SLorenzo Bianconi static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
514e40803f2SLorenzo Bianconi 					     struct mt76x02_dfs_event *event)
515b7384e4eSLorenzo Bianconi {
516e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
517e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sw_detector_params *sw_params;
518e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq, *tmp_seq;
519b7384e4eSLorenzo Bianconi 	u16 max_seq_len = 0;
52000257508SYe Bin 	int factor, pri;
521b7384e4eSLorenzo Bianconi 
522b7384e4eSLorenzo Bianconi 	sw_params = &dfs_pd->sw_dpd_params;
523b7384e4eSLorenzo Bianconi 	list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
524b7384e4eSLorenzo Bianconi 		if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) {
525b7384e4eSLorenzo Bianconi 			list_del_init(&seq->head);
526e6cb3291SLorenzo Bianconi 			mt76x02_dfs_seq_pool_put(dev, seq);
527b7384e4eSLorenzo Bianconi 			continue;
528b7384e4eSLorenzo Bianconi 		}
529b7384e4eSLorenzo Bianconi 
530b7384e4eSLorenzo Bianconi 		if (event->engine != seq->engine)
531b7384e4eSLorenzo Bianconi 			continue;
532b7384e4eSLorenzo Bianconi 
533b7384e4eSLorenzo Bianconi 		pri = event->ts - seq->last_ts;
534e6cb3291SLorenzo Bianconi 		factor = mt76x02_dfs_get_multiple(pri, seq->pri,
535b7384e4eSLorenzo Bianconi 						  sw_params->pri_margin);
536b7384e4eSLorenzo Bianconi 		if (factor > 0) {
537b7384e4eSLorenzo Bianconi 			seq->last_ts = event->ts;
538b7384e4eSLorenzo Bianconi 			seq->count++;
539b7384e4eSLorenzo Bianconi 			max_seq_len = max_t(u16, max_seq_len, seq->count);
540b7384e4eSLorenzo Bianconi 		}
541b7384e4eSLorenzo Bianconi 	}
542b7384e4eSLorenzo Bianconi 	return max_seq_len;
543b7384e4eSLorenzo Bianconi }
544b7384e4eSLorenzo Bianconi 
mt76x02_dfs_check_detection(struct mt76x02_dev * dev)545e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev)
546b7384e4eSLorenzo Bianconi {
547e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
548e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq;
549b7384e4eSLorenzo Bianconi 
550b7384e4eSLorenzo Bianconi 	if (list_empty(&dfs_pd->sequences))
551b7384e4eSLorenzo Bianconi 		return false;
552b7384e4eSLorenzo Bianconi 
553b7384e4eSLorenzo Bianconi 	list_for_each_entry(seq, &dfs_pd->sequences, head) {
5544a07ed51SLorenzo Bianconi 		if (seq->count > MT_DFS_SEQUENCE_TH) {
5554a07ed51SLorenzo Bianconi 			dfs_pd->stats[seq->engine].sw_pattern++;
556b7384e4eSLorenzo Bianconi 			return true;
557b7384e4eSLorenzo Bianconi 		}
5584a07ed51SLorenzo Bianconi 	}
559b7384e4eSLorenzo Bianconi 	return false;
560b7384e4eSLorenzo Bianconi }
561b7384e4eSLorenzo Bianconi 
mt76x02_dfs_add_events(struct mt76x02_dev * dev)562e6cb3291SLorenzo Bianconi static void mt76x02_dfs_add_events(struct mt76x02_dev *dev)
5631fc9bc9aSLorenzo Bianconi {
564e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
565e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event event;
566b7384e4eSLorenzo Bianconi 	int i, seq_len;
5671fc9bc9aSLorenzo Bianconi 
5681fc9bc9aSLorenzo Bianconi 	/* disable debug mode */
569e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_capture_mode_ctrl(dev, false);
5701fc9bc9aSLorenzo Bianconi 	for (i = 0; i < MT_DFS_EVENT_LOOP; i++) {
571e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_fetch_event(dev, &event))
5721fc9bc9aSLorenzo Bianconi 			break;
5731fc9bc9aSLorenzo Bianconi 
5741fc9bc9aSLorenzo Bianconi 		if (dfs_pd->last_event_ts > event.ts)
575e6cb3291SLorenzo Bianconi 			mt76x02_dfs_detector_reset(dev);
5761fc9bc9aSLorenzo Bianconi 		dfs_pd->last_event_ts = event.ts;
5771fc9bc9aSLorenzo Bianconi 
578e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_check_event(dev, &event))
5791fc9bc9aSLorenzo Bianconi 			continue;
5801fc9bc9aSLorenzo Bianconi 
581e6cb3291SLorenzo Bianconi 		seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event);
582e6cb3291SLorenzo Bianconi 		mt76x02_dfs_create_sequence(dev, &event, seq_len);
583b7384e4eSLorenzo Bianconi 
584e6cb3291SLorenzo Bianconi 		mt76x02_dfs_queue_event(dev, &event);
5851fc9bc9aSLorenzo Bianconi 	}
586e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_capture_mode_ctrl(dev, true);
5871fc9bc9aSLorenzo Bianconi }
5881fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_check_event_window(struct mt76x02_dev * dev)589e6cb3291SLorenzo Bianconi static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
5901fc9bc9aSLorenzo Bianconi {
591e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
592e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_buff;
593e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_event *event;
5941fc9bc9aSLorenzo Bianconi 	int i;
5951fc9bc9aSLorenzo Bianconi 
5961fc9bc9aSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
5971fc9bc9aSLorenzo Bianconi 		event_buff = &dfs_pd->event_rb[i];
5981fc9bc9aSLorenzo Bianconi 
5991fc9bc9aSLorenzo Bianconi 		while (event_buff->h_rb != event_buff->t_rb) {
6001fc9bc9aSLorenzo Bianconi 			event = &event_buff->data[event_buff->h_rb];
6011fc9bc9aSLorenzo Bianconi 
6021fc9bc9aSLorenzo Bianconi 			/* sorted list */
6031fc9bc9aSLorenzo Bianconi 			if (time_is_after_jiffies(event->fetch_ts +
6041fc9bc9aSLorenzo Bianconi 						  MT_DFS_EVENT_WINDOW))
6051fc9bc9aSLorenzo Bianconi 				break;
6061fc9bc9aSLorenzo Bianconi 			event_buff->h_rb = mt76_incr(event_buff->h_rb,
6071fc9bc9aSLorenzo Bianconi 						     MT_DFS_EVENT_BUFLEN);
6081fc9bc9aSLorenzo Bianconi 		}
6091fc9bc9aSLorenzo Bianconi 	}
6101fc9bc9aSLorenzo Bianconi }
6111fc9bc9aSLorenzo Bianconi 
mt76x02_dfs_tasklet(struct tasklet_struct * t)6125ee3e780SAllen Pais static void mt76x02_dfs_tasklet(struct tasklet_struct *t)
6137bc04215SFelix Fietkau {
6145ee3e780SAllen Pais 	struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t,
6155ee3e780SAllen Pais 								   dfs_tasklet);
6165ee3e780SAllen Pais 	struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd);
6177bc04215SFelix Fietkau 	u32 engine_mask;
6187bc04215SFelix Fietkau 	int i;
6197bc04215SFelix Fietkau 
620011849e0SFelix Fietkau 	if (test_bit(MT76_SCANNING, &dev->mphy.state))
6217bc04215SFelix Fietkau 		goto out;
6227bc04215SFelix Fietkau 
6231fc9bc9aSLorenzo Bianconi 	if (time_is_before_jiffies(dfs_pd->last_sw_check +
6241fc9bc9aSLorenzo Bianconi 				   MT_DFS_SW_TIMEOUT)) {
625b7384e4eSLorenzo Bianconi 		bool radar_detected;
626b7384e4eSLorenzo Bianconi 
6271fc9bc9aSLorenzo Bianconi 		dfs_pd->last_sw_check = jiffies;
6281fc9bc9aSLorenzo Bianconi 
629e6cb3291SLorenzo Bianconi 		mt76x02_dfs_add_events(dev);
630e6cb3291SLorenzo Bianconi 		radar_detected = mt76x02_dfs_check_detection(dev);
631b7384e4eSLorenzo Bianconi 		if (radar_detected) {
632b7384e4eSLorenzo Bianconi 			/* sw detector rx radar pattern */
633bca8bc03SAditya Kumar Singh 			ieee80211_radar_detected(dev->mt76.hw, NULL);
634e6cb3291SLorenzo Bianconi 			mt76x02_dfs_detector_reset(dev);
635b7384e4eSLorenzo Bianconi 
636b7384e4eSLorenzo Bianconi 			return;
637b7384e4eSLorenzo Bianconi 		}
638e6cb3291SLorenzo Bianconi 		mt76x02_dfs_check_event_window(dev);
6391fc9bc9aSLorenzo Bianconi 	}
6401fc9bc9aSLorenzo Bianconi 
6417bc04215SFelix Fietkau 	engine_mask = mt76_rr(dev, MT_BBP(DFS, 1));
6427bc04215SFelix Fietkau 	if (!(engine_mask & 0xf))
6437bc04215SFelix Fietkau 		goto out;
6447bc04215SFelix Fietkau 
6457bc04215SFelix Fietkau 	for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
646e40803f2SLorenzo Bianconi 		struct mt76x02_dfs_hw_pulse pulse;
6477bc04215SFelix Fietkau 
6487bc04215SFelix Fietkau 		if (!(engine_mask & (1 << i)))
6497bc04215SFelix Fietkau 			continue;
6507bc04215SFelix Fietkau 
6517bc04215SFelix Fietkau 		pulse.engine = i;
652e6cb3291SLorenzo Bianconi 		mt76x02_dfs_get_hw_pulse(dev, &pulse);
6537bc04215SFelix Fietkau 
654e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) {
6557bc04215SFelix Fietkau 			dfs_pd->stats[i].hw_pulse_discarded++;
6567bc04215SFelix Fietkau 			continue;
6577bc04215SFelix Fietkau 		}
6587bc04215SFelix Fietkau 
6597bc04215SFelix Fietkau 		/* hw detector rx radar pattern */
6607bc04215SFelix Fietkau 		dfs_pd->stats[i].hw_pattern++;
661bca8bc03SAditya Kumar Singh 		ieee80211_radar_detected(dev->mt76.hw, NULL);
662e6cb3291SLorenzo Bianconi 		mt76x02_dfs_detector_reset(dev);
6637bc04215SFelix Fietkau 
6647bc04215SFelix Fietkau 		return;
6657bc04215SFelix Fietkau 	}
6667bc04215SFelix Fietkau 
6677bc04215SFelix Fietkau 	/* reset hw detector */
6687bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
6697bc04215SFelix Fietkau 
6707bc04215SFelix Fietkau out:
671a23fde09SLorenzo Bianconi 	mt76x02_irq_enable(dev, MT_INT_GPTIMER);
6727bc04215SFelix Fietkau }
6737bc04215SFelix Fietkau 
mt76x02_dfs_init_sw_detector(struct mt76x02_dev * dev)674e6cb3291SLorenzo Bianconi static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev)
675b7384e4eSLorenzo Bianconi {
676e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
677b7384e4eSLorenzo Bianconi 
678d8b8890dSLorenzo Bianconi 	switch (dev->mt76.region) {
679b7384e4eSLorenzo Bianconi 	case NL80211_DFS_FCC:
680b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI;
681b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI;
682b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
683b7384e4eSLorenzo Bianconi 		break;
684b7384e4eSLorenzo Bianconi 	case NL80211_DFS_ETSI:
685b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI;
686b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI;
687b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2;
688b7384e4eSLorenzo Bianconi 		break;
689b7384e4eSLorenzo Bianconi 	case NL80211_DFS_JP:
690b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI;
691b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI;
692b7384e4eSLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
693b7384e4eSLorenzo Bianconi 		break;
694b7384e4eSLorenzo Bianconi 	case NL80211_DFS_UNSET:
695b7384e4eSLorenzo Bianconi 	default:
696b7384e4eSLorenzo Bianconi 		break;
697b7384e4eSLorenzo Bianconi 	}
698b7384e4eSLorenzo Bianconi }
699b7384e4eSLorenzo Bianconi 
mt76x02_dfs_set_bbp_params(struct mt76x02_dev * dev)700e6cb3291SLorenzo Bianconi static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev)
7017bc04215SFelix Fietkau {
702e40803f2SLorenzo Bianconi 	const struct mt76x02_radar_specs *radar_specs;
7037bc04215SFelix Fietkau 	u8 i, shift;
704e40803f2SLorenzo Bianconi 	u32 data;
7057bc04215SFelix Fietkau 
70696747a51SFelix Fietkau 	switch (dev->mphy.chandef.width) {
7077bc04215SFelix Fietkau 	case NL80211_CHAN_WIDTH_40:
7087bc04215SFelix Fietkau 		shift = MT_DFS_NUM_ENGINES;
7097bc04215SFelix Fietkau 		break;
7107bc04215SFelix Fietkau 	case NL80211_CHAN_WIDTH_80:
7117bc04215SFelix Fietkau 		shift = 2 * MT_DFS_NUM_ENGINES;
7127bc04215SFelix Fietkau 		break;
7137bc04215SFelix Fietkau 	default:
7147bc04215SFelix Fietkau 		shift = 0;
7157bc04215SFelix Fietkau 		break;
7167bc04215SFelix Fietkau 	}
7177bc04215SFelix Fietkau 
718d8b8890dSLorenzo Bianconi 	switch (dev->mt76.region) {
7197bc04215SFelix Fietkau 	case NL80211_DFS_FCC:
7207bc04215SFelix Fietkau 		radar_specs = &fcc_radar_specs[shift];
7217bc04215SFelix Fietkau 		break;
7227bc04215SFelix Fietkau 	case NL80211_DFS_ETSI:
7237bc04215SFelix Fietkau 		radar_specs = &etsi_radar_specs[shift];
7247bc04215SFelix Fietkau 		break;
7257bc04215SFelix Fietkau 	case NL80211_DFS_JP:
72696747a51SFelix Fietkau 		if (dev->mphy.chandef.chan->center_freq >= 5250 &&
72796747a51SFelix Fietkau 		    dev->mphy.chandef.chan->center_freq <= 5350)
7287bc04215SFelix Fietkau 			radar_specs = &jp_w53_radar_specs[shift];
7297bc04215SFelix Fietkau 		else
7307bc04215SFelix Fietkau 			radar_specs = &jp_w56_radar_specs[shift];
7317bc04215SFelix Fietkau 		break;
7327bc04215SFelix Fietkau 	case NL80211_DFS_UNSET:
7337bc04215SFelix Fietkau 	default:
7347bc04215SFelix Fietkau 		return;
7357bc04215SFelix Fietkau 	}
7367bc04215SFelix Fietkau 
7377bc04215SFelix Fietkau 	data = (MT_DFS_VGA_MASK << 16) |
7387bc04215SFelix Fietkau 	       (MT_DFS_PWR_GAIN_OFFSET << 12) |
7397bc04215SFelix Fietkau 	       (MT_DFS_PWR_DOWN_TIME << 8) |
7407bc04215SFelix Fietkau 	       (MT_DFS_SYM_ROUND << 4) |
7417bc04215SFelix Fietkau 	       (MT_DFS_DELTA_DELAY & 0xf);
7427bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 2), data);
7437bc04215SFelix Fietkau 
7447bc04215SFelix Fietkau 	data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK;
7457bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 3), data);
7467bc04215SFelix Fietkau 
7477bc04215SFelix Fietkau 	for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
7487bc04215SFelix Fietkau 		/* configure engine */
7497bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 0), i);
7507bc04215SFelix Fietkau 
7517bc04215SFelix Fietkau 		/* detection mode + avg_len */
7527bc04215SFelix Fietkau 		data = ((radar_specs[i].avg_len & 0x1ff) << 16) |
7537bc04215SFelix Fietkau 		       (radar_specs[i].mode & 0xf);
7547bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 4), data);
7557bc04215SFelix Fietkau 
7567bc04215SFelix Fietkau 		/* dfs energy */
7577bc04215SFelix Fietkau 		data = ((radar_specs[i].e_high & 0x0fff) << 16) |
7587bc04215SFelix Fietkau 		       (radar_specs[i].e_low & 0x0fff);
7597bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 5), data);
7607bc04215SFelix Fietkau 
7617bc04215SFelix Fietkau 		/* dfs period */
7627bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low);
7637bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high);
7647bc04215SFelix Fietkau 
7657bc04215SFelix Fietkau 		/* dfs burst */
7667bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low);
7677bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high);
7687bc04215SFelix Fietkau 
7697bc04215SFelix Fietkau 		/* dfs width */
7707bc04215SFelix Fietkau 		data = ((radar_specs[i].w_high & 0x0fff) << 16) |
7717bc04215SFelix Fietkau 		       (radar_specs[i].w_low & 0x0fff);
7727bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 14), data);
7737bc04215SFelix Fietkau 
7747bc04215SFelix Fietkau 		/* dfs margins */
7757bc04215SFelix Fietkau 		data = (radar_specs[i].w_margin << 16) |
7767bc04215SFelix Fietkau 		       radar_specs[i].t_margin;
7777bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 15), data);
7787bc04215SFelix Fietkau 
7797bc04215SFelix Fietkau 		/* dfs event expiration */
7807bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration);
7817bc04215SFelix Fietkau 
7827bc04215SFelix Fietkau 		/* dfs pwr adj */
7837bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp);
7847bc04215SFelix Fietkau 	}
7857bc04215SFelix Fietkau 
7867bc04215SFelix Fietkau 	/* reset status */
7877bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
7887bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 36), 0x3);
7897bc04215SFelix Fietkau 
7907bc04215SFelix Fietkau 	/* enable detection*/
7917bc04215SFelix Fietkau 	mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
7926bf4a8e9SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(IBI, 11), 0x0c350001);
7937bc04215SFelix Fietkau }
7947bc04215SFelix Fietkau 
mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev * dev)795801ccc8aSLorenzo Bianconi void mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev *dev)
796801ccc8aSLorenzo Bianconi {
797801ccc8aSLorenzo Bianconi 	u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31;
798801ccc8aSLorenzo Bianconi 
799801ccc8aSLorenzo Bianconi 	agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8));
800801ccc8aSLorenzo Bianconi 	agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4));
801801ccc8aSLorenzo Bianconi 
802801ccc8aSLorenzo Bianconi 	val_r8 = (agc_r8 & 0x00007e00) >> 9;
803801ccc8aSLorenzo Bianconi 	val_r4 = agc_r4 & ~0x1f000000;
804801ccc8aSLorenzo Bianconi 	val_r4 += (((val_r8 + 1) >> 1) << 24);
805801ccc8aSLorenzo Bianconi 	mt76_wr(dev, MT_BBP(AGC, 4), val_r4);
806801ccc8aSLorenzo Bianconi 
807801ccc8aSLorenzo Bianconi 	dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4);
808801ccc8aSLorenzo Bianconi 	dfs_r31 += val_r8;
809801ccc8aSLorenzo Bianconi 	dfs_r31 -= (agc_r8 & 0x00000038) >> 3;
810801ccc8aSLorenzo Bianconi 	dfs_r31 = (dfs_r31 << 16) | 0x00000307;
811801ccc8aSLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31);
812801ccc8aSLorenzo Bianconi 
813801ccc8aSLorenzo Bianconi 	if (is_mt76x2(dev)) {
814801ccc8aSLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071);
815801ccc8aSLorenzo Bianconi 	} else {
816801ccc8aSLorenzo Bianconi 		/* disable hw detector */
817801ccc8aSLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 0), 0);
818801ccc8aSLorenzo Bianconi 		/* enable hw detector */
819801ccc8aSLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
820801ccc8aSLorenzo Bianconi 	}
821801ccc8aSLorenzo Bianconi }
822801ccc8aSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_phy_dfs_adjust_agc);
823801ccc8aSLorenzo Bianconi 
mt76x02_dfs_init_params(struct mt76x02_dev * dev)824e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_params(struct mt76x02_dev *dev)
8257bc04215SFelix Fietkau {
8265b7cc6d1SFelix Fietkau 	if (mt76_phy_dfs_state(&dev->mphy) > MT_DFS_STATE_DISABLED) {
827e6cb3291SLorenzo Bianconi 		mt76x02_dfs_init_sw_detector(dev);
828e6cb3291SLorenzo Bianconi 		mt76x02_dfs_set_bbp_params(dev);
8297bc04215SFelix Fietkau 		/* enable debug mode */
830e6cb3291SLorenzo Bianconi 		mt76x02_dfs_set_capture_mode_ctrl(dev, true);
8317bc04215SFelix Fietkau 
832a23fde09SLorenzo Bianconi 		mt76x02_irq_enable(dev, MT_INT_GPTIMER);
8337bc04215SFelix Fietkau 		mt76_rmw_field(dev, MT_INT_TIMER_EN,
8347bc04215SFelix Fietkau 			       MT_INT_TIMER_EN_GP_TIMER_EN, 1);
8357bc04215SFelix Fietkau 	} else {
8367bc04215SFelix Fietkau 		/* disable hw detector */
8377bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 0), 0);
8387bc04215SFelix Fietkau 		/* clear detector status */
8397bc04215SFelix Fietkau 		mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
8406bf4a8e9SLorenzo Bianconi 		if (mt76_chip(&dev->mt76) == 0x7610 ||
8416bf4a8e9SLorenzo Bianconi 		    mt76_chip(&dev->mt76) == 0x7630)
8426bf4a8e9SLorenzo Bianconi 			mt76_wr(dev, MT_BBP(IBI, 11), 0xfde8081);
8436bf4a8e9SLorenzo Bianconi 		else
8446bf4a8e9SLorenzo Bianconi 			mt76_wr(dev, MT_BBP(IBI, 11), 0);
8457bc04215SFelix Fietkau 
846a23fde09SLorenzo Bianconi 		mt76x02_irq_disable(dev, MT_INT_GPTIMER);
8477bc04215SFelix Fietkau 		mt76_rmw_field(dev, MT_INT_TIMER_EN,
8487bc04215SFelix Fietkau 			       MT_INT_TIMER_EN_GP_TIMER_EN, 0);
8497bc04215SFelix Fietkau 	}
8507bc04215SFelix Fietkau }
851e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params);
8527bc04215SFelix Fietkau 
mt76x02_dfs_init_detector(struct mt76x02_dev * dev)853e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
8547bc04215SFelix Fietkau {
855e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
8567bc04215SFelix Fietkau 
857b7384e4eSLorenzo Bianconi 	INIT_LIST_HEAD(&dfs_pd->sequences);
858b7384e4eSLorenzo Bianconi 	INIT_LIST_HEAD(&dfs_pd->seq_pool);
859d8b8890dSLorenzo Bianconi 	dev->mt76.region = NL80211_DFS_UNSET;
8601fc9bc9aSLorenzo Bianconi 	dfs_pd->last_sw_check = jiffies;
8615ee3e780SAllen Pais 	tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet);
8627bc04215SFelix Fietkau }
8637bc04215SFelix Fietkau 
864e6cb3291SLorenzo Bianconi static void
mt76x02_dfs_set_domain(struct mt76x02_dev * dev,enum nl80211_dfs_regions region)865e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
8662070f3ccSLorenzo Bianconi 		       enum nl80211_dfs_regions region)
8672070f3ccSLorenzo Bianconi {
868e40803f2SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
8692070f3ccSLorenzo Bianconi 
87035c57281SLorenzo Bianconi 	mutex_lock(&dev->mt76.mutex);
871d8b8890dSLorenzo Bianconi 	if (dev->mt76.region != region) {
8722070f3ccSLorenzo Bianconi 		tasklet_disable(&dfs_pd->dfs_tasklet);
873f82ce8d9SLorenzo Bianconi 
874643749d4SFelix Fietkau 		dev->ed_monitor = dev->ed_monitor_enabled &&
875643749d4SFelix Fietkau 				  region == NL80211_DFS_ETSI;
876a78f1547SLorenzo Bianconi 		mt76x02_edcca_init(dev);
877f82ce8d9SLorenzo Bianconi 
878d8b8890dSLorenzo Bianconi 		dev->mt76.region = region;
879e6cb3291SLorenzo Bianconi 		mt76x02_dfs_init_params(dev);
8802070f3ccSLorenzo Bianconi 		tasklet_enable(&dfs_pd->dfs_tasklet);
8812070f3ccSLorenzo Bianconi 	}
88235c57281SLorenzo Bianconi 	mutex_unlock(&dev->mt76.mutex);
8832070f3ccSLorenzo Bianconi }
8842070f3ccSLorenzo Bianconi 
mt76x02_regd_notifier(struct wiphy * wiphy,struct regulatory_request * request)885e6cb3291SLorenzo Bianconi void mt76x02_regd_notifier(struct wiphy *wiphy,
886e6cb3291SLorenzo Bianconi 			   struct regulatory_request *request)
887e6cb3291SLorenzo Bianconi {
888e6cb3291SLorenzo Bianconi 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
889e6cb3291SLorenzo Bianconi 	struct mt76x02_dev *dev = hw->priv;
890e6cb3291SLorenzo Bianconi 
891e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_domain(dev, request->dfs_region);
892e6cb3291SLorenzo Bianconi }
893