1*e6cb3291SLorenzo Bianconi /* 2*e6cb3291SLorenzo Bianconi * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 3*e6cb3291SLorenzo Bianconi * 4*e6cb3291SLorenzo Bianconi * Permission to use, copy, modify, and/or distribute this software for any 5*e6cb3291SLorenzo Bianconi * purpose with or without fee is hereby granted, provided that the above 6*e6cb3291SLorenzo Bianconi * copyright notice and this permission notice appear in all copies. 7*e6cb3291SLorenzo Bianconi * 8*e6cb3291SLorenzo Bianconi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9*e6cb3291SLorenzo Bianconi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10*e6cb3291SLorenzo Bianconi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11*e6cb3291SLorenzo Bianconi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12*e6cb3291SLorenzo Bianconi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13*e6cb3291SLorenzo Bianconi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14*e6cb3291SLorenzo Bianconi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15*e6cb3291SLorenzo Bianconi */ 16*e6cb3291SLorenzo Bianconi 17*e6cb3291SLorenzo Bianconi #include "mt76x02.h" 18*e6cb3291SLorenzo Bianconi 19*e6cb3291SLorenzo Bianconi #define RADAR_SPEC(m, len, el, eh, wl, wh, \ 20*e6cb3291SLorenzo Bianconi w_tolerance, tl, th, t_tolerance, \ 21*e6cb3291SLorenzo Bianconi bl, bh, event_exp, power_jmp) \ 22*e6cb3291SLorenzo Bianconi { \ 23*e6cb3291SLorenzo Bianconi .mode = m, \ 24*e6cb3291SLorenzo Bianconi .avg_len = len, \ 25*e6cb3291SLorenzo Bianconi .e_low = el, \ 26*e6cb3291SLorenzo Bianconi .e_high = eh, \ 27*e6cb3291SLorenzo Bianconi .w_low = wl, \ 28*e6cb3291SLorenzo Bianconi .w_high = wh, \ 29*e6cb3291SLorenzo Bianconi .w_margin = w_tolerance, \ 30*e6cb3291SLorenzo Bianconi .t_low = tl, \ 31*e6cb3291SLorenzo Bianconi .t_high = th, \ 32*e6cb3291SLorenzo Bianconi .t_margin = t_tolerance, \ 33*e6cb3291SLorenzo Bianconi .b_low = bl, \ 34*e6cb3291SLorenzo Bianconi .b_high = bh, \ 35*e6cb3291SLorenzo Bianconi .event_expiration = event_exp, \ 36*e6cb3291SLorenzo Bianconi .pwr_jmp = power_jmp \ 37*e6cb3291SLorenzo Bianconi } 38*e6cb3291SLorenzo Bianconi 39*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs etsi_radar_specs[] = { 40*e6cb3291SLorenzo Bianconi /* 20MHz */ 41*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 42*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 43*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 44*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 45*e6cb3291SLorenzo Bianconi RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 46*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19dd), 47*e6cb3291SLorenzo Bianconi RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 48*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x2191c0, 0x15cc), 49*e6cb3291SLorenzo Bianconi /* 40MHz */ 50*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 51*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 52*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 53*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 54*e6cb3291SLorenzo Bianconi RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 55*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19dd), 56*e6cb3291SLorenzo Bianconi RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 57*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x2191c0, 0x15cc), 58*e6cb3291SLorenzo Bianconi /* 80MHz */ 59*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 60*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 61*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 62*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19cc), 63*e6cb3291SLorenzo Bianconi RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 64*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x155cc0, 0x19dd), 65*e6cb3291SLorenzo Bianconi RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 66*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x2191c0, 0x15cc) 67*e6cb3291SLorenzo Bianconi }; 68*e6cb3291SLorenzo Bianconi 69*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs fcc_radar_specs[] = { 70*e6cb3291SLorenzo Bianconi /* 20MHz */ 71*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, 72*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x13dc), 73*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 74*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x19dd), 75*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 76*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x12cc), 77*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 78*e6cb3291SLorenzo Bianconi 0x3938700, 0x57bcf00, 0x1289), 79*e6cb3291SLorenzo Bianconi /* 40MHz */ 80*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, 81*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x13dc), 82*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 83*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x19dd), 84*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 85*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x12cc), 86*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 87*e6cb3291SLorenzo Bianconi 0x3938700, 0x57bcf00, 0x1289), 88*e6cb3291SLorenzo Bianconi /* 80MHz */ 89*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0, 90*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x16cc), 91*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 92*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x19dd), 93*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 94*e6cb3291SLorenzo Bianconi 0x7fffffff, 0xfe808, 0x12cc), 95*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 96*e6cb3291SLorenzo Bianconi 0x3938700, 0x57bcf00, 0x1289) 97*e6cb3291SLorenzo Bianconi }; 98*e6cb3291SLorenzo Bianconi 99*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w56_radar_specs[] = { 100*e6cb3291SLorenzo Bianconi /* 20MHz */ 101*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, 102*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x13dc), 103*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 104*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x19dd), 105*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 106*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x12cc), 107*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 108*e6cb3291SLorenzo Bianconi 0x3938700, 0X57bcf00, 0x1289), 109*e6cb3291SLorenzo Bianconi /* 40MHz */ 110*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, 111*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x13dc), 112*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 113*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x19dd), 114*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 115*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x12cc), 116*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 117*e6cb3291SLorenzo Bianconi 0x3938700, 0X57bcf00, 0x1289), 118*e6cb3291SLorenzo Bianconi /* 80MHz */ 119*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0, 120*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 121*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 122*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x19dd), 123*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 124*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x12cc), 125*e6cb3291SLorenzo Bianconi RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 126*e6cb3291SLorenzo Bianconi 0x3938700, 0X57bcf00, 0x1289) 127*e6cb3291SLorenzo Bianconi }; 128*e6cb3291SLorenzo Bianconi 129*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w53_radar_specs[] = { 130*e6cb3291SLorenzo Bianconi /* 20MHz */ 131*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 132*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 133*e6cb3291SLorenzo Bianconi { 0 }, 134*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 135*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 136*e6cb3291SLorenzo Bianconi { 0 }, 137*e6cb3291SLorenzo Bianconi /* 40MHz */ 138*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 139*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 140*e6cb3291SLorenzo Bianconi { 0 }, 141*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 142*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 143*e6cb3291SLorenzo Bianconi { 0 }, 144*e6cb3291SLorenzo Bianconi /* 80MHz */ 145*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 146*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 147*e6cb3291SLorenzo Bianconi { 0 }, 148*e6cb3291SLorenzo Bianconi RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 149*e6cb3291SLorenzo Bianconi 0x7fffffff, 0x14c080, 0x16cc), 150*e6cb3291SLorenzo Bianconi { 0 } 151*e6cb3291SLorenzo Bianconi }; 152*e6cb3291SLorenzo Bianconi 153*e6cb3291SLorenzo Bianconi static void 154*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable) 155*e6cb3291SLorenzo Bianconi { 156*e6cb3291SLorenzo Bianconi u32 data; 157*e6cb3291SLorenzo Bianconi 158*e6cb3291SLorenzo Bianconi data = (1 << 1) | enable; 159*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 36), data); 160*e6cb3291SLorenzo Bianconi } 161*e6cb3291SLorenzo Bianconi 162*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev, 163*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence *seq) 164*e6cb3291SLorenzo Bianconi { 165*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 166*e6cb3291SLorenzo Bianconi 167*e6cb3291SLorenzo Bianconi list_add(&seq->head, &dfs_pd->seq_pool); 168*e6cb3291SLorenzo Bianconi 169*e6cb3291SLorenzo Bianconi dfs_pd->seq_stats.seq_pool_len++; 170*e6cb3291SLorenzo Bianconi dfs_pd->seq_stats.seq_len--; 171*e6cb3291SLorenzo Bianconi } 172*e6cb3291SLorenzo Bianconi 173*e6cb3291SLorenzo Bianconi static struct mt76x02_dfs_sequence * 174*e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev) 175*e6cb3291SLorenzo Bianconi { 176*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 177*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence *seq; 178*e6cb3291SLorenzo Bianconi 179*e6cb3291SLorenzo Bianconi if (list_empty(&dfs_pd->seq_pool)) { 180*e6cb3291SLorenzo Bianconi seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); 181*e6cb3291SLorenzo Bianconi } else { 182*e6cb3291SLorenzo Bianconi seq = list_first_entry(&dfs_pd->seq_pool, 183*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence, 184*e6cb3291SLorenzo Bianconi head); 185*e6cb3291SLorenzo Bianconi list_del(&seq->head); 186*e6cb3291SLorenzo Bianconi dfs_pd->seq_stats.seq_pool_len--; 187*e6cb3291SLorenzo Bianconi } 188*e6cb3291SLorenzo Bianconi if (seq) 189*e6cb3291SLorenzo Bianconi dfs_pd->seq_stats.seq_len++; 190*e6cb3291SLorenzo Bianconi 191*e6cb3291SLorenzo Bianconi return seq; 192*e6cb3291SLorenzo Bianconi } 193*e6cb3291SLorenzo Bianconi 194*e6cb3291SLorenzo Bianconi static int mt76x02_dfs_get_multiple(int val, int frac, int margin) 195*e6cb3291SLorenzo Bianconi { 196*e6cb3291SLorenzo Bianconi int remainder, factor; 197*e6cb3291SLorenzo Bianconi 198*e6cb3291SLorenzo Bianconi if (!frac) 199*e6cb3291SLorenzo Bianconi return 0; 200*e6cb3291SLorenzo Bianconi 201*e6cb3291SLorenzo Bianconi if (abs(val - frac) <= margin) 202*e6cb3291SLorenzo Bianconi return 1; 203*e6cb3291SLorenzo Bianconi 204*e6cb3291SLorenzo Bianconi factor = val / frac; 205*e6cb3291SLorenzo Bianconi remainder = val % frac; 206*e6cb3291SLorenzo Bianconi 207*e6cb3291SLorenzo Bianconi if (remainder > margin) { 208*e6cb3291SLorenzo Bianconi if ((frac - remainder) <= margin) 209*e6cb3291SLorenzo Bianconi factor++; 210*e6cb3291SLorenzo Bianconi else 211*e6cb3291SLorenzo Bianconi factor = 0; 212*e6cb3291SLorenzo Bianconi } 213*e6cb3291SLorenzo Bianconi return factor; 214*e6cb3291SLorenzo Bianconi } 215*e6cb3291SLorenzo Bianconi 216*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev) 217*e6cb3291SLorenzo Bianconi { 218*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 219*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence *seq, *tmp_seq; 220*e6cb3291SLorenzo Bianconi int i; 221*e6cb3291SLorenzo Bianconi 222*e6cb3291SLorenzo Bianconi /* reset hw detector */ 223*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 1), 0xf); 224*e6cb3291SLorenzo Bianconi 225*e6cb3291SLorenzo Bianconi /* reset sw detector */ 226*e6cb3291SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { 227*e6cb3291SLorenzo Bianconi dfs_pd->event_rb[i].h_rb = 0; 228*e6cb3291SLorenzo Bianconi dfs_pd->event_rb[i].t_rb = 0; 229*e6cb3291SLorenzo Bianconi } 230*e6cb3291SLorenzo Bianconi 231*e6cb3291SLorenzo Bianconi list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { 232*e6cb3291SLorenzo Bianconi list_del_init(&seq->head); 233*e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_put(dev, seq); 234*e6cb3291SLorenzo Bianconi } 235*e6cb3291SLorenzo Bianconi } 236*e6cb3291SLorenzo Bianconi 237*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev) 238*e6cb3291SLorenzo Bianconi { 239*e6cb3291SLorenzo Bianconi bool ret = false; 240*e6cb3291SLorenzo Bianconi u32 current_ts, delta_ts; 241*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 242*e6cb3291SLorenzo Bianconi 243*e6cb3291SLorenzo Bianconi current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); 244*e6cb3291SLorenzo Bianconi delta_ts = current_ts - dfs_pd->chirp_pulse_ts; 245*e6cb3291SLorenzo Bianconi dfs_pd->chirp_pulse_ts = current_ts; 246*e6cb3291SLorenzo Bianconi 247*e6cb3291SLorenzo Bianconi /* 12 sec */ 248*e6cb3291SLorenzo Bianconi if (delta_ts <= (12 * (1 << 20))) { 249*e6cb3291SLorenzo Bianconi if (++dfs_pd->chirp_pulse_cnt > 8) 250*e6cb3291SLorenzo Bianconi ret = true; 251*e6cb3291SLorenzo Bianconi } else { 252*e6cb3291SLorenzo Bianconi dfs_pd->chirp_pulse_cnt = 1; 253*e6cb3291SLorenzo Bianconi } 254*e6cb3291SLorenzo Bianconi 255*e6cb3291SLorenzo Bianconi return ret; 256*e6cb3291SLorenzo Bianconi } 257*e6cb3291SLorenzo Bianconi 258*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev, 259*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_hw_pulse *pulse) 260*e6cb3291SLorenzo Bianconi { 261*e6cb3291SLorenzo Bianconi u32 data; 262*e6cb3291SLorenzo Bianconi 263*e6cb3291SLorenzo Bianconi /* select channel */ 264*e6cb3291SLorenzo Bianconi data = (MT_DFS_CH_EN << 16) | pulse->engine; 265*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), data); 266*e6cb3291SLorenzo Bianconi 267*e6cb3291SLorenzo Bianconi /* reported period */ 268*e6cb3291SLorenzo Bianconi pulse->period = mt76_rr(dev, MT_BBP(DFS, 19)); 269*e6cb3291SLorenzo Bianconi 270*e6cb3291SLorenzo Bianconi /* reported width */ 271*e6cb3291SLorenzo Bianconi pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20)); 272*e6cb3291SLorenzo Bianconi pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23)); 273*e6cb3291SLorenzo Bianconi 274*e6cb3291SLorenzo Bianconi /* reported burst number */ 275*e6cb3291SLorenzo Bianconi pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); 276*e6cb3291SLorenzo Bianconi } 277*e6cb3291SLorenzo Bianconi 278*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev, 279*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_hw_pulse *pulse) 280*e6cb3291SLorenzo Bianconi { 281*e6cb3291SLorenzo Bianconi bool ret = false; 282*e6cb3291SLorenzo Bianconi 283*e6cb3291SLorenzo Bianconi if (!pulse->period || !pulse->w1) 284*e6cb3291SLorenzo Bianconi return false; 285*e6cb3291SLorenzo Bianconi 286*e6cb3291SLorenzo Bianconi switch (dev->dfs_pd.region) { 287*e6cb3291SLorenzo Bianconi case NL80211_DFS_FCC: 288*e6cb3291SLorenzo Bianconi if (pulse->engine > 3) 289*e6cb3291SLorenzo Bianconi break; 290*e6cb3291SLorenzo Bianconi 291*e6cb3291SLorenzo Bianconi if (pulse->engine == 3) { 292*e6cb3291SLorenzo Bianconi ret = mt76x02_dfs_check_chirp(dev); 293*e6cb3291SLorenzo Bianconi break; 294*e6cb3291SLorenzo Bianconi } 295*e6cb3291SLorenzo Bianconi 296*e6cb3291SLorenzo Bianconi /* check short pulse*/ 297*e6cb3291SLorenzo Bianconi if (pulse->w1 < 120) 298*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 2900 && 299*e6cb3291SLorenzo Bianconi (pulse->period <= 4700 || 300*e6cb3291SLorenzo Bianconi pulse->period >= 6400) && 301*e6cb3291SLorenzo Bianconi (pulse->period <= 6800 || 302*e6cb3291SLorenzo Bianconi pulse->period >= 10200) && 303*e6cb3291SLorenzo Bianconi pulse->period <= 61600); 304*e6cb3291SLorenzo Bianconi else if (pulse->w1 < 130) /* 120 - 130 */ 305*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 2900 && 306*e6cb3291SLorenzo Bianconi pulse->period <= 61600); 307*e6cb3291SLorenzo Bianconi else 308*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 3500 && 309*e6cb3291SLorenzo Bianconi pulse->period <= 10100); 310*e6cb3291SLorenzo Bianconi break; 311*e6cb3291SLorenzo Bianconi case NL80211_DFS_ETSI: 312*e6cb3291SLorenzo Bianconi if (pulse->engine >= 3) 313*e6cb3291SLorenzo Bianconi break; 314*e6cb3291SLorenzo Bianconi 315*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 4900 && 316*e6cb3291SLorenzo Bianconi (pulse->period <= 10200 || 317*e6cb3291SLorenzo Bianconi pulse->period >= 12400) && 318*e6cb3291SLorenzo Bianconi pulse->period <= 100100); 319*e6cb3291SLorenzo Bianconi break; 320*e6cb3291SLorenzo Bianconi case NL80211_DFS_JP: 321*e6cb3291SLorenzo Bianconi if (dev->mt76.chandef.chan->center_freq >= 5250 && 322*e6cb3291SLorenzo Bianconi dev->mt76.chandef.chan->center_freq <= 5350) { 323*e6cb3291SLorenzo Bianconi /* JPW53 */ 324*e6cb3291SLorenzo Bianconi if (pulse->w1 <= 130) 325*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 28360 && 326*e6cb3291SLorenzo Bianconi (pulse->period <= 28700 || 327*e6cb3291SLorenzo Bianconi pulse->period >= 76900) && 328*e6cb3291SLorenzo Bianconi pulse->period <= 76940); 329*e6cb3291SLorenzo Bianconi break; 330*e6cb3291SLorenzo Bianconi } 331*e6cb3291SLorenzo Bianconi 332*e6cb3291SLorenzo Bianconi if (pulse->engine > 3) 333*e6cb3291SLorenzo Bianconi break; 334*e6cb3291SLorenzo Bianconi 335*e6cb3291SLorenzo Bianconi if (pulse->engine == 3) { 336*e6cb3291SLorenzo Bianconi ret = mt76x02_dfs_check_chirp(dev); 337*e6cb3291SLorenzo Bianconi break; 338*e6cb3291SLorenzo Bianconi } 339*e6cb3291SLorenzo Bianconi 340*e6cb3291SLorenzo Bianconi /* check short pulse*/ 341*e6cb3291SLorenzo Bianconi if (pulse->w1 < 120) 342*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 2900 && 343*e6cb3291SLorenzo Bianconi (pulse->period <= 4700 || 344*e6cb3291SLorenzo Bianconi pulse->period >= 6400) && 345*e6cb3291SLorenzo Bianconi (pulse->period <= 6800 || 346*e6cb3291SLorenzo Bianconi pulse->period >= 27560) && 347*e6cb3291SLorenzo Bianconi (pulse->period <= 27960 || 348*e6cb3291SLorenzo Bianconi pulse->period >= 28360) && 349*e6cb3291SLorenzo Bianconi (pulse->period <= 28700 || 350*e6cb3291SLorenzo Bianconi pulse->period >= 79900) && 351*e6cb3291SLorenzo Bianconi pulse->period <= 80100); 352*e6cb3291SLorenzo Bianconi else if (pulse->w1 < 130) /* 120 - 130 */ 353*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 2900 && 354*e6cb3291SLorenzo Bianconi (pulse->period <= 10100 || 355*e6cb3291SLorenzo Bianconi pulse->period >= 27560) && 356*e6cb3291SLorenzo Bianconi (pulse->period <= 27960 || 357*e6cb3291SLorenzo Bianconi pulse->period >= 28360) && 358*e6cb3291SLorenzo Bianconi (pulse->period <= 28700 || 359*e6cb3291SLorenzo Bianconi pulse->period >= 79900) && 360*e6cb3291SLorenzo Bianconi pulse->period <= 80100); 361*e6cb3291SLorenzo Bianconi else 362*e6cb3291SLorenzo Bianconi ret = (pulse->period >= 3900 && 363*e6cb3291SLorenzo Bianconi pulse->period <= 10100); 364*e6cb3291SLorenzo Bianconi break; 365*e6cb3291SLorenzo Bianconi case NL80211_DFS_UNSET: 366*e6cb3291SLorenzo Bianconi default: 367*e6cb3291SLorenzo Bianconi return false; 368*e6cb3291SLorenzo Bianconi } 369*e6cb3291SLorenzo Bianconi 370*e6cb3291SLorenzo Bianconi return ret; 371*e6cb3291SLorenzo Bianconi } 372*e6cb3291SLorenzo Bianconi 373*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev, 374*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event) 375*e6cb3291SLorenzo Bianconi { 376*e6cb3291SLorenzo Bianconi u32 data; 377*e6cb3291SLorenzo Bianconi 378*e6cb3291SLorenzo Bianconi /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2) 379*e6cb3291SLorenzo Bianconi * 2nd: DFS_R37[21:0]: pulse time 380*e6cb3291SLorenzo Bianconi * 3rd: DFS_R37[11:0]: pulse width 381*e6cb3291SLorenzo Bianconi * 3rd: DFS_R37[25:16]: phase 382*e6cb3291SLorenzo Bianconi * 4th: DFS_R37[12:0]: current pwr 383*e6cb3291SLorenzo Bianconi * 4th: DFS_R37[21:16]: pwr stable counter 384*e6cb3291SLorenzo Bianconi * 385*e6cb3291SLorenzo Bianconi * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected 386*e6cb3291SLorenzo Bianconi */ 387*e6cb3291SLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37)); 388*e6cb3291SLorenzo Bianconi if (!MT_DFS_CHECK_EVENT(data)) 389*e6cb3291SLorenzo Bianconi return false; 390*e6cb3291SLorenzo Bianconi 391*e6cb3291SLorenzo Bianconi event->engine = MT_DFS_EVENT_ENGINE(data); 392*e6cb3291SLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37)); 393*e6cb3291SLorenzo Bianconi event->ts = MT_DFS_EVENT_TIMESTAMP(data); 394*e6cb3291SLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37)); 395*e6cb3291SLorenzo Bianconi event->width = MT_DFS_EVENT_WIDTH(data); 396*e6cb3291SLorenzo Bianconi 397*e6cb3291SLorenzo Bianconi return true; 398*e6cb3291SLorenzo Bianconi } 399*e6cb3291SLorenzo Bianconi 400*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev, 401*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event) 402*e6cb3291SLorenzo Bianconi { 403*e6cb3291SLorenzo Bianconi if (event->engine == 2) { 404*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 405*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; 406*e6cb3291SLorenzo Bianconi u16 last_event_idx; 407*e6cb3291SLorenzo Bianconi u32 delta_ts; 408*e6cb3291SLorenzo Bianconi 409*e6cb3291SLorenzo Bianconi last_event_idx = mt76_decr(event_buff->t_rb, 410*e6cb3291SLorenzo Bianconi MT_DFS_EVENT_BUFLEN); 411*e6cb3291SLorenzo Bianconi delta_ts = event->ts - event_buff->data[last_event_idx].ts; 412*e6cb3291SLorenzo Bianconi if (delta_ts < MT_DFS_EVENT_TIME_MARGIN && 413*e6cb3291SLorenzo Bianconi event_buff->data[last_event_idx].width >= 200) 414*e6cb3291SLorenzo Bianconi return false; 415*e6cb3291SLorenzo Bianconi } 416*e6cb3291SLorenzo Bianconi return true; 417*e6cb3291SLorenzo Bianconi } 418*e6cb3291SLorenzo Bianconi 419*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev, 420*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event) 421*e6cb3291SLorenzo Bianconi { 422*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 423*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff; 424*e6cb3291SLorenzo Bianconi 425*e6cb3291SLorenzo Bianconi /* add radar event to ring buffer */ 426*e6cb3291SLorenzo Bianconi event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] 427*e6cb3291SLorenzo Bianconi : &dfs_pd->event_rb[0]; 428*e6cb3291SLorenzo Bianconi event_buff->data[event_buff->t_rb] = *event; 429*e6cb3291SLorenzo Bianconi event_buff->data[event_buff->t_rb].fetch_ts = jiffies; 430*e6cb3291SLorenzo Bianconi 431*e6cb3291SLorenzo Bianconi event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); 432*e6cb3291SLorenzo Bianconi if (event_buff->t_rb == event_buff->h_rb) 433*e6cb3291SLorenzo Bianconi event_buff->h_rb = mt76_incr(event_buff->h_rb, 434*e6cb3291SLorenzo Bianconi MT_DFS_EVENT_BUFLEN); 435*e6cb3291SLorenzo Bianconi } 436*e6cb3291SLorenzo Bianconi 437*e6cb3291SLorenzo Bianconi static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev, 438*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event, 439*e6cb3291SLorenzo Bianconi u16 cur_len) 440*e6cb3291SLorenzo Bianconi { 441*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 442*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sw_detector_params *sw_params; 443*e6cb3291SLorenzo Bianconi u32 width_delta, with_sum, factor, cur_pri; 444*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence seq, *seq_p; 445*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_rb; 446*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *cur_event; 447*e6cb3291SLorenzo Bianconi int i, j, end, pri; 448*e6cb3291SLorenzo Bianconi 449*e6cb3291SLorenzo Bianconi event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] 450*e6cb3291SLorenzo Bianconi : &dfs_pd->event_rb[0]; 451*e6cb3291SLorenzo Bianconi 452*e6cb3291SLorenzo Bianconi i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN); 453*e6cb3291SLorenzo Bianconi end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN); 454*e6cb3291SLorenzo Bianconi 455*e6cb3291SLorenzo Bianconi while (i != end) { 456*e6cb3291SLorenzo Bianconi cur_event = &event_rb->data[i]; 457*e6cb3291SLorenzo Bianconi with_sum = event->width + cur_event->width; 458*e6cb3291SLorenzo Bianconi 459*e6cb3291SLorenzo Bianconi sw_params = &dfs_pd->sw_dpd_params; 460*e6cb3291SLorenzo Bianconi switch (dev->dfs_pd.region) { 461*e6cb3291SLorenzo Bianconi case NL80211_DFS_FCC: 462*e6cb3291SLorenzo Bianconi case NL80211_DFS_JP: 463*e6cb3291SLorenzo Bianconi if (with_sum < 600) 464*e6cb3291SLorenzo Bianconi width_delta = 8; 465*e6cb3291SLorenzo Bianconi else 466*e6cb3291SLorenzo Bianconi width_delta = with_sum >> 3; 467*e6cb3291SLorenzo Bianconi break; 468*e6cb3291SLorenzo Bianconi case NL80211_DFS_ETSI: 469*e6cb3291SLorenzo Bianconi if (event->engine == 2) 470*e6cb3291SLorenzo Bianconi width_delta = with_sum >> 6; 471*e6cb3291SLorenzo Bianconi else if (with_sum < 620) 472*e6cb3291SLorenzo Bianconi width_delta = 24; 473*e6cb3291SLorenzo Bianconi else 474*e6cb3291SLorenzo Bianconi width_delta = 8; 475*e6cb3291SLorenzo Bianconi break; 476*e6cb3291SLorenzo Bianconi case NL80211_DFS_UNSET: 477*e6cb3291SLorenzo Bianconi default: 478*e6cb3291SLorenzo Bianconi return -EINVAL; 479*e6cb3291SLorenzo Bianconi } 480*e6cb3291SLorenzo Bianconi 481*e6cb3291SLorenzo Bianconi pri = event->ts - cur_event->ts; 482*e6cb3291SLorenzo Bianconi if (abs(event->width - cur_event->width) > width_delta || 483*e6cb3291SLorenzo Bianconi pri < sw_params->min_pri) 484*e6cb3291SLorenzo Bianconi goto next; 485*e6cb3291SLorenzo Bianconi 486*e6cb3291SLorenzo Bianconi if (pri > sw_params->max_pri) 487*e6cb3291SLorenzo Bianconi break; 488*e6cb3291SLorenzo Bianconi 489*e6cb3291SLorenzo Bianconi seq.pri = event->ts - cur_event->ts; 490*e6cb3291SLorenzo Bianconi seq.first_ts = cur_event->ts; 491*e6cb3291SLorenzo Bianconi seq.last_ts = event->ts; 492*e6cb3291SLorenzo Bianconi seq.engine = event->engine; 493*e6cb3291SLorenzo Bianconi seq.count = 2; 494*e6cb3291SLorenzo Bianconi 495*e6cb3291SLorenzo Bianconi j = mt76_decr(i, MT_DFS_EVENT_BUFLEN); 496*e6cb3291SLorenzo Bianconi while (j != end) { 497*e6cb3291SLorenzo Bianconi cur_event = &event_rb->data[j]; 498*e6cb3291SLorenzo Bianconi cur_pri = event->ts - cur_event->ts; 499*e6cb3291SLorenzo Bianconi factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri, 500*e6cb3291SLorenzo Bianconi sw_params->pri_margin); 501*e6cb3291SLorenzo Bianconi if (factor > 0) { 502*e6cb3291SLorenzo Bianconi seq.first_ts = cur_event->ts; 503*e6cb3291SLorenzo Bianconi seq.count++; 504*e6cb3291SLorenzo Bianconi } 505*e6cb3291SLorenzo Bianconi 506*e6cb3291SLorenzo Bianconi j = mt76_decr(j, MT_DFS_EVENT_BUFLEN); 507*e6cb3291SLorenzo Bianconi } 508*e6cb3291SLorenzo Bianconi if (seq.count <= cur_len) 509*e6cb3291SLorenzo Bianconi goto next; 510*e6cb3291SLorenzo Bianconi 511*e6cb3291SLorenzo Bianconi seq_p = mt76x02_dfs_seq_pool_get(dev); 512*e6cb3291SLorenzo Bianconi if (!seq_p) 513*e6cb3291SLorenzo Bianconi return -ENOMEM; 514*e6cb3291SLorenzo Bianconi 515*e6cb3291SLorenzo Bianconi *seq_p = seq; 516*e6cb3291SLorenzo Bianconi INIT_LIST_HEAD(&seq_p->head); 517*e6cb3291SLorenzo Bianconi list_add(&seq_p->head, &dfs_pd->sequences); 518*e6cb3291SLorenzo Bianconi next: 519*e6cb3291SLorenzo Bianconi i = mt76_decr(i, MT_DFS_EVENT_BUFLEN); 520*e6cb3291SLorenzo Bianconi } 521*e6cb3291SLorenzo Bianconi return 0; 522*e6cb3291SLorenzo Bianconi } 523*e6cb3291SLorenzo Bianconi 524*e6cb3291SLorenzo Bianconi static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev, 525*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event) 526*e6cb3291SLorenzo Bianconi { 527*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 528*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sw_detector_params *sw_params; 529*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence *seq, *tmp_seq; 530*e6cb3291SLorenzo Bianconi u16 max_seq_len = 0; 531*e6cb3291SLorenzo Bianconi u32 factor, pri; 532*e6cb3291SLorenzo Bianconi 533*e6cb3291SLorenzo Bianconi sw_params = &dfs_pd->sw_dpd_params; 534*e6cb3291SLorenzo Bianconi list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { 535*e6cb3291SLorenzo Bianconi if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) { 536*e6cb3291SLorenzo Bianconi list_del_init(&seq->head); 537*e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_put(dev, seq); 538*e6cb3291SLorenzo Bianconi continue; 539*e6cb3291SLorenzo Bianconi } 540*e6cb3291SLorenzo Bianconi 541*e6cb3291SLorenzo Bianconi if (event->engine != seq->engine) 542*e6cb3291SLorenzo Bianconi continue; 543*e6cb3291SLorenzo Bianconi 544*e6cb3291SLorenzo Bianconi pri = event->ts - seq->last_ts; 545*e6cb3291SLorenzo Bianconi factor = mt76x02_dfs_get_multiple(pri, seq->pri, 546*e6cb3291SLorenzo Bianconi sw_params->pri_margin); 547*e6cb3291SLorenzo Bianconi if (factor > 0) { 548*e6cb3291SLorenzo Bianconi seq->last_ts = event->ts; 549*e6cb3291SLorenzo Bianconi seq->count++; 550*e6cb3291SLorenzo Bianconi max_seq_len = max_t(u16, max_seq_len, seq->count); 551*e6cb3291SLorenzo Bianconi } 552*e6cb3291SLorenzo Bianconi } 553*e6cb3291SLorenzo Bianconi return max_seq_len; 554*e6cb3291SLorenzo Bianconi } 555*e6cb3291SLorenzo Bianconi 556*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev) 557*e6cb3291SLorenzo Bianconi { 558*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 559*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_sequence *seq; 560*e6cb3291SLorenzo Bianconi 561*e6cb3291SLorenzo Bianconi if (list_empty(&dfs_pd->sequences)) 562*e6cb3291SLorenzo Bianconi return false; 563*e6cb3291SLorenzo Bianconi 564*e6cb3291SLorenzo Bianconi list_for_each_entry(seq, &dfs_pd->sequences, head) { 565*e6cb3291SLorenzo Bianconi if (seq->count > MT_DFS_SEQUENCE_TH) { 566*e6cb3291SLorenzo Bianconi dfs_pd->stats[seq->engine].sw_pattern++; 567*e6cb3291SLorenzo Bianconi return true; 568*e6cb3291SLorenzo Bianconi } 569*e6cb3291SLorenzo Bianconi } 570*e6cb3291SLorenzo Bianconi return false; 571*e6cb3291SLorenzo Bianconi } 572*e6cb3291SLorenzo Bianconi 573*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_add_events(struct mt76x02_dev *dev) 574*e6cb3291SLorenzo Bianconi { 575*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 576*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event event; 577*e6cb3291SLorenzo Bianconi int i, seq_len; 578*e6cb3291SLorenzo Bianconi 579*e6cb3291SLorenzo Bianconi /* disable debug mode */ 580*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, false); 581*e6cb3291SLorenzo Bianconi for (i = 0; i < MT_DFS_EVENT_LOOP; i++) { 582*e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_fetch_event(dev, &event)) 583*e6cb3291SLorenzo Bianconi break; 584*e6cb3291SLorenzo Bianconi 585*e6cb3291SLorenzo Bianconi if (dfs_pd->last_event_ts > event.ts) 586*e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev); 587*e6cb3291SLorenzo Bianconi dfs_pd->last_event_ts = event.ts; 588*e6cb3291SLorenzo Bianconi 589*e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_check_event(dev, &event)) 590*e6cb3291SLorenzo Bianconi continue; 591*e6cb3291SLorenzo Bianconi 592*e6cb3291SLorenzo Bianconi seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event); 593*e6cb3291SLorenzo Bianconi mt76x02_dfs_create_sequence(dev, &event, seq_len); 594*e6cb3291SLorenzo Bianconi 595*e6cb3291SLorenzo Bianconi mt76x02_dfs_queue_event(dev, &event); 596*e6cb3291SLorenzo Bianconi } 597*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, true); 598*e6cb3291SLorenzo Bianconi } 599*e6cb3291SLorenzo Bianconi 600*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev) 601*e6cb3291SLorenzo Bianconi { 602*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 603*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff; 604*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_event *event; 605*e6cb3291SLorenzo Bianconi int i; 606*e6cb3291SLorenzo Bianconi 607*e6cb3291SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { 608*e6cb3291SLorenzo Bianconi event_buff = &dfs_pd->event_rb[i]; 609*e6cb3291SLorenzo Bianconi 610*e6cb3291SLorenzo Bianconi while (event_buff->h_rb != event_buff->t_rb) { 611*e6cb3291SLorenzo Bianconi event = &event_buff->data[event_buff->h_rb]; 612*e6cb3291SLorenzo Bianconi 613*e6cb3291SLorenzo Bianconi /* sorted list */ 614*e6cb3291SLorenzo Bianconi if (time_is_after_jiffies(event->fetch_ts + 615*e6cb3291SLorenzo Bianconi MT_DFS_EVENT_WINDOW)) 616*e6cb3291SLorenzo Bianconi break; 617*e6cb3291SLorenzo Bianconi event_buff->h_rb = mt76_incr(event_buff->h_rb, 618*e6cb3291SLorenzo Bianconi MT_DFS_EVENT_BUFLEN); 619*e6cb3291SLorenzo Bianconi } 620*e6cb3291SLorenzo Bianconi } 621*e6cb3291SLorenzo Bianconi } 622*e6cb3291SLorenzo Bianconi 623*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_tasklet(unsigned long arg) 624*e6cb3291SLorenzo Bianconi { 625*e6cb3291SLorenzo Bianconi struct mt76x02_dev *dev = (struct mt76x02_dev *)arg; 626*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 627*e6cb3291SLorenzo Bianconi u32 engine_mask; 628*e6cb3291SLorenzo Bianconi int i; 629*e6cb3291SLorenzo Bianconi 630*e6cb3291SLorenzo Bianconi if (test_bit(MT76_SCANNING, &dev->mt76.state)) 631*e6cb3291SLorenzo Bianconi goto out; 632*e6cb3291SLorenzo Bianconi 633*e6cb3291SLorenzo Bianconi if (time_is_before_jiffies(dfs_pd->last_sw_check + 634*e6cb3291SLorenzo Bianconi MT_DFS_SW_TIMEOUT)) { 635*e6cb3291SLorenzo Bianconi bool radar_detected; 636*e6cb3291SLorenzo Bianconi 637*e6cb3291SLorenzo Bianconi dfs_pd->last_sw_check = jiffies; 638*e6cb3291SLorenzo Bianconi 639*e6cb3291SLorenzo Bianconi mt76x02_dfs_add_events(dev); 640*e6cb3291SLorenzo Bianconi radar_detected = mt76x02_dfs_check_detection(dev); 641*e6cb3291SLorenzo Bianconi if (radar_detected) { 642*e6cb3291SLorenzo Bianconi /* sw detector rx radar pattern */ 643*e6cb3291SLorenzo Bianconi ieee80211_radar_detected(dev->mt76.hw); 644*e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev); 645*e6cb3291SLorenzo Bianconi 646*e6cb3291SLorenzo Bianconi return; 647*e6cb3291SLorenzo Bianconi } 648*e6cb3291SLorenzo Bianconi mt76x02_dfs_check_event_window(dev); 649*e6cb3291SLorenzo Bianconi } 650*e6cb3291SLorenzo Bianconi 651*e6cb3291SLorenzo Bianconi engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); 652*e6cb3291SLorenzo Bianconi if (!(engine_mask & 0xf)) 653*e6cb3291SLorenzo Bianconi goto out; 654*e6cb3291SLorenzo Bianconi 655*e6cb3291SLorenzo Bianconi for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { 656*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_hw_pulse pulse; 657*e6cb3291SLorenzo Bianconi 658*e6cb3291SLorenzo Bianconi if (!(engine_mask & (1 << i))) 659*e6cb3291SLorenzo Bianconi continue; 660*e6cb3291SLorenzo Bianconi 661*e6cb3291SLorenzo Bianconi pulse.engine = i; 662*e6cb3291SLorenzo Bianconi mt76x02_dfs_get_hw_pulse(dev, &pulse); 663*e6cb3291SLorenzo Bianconi 664*e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) { 665*e6cb3291SLorenzo Bianconi dfs_pd->stats[i].hw_pulse_discarded++; 666*e6cb3291SLorenzo Bianconi continue; 667*e6cb3291SLorenzo Bianconi } 668*e6cb3291SLorenzo Bianconi 669*e6cb3291SLorenzo Bianconi /* hw detector rx radar pattern */ 670*e6cb3291SLorenzo Bianconi dfs_pd->stats[i].hw_pattern++; 671*e6cb3291SLorenzo Bianconi ieee80211_radar_detected(dev->mt76.hw); 672*e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev); 673*e6cb3291SLorenzo Bianconi 674*e6cb3291SLorenzo Bianconi return; 675*e6cb3291SLorenzo Bianconi } 676*e6cb3291SLorenzo Bianconi 677*e6cb3291SLorenzo Bianconi /* reset hw detector */ 678*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 1), 0xf); 679*e6cb3291SLorenzo Bianconi 680*e6cb3291SLorenzo Bianconi out: 681*e6cb3291SLorenzo Bianconi mt76x02_irq_enable(dev, MT_INT_GPTIMER); 682*e6cb3291SLorenzo Bianconi } 683*e6cb3291SLorenzo Bianconi 684*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev) 685*e6cb3291SLorenzo Bianconi { 686*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 687*e6cb3291SLorenzo Bianconi 688*e6cb3291SLorenzo Bianconi switch (dev->dfs_pd.region) { 689*e6cb3291SLorenzo Bianconi case NL80211_DFS_FCC: 690*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI; 691*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI; 692*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; 693*e6cb3291SLorenzo Bianconi break; 694*e6cb3291SLorenzo Bianconi case NL80211_DFS_ETSI: 695*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI; 696*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI; 697*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2; 698*e6cb3291SLorenzo Bianconi break; 699*e6cb3291SLorenzo Bianconi case NL80211_DFS_JP: 700*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI; 701*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI; 702*e6cb3291SLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; 703*e6cb3291SLorenzo Bianconi break; 704*e6cb3291SLorenzo Bianconi case NL80211_DFS_UNSET: 705*e6cb3291SLorenzo Bianconi default: 706*e6cb3291SLorenzo Bianconi break; 707*e6cb3291SLorenzo Bianconi } 708*e6cb3291SLorenzo Bianconi } 709*e6cb3291SLorenzo Bianconi 710*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev) 711*e6cb3291SLorenzo Bianconi { 712*e6cb3291SLorenzo Bianconi const struct mt76x02_radar_specs *radar_specs; 713*e6cb3291SLorenzo Bianconi u8 i, shift; 714*e6cb3291SLorenzo Bianconi u32 data; 715*e6cb3291SLorenzo Bianconi 716*e6cb3291SLorenzo Bianconi switch (dev->mt76.chandef.width) { 717*e6cb3291SLorenzo Bianconi case NL80211_CHAN_WIDTH_40: 718*e6cb3291SLorenzo Bianconi shift = MT_DFS_NUM_ENGINES; 719*e6cb3291SLorenzo Bianconi break; 720*e6cb3291SLorenzo Bianconi case NL80211_CHAN_WIDTH_80: 721*e6cb3291SLorenzo Bianconi shift = 2 * MT_DFS_NUM_ENGINES; 722*e6cb3291SLorenzo Bianconi break; 723*e6cb3291SLorenzo Bianconi default: 724*e6cb3291SLorenzo Bianconi shift = 0; 725*e6cb3291SLorenzo Bianconi break; 726*e6cb3291SLorenzo Bianconi } 727*e6cb3291SLorenzo Bianconi 728*e6cb3291SLorenzo Bianconi switch (dev->dfs_pd.region) { 729*e6cb3291SLorenzo Bianconi case NL80211_DFS_FCC: 730*e6cb3291SLorenzo Bianconi radar_specs = &fcc_radar_specs[shift]; 731*e6cb3291SLorenzo Bianconi break; 732*e6cb3291SLorenzo Bianconi case NL80211_DFS_ETSI: 733*e6cb3291SLorenzo Bianconi radar_specs = &etsi_radar_specs[shift]; 734*e6cb3291SLorenzo Bianconi break; 735*e6cb3291SLorenzo Bianconi case NL80211_DFS_JP: 736*e6cb3291SLorenzo Bianconi if (dev->mt76.chandef.chan->center_freq >= 5250 && 737*e6cb3291SLorenzo Bianconi dev->mt76.chandef.chan->center_freq <= 5350) 738*e6cb3291SLorenzo Bianconi radar_specs = &jp_w53_radar_specs[shift]; 739*e6cb3291SLorenzo Bianconi else 740*e6cb3291SLorenzo Bianconi radar_specs = &jp_w56_radar_specs[shift]; 741*e6cb3291SLorenzo Bianconi break; 742*e6cb3291SLorenzo Bianconi case NL80211_DFS_UNSET: 743*e6cb3291SLorenzo Bianconi default: 744*e6cb3291SLorenzo Bianconi return; 745*e6cb3291SLorenzo Bianconi } 746*e6cb3291SLorenzo Bianconi 747*e6cb3291SLorenzo Bianconi data = (MT_DFS_VGA_MASK << 16) | 748*e6cb3291SLorenzo Bianconi (MT_DFS_PWR_GAIN_OFFSET << 12) | 749*e6cb3291SLorenzo Bianconi (MT_DFS_PWR_DOWN_TIME << 8) | 750*e6cb3291SLorenzo Bianconi (MT_DFS_SYM_ROUND << 4) | 751*e6cb3291SLorenzo Bianconi (MT_DFS_DELTA_DELAY & 0xf); 752*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 2), data); 753*e6cb3291SLorenzo Bianconi 754*e6cb3291SLorenzo Bianconi data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK; 755*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 3), data); 756*e6cb3291SLorenzo Bianconi 757*e6cb3291SLorenzo Bianconi for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { 758*e6cb3291SLorenzo Bianconi /* configure engine */ 759*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), i); 760*e6cb3291SLorenzo Bianconi 761*e6cb3291SLorenzo Bianconi /* detection mode + avg_len */ 762*e6cb3291SLorenzo Bianconi data = ((radar_specs[i].avg_len & 0x1ff) << 16) | 763*e6cb3291SLorenzo Bianconi (radar_specs[i].mode & 0xf); 764*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 4), data); 765*e6cb3291SLorenzo Bianconi 766*e6cb3291SLorenzo Bianconi /* dfs energy */ 767*e6cb3291SLorenzo Bianconi data = ((radar_specs[i].e_high & 0x0fff) << 16) | 768*e6cb3291SLorenzo Bianconi (radar_specs[i].e_low & 0x0fff); 769*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 5), data); 770*e6cb3291SLorenzo Bianconi 771*e6cb3291SLorenzo Bianconi /* dfs period */ 772*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low); 773*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high); 774*e6cb3291SLorenzo Bianconi 775*e6cb3291SLorenzo Bianconi /* dfs burst */ 776*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low); 777*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high); 778*e6cb3291SLorenzo Bianconi 779*e6cb3291SLorenzo Bianconi /* dfs width */ 780*e6cb3291SLorenzo Bianconi data = ((radar_specs[i].w_high & 0x0fff) << 16) | 781*e6cb3291SLorenzo Bianconi (radar_specs[i].w_low & 0x0fff); 782*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 14), data); 783*e6cb3291SLorenzo Bianconi 784*e6cb3291SLorenzo Bianconi /* dfs margins */ 785*e6cb3291SLorenzo Bianconi data = (radar_specs[i].w_margin << 16) | 786*e6cb3291SLorenzo Bianconi radar_specs[i].t_margin; 787*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 15), data); 788*e6cb3291SLorenzo Bianconi 789*e6cb3291SLorenzo Bianconi /* dfs event expiration */ 790*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration); 791*e6cb3291SLorenzo Bianconi 792*e6cb3291SLorenzo Bianconi /* dfs pwr adj */ 793*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp); 794*e6cb3291SLorenzo Bianconi } 795*e6cb3291SLorenzo Bianconi 796*e6cb3291SLorenzo Bianconi /* reset status */ 797*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 1), 0xf); 798*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 36), 0x3); 799*e6cb3291SLorenzo Bianconi 800*e6cb3291SLorenzo Bianconi /* enable detection*/ 801*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); 802*e6cb3291SLorenzo Bianconi mt76_wr(dev, 0x212c, 0x0c350001); 803*e6cb3291SLorenzo Bianconi } 804*e6cb3291SLorenzo Bianconi 805*e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_params(struct mt76x02_dev *dev) 806*e6cb3291SLorenzo Bianconi { 807*e6cb3291SLorenzo Bianconi struct cfg80211_chan_def *chandef = &dev->mt76.chandef; 808*e6cb3291SLorenzo Bianconi 809*e6cb3291SLorenzo Bianconi if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && 810*e6cb3291SLorenzo Bianconi dev->dfs_pd.region != NL80211_DFS_UNSET) { 811*e6cb3291SLorenzo Bianconi mt76x02_dfs_init_sw_detector(dev); 812*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_bbp_params(dev); 813*e6cb3291SLorenzo Bianconi /* enable debug mode */ 814*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, true); 815*e6cb3291SLorenzo Bianconi 816*e6cb3291SLorenzo Bianconi mt76x02_irq_enable(dev, MT_INT_GPTIMER); 817*e6cb3291SLorenzo Bianconi mt76_rmw_field(dev, MT_INT_TIMER_EN, 818*e6cb3291SLorenzo Bianconi MT_INT_TIMER_EN_GP_TIMER_EN, 1); 819*e6cb3291SLorenzo Bianconi } else { 820*e6cb3291SLorenzo Bianconi /* disable hw detector */ 821*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), 0); 822*e6cb3291SLorenzo Bianconi /* clear detector status */ 823*e6cb3291SLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 1), 0xf); 824*e6cb3291SLorenzo Bianconi mt76_wr(dev, 0x212c, 0); 825*e6cb3291SLorenzo Bianconi 826*e6cb3291SLorenzo Bianconi mt76x02_irq_disable(dev, MT_INT_GPTIMER); 827*e6cb3291SLorenzo Bianconi mt76_rmw_field(dev, MT_INT_TIMER_EN, 828*e6cb3291SLorenzo Bianconi MT_INT_TIMER_EN_GP_TIMER_EN, 0); 829*e6cb3291SLorenzo Bianconi } 830*e6cb3291SLorenzo Bianconi } 831*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params); 832*e6cb3291SLorenzo Bianconi 833*e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_detector(struct mt76x02_dev *dev) 834*e6cb3291SLorenzo Bianconi { 835*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 836*e6cb3291SLorenzo Bianconi 837*e6cb3291SLorenzo Bianconi INIT_LIST_HEAD(&dfs_pd->sequences); 838*e6cb3291SLorenzo Bianconi INIT_LIST_HEAD(&dfs_pd->seq_pool); 839*e6cb3291SLorenzo Bianconi dfs_pd->region = NL80211_DFS_UNSET; 840*e6cb3291SLorenzo Bianconi dfs_pd->last_sw_check = jiffies; 841*e6cb3291SLorenzo Bianconi tasklet_init(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet, 842*e6cb3291SLorenzo Bianconi (unsigned long)dev); 843*e6cb3291SLorenzo Bianconi } 844*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_detector); 845*e6cb3291SLorenzo Bianconi 846*e6cb3291SLorenzo Bianconi static void 847*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(struct mt76x02_dev *dev, 848*e6cb3291SLorenzo Bianconi enum nl80211_dfs_regions region) 849*e6cb3291SLorenzo Bianconi { 850*e6cb3291SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; 851*e6cb3291SLorenzo Bianconi 852*e6cb3291SLorenzo Bianconi if (dfs_pd->region != region) { 853*e6cb3291SLorenzo Bianconi tasklet_disable(&dfs_pd->dfs_tasklet); 854*e6cb3291SLorenzo Bianconi dfs_pd->region = region; 855*e6cb3291SLorenzo Bianconi mt76x02_dfs_init_params(dev); 856*e6cb3291SLorenzo Bianconi tasklet_enable(&dfs_pd->dfs_tasklet); 857*e6cb3291SLorenzo Bianconi } 858*e6cb3291SLorenzo Bianconi } 859*e6cb3291SLorenzo Bianconi 860*e6cb3291SLorenzo Bianconi void mt76x02_regd_notifier(struct wiphy *wiphy, 861*e6cb3291SLorenzo Bianconi struct regulatory_request *request) 862*e6cb3291SLorenzo Bianconi { 863*e6cb3291SLorenzo Bianconi struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 864*e6cb3291SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv; 865*e6cb3291SLorenzo Bianconi 866*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(dev, request->dfs_region); 867*e6cb3291SLorenzo Bianconi } 868*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_regd_notifier); 869