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