mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
mt76x2: add hw radar detector
add hw DFS pattern detector support for mt76x2 based devices DFS region supported: - FCC - ETSI - JAPAN_W53 - JAPAN_W56 Signed-off-by: Lorenzo Bianconi <[email protected]>
This commit is contained in:
committed by
Felix Fietkau
parent
838d439f7b
commit
6375fc1abe
@@ -9,7 +9,7 @@ mt76x2e-y := \
|
||||
mt76x2_pci.o mt76x2_dma.o \
|
||||
mt76x2_main.o mt76x2_init.o mt76x2_debugfs.o mt76x2_tx.o \
|
||||
mt76x2_core.o mt76x2_mac.o mt76x2_eeprom.o mt76x2_mcu.o mt76x2_phy.o \
|
||||
mt76x2_trace.o
|
||||
mt76x2_dfs.o mt76x2_trace.o
|
||||
|
||||
mt7603e-y := \
|
||||
mt7603_pci.o mt7603_soc.o mt7603_main.o mt7603_init.o mt7603_mcu.o \
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "mt76.h"
|
||||
#include "mt76x2_regs.h"
|
||||
#include "mt76x2_mac.h"
|
||||
#include "mt76x2_dfs.h"
|
||||
|
||||
struct mt76x2_mcu {
|
||||
struct mutex mutex;
|
||||
@@ -126,6 +127,8 @@ struct mt76x2_dev {
|
||||
|
||||
u8 coverage_class;
|
||||
u8 slottime;
|
||||
|
||||
struct mt76x2_dfs_pattern_detector dfs_pd;
|
||||
};
|
||||
|
||||
struct mt76x2_vif {
|
||||
|
||||
@@ -78,6 +78,11 @@ irqreturn_t mt76x2_irq_handler(int irq, void *dev_instance)
|
||||
tasklet_schedule(&dev->tx_tasklet);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_GPTIMER) {
|
||||
mt76x2_irq_disable(dev, MT_INT_GPTIMER);
|
||||
tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Lorenzo Bianconi <[email protected]>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mt76x2.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 mt76x2_radar_specs etsi_radar_specs[] = {
|
||||
/* 20MHz */
|
||||
RADAR_SPEC(0, 8, 2, 9, 106, 150, 10, 4900, 100096, 10, 0,
|
||||
0x7fffffff, 0x155cc0, 0x19cc),
|
||||
RADAR_SPEC(0, 40, 4, 44, 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, 9, 106, 150, 10, 4900, 100096, 10, 0,
|
||||
0x7fffffff, 0x155cc0, 0x19cc),
|
||||
RADAR_SPEC(0, 40, 4, 44, 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, 9, 106, 150, 10, 4900, 100096, 10, 0,
|
||||
0x7fffffff, 0x155cc0, 0x19cc),
|
||||
RADAR_SPEC(0, 40, 4, 44, 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 mt76x2_radar_specs fcc_radar_specs[] = {
|
||||
/* 20MHz */
|
||||
RADAR_SPEC(0, 8, 2, 7, 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, 44, 96, 480, 150, 2900, 80100, 40, 0,
|
||||
0x7fffffff, 0xfe808, 0x12cc),
|
||||
RADAR_SPEC(2, 60, 15, 48, 640, 2080, 32, 19600, 40200, 32, 0,
|
||||
0x3938700, 0x57bcf00, 0x1289),
|
||||
/* 40MHz */
|
||||
RADAR_SPEC(0, 8, 2, 7, 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, 44, 96, 480, 150, 2900, 80100, 40, 0,
|
||||
0x7fffffff, 0xfe808, 0x12cc),
|
||||
RADAR_SPEC(2, 60, 15, 48, 640, 2080, 32, 19600, 40200, 32, 0,
|
||||
0x3938700, 0x57bcf00, 0x1289),
|
||||
/* 80MHz */
|
||||
RADAR_SPEC(0, 8, 2, 9, 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, 44, 96, 480, 150, 2900, 80100, 40, 0,
|
||||
0x7fffffff, 0xfe808, 0x12cc),
|
||||
RADAR_SPEC(2, 60, 15, 48, 640, 2080, 32, 19600, 40200, 32, 0,
|
||||
0x3938700, 0x57bcf00, 0x1289)
|
||||
};
|
||||
|
||||
static const struct mt76x2_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 mt76x2_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 mt76x2_dfs_set_capture_mode_ctrl(struct mt76x2_dev *dev,
|
||||
u8 enable)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
data = (1 << 1) | enable;
|
||||
mt76_wr(dev, MT_BBP(DFS, 36), data);
|
||||
}
|
||||
|
||||
static bool mt76x2_dfs_check_chirp(struct mt76x2_dev *dev)
|
||||
{
|
||||
bool ret = false;
|
||||
u32 current_ts, delta_ts;
|
||||
struct mt76x2_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 mt76x2_dfs_get_hw_pulse(struct mt76x2_dev *dev,
|
||||
struct mt76x2_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 mt76x2_dfs_check_hw_pulse(struct mt76x2_dev *dev,
|
||||
struct mt76x2_dfs_hw_pulse *pulse)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (!pulse->period || !pulse->w1)
|
||||
return false;
|
||||
|
||||
switch (dev->dfs_pd.region) {
|
||||
case NL80211_DFS_FCC:
|
||||
if (pulse->engine < 3) {
|
||||
/* 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 >= 3900 &&
|
||||
pulse->period <= 10100);
|
||||
} else if (pulse->engine == 3) {
|
||||
ret = mt76x2_dfs_check_chirp(dev);
|
||||
}
|
||||
break;
|
||||
case NL80211_DFS_ETSI:
|
||||
if (pulse->engine < 3) {
|
||||
ret = (pulse->period >= 4900 &&
|
||||
(pulse->period <= 10200 ||
|
||||
pulse->period >= 12400) &&
|
||||
pulse->period <= 100100);
|
||||
}
|
||||
break;
|
||||
case NL80211_DFS_JP:
|
||||
if (dev->mt76.chandef.chan->center_freq >= 5250 &&
|
||||
dev->mt76.chandef.chan->center_freq <= 5350) {
|
||||
/* JPW53 */
|
||||
if (pulse->w1 <= 130)
|
||||
ret = (pulse->period >= 28360 &&
|
||||
(pulse->period <= 28700 ||
|
||||
pulse->period >= 76900) &&
|
||||
pulse->period <= 76940);
|
||||
} else {
|
||||
if (pulse->engine < 3) {
|
||||
/* 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);
|
||||
} else if (pulse->engine == 3) {
|
||||
ret = mt76x2_dfs_check_chirp(dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NL80211_DFS_UNSET:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mt76x2_dfs_chan_state(struct mt76x2_dev *dev)
|
||||
{
|
||||
u64 ch_active_time, ch_busy_time;
|
||||
u32 ch_active_delta, ch_busy_delta;
|
||||
struct mt76_channel_state *state;
|
||||
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
|
||||
struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
|
||||
mt76x2_update_channel(&dev->mt76);
|
||||
state = mt76_channel_state(&dev->mt76, chandef->chan);
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
ch_active_time = state->cc_active;
|
||||
ch_busy_time = state->cc_busy;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
|
||||
ch_active_delta = ch_active_time - dfs_pd->ch_active_time;
|
||||
ch_busy_delta = ch_busy_time - dfs_pd->ch_busy_time;
|
||||
|
||||
dfs_pd->ch_busy = (MT_DFS_FRAC(ch_busy_delta, ch_active_delta) >
|
||||
MT_DFS_FRAC(80, 100));
|
||||
|
||||
dfs_pd->ch_active_time = ch_active_time;
|
||||
dfs_pd->ch_busy_time = ch_busy_time;
|
||||
}
|
||||
|
||||
void mt76x2_dfs_tasklet(unsigned long arg)
|
||||
{
|
||||
u32 engine_mask;
|
||||
struct mt76x2_dev *dev = (struct mt76x2_dev *)arg;
|
||||
struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
|
||||
if (test_bit(MT76_SCANNING, &dev->mt76.state))
|
||||
goto out;
|
||||
|
||||
if (++dfs_pd->ch_state_cnt > MT_DFS_CH_STATE_INTERVAL) {
|
||||
dfs_pd->ch_state_cnt = 0;
|
||||
mt76x2_dfs_chan_state(dev);
|
||||
}
|
||||
|
||||
if (dfs_pd->ch_busy)
|
||||
goto out;
|
||||
|
||||
engine_mask = mt76_rr(dev, MT_BBP(DFS, 1));
|
||||
if (engine_mask & 0xf) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
|
||||
if (engine_mask & (1 << i)) {
|
||||
struct mt76x2_dfs_hw_pulse pulse;
|
||||
|
||||
pulse.engine = i;
|
||||
mt76x2_dfs_get_hw_pulse(dev, &pulse);
|
||||
|
||||
if (mt76x2_dfs_check_hw_pulse(dev, &pulse)) {
|
||||
/* hw detector rx radar pattern */
|
||||
ieee80211_radar_detected(dev->mt76.hw);
|
||||
/* reset hw detector */
|
||||
mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* reset hw detector */
|
||||
mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
|
||||
}
|
||||
|
||||
out:
|
||||
mt76x2_irq_enable(dev, MT_INT_GPTIMER);
|
||||
}
|
||||
|
||||
static void mt76x2_dfs_set_bbp_params(struct mt76x2_dev *dev)
|
||||
{
|
||||
u32 data;
|
||||
u8 i, shift;
|
||||
const struct mt76x2_radar_specs *radar_specs;
|
||||
|
||||
switch (dev->mt76.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->dfs_pd.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->mt76.chandef.chan->center_freq >= 5250 &&
|
||||
dev->mt76.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, 0x212c, 0x0c350001);
|
||||
}
|
||||
|
||||
void mt76x2_dfs_adjust_agc(struct mt76x2_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_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);
|
||||
|
||||
mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071);
|
||||
}
|
||||
|
||||
void mt76x2_dfs_init_params(struct mt76x2_dev *dev)
|
||||
{
|
||||
struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
|
||||
|
||||
tasklet_kill(&dev->dfs_pd.dfs_tasklet);
|
||||
if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
|
||||
mt76x2_dfs_set_bbp_params(dev);
|
||||
/* enable debug mode */
|
||||
mt76x2_dfs_set_capture_mode_ctrl(dev, true);
|
||||
|
||||
mt76x2_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);
|
||||
mt76_wr(dev, 0x212c, 0);
|
||||
|
||||
mt76x2_irq_disable(dev, MT_INT_GPTIMER);
|
||||
mt76_rmw_field(dev, MT_INT_TIMER_EN,
|
||||
MT_INT_TIMER_EN_GP_TIMER_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mt76x2_dfs_init_detector(struct mt76x2_dev *dev)
|
||||
{
|
||||
struct mt76x2_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
|
||||
|
||||
memset(dfs_pd, 0, sizeof(*dfs_pd));
|
||||
|
||||
dfs_pd->region = NL80211_DFS_UNSET;
|
||||
tasklet_init(&dfs_pd->dfs_tasklet, mt76x2_dfs_tasklet,
|
||||
(unsigned long)dev);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Lorenzo Bianconi <[email protected]>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MT76x2_DFS_H
|
||||
#define __MT76x2_DFS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#define MT_DFS_GP_INTERVAL (10 << 4) /* 64 us unit */
|
||||
#define MT_DFS_CH_STATE_INTERVAL 20
|
||||
#define MT_DFS_NUM_ENGINES 4
|
||||
|
||||
/* scaled fraction values */
|
||||
#define MT_DFS_SCALE 16
|
||||
#define MT_DFS_FRAC(val, div) (((val) << MT_DFS_SCALE) / div)
|
||||
|
||||
/* bbp params */
|
||||
#define MT_DFS_SYM_ROUND 0
|
||||
#define MT_DFS_DELTA_DELAY 2
|
||||
#define MT_DFS_VGA_MASK 0
|
||||
#define MT_DFS_PWR_GAIN_OFFSET 3
|
||||
#define MT_DFS_PWR_DOWN_TIME 0xf
|
||||
#define MT_DFS_RX_PE_MASK 0xff
|
||||
#define MT_DFS_PKT_END_MASK 0
|
||||
#define MT_DFS_CH_EN 0xf
|
||||
|
||||
struct mt76x2_radar_specs {
|
||||
u8 mode;
|
||||
u16 avg_len;
|
||||
u16 e_low;
|
||||
u16 e_high;
|
||||
u16 w_low;
|
||||
u16 w_high;
|
||||
u16 w_margin;
|
||||
u32 t_low;
|
||||
u32 t_high;
|
||||
u16 t_margin;
|
||||
u32 b_low;
|
||||
u32 b_high;
|
||||
u32 event_expiration;
|
||||
u16 pwr_jmp;
|
||||
};
|
||||
|
||||
struct mt76x2_dfs_hw_pulse {
|
||||
u8 engine;
|
||||
u32 period;
|
||||
u32 w1;
|
||||
u32 w2;
|
||||
u32 burst;
|
||||
};
|
||||
|
||||
struct mt76x2_dfs_pattern_detector {
|
||||
enum nl80211_dfs_regions region;
|
||||
|
||||
u8 chirp_pulse_cnt;
|
||||
u32 chirp_pulse_ts;
|
||||
|
||||
u16 ch_state_cnt;
|
||||
u64 ch_active_time;
|
||||
u64 ch_busy_time;
|
||||
bool ch_busy;
|
||||
|
||||
struct tasklet_struct dfs_tasklet;
|
||||
};
|
||||
|
||||
void mt76x2_dfs_init_params(struct mt76x2_dev *dev);
|
||||
void mt76x2_dfs_init_detector(struct mt76x2_dev *dev);
|
||||
void mt76x2_dfs_adjust_agc(struct mt76x2_dev *dev);
|
||||
|
||||
#endif /* __MT76x2_DFS_H */
|
||||
@@ -282,6 +282,8 @@ int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard)
|
||||
/* Fire a pre-TBTT interrupt 8 ms before TBTT */
|
||||
mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT,
|
||||
8 << 4);
|
||||
mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER,
|
||||
MT_DFS_GP_INTERVAL);
|
||||
mt76_wr(dev, MT_INT_TIMER_EN, 0);
|
||||
|
||||
mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff);
|
||||
@@ -642,6 +644,15 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev)
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void mt76x2_regd_notifier(struct wiphy *wiphy,
|
||||
struct regulatory_request *request)
|
||||
{
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt76x2_dev *dev = hw->priv;
|
||||
|
||||
dev->dfs_pd.region = request->dfs_region;
|
||||
}
|
||||
|
||||
#define CCK_RATE(_idx, _rate) { \
|
||||
.bitrate = _rate, \
|
||||
.flags = IEEE80211_RATE_SHORT_PREAMBLE, \
|
||||
@@ -739,6 +750,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
|
||||
wiphy->reg_notifier = mt76x2_regd_notifier;
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
|
||||
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
|
||||
@@ -748,6 +761,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
|
||||
dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
|
||||
mt76x2_dfs_init_detector(dev);
|
||||
|
||||
ret = mt76_register_device(&dev->mt76, true, mt76x2_rates,
|
||||
ARRAY_SIZE(mt76x2_rates));
|
||||
if (ret)
|
||||
|
||||
@@ -137,6 +137,8 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
mt76_rr(dev, MT_CH_IDLE);
|
||||
mt76_rr(dev, MT_CH_BUSY);
|
||||
|
||||
mt76x2_dfs_init_params(dev);
|
||||
|
||||
mt76x2_mac_resume(dev);
|
||||
tasklet_enable(&dev->pre_tbtt_tasklet);
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ mt76x2_apply_gain_adj(struct mt76x2_dev *dev)
|
||||
|
||||
mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]);
|
||||
mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]);
|
||||
|
||||
if (dev->mt76.chandef.chan->flags & IEEE80211_CHAN_RADAR)
|
||||
mt76x2_dfs_adjust_agc(dev);
|
||||
}
|
||||
|
||||
static u32
|
||||
|
||||
@@ -266,6 +266,8 @@
|
||||
#define MT_CH_TIME_CFG_CH_TIMER_CLR GENMASK(9, 8)
|
||||
#define MT_CH_TIME_CFG_MDRDY_CLR GENMASK(11, 10)
|
||||
|
||||
#define MT_PBF_LIFE_TIMER 0x1110
|
||||
|
||||
#define MT_BEACON_TIME_CFG 0x1114
|
||||
#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0)
|
||||
#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16)
|
||||
|
||||
Reference in New Issue
Block a user