Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/wireless/mediatek/mt76/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 23 kB image not shown  

Quelle  mt76x02_dfs.c   Sprache: C

 
// SPDX-License-Identifier: ISC
/*
 * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
 */


#include "mt76x02.h"

#define RADAR_SPEC(m, len, el, eh, wl, wh,  \
     w_tolerance, tl, th, t_tolerance, \
     bl, bh, event_exp, power_jmp) \
{       \
 .mode = m,     \
 .avg_len = len,     \
 .e_low = el,     \
 .e_high = eh,     \
 .w_low = wl,     \
 .w_high = wh,     \
 .w_margin = w_tolerance,   \
 .t_low = tl,     \
 .t_high = th,     \
 .t_margin = t_tolerance,   \
 .b_low = bl,     \
 .b_high = bh,     \
 .event_expiration = event_exp,   \
 .pwr_jmp = power_jmp    \
}

static const struct mt76x02_radar_specs etsi_radar_specs[] = {
 /* 20MHz */
 RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
     0x7fffffff, 0x155cc0, 0x19dd),
 RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
     0x7fffffff, 0x2191c0, 0x15cc),
 /* 40MHz */
 RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
     0x7fffffff, 0x155cc0, 0x19dd),
 RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
     0x7fffffff, 0x2191c0, 0x15cc),
 /* 80MHz */
 RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
     0x7fffffff, 0x155cc0, 0x19cc),
 RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
     0x7fffffff, 0x155cc0, 0x19dd),
 RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
     0x7fffffff, 0x2191c0, 0x15cc)
};

static const struct mt76x02_radar_specs fcc_radar_specs[] = {
 /* 20MHz */
 RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
     0x7fffffff, 0xfe808, 0x13dc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0xfe808, 0x19dd),
 RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0xfe808, 0x12cc),
 RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0x57bcf00, 0x1289),
 /* 40MHz */
 RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
     0x7fffffff, 0xfe808, 0x13dc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0xfe808, 0x19dd),
 RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0xfe808, 0x12cc),
 RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0x57bcf00, 0x1289),
 /* 80MHz */
 RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0,
     0x7fffffff, 0xfe808, 0x16cc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0xfe808, 0x19dd),
 RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0xfe808, 0x12cc),
 RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0x57bcf00, 0x1289)
};

static const struct mt76x02_radar_specs jp_w56_radar_specs[] = {
 /* 20MHz */
 RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
     0x7fffffff, 0x14c080, 0x13dc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0x14c080, 0x19dd),
 RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0x14c080, 0x12cc),
 RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0X57bcf00, 0x1289),
 /* 40MHz */
 RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
     0x7fffffff, 0x14c080, 0x13dc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0x14c080, 0x19dd),
 RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0x14c080, 0x12cc),
 RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0X57bcf00, 0x1289),
 /* 80MHz */
 RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
     0x7fffffff, 0x14c080, 0x19dd),
 RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
     0x7fffffff, 0x14c080, 0x12cc),
 RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
     0x3938700, 0X57bcf00, 0x1289)
};

static const struct mt76x02_radar_specs jp_w53_radar_specs[] = {
 /* 20MHz */
 RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 },
 RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 },
 /* 40MHz */
 RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 },
 RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 },
 /* 80MHz */
 RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 },
 RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
     0x7fffffff, 0x14c080, 0x16cc),
 { 0 }
};

static void
mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable)
{
 u32 data;

 data = (1 << 1) | enable;
 mt76_wr(dev, MT_BBP(DFS, 36), data);
}

static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev,
         struct mt76x02_dfs_sequence *seq)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;

 list_add(&seq->head, &dfs_pd->seq_pool);

 dfs_pd->seq_stats.seq_pool_len++;
 dfs_pd->seq_stats.seq_len--;
}

static struct mt76x02_dfs_sequence *
mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_sequence *seq;

 if (list_empty(&dfs_pd->seq_pool)) {
  seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC);
 } else {
  seq = list_first_entry(&dfs_pd->seq_pool,
           struct mt76x02_dfs_sequence,
           head);
  list_del(&seq->head);
  dfs_pd->seq_stats.seq_pool_len--;
 }
 if (seq)
  dfs_pd->seq_stats.seq_len++;

 return seq;
}

static int mt76x02_dfs_get_multiple(int val, int frac, int margin)
{
 int remainder, factor;

 if (!frac)
  return 0;

 if (abs(val - frac) <= margin)
  return 1;

 factor = val / frac;
 remainder = val % frac;

 if (remainder > margin) {
  if ((frac - remainder) <= margin)
   factor++;
  else
   factor = 0;
 }
 return factor;
}

static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_sequence *seq, *tmp_seq;
 int i;

 /* reset hw detector */
 mt76_wr(dev, MT_BBP(DFS, 1), 0xf);

 /* reset sw detector */
 for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
  dfs_pd->event_rb[i].h_rb = 0;
  dfs_pd->event_rb[i].t_rb = 0;
 }

 list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
  list_del_init(&seq->head);
  mt76x02_dfs_seq_pool_put(dev, seq);
 }
}

static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev)
{
 bool ret = false;
 u32 current_ts, delta_ts;
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;

 current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER);
 delta_ts = current_ts - dfs_pd->chirp_pulse_ts;
 dfs_pd->chirp_pulse_ts = current_ts;

 /* 12 sec */
 if (delta_ts <= (12 * (1 << 20))) {
  if (++dfs_pd->chirp_pulse_cnt > 8)
   ret = true;
 } else {
  dfs_pd->chirp_pulse_cnt = 1;
 }

 return ret;
}

static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev,
         struct mt76x02_dfs_hw_pulse *pulse)
{
 u32 data;

 /* select channel */
 data = (MT_DFS_CH_EN << 16) | pulse->engine;
 mt76_wr(dev, MT_BBP(DFS, 0), data);

 /* reported period */
 pulse->period = mt76_rr(dev, MT_BBP(DFS, 19));

 /* reported width */
 pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20));
 pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23));

 /* reported burst number */
 pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22));
}

static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev,
           struct mt76x02_dfs_hw_pulse *pulse)
{
 bool ret = false;

 if (!pulse->period || !pulse->w1)
  return false;

 switch (dev->mt76.region) {
 case NL80211_DFS_FCC:
  if (pulse->engine > 3)
   break;

  if (pulse->engine == 3) {
   ret = mt76x02_dfs_check_chirp(dev);
   break;
  }

  /* check short pulse*/
  if (pulse->w1 < 120)
   ret = (pulse->period >= 2900 &&
          (pulse->period <= 4700 ||
    pulse->period >= 6400) &&
          (pulse->period <= 6800 ||
    pulse->period >= 10200) &&
          pulse->period <= 61600);
  else if (pulse->w1 < 130) /* 120 - 130 */
   ret = (pulse->period >= 2900 &&
          pulse->period <= 61600);
  else
   ret = (pulse->period >= 3500 &&
          pulse->period <= 10100);
  break;
 case NL80211_DFS_ETSI:
  if (pulse->engine >= 3)
   break;

  ret = (pulse->period >= 4900 &&
         (pulse->period <= 10200 ||
   pulse->period >= 12400) &&
         pulse->period <= 100100);
  break;
 case NL80211_DFS_JP:
  if (dev->mphy.chandef.chan->center_freq >= 5250 &&
      dev->mphy.chandef.chan->center_freq <= 5350) {
   /* JPW53 */
   if (pulse->w1 <= 130)
    ret = (pulse->period >= 28360 &&
           (pulse->period <= 28700 ||
     pulse->period >= 76900) &&
           pulse->period <= 76940);
   break;
  }

  if (pulse->engine > 3)
   break;

  if (pulse->engine == 3) {
   ret = mt76x02_dfs_check_chirp(dev);
   break;
  }

  /* check short pulse*/
  if (pulse->w1 < 120)
   ret = (pulse->period >= 2900 &&
          (pulse->period <= 4700 ||
    pulse->period >= 6400) &&
          (pulse->period <= 6800 ||
    pulse->period >= 27560) &&
          (pulse->period <= 27960 ||
    pulse->period >= 28360) &&
          (pulse->period <= 28700 ||
    pulse->period >= 79900) &&
          pulse->period <= 80100);
  else if (pulse->w1 < 130) /* 120 - 130 */
   ret = (pulse->period >= 2900 &&
          (pulse->period <= 10100 ||
    pulse->period >= 27560) &&
          (pulse->period <= 27960 ||
    pulse->period >= 28360) &&
          (pulse->period <= 28700 ||
    pulse->period >= 79900) &&
          pulse->period <= 80100);
  else
   ret = (pulse->period >= 3900 &&
          pulse->period <= 10100);
  break;
 case NL80211_DFS_UNSET:
 default:
  return false;
 }

 return ret;
}

static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev,
        struct mt76x02_dfs_event *event)
{
 u32 data;

 /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2)
 * 2nd: DFS_R37[21:0]: pulse time
 * 3rd: DFS_R37[11:0]: pulse width
 * 3rd: DFS_R37[25:16]: phase
 * 4th: DFS_R37[12:0]: current pwr
 * 4th: DFS_R37[21:16]: pwr stable counter
 *
 * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected
 */

 data = mt76_rr(dev, MT_BBP(DFS, 37));
 if (!MT_DFS_CHECK_EVENT(data))
  return false;

 event->engine = MT_DFS_EVENT_ENGINE(data);
 data = mt76_rr(dev, MT_BBP(DFS, 37));
 event->ts = MT_DFS_EVENT_TIMESTAMP(data);
 data = mt76_rr(dev, MT_BBP(DFS, 37));
 event->width = MT_DFS_EVENT_WIDTH(data);

 return true;
}

static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev,
        struct mt76x02_dfs_event *event)
{
 if (event->engine == 2) {
  struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
  struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
  u16 last_event_idx;
  u32 delta_ts;

  last_event_idx = mt76_decr(event_buff->t_rb,
        MT_DFS_EVENT_BUFLEN);
  delta_ts = event->ts - event_buff->data[last_event_idx].ts;
  if (delta_ts < MT_DFS_EVENT_TIME_MARGIN &&
      event_buff->data[last_event_idx].width >= 200)
   return false;
 }
 return true;
}

static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev,
        struct mt76x02_dfs_event *event)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_event_rb *event_buff;

 /* add radar event to ring buffer */
 event_buff = event->engine == 2 ? &dfs_pd->event_rb[1]
     : &dfs_pd->event_rb[0];
 event_buff->data[event_buff->t_rb] = *event;
 event_buff->data[event_buff->t_rb].fetch_ts = jiffies;

 event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN);
 if (event_buff->t_rb == event_buff->h_rb)
  event_buff->h_rb = mt76_incr(event_buff->h_rb,
          MT_DFS_EVENT_BUFLEN);
}

static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
           struct mt76x02_dfs_event *event,
           u16 cur_len)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_sw_detector_params *sw_params;
 u32 width_delta, with_sum;
 struct mt76x02_dfs_sequence seq, *seq_p;
 struct mt76x02_dfs_event_rb *event_rb;
 struct mt76x02_dfs_event *cur_event;
 int i, j, end, pri, factor, cur_pri;

 event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
          : &dfs_pd->event_rb[0];

 i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN);
 end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN);

 while (i != end) {
  cur_event = &event_rb->data[i];
  with_sum = event->width + cur_event->width;

  sw_params = &dfs_pd->sw_dpd_params;
  switch (dev->mt76.region) {
  case NL80211_DFS_FCC:
  case NL80211_DFS_JP:
   if (with_sum < 600)
    width_delta = 8;
   else
    width_delta = with_sum >> 3;
   break;
  case NL80211_DFS_ETSI:
   if (event->engine == 2)
    width_delta = with_sum >> 6;
   else if (with_sum < 620)
    width_delta = 24;
   else
    width_delta = 8;
   break;
  case NL80211_DFS_UNSET:
  default:
   return -EINVAL;
  }

  pri = event->ts - cur_event->ts;
  if (abs(event->width - cur_event->width) > width_delta ||
      pri < sw_params->min_pri)
   goto next;

  if (pri > sw_params->max_pri)
   break;

  seq.pri = event->ts - cur_event->ts;
  seq.first_ts = cur_event->ts;
  seq.last_ts = event->ts;
  seq.engine = event->engine;
  seq.count = 2;

  j = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
  while (j != end) {
   cur_event = &event_rb->data[j];
   cur_pri = event->ts - cur_event->ts;
   factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri,
      sw_params->pri_margin);
   if (factor > 0) {
    seq.first_ts = cur_event->ts;
    seq.count++;
   }

   j = mt76_decr(j, MT_DFS_EVENT_BUFLEN);
  }
  if (seq.count <= cur_len)
   goto next;

  seq_p = mt76x02_dfs_seq_pool_get(dev);
  if (!seq_p)
   return -ENOMEM;

  *seq_p = seq;
  INIT_LIST_HEAD(&seq_p->head);
  list_add(&seq_p->head, &dfs_pd->sequences);
next:
  i = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
 }
 return 0;
}

static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
          struct mt76x02_dfs_event *event)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_sw_detector_params *sw_params;
 struct mt76x02_dfs_sequence *seq, *tmp_seq;
 u16 max_seq_len = 0;
 int factor, pri;

 sw_params = &dfs_pd->sw_dpd_params;
 list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
  if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) {
   list_del_init(&seq->head);
   mt76x02_dfs_seq_pool_put(dev, seq);
   continue;
  }

  if (event->engine != seq->engine)
   continue;

  pri = event->ts - seq->last_ts;
  factor = mt76x02_dfs_get_multiple(pri, seq->pri,
        sw_params->pri_margin);
  if (factor > 0) {
   seq->last_ts = event->ts;
   seq->count++;
   max_seq_len = max_t(u16, max_seq_len, seq->count);
  }
 }
 return max_seq_len;
}

static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_sequence *seq;

 if (list_empty(&dfs_pd->sequences))
  return false;

 list_for_each_entry(seq, &dfs_pd->sequences, head) {
  if (seq->count > MT_DFS_SEQUENCE_TH) {
   dfs_pd->stats[seq->engine].sw_pattern++;
   return true;
  }
 }
 return false;
}

static void mt76x02_dfs_add_events(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_event event;
 int i, seq_len;

 /* disable debug mode */
 mt76x02_dfs_set_capture_mode_ctrl(dev, false);
 for (i = 0; i < MT_DFS_EVENT_LOOP; i++) {
  if (!mt76x02_dfs_fetch_event(dev, &event))
   break;

  if (dfs_pd->last_event_ts > event.ts)
   mt76x02_dfs_detector_reset(dev);
  dfs_pd->last_event_ts = event.ts;

  if (!mt76x02_dfs_check_event(dev, &event))
   continue;

  seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event);
  mt76x02_dfs_create_sequence(dev, &event, seq_len);

  mt76x02_dfs_queue_event(dev, &event);
 }
 mt76x02_dfs_set_capture_mode_ctrl(dev, true);
}

static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
 struct mt76x02_dfs_event_rb *event_buff;
 struct mt76x02_dfs_event *event;
 int i;

 for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
  event_buff = &dfs_pd->event_rb[i];

  while (event_buff->h_rb != event_buff->t_rb) {
   event = &event_buff->data[event_buff->h_rb];

   /* sorted list */
   if (time_is_after_jiffies(event->fetch_ts +
        MT_DFS_EVENT_WINDOW))
    break;
   event_buff->h_rb = mt76_incr(event_buff->h_rb,
           MT_DFS_EVENT_BUFLEN);
  }
 }
}

static void mt76x02_dfs_tasklet(struct tasklet_struct *t)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t,
           dfs_tasklet);
 struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd);
 u32 engine_mask;
 int i;

 if (test_bit(MT76_SCANNING, &dev->mphy.state))
  goto out;

 if (time_is_before_jiffies(dfs_pd->last_sw_check +
       MT_DFS_SW_TIMEOUT)) {
  bool radar_detected;

  dfs_pd->last_sw_check = jiffies;

  mt76x02_dfs_add_events(dev);
  radar_detected = mt76x02_dfs_check_detection(dev);
  if (radar_detected) {
   /* sw detector rx radar pattern */
   ieee80211_radar_detected(dev->mt76.hw, NULL);
   mt76x02_dfs_detector_reset(dev);

   return;
  }
  mt76x02_dfs_check_event_window(dev);
 }

 engine_mask = mt76_rr(dev, MT_BBP(DFS, 1));
 if (!(engine_mask & 0xf))
  goto out;

 for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
  struct mt76x02_dfs_hw_pulse pulse;

  if (!(engine_mask & (1 << i)))
   continue;

  pulse.engine = i;
  mt76x02_dfs_get_hw_pulse(dev, &pulse);

  if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) {
   dfs_pd->stats[i].hw_pulse_discarded++;
   continue;
  }

  /* hw detector rx radar pattern */
  dfs_pd->stats[i].hw_pattern++;
  ieee80211_radar_detected(dev->mt76.hw, NULL);
  mt76x02_dfs_detector_reset(dev);

  return;
 }

 /* reset hw detector */
 mt76_wr(dev, MT_BBP(DFS, 1), 0xf);

out:
 mt76x02_irq_enable(dev, MT_INT_GPTIMER);
}

static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;

 switch (dev->mt76.region) {
 case NL80211_DFS_FCC:
  dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI;
  dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI;
  dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
  break;
 case NL80211_DFS_ETSI:
  dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI;
  dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI;
  dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2;
  break;
 case NL80211_DFS_JP:
  dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI;
  dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI;
  dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
  break;
 case NL80211_DFS_UNSET:
 default:
  break;
 }
}

static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev)
{
 const struct mt76x02_radar_specs *radar_specs;
 u8 i, shift;
 u32 data;

 switch (dev->mphy.chandef.width) {
 case NL80211_CHAN_WIDTH_40:
  shift = MT_DFS_NUM_ENGINES;
  break;
 case NL80211_CHAN_WIDTH_80:
  shift = 2 * MT_DFS_NUM_ENGINES;
  break;
 default:
  shift = 0;
  break;
 }

 switch (dev->mt76.region) {
 case NL80211_DFS_FCC:
  radar_specs = &fcc_radar_specs[shift];
  break;
 case NL80211_DFS_ETSI:
  radar_specs = &etsi_radar_specs[shift];
  break;
 case NL80211_DFS_JP:
  if (dev->mphy.chandef.chan->center_freq >= 5250 &&
      dev->mphy.chandef.chan->center_freq <= 5350)
   radar_specs = &jp_w53_radar_specs[shift];
  else
   radar_specs = &jp_w56_radar_specs[shift];
  break;
 case NL80211_DFS_UNSET:
 default:
  return;
 }

 data = (MT_DFS_VGA_MASK << 16) |
        (MT_DFS_PWR_GAIN_OFFSET << 12) |
        (MT_DFS_PWR_DOWN_TIME << 8) |
        (MT_DFS_SYM_ROUND << 4) |
        (MT_DFS_DELTA_DELAY & 0xf);
 mt76_wr(dev, MT_BBP(DFS, 2), data);

 data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK;
 mt76_wr(dev, MT_BBP(DFS, 3), data);

 for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
  /* configure engine */
  mt76_wr(dev, MT_BBP(DFS, 0), i);

  /* detection mode + avg_len */
  data = ((radar_specs[i].avg_len & 0x1ff) << 16) |
         (radar_specs[i].mode & 0xf);
  mt76_wr(dev, MT_BBP(DFS, 4), data);

  /* dfs energy */
  data = ((radar_specs[i].e_high & 0x0fff) << 16) |
         (radar_specs[i].e_low & 0x0fff);
  mt76_wr(dev, MT_BBP(DFS, 5), data);

  /* dfs period */
  mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low);
  mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high);

  /* dfs burst */
  mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low);
  mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high);

  /* dfs width */
  data = ((radar_specs[i].w_high & 0x0fff) << 16) |
         (radar_specs[i].w_low & 0x0fff);
  mt76_wr(dev, MT_BBP(DFS, 14), data);

  /* dfs margins */
  data = (radar_specs[i].w_margin << 16) |
         radar_specs[i].t_margin;
  mt76_wr(dev, MT_BBP(DFS, 15), data);

  /* dfs event expiration */
  mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration);

  /* dfs pwr adj */
  mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp);
 }

 /* reset status */
 mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
 mt76_wr(dev, MT_BBP(DFS, 36), 0x3);

 /* enable detection*/
 mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
 mt76_wr(dev, MT_BBP(IBI, 11), 0x0c350001);
}

void mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev *dev)
{
 u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31;

 agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8));
 agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4));

 val_r8 = (agc_r8 & 0x00007e00) >> 9;
 val_r4 = agc_r4 & ~0x1f000000;
 val_r4 += (((val_r8 + 1) >> 1) << 24);
 mt76_wr(dev, MT_BBP(AGC, 4), val_r4);

 dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4);
 dfs_r31 += val_r8;
 dfs_r31 -= (agc_r8 & 0x00000038) >> 3;
 dfs_r31 = (dfs_r31 << 16) | 0x00000307;
 mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31);

 if (is_mt76x2(dev)) {
  mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071);
 } else {
  /* disable hw detector */
  mt76_wr(dev, MT_BBP(DFS, 0), 0);
  /* enable hw detector */
  mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
 }
}
EXPORT_SYMBOL_GPL(mt76x02_phy_dfs_adjust_agc);

void mt76x02_dfs_init_params(struct mt76x02_dev *dev)
{
 if (mt76_phy_dfs_state(&dev->mphy) > MT_DFS_STATE_DISABLED) {
  mt76x02_dfs_init_sw_detector(dev);
  mt76x02_dfs_set_bbp_params(dev);
  /* enable debug mode */
  mt76x02_dfs_set_capture_mode_ctrl(dev, true);

  mt76x02_irq_enable(dev, MT_INT_GPTIMER);
  mt76_rmw_field(dev, MT_INT_TIMER_EN,
          MT_INT_TIMER_EN_GP_TIMER_EN, 1);
 } else {
  /* disable hw detector */
  mt76_wr(dev, MT_BBP(DFS, 0), 0);
  /* clear detector status */
  mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
  if (mt76_chip(&dev->mt76) == 0x7610 ||
      mt76_chip(&dev->mt76) == 0x7630)
   mt76_wr(dev, MT_BBP(IBI, 11), 0xfde8081);
  else
   mt76_wr(dev, MT_BBP(IBI, 11), 0);

  mt76x02_irq_disable(dev, MT_INT_GPTIMER);
  mt76_rmw_field(dev, MT_INT_TIMER_EN,
          MT_INT_TIMER_EN_GP_TIMER_EN, 0);
 }
}
EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params);

void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;

 INIT_LIST_HEAD(&dfs_pd->sequences);
 INIT_LIST_HEAD(&dfs_pd->seq_pool);
 dev->mt76.region = NL80211_DFS_UNSET;
 dfs_pd->last_sw_check = jiffies;
 tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet);
}

static void
mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
         enum nl80211_dfs_regions region)
{
 struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;

 mutex_lock(&dev->mt76.mutex);
 if (dev->mt76.region != region) {
  tasklet_disable(&dfs_pd->dfs_tasklet);

  dev->ed_monitor = dev->ed_monitor_enabled &&
      region == NL80211_DFS_ETSI;
  mt76x02_edcca_init(dev);

  dev->mt76.region = region;
  mt76x02_dfs_init_params(dev);
  tasklet_enable(&dfs_pd->dfs_tasklet);
 }
 mutex_unlock(&dev->mt76.mutex);
}

void mt76x02_regd_notifier(struct wiphy *wiphy,
      struct regulatory_request *request)
{
 struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
 struct mt76x02_dev *dev = hw->priv;

 mt76x02_dfs_set_domain(dev, request->dfs_region);
}

Messung V0.5
C=96 H=93 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.