diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7603')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/dma.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/init.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 141 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/main.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/mt7603/regs.h | 5 |
7 files changed, 203 insertions, 32 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index 5942fe76c6e9..47c85a9fac28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -69,6 +69,41 @@ mt7603_edcca_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get, mt7603_edcca_set, "%lld\n"); +static int +mt7603_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7603_dev *dev = file->private; + int bound[3], i, range; + + range = mt76_rr(dev, MT_AGG_ASRCR); + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i], bound[i + 1]); + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + return 0; +} + +static int +mt7603_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7603_ampdu_stat_read, inode->i_private); +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt7603_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + void mt7603_init_debugfs(struct mt7603_dev *dev) { struct dentry *dir; @@ -77,6 +112,9 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) if (!dir) return; + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test); debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 24d82a20d046..a6ab73060aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) for (i = MT_TXQ_MCU; i >= 0; i--) mt76_queue_tx_cleanup(dev, i, false); + mt7603_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index ad2ccdbe7258..0696dbf28c5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -7,6 +7,8 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, + .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, @@ -524,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev) bus_ops->rmw = mt7603_rmw; dev->mt76.bus = bus_ops; + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->ps_lock); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); @@ -552,7 +556,6 @@ int mt7603_register_device(struct mt7603_dev *dev) wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); /* init led callbacks */ @@ -561,16 +564,7 @@ int mt7603_register_device(struct mt7603_dev *dev) dev->mt76.led_cdev.blink_set = mt7603_led_set_blink; } - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - wiphy->reg_notifier = mt7603_regd_notifier; ret = mt76_register_device(&dev->mt76, true, mt7603_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index c328192307c4..812d081ad943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -31,6 +31,16 @@ mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev) +{ + int i; + + for (i = 0; i < 2; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); +} + void mt7603_mac_set_timing(struct mt7603_dev *dev) { u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | @@ -150,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, addr = mt7603_wtbl4_addr(idx); for (i = 0; i < MT_WTBL4_SIZE; i += 4) mt76_wr(dev, addr + i, 0); + + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } static void @@ -370,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); } +void mt7603_mac_sta_poll(struct mt7603_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt7603_sta *msta; + u32 total_airtime = 0; + u32 airtime[4]; + u32 addr; + int i; + + rcu_read_lock(); + + while (1) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + + msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta, + poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7603_wtbl4_addr(msta->wcid.idx); + for (i = 0; i < 4; i++) { + u32 airtime_last = msta->tx_airtime_ac[i]; + + msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); + airtime[i] = msta->tx_airtime_ac[i] - airtime_last; + airtime[i] *= 32; + total_airtime += airtime[i]; + + if (msta->tx_airtime_ac[i] & BIT(22)) + clear = true; + } + + if (clear) { + mt7603_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->tx_airtime_ac, 0, + sizeof(msta->tx_airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + for (i = 0; i < 4; i++) { + struct mt76_queue *q = dev->mt76.q_tx[i].q; + u8 qidx = q->hw_idx; + u8 tid = ac_to_tid[i]; + u32 txtime = airtime[qidx]; + + if (!txtime) + continue; + + ieee80211_sta_register_airtime(sta, tid, txtime, 0); + } + } + + rcu_read_unlock(); + + if (!total_airtime) + return; + + spin_lock_bh(&dev->mt76.cc_lock); + dev->mt76.chan_state->cc_tx += total_airtime; + spin_unlock_bh(&dev->mt76.cc_lock); +} + static struct mt76_wcid * mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) { @@ -435,6 +525,20 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } + if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | + MT_RXD2_NORMAL_NON_AMPDU))) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (dev->rx_ampdu_ts != rxd[12]) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + dev->rx_ampdu_ts = rxd[12]; + + status->ampdu_ref = dev->mt76.ampdu_ref; + } + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) @@ -1032,8 +1136,10 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; - if (i == ARRAY_SIZE(info->status.rates)) + if (i == ARRAY_SIZE(info->status.rates)) { + i--; break; + } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; @@ -1135,6 +1241,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) msta = container_of(wcid, struct mt7603_sta, wcid); sta = wcid_to_sta(wcid); + if (list_empty(&msta->poll_list)) { + spin_lock_bh(&dev->sta_poll_lock); + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; @@ -1461,22 +1573,9 @@ void mt7603_update_channel(struct mt76_dev *mdev) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt76_channel_state *state; - ktime_t cur_time; - u32 busy; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return; - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); - busy = mt76_rr(dev, MT_MIB_STAT_PSCCA); - - spin_lock_bh(&dev->mt76.cc_lock); - cur_time = ktime_get_boottime(); - state->cc_busy += busy; - state->cc_active += ktime_to_us(ktime_sub(cur_time, - dev->mt76.survey_time)); - dev->mt76.survey_time = cur_time; - spin_unlock_bh(&dev->mt76.cc_lock); + state = mdev->chan_state; + state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } void @@ -1677,15 +1776,23 @@ void mt7603_mac_work(struct work_struct *work) struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mt76.mac_work.work); bool reset = false; + int i, idx; mt76_tx_status_check(&dev->mt76, NULL, false); mutex_lock(&dev->mt76.mutex); dev->mac_work_count++; - mt7603_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); mt7603_edcca_check(dev); + for (i = 0, idx = 0; i < 2; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; + } + if (dev->mac_work_count == 10) mt7603_false_cca_check(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 25d5b1608bc9..962e2822d19f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -13,6 +13,7 @@ mt7603_start(struct ieee80211_hw *hw) { struct mt7603_dev *dev = hw->priv; + mt7603_mac_reset_counters(dev); mt7603_mac_start(dev); dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); @@ -65,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; dev->vif_mask |= BIT(mvif->idx); + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -86,8 +88,9 @@ static void mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; + struct mt7603_sta *msta = &mvif->sta; struct mt7603_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0); @@ -98,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mt76_txq_remove(&dev->mt76, vif->txq); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mutex_lock(&dev->mt76.mutex); dev->vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); @@ -324,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); __skb_queue_head_init(&msta->psq); msta->ps = ~0; msta->smps = ~0; @@ -360,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7603_filter_tx(dev, wcid->idx, true); spin_unlock_bh(&dev->ps_lock); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mt7603_wtbl_clear(dev, wcid->idx); } @@ -555,12 +569,14 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 ssn = params->ssn; u8 ba_size = params->buf_size; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -582,7 +598,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; @@ -590,8 +606,9 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); - return 0; + return ret; } static void @@ -676,6 +693,7 @@ const struct ieee80211_ops mt7603_ops = { .set_coverage_class = mt7603_set_coverage_class, .set_tim = mt76_set_tim, .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 257300fec4f8..ab54b0612e98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -61,6 +61,9 @@ struct mt7603_sta { struct mt7603_vif *vif; + struct list_head poll_list; + u32 tx_airtime_ac[4]; + struct sk_buff_head psq; struct ieee80211_tx_rate rates[4]; @@ -103,12 +106,16 @@ struct mt7603_dev { u8 vif_mask; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct mt7603_sta global_sta; u32 agc0, agc3; u32 false_cca_ofdm, false_cca_cck; unsigned long last_cca_adj; + __le32 rx_ampdu_ts; u8 rssi_offset[3]; u8 slottime; @@ -118,8 +125,6 @@ struct mt7603_dev { ktime_t ed_time; - struct mt76_queue q_rx; - spinlock_t ps_lock; u8 mac_work_count; @@ -191,6 +196,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev); void mt7603_mac_dma_start(struct mt7603_dev *dev); void mt7603_mac_start(struct mt7603_dev *dev); void mt7603_mac_stop(struct mt7603_dev *dev); @@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size); +void mt7603_mac_sta_poll(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index eb9eefe8e125..6e23ed3dfdff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -212,6 +212,9 @@ #define MT_AGG_PCR_RTS_THR GENMASK(19, 0) #define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25) +#define MT_AGG_ASRCR MT_WF_AGG(0x060) +#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) + #define MT_AGG_CONTROL MT_WF_AGG(0x070) #define MT_AGG_CONTROL_NO_BA_RULE BIT(0) #define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1) @@ -555,6 +558,8 @@ enum { #define MT_MIB_STAT_PSCCA MT_MIB_STAT(16) #define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0) +#define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2)) + #define MT_MIB_STAT_ED MT_MIB_STAT(18) #define MT_MIB_STAT_ED_MASK GENMASK(23, 0) |