Add attributes for setting tx inter-packet gap (ipg), duty cycle, and
transmission time in testmode.
Signed-off-by: Shayne Chen <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++++
drivers/net/wireless/mediatek/mt76/testmode.c | 17 +++++++++++++++++
drivers/net/wireless/mediatek/mt76/testmode.h | 8 ++++++++
3 files changed, 29 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 245a7197b017..cbe9689dc2ca 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -541,6 +541,10 @@ struct mt76_testmode_data {
u8 tx_antenna_mask;
u8 tx_spe_idx;
+ u8 tx_duty_cycle;
+ u32 tx_time;
+ u32 tx_ipg;
+
u32 freq_offset;
u8 tx_power[4];
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index ad8edf137b36..74cadf51df55 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -17,6 +17,9 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED },
+ [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 },
+ [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },
+ [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
[MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
};
@@ -361,10 +364,18 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask,
1 << (ext_phy * 2), phy->antenna_mask << (ext_phy * 2)) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_SPE_IDX], &td->tx_spe_idx, 0, 27) ||
+ mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],
+ &td->tx_duty_cycle, 0, 99) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
&td->tx_power_control, 0, 1))
goto out;
+ if (tb[MT76_TM_ATTR_TX_IPG])
+ td->tx_ipg = nla_get_u32(tb[MT76_TM_ATTR_TX_IPG]);
+
+ if (tb[MT76_TM_ATTR_TX_TIME])
+ td->tx_time = nla_get_u32(tb[MT76_TM_ATTR_TX_TIME]);
+
if (tb[MT76_TM_ATTR_FREQ_OFFSET])
td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]);
@@ -503,6 +514,12 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_SPE_IDX) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX, td->tx_spe_idx)) ||
+ (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_DUTY_CYCLE) &&
+ nla_put_u8(msg, MT76_TM_ATTR_TX_DUTY_CYCLE, td->tx_duty_cycle)) ||
+ (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_IPG) &&
+ nla_put_u32(msg, MT76_TM_ATTR_TX_IPG, td->tx_ipg)) ||
+ (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME) &&
+ nla_put_u32(msg, MT76_TM_ATTR_TX_TIME, td->tx_time)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) &&
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h
index f215b377d7fb..cecdf358aa44 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/testmode.h
@@ -33,6 +33,10 @@
* @MT76_TM_ATTR_TX_POWER_CONTROL: enable tx power control (u8)
* @MT76_TM_ATTR_TX_POWER: per-antenna tx power array (nested, u8 attrs)
*
+ * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
+ * @MT76_TM_ATTR_TX_IPG: tx inter-packet gap, in unit of us (u32)
+ * @MT76_TM_ATTR_TX_TIME: packet transmission time, in unit of us (u32)
+ *
* @MT76_TM_ATTR_FREQ_OFFSET: RF frequency offset (u32)
*
* @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
@@ -61,6 +65,10 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_TX_POWER_CONTROL,
MT76_TM_ATTR_TX_POWER,
+ MT76_TM_ATTR_TX_DUTY_CYCLE,
+ MT76_TM_ATTR_TX_IPG,
+ MT76_TM_ATTR_TX_TIME,
+
MT76_TM_ATTR_FREQ_OFFSET,
MT76_TM_ATTR_STATS,
--
2.29.2
Split parameter settings and mcu command update in mt7915_mcu_set_tx().
This is for reusing edca update function in testmode ipg setting.
Signed-off-by: Shayne Chen <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7915/mcu.c | 37 +++++++------------
.../net/wireless/mediatek/mt76/mt7915/mcu.h | 24 ++++++++++++
.../wireless/mediatek/mt76/mt7915/mt7915.h | 1 +
3 files changed, 39 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 0baef70fc522..9f78e4ec14c9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -2977,30 +2977,21 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val)
sizeof(req), true);
}
+int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param)
+{
+ struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param;
+ u8 num = req->total;
+ size_t len = sizeof(*req) -
+ (IEEE80211_NUM_ACS - num) * sizeof(struct edca);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, req,
+ len, true);
+}
+
int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
{
-#define WMM_AIFS_SET BIT(0)
-#define WMM_CW_MIN_SET BIT(1)
-#define WMM_CW_MAX_SET BIT(2)
-#define WMM_TXOP_SET BIT(3)
-#define WMM_PARAM_SET GENMASK(3, 0)
#define TX_CMD_MODE 1
- struct edca {
- u8 queue;
- u8 set;
- u8 aifs;
- u8 cw_min;
- __le16 cw_max;
- __le16 txop;
- };
- struct mt7915_mcu_tx {
- u8 total;
- u8 action;
- u8 valid;
- u8 mode;
-
- struct edca edca[IEEE80211_NUM_ACS];
- } __packed req = {
+ struct mt7915_mcu_tx req = {
.valid = true,
.mode = TX_CMD_MODE,
.total = IEEE80211_NUM_ACS,
@@ -3027,8 +3018,8 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
else
e->cw_max = cpu_to_le16(10);
}
- return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req,
- sizeof(req), true);
+
+ return mt7915_mcu_update_edca(dev, &req);
}
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 30ec2ef4cc74..ee6d70339d92 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -182,6 +182,30 @@ struct mt7915_mcu_phy_rx_info {
#define MT_RA_RATE_DCM_EN BIT(4)
#define MT_RA_RATE_BW GENMASK(14, 13)
+struct edca {
+ u8 queue;
+ u8 set;
+ u8 aifs;
+ u8 cw_min;
+ __le16 cw_max;
+ __le16 txop;
+};
+
+struct mt7915_mcu_tx {
+ u8 total;
+ u8 action;
+ u8 valid;
+ u8 mode;
+
+ struct edca edca[IEEE80211_NUM_ACS];
+} __packed;
+
+#define WMM_AIFS_SET BIT(0)
+#define WMM_CW_MIN_SET BIT(1)
+#define WMM_CW_MAX_SET BIT(2)
+#define WMM_TXOP_SET BIT(3)
+#define WMM_PARAM_SET GENMASK(3, 0)
+
#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10))
#define MCU_PKT_ID 0xa0
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index df7ac2cf052f..c9c9aefacd88 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -327,6 +327,7 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
int mt7915_set_channel(struct mt7915_phy *phy);
int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd);
int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif);
+int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *req);
int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
struct ieee80211_sta *sta, u32 rate);
int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
--
2.29.2
Add support to calculate and apply ipg parameters in testmode
for MT7915 NIC.
Signed-off-by: Shayne Chen <[email protected]>
---
.../net/wireless/mediatek/mt76/mt7915/mcu.h | 1 +
.../net/wireless/mediatek/mt76/mt7915/regs.h | 8 +-
.../wireless/mediatek/mt76/mt7915/testmode.c | 125 +++++++++++++++++-
.../wireless/mediatek/mt76/mt7915/testmode.h | 11 ++
4 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index ee6d70339d92..66d34d78c1d4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -49,6 +49,7 @@ enum {
enum {
MCU_ATE_SET_TRX = 0x1,
MCU_ATE_SET_FREQ_OFFSET = 0xa,
+ MCU_ATE_SET_SLOT_TIME = 0x13,
};
struct mt7915_mcu_rxd {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index 848703e6eb7c..6fb5cbab9c32 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -59,6 +59,13 @@
#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16)
+#define MT_TMAC_ATCR(_band) MT_WF_TMAC(_band, 0x098)
+#define MT_TMAC_ATCR_TXV_TOUT GENMASK(7, 0)
+
+#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
+#define MT_TMAC_TRCR0_TR2T_CHK GENMASK(8, 0)
+#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_RIFS GENMASK(14, 10)
@@ -70,7 +77,6 @@
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
-#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
index 278f279cc67b..748c9b55e498 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -132,6 +132,111 @@ mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en)
sizeof(req), false);
}
+static int
+mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs)
+{
+ struct mt7915_dev *dev = phy->dev;
+ struct mt7915_tm_cmd req = {
+ .testmode_en = !(phy->mt76->test.state == MT76_TM_STATE_OFF),
+ .param_idx = MCU_ATE_SET_SLOT_TIME,
+ .param.slot.slot_time = slot_time,
+ .param.slot.sifs = sifs,
+ .param.slot.rifs = 2,
+ .param.slot.eifs = cpu_to_le16(60),
+ .param.slot.band = phy != &dev->phy,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
+ sizeof(req), false);
+}
+
+static int
+mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min,
+ u16 cw_max, u16 txop)
+{
+ struct mt7915_mcu_tx req = { .total = 1 };
+ struct edca *e = &req.edca[0];
+
+ e->queue = qid;
+ e->set = WMM_PARAM_SET;
+
+ e->aifs = aifs;
+ e->cw_min = cw_min;
+ e->cw_max = cpu_to_le16(cw_max);
+ e->txop = cpu_to_le16(txop);
+
+ return mt7915_mcu_update_edca(dev, &req);
+}
+
+static int
+mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode)
+{
+#define TM_DEFAULT_SIFS 10
+#define TM_MAX_SIFS 127
+#define TM_MAX_AIFSN 0xf
+#define TM_MIN_AIFSN 0x1
+#define BBP_PROC_TIME 1500
+ struct mt7915_dev *dev = phy->dev;
+ u8 sig_ext = (mode == MT76_TM_TX_MODE_CCK) ? 0 : 6;
+ u8 slot_time = 9, sifs = TM_DEFAULT_SIFS;
+ u8 aifsn = TM_MIN_AIFSN;
+ u32 i2t_time, tr2t_time, txv_time;
+ bool ext_phy = phy != &dev->phy;
+ u16 cw = 0;
+
+ if (ipg < sig_ext + slot_time + sifs)
+ ipg = 0;
+
+ if (!ipg)
+ goto done;
+
+ ipg -= sig_ext;
+
+ if (ipg <= (TM_MAX_SIFS + slot_time)) {
+ sifs = ipg - slot_time;
+ } else {
+ u32 val = (ipg + slot_time) / slot_time;
+
+ while (val >>= 1)
+ cw++;
+
+ if (cw > 16)
+ cw = 16;
+
+ ipg -= ((1 << cw) - 1) * slot_time;
+
+ aifsn = ipg / slot_time;
+ if (aifsn > TM_MAX_AIFSN)
+ aifsn = TM_MAX_AIFSN;
+
+ ipg -= aifsn * slot_time;
+
+ if (ipg > TM_DEFAULT_SIFS) {
+ if (ipg < TM_MAX_SIFS)
+ sifs = ipg;
+ else
+ sifs = TM_MAX_SIFS;
+ }
+ }
+done:
+ txv_time = mt76_get_field(dev, MT_TMAC_ATCR(ext_phy),
+ MT_TMAC_ATCR_TXV_TOUT);
+ txv_time *= 50; /* normal clock time */
+
+ i2t_time = (slot_time * 1000 - txv_time - BBP_PROC_TIME) / 50;
+ tr2t_time = (sifs * 1000 - txv_time - BBP_PROC_TIME) / 50;
+
+ mt76_set(dev, MT_TMAC_TRCR0(ext_phy),
+ FIELD_PREP(MT_TMAC_TRCR0_TR2T_CHK, tr2t_time) |
+ FIELD_PREP(MT_TMAC_TRCR0_I2T_CHK, i2t_time));
+
+ mt7915_tm_set_slot_time(phy, slot_time, sifs);
+
+ return mt7915_tm_set_wmm_qid(dev,
+ mt7915_lmac_mapping(dev, IEEE80211_AC_BE),
+ aifsn, cw, cw, 0);
+}
+
static void
mt7915_tm_reg_backup_restore(struct mt7915_phy *phy)
{
@@ -206,9 +311,12 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0,
9, 8, 6, 10, 16, 12, 18, 0};
struct mt76_testmode_data *td = &phy->mt76->test;
- struct sk_buff *skb = phy->mt76->test.tx_skb;
struct mt7915_dev *dev = phy->dev;
+ struct sk_buff *skb = td->tx_skb;
struct ieee80211_tx_info *info;
+ u8 duty_cycle = td->tx_duty_cycle;
+ u32 tx_time = td->tx_time;
+ u32 ipg = td->tx_ipg;
mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false);
@@ -230,13 +338,26 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
}
}
- mt7915_tm_set_trx(phy, TM_MAC_TX, en);
+ /* 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;
+ } else if (duty_cycle && !tx_time && ipg) {
+ if (duty_cycle < 100)
+ tx_time = duty_cycle * ipg / (100 - duty_cycle);
+ }
+
+ mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode);
+
+ if (ipg)
+ td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2;
if (!en || !skb)
return;
info = IEEE80211_SKB_CB(skb);
info->control.vif = phy->monitor_vif;
+
+ mt7915_tm_set_trx(phy, TM_MAC_TX, en);
}
static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
index 964f2d7fde3a..784d4c948886 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
@@ -16,6 +16,16 @@ struct mt7915_tm_freq_offset {
__le32 freq_offset;
};
+struct mt7915_tm_slot_time {
+ u8 slot_time;
+ u8 sifs;
+ u8 rifs;
+ u8 _rsv;
+ __le16 eifs;
+ u8 band;
+ u8 _rsv1[5];
+};
+
struct mt7915_tm_cmd {
u8 testmode_en;
u8 param_idx;
@@ -24,6 +34,7 @@ struct mt7915_tm_cmd {
__le32 data;
struct mt7915_tm_trx trx;
struct mt7915_tm_freq_offset freq;
+ struct mt7915_tm_slot_time slot;
u8 test[72];
} param;
} __packed;
--
2.29.2
Originally, tx queued limit is set to 1000 to prevent from running out
of tx token. If a new testmode tx is triggered while the previous one
hasn't finished yet, we'll wait a period of time until tx_done equals to
tx_queued. Normally, current queued limit can finish in 10 seconds.
However, if ipg is configured to a larger value, less than 1000 packets
can be done in the default timeout period, which may lead to a crash
when a new testmode tx triggered.
To deal with this, make tx queued limit dynamically adjusted according
to ipg value.
Signed-off-by: Shayne Chen <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
drivers/net/wireless/mediatek/mt76/testmode.c | 9 +++++++--
drivers/net/wireless/mediatek/mt76/testmode.h | 2 ++
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index cbe9689dc2ca..9de9a3b842d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -552,6 +552,7 @@ struct mt76_testmode_data {
u32 tx_pending;
u32 tx_queued;
+ u16 tx_queued_limit;
u32 tx_done;
struct {
u64 packets[__MT_RXQ_MAX];
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index 74cadf51df55..cc769645afa5 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -30,6 +30,7 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy)
struct mt76_wcid *wcid = &dev->global_wcid;
struct sk_buff *skb = td->tx_skb;
struct mt76_queue *q;
+ u16 tx_queued_limit;
int qid;
if (!skb || !td->tx_pending)
@@ -38,9 +39,12 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy)
qid = skb_get_queue_mapping(skb);
q = phy->q_tx[qid];
+ tx_queued_limit = td->tx_queued_limit ? td->tx_queued_limit : 1000;
+
spin_lock_bh(&q->lock);
- while (td->tx_pending > 0 && td->tx_queued - td->tx_done < 1000 &&
+ while (td->tx_pending > 0 &&
+ td->tx_queued - td->tx_done < tx_queued_limit &&
q->queued < q->ndesc / 2) {
int ret;
@@ -196,7 +200,8 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
mt76_worker_enable(&dev->tx_worker);
- wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ);
+ wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued,
+ MT76_TM_TIMEOUT * HZ);
dev_kfree_skb(td->tx_skb);
td->tx_skb = NULL;
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h
index cecdf358aa44..e4849946f180 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/testmode.h
@@ -5,6 +5,8 @@
#ifndef __MT76_TESTMODE_H
#define __MT76_TESTMODE_H
+#define MT76_TM_TIMEOUT 10
+
/**
* enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA
*
--
2.29.2
If tx_time is set, calculate a new packet length based on tx time and
tx rate.
Signed-off-by: Shayne Chen <[email protected]>
---
.../wireless/mediatek/mt76/mt7915/testmode.c | 96 ++++++++++++++++++-
1 file changed, 93 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
index 748c9b55e498..a8e639ffe6de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -237,6 +237,96 @@ mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode)
aifsn, cw, cw, 0);
}
+static int
+mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time)
+{
+ struct mt76_phy *mphy = phy->mt76;
+ struct mt76_testmode_data *td = &mphy->test;
+ struct sk_buff *old = td->tx_skb, *new;
+ struct ieee80211_supported_band *sband;
+ struct rate_info rate = {};
+ u16 flags = 0, tx_len;
+ u32 bitrate;
+
+ if (!tx_time || !old)
+ return 0;
+
+ rate.mcs = td->tx_rate_idx;
+ rate.nss = td->tx_rate_nss;
+
+ switch (td->tx_rate_mode) {
+ case MT76_TM_TX_MODE_CCK:
+ case MT76_TM_TX_MODE_OFDM:
+ if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &mphy->sband_5g.sband;
+ else
+ sband = &mphy->sband_2g.sband;
+
+ rate.legacy = sband->bitrates[rate.mcs].bitrate;
+ break;
+ case MT76_TM_TX_MODE_HT:
+ rate.mcs += rate.nss * 8;
+ flags |= RATE_INFO_FLAGS_MCS;
+
+ if (td->tx_rate_sgi)
+ flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT76_TM_TX_MODE_VHT:
+ flags |= RATE_INFO_FLAGS_VHT_MCS;
+
+ if (td->tx_rate_sgi)
+ flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT76_TM_TX_MODE_HE_SU:
+ case MT76_TM_TX_MODE_HE_EXT_SU:
+ case MT76_TM_TX_MODE_HE_TB:
+ case MT76_TM_TX_MODE_HE_MU:
+ rate.he_gi = td->tx_rate_sgi;
+ flags |= RATE_INFO_FLAGS_HE_MCS;
+ break;
+ default:
+ break;
+ }
+ rate.flags = flags;
+
+ switch (mphy->chandef.width) {
+ case NL80211_CHAN_WIDTH_160:
+ case NL80211_CHAN_WIDTH_80P80:
+ rate.bw = RATE_INFO_BW_160;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ rate.bw = RATE_INFO_BW_80;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ rate.bw = RATE_INFO_BW_40;
+ break;
+ default:
+ rate.bw = RATE_INFO_BW_20;
+ break;
+ }
+
+ bitrate = cfg80211_calculate_bitrate(&rate);
+ tx_len = bitrate * tx_time / 10 / 8;
+
+ if (tx_len < sizeof(struct ieee80211_hdr))
+ tx_len = sizeof(struct ieee80211_hdr);
+ else if (tx_len > IEEE80211_MAX_FRAME_LEN)
+ tx_len = IEEE80211_MAX_FRAME_LEN;
+
+ new = alloc_skb(tx_len, GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ skb_copy_header(new, old);
+ __skb_put_zero(new, tx_len);
+ memcpy(new->data, old->data, sizeof(struct ieee80211_hdr));
+
+ dev_kfree_skb(old);
+ td->tx_skb = new;
+
+ return 0;
+}
+
static void
mt7915_tm_reg_backup_restore(struct mt7915_phy *phy)
{
@@ -312,7 +402,6 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
9, 8, 6, 10, 16, 12, 18, 0};
struct mt76_testmode_data *td = &phy->mt76->test;
struct mt7915_dev *dev = phy->dev;
- struct sk_buff *skb = td->tx_skb;
struct ieee80211_tx_info *info;
u8 duty_cycle = td->tx_duty_cycle;
u32 tx_time = td->tx_time;
@@ -347,14 +436,15 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
}
mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode);
+ mt7915_tm_set_tx_len(phy, tx_time);
if (ipg)
td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2;
- if (!en || !skb)
+ if (!en || !td->tx_skb)
return;
- info = IEEE80211_SKB_CB(skb);
+ info = IEEE80211_SKB_CB(td->tx_skb);
info->control.vif = phy->monitor_vif;
mt7915_tm_set_trx(phy, TM_MAC_TX, en);
--
2.29.2