summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt76/mt7915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c381
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c170
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c646
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.h11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c334
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c1046
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h105
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mmio.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h144
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/pci.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h149
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.h6
13 files changed, 2122 insertions, 901 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 64048243e34b..4b7f38fcbe64 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -7,6 +7,13 @@
/** global debugfs **/
+struct hw_queue_map {
+ const char *name;
+ u8 index;
+ u8 pid;
+ u8 qid;
+};
+
static int
mt7915_implicit_txbf_set(void *data, u64 val)
{
@@ -113,13 +120,10 @@ static void
mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
struct seq_file *file)
{
- struct mt7915_dev *dev = file->private;
+ struct mt7915_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
int bound[15], range[4], i, n;
- if (!phy)
- return;
-
/* Tx ampdu stat */
for (i = 0; i < ARRAY_SIZE(range); i++)
range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i));
@@ -146,56 +150,46 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
static void
mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
{
- struct mt7915_dev *dev = s->private;
- bool ext_phy = phy != &dev->phy;
static const char * const bw[] = {
"BW20", "BW40", "BW80", "BW160"
};
- int cnt;
-
- if (!phy)
- return;
+ struct mib_stats *mib = &phy->mib;
/* Tx Beamformer monitor */
seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
- cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy));
- seq_printf(s, "iBF: %ld, eBF: %ld\n",
- FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt),
- FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt));
+ seq_printf(s, "iBF: %d, eBF: %d\n",
+ mib->tx_bf_ibf_ppdu_cnt,
+ mib->tx_bf_ebf_ppdu_cnt);
/* Tx Beamformer Rx feedback monitor */
seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
- cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy));
- seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld, ",
- FIELD_GET(MT_ETBF_RX_FB_ALL, cnt),
- FIELD_GET(MT_ETBF_RX_FB_HE, cnt),
- FIELD_GET(MT_ETBF_RX_FB_VHT, cnt),
- FIELD_GET(MT_ETBF_RX_FB_HT, cnt));
- cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy));
- seq_printf(s, "%s, NC: %ld, NR: %ld\n",
- bw[FIELD_GET(MT_ETBF_RX_FB_BW, cnt)],
- FIELD_GET(MT_ETBF_RX_FB_NC, cnt),
- FIELD_GET(MT_ETBF_RX_FB_NR, cnt));
+ seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
+ mib->tx_bf_rx_fb_all_cnt,
+ mib->tx_bf_rx_fb_he_cnt,
+ mib->tx_bf_rx_fb_vht_cnt,
+ mib->tx_bf_rx_fb_ht_cnt);
+
+ seq_printf(s, "%s, NC: %d, NR: %d\n",
+ bw[mib->tx_bf_rx_fb_bw],
+ mib->tx_bf_rx_fb_nc_cnt,
+ mib->tx_bf_rx_fb_nr_cnt);
/* Tx Beamformee Rx NDPA & Tx feedback report */
- cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy));
- seq_printf(s, "Tx Beamformee successful feedback frames: %ld\n",
- FIELD_GET(MT_ETBF_TX_FB_CPL, cnt));
- seq_printf(s, "Tx Beamformee feedback triggered counts: %ld\n",
- FIELD_GET(MT_ETBF_TX_FB_TRI, cnt));
+ seq_printf(s, "Tx Beamformee successful feedback frames: %d\n",
+ mib->tx_bf_fb_cpl_cnt);
+ seq_printf(s, "Tx Beamformee feedback triggered counts: %d\n",
+ mib->tx_bf_fb_trig_cnt);
/* Tx SU & MU counters */
- cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy));
- seq_printf(s, "Tx multi-user Beamforming counts: %ld\n",
- FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt));
- cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy));
- seq_printf(s, "Tx multi-user MPDU counts: %d\n", cnt);
- cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy));
- seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", cnt);
- cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy));
- seq_printf(s, "Tx single-user successful MPDU counts: %d\n", cnt);
+ seq_printf(s, "Tx multi-user Beamforming counts: %d\n",
+ mib->tx_bf_cnt);
+ seq_printf(s, "Tx multi-user MPDU counts: %d\n", mib->tx_mu_mpdu_cnt);
+ seq_printf(s, "Tx multi-user successful MPDU counts: %d\n",
+ mib->tx_mu_acked_mpdu_cnt);
+ seq_printf(s, "Tx single-user successful MPDU counts: %d\n",
+ mib->tx_su_acked_mpdu_cnt);
seq_puts(s, "\n");
}
@@ -203,91 +197,189 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
static int
mt7915_tx_stats_show(struct seq_file *file, void *data)
{
- struct mt7915_dev *dev = file->private;
- int stat[8], i, n;
+ struct mt7915_phy *phy = file->private;
+ struct mt7915_dev *dev = phy->dev;
+ struct mib_stats *mib = &phy->mib;
+ int i;
- mt7915_ampdu_stat_read_phy(&dev->phy, file);
- mt7915_txbf_stat_read_phy(&dev->phy, file);
+ mutex_lock(&dev->mt76.mutex);
- mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file);
- mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file);
+ mt7915_ampdu_stat_read_phy(phy, file);
+ mt7915_mac_update_stats(phy);
+ mt7915_txbf_stat_read_phy(phy, file);
/* Tx amsdu info */
seq_puts(file, "Tx MSDU statistics:\n");
- for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
- stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
- n += stat[i];
- }
-
- for (i = 0; i < ARRAY_SIZE(stat); i++) {
- seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
- i + 1, stat[i]);
- if (n != 0)
- seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
+ seq_printf(file, "AMSDU pack count of %d MSDU in TXD: %8d ",
+ i + 1, mib->tx_amsdu[i]);
+ if (mib->tx_amsdu_cnt)
+ seq_printf(file, "(%3d%%)\n",
+ mib->tx_amsdu[i] * 100 / mib->tx_amsdu_cnt);
else
seq_puts(file, "\n");
}
+ mutex_unlock(&dev->mt76.mutex);
+
return 0;
}
DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
-static int
-mt7915_queues_acq(struct seq_file *s, void *data)
+static void
+mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size,
+ const struct hw_queue_map *map)
{
- struct mt7915_dev *dev = dev_get_drvdata(s->private);
- int i;
+ struct mt7915_phy *phy = s->private;
+ struct mt7915_dev *dev = phy->dev;
+ u32 i, val;
- for (i = 0; i < 16; i++) {
- int j, acs = i / 4, index = i % 4;
- u32 ctrl, val, qlen = 0;
+ val = mt76_rr(dev, base + MT_FL_Q_EMPTY);
+ for (i = 0; i < size; i++) {
+ u32 ctrl, head, tail, queued;
- val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
- ctrl = BIT(31) | BIT(15) | (acs << 8);
+ if (val & BIT(map[i].index))
+ continue;
- for (j = 0; j < 32; j++) {
- if (val & BIT(j))
- continue;
+ ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24);
+ mt76_wr(dev, base + MT_FL_Q0_CTRL, ctrl);
- mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
- ctrl | (j + (index << 5)));
- qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
- GENMASK(11, 0));
- }
- seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
+ head = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
+ GENMASK(11, 0));
+ tail = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
+ GENMASK(27, 16));
+ queued = mt76_get_field(dev, base + MT_FL_Q3_CTRL,
+ GENMASK(11, 0));
+
+ seq_printf(s, "\t%s: ", map[i].name);
+ seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
+ queued, head, tail);
}
+}
+
+static void
+mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
+{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct mt7915_dev *dev = msta->vif->phy->dev;
+ struct seq_file *s = data;
+ u8 ac;
+
+ for (ac = 0; ac < 4; ac++) {
+ u32 qlen, ctrl, val;
+ u32 idx = msta->wcid.idx >> 5;
+ u8 offs = msta->wcid.idx & GENMASK(4, 0);
+
+ ctrl = BIT(31) | BIT(11) | (ac << 24);
+ val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
+
+ if (val & BIT(offs))
+ continue;
+
+ mt76_wr(dev, MT_PLE_BASE + MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
+ qlen = mt76_get_field(dev, MT_PLE_BASE + MT_FL_Q3_CTRL,
+ GENMASK(11, 0));
+ seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
+ sta->addr, msta->wcid.idx, msta->vif->wmm_idx,
+ ac, qlen);
+ }
+}
+
+static int
+mt7915_hw_queues_show(struct seq_file *file, void *data)
+{
+ struct mt7915_phy *phy = file->private;
+ struct mt7915_dev *dev = phy->dev;
+ static const struct hw_queue_map ple_queue_map[] = {
+ { "CPU_Q0", 0, 1, MT_CTX0 },
+ { "CPU_Q1", 1, 1, MT_CTX0 + 1 },
+ { "CPU_Q2", 2, 1, MT_CTX0 + 2 },
+ { "CPU_Q3", 3, 1, MT_CTX0 + 3 },
+ { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 },
+ { "BMC_Q0", 9, 2, MT_LMAC_BMC0 },
+ { "BCN_Q0", 10, 2, MT_LMAC_BCN0 },
+ { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 },
+ { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
+ { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 },
+ { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 },
+ { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
+ };
+ static const struct hw_queue_map pse_queue_map[] = {
+ { "CPU Q0", 0, 1, MT_CTX0 },
+ { "CPU Q1", 1, 1, MT_CTX0 + 1 },
+ { "CPU Q2", 2, 1, MT_CTX0 + 2 },
+ { "CPU Q3", 3, 1, MT_CTX0 + 3 },
+ { "HIF_Q0", 8, 0, MT_HIF0 },
+ { "HIF_Q1", 9, 0, MT_HIF0 + 1 },
+ { "HIF_Q2", 10, 0, MT_HIF0 + 2 },
+ { "HIF_Q3", 11, 0, MT_HIF0 + 3 },
+ { "HIF_Q4", 12, 0, MT_HIF0 + 4 },
+ { "HIF_Q5", 13, 0, MT_HIF0 + 5 },
+ { "LMAC_Q", 16, 2, 0 },
+ { "MDP_TXQ", 17, 2, 1 },
+ { "MDP_RXQ", 18, 2, 2 },
+ { "SEC_TXQ", 19, 2, 3 },
+ { "SEC_RXQ", 20, 2, 4 },
+ };
+ u32 val, head, tail;
+
+ /* ple queue */
+ val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
+ head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
+ tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
+ seq_puts(file, "PLE page info:\n");
+ seq_printf(file,
+ "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
+ val, head, tail);
+
+ val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
+ head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
+ tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
+ seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
+ val, head, tail);
+
+ seq_puts(file, "PLE non-empty queue info:\n");
+ mt7915_hw_queue_read(file, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map),
+ &ple_queue_map[0]);
+
+ /* iterate per-sta ple queue */
+ ieee80211_iterate_stations_atomic(phy->mt76->hw,
+ mt7915_sta_hw_queue_read, file);
+ /* pse queue */
+ seq_puts(file, "PSE non-empty queue info:\n");
+ mt7915_hw_queue_read(file, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map),
+ &pse_queue_map[0]);
return 0;
}
+DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues);
+
static int
-mt7915_queues_read(struct seq_file *s, void *data)
+mt7915_xmit_queues_show(struct seq_file *file, void *data)
{
- struct mt7915_dev *dev = dev_get_drvdata(s->private);
- struct mt76_phy *mphy_ext = dev->mt76.phy2;
- struct mt76_queue *ext_q = mphy_ext ? mphy_ext->q_tx[MT_TXQ_BE] : NULL;
+ struct mt7915_phy *phy = file->private;
+ struct mt7915_dev *dev = phy->dev;
struct {
struct mt76_queue *q;
char *queue;
} queue_map[] = {
- { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
- { ext_q, "WFDMA1" },
- { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
- { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" },
- { dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" },
- { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
+ { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" },
+ { dev->mt76.q_mcu[MT_MCUQ_WM], " MCUWM" },
+ { dev->mt76.q_mcu[MT_MCUQ_WA], " MCUWA" },
+ { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWDL" },
};
int i;
+ seq_puts(file, " queue | hw-queued | head | tail |\n");
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
struct mt76_queue *q = queue_map[i].q;
if (!q)
continue;
- seq_printf(s,
- "%s: queued=%d head=%d tail=%d\n",
+ seq_printf(file, " %s | %9d | %9d | %9d |\n",
queue_map[i].queue, q->queued, q->head,
q->tail);
}
@@ -295,8 +387,10 @@ mt7915_queues_read(struct seq_file *s, void *data)
return 0;
}
-static void
-mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy)
+DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues);
+
+static int
+mt7915_rate_txpower_show(struct seq_file *file, void *data)
{
static const char * const sku_group_name[] = {
"CCK", "OFDM", "HT20", "HT40",
@@ -304,14 +398,11 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy)
"RU26", "RU52", "RU106", "RU242/SU20",
"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
};
+ struct mt7915_phy *phy = file->private;
s8 txpower[MT7915_SKU_RATE_NUM], *buf;
int i;
- if (!phy)
- return;
-
- seq_printf(s, "\nBand %d\n", phy != &phy->dev->phy);
-
+ seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy);
mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower));
for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
u8 mcs_num = mt7915_sku_group_len[i];
@@ -319,45 +410,70 @@ mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy)
if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160)
mcs_num = 10;
- mt76_seq_puts_array(s, sku_group_name[i], buf, mcs_num);
+ mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num);
buf += mt7915_sku_group_len[i];
}
+
+ return 0;
}
+DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower);
+
static int
-mt7915_read_rate_txpower(struct seq_file *s, void *data)
+mt7915_twt_stats(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
+ struct mt7915_twt_flow *iter;
- mt7915_puts_rate_txpower(s, &dev->phy);
- mt7915_puts_rate_txpower(s, mt7915_ext_phy(dev));
+ rcu_read_lock();
+
+ seq_puts(s, " wcid | id | flags | exp | mantissa");
+ seq_puts(s, " | duration | tsf |\n");
+ list_for_each_entry_rcu(iter, &dev->twt_list, list)
+ seq_printf(s,
+ "%9d | %8d | %5c%c%c%c | %8d | %8d | %8d | %14lld |\n",
+ iter->wcid, iter->id,
+ iter->sched ? 's' : 'u',
+ iter->protection ? 'p' : '-',
+ iter->trigger ? 't' : '-',
+ iter->flowtype ? '-' : 'a',
+ iter->exp, iter->mantissa,
+ iter->duration, iter->tsf);
+
+ rcu_read_unlock();
return 0;
}
-int mt7915_init_debugfs(struct mt7915_dev *dev)
+int mt7915_init_debugfs(struct mt7915_phy *phy)
{
+ struct mt7915_dev *dev = phy->dev;
+ bool ext_phy = phy != &dev->phy;
struct dentry *dir;
- dir = mt76_register_debugfs(&dev->mt76);
+ dir = mt76_register_debugfs_fops(phy->mt76, NULL);
if (!dir)
return -ENOMEM;
- debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
- mt7915_queues_read);
- debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
- mt7915_queues_acq);
- debugfs_create_file("tx_stats", 0400, dir, dev, &mt7915_tx_stats_fops);
+ debugfs_create_file("hw-queues", 0400, dir, phy,
+ &mt7915_hw_queues_fops);
+ debugfs_create_file("xmit-queues", 0400, dir, phy,
+ &mt7915_xmit_queues_fops);
+ debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
debugfs_create_file("implicit_txbf", 0600, dir, dev,
&fops_implicit_txbf);
- debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
- /* test knobs */
- debugfs_create_file("radar_trigger", 0200, dir, dev,
- &fops_radar_trigger);
+ debugfs_create_file("txpower_sku", 0400, dir, phy,
+ &mt7915_rate_txpower_fops);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
+ mt7915_twt_stats);
debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
- debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
- mt7915_read_rate_txpower);
+ if (!dev->dbdc_support || ext_phy) {
+ debugfs_create_u32("dfs_hw_pattern", 0400, dir,
+ &dev->hw_pattern);
+ debugfs_create_file("radar_trigger", 0200, dir, dev,
+ &fops_radar_trigger);
+ }
return 0;
}
@@ -365,12 +481,14 @@ int mt7915_init_debugfs(struct mt7915_dev *dev)
#ifdef CONFIG_MAC80211_DEBUGFS
/** per-station debugfs **/
-/* usage: <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> */
static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
{
struct ieee80211_sta *sta = data;
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ /* usage: <he ltf> <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs>
+ * <tx mode>: see enum mt76_phy_type
+ */
return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate);
}
@@ -378,55 +496,22 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
mt7915_sta_fixed_rate_set, "%llx\n");
static int
-mt7915_sta_stats_show(struct seq_file *s, void *data)
+mt7915_queues_show(struct seq_file *s, void *data)
{
struct ieee80211_sta *sta = s->private;
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct mt7915_sta_stats *stats = &msta->stats;
- struct rate_info *rate = &stats->prob_rate;
- static const char * const bw[] = {
- "BW20", "BW5", "BW10", "BW40",
- "BW80", "BW160", "BW_HE_RU"
- };
- if (!rate->legacy && !rate->flags)
- return 0;
-
- seq_puts(s, "Probing rate - ");
- if (rate->flags & RATE_INFO_FLAGS_MCS)
- seq_puts(s, "HT ");
- else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
- seq_puts(s, "VHT ");
- else if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
- seq_puts(s, "HE ");
- else
- seq_printf(s, "Bitrate %d\n", rate->legacy);
-
- if (rate->flags) {
- seq_printf(s, "%s NSS%d MCS%d ",
- bw[rate->bw], rate->nss, rate->mcs);
-
- if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
- seq_puts(s, "SGI ");
- else if (rate->he_gi)
- seq_puts(s, "HE GI ");
-
- if (rate->he_dcm)
- seq_puts(s, "DCM ");
- }
-
- seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n",
- stats->per / 10, stats->per % 10);
+ mt7915_sta_hw_queue_read(s, sta);
return 0;
}
-DEFINE_SHOW_ATTRIBUTE(mt7915_sta_stats);
+DEFINE_SHOW_ATTRIBUTE(mt7915_queues);
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
- debugfs_create_file("stats", 0400, dir, sta, &mt7915_sta_stats_fops);
+ debugfs_create_file("hw-queues", 0400, dir, sta, &mt7915_queues_fops);
}
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 4798d6344305..4fa8e7ba93e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -42,13 +42,17 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
-static ssize_t mt7915_thermal_show_temp(struct device *dev,
+static ssize_t mt7915_thermal_temp_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mt7915_phy *phy = dev_get_drvdata(dev);
+ int i = to_sensor_dev_attr(attr)->index;
int temperature;
+ if (i)
+ return sprintf(buf, "%u\n", phy->throttle_temp[i - 1] * 1000);
+
temperature = mt7915_mcu_get_temperature(phy);
if (temperature < 0)
return temperature;
@@ -57,11 +61,34 @@ static ssize_t mt7915_thermal_show_temp(struct device *dev,
return sprintf(buf, "%u\n", temperature * 1000);
}
-static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7915_thermal_show_temp,
- NULL, 0);
+static ssize_t mt7915_thermal_temp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mt7915_phy *phy = dev_get_drvdata(dev);
+ int ret, i = to_sensor_dev_attr(attr)->index;
+ long val;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 60, 130);
+ phy->throttle_temp[i - 1] = val;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7915_thermal_temp, 0);
+static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7915_thermal_temp, 1);
+static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7915_thermal_temp, 2);
static struct attribute *mt7915_hwmon_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(mt7915_hwmon);
@@ -96,6 +123,9 @@ mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
if (state > MT7915_THERMAL_THROTTLE_MAX)
return -EINVAL;
+ if (phy->throttle_temp[0] > phy->throttle_temp[1])
+ return 0;
+
if (state == phy->throttle_state)
return 0;
@@ -130,9 +160,12 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
struct wiphy *wiphy = phy->mt76->hw->wiphy;
struct thermal_cooling_device *cdev;
struct device *hwmon;
+ const char *name;
- cdev = thermal_cooling_device_register(wiphy_name(wiphy), phy,
- &mt7915_thermal_ops);
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s",
+ wiphy_name(wiphy));
+
+ cdev = thermal_cooling_device_register(name, phy, &mt7915_thermal_ops);
if (!IS_ERR(cdev)) {
if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
"cooling_device") < 0)
@@ -144,15 +177,76 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
- hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
- wiphy_name(wiphy), phy,
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
mt7915_hwmon_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
+ /* initialize critical/maximum high temperature */
+ phy->throttle_temp[0] = 110;
+ phy->throttle_temp[1] = 120;
+
+ return 0;
+}
+
+static void mt7915_led_set_config(struct led_classdev *led_cdev,
+ u8 delay_on, u8 delay_off)
+{
+ struct mt7915_dev *dev;
+ struct mt76_dev *mt76;
+ u32 val;
+
+ mt76 = container_of(led_cdev, struct mt76_dev, led_cdev);
+ dev = container_of(mt76, struct mt7915_dev, mt76);
+
+ /* select TX blink mode, 2: only data frames */
+ mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2);
+
+ /* enable LED */
+ mt76_wr(dev, MT_LED_EN(0), 1);
+
+ /* set LED Tx blink on/off time */
+ val = FIELD_PREP(MT_LED_TX_BLINK_ON_MASK, delay_on) |
+ FIELD_PREP(MT_LED_TX_BLINK_OFF_MASK, delay_off);
+ mt76_wr(dev, MT_LED_TX_BLINK(0), val);
+
+ /* control LED */
+ val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK;
+ if (dev->mt76.led_al)
+ val |= MT_LED_CTRL_POLARITY;
+
+ mt76_wr(dev, MT_LED_CTRL(0), val);
+ mt76_clear(dev, MT_LED_CTRL(0), MT_LED_CTRL_KICK);
+}
+
+static int mt7915_led_set_blink(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ u16 delta_on = 0, delta_off = 0;
+
+#define HW_TICK 10
+#define TO_HW_TICK(_t) (((_t) > HW_TICK) ? ((_t) / HW_TICK) : HW_TICK)
+
+ if (*delay_on)
+ delta_on = TO_HW_TICK(*delay_on);
+ if (*delay_off)
+ delta_off = TO_HW_TICK(*delay_off);
+
+ mt7915_led_set_config(led_cdev, delta_on, delta_off);
+
return 0;
}
+static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ if (!brightness)
+ mt7915_led_set_config(led_cdev, 0, 0xff);
+ else
+ mt7915_led_set_config(led_cdev, 0xff, 0);
+}
+
static void
mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband)
@@ -232,7 +326,12 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
wiphy->reg_notifier = mt7915_regd_notifier;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
@@ -287,9 +386,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
- mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
-
- mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
+ mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 0x680);
/* disable rx rate report by default due to hw issues */
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}
@@ -298,7 +395,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
{
int i;
- mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
+ mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 0x400);
/* enable hardware de-agg */
mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
@@ -307,6 +404,11 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
for (i = 0; i < 2; i++)
mt7915_mac_init_band(dev, i);
+
+ if (IS_ENABLED(CONFIG_MT76_LEDS)) {
+ i = dev->mt76.led_pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2;
+ mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4);
+ }
}
static int mt7915_txbf_init(struct mt7915_dev *dev)
@@ -350,7 +452,6 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev)
mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask;
mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1;
- INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);
mt7915_eeprom_parse_band_config(phy);
@@ -374,6 +475,10 @@ static int mt7915_register_ext_phy(struct mt7915_dev *dev)
if (ret)
goto error;
+ ret = mt7915_init_debugfs(phy);
+ if (ret)
+ goto error;
+
return 0;
error:
@@ -480,7 +585,7 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
}
/* Beacon and mgmt frames should occupy wcid 0 */
- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
if (idx)
return -ENOSPC;
@@ -525,7 +630,6 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
int vif, int nss)
{
struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
- struct ieee80211_he_mcs_nss_supp *mcs = &he_cap->he_mcs_nss_supp;
u8 c;
#ifdef CONFIG_MAC80211_MESH
@@ -577,8 +681,11 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
- /* num_snd_dim */
- c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3);
+ /* num_snd_dim
+ * for mt7915, max supported nss is 2 for bw > 80MHz
+ */
+ c = (nss - 1) |
+ IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2;
elem->phy_cap_info[5] |= c;
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
@@ -613,12 +720,19 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
{
int i, idx = 0, nss = hweight8(phy->mt76->chainmask);
u16 mcs_map = 0;
+ u16 mcs_map_160 = 0;
for (i = 0; i < 8; i++) {
if (i < nss)
mcs_map |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
else
mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
+
+ /* Can do 1/2 of NSS streams in 160Mhz mode. */
+ if (i < nss / 2)
+ mcs_map_160 |= (IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2));
+ else
+ mcs_map_160 |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
}
for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
@@ -667,6 +781,8 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
switch (i) {
case NL80211_IFTYPE_AP:
+ he_cap_elem->mac_cap_info[0] |=
+ IEEE80211_HE_MAC_CAP0_TWT_RES;
he_cap_elem->mac_cap_info[2] |=
IEEE80211_HE_MAC_CAP2_BSR;
he_cap_elem->mac_cap_info[4] |=
@@ -677,7 +793,11 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
+ IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
+ he_cap_elem->phy_cap_info[9] |=
+ IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
+ IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
break;
case NL80211_IFTYPE_STATION:
he_cap_elem->mac_cap_info[1] |=
@@ -720,10 +840,10 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
- he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
- he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
- he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map);
- he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map);
+ he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map_160);
+ he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160);
+ he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map_160);
+ he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map_160);
mt7915_set_stream_he_txbf_caps(he_cap, i, nss);
@@ -787,11 +907,11 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
- INIT_LIST_HEAD(&dev->phy.stats_list);
INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
INIT_LIST_HEAD(&dev->sta_rc_list);
INIT_LIST_HEAD(&dev->sta_poll_list);
+ INIT_LIST_HEAD(&dev->twt_list);
spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
@@ -816,6 +936,12 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->mt76.test_ops = &mt7915_testmode_ops;
#endif
+ /* init led callbacks */
+ if (IS_ENABLED(CONFIG_MT76_LEDS)) {
+ dev->mt76.led_cdev.brightness_set = mt7915_led_set_brightness;
+ dev->mt76.led_cdev.blink_set = mt7915_led_set_blink;
+ }
+
ret = mt76_register_device(&dev->mt76, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
@@ -831,7 +957,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
if (ret)
return ret;
- return mt7915_init_debugfs(dev);
+ return mt7915_init_debugfs(&dev->phy);
}
void mt7915_unregister_device(struct mt7915_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 2462704094b0..21e6ef07814c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -6,6 +6,7 @@
#include "mt7915.h"
#include "../dma.h"
#include "mac.h"
+#include "mcu.h"
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
@@ -88,15 +89,14 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
0, 5000);
}
-static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid)
+static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
{
mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
- return MT_WTBL_LMAC_OFFS(wcid, 0);
+ return MT_WTBL_LMAC_OFFS(wcid, dw);
}
-/* TODO: use txfree airtime info to avoid runtime accessing in the long run */
static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
{
static const u8 ac_to_tid[] = {
@@ -107,6 +107,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
};
struct ieee80211_sta *sta;
struct mt7915_sta *msta;
+ struct rate_info *rate;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
int i;
@@ -119,8 +120,9 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
while (true) {
bool clear = false;
- u32 addr;
+ u32 addr, val;
u16 idx;
+ u8 bw;
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&sta_poll_list)) {
@@ -133,7 +135,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
spin_unlock_bh(&dev->sta_poll_lock);
idx = msta->wcid.idx;
- addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4;
+ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u32 tx_last = msta->airtime_ac[i];
@@ -174,6 +176,43 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
ieee80211_sta_register_airtime(sta, tid, tx_cur,
rx_cur);
}
+
+ /*
+ * We don't support reading GI info from txs packets.
+ * For accurate tx status reporting and AQL improvement,
+ * we need to make sure that flags match so polling GI
+ * from per-sta counters directly.
+ */
+ rate = &msta->wcid.rate;
+ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7);
+ val = mt76_rr(dev, addr);
+
+ switch (rate->bw) {
+ case RATE_INFO_BW_160:
+ bw = IEEE80211_STA_RX_BW_160;
+ break;
+ case RATE_INFO_BW_80:
+ bw = IEEE80211_STA_RX_BW_80;
+ break;
+ case RATE_INFO_BW_40:
+ bw = IEEE80211_STA_RX_BW_40;
+ break;
+ default:
+ bw = IEEE80211_STA_RX_BW_20;
+ break;
+ }
+
+ if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
+ u8 offs = 24 + 2 * bw;
+
+ rate->he_gi = (val & (0x3 << offs)) >> offs;
+ } else if (rate->flags &
+ (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
+ if (val & BIT(12 + bw))
+ rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+ else
+ rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
+ }
}
rcu_read_unlock();
@@ -229,11 +268,50 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
}
static void
+mt7915_mac_decode_he_mu_radiotap(struct sk_buff *skb,
+ struct mt76_rx_status *status,
+ __le32 *rxv)
+{
+ static const struct ieee80211_radiotap_he_mu mu_known = {
+ .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
+ HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
+ HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
+ HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
+ .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
+ };
+ struct ieee80211_radiotap_he_mu *he_mu = NULL;
+
+ he_mu = skb_push(skb, sizeof(mu_known));
+ memcpy(he_mu, &mu_known, sizeof(mu_known));
+
+#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
+
+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
+ if (status->he_dcm)
+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
+
+ he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
+ le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
+
+ he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
+
+ if (status->bw >= RATE_INFO_BW_40) {
+ he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
+ he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
+ }
+
+ if (status->bw >= RATE_INFO_BW_80) {
+ he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
+ he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
+ }
+}
+
+static void
mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
struct mt76_rx_status *status,
__le32 *rxv, u32 phy)
{
- /* TODO: struct ieee80211_radiotap_he_mu */
static const struct ieee80211_radiotap_he known = {
.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
HE_BITS(DATA1_DATA_DCM_KNOWN) |
@@ -241,6 +319,7 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
HE_BITS(DATA1_CODING_KNOWN) |
HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
HE_BITS(DATA1_DOPPLER_KNOWN) |
+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
HE_BITS(DATA1_BSS_COLOR_KNOWN),
.data2 = HE_BITS(DATA2_GI_KNOWN) |
HE_BITS(DATA2_TXBF_KNOWN) |
@@ -255,9 +334,12 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
+ he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
le16_encode_bits(ltf_size,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
+ he->data5 |= HE_BITS(DATA5_TXBF);
he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
@@ -265,12 +347,10 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
case MT_PHY_TYPE_HE_SU:
he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
HE_BITS(DATA1_UL_DL_KNOWN) |
- HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
- HE_BITS(DATA1_SPTL_REUSE_KNOWN);
+ HE_BITS(DATA1_BEAM_CHANGE_KNOWN);
he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
- he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
break;
case MT_PHY_TYPE_HE_EXT_SU:
he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
@@ -280,23 +360,20 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb,
break;
case MT_PHY_TYPE_HE_MU:
he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
- HE_BITS(DATA1_UL_DL_KNOWN) |
- HE_BITS(DATA1_SPTL_REUSE_KNOWN);
+ HE_BITS(DATA1_UL_DL_KNOWN);
he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
- he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
+ he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
mt7915_mac_decode_he_radiotap_ru(status, he, rxv);
break;
case MT_PHY_TYPE_HE_TB:
he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
- HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
- he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
- HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
+ he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
@@ -610,8 +687,11 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
status->flag |= RX_FLAG_8023;
}
- if (rxv && status->flag & RX_FLAG_RADIOTAP_HE)
+ if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) {
mt7915_mac_decode_he_radiotap(skb, status, rxv, mode);
+ if (status->flag & RX_FLAG_RADIOTAP_HE_MU)
+ mt7915_mac_decode_he_mu_radiotap(skb, status, rxv);
+ }
if (!status->wcid || !ieee80211_is_data_qos(fc))
return 0;
@@ -825,17 +905,19 @@ mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi,
static void
mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
- struct sk_buff *skb, struct ieee80211_key_conf *key)
+ struct sk_buff *skb, struct ieee80211_key_conf *key,
+ bool *mcast)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- bool multicast = is_multicast_ether_addr(hdr->addr1);
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
__le16 fc = hdr->frame_control;
u8 fc_type, fc_stype;
u32 val;
+ *mcast = is_multicast_ether_addr(hdr->addr1);
+
if (ieee80211_is_action(fc) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
@@ -861,15 +943,16 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
- FIELD_PREP(MT_TXD2_MULTICAST, multicast);
+ FIELD_PREP(MT_TXD2_MULTICAST, *mcast);
- if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+ if (key && *mcast && ieee80211_is_robust_mgmt_frame(skb) &&
key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
val |= MT_TXD2_BIP;
txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
}
- if (!ieee80211_is_data(fc) || multicast)
+ if (!ieee80211_is_data(fc) || *mcast ||
+ info->flags & IEEE80211_TX_CTL_USE_MINRATE)
val |= MT_TXD2_FIX_RATE;
txwi[2] |= cpu_to_le32(val);
@@ -899,6 +982,51 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
txwi[7] |= cpu_to_le32(val);
}
+static u16
+mt7915_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif,
+ bool beacon, bool mcast)
+{
+ u8 mode = 0, band = mphy->chandef.chan->band;
+ int rateidx = 0, mcast_rate;
+
+ if (beacon) {
+ struct cfg80211_bitrate_mask *mask;
+
+ mask = &vif->bss_conf.beacon_tx_rate;
+ if (hweight16(mask->control[band].he_mcs[0]) == 1) {
+ rateidx = ffs(mask->control[band].he_mcs[0]) - 1;
+ mode = MT_PHY_TYPE_HE_SU;
+ goto out;
+ } else if (hweight16(mask->control[band].vht_mcs[0]) == 1) {
+ rateidx = ffs(mask->control[band].vht_mcs[0]) - 1;
+ mode = MT_PHY_TYPE_VHT;
+ goto out;
+ } else if (hweight8(mask->control[band].ht_mcs[0]) == 1) {
+ rateidx = ffs(mask->control[band].ht_mcs[0]) - 1;
+ mode = MT_PHY_TYPE_HT;
+ goto out;
+ } else if (hweight32(mask->control[band].legacy) == 1) {
+ rateidx = ffs(mask->control[band].legacy) - 1;
+ goto legacy;
+ }
+ }
+
+ mcast_rate = vif->bss_conf.mcast_rate[band];
+ if (mcast && mcast_rate > 0)
+ rateidx = mcast_rate - 1;
+ else
+ rateidx = ffs(vif->bss_conf.basic_rates) - 1;
+
+legacy:
+ rateidx = mt76_calculate_default_rate(mphy, rateidx);
+ mode = rateidx >> 8;
+ rateidx &= GENMASK(7, 0);
+
+out:
+ return FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
+ FIELD_PREP(MT_TX_RATE_MODE, mode);
+}
+
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, bool beacon)
@@ -909,6 +1037,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+ bool mcast = false;
u16 tx_count = 15;
u32 val;
@@ -939,7 +1068,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
txwi[0] = cpu_to_le32(val);
- val = MT_TXD1_LONG_FORMAT |
+ val = MT_TXD1_LONG_FORMAT | MT_TXD1_VTA |
FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
@@ -971,19 +1100,14 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
if (is_8023)
mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid);
else
- mt7915_mac_write_txwi_80211(dev, txwi, skb, key);
+ mt7915_mac_write_txwi_80211(dev, txwi, skb, key, &mcast);
if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
- u16 rate;
+ u16 rate = mt7915_mac_tx_rate_val(mphy, vif, beacon, mcast);
/* hardware won't add HTC for mgmt/ctrl frame */
txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
- if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
- rate = MT7915_5G_RATE_DEFAULT;
- else
- rate = MT7915_2G_RATE_DEFAULT;
-
val = MT_TXD6_FIXED_BW |
FIELD_PREP(MT_TXD6_TX_RATE, rate);
txwi[6] |= cpu_to_le32(val);
@@ -1016,6 +1140,17 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
+ if (sta) {
+ struct mt7915_sta *msta;
+
+ msta = (struct mt7915_sta *)sta->drv_priv;
+
+ if (time_after(jiffies, msta->jiffies + HZ / 4)) {
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ msta->jiffies = jiffies;
+ }
+ }
+
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
@@ -1162,7 +1297,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
count = FIELD_GET(MT_TX_FREE_MSDU_CNT, le16_to_cpu(free->ctrl));
for (i = 0; i < count; i++) {
u32 msdu, info = le32_to_cpu(free->info[i]);
- u8 stat;
/*
* 1'b1: new wcid pair.
@@ -1170,7 +1304,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
*/
if (info & MT_TX_FREE_PAIR) {
struct mt7915_sta *msta;
- struct mt7915_phy *phy;
struct mt76_wcid *wcid;
u16 idx;
@@ -1182,10 +1315,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
continue;
msta = container_of(wcid, struct mt7915_sta, wcid);
- phy = msta->vif->phy;
spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->stats_list))
- list_add_tail(&msta->stats_list, &phy->stats_list);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
@@ -1193,8 +1323,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
}
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
- stat = FIELD_GET(MT_TX_FREE_STATUS, info);
-
txwi = mt76_token_release(mdev, msdu, &wake);
if (!txwi)
continue;
@@ -1219,20 +1347,27 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
static bool
mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
- __le32 *txs_data)
+ __le32 *txs_data, struct mt76_sta_stats *stats)
{
+ struct ieee80211_supported_band *sband;
struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_phy *mphy;
struct ieee80211_tx_info *info;
struct sk_buff_head list;
+ struct rate_info rate = {};
struct sk_buff *skb;
+ bool cck = false;
+ u32 txrate, txs, mode;
mt76_tx_status_lock(mdev, &list);
skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
if (!skb)
- goto out;
+ goto out_no_skb;
+
+ txs = le32_to_cpu(txs_data[0]);
info = IEEE80211_SKB_CB(skb);
- if (!(txs_data[0] & le32_to_cpu(MT_TXS0_ACK_ERROR_MASK)))
+ if (!(txs & MT_TXS0_ACK_ERROR_MASK))
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ampdu_len = 1;
@@ -1240,9 +1375,92 @@ mt7915_mac_add_txs_skb(struct mt7915_dev *dev, struct mt76_wcid *wcid, int pid,
IEEE80211_TX_STAT_ACK);
info->status.rates[0].idx = -1;
- mt76_tx_status_skb_done(mdev, skb, &list);
+
+ txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+
+ rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+ rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+
+ if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
+ stats->tx_nss[rate.nss - 1]++;
+ if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
+ stats->tx_mcs[rate.mcs]++;
+
+ mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
+ switch (mode) {
+ case MT_PHY_TYPE_CCK:
+ cck = true;
+ fallthrough;
+ case MT_PHY_TYPE_OFDM:
+ mphy = &dev->mphy;
+ if (wcid->ext_phy && dev->mt76.phy2)
+ mphy = dev->mt76.phy2;
+
+ if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &mphy->sband_5g.sband;
+ else
+ sband = &mphy->sband_2g.sband;
+
+ rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
+ rate.legacy = sband->bitrates[rate.mcs].bitrate;
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ rate.mcs += (rate.nss - 1) * 8;
+ if (rate.mcs > 31)
+ goto out;
+
+ rate.flags = RATE_INFO_FLAGS_MCS;
+ if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+ rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT_PHY_TYPE_VHT:
+ if (rate.mcs > 9)
+ goto out;
+
+ rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ break;
+ case MT_PHY_TYPE_HE_SU:
+ case MT_PHY_TYPE_HE_EXT_SU:
+ case MT_PHY_TYPE_HE_TB:
+ case MT_PHY_TYPE_HE_MU:
+ if (rate.mcs > 11)
+ goto out;
+
+ rate.he_gi = wcid->rate.he_gi;
+ rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
+ rate.flags = RATE_INFO_FLAGS_HE_MCS;
+ break;
+ default:
+ goto out;
+ }
+
+ stats->tx_mode[mode]++;
+
+ switch (FIELD_GET(MT_TXS0_BW, txs)) {
+ case IEEE80211_STA_RX_BW_160:
+ rate.bw = RATE_INFO_BW_160;
+ stats->tx_bw[3]++;
+ break;
+ case IEEE80211_STA_RX_BW_80:
+ rate.bw = RATE_INFO_BW_80;
+ stats->tx_bw[2]++;
+ break;
+ case IEEE80211_STA_RX_BW_40:
+ rate.bw = RATE_INFO_BW_40;
+ stats->tx_bw[1]++;
+ break;
+ default:
+ rate.bw = RATE_INFO_BW_20;
+ stats->tx_bw[0]++;
+ break;
+ }
+ wcid->rate = rate;
out:
+ mt76_tx_status_skb_done(mdev, skb, &list);
+
+out_no_skb:
mt76_tx_status_unlock(mdev, &list);
return !!skb;
@@ -1279,12 +1497,13 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
if (!wcid)
goto out;
- mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data);
+ msta = container_of(wcid, struct mt7915_sta, wcid);
+
+ mt7915_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
if (!wcid->sta)
goto out;
- msta = container_of(wcid, struct mt7915_sta, wcid);
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
@@ -1333,15 +1552,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
- struct mt7915_dev *dev;
-
if (!e->txwi) {
dev_kfree_skb_any(e->skb);
return;
}
- dev = container_of(mdev, struct mt7915_dev, mt76);
-
/* error path */
if (e->skb == DMA_DUMMY_DATA) {
struct mt76_txwi_cache *t;
@@ -1403,17 +1618,12 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy)
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
- int sifs, offset;
+ int offset;
bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ;
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
return;
- if (is_5ghz)
- sifs = 16;
- else
- sifs = 10;
-
if (ext_phy) {
coverage_class = max_t(s16, dev->phy.coverage_class,
coverage_class);
@@ -1435,11 +1645,14 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy)
mt76_wr(dev, MT_TMAC_CDTR(ext_phy), cck + reg_offset);
mt76_wr(dev, MT_TMAC_ODTR(ext_phy), ofdm + reg_offset);
mt76_wr(dev, MT_TMAC_ICR0(ext_phy),
- FIELD_PREP(MT_IFS_EIFS, 360) |
+ FIELD_PREP(MT_IFS_EIFS_OFDM, is_5ghz ? 84 : 78) |
FIELD_PREP(MT_IFS_RIFS, 2) |
- FIELD_PREP(MT_IFS_SIFS, sifs) |
+ FIELD_PREP(MT_IFS_SIFS, 10) |
FIELD_PREP(MT_IFS_SLOT, phy->slottime));
+ mt76_wr(dev, MT_TMAC_ICR1(ext_phy),
+ FIELD_PREP(MT_IFS_EIFS_CCK, 314));
+
if (phy->slottime < 20 || is_5ghz)
val = MT7915_CFEND_RATE_DEFAULT;
else
@@ -1580,7 +1793,7 @@ mt7915_dma_reset(struct mt7915_dev *dev)
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
- mt76_tx_status_check(&dev->mt76, NULL, true);
+ mt76_tx_status_check(&dev->mt76, true);
/* re-init prefetch settings after reset */
mt7915_dma_prefetch(dev);
@@ -1668,6 +1881,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (phy2)
clear_bit(MT76_RESET, &phy2->mt76->state);
+ local_bh_disable();
napi_enable(&dev->mt76.napi[0]);
napi_schedule(&dev->mt76.napi[0]);
@@ -1676,6 +1890,8 @@ void mt7915_mac_reset_work(struct work_struct *work)
napi_enable(&dev->mt76.napi[2]);
napi_schedule(&dev->mt76.napi[2]);
+ local_bh_enable();
+
tasklet_schedule(&dev->irq_tasklet);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
@@ -1702,17 +1918,117 @@ void mt7915_mac_reset_work(struct work_struct *work)
MT7915_WATCHDOG_TIME);
}
-static void
-mt7915_mac_update_stats(struct mt7915_phy *phy)
+void mt7915_mac_update_stats(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mib_stats *mib = &phy->mib;
bool ext_phy = phy != &dev->phy;
- int i, aggr0, aggr1;
+ int i, aggr0, aggr1, cnt;
mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy),
MT_MIB_SDR3_FCS_ERR_MASK);
+ cnt = mt76_rr(dev, MT_MIB_SDR4(ext_phy));
+ mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR5(ext_phy));
+ mib->rx_mpdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR6(ext_phy));
+ mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR7(ext_phy));
+ mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR8(ext_phy));
+ mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR11(ext_phy));
+ mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR12(ext_phy));
+ mib->tx_ampdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR13(ext_phy));
+ mib->tx_stop_q_empty_cnt += FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR14(ext_phy));
+ mib->tx_mpdu_attempts_cnt += FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR15(ext_phy));
+ mib->tx_mpdu_success_cnt += FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR22(ext_phy));
+ mib->rx_ampdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR23(ext_phy));
+ mib->rx_ampdu_bytes_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR24(ext_phy));
+ mib->rx_ampdu_valid_subframe_cnt += FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR25(ext_phy));
+ mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR27(ext_phy));
+ mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR28(ext_phy));
+ mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR29(ext_phy));
+ mib->rx_pfdrop_cnt += FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR30(ext_phy));
+ mib->rx_vec_queue_overflow_drop_cnt +=
+ FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR31(ext_phy));
+ mib->rx_ba_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_SDR32(ext_phy));
+ mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR33(ext_phy));
+ mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT_MASK, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy));
+ mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt);
+
+ cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy));
+ mib->tx_mu_mpdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy));
+ mib->tx_mu_acked_mpdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy));
+ mib->tx_su_acked_mpdu_cnt += cnt;
+
+ cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy));
+ mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt);
+ mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt);
+
+ cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy));
+ mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt);
+ mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt);
+ mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt);
+ mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, cnt);
+
+ cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(ext_phy));
+ mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
+ mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
+ mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
+
+ cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy));
+ mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt);
+ mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt);
+
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
+ cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
+ mib->tx_amsdu[i] += cnt;
+ mib->tx_amsdu_cnt += cnt;
+ }
+
aggr0 = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) {
u32 val;
@@ -1737,30 +2053,6 @@ mt7915_mac_update_stats(struct mt7915_phy *phy)
}
}
-static void
-mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
-{
- struct mt7915_dev *dev = phy->dev;
- struct mt7915_sta *msta;
- LIST_HEAD(list);
-
- spin_lock_bh(&dev->sta_poll_lock);
- list_splice_init(&phy->stats_list, &list);
-
- while (!list_empty(&list)) {
- msta = list_first_entry(&list, struct mt7915_sta, stats_list);
- list_del_init(&msta->stats_list);
- spin_unlock_bh(&dev->sta_poll_lock);
-
- /* use MT_TX_FREE_RATE to report Tx rate for further devices */
- mt7915_mcu_get_tx_rate(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
-
- spin_lock_bh(&dev->sta_poll_lock);
- }
-
- spin_unlock_bh(&dev->sta_poll_lock);
-}
-
void mt7915_mac_sta_rc_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
@@ -1776,8 +2068,8 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
while (!list_empty(&list)) {
msta = list_first_entry(&list, struct mt7915_sta, rc_list);
list_del_init(&msta->rc_list);
- changed = msta->stats.changed;
- msta->stats.changed = 0;
+ changed = msta->changed;
+ msta->changed = 0;
spin_unlock_bh(&dev->sta_poll_lock);
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
@@ -1817,14 +2109,9 @@ void mt7915_mac_work(struct work_struct *work)
mt7915_mac_update_stats(phy);
}
- if (++phy->sta_work_count == 10) {
- phy->sta_work_count = 0;
- mt7915_mac_sta_stats_work(phy);
- }
-
mutex_unlock(&mphy->dev->mutex);
- mt76_tx_status_check(mphy->dev, NULL, false);
+ mt76_tx_status_check(mphy->dev, false);
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
MT7915_WATCHDOG_TIME);
@@ -1961,3 +2248,182 @@ stop:
mt7915_dfs_stop_radar_detector(phy);
return 0;
}
+
+static int
+mt7915_mac_twt_duration_align(int duration)
+{
+ return duration << 8;
+}
+
+static u64
+mt7915_mac_twt_sched_list_add(struct mt7915_dev *dev,
+ struct mt7915_twt_flow *flow)
+{
+ struct mt7915_twt_flow *iter, *iter_next;
+ u32 duration = flow->duration << 8;
+ u64 start_tsf;
+
+ iter = list_first_entry_or_null(&dev->twt_list,
+ struct mt7915_twt_flow, list);
+ if (!iter || !iter->sched || iter->start_tsf > duration) {
+ /* add flow as first entry in the list */
+ list_add(&flow->list, &dev->twt_list);
+ return 0;
+ }
+
+ list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
+ start_tsf = iter->start_tsf +
+ mt7915_mac_twt_duration_align(iter->duration);
+ if (list_is_last(&iter->list, &dev->twt_list))
+ break;
+
+ if (!iter_next->sched ||
+ iter_next->start_tsf > start_tsf + duration) {
+ list_add(&flow->list, &iter->list);
+ goto out;
+ }
+ }
+
+ /* add flow as last entry in the list */
+ list_add_tail(&flow->list, &dev->twt_list);
+out:
+ return start_tsf;
+}
+
+static int mt7915_mac_check_twt_req(struct ieee80211_twt_setup *twt)
+{
+ struct ieee80211_twt_params *twt_agrt;
+ u64 interval, duration;
+ u16 mantissa;
+ u8 exp;
+
+ /* only individual agreement supported */
+ if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
+ return -EOPNOTSUPP;
+
+ /* only 256us unit supported */
+ if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
+ return -EOPNOTSUPP;
+
+ twt_agrt = (struct ieee80211_twt_params *)twt->params;
+
+ /* explicit agreement not supported */
+ if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
+ return -EOPNOTSUPP;
+
+ exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
+ le16_to_cpu(twt_agrt->req_type));
+ mantissa = le16_to_cpu(twt_agrt->mantissa);
+ duration = twt_agrt->min_twt_dur << 8;
+
+ interval = (u64)mantissa << exp;
+ if (interval < duration)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct ieee80211_twt_setup *twt)
+{
+ enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
+ u16 req_type = le16_to_cpu(twt_agrt->req_type);
+ enum ieee80211_twt_setup_cmd sta_setup_cmd;
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ struct mt7915_twt_flow *flow;
+ int flowid, table_id;
+ u8 exp;
+
+ if (mt7915_mac_check_twt_req(twt))
+ goto out;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ if (dev->twt.n_agrt == MT7915_MAX_TWT_AGRT)
+ goto unlock;
+
+ if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
+ goto unlock;
+
+ flowid = ffs(~msta->twt.flowid_mask) - 1;
+ le16p_replace_bits(&twt_agrt->req_type, flowid,
+ IEEE80211_TWT_REQTYPE_FLOWID);
+
+ table_id = ffs(~dev->twt.table_mask) - 1;
+ exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
+ sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
+
+ flow = &msta->twt.flow[flowid];
+ memset(flow, 0, sizeof(*flow));
+ INIT_LIST_HEAD(&flow->list);
+ flow->wcid = msta->wcid.idx;
+ flow->table_id = table_id;
+ flow->id = flowid;
+ flow->duration = twt_agrt->min_twt_dur;
+ flow->mantissa = twt_agrt->mantissa;
+ flow->exp = exp;
+ flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
+ flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
+ flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
+
+ if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
+ sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
+ u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
+ u64 flow_tsf, curr_tsf;
+ u32 rem;
+
+ flow->sched = true;
+ flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow);
+ curr_tsf = __mt7915_get_tsf(hw, msta->vif);
+ div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
+ flow_tsf = curr_tsf + interval - rem;
+ twt_agrt->twt = cpu_to_le64(flow_tsf);
+ } else {
+ list_add_tail(&flow->list, &dev->twt_list);
+ }
+ flow->tsf = le64_to_cpu(twt_agrt->twt);
+
+ if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
+ goto unlock;
+
+ setup_cmd = TWT_SETUP_CMD_ACCEPT;
+ dev->twt.table_mask |= BIT(table_id);
+ msta->twt.flowid_mask |= BIT(flowid);
+ dev->twt.n_agrt++;
+
+unlock:
+ mutex_unlock(&dev->mt76.mutex);
+out:
+ le16p_replace_bits(&twt_agrt->req_type, setup_cmd,
+ IEEE80211_TWT_REQTYPE_SETUP_CMD);
+ twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
+ (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
+}
+
+void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
+ struct mt7915_sta *msta,
+ u8 flowid)
+{
+ struct mt7915_twt_flow *flow;
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+ if (flowid >= ARRAY_SIZE(msta->twt.flow))
+ return;
+
+ if (!(msta->twt.flowid_mask & BIT(flowid)))
+ return;
+
+ flow = &msta->twt.flow[flowid];
+ if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow,
+ MCU_TWT_AGRT_DELETE))
+ return;
+
+ list_del_init(&flow->list);
+ msta->twt.flowid_mask &= ~BIT(flowid);
+ dev->twt.table_mask &= ~BIT(flow->table_id);
+ dev->twt.n_agrt--;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
index eb1885f4bd8e..7a2c740d1464 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
@@ -117,6 +117,7 @@ enum rx_pkt_type {
#define MT_PRXV_TX_DCM BIT(4)
#define MT_PRXV_TX_ER_SU_106T BIT(5)
#define MT_PRXV_NSTS GENMASK(9, 7)
+#define MT_PRXV_TXBF BIT(10)
#define MT_PRXV_HT_AD_CODE BIT(11)
#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28)
#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0)
@@ -133,7 +134,14 @@ enum rx_pkt_type {
#define MT_CRXV_HE_LTF_SIZE GENMASK(18, 17)
#define MT_CRXV_HE_LDPC_EXT_SYM BIT(20)
#define MT_CRXV_HE_PE_DISAMBIG BIT(23)
+#define MT_CRXV_HE_NUM_USER GENMASK(30, 24)
#define MT_CRXV_HE_UPLINK BIT(31)
+#define MT_CRXV_HE_RU0 GENMASK(7, 0)
+#define MT_CRXV_HE_RU1 GENMASK(15, 8)
+#define MT_CRXV_HE_RU2 GENMASK(23, 16)
+#define MT_CRXV_HE_RU3 GENMASK(31, 24)
+
+#define MT_CRXV_HE_MU_AID GENMASK(30, 20)
#define MT_CRXV_HE_SR_MASK GENMASK(11, 8)
#define MT_CRXV_HE_SR1_MASK GENMASK(16, 12)
@@ -272,7 +280,8 @@ enum tx_mcu_port_q_idx {
#define MT_TX_RATE_MODE GENMASK(9, 6)
#define MT_TX_RATE_SU_EXT_TONE BIT(5)
#define MT_TX_RATE_DCM BIT(4)
-#define MT_TX_RATE_IDX GENMASK(3, 0)
+/* VHT/HE only use bits 0-3 */
+#define MT_TX_RATE_IDX GENMASK(5, 0)
#define MT_TXP_MAX_BUF_NUM 6
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index c25f8da590dd..8be78917dee9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -215,7 +215,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mvif->phy = phy;
mvif->band_idx = ext_phy;
- if (ext_phy)
+ if (dev->mt76.phy2)
mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) +
mvif->idx % (MT7915_MAX_WMM_SETS / 2);
else
@@ -231,12 +231,13 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
idx = MT7915_WTBL_RESERVED - mvif->idx;
INIT_LIST_HEAD(&mvif->sta.rc_list);
- INIT_LIST_HEAD(&mvif->sta.stats_list);
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.ext_phy = mvif->band_idx;
mvif->sta.wcid.hw_key_idx = -1;
mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
+ mt76_packet_id_init(&mvif->sta.wcid);
+
mt7915_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -252,6 +253,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
mt7915_init_bitrate_mask(vif);
+ memset(&mvif->cap, -1, sizeof(mvif->cap));
out:
mutex_unlock(&dev->mt76.mutex);
@@ -291,6 +293,8 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
+
+ mt76_packet_id_flush(&dev->mt76, &msta->wcid);
}
static void mt7915_init_dfs_state(struct mt7915_phy *phy)
@@ -538,6 +542,29 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw,
mutex_unlock(&dev->mt76.mutex);
}
+static void
+mt7915_update_bss_color(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_he_bss_color *bss_color)
+{
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP: {
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+
+ if (mvif->omac_idx > HW_BSSID_MAX)
+ return;
+ fallthrough;
+ }
+ case NL80211_IFTYPE_STATION:
+ mt7915_mcu_update_bss_color(dev, vif, bss_color);
+ break;
+ default:
+ break;
+ }
+}
+
static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -586,6 +613,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_HE_OBSS_PD)
mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable);
+ if (changed & BSS_CHANGED_HE_BSS_COLOR)
+ mt7915_update_bss_color(hw, vif, &info->he_bss_color);
+
if (changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED))
mt7915_mcu_add_beacon(hw, vif, info->enable_beacon);
@@ -613,19 +643,18 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
int ret, idx;
- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
if (idx < 0)
return -ENOSPC;
INIT_LIST_HEAD(&msta->rc_list);
- INIT_LIST_HEAD(&msta->stats_list);
INIT_LIST_HEAD(&msta->poll_list);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
msta->wcid.ext_phy = mvif->band_idx;
msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
- msta->stats.jiffies = jiffies;
+ msta->jiffies = jiffies;
mt7915_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -634,7 +663,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (ret)
return ret;
- return mt7915_mcu_add_sta_adv(dev, vif, sta, true);
+ return mt7915_mcu_add_rate_ctrl(dev, vif, sta);
}
void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -642,18 +671,19 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ int i;
- mt7915_mcu_add_sta_adv(dev, vif, sta, false);
mt7915_mcu_add_sta(dev, vif, sta, false);
mt7915_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+ for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
+ mt7915_mac_twt_teardown_flow(dev, msta, i);
+
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
- if (!list_empty(&msta->stats_list))
- list_del_init(&msta->stats_list);
if (!list_empty(&msta->rc_list))
list_del_init(&msta->rc_list);
spin_unlock_bh(&dev->sta_poll_lock);
@@ -781,22 +811,19 @@ mt7915_get_stats(struct ieee80211_hw *hw,
struct mib_stats *mib = &phy->mib;
mutex_lock(&dev->mt76.mutex);
+
stats->dot11RTSSuccessCount = mib->rts_cnt;
stats->dot11RTSFailureCount = mib->rts_retries_cnt;
stats->dot11FCSErrorCount = mib->fcs_err_cnt;
stats->dot11ACKFailureCount = mib->ack_fail_cnt;
- memset(mib, 0, sizeof(*mib));
-
mutex_unlock(&dev->mt76.mutex);
return 0;
}
-static u64
-mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif)
{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
bool band = phy != &dev->phy;
@@ -806,7 +833,7 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
} tsf;
u16 n;
- mutex_lock(&dev->mt76.mutex);
+ lockdep_assert_held(&dev->mt76.mutex);
n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx;
/* TSF software read */
@@ -815,9 +842,21 @@ mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band));
tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band));
+ return tsf.t64;
+}
+
+static u64
+mt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ u64 ret;
+
+ mutex_lock(&dev->mt76.mutex);
+ ret = __mt7915_get_tsf(hw, mvif);
mutex_unlock(&dev->mt76.mutex);
- return tsf.t64;
+ return ret;
}
static void
@@ -926,7 +965,7 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct mt7915_sta_stats *stats = &msta->stats;
+ struct rate_info *txrate = &msta->wcid.rate;
struct rate_info rxrate = {};
if (!mt7915_mcu_get_rx_rate(phy, vif, sta, &rxrate)) {
@@ -934,20 +973,20 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
}
- if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
+ if (!txrate->legacy && !txrate->flags)
return;
- if (stats->tx_rate.legacy) {
- sinfo->txrate.legacy = stats->tx_rate.legacy;
+ if (txrate->legacy) {
+ sinfo->txrate.legacy = txrate->legacy;
} else {
- sinfo->txrate.mcs = stats->tx_rate.mcs;
- sinfo->txrate.nss = stats->tx_rate.nss;
- sinfo->txrate.bw = stats->tx_rate.bw;
- sinfo->txrate.he_gi = stats->tx_rate.he_gi;
- sinfo->txrate.he_dcm = stats->tx_rate.he_dcm;
- sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc;
+ sinfo->txrate.mcs = txrate->mcs;
+ sinfo->txrate.nss = txrate->nss;
+ sinfo->txrate.bw = txrate->bw;
+ sinfo->txrate.he_gi = txrate->he_gi;
+ sinfo->txrate.he_dcm = txrate->he_dcm;
+ sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
}
- sinfo->txrate.flags = stats->tx_rate.flags;
+ sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
@@ -959,7 +998,7 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
u32 *changed = data;
spin_lock_bh(&dev->sta_poll_lock);
- msta->stats.changed |= *changed;
+ msta->changed |= *changed;
if (list_empty(&msta->rc_list))
list_add_tail(&msta->rc_list, &dev->sta_rc_list);
spin_unlock_bh(&dev->sta_poll_lock);
@@ -1032,6 +1071,240 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw,
mt7915_mcu_sta_update_hdr_trans(dev, vif, sta);
}
+static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
+ "tx_ampdu_cnt",
+ "tx_stop_q_empty_cnt",
+ "tx_mpdu_attempts",
+ "tx_mpdu_success",
+ "tx_rwp_fail_cnt",
+ "tx_rwp_need_cnt",
+ "tx_pkt_ebf_cnt",
+ "tx_pkt_ibf_cnt",
+ "tx_ampdu_len:0-1",
+ "tx_ampdu_len:2-10",
+ "tx_ampdu_len:11-19",
+ "tx_ampdu_len:20-28",
+ "tx_ampdu_len:29-37",
+ "tx_ampdu_len:38-46",
+ "tx_ampdu_len:47-55",
+ "tx_ampdu_len:56-79",
+ "tx_ampdu_len:80-103",
+ "tx_ampdu_len:104-127",
+ "tx_ampdu_len:128-151",
+ "tx_ampdu_len:152-175",
+ "tx_ampdu_len:176-199",
+ "tx_ampdu_len:200-223",
+ "tx_ampdu_len:224-247",
+ "ba_miss_count",
+ "tx_beamformer_ppdu_iBF",
+ "tx_beamformer_ppdu_eBF",
+ "tx_beamformer_rx_feedback_all",
+ "tx_beamformer_rx_feedback_he",
+ "tx_beamformer_rx_feedback_vht",
+ "tx_beamformer_rx_feedback_ht",
+ "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */
+ "tx_beamformer_rx_feedback_nc",
+ "tx_beamformer_rx_feedback_nr",
+ "tx_beamformee_ok_feedback_pkts",
+ "tx_beamformee_feedback_trig",
+ "tx_mu_beamforming",
+ "tx_mu_mpdu",
+ "tx_mu_successful_mpdu",
+ "tx_su_successful_mpdu",
+ "tx_msdu_pack_1",
+ "tx_msdu_pack_2",
+ "tx_msdu_pack_3",
+ "tx_msdu_pack_4",
+ "tx_msdu_pack_5",
+ "tx_msdu_pack_6",
+ "tx_msdu_pack_7",
+ "tx_msdu_pack_8",
+
+ /* rx counters */
+ "rx_fifo_full_cnt",
+ "rx_mpdu_cnt",
+ "channel_idle_cnt",
+ "rx_vector_mismatch_cnt",
+ "rx_delimiter_fail_cnt",
+ "rx_len_mismatch_cnt",
+ "rx_ampdu_cnt",
+ "rx_ampdu_bytes_cnt",
+ "rx_ampdu_valid_subframe_cnt",
+ "rx_ampdu_valid_subframe_b_cnt",
+ "rx_pfdrop_cnt",
+ "rx_vec_queue_overflow_drop_cnt",
+ "rx_ba_cnt",
+
+ /* per vif counters */
+ "v_tx_mode_cck",
+ "v_tx_mode_ofdm",
+ "v_tx_mode_ht",
+ "v_tx_mode_ht_gf",
+ "v_tx_mode_vht",
+ "v_tx_mode_he_su",
+ "v_tx_mode_he_ext_su",
+ "v_tx_mode_he_tb",
+ "v_tx_mode_he_mu",
+ "v_tx_bw_20",
+ "v_tx_bw_40",
+ "v_tx_bw_80",
+ "v_tx_bw_160",
+ "v_tx_mcs_0",
+ "v_tx_mcs_1",
+ "v_tx_mcs_2",
+ "v_tx_mcs_3",
+ "v_tx_mcs_4",
+ "v_tx_mcs_5",
+ "v_tx_mcs_6",
+ "v_tx_mcs_7",
+ "v_tx_mcs_8",
+ "v_tx_mcs_9",
+ "v_tx_mcs_10",
+ "v_tx_mcs_11",
+};
+
+#define MT7915_SSTATS_LEN ARRAY_SIZE(mt7915_gstrings_stats)
+
+/* Ethtool related API */
+static
+void mt7915_get_et_strings(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u32 sset, u8 *data)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(data, *mt7915_gstrings_stats,
+ sizeof(mt7915_gstrings_stats));
+}
+
+static
+int mt7915_get_et_sset_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return MT7915_SSTATS_LEN;
+
+ return 0;
+}
+
+static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+{
+ struct mt76_ethtool_worker_info *wi = wi_data;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+
+ if (msta->vif->idx != wi->idx)
+ return;
+
+ mt76_ethtool_worker(wi, &msta->stats);
+}
+
+static
+void mt7915_get_et_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt76_ethtool_worker_info wi = {
+ .data = data,
+ .idx = mvif->idx,
+ };
+ struct mib_stats *mib = &phy->mib;
+ /* See mt7915_ampdu_stat_read_phy, etc */
+ bool ext_phy = phy != &dev->phy;
+ int i, n, ei = 0;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ mt7915_mac_update_stats(phy);
+
+ data[ei++] = mib->tx_ampdu_cnt;
+ data[ei++] = mib->tx_stop_q_empty_cnt;
+ data[ei++] = mib->tx_mpdu_attempts_cnt;
+ data[ei++] = mib->tx_mpdu_success_cnt;
+ data[ei++] = mib->tx_rwp_fail_cnt;
+ data[ei++] = mib->tx_rwp_need_cnt;
+ data[ei++] = mib->tx_pkt_ebf_cnt;
+ data[ei++] = mib->tx_pkt_ibf_cnt;
+
+ /* Tx ampdu stat */
+ n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
+ for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++)
+ data[ei++] = dev->mt76.aggr_stats[i + n];
+
+ data[ei++] = phy->mib.ba_miss_cnt;
+
+ /* Tx Beamformer monitor */
+ data[ei++] = mib->tx_bf_ibf_ppdu_cnt;
+ data[ei++] = mib->tx_bf_ebf_ppdu_cnt;
+
+ /* Tx Beamformer Rx feedback monitor */
+ data[ei++] = mib->tx_bf_rx_fb_all_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_he_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_vht_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_ht_cnt;
+
+ data[ei++] = mib->tx_bf_rx_fb_bw;
+ data[ei++] = mib->tx_bf_rx_fb_nc_cnt;
+ data[ei++] = mib->tx_bf_rx_fb_nr_cnt;
+
+ /* Tx Beamformee Rx NDPA & Tx feedback report */
+ data[ei++] = mib->tx_bf_fb_cpl_cnt;
+ data[ei++] = mib->tx_bf_fb_trig_cnt;
+
+ /* Tx SU & MU counters */
+ data[ei++] = mib->tx_bf_cnt;
+ data[ei++] = mib->tx_mu_mpdu_cnt;
+ data[ei++] = mib->tx_mu_acked_mpdu_cnt;
+ data[ei++] = mib->tx_su_acked_mpdu_cnt;
+
+ /* Tx amsdu info (pack-count histogram) */
+ for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++)
+ data[ei++] = mib->tx_amsdu[i];
+
+ /* rx counters */
+ data[ei++] = mib->rx_fifo_full_cnt;
+ data[ei++] = mib->rx_mpdu_cnt;
+ data[ei++] = mib->channel_idle_cnt;
+ data[ei++] = mib->rx_vector_mismatch_cnt;
+ data[ei++] = mib->rx_delimiter_fail_cnt;
+ data[ei++] = mib->rx_len_mismatch_cnt;
+ data[ei++] = mib->rx_ampdu_cnt;
+ data[ei++] = mib->rx_ampdu_bytes_cnt;
+ data[ei++] = mib->rx_ampdu_valid_subframe_cnt;
+ data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt;
+ data[ei++] = mib->rx_pfdrop_cnt;
+ data[ei++] = mib->rx_vec_queue_overflow_drop_cnt;
+ data[ei++] = mib->rx_ba_cnt;
+
+ /* Add values for all stations owned by this vif */
+ wi.initial_stat_idx = ei;
+ ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi);
+
+ mutex_unlock(&dev->mt76.mutex);
+
+ if (wi.sta_count == 0)
+ return;
+
+ ei += wi.worker_stat_count;
+ if (ei != MT7915_SSTATS_LEN)
+ dev_err(dev->mt76.dev, "ei: %d MT7915_SSTATS_LEN: %d",
+ ei, (int)MT7915_SSTATS_LEN);
+}
+
+static void
+mt7915_twt_teardown_request(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 flowid)
+{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+ mt7915_mac_twt_teardown_flow(dev, msta, flowid);
+ mutex_unlock(&dev->mt76.mutex);
+}
+
const struct ieee80211_ops mt7915_ops = {
.tx = mt7915_tx,
.start = mt7915_start,
@@ -1056,6 +1329,9 @@ const struct ieee80211_ops mt7915_ops = {
.get_txpower = mt76_get_txpower,
.channel_switch_beacon = mt7915_channel_switch_beacon,
.get_stats = mt7915_get_stats,
+ .get_et_sset_count = mt7915_get_et_sset_count,
+ .get_et_stats = mt7915_get_et_stats,
+ .get_et_strings = mt7915_get_et_strings,
.get_tsf = mt7915_get_tsf,
.set_tsf = mt7915_set_tsf,
.offset_tsf = mt7915_offset_tsf,
@@ -1067,6 +1343,8 @@ const struct ieee80211_ops mt7915_ops = {
.sta_statistics = mt7915_sta_statistics,
.sta_set_4addr = mt7915_sta_set_4addr,
.sta_set_decap_offload = mt7915_sta_set_decap_offload,
+ .add_twt_setup = mt7915_mac_add_twt_setup,
+ .twt_teardown_request = mt7915_twt_teardown_request,
CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 43960770a9af..b4cc4cb35762 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -416,7 +416,7 @@ exit:
return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
}
-static void
+static int
mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
{
struct {
@@ -429,7 +429,7 @@ mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
},
};
- mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
static void
@@ -488,152 +488,6 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
dev->hw_pattern++;
}
-static int
-mt7915_mcu_tx_rate_parse(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra,
- struct rate_info *rate, u16 r)
-{
- struct ieee80211_supported_band *sband;
- u16 ru_idx = le16_to_cpu(ra->ru_idx);
- bool cck = false;
-
- rate->mcs = FIELD_GET(MT_RA_RATE_MCS, r);
- rate->nss = FIELD_GET(MT_RA_RATE_NSS, r) + 1;
-
- switch (FIELD_GET(MT_RA_RATE_TX_MODE, r)) {
- case MT_PHY_TYPE_CCK:
- cck = true;
- fallthrough;
- case MT_PHY_TYPE_OFDM:
- if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
- sband = &mphy->sband_5g.sband;
- else
- sband = &mphy->sband_2g.sband;
-
- rate->mcs = mt76_get_rate(mphy->dev, sband, rate->mcs, cck);
- rate->legacy = sband->bitrates[rate->mcs].bitrate;
- break;
- case MT_PHY_TYPE_HT:
- case MT_PHY_TYPE_HT_GF:
- rate->mcs += (rate->nss - 1) * 8;
- if (rate->mcs > 31)
- return -EINVAL;
-
- rate->flags = RATE_INFO_FLAGS_MCS;
- if (ra->gi)
- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
- break;
- case MT_PHY_TYPE_VHT:
- if (rate->mcs > 9)
- return -EINVAL;
-
- rate->flags = RATE_INFO_FLAGS_VHT_MCS;
- if (ra->gi)
- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
- break;
- case MT_PHY_TYPE_HE_SU:
- case MT_PHY_TYPE_HE_EXT_SU:
- case MT_PHY_TYPE_HE_TB:
- case MT_PHY_TYPE_HE_MU:
- if (ra->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11)
- return -EINVAL;
-
- rate->he_gi = ra->gi;
- rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r);
- rate->flags = RATE_INFO_FLAGS_HE_MCS;
- break;
- default:
- return -EINVAL;
- }
-
- if (ru_idx) {
- switch (ru_idx) {
- case 1 ... 2:
- rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_996;
- break;
- case 3 ... 6:
- rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_484;
- break;
- case 7 ... 14:
- rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_242;
- break;
- default:
- rate->he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106;
- break;
- }
- rate->bw = RATE_INFO_BW_HE_RU;
- } else {
- u8 bw = mt7915_mcu_chan_bw(&mphy->chandef) -
- FIELD_GET(MT_RA_RATE_BW, r);
-
- switch (bw) {
- case IEEE80211_STA_RX_BW_160:
- rate->bw = RATE_INFO_BW_160;
- break;
- case IEEE80211_STA_RX_BW_80:
- rate->bw = RATE_INFO_BW_80;
- break;
- case IEEE80211_STA_RX_BW_40:
- rate->bw = RATE_INFO_BW_40;
- break;
- default:
- rate->bw = RATE_INFO_BW_20;
- break;
- }
- }
-
- return 0;
-}
-
-static void
-mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
-{
- struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data;
- struct rate_info rate = {}, prob_rate = {};
- u16 probe = le16_to_cpu(ra->prob_up_rate);
- u16 attempts = le16_to_cpu(ra->attempts);
- u16 curr = le16_to_cpu(ra->curr_rate);
- u16 wcidx = le16_to_cpu(ra->wlan_idx);
- struct ieee80211_tx_status status = {};
- struct mt76_phy *mphy = &dev->mphy;
- struct mt7915_sta_stats *stats;
- struct mt7915_sta *msta;
- struct mt76_wcid *wcid;
-
- if (wcidx >= MT76_N_WCIDS)
- return;
-
- wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
- if (!wcid)
- return;
-
- msta = container_of(wcid, struct mt7915_sta, wcid);
- stats = &msta->stats;
-
- if (msta->wcid.ext_phy && dev->mt76.phy2)
- mphy = dev->mt76.phy2;
-
- /* current rate */
- if (!mt7915_mcu_tx_rate_parse(mphy, ra, &rate, curr))
- stats->tx_rate = rate;
-
- /* probing rate */
- if (!mt7915_mcu_tx_rate_parse(mphy, ra, &prob_rate, probe))
- stats->prob_rate = prob_rate;
-
- if (attempts) {
- u16 success = le16_to_cpu(ra->success);
-
- stats->per = 1000 * (attempts - success) / attempts;
- }
-
- status.sta = wcid_to_sta(wcid);
- if (!status.sta)
- return;
-
- status.rate = &stats->tx_rate;
- ieee80211_tx_status_ext(mphy->hw, &status);
-}
-
static void
mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
{
@@ -658,6 +512,15 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
}
static void
+mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ if (!vif->color_change_active)
+ return;
+
+ ieee80211_color_change_finish(vif);
+}
+
+static void
mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data;
@@ -672,12 +535,14 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
case MCU_EXT_EVENT_CSA_NOTIFY:
mt7915_mcu_rx_csa_notify(dev, skb);
break;
- case MCU_EXT_EVENT_RATE_REPORT:
- mt7915_mcu_tx_rate_report(dev, skb);
- break;
case MCU_EXT_EVENT_FW_LOG_2_HOST:
mt7915_mcu_rx_log_message(dev, skb);
break;
+ case MCU_EXT_EVENT_BCC_NOTIFY:
+ ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7915_mcu_cca_finish, dev);
+ break;
default:
break;
}
@@ -706,7 +571,7 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
- rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
+ rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
!rxd->seq)
mt7915_mcu_rx_unsolicited_event(dev, skb);
else
@@ -721,7 +586,7 @@ mt7915_mcu_alloc_sta_req(struct mt7915_dev *dev, struct mt7915_vif *mvif,
.bss_idx = mvif->idx,
.wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0,
.wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0,
- .muar_idx = msta ? mvif->omac_idx : 0,
+ .muar_idx = msta && msta->wcid.sta ? mvif->omac_idx : 0xe,
.is_tlv_append = 1,
};
struct sk_buff *skb;
@@ -757,7 +622,7 @@ mt7915_mcu_alloc_wtbl_req(struct mt7915_dev *dev, struct mt7915_sta *msta,
}
if (sta_hdr)
- sta_hdr->len = cpu_to_le16(sizeof(hdr));
+ le16_add_cpu(&sta_hdr->len, sizeof(hdr));
return skb_put_data(nskb, &hdr, sizeof(hdr));
}
@@ -923,12 +788,15 @@ static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
struct mt7915_he_obss_narrow_bw_ru_data *data = _data;
const struct element *elem;
+ rcu_read_lock();
elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
- if (!elem || elem->datalen < 10 ||
+ if (!elem || elem->datalen <= 10 ||
!(elem->data[10] &
WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
data->tolerated = false;
+
+ rcu_read_unlock();
}
static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
@@ -1201,7 +1069,7 @@ mt7915_mcu_sta_key_tlv(struct mt7915_sta *msta, struct sk_buff *skb,
u8 cipher;
cipher = mt7915_mcu_get_cipher(key->cipher);
- if (cipher == MT_CIPHER_NONE)
+ if (cipher == MCU_CIPHER_NONE)
return -EOPNOTSUPP;
sec_key = &sec->key[0];
@@ -1317,7 +1185,7 @@ mt7915_mcu_wtbl_ba_tlv(struct sk_buff *skb,
ba->rst_ba_sb = 1;
}
- if (enable && tx)
+ if (enable)
ba->ba_winsize = cpu_to_le16(params->buf_size);
}
@@ -1469,17 +1337,21 @@ mt7915_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
}
static void
-mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif)
{
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
- struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem;
enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
const u16 *mcs_mask = msta->vif->bitrate_mask.control[band].he_mcs;
struct sta_rec_he *he;
struct tlv *tlv;
u32 cap = 0;
+ if (!sta->he_cap.has_he)
+ return;
+
tlv = mt7915_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
he = (struct sta_rec_he *)tlv;
@@ -1504,8 +1376,8 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
- if (elem->phy_cap_info[1] &
- IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
+ if (mvif->cap.ldpc && (elem->phy_cap_info[1] &
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
cap |= STA_REC_HE_CAP_LDPC;
if (elem->phy_cap_info[1] &
@@ -1525,6 +1397,10 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
if (elem->phy_cap_info[6] &
+ IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB)
+ cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
+
+ if (elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
@@ -1549,10 +1425,6 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
if (elem->phy_cap_info[9] &
- IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK)
- cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
-
- if (elem->phy_cap_info[9] &
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
@@ -1640,19 +1512,45 @@ mt7915_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
}
static void
-mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif)
{
- struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
- struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem;
struct sta_rec_muru *muru;
struct tlv *tlv;
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP)
+ return;
+
+ if (!sta->vht_cap.vht_supported)
+ return;
+
tlv = mt7915_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
muru = (struct sta_rec_muru *)tlv;
- muru->cfg.ofdma_dl_en = true;
- muru->cfg.mimo_dl_en = true;
+ muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
+ mvif->cap.vht_mu_ebfer ||
+ mvif->cap.vht_mu_ebfee;
+
+ muru->mimo_dl.vht_mu_bfee =
+ !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+
+ if (!sta->he_cap.has_he)
+ return;
+
+ muru->mimo_dl.partial_bw_dl_mimo =
+ HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
+
+ muru->cfg.mimo_ul_en = true;
+ muru->mimo_ul.full_ul_mimo =
+ HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
+ muru->mimo_ul.partial_ul_mimo =
+ HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
+
+ muru->cfg.ofdma_dl_en = true;
muru->ofdma_dl.punc_pream_rx =
HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
muru->ofdma_dl.he_20m_in_40m_2g =
@@ -1661,9 +1559,6 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
muru->ofdma_dl.he_80m_in_160m =
HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
- muru->ofdma_dl.lt16_sigb = 0;
- muru->ofdma_dl.rx_su_comp_sigb = 0;
- muru->ofdma_dl.rx_su_non_comp_sigb = 0;
muru->ofdma_ul.t_frame_dur =
HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
@@ -1671,18 +1566,18 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
muru->ofdma_ul.uo_ra =
HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
- muru->ofdma_ul.he_2x996_tone = 0;
- muru->ofdma_ul.rx_t_frame_11ac = 0;
+}
- muru->mimo_dl.vht_mu_bfee =
- !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
- muru->mimo_dl.partial_bw_dl_mimo =
- HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
+static void
+mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+{
+ struct sta_rec_ht *ht;
+ struct tlv *tlv;
- muru->mimo_ul.full_ul_mimo =
- HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
- muru->mimo_ul.partial_ul_mimo =
- HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
+ tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
+
+ ht = (struct sta_rec_ht *)tlv;
+ ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
}
static void
@@ -1691,6 +1586,9 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
struct sta_rec_vht *vht;
struct tlv *tlv;
+ if (!sta->vht_cap.vht_supported)
+ return;
+
tlv = mt7915_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
vht = (struct sta_rec_vht *)tlv;
@@ -1700,12 +1598,17 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
}
static void
-mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct sta_rec_amsdu *amsdu;
struct tlv *tlv;
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP)
+ return;
+
if (!sta->max_amsdu_len)
return;
@@ -1718,44 +1621,6 @@ mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
msta->wcid.amsdu = true;
}
-static bool
-mt7915_hw_amsdu_supported(struct ieee80211_vif *vif)
-{
- switch (vif->type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_STATION:
- return true;
- default:
- return false;
- }
-}
-
-static void
-mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
- struct ieee80211_sta *sta, struct ieee80211_vif *vif)
-{
- struct tlv *tlv;
-
- /* starec ht */
- if (sta->ht_cap.ht_supported) {
- struct sta_rec_ht *ht;
-
- tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
- ht = (struct sta_rec_ht *)tlv;
- ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
-
- if (mt7915_hw_amsdu_supported(vif))
- mt7915_mcu_sta_amsdu_tlv(skb, sta);
- }
-
- /* starec he */
- if (sta->he_cap.has_he)
- mt7915_mcu_sta_he_tlv(skb, sta);
-
- /* starec uapsd */
- mt7915_mcu_sta_uapsd_tlv(skb, sta, vif);
-}
-
static void
mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
void *sta_wtbl, void *wtbl_tlv)
@@ -1766,15 +1631,15 @@ mt7915_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps),
wtbl_tlv, sta_wtbl);
smps = (struct wtbl_smps *)tlv;
-
- if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
- smps->smps = true;
+ smps->smps = (sta->smps_mode == IEEE80211_SMPS_DYNAMIC);
}
static void
-mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
- void *sta_wtbl, void *wtbl_tlv)
+mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *sta_wtbl,
+ void *wtbl_tlv)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct wtbl_ht *ht = NULL;
struct tlv *tlv;
@@ -1783,7 +1648,8 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
wtbl_tlv, sta_wtbl);
ht = (struct wtbl_ht *)tlv;
- ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
+ ht->ldpc = mvif->cap.ldpc &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
ht->af = sta->ht_cap.ampdu_factor;
ht->mm = sta->ht_cap.ampdu_density;
ht->ht = true;
@@ -1797,7 +1663,8 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
wtbl_tlv, sta_wtbl);
vht = (struct wtbl_vht *)tlv;
- vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
+ vht->ldpc = mvif->cap.ldpc &&
+ (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
vht->vht = true;
af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
@@ -1838,6 +1705,32 @@ mt7915_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
}
}
+static int
+mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *tlv;
+
+ msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
+
+ tlv = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+ wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET,
+ tlv, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, tlv, wtbl_hdr);
+ mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, tlv, wtbl_hdr);
+
+ if (sta)
+ mt7915_mcu_wtbl_ht_tlv(skb, vif, sta, tlv, wtbl_hdr);
+
+ return 0;
+}
+
int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -1887,10 +1780,48 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
MCU_EXT_CMD(STA_REC_UPDATE), true);
}
+static inline bool
+mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool bfee)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ int tx_ant = hweight8(phy->mt76->chainmask) - 1;
+
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP)
+ return false;
+
+ if (!bfee && tx_ant < 2)
+ return false;
+
+ if (sta->he_cap.has_he) {
+ struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem;
+
+ if (bfee)
+ return mvif->cap.he_su_ebfee &&
+ HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
+ else
+ return mvif->cap.he_su_ebfer &&
+ HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
+ }
+
+ if (sta->vht_cap.vht_supported) {
+ u32 cap = sta->vht_cap.cap;
+
+ if (bfee)
+ return mvif->cap.vht_su_ebfee &&
+ (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ else
+ return mvif->cap.vht_su_ebfer &&
+ (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ }
+
+ return false;
+}
+
static void
mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
{
- bf->bf_cap = MT_EBF;
bf->sounding_phy = MT_PHY_TYPE_OFDM;
bf->ndp_rate = 0; /* mcs0 */
bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */
@@ -1905,9 +1836,8 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
u8 n = 0;
bf->tx_mode = MT_PHY_TYPE_HT;
- bf->bf_cap = MT_IBF;
- if (mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF &&
+ if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
(mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
mcs->tx_params);
@@ -1918,8 +1848,8 @@ mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
else if (mcs->rx_mask[1])
n = 1;
- bf->nr = hweight8(phy->mt76->chainmask) - 1;
- bf->nc = min_t(u8, bf->nr, n);
+ bf->nrow = hweight8(phy->mt76->chainmask) - 1;
+ bf->ncol = min_t(u8, bf->nrow, n);
bf->ibf_ncol = n;
}
@@ -1936,23 +1866,23 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
bf->tx_mode = MT_PHY_TYPE_VHT;
if (explicit) {
- u8 bfee_nr, bfer_nr;
+ u8 sts, snd_dim;
mt7915_mcu_sta_sounding_rate(bf);
- bfee_nr = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
- pc->cap);
- bfer_nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
+
+ sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
+ pc->cap);
+ snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
vc->cap);
- bf->nr = min_t(u8, min_t(u8, bfer_nr, bfee_nr), tx_ant);
- bf->nc = min_t(u8, nss_mcs, bf->nr);
- bf->ibf_ncol = bf->nc;
+ bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = bf->ncol;
if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
- bf->nr = 1;
+ bf->nrow = 1;
} else {
- bf->bf_cap = MT_IBF;
- bf->nr = tx_ant;
- bf->nc = min_t(u8, nss_mcs, bf->nr);
+ bf->nrow = tx_ant;
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = nss_mcs;
if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
@@ -1970,21 +1900,23 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
- u8 bfee_nr, bfer_nr;
+ u8 snd_dim, sts;
bf->tx_mode = MT_PHY_TYPE_HE_SU;
+
mt7915_mcu_sta_sounding_rate(bf);
+
bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
pe->phy_cap_info[6]);
bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
pe->phy_cap_info[6]);
- bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
+ snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
ve->phy_cap_info[5]);
- bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
- pe->phy_cap_info[4]);
- bf->nr = min_t(u8, bfer_nr, bfee_nr);
- bf->nc = min_t(u8, nss_mcs, bf->nr);
- bf->ibf_ncol = bf->nc;
+ sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
+ pe->phy_cap_info[4]);
+ bf->nrow = min_t(u8, snd_dim, sts);
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = bf->ncol;
if (sta->bandwidth != IEEE80211_STA_RX_BW_160)
return;
@@ -1995,7 +1927,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
- bf->nc_bw160 = nss_mcs;
+ bf->ncol_bw160 = nss_mcs;
}
if (pe->phy_cap_info[0] &
@@ -2003,25 +1935,27 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
- if (bf->nc_bw160)
- bf->nc_bw160 = min_t(u8, bf->nc_bw160, nss_mcs);
+ if (bf->ncol_bw160)
+ bf->ncol_bw160 = min_t(u8, bf->ncol_bw160, nss_mcs);
else
- bf->nc_bw160 = nss_mcs;
+ bf->ncol_bw160 = nss_mcs;
}
- bfer_nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
+ snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
ve->phy_cap_info[5]);
- bfee_nr = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
- pe->phy_cap_info[4]);
+ sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
+ pe->phy_cap_info[4]);
- bf->nr_bw160 = min_t(int, bfer_nr, bfee_nr);
+ bf->nrow_bw160 = min_t(int, snd_dim, sts);
}
static void
-mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
- struct ieee80211_vif *vif, struct mt7915_phy *phy,
- bool enable, bool explicit)
+mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_phy *phy =
+ mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy;
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
struct sta_rec_bf *bf;
struct tlv *tlv;
@@ -2031,43 +1965,42 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
{2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */
{3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */
};
+ bool ebf;
-#define MT_BFER_FREE cpu_to_le16(GENMASK(15, 0))
+ ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
+ if (!ebf && !dev->ibf)
+ return;
tlv = mt7915_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
bf = (struct sta_rec_bf *)tlv;
- if (!enable) {
- bf->pfmu = MT_BFER_FREE;
- return;
- }
-
/* he: eBF only, in accordance with spec
* vht: support eBF and iBF
* ht: iBF only, since mac80211 lacks of eBF support
*/
- if (sta->he_cap.has_he && explicit)
+ if (sta->he_cap.has_he && ebf)
mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
else if (sta->vht_cap.vht_supported)
- mt7915_mcu_sta_bfer_vht(sta, phy, bf, explicit);
+ mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
else if (sta->ht_cap.ht_supported)
mt7915_mcu_sta_bfer_ht(sta, phy, bf);
else
return;
+ bf->bf_cap = ebf ? ebf : dev->ibf << 1;
bf->bw = sta->bandwidth;
bf->ibf_dbw = sta->bandwidth;
bf->ibf_nrow = tx_ant;
- if (!explicit && sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->nc)
+ if (!ebf && sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
bf->ibf_timeout = 0x48;
else
bf->ibf_timeout = 0x18;
- if (explicit && bf->nr != tx_ant)
- bf->mem_20m = matrix[tx_ant][bf->nc];
+ if (ebf && bf->nrow != tx_ant)
+ bf->mem_20m = matrix[tx_ant][bf->ncol];
else
- bf->mem_20m = matrix[bf->nr][bf->nc];
+ bf->mem_20m = matrix[bf->nrow][bf->ncol];
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
@@ -2084,13 +2017,19 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
}
static void
-mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
- struct mt7915_phy *phy)
+mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_phy *phy =
+ mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy;
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
struct sta_rec_bfee *bfee;
struct tlv *tlv;
- u8 nr = 0;
+ u8 nrow = 0;
+
+ if (!mt7915_is_ebf_supported(phy, vif, sta, true))
+ return;
tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
bfee = (struct sta_rec_bfee *)tlv;
@@ -2098,97 +2037,17 @@ mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
if (sta->he_cap.has_he) {
struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem;
- nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
- pe->phy_cap_info[5]);
+ nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
+ pe->phy_cap_info[5]);
} else if (sta->vht_cap.vht_supported) {
struct ieee80211_sta_vht_cap *pc = &sta->vht_cap;
- nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
- pc->cap);
+ nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
+ pc->cap);
}
/* reply with identity matrix to avoid 2x2 BF negative gain */
- bfee->fb_identity_matrix = !!(nr == 1 && tx_ant == 2);
-}
-
-static int
-mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool enable)
-{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct mt7915_phy *phy;
- struct sk_buff *skb;
- int r, len;
- bool ebfee = 0, ebf = 0;
-
- if (vif->type != NL80211_IFTYPE_STATION &&
- vif->type != NL80211_IFTYPE_AP)
- return 0;
-
- phy = mvif->band_idx ? mt7915_ext_phy(dev) : &dev->phy;
-
- if (sta->he_cap.has_he) {
- struct ieee80211_he_cap_elem *pe;
- const struct ieee80211_he_cap_elem *ve;
- const struct ieee80211_sta_he_cap *vc;
-
- pe = &sta->he_cap.he_cap_elem;
- vc = mt7915_get_he_phy_cap(phy, vif);
- ve = &vc->he_cap_elem;
-
- ebfee = !!(HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) &&
- HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4]));
- ebf = !!(HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) &&
- HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]));
- } else if (sta->vht_cap.vht_supported) {
- struct ieee80211_sta_vht_cap *pc;
- struct ieee80211_sta_vht_cap *vc;
-
- pc = &sta->vht_cap;
- vc = &phy->mt76->sband_5g.sband.vht_cap;
-
- ebfee = !!((pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
- (vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
- ebf = !!((vc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
- (pc->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
- }
-
- /* must keep each tag independent */
-
- /* starec bf */
- if (ebf || dev->ibf) {
- len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bf);
-
- skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable, ebf);
-
- r = mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD(STA_REC_UPDATE), true);
- if (r)
- return r;
- }
-
- /* starec bfee */
- if (ebfee) {
- len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee);
-
- skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- mt7915_mcu_sta_bfee_tlv(skb, sta, phy);
-
- r = mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD(STA_REC_UPDATE), true);
- if (r)
- return r;
- }
-
- return 0;
+ bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
}
static void
@@ -2248,7 +2107,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_TX_STBC;
if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
cap |= STA_CAP_RX_STBC;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)
+ if (mvif->cap.ldpc &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
cap |= STA_CAP_LDPC;
mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask);
@@ -2273,7 +2133,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
cap |= STA_CAP_VHT_TX_STBC;
if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
cap |= STA_CAP_VHT_RX_STBC;
- if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)
+ if (mvif->cap.ldpc &&
+ (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
cap |= STA_CAP_VHT_LDPC;
mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask);
@@ -2322,7 +2183,7 @@ int mt7915_mcu_add_he(struct mt7915_dev *dev, struct ieee80211_vif *vif,
if (IS_ERR(skb))
return PTR_ERR(skb);
- mt7915_mcu_sta_he_tlv(skb, sta);
+ mt7915_mcu_sta_he_tlv(skb, sta, vif);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD(STA_REC_UPDATE), true);
@@ -2334,7 +2195,7 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
{
#define MT_STA_BSS_GROUP 1
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct mt7915_sta *msta;
struct {
__le32 action;
u8 wlan_idx_lo;
@@ -2345,75 +2206,24 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
u8 rsv1[8];
} __packed req = {
.action = cpu_to_le32(MT_STA_BSS_GROUP),
- .wlan_idx_lo = to_wcid_lo(msta->wcid.idx),
- .wlan_idx_hi = to_wcid_hi(msta->wcid.idx),
.val = cpu_to_le32(mvif->idx % 16),
};
+ msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
+ req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx);
+ req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx);
+
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
sizeof(req), true);
}
-static int
-mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- struct sk_buff *skb;
- int ret;
-
- if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he)
- return 0;
-
- ret = mt7915_mcu_add_group(dev, vif, sta);
- if (ret)
- return ret;
-
- skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
- MT7915_STA_UPDATE_MAX_SIZE);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
- /* wait until TxBF and MU ready to update stare vht */
-
- /* starec muru */
- mt7915_mcu_sta_muru_tlv(skb, sta);
- /* starec vht */
- mt7915_mcu_sta_vht_tlv(skb, sta);
-
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD(STA_REC_UPDATE), true);
-}
-
-int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool enable)
-{
- int ret;
-
- if (!sta)
- return 0;
-
- /* must keep the order */
- ret = mt7915_mcu_add_txbf(dev, vif, sta, enable);
- if (ret || !enable)
- return ret;
-
- ret = mt7915_mcu_add_mu(dev, vif, sta);
- if (ret)
- return ret;
-
- return mt7915_mcu_add_rate_ctrl(dev, vif, sta);
-}
-
int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- struct wtbl_req_hdr *wtbl_hdr;
struct mt7915_sta *msta;
- struct tlv *sta_wtbl;
struct sk_buff *skb;
+ int ret;
msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
@@ -2422,24 +2232,42 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
if (IS_ERR(skb))
return PTR_ERR(skb);
+ /* starec basic */
mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable);
- if (enable && sta)
- mt7915_mcu_sta_tlv(dev, skb, sta, vif);
+ if (!enable)
+ goto out;
- sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+ /* tag order is in accordance with firmware dependency. */
+ if (sta && sta->ht_cap.ht_supported) {
+ /* starec bfer */
+ mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta);
+ /* starec ht */
+ mt7915_mcu_sta_ht_tlv(skb, sta);
+ /* starec vht */
+ mt7915_mcu_sta_vht_tlv(skb, sta);
+ /* starec uapsd */
+ mt7915_mcu_sta_uapsd_tlv(skb, sta, vif);
+ }
- wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET,
- sta_wtbl, &skb);
- if (IS_ERR(wtbl_hdr))
- return PTR_ERR(wtbl_hdr);
+ ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta);
+ if (ret)
+ return ret;
- if (enable) {
- mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
- mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
- if (sta)
- mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr);
+ if (sta && sta->ht_cap.ht_supported) {
+ /* starec amsdu */
+ mt7915_mcu_sta_amsdu_tlv(skb, vif, sta);
+ /* starec he */
+ mt7915_mcu_sta_he_tlv(skb, sta, vif);
+ /* starec muru */
+ mt7915_mcu_sta_muru_tlv(skb, sta, vif);
+ /* starec bfee */
+ mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta);
}
+ ret = mt7915_mcu_add_group(dev, vif, sta);
+ if (ret)
+ return ret;
+out:
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD(STA_REC_UPDATE), true);
}
@@ -2464,10 +2292,9 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
if (!rate) {
ra->field = cpu_to_le32(RATE_PARAM_AUTO);
goto out;
- } else {
- ra->field = cpu_to_le32(RATE_PARAM_FIXED);
}
+ ra->field = cpu_to_le32(RATE_PARAM_FIXED);
ra->phy.type = FIELD_GET(RATE_CFG_PHY_TYPE, rate);
ra->phy.bw = FIELD_GET(RATE_CFG_BW, rate);
ra->phy.nss = FIELD_GET(RATE_CFG_NSS, rate);
@@ -2480,10 +2307,12 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
ra->phy.ldpc = FIELD_GET(RATE_CFG_LDPC, rate) * 7;
/* HT/VHT - SGI: 1, LGI: 0; HE - SGI: 0, MGI: 1, LGI: 2 */
- if (ra->phy.type > MT_PHY_TYPE_VHT)
- ra->phy.sgi = ra->phy.mcs * 85;
- else
- ra->phy.sgi = ra->phy.mcs * 15;
+ if (ra->phy.type > MT_PHY_TYPE_VHT) {
+ ra->phy.he_ltf = FIELD_GET(RATE_CFG_HE_LTF, rate) * 85;
+ ra->phy.sgi = FIELD_GET(RATE_CFG_GI, rate) * 85;
+ } else {
+ ra->phy.sgi = FIELD_GET(RATE_CFG_GI, rate) * 15;
+ }
out:
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
@@ -2534,25 +2363,28 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
}
static void
-mt7915_mcu_beacon_csa(struct sk_buff *rskb, struct sk_buff *skb,
- struct bss_info_bcn *bcn,
- struct ieee80211_mutable_offsets *offs)
+mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
+ struct sk_buff *skb, struct bss_info_bcn *bcn,
+ struct ieee80211_mutable_offsets *offs)
{
- if (offs->cntdwn_counter_offs[0]) {
- struct tlv *tlv;
- struct bss_info_bcn_csa *csa;
+ struct bss_info_bcn_cntdwn *info;
+ struct tlv *tlv;
+ int sub_tag;
- tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CSA,
- sizeof(*csa), &bcn->sub_ntlv,
- &bcn->len);
- csa = (struct bss_info_bcn_csa *)tlv;
- csa->cnt = skb->data[offs->cntdwn_counter_offs[0]];
- }
+ if (!offs->cntdwn_counter_offs[0])
+ return;
+
+ sub_tag = vif->csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC;
+ tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
+ &bcn->sub_ntlv, &bcn->len);
+ info = (struct bss_info_bcn_cntdwn *)tlv;
+ info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
}
static void
-mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb,
- struct sk_buff *skb, struct bss_info_bcn *bcn,
+mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct sk_buff *rskb, struct sk_buff *skb,
+ struct bss_info_bcn *bcn,
struct ieee80211_mutable_offsets *offs)
{
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
@@ -2568,8 +2400,14 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb,
cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
cont->tim_ofs = cpu_to_le16(offs->tim_offset);
- if (offs->cntdwn_counter_offs[0])
- cont->csa_ofs = cpu_to_le16(offs->cntdwn_counter_offs[0] - 4);
+ if (offs->cntdwn_counter_offs[0]) {
+ u16 offset = offs->cntdwn_counter_offs[0];
+
+ if (vif->csa_active)
+ cont->csa_ofs = cpu_to_le16(offset - 4);
+ if (vif->color_change_active)
+ cont->bcc_ofs = cpu_to_le16(offset - 3);
+ }
buf = (u8 *)tlv + sizeof(*cont);
mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
@@ -2577,6 +2415,83 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct sk_buff *rskb,
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
}
+static void
+mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ struct sk_buff *skb)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_vif_cap *vc = &mvif->cap;
+ const struct ieee80211_he_cap_elem *he;
+ const struct ieee80211_vht_cap *vht;
+ const struct ieee80211_ht_cap *ht;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+ const u8 *ie;
+ u32 len, bc;
+
+ /* Check missing configuration options to allow AP mode in mac80211
+ * to remain in sync with hostapd settings, and get a subset of
+ * beacon and hardware capabilities.
+ */
+ if (WARN_ON_ONCE(skb->len <= (mgmt->u.beacon.variable - skb->data)))
+ return;
+
+ memset(vc, 0, sizeof(*vc));
+
+ len = skb->len - (mgmt->u.beacon.variable - skb->data);
+
+ ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, mgmt->u.beacon.variable,
+ len);
+ if (ie && ie[1] >= sizeof(*ht)) {
+ ht = (void *)(ie + 2);
+ bc = le32_to_cpu(ht->cap_info);
+
+ vc->ldpc |= !!(bc & IEEE80211_HT_CAP_LDPC_CODING);
+ }
+
+ ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, mgmt->u.beacon.variable,
+ len);
+ if (ie && ie[1] >= sizeof(*vht)) {
+ u32 pc = phy->mt76->sband_5g.sband.vht_cap.cap;
+
+ vht = (void *)(ie + 2);
+ bc = le32_to_cpu(vht->vht_cap_info);
+
+ vc->ldpc |= !!(bc & IEEE80211_VHT_CAP_RXLDPC);
+ vc->vht_su_ebfer =
+ (bc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) &&
+ (pc & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ vc->vht_su_ebfee =
+ (bc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) &&
+ (pc & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ vc->vht_mu_ebfer =
+ (bc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
+ (pc & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
+ vc->vht_mu_ebfee =
+ (bc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
+ (pc & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+ }
+
+ ie = cfg80211_find_ext_ie(WLAN_EID_EXT_HE_CAPABILITY,
+ mgmt->u.beacon.variable, len);
+ if (ie && ie[1] >= sizeof(*he) + 1) {
+ const struct ieee80211_sta_he_cap *pc =
+ mt7915_get_he_phy_cap(phy, vif);
+ const struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
+
+ he = (void *)(ie + 3);
+
+ vc->he_su_ebfer =
+ HE_PHY(CAP3_SU_BEAMFORMER, he->phy_cap_info[3]) &&
+ HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
+ vc->he_su_ebfee =
+ HE_PHY(CAP4_SU_BEAMFORMEE, he->phy_cap_info[4]) &&
+ HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
+ vc->he_mu_ebfer =
+ HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) &&
+ HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]);
+ }
+}
+
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int en)
{
@@ -2617,9 +2532,11 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
}
- /* TODO: subtag - bss color count & 11v MBSSID */
- mt7915_mcu_beacon_csa(rskb, skb, bcn, &offs);
- mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs);
+ mt7915_mcu_beacon_check_caps(phy, vif, skb);
+
+ /* TODO: subtag - 11v MBSSID */
+ mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
+ mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
dev_kfree_skb(skb);
out:
@@ -2770,8 +2687,8 @@ static int mt7915_load_patch(struct mt7915_dev *dev)
goto out;
}
- ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
- dl, len);
+ ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
+ dl, len, 4096);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send patch\n");
goto out;
@@ -2790,7 +2707,7 @@ out:
default:
ret = -EAGAIN;
dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
- goto out;
+ break;
}
release_firmware(fw);
@@ -2839,8 +2756,8 @@ mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev,
return err;
}
- err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
- data + offset, len);
+ err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
+ data + offset, len, 4096);
if (err) {
dev_err(dev->mt76.dev, "Failed to send firmware.\n");
return err;
@@ -2990,6 +2907,62 @@ static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
sizeof(req), false);
}
+int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val)
+{
+ struct {
+ __le32 cmd;
+ u8 val[4];
+ } __packed req = {
+ .cmd = cpu_to_le32(cmd),
+ };
+
+ put_unaligned_le32(val, req.val);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req,
+ sizeof(req), false);
+}
+
+static int
+mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
+{
+#define RX_AIRTIME_FEATURE_CTRL 1
+#define RX_AIRTIME_BITWISE_CTRL 2
+#define RX_AIRTIME_CLEAR_EN 1
+ struct {
+ __le16 field;
+ __le16 sub_field;
+ __le32 set_status;
+ __le32 get_status;
+ u8 _rsv[12];
+
+ bool airtime_en;
+ bool mibtime_en;
+ bool earlyend_en;
+ u8 _rsv1[9];
+
+ bool airtime_clear;
+ bool mibtime_clear;
+ u8 _rsv2[98];
+ } __packed req = {
+ .field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL),
+ .sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN),
+ .airtime_clear = true,
+ };
+ int ret;
+
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
+ sizeof(req), true);
+ if (ret)
+ return ret;
+
+ req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL);
+ req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN);
+ req.airtime_en = true;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
+ sizeof(req), true);
+}
+
int mt7915_mcu_init(struct mt7915_dev *dev)
{
static const struct mt76_mcu_ops mt7915_mcu_ops = {
@@ -3011,11 +2984,25 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
return ret;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
- mt7915_mcu_fw_log_2_host(dev, 0);
- mt7915_mcu_set_mwds(dev, 1);
- mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, 0, 0);
+ ret = mt7915_mcu_fw_log_2_host(dev, 0);
+ if (ret)
+ return ret;
- return 0;
+ ret = mt7915_mcu_set_mwds(dev, 1);
+ if (ret)
+ return ret;
+
+ ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE,
+ MURU_PLATFORM_TYPE_PERF_LEVEL_2);
+ if (ret)
+ return ret;
+
+ ret = mt7915_mcu_init_rx_airtime(dev);
+ if (ret)
+ return ret;
+
+ return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
+ MCU_WA_PARAM_RED, 0, 0);
}
void mt7915_mcu_exit(struct mt7915_dev *dev)
@@ -3391,20 +3378,20 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
{
-#define TOTAL_PAGE_MASK GENMASK(7, 5)
+#define MAX_PAGE_IDX_MASK GENMASK(7, 5)
#define PAGE_IDX_MASK GENMASK(4, 2)
#define PER_PAGE_SIZE 0x400
struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
- u8 total = MT7915_EEPROM_SIZE / PER_PAGE_SIZE;
+ u8 total = DIV_ROUND_UP(MT7915_EEPROM_SIZE, PER_PAGE_SIZE);
u8 *eep = (u8 *)dev->mt76.eeprom.data;
int eep_len;
int i;
- for (i = 0; i <= total; i++, eep += eep_len) {
+ for (i = 0; i < total; i++, eep += eep_len) {
struct sk_buff *skb;
int ret;
- if (i == total)
+ if (i == total - 1 && !!(MT7915_EEPROM_SIZE % PER_PAGE_SIZE))
eep_len = MT7915_EEPROM_SIZE % PER_PAGE_SIZE;
else
eep_len = PER_PAGE_SIZE;
@@ -3414,7 +3401,7 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
if (!skb)
return -ENOMEM;
- req.format = FIELD_PREP(TOTAL_PAGE_MASK, total) |
+ req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
req.len = cpu_to_le16(eep_len);
@@ -3481,7 +3468,7 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
u8 idx;
u8 rsv[4];
__le32 len;
- } req;
+ } req = {};
struct sk_buff *skb;
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
@@ -3691,10 +3678,6 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
};
int level;
-#define TRIGGER_TEMPERATURE 122
-#define RESTORE_TEMPERATURE 116
-#define SUSTAIN_PERIOD 10
-
if (!state) {
req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
goto out;
@@ -3707,7 +3690,7 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG;
req.ctrl.duty.duty_level = level;
req.ctrl.duty.duty_cycle = state;
- state = state * 4 / 5;
+ state /= 2;
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
&req, sizeof(req.ctrl), false);
@@ -3715,15 +3698,12 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
return ret;
}
- /* currently use fixed values for throttling, and would be better
- * to implement thermal zone for dynamic trip in the long run.
- */
-
/* set high-temperature trigger threshold */
req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
- req.trigger_temp = cpu_to_le32(TRIGGER_TEMPERATURE);
- req.restore_temp = cpu_to_le32(RESTORE_TEMPERATURE);
- req.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
+ /* add a safety margin ~10 */
+ req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
+ req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
+ req.sustain_time = cpu_to_le16(10);
out:
req.ctrl.type.protect_type = 1;
@@ -3733,24 +3713,6 @@ out:
&req, sizeof(req), false);
}
-int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
-{
- struct {
- __le32 cmd;
- __le16 wlan_idx;
- __le16 ru_idx;
- __le16 direction;
- __le16 dump_group;
- } req = {
- .cmd = cpu_to_le32(cmd),
- .wlan_idx = cpu_to_le16(wlan_idx),
- .dump_group = cpu_to_le16(1),
- };
-
- return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RATE_CTRL), &req,
- sizeof(req), false);
-}
-
int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
@@ -4069,3 +4031,75 @@ out:
return ret;
}
+
+int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct cfg80211_he_bss_color *he_bss_color)
+{
+ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color);
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct bss_info_color *bss_color;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+
+ skb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR, sizeof(*bss_color));
+ bss_color = (struct bss_info_color *)tlv;
+ bss_color->disable = !he_bss_color->enabled;
+ bss_color->color = he_bss_color->color;
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD(BSS_INFO_UPDATE), true);
+}
+
+#define TWT_AGRT_TRIGGER BIT(0)
+#define TWT_AGRT_ANNOUNCE BIT(1)
+#define TWT_AGRT_PROTECT BIT(2)
+
+int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+ struct mt7915_vif *mvif,
+ struct mt7915_twt_flow *flow,
+ int cmd)
+{
+ struct {
+ u8 tbl_idx;
+ u8 cmd;
+ u8 own_mac_idx;
+ u8 flowid; /* 0xff for group id */
+ __le16 peer_id; /* specify the peer_id (msb=0)
+ * or group_id (msb=1)
+ */
+ u8 duration; /* 256 us */
+ u8 bss_idx;
+ __le64 start_tsf;
+ __le16 mantissa;
+ u8 exponent;
+ u8 is_ap;
+ u8 agrt_params;
+ u8 rsv[23];
+ } __packed req = {
+ .tbl_idx = flow->table_id,
+ .cmd = cmd,
+ .own_mac_idx = mvif->omac_idx,
+ .flowid = flow->id,
+ .peer_id = cpu_to_le16(flow->wcid),
+ .duration = flow->duration,
+ .bss_idx = mvif->idx,
+ .start_tsf = cpu_to_le64(flow->tsf),
+ .mantissa = flow->mantissa,
+ .exponent = flow->exp,
+ .is_ap = true,
+ };
+
+ if (flow->protection)
+ req.agrt_params |= TWT_AGRT_PROTECT;
+ if (!flow->flowtype)
+ req.agrt_params |= TWT_AGRT_ANNOUNCE;
+ if (flow->trigger)
+ req.agrt_params |= TWT_AGRT_TRIGGER;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE),
+ &req, sizeof(req), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index e68a562cc5b4..d66918d914da 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -43,7 +43,7 @@ enum {
MCU_EXT_EVENT_ASSERT_DUMP = 0x23,
MCU_EXT_EVENT_RDD_REPORT = 0x3a,
MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
- MCU_EXT_EVENT_RATE_REPORT = 0x87,
+ MCU_EXT_EVENT_BCC_NOTIFY = 0x75,
};
enum {
@@ -164,41 +164,6 @@ struct mt7915_mcu_eeprom_info {
u8 data[16];
} __packed;
-struct mt7915_mcu_ra_info {
- struct mt7915_mcu_rxd rxd;
-
- __le32 event_id;
- __le16 wlan_idx;
- __le16 ru_idx;
- __le16 direction;
- __le16 dump_group;
-
- __le32 suggest_rate;
- __le32 min_rate; /* for dynamic sounding */
- __le32 max_rate; /* for dynamic sounding */
- __le32 init_rate_down_rate;
-
- __le16 curr_rate;
- __le16 init_rate_down_total;
- __le16 init_rate_down_succ;
- __le16 success;
- __le16 attempts;
-
- __le16 prev_rate;
- __le16 prob_up_rate;
- u8 no_rate_up_cnt;
- u8 ppdu_cnt;
- u8 gi;
-
- u8 try_up_fail;
- u8 try_up_total;
- u8 suggest_wf;
- u8 try_up_check;
- u8 prob_up_period;
- u8 prob_down_pending;
-} __packed;
-
-
struct mt7915_mcu_phy_rx_info {
u8 category;
u8 rate;
@@ -210,12 +175,6 @@ struct mt7915_mcu_phy_rx_info {
u8 bw;
};
-#define MT_RA_RATE_NSS GENMASK(8, 6)
-#define MT_RA_RATE_MCS GENMASK(3, 0)
-#define MT_RA_RATE_TX_MODE GENMASK(12, 9)
-#define MT_RA_RATE_DCM_EN BIT(4)
-#define MT_RA_RATE_BW GENMASK(14, 13)
-
struct mt7915_mcu_mib {
__le32 band;
__le32 offs;
@@ -312,15 +271,17 @@ enum {
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_RX_HDR_TRANS = 0x47,
MCU_EXT_CMD_MUAR_UPDATE = 0x48,
+ MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
MCU_EXT_CMD_GET_MIB_INFO = 0x5a,
MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
MCU_EXT_CMD_SET_SER_TRIGGER = 0x81,
MCU_EXT_CMD_SCS_CTRL = 0x82,
- MCU_EXT_CMD_RATE_CTRL = 0x87,
+ MCU_EXT_CMD_TWT_AGRT_UPDATE = 0x94,
MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
+ MCU_EXT_CMD_MURU_CTRL = 0x9f,
MCU_EXT_CMD_SET_SPR = 0xa8,
MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
@@ -328,6 +289,14 @@ enum {
};
enum {
+ MCU_TWT_AGRT_ADD,
+ MCU_TWT_AGRT_MODIFY,
+ MCU_TWT_AGRT_DELETE,
+ MCU_TWT_AGRT_TEARDOWN,
+ MCU_TWT_AGRT_GET_TSF,
+};
+
+enum {
MCU_WA_PARAM_CMD_QUERY,
MCU_WA_PARAM_CMD_SET,
MCU_WA_PARAM_CMD_CAPABILITY,
@@ -545,6 +514,14 @@ struct bss_info_hw_amsdu {
u8 rsv;
} __packed;
+struct bss_info_color {
+ __le16 tag;
+ __le16 len;
+ u8 disable;
+ u8 color;
+ u8 rsv[2];
+} __packed;
+
struct bss_info_he {
__le16 tag;
__le16 len;
@@ -563,14 +540,7 @@ struct bss_info_bcn {
__le16 sub_ntlv;
} __packed __aligned(4);
-struct bss_info_bcn_csa {
- __le16 tag;
- __le16 len;
- u8 cnt;
- u8 rsv[3];
-} __packed __aligned(4);
-
-struct bss_info_bcn_bcc {
+struct bss_info_bcn_cntdwn {
__le16 tag;
__le16 len;
u8 cnt;
@@ -716,6 +686,7 @@ struct wtbl_ba {
__le16 sn;
u8 ba_en;
u8 ba_winsize_idx;
+ /* originator & recipient */
__le16 ba_winsize;
/* recipient only */
u8 peer_addr[ETH_ALEN];
@@ -989,6 +960,7 @@ struct sta_rec_ra_fixed {
#define RATE_CFG_STBC GENMASK(19, 16)
#define RATE_CFG_LDPC GENMASK(23, 20)
#define RATE_CFG_PHY_TYPE GENMASK(27, 24)
+#define RATE_CFG_HE_LTF GENMASK(31, 28)
struct sta_rec_bf {
__le16 tag;
@@ -1002,8 +974,8 @@ struct sta_rec_bf {
u8 ndp_rate;
u8 rept_poll_rate;
u8 tx_mode; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT ... */
- u8 nc;
- u8 nr;
+ u8 ncol;
+ u8 nrow;
u8 bw; /* 0: 20M, 1: 40M, 2: 80M, 3: 160M */
u8 mem_total;
@@ -1023,8 +995,8 @@ struct sta_rec_bf {
u8 ibf_dbw;
u8 ibf_ncol;
u8 ibf_nrow;
- u8 nr_bw160;
- u8 nc_bw160;
+ u8 nrow_bw160;
+ u8 ncol_bw160;
u8 ru_start_idx;
u8 ru_end_idx;
@@ -1036,7 +1008,7 @@ struct sta_rec_bf {
bool codebook75_mu;
u8 he_ltf;
- u8 rsv[2];
+ u8 rsv[3];
} __packed;
struct sta_rec_bfee {
@@ -1116,16 +1088,21 @@ enum {
};
enum {
- MT_EBF = BIT(0), /* explicit beamforming */
- MT_IBF = BIT(1) /* implicit beamforming */
-};
-
-enum {
MT_BF_SOUNDING_ON = 1,
MT_BF_TYPE_UPDATE = 20,
MT_BF_MODULE_UPDATE = 25
};
+enum {
+ MURU_SET_ARB_OP_MODE = 14,
+ MURU_SET_PLATFORM_TYPE = 25,
+};
+
+enum {
+ MURU_PLATFORM_TYPE_PERF_LEVEL_1 = 1,
+ MURU_PLATFORM_TYPE_PERF_LEVEL_2,
+};
+
#define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \
sizeof(struct wtbl_generic) + \
sizeof(struct wtbl_rx) + \
@@ -1137,12 +1114,15 @@ enum {
#define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct sta_rec_basic) + \
+ sizeof(struct sta_rec_bf) + \
sizeof(struct sta_rec_ht) + \
sizeof(struct sta_rec_he) + \
sizeof(struct sta_rec_ba) + \
sizeof(struct sta_rec_vht) + \
sizeof(struct sta_rec_uapsd) + \
sizeof(struct sta_rec_amsdu) + \
+ sizeof(struct sta_rec_muru) + \
+ sizeof(struct sta_rec_bfee) + \
sizeof(struct tlv) + \
MT7915_WTBL_UPDATE_MAX_SIZE)
@@ -1157,8 +1137,7 @@ enum {
sizeof(struct bss_info_ext_bss))
#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \
- sizeof(struct bss_info_bcn_csa) + \
- sizeof(struct bss_info_bcn_bcc) + \
+ sizeof(struct bss_info_bcn_cntdwn) + \
sizeof(struct bss_info_bcn_mbss) + \
sizeof(struct bss_info_bcn_cont))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index af712a936ef6..7bbb38e7116a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -92,8 +92,7 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr)
}
if ((addr >= 0x18000000 && addr < 0x18c00000) ||
- (addr >= 0x70000000 && addr < 0x78000000) ||
- (addr >= 0x7c000000 && addr < 0x7c400000))
+ (addr >= 0x70000000 && addr < 0x78000000))
return mt7915_reg_map_l1(dev, addr);
return mt7915_reg_map_l2(dev, addr);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 3f613fae6218..fff15f6b9cad 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -36,13 +36,14 @@
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
-#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
-#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */
#define MT7915_THERMAL_THROTTLE_MAX 100
#define MT7915_SKU_RATE_NUM 161
+#define MT7915_MAX_TWT_AGRT 16
+#define MT7915_MAX_STA_TWT_AGRT 8
+
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -64,35 +65,59 @@ enum mt7915_rxq_id {
MT7915_RXQ_MCU_WA_EXT,
};
-struct mt7915_sta_stats {
- struct rate_info prob_rate;
- struct rate_info tx_rate;
-
- unsigned long per;
- unsigned long changed;
- unsigned long jiffies;
-};
-
struct mt7915_sta_key_conf {
s8 keyidx;
u8 key[16];
};
+struct mt7915_twt_flow {
+ struct list_head list;
+ u64 start_tsf;
+ u64 tsf;
+ u32 duration;
+ u16 wcid;
+ __le16 mantissa;
+ u8 exp;
+ u8 table_id;
+ u8 id;
+ u8 protection:1;
+ u8 flowtype:1;
+ u8 trigger:1;
+ u8 sched:1;
+};
+
struct mt7915_sta {
struct mt76_wcid wcid; /* must be first */
struct mt7915_vif *vif;
- struct list_head stats_list;
struct list_head poll_list;
struct list_head rc_list;
u32 airtime_ac[8];
- struct mt7915_sta_stats stats;
-
+ unsigned long changed;
+ unsigned long jiffies;
unsigned long ampdu_state;
+ struct mt76_sta_stats stats;
+
struct mt7915_sta_key_conf bip;
+
+ struct {
+ u8 flowid_mask;
+ struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT];
+ } twt;
+};
+
+struct mt7915_vif_cap {
+ bool ldpc:1;
+ bool vht_su_ebfer:1;
+ bool vht_su_ebfee:1;
+ bool vht_mu_ebfer:1;
+ bool vht_mu_ebfee:1;
+ bool he_su_ebfer:1;
+ bool he_su_ebfee:1;
+ bool he_mu_ebfer:1;
};
struct mt7915_vif {
@@ -101,6 +126,7 @@ struct mt7915_vif {
u8 band_idx;
u8 wmm_idx;
+ struct mt7915_vif_cap cap;
struct mt7915_sta sta;
struct mt7915_phy *phy;
@@ -108,12 +134,58 @@ struct mt7915_vif {
struct cfg80211_bitrate_mask bitrate_mask;
};
+/* per-phy stats. */
struct mib_stats {
u32 ack_fail_cnt;
u32 fcs_err_cnt;
u32 rts_cnt;
u32 rts_retries_cnt;
u32 ba_miss_cnt;
+ u32 tx_bf_cnt;
+ u32 tx_mu_mpdu_cnt;
+ u32 tx_mu_acked_mpdu_cnt;
+ u32 tx_su_acked_mpdu_cnt;
+ u32 tx_bf_ibf_ppdu_cnt;
+ u32 tx_bf_ebf_ppdu_cnt;
+
+ u32 tx_bf_rx_fb_all_cnt;
+ u32 tx_bf_rx_fb_he_cnt;
+ u32 tx_bf_rx_fb_vht_cnt;
+ u32 tx_bf_rx_fb_ht_cnt;
+
+ u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
+ u32 tx_bf_rx_fb_nc_cnt;
+ u32 tx_bf_rx_fb_nr_cnt;
+ u32 tx_bf_fb_cpl_cnt;
+ u32 tx_bf_fb_trig_cnt;
+
+ u32 tx_ampdu_cnt;
+ u32 tx_stop_q_empty_cnt;
+ u32 tx_mpdu_attempts_cnt;
+ u32 tx_mpdu_success_cnt;
+ u32 tx_pkt_ebf_cnt;
+ u32 tx_pkt_ibf_cnt;
+
+ u32 tx_rwp_fail_cnt;
+ u32 tx_rwp_need_cnt;
+
+ /* rx stats */
+ u32 rx_fifo_full_cnt;
+ u32 channel_idle_cnt;
+ u32 rx_vector_mismatch_cnt;
+ u32 rx_delimiter_fail_cnt;
+ u32 rx_len_mismatch_cnt;
+ u32 rx_mpdu_cnt;
+ u32 rx_ampdu_cnt;
+ u32 rx_ampdu_bytes_cnt;
+ u32 rx_ampdu_valid_subframe_cnt;
+ u32 rx_ampdu_valid_subframe_bytes_cnt;
+ u32 rx_pfdrop_cnt;
+ u32 rx_vec_queue_overflow_drop_cnt;
+ u32 rx_ba_cnt;
+
+ u32 tx_amsdu[8];
+ u32 tx_amsdu_cnt;
};
struct mt7915_hif {
@@ -134,6 +206,7 @@ struct mt7915_phy {
struct thermal_cooling_device *cdev;
u8 throttle_state;
+ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
u32 rxfilter;
u64 omac_mask;
@@ -151,9 +224,6 @@ struct mt7915_phy {
struct mib_stats mib;
struct mt76_channel_state state_ts;
- struct list_head stats_list;
-
- u8 sta_work_count;
#ifdef CONFIG_NL80211_TESTMODE
struct {
@@ -193,6 +263,7 @@ struct mt7915_dev {
struct list_head sta_rc_list;
struct list_head sta_poll_list;
+ struct list_head twt_list;
spinlock_t sta_poll_lock;
u32 hw_pattern;
@@ -203,6 +274,11 @@ struct mt7915_dev {
bool ibf;
void *cal;
+
+ struct {
+ u8 table_mask;
+ u8 n_agrt;
+ } twt;
};
enum {
@@ -220,13 +296,17 @@ enum {
};
enum {
- MT_LMAC_AC00,
+ MT_CTX0,
+ MT_HIF0 = 0x0,
+
+ MT_LMAC_AC00 = 0x0,
MT_LMAC_AC01,
MT_LMAC_AC02,
MT_LMAC_AC03,
MT_LMAC_ALTX0 = 0x10,
MT_LMAC_BMC0,
MT_LMAC_BCN0,
+ MT_LMAC_PSMP0,
};
enum {
@@ -250,13 +330,6 @@ enum mt7915_rdd_cmd {
RDD_IRQ_OFF,
};
-enum {
- RATE_CTRL_RU_INFO,
- RATE_CTRL_FIXED_RATE_INFO,
- RATE_CTRL_DUMP_INFO,
- RATE_CTRL_MU_INFO,
-};
-
static inline struct mt7915_phy *
mt7915_hw_phy(struct ieee80211_hw *hw)
{
@@ -294,7 +367,7 @@ extern const struct ieee80211_ops mt7915_ops;
extern const struct mt76_testmode_ops mt7915_testmode_ops;
u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr);
-
+u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif);
int mt7915_register_device(struct mt7915_dev *dev);
void mt7915_unregister_device(struct mt7915_dev *dev);
int mt7915_eeprom_init(struct mt7915_dev *dev);
@@ -307,14 +380,16 @@ int mt7915_dma_init(struct mt7915_dev *dev);
void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_mcu_init(struct mt7915_dev *dev);
+int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+ struct mt7915_vif *mvif,
+ struct mt7915_twt_flow *flow,
+ int cmd);
int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, bool enable);
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, int enable);
int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
-int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool enable);
int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@@ -327,6 +402,8 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct mt7915_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
+int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct cfg80211_he_bss_color *he_bss_color);
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int enable);
int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -362,12 +439,12 @@ int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
const struct mt7915_dfs_pulse *pulse);
int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
const struct mt7915_dfs_pattern *pattern);
+int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val);
int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev);
int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy);
int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch);
int mt7915_mcu_get_temperature(struct mt7915_phy *phy);
int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state);
-int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
@@ -418,7 +495,14 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7915_mac_work(struct work_struct *work);
void mt7915_mac_reset_work(struct work_struct *work);
void mt7915_mac_sta_rc_work(struct work_struct *work);
+void mt7915_mac_update_stats(struct mt7915_phy *phy);
int mt7915_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, int irq);
+void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
+ struct mt7915_sta *msta,
+ u8 flowid);
+void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct ieee80211_twt_setup *twt);
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
@@ -435,7 +519,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
void mt7915_update_channel(struct mt76_phy *mphy);
-int mt7915_init_debugfs(struct mt7915_dev *dev);
+int mt7915_init_debugfs(struct mt7915_phy *phy);
#ifdef CONFIG_MAC80211_DEBUGFS
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 340b364da5f0..0af4cdb897b7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -222,8 +222,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp),
- .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
- MT_DRV_AMSDU_OFFLOAD,
+ .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
@@ -251,7 +250,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index a213b5cb82f8..a2e98788f421 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -22,15 +22,22 @@
#define MT_PLE_BASE 0x8000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
-#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
-#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
-#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8)
-#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc)
-
-#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
+#define MT_FL_Q_EMPTY 0x0b0
+#define MT_FL_Q0_CTRL 0x1b0
+#define MT_FL_Q2_CTRL 0x1b8
+#define MT_FL_Q3_CTRL 0x1bc
+
+#define MT_PLE_FREEPG_CNT MT_PLE(0x100)
+#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x104)
+#define MT_PLE_PG_HIF_GROUP MT_PLE(0x110)
+#define MT_PLE_HIF_PG_INFO MT_PLE(0x114)
+#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x500 + 0x40 * (ac) + \
((n) << 2))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
+#define MT_PSE_BASE 0xc000
+#define MT_PSE(ofs) (MT_PSE_BASE + (ofs))
+
#define MT_MDP_BASE 0xf000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
@@ -57,6 +64,7 @@
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
+#define MT_TMAC_TCR0_TX_BLINK GENMASK(7, 6)
#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25)
#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
@@ -72,11 +80,14 @@
#define MT_TMAC_TRCR0_I2T_CHK GENMASK(24, 16)
#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4)
-#define MT_IFS_EIFS GENMASK(8, 0)
+#define MT_IFS_EIFS_OFDM GENMASK(8, 0)
#define MT_IFS_RIFS GENMASK(14, 10)
#define MT_IFS_SIFS GENMASK(22, 16)
#define MT_IFS_SLOT GENMASK(30, 24)
+#define MT_TMAC_ICR1(_band) MT_WF_TMAC(_band, 0x0b4)
+#define MT_IFS_EIFS_CCK GENMASK(8, 0)
+
#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4)
#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0)
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
@@ -128,15 +139,120 @@
#define MT_LPON_TCR_SW_READ GENMASK(1, 0)
/* MIB: band 0(0x24800), band 1(0xa4800) */
+/* These counters are (mostly?) clear-on-read. So, some should not
+ * be read at all in case firmware is already reading them. These
+ * are commented with 'DNR' below. The DNR stats will be read by querying
+ * the firmware API for the appropriate message. For counters the driver
+ * does read, the driver should accumulate the counters.
+ */
#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
+#define MT_MIB_SDR0(_band) MT_WF_MIB(_band, 0x010)
+#define MT_MIB_SDR0_BERACON_TX_CNT_MASK GENMASK(15, 0)
+
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014)
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0)
+#define MT_MIB_SDR4(_band) MT_WF_MIB(_band, 0x018)
+#define MT_MIB_SDR4_RX_FIFO_FULL_MASK GENMASK(15, 0)
+
+/* rx mpdu counter, full 32 bits */
+#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x01c)
+
+#define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020)
+#define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR7(_band) MT_WF_MIB(_band, 0x024)
+#define MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR8(_band) MT_WF_MIB(_band, 0x028)
+#define MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK GENMASK(15, 0)
+
+/* aka CCA_NAV_TX_TIME */
+#define MT_MIB_SDR9_DNR(_band) MT_WF_MIB(_band, 0x02c)
+#define MT_MIB_SDR9_CCA_BUSY_TIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR10_DNR(_band) MT_WF_MIB(_band, 0x030)
+#define MT_MIB_SDR10_MRDY_COUNT_MASK GENMASK(25, 0)
+
+#define MT_MIB_SDR11(_band) MT_WF_MIB(_band, 0x034)
+#define MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK GENMASK(15, 0)
+
+/* tx ampdu cnt, full 32 bits */
+#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x038)
+
+#define MT_MIB_SDR13(_band) MT_WF_MIB(_band, 0x03c)
+#define MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK GENMASK(15, 0)
+
+/* counts all mpdus in ampdu, regardless of success */
+#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x040)
+#define MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK GENMASK(23, 0)
+
+/* counts all successfully tx'd mpdus in ampdu */
+#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x044)
+#define MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK GENMASK(23, 0)
+
+/* in units of 'us' */
+#define MT_MIB_SDR16_DNR(_band) MT_WF_MIB(_band, 0x048)
+#define MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR17_DNR(_band) MT_WF_MIB(_band, 0x04c)
+#define MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR18(_band) MT_WF_MIB(_band, 0x050)
+#define MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK GENMASK(23, 0)
+
+/* units are us */
+#define MT_MIB_SDR19_DNR(_band) MT_WF_MIB(_band, 0x054)
+#define MT_MIB_SDR19_CCK_MDRDY_TIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR20_DNR(_band) MT_WF_MIB(_band, 0x058)
+#define MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK GENMASK(23, 0)
+
+#define MT_MIB_SDR21_DNR(_band) MT_WF_MIB(_band, 0x05c)
+#define MT_MIB_SDR20_GREEN_MDRDY_TIME_MASK GENMASK(23, 0)
+
+/* rx ampdu count, 32-bit */
+#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x060)
+
+/* rx ampdu bytes count, 32-bit */
+#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x064)
+
+/* rx ampdu valid subframe count */
+#define MT_MIB_SDR24(_band) MT_WF_MIB(_band, 0x068)
+#define MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK GENMASK(23, 0)
+
+/* rx ampdu valid subframe bytes count, 32bits */
+#define MT_MIB_SDR25(_band) MT_WF_MIB(_band, 0x06c)
+
+/* remaining windows protected stats */
+#define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x074)
+#define MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x078)
+#define MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR29(_band) MT_WF_MIB(_band, 0x07c)
+#define MT_MIB_SDR29_RX_PFDROP_CNT_MASK GENMASK(7, 0)
+
+#define MT_MIB_SDR30(_band) MT_WF_MIB(_band, 0x080)
+#define MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK GENMASK(15, 0)
+
+/* rx blockack count, 32 bits */
+#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x084)
+
+#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x088)
+#define MT_MIB_SDR32_TX_PKT_EBF_CNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR33(_band) MT_WF_MIB(_band, 0x08c)
+#define MT_MIB_SDR33_TX_PKT_IBF_CNT_MASK GENMASK(15, 0)
+
#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090)
#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0)
+/* 36, 37 both DNR */
+
#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4)
#define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc)
@@ -248,7 +364,6 @@
#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
-#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
/* WFDMA0 */
#define MT_WFDMA0_BASE 0xd4000
@@ -420,6 +535,20 @@
#define MT_SWDEF_ICAP_MODE 1
#define MT_SWDEF_SPECTRUM_MODE 2
+#define MT_LED_TOP_BASE 0x18013000
+#define MT_LED_PHYS(_n) (MT_LED_TOP_BASE + (_n))
+
+#define MT_LED_CTRL(_n) MT_LED_PHYS(0x00 + ((_n) * 4))
+#define MT_LED_CTRL_KICK BIT(7)
+#define MT_LED_CTRL_BLINK_MODE BIT(2)
+#define MT_LED_CTRL_POLARITY BIT(1)
+
+#define MT_LED_TX_BLINK(_n) MT_LED_PHYS(0x10 + ((_n) * 4))
+#define MT_LED_TX_BLINK_ON_MASK GENMASK(7, 0)
+#define MT_LED_TX_BLINK_OFF_MASK GENMASK(15, 8)
+
+#define MT_LED_EN(_n) MT_LED_PHYS(0x40 + ((_n) * 4))
+
#define MT_TOP_BASE 0x18060000
#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
@@ -430,6 +559,10 @@
#define MT_TOP_MISC MT_TOP(0xf0)
#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+#define MT_LED_GPIO_MUX2 0x70005058 /* GPIO 18 */
+#define MT_LED_GPIO_MUX3 0x7000505C /* GPIO 26 */
+#define MT_LED_GPIO_SEL_MASK GENMASK(11, 8)
+
#define MT_HW_BOUND 0x70010020
#define MT_HW_CHIPID 0x70010200
#define MT_HW_REV 0x70010204
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
index b220b334906b..89aae323d29e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -166,6 +166,22 @@ mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs)
}
static int
+mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu)
+{
+ struct mt7915_dev *dev = phy->dev;
+ u32 op_mode;
+
+ if (!enable)
+ op_mode = TAM_ARB_OP_MODE_NORMAL;
+ else if (mu)
+ op_mode = TAM_ARB_OP_MODE_TEST;
+ else
+ op_mode = TAM_ARB_OP_MODE_FORCE_SU;
+
+ return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode);
+}
+
+static int
mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min,
u16 cw_max, u16 txop)
{
@@ -397,6 +413,10 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en);
mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en);
+ mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
+
+ if (!en)
+ mt7915_tm_set_tam_arb(phy, en, 0);
}
static void
@@ -438,6 +458,9 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
}
}
+ mt7915_tm_set_tam_arb(phy, en,
+ td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU);
+
/* if all three params are set, duty_cycle will be ignored */
if (duty_cycle && tx_time && !ipg) {
ipg = tx_time * 100 / duty_cycle - tx_time;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
index 397a6b5532bc..5573ac309363 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
@@ -96,4 +96,10 @@ enum {
RF_OPER_WIFI_SPECTRUM,
};
+enum {
+ TAM_ARB_OP_MODE_NORMAL = 1,
+ TAM_ARB_OP_MODE_TEST,
+ TAM_ARB_OP_MODE_FORCE_SU = 5,
+};
+
#endif