diff --git a/mt7603/init.c b/mt7603/init.c index 22c248b5..3b8903c0 100644 --- a/mt7603/init.c +++ b/mt7603/init.c @@ -454,6 +454,16 @@ static u32 mt7603_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, addr, mask, val); } +static void +mt7603_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt7603_dev *dev = hw->priv; + + dev->ed_monitor = request->dfs_region == NL80211_DFS_ETSI; +} + int mt7603_register_device(struct mt7603_dev *dev) { struct mt76_bus_ops *bus_ops; @@ -512,6 +522,8 @@ int mt7603_register_device(struct mt7603_dev *dev) #endif BIT(NL80211_IFTYPE_ADHOC); + wiphy->reg_notifier = mt7603_regd_notifier; + ret = mt76_register_device(&dev->mt76, true, mt7603_rates, ARRAY_SIZE(mt7603_rates)); if (ret) diff --git a/mt7603/mac.c b/mt7603/mac.c index f7e38723..5f272173 100644 --- a/mt7603/mac.c +++ b/mt7603/mac.c @@ -1478,6 +1478,91 @@ void mt7603_update_channel(struct mt76_dev *mdev) spin_unlock_bh(&dev->mt76.cc_lock); } +void +mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val) +{ + u32 rxtd_6 = 0xd7c80000; + + if (val == dev->ed_strict_mode) + return; + + dev->ed_strict_mode = val; + + /* Ensure that ED/CCA does not trigger if disabled */ + if (!dev->ed_monitor) + rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x34); + else + rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x7d); + + if (dev->ed_monitor && !dev->ed_strict_mode) + rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x0f); + else + rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x10); + + mt76_wr(dev, MT_RXTD(6), rxtd_6); + + mt76_rmw_field(dev, MT_RXTD(13), MT_RXTD_13_ACI_TH_EN, + dev->ed_monitor && !dev->ed_strict_mode); +} + +static void +mt7603_edcca_check(struct mt7603_dev *dev) +{ + u32 val = mt76_rr(dev, MT_AGC(41)); + ktime_t cur_time; + int rssi0, rssi1; + u32 active; + u32 ed_busy; + + if (!dev->ed_monitor) + return; + + rssi0 = FIELD_GET(MT_AGC_41_RSSI_0, val); + if (rssi0 > 128) + rssi0 -= 256; + + rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val); + if (rssi1 > 128) + rssi1 -= 256; + + if (max(rssi0, rssi1) >= -40 && + dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH) + dev->ed_strong_signal++; + else if (dev->ed_strong_signal > 0) + dev->ed_strong_signal--; + + cur_time = ktime_get_boottime(); + ed_busy = mt76_rr(dev, MT_MIB_STAT_ED) & MT_MIB_STAT_ED_MASK; + + active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); + dev->ed_time = cur_time; + + if (!active) + return; + + if (100 * ed_busy / active > 90) { + if (dev->ed_trigger < 0) + dev->ed_trigger = 0; + dev->ed_trigger++; + } else { + if (dev->ed_trigger > 0) + dev->ed_trigger = 0; + dev->ed_trigger--; + } + + if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH || + dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH / 2) { + mt7603_edcca_set_strict(dev, true); + } else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) { + mt7603_edcca_set_strict(dev, false); + } + + if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH) + dev->ed_trigger = MT7603_EDCCA_BLOCK_TH; + else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) + dev->ed_trigger = -MT7603_EDCCA_BLOCK_TH; +} + void mt7603_mac_work(struct work_struct *work) { struct mt7603_dev *dev = container_of(work, struct mt7603_dev, @@ -1489,6 +1574,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); mt7603_update_channel(&dev->mt76); + mt7603_edcca_check(dev); if (mt7603_watchdog_check(dev, &dev->rx_pse_check, RESET_CAUSE_RX_PSE_BUSY, diff --git a/mt7603/main.c b/mt7603/main.c index 3c7626eb..ec8b1dd1 100644 --- a/mt7603/main.c +++ b/mt7603/main.c @@ -122,6 +122,27 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_unlock(&dev->mt76.mutex); } +static void +mt7603_init_edcca(struct mt7603_dev *dev) +{ + /* Set lower signal level to -65dBm */ + mt76_rmw_field(dev, MT_RXTD(8), MT_RXTD_8_LOWER_SIGNAL, 0x23); + + /* clear previous energy detect monitor results */ + mt76_rr(dev, MT_MIB_STAT_ED); + + if (dev->ed_monitor) + mt76_set(dev, MT_MIB_CTL, MT_MIB_CTL_ED_TIME); + else + mt76_clear(dev, MT_MIB_CTL, MT_MIB_CTL_ED_TIME); + + dev->ed_strict_mode = 0xff; + dev->ed_strong_signal = 0; + dev->ed_time = ktime_get_boottime(); + + mt7603_edcca_set_strict(dev, false); +} + static int mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) { @@ -180,6 +201,8 @@ mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) dev->survey_time = ktime_get_boottime(); + mt7603_init_edcca(dev); + out: mutex_unlock(&dev->mt76.mutex); diff --git a/mt7603/mt7603.h b/mt7603/mt7603.h index 4a5a96ba..63bd4891 100644 --- a/mt7603/mt7603.h +++ b/mt7603/mt7603.h @@ -46,6 +46,8 @@ #define MT7603_WATCHDOG_TIME 100 /* ms */ #define MT7603_WATCHDOG_TIMEOUT 10 /* number of checks */ +#define MT7603_EDCCA_BLOCK_TH 10 + struct mt7603_vif; struct mt7603_sta; @@ -115,6 +117,7 @@ struct mt7603_dev { s16 coverage_class; ktime_t survey_time; + ktime_t ed_time; int beacon_int; struct mt76_queue q_rx; @@ -122,6 +125,11 @@ struct mt7603_dev { spinlock_t ps_lock; u8 mcu_running; + u8 ed_monitor; + + s8 ed_trigger; + u8 ed_strict_mode; + u8 ed_strong_signal; u8 beacon_mask; @@ -241,4 +249,6 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg); void mt7603_update_channel(struct mt76_dev *mdev); +void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val); + #endif diff --git a/mt7603/regs.h b/mt7603/regs.h index 42e9f3cf..ec199ce0 100644 --- a/mt7603/regs.h +++ b/mt7603/regs.h @@ -147,8 +147,21 @@ #define MT_WF_PHY_OFFSET 0x1000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) -#define MT_WF_PHY_CR_RXTD_BASE MT_WF_PHY(0x600) -#define MT_WF_PHY_CR_RXTD(n) (MT_WF_PHY_CR_RXTD_BASE + ((n) * 4)) +#define MT_AGC_BASE MT_WF_PHY(0x500) +#define MT_AGC(n) (MT_AGC_BASE + ((n) * 4)) + +#define MT_AGC_41_RSSI_0 GENMASK(23, 16) +#define MT_AGC_41_RSSI_1 GENMASK(7, 0) + +#define MT_RXTD_BASE MT_WF_PHY(0x600) +#define MT_RXTD(n) (MT_RXTD_BASE + ((n) * 4)) + +#define MT_RXTD_6_ACI_TH GENMASK(4, 0) +#define MT_RXTD_6_CCAED_TH GENMASK(14, 8) + +#define MT_RXTD_8_LOWER_SIGNAL GENMASK(5, 0) + +#define MT_RXTD_13_ACI_TH_EN BIT(0) #define MT_WF_PHY_CR_TSSI_BASE MT_WF_PHY(0xd00) #define MT_WF_PHY_CR_TSSI(phy, n) (MT_WF_PHY_CR_TSSI_BASE + \ @@ -515,8 +528,9 @@ enum { #define MT_MIB(_n) (MT_MIB_BASE + (_n)) #define MT_MIB_CTL MT_MIB(0x00) -#define MT_MIB_CTL_CCA_NAV_TX GENMASK(16, 14) #define MT_MIB_CTL_PSCCA_TIME GENMASK(13, 11) +#define MT_MIB_CTL_CCA_NAV_TX GENMASK(16, 14) +#define MT_MIB_CTL_ED_TIME GENMASK(30, 28) #define MT_MIB_CTL_READ_CLR_DIS BIT(31) #define MT_MIB_STAT(_n) MT_MIB(0x08 + (_n) * 4) @@ -527,6 +541,9 @@ enum { #define MT_MIB_STAT_PSCCA MT_MIB_STAT(16) #define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0) +#define MT_MIB_STAT_ED MT_MIB_STAT(18) +#define MT_MIB_STAT_ED_MASK GENMASK(23, 0) + #define MT_PCIE_REMAP_BASE_1 0x40000 #define MT_PCIE_REMAP_BASE_2 0x80000