mt76 patches for 5.16

* various bugfixes
 * endian fixes
 * mt7921 aspm support
 * cleanup
 * mt7921 testmode support
 * rate handling fixes
 * tx status fixes/improvements
 * mt7921 power management improvements
 * mt7915 LED support
 * DBDC fixes
 * mt7921 6GHz support
 * support for eeprom data in DT
 * mt7915 TWT support
 * mt7915 txbf + MU-MIMO improvements
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - http://gpgtools.org
 
 iEYEABECAAYFAmFv4F4ACgkQ130UHQKnbvWiCQCbBaVvAjHfJdW8eJrqk7GCh64v
 qo8An3OrUINp5qzewe+F/vlLoJGNfCM0
 =ZkbS
 -----END PGP SIGNATURE-----

Merge tag 'mt76-for-kvalo-2021-10-20' of https://github.com/nbd168/wireless

mt76 patches for 5.16

* various bugfixes
* endian fixes
* mt7921 aspm support
* cleanup
* mt7921 testmode support
* rate handling fixes
* tx status fixes/improvements
* mt7921 power management improvements
* mt7915 LED support
* DBDC fixes
* mt7921 6GHz support
* support for eeprom data in DT
* mt7915 TWT support
* mt7915 txbf + MU-MIMO improvements

# gpg: Signature made Wed 20 Oct 2021 12:24:46 PM EEST
# gpg:                using DSA key D77D141D02A76EF5
# gpg: Good signature from "Felix Fietkau <nbd@nbd.name>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 75D1 1A7D 91A7 710F 4900  42EF D77D 141D 02A7 6EF5
This commit is contained in:
Kalle Valo 2021-10-20 19:08:25 +03:00
commit 9bc0b1aa8b
71 changed files with 6144 additions and 2569 deletions

View File

@ -47,6 +47,11 @@ properties:
ieee80211-freq-limit: true
mediatek,eeprom-data:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
EEPROM data embedded as array.
mediatek,mtd-eeprom:
$ref: /schemas/types.yaml#/definitions/phandle-array
description:

View File

@ -14,7 +14,7 @@ mt76-$(CONFIG_PCI) += pci.o
mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt76-usb-y := usb.o usb_trace.o
mt76-sdio-y := sdio.o
mt76-sdio-y := sdio.o sdio_txrx.o
CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src)

View File

@ -56,14 +56,14 @@ int mt76_queues_read(struct seq_file *s, void *data)
struct mt76_dev *dev = dev_get_drvdata(s->private);
int i;
seq_puts(s, " queue | hw-queued | head | tail |\n");
for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
struct mt76_queue *q = dev->phy.q_tx[i];
if (!q)
continue;
seq_printf(s,
"%d: queued=%d head=%d tail=%d\n",
seq_printf(s, " %9d | %9d | %9d | %9d |\n",
i, q->queued, q->head, q->tail);
}
@ -76,12 +76,13 @@ static int mt76_rx_queues_read(struct seq_file *s, void *data)
struct mt76_dev *dev = dev_get_drvdata(s->private);
int i, queued;
seq_puts(s, " queue | hw-queued | head | tail |\n");
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued;
seq_printf(s, "%d: queued=%d head=%d tail=%d\n",
i, queued, q->head, q->tail);
seq_printf(s, " %9d | %9d | %9d | %9d |\n",
i, q->queued, q->head, q->tail);
}
return 0;
@ -116,18 +117,21 @@ static int mt76_read_rate_txpower(struct seq_file *s, void *data)
return 0;
}
struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
struct dentry *
mt76_register_debugfs_fops(struct mt76_phy *phy,
const struct file_operations *ops)
{
const struct file_operations *fops = ops ? ops : &fops_regval;
struct mt76_dev *dev = phy->dev;
struct dentry *dir;
dir = debugfs_create_dir("mt76", dev->hw->wiphy->debugfsdir);
dir = debugfs_create_dir("mt76", phy->hw->wiphy->debugfsdir);
if (!dir)
return NULL;
debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin);
debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
debugfs_create_file_unsafe("regval", 0600, dir, dev,
&fops_regval);
debugfs_create_file_unsafe("regval", 0600, dir, dev, fops);
debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev,
&fops_napi_threaded);
debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
@ -140,4 +144,4 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
return dir;
}
EXPORT_SYMBOL_GPL(mt76_register_debugfs);
EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops);

View File

@ -15,6 +15,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
struct device_node *np = dev->dev->of_node;
struct mtd_info *mtd;
const __be32 *list;
const void *data;
const char *part;
phandle phandle;
int size;
@ -24,6 +25,16 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
if (!np)
return -ENOENT;
data = of_get_property(np, "mediatek,eeprom-data", &size);
if (data) {
if (size > len)
return -EINVAL;
memcpy(eep, data, size);
return 0;
}
list = of_get_property(np, "mediatek,mtd-eeprom", &size);
if (!list)
return -ENOENT;
@ -285,6 +296,9 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
case NL80211_BAND_5GHZ:
band = '5';
break;
case NL80211_BAND_6GHZ:
band = '6';
break;
default:
return target_power;
}

View File

@ -20,6 +20,13 @@
.max_power = 30, \
}
#define CHAN6G(_idx, _freq) { \
.band = NL80211_BAND_6GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 30, \
}
static const struct ieee80211_channel mt76_channels_2ghz[] = {
CHAN2G(1, 2412),
CHAN2G(2, 2417),
@ -70,6 +77,72 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
CHAN5G(173, 5865),
};
static const struct ieee80211_channel mt76_channels_6ghz[] = {
/* UNII-5 */
CHAN6G(1, 5955),
CHAN6G(5, 5975),
CHAN6G(9, 5995),
CHAN6G(13, 6015),
CHAN6G(17, 6035),
CHAN6G(21, 6055),
CHAN6G(25, 6075),
CHAN6G(29, 6095),
CHAN6G(33, 6115),
CHAN6G(37, 6135),
CHAN6G(41, 6155),
CHAN6G(45, 6175),
CHAN6G(49, 6195),
CHAN6G(53, 6215),
CHAN6G(57, 6235),
CHAN6G(61, 6255),
CHAN6G(65, 6275),
CHAN6G(69, 6295),
CHAN6G(73, 6315),
CHAN6G(77, 6335),
CHAN6G(81, 6355),
CHAN6G(85, 6375),
CHAN6G(89, 6395),
CHAN6G(93, 6415),
/* UNII-6 */
CHAN6G(97, 6435),
CHAN6G(101, 6455),
CHAN6G(105, 6475),
CHAN6G(109, 6495),
CHAN6G(113, 6515),
CHAN6G(117, 6535),
/* UNII-7 */
CHAN6G(121, 6555),
CHAN6G(125, 6575),
CHAN6G(129, 6595),
CHAN6G(133, 6615),
CHAN6G(137, 6635),
CHAN6G(141, 6655),
CHAN6G(145, 6675),
CHAN6G(149, 6695),
CHAN6G(153, 6715),
CHAN6G(157, 6735),
CHAN6G(161, 6755),
CHAN6G(165, 6775),
CHAN6G(169, 6795),
CHAN6G(173, 6815),
CHAN6G(177, 6835),
CHAN6G(181, 6855),
CHAN6G(185, 6875),
/* UNII-8 */
CHAN6G(189, 6895),
CHAN6G(193, 6915),
CHAN6G(197, 6935),
CHAN6G(201, 6955),
CHAN6G(205, 6975),
CHAN6G(209, 6995),
CHAN6G(213, 7015),
CHAN6G(217, 7035),
CHAN6G(221, 7055),
CHAN6G(225, 7075),
CHAN6G(229, 7095),
CHAN6G(233, 7115),
};
static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
{ .throughput = 0 * 1024, .blink_time = 334 },
{ .throughput = 1 * 1024, .blink_time = 260 },
@ -99,6 +172,21 @@ struct ieee80211_rate mt76_rates[] = {
};
EXPORT_SYMBOL_GPL(mt76_rates);
static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
{ .start_freq = 2402, .end_freq = 2494, },
{ .start_freq = 5150, .end_freq = 5350, },
{ .start_freq = 5350, .end_freq = 5470, },
{ .start_freq = 5470, .end_freq = 5725, },
{ .start_freq = 5725, .end_freq = 5950, },
};
const struct cfg80211_sar_capa mt76_sar_capa = {
.type = NL80211_SAR_TYPE_POWER,
.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
.freq_ranges = &mt76_sar_freq_ranges[0],
};
EXPORT_SYMBOL_GPL(mt76_sar_capa);
static int mt76_led_init(struct mt76_dev *dev)
{
struct device_node *np = dev->dev->of_node;
@ -179,13 +267,16 @@ void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
if (phy->cap.has_5ghz)
mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
if (phy->cap.has_6ghz)
mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
}
EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
static int
mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
const struct ieee80211_channel *chan, int n_chan,
struct ieee80211_rate *rates, int n_rates, bool vht)
struct ieee80211_rate *rates, int n_rates,
bool ht, bool vht)
{
struct ieee80211_supported_band *sband = &msband->sband;
struct ieee80211_sta_vht_cap *vht_cap;
@ -209,6 +300,9 @@ mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
sband->bitrates = rates;
sband->n_bitrates = n_rates;
if (!ht)
return 0;
ht_cap = &sband->ht_cap;
ht_cap->ht_supported = true;
ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@ -245,7 +339,7 @@ mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
ARRAY_SIZE(mt76_channels_2ghz), rates,
n_rates, false);
n_rates, true, false);
}
static int
@ -256,7 +350,18 @@ mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
ARRAY_SIZE(mt76_channels_5ghz), rates,
n_rates, vht);
n_rates, true, vht);
}
static int
mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
int n_rates)
{
phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
ARRAY_SIZE(mt76_channels_6ghz), rates,
n_rates, false, false);
}
static void
@ -322,12 +427,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
ieee80211_hw_set(hw, TX_AMSDU);
ieee80211_hw_set(hw, TX_FRAG_LIST);
}
ieee80211_hw_set(hw, TX_AMSDU);
ieee80211_hw_set(hw, TX_FRAG_LIST);
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, AP_LINK_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
@ -385,9 +486,16 @@ int mt76_register_phy(struct mt76_phy *phy, bool vht,
return ret;
}
if (phy->cap.has_6ghz) {
ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
if (ret)
return ret;
}
wiphy_read_of_freq_limits(phy->hw->wiphy);
mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
ret = ieee80211_register_hw(phy->hw);
if (ret)
@ -403,7 +511,7 @@ void mt76_unregister_phy(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
mt76_tx_status_check(dev, NULL, true);
mt76_tx_status_check(dev, true);
ieee80211_unregister_hw(phy->hw);
dev->phy2 = NULL;
}
@ -435,9 +543,9 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
spin_lock_init(&dev->rx_lock);
spin_lock_init(&dev->lock);
spin_lock_init(&dev->cc_lock);
spin_lock_init(&dev->status_lock);
mutex_init(&dev->mutex);
init_waitqueue_head(&dev->tx_wait);
skb_queue_head_init(&dev->status_list);
skb_queue_head_init(&dev->mcu.res_q);
init_waitqueue_head(&dev->mcu.wait);
@ -458,6 +566,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
INIT_LIST_HEAD(&dev->wcid_list);
INIT_LIST_HEAD(&dev->txwi_cache);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
@ -495,9 +605,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
return ret;
}
if (phy->cap.has_6ghz) {
ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
if (ret)
return ret;
}
wiphy_read_of_freq_limits(hw->wiphy);
mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
ret = mt76_led_init(dev);
@ -522,7 +639,7 @@ void mt76_unregister_device(struct mt76_dev *dev)
if (IS_ENABLED(CONFIG_MT76_LEDS))
mt76_led_cleanup(dev);
mt76_tx_status_check(dev, NULL, true);
mt76_tx_status_check(dev, true);
ieee80211_unregister_hw(hw);
}
EXPORT_SYMBOL_GPL(mt76_unregister_device);
@ -642,6 +759,8 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
if (c->band == NL80211_BAND_2GHZ)
msband = &phy->sband_2g;
else if (c->band == NL80211_BAND_6GHZ)
msband = &phy->sband_6g;
else
msband = &phy->sband_5g;
@ -717,10 +836,16 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,
if (idx == 0 && dev->drv->update_survey)
mt76_update_survey(phy);
sband = &phy->sband_2g;
if (idx >= sband->sband.n_channels) {
idx -= sband->sband.n_channels;
if (idx >= phy->sband_2g.sband.n_channels +
phy->sband_5g.sband.n_channels) {
idx -= (phy->sband_2g.sband.n_channels +
phy->sband_5g.sband.n_channels);
sband = &phy->sband_6g;
} else if (idx >= phy->sband_2g.sband.n_channels) {
idx -= phy->sband_2g.sband.n_channels;
sband = &phy->sband_5g;
} else {
sband = &phy->sband_2g;
}
if (idx >= sband->sband.n_channels) {
@ -777,10 +902,17 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
return;
wcid->rx_check_pn = true;
/* data frame */
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
ieee80211_get_key_rx_seq(key, i, &seq);
memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
}
/* robust management frame */
ieee80211_get_key_rx_seq(key, -1, &seq);
memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
}
EXPORT_SYMBOL(mt76_wcid_key_setup);
@ -790,6 +922,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_sta **sta)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
struct mt76_rx_status mstat;
mstat = *((struct mt76_rx_status *)skb->cb);
@ -812,6 +945,10 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
status->device_timestamp = mstat.timestamp;
status->mactime = mstat.timestamp;
if (ieee80211_is_beacon(hdr->frame_control) ||
ieee80211_is_probe_resp(hdr->frame_control))
status->boottime_ns = ktime_get_boottime_ns();
BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
BUILD_BUG_ON(sizeof(status->chain_signal) !=
sizeof(mstat.chain_signal));
@ -828,7 +965,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_wcid *wcid = status->wcid;
struct ieee80211_hdr *hdr;
u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
int security_idx;
int ret;
if (!(status->flag & RX_FLAG_DECRYPTED))
@ -837,24 +974,39 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
if (!wcid || !wcid->rx_check_pn)
return 0;
security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
if (status->flag & RX_FLAG_8023)
goto skip_hdr_check;
hdr = mt76_skb_get_hdr(skb);
if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
/*
* Validate the first fragment both here and in mac80211
* All further fragments will be validated by mac80211 only.
*/
hdr = mt76_skb_get_hdr(skb);
if (ieee80211_is_frag(hdr) &&
!ieee80211_is_first_frag(hdr->frame_control))
return 0;
}
/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
*
* the recipient shall maintain a single replay counter for received
* individually addressed robust Management frames that are received
* with the To DS subfield equal to 0, [...]
*/
if (ieee80211_is_mgmt(hdr->frame_control) &&
!ieee80211_has_tods(hdr->frame_control))
security_idx = IEEE80211_NUM_TIDS;
skip_hdr_check:
BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
ret = memcmp(status->iv, wcid->rx_key_pn[tidno],
ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
sizeof(status->iv));
if (ret <= 0)
return -EINVAL; /* replay */
memcpy(wcid->rx_key_pn[tidno], status->iv, sizeof(status->iv));
memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
if (status->flag & RX_FLAG_IV_STRIPPED)
status->flag |= RX_FLAG_PN_VALIDATED;
@ -1109,6 +1261,7 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
wcid->ext_phy = ext_phy;
rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
mt76_packet_id_init(wcid);
out:
mutex_unlock(&dev->mutex);
@ -1127,7 +1280,8 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
if (dev->drv->sta_remove)
dev->drv->sta_remove(dev, vif, sta);
mt76_tx_status_check(dev, wcid, true);
mt76_packet_id_flush(dev, wcid);
mt76_wcid_mask_clear(dev->wcid_mask, idx);
mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
}
@ -1270,7 +1424,7 @@ int mt76_get_rate(struct mt76_dev *dev,
int i, offset = 0, len = sband->n_bitrates;
if (cck) {
if (sband == &dev->phy.sband_5g.sband)
if (sband != &dev->phy.sband_2g.sband)
return 0;
idx &= ~BIT(2); /* short preamble */
@ -1336,3 +1490,49 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
return hwq;
}
EXPORT_SYMBOL_GPL(mt76_init_queue);
u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
{
int offset = 0;
struct ieee80211_rate *rate;
if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
offset = 4;
/* pick the lowest rate for hidden nodes */
if (rateidx < 0)
rateidx = 0;
rate = &mt76_rates[offset + rateidx];
return rate->hw_value;
}
EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats)
{
int i, ei = wi->initial_stat_idx;
u64 *data = wi->data;
wi->sta_count++;
data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
data[ei++] += stats->tx_bw[i];
for (i = 0; i < 12; i++)
data[ei++] += stats->tx_mcs[i];
wi->worker_stat_count = ei - wi->initial_stat_idx;
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);

View File

@ -106,13 +106,13 @@ out:
}
EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len)
int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len, int max_len)
{
int err, cur_len;
while (len > 0) {
cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len);
cur_len = min_t(int, max_len, len);
err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
if (err)
@ -129,4 +129,4 @@ int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
return 0;
}
EXPORT_SYMBOL_GPL(mt76_mcu_send_firmware);
EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware);

View File

@ -29,6 +29,7 @@
struct mt76_dev;
struct mt76_phy;
struct mt76_wcid;
struct mt76s_intr;
struct mt76_reg_pair {
u32 reg;
@ -244,6 +245,8 @@ struct mt76_wcid {
struct ewma_signal rssi;
int inactive_count;
struct rate_info rate;
u16 idx;
u8 hw_key_idx;
u8 hw_key_idx2;
@ -253,13 +256,14 @@ struct mt76_wcid {
u8 amsdu:1;
u8 rx_check_pn;
u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6];
u16 cipher;
u32 tx_info;
bool sw_iv;
u8 packet_id;
struct list_head list;
struct idr pktid;
};
struct mt76_txq {
@ -305,8 +309,13 @@ struct mt76_rx_tid {
#define MT_PACKET_ID_NO_SKB 1
#define MT_PACKET_ID_FIRST 2
#define MT_PACKET_ID_HAS_RATE BIT(7)
#define MT_TX_STATUS_SKB_TIMEOUT HZ
/* This is timer for when to give up when waiting for TXS callback,
* with starting time being the time at which the DMA_DONE callback
* was seen (so, we know packet was processed then, it should not take
* long after that for firmware to send the TXS callback if it is going
* to do so.)
*/
#define MT_TX_STATUS_SKB_TIMEOUT (HZ / 4)
struct mt76_tx_cb {
unsigned long jiffies;
@ -344,7 +353,6 @@ struct mt76_hw_cap {
#define MT_DRV_SW_RX_AIRTIME BIT(2)
#define MT_DRV_RX_DMA_HDR BIT(3)
#define MT_DRV_HW_MGMT_TXQ BIT(4)
#define MT_DRV_AMSDU_OFFLOAD BIT(5)
struct mt76_driver_ops {
u32 drv_flags;
@ -498,13 +506,18 @@ struct mt76_sdio {
struct sdio_func *func;
void *intr_data;
u8 hw_ver;
wait_queue_head_t wait;
struct {
int pse_data_quota;
int ple_data_quota;
int pse_mcu_quota;
int pse_page_size;
int deficit;
} sched;
int (*parse_irq)(struct mt76_dev *dev, struct mt76s_intr *intr);
};
struct mt76_mmio {
@ -545,6 +558,11 @@ struct mt76_rx_status {
s8 chain_signal[IEEE80211_MAX_CHAINS];
};
struct mt76_freq_range_power {
const struct cfg80211_sar_freq_ranges *range;
s8 power;
};
struct mt76_testmode_ops {
int (*set_state)(struct mt76_phy *phy, enum mt76_testmode_state state);
int (*set_params)(struct mt76_phy *phy, struct nlattr **tb,
@ -617,6 +635,7 @@ struct mt76_phy {
struct mt76_hw_cap cap;
struct mt76_sband sband_2g;
struct mt76_sband sband_5g;
struct mt76_sband sband_6g;
u8 macaddr[ETH_ALEN];
@ -636,6 +655,8 @@ struct mt76_phy {
struct sk_buff **tail;
u16 seqno;
} rx_amsdu[__MT_RXQ_MAX];
struct mt76_freq_range_power *frp;
};
struct mt76_dev {
@ -683,7 +704,8 @@ struct mt76_dev {
int token_count;
wait_queue_head_t tx_wait;
struct sk_buff_head status_list;
/* spinclock used to protect wcid pktid linked list */
spinlock_t status_lock;
u32 wcid_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)];
u32 wcid_phy_mask[DIV_ROUND_UP(MT76_N_WCIDS, 32)];
@ -692,6 +714,7 @@ struct mt76_dev {
struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
struct list_head wcid_list;
u32 rev;
@ -753,6 +776,22 @@ enum mt76_phy_type {
MT_PHY_TYPE_HE_EXT_SU,
MT_PHY_TYPE_HE_TB,
MT_PHY_TYPE_HE_MU,
__MT_PHY_TYPE_HE_MAX,
};
struct mt76_sta_stats {
u64 tx_mode[__MT_PHY_TYPE_HE_MAX];
u64 tx_bw[4]; /* 20, 40, 80, 160 */
u64 tx_nss[4]; /* 1, 2, 3, 4 */
u64 tx_mcs[16]; /* mcs idx */
};
struct mt76_ethtool_worker_info {
u64 *data;
int idx;
int initial_stat_idx;
int worker_stat_count;
int sta_count;
};
#define CCK_RATE(_idx, _rate) { \
@ -769,6 +808,7 @@ enum mt76_phy_type {
}
extern struct ieee80211_rate mt76_rates[12];
extern const struct cfg80211_sar_capa mt76_sar_capa;
#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__)
#define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__)
@ -869,7 +909,13 @@ struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
int mt76_register_phy(struct mt76_phy *phy, bool vht,
struct ieee80211_rate *rates, int n_rates);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
struct dentry *mt76_register_debugfs_fops(struct mt76_phy *phy,
const struct file_operations *ops);
static inline struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
{
return mt76_register_debugfs_fops(&dev->phy, NULL);
}
int mt76_queues_read(struct seq_file *s, void *data);
void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len);
@ -881,6 +927,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
int ring_base);
u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx);
static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
int n_desc, int ring_base)
{
@ -1077,9 +1124,9 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key);
void mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
__acquires(&dev->status_list.lock);
__acquires(&dev->status_lock);
void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
__releases(&dev->status_list.lock);
__releases(&dev->status_lock);
int mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct sk_buff *skb);
@ -1096,8 +1143,7 @@ mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb)
__mt76_tx_complete_skb(dev, wcid, skb, NULL);
}
void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid,
bool flush);
void mt76_tx_status_check(struct mt76_dev *dev, bool flush);
int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
@ -1203,6 +1249,8 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
}
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats);
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
u8 req_type, u16 val, u16 offset,
@ -1220,8 +1268,27 @@ void mt76u_queues_deinit(struct mt76_dev *dev);
int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
const struct mt76_bus_ops *bus_ops);
int mt76s_alloc_queues(struct mt76_dev *dev);
int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid);
int mt76s_alloc_tx(struct mt76_dev *dev);
void mt76s_deinit(struct mt76_dev *dev);
void mt76s_sdio_irq(struct sdio_func *func);
void mt76s_txrx_worker(struct mt76_sdio *sdio);
bool mt76s_txqs_empty(struct mt76_dev *dev);
int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func,
int hw_ver);
u32 mt76s_rr(struct mt76_dev *dev, u32 offset);
void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val);
u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
u32 mt76s_read_pcr(struct mt76_dev *dev);
void mt76s_write_copy(struct mt76_dev *dev, u32 offset,
const void *data, int len);
void mt76s_read_copy(struct mt76_dev *dev, u32 offset,
void *data, int len);
int mt76s_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data,
int len);
int mt76s_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data, int len);
struct sk_buff *
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
@ -1233,8 +1300,17 @@ int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
int len, bool wait_resp, struct sk_buff **ret);
int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp, struct sk_buff **ret);
int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len);
int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len, int max_len);
static inline int
mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len)
{
int max_len = 4096 - dev->mcu_ops->headroom;
return __mt76_mcu_send_firmware(dev, cmd, data, len, max_len);
}
static inline int
mt76_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len,
bool wait_resp)
@ -1293,14 +1369,22 @@ mt76_token_put(struct mt76_dev *dev, int token)
return txwi;
}
static inline int
mt76_get_next_pkt_id(struct mt76_wcid *wcid)
static inline void mt76_packet_id_init(struct mt76_wcid *wcid)
{
wcid->packet_id = (wcid->packet_id + 1) & MT_PACKET_ID_MASK;
if (wcid->packet_id == MT_PACKET_ID_NO_ACK ||
wcid->packet_id == MT_PACKET_ID_NO_SKB)
wcid->packet_id = MT_PACKET_ID_FIRST;
return wcid->packet_id;
INIT_LIST_HEAD(&wcid->list);
idr_init(&wcid->pktid);
}
static inline void
mt76_packet_id_flush(struct mt76_dev *dev, struct mt76_wcid *wcid)
{
struct sk_buff_head list;
mt76_tx_status_lock(dev, &list);
mt76_tx_status_skb_get(dev, wcid, -1, &list);
mt76_tx_status_unlock(dev, &list);
idr_destroy(&wcid->pktid);
}
#endif

View File

@ -1458,7 +1458,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
mt76_queue_rx_reset(dev, i);
}
mt76_tx_status_check(&dev->mt76, NULL, true);
mt76_tx_status_check(&dev->mt76, true);
mt7603_dma_sched_reset(dev);
@ -1471,17 +1471,20 @@ skip_dma_reset:
mutex_unlock(&dev->mt76.mutex);
mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
mt7603_beacon_set_timer(dev, -1, beacon_int);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
napi_enable(&dev->mt76.napi[0]);
napi_schedule(&dev->mt76.napi[0]);
napi_enable(&dev->mt76.napi[1]);
napi_schedule(&dev->mt76.napi[1]);
local_bh_enable();
ieee80211_wake_queues(dev->mt76.hw);
mt76_txq_schedule_all(&dev->mphy);
@ -1814,7 +1817,7 @@ void mt7603_mac_work(struct work_struct *work)
bool reset = false;
int i, idx;
mt76_tx_status_check(&dev->mt76, NULL, false);
mt76_tx_status_check(&dev->mt76, false);
mutex_lock(&dev->mt76.mutex);

View File

@ -69,6 +69,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.hw_key_idx = -1;
mt76_packet_id_init(&mvif->sta.wcid);
eth_broadcast_addr(bc_addr);
mt7603_wtbl_init(dev, idx, mvif->idx, bc_addr);
@ -107,6 +108,8 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mutex_lock(&dev->mt76.mutex);
dev->mt76.vif_mask &= ~BIT(mvif->idx);
mutex_unlock(&dev->mt76.mutex);
mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
}
void mt7603_init_edcca(struct mt7603_dev *dev)

View File

@ -28,7 +28,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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;

View File

@ -17,4 +17,4 @@ mt7615e-$(CONFIG_MT7622_WMAC) += soc.o
mt7663-usb-sdio-common-y := usb_sdio.o
mt7663u-y := usb.o usb_mcu.o
mt7663s-y := sdio.o sdio_mcu.o sdio_txrx.o
mt7663s-y := sdio.o sdio_mcu.o

View File

@ -2,6 +2,33 @@
#include "mt7615.h"
static int
mt7615_reg_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
mt7615_mutex_acquire(dev);
mt76_wr(dev, dev->mt76.debugfs_reg, val);
mt7615_mutex_release(dev);
return 0;
}
static int
mt7615_reg_get(void *data, u64 *val)
{
struct mt7615_dev *dev = data;
mt7615_mutex_acquire(dev);
*val = mt76_rr(dev, dev->mt76.debugfs_reg);
mt7615_mutex_release(dev);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7615_reg_get, mt7615_reg_set,
"0x%08llx\n");
static int
mt7615_radar_pattern_set(void *data, u64 val)
{
@ -506,7 +533,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
dir = mt76_register_debugfs(&dev->mt76);
dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
if (!dir)
return -ENOMEM;

View File

@ -49,12 +49,14 @@ int mt7615_thermal_init(struct mt7615_dev *dev)
{
struct wiphy *wiphy = mt76_hw(dev)->wiphy;
struct device *hwmon;
const char *name;
if (!IS_REACHABLE(CONFIG_HWMON))
return 0;
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev,
wiphy_name(wiphy), dev,
name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7615_%s",
wiphy_name(wiphy));
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, dev,
mt7615_hwmon_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);

View File

@ -755,12 +755,15 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
if (!is_mmio)
txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
txwi[7] = cpu_to_le32(val);
if (!is_mmio) {
val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
txwi[8] = cpu_to_le32(val);
}
return 0;
}
@ -1493,31 +1496,40 @@ out:
rcu_read_unlock();
}
static void
mt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi)
{
struct mt76_dev *mdev = &dev->mt76;
__le32 *txwi_data;
u32 val;
u8 wcid;
mt7615_txp_skb_unmap(mdev, txwi);
if (!txwi->skb)
goto out;
txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
val = le32_to_cpu(txwi_data[1]);
wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
mt76_tx_complete_skb(mdev, wcid, txwi->skb);
out:
txwi->skb = NULL;
mt76_put_txwi(mdev, txwi);
}
static void
mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
{
struct mt76_dev *mdev = &dev->mt76;
struct mt76_txwi_cache *txwi;
__le32 *txwi_data;
u32 val;
u8 wcid;
trace_mac_tx_free(dev, token);
txwi = mt76_token_put(mdev, token);
if (!txwi)
return;
txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
val = le32_to_cpu(txwi_data[1]);
wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
mt7615_txp_skb_unmap(mdev, txwi);
if (txwi->skb) {
mt76_tx_complete_skb(mdev, wcid, txwi->skb);
txwi->skb = NULL;
}
mt76_put_txwi(mdev, txwi);
mt7615_txwi_free(dev, txwi);
}
static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
@ -2014,7 +2026,7 @@ void mt7615_mac_work(struct work_struct *work)
mt7615_mutex_release(phy->dev);
mt76_tx_status_check(mphy->dev, NULL, false);
mt76_tx_status_check(mphy->dev, false);
timeout = mt7615_get_macwork_timeout(phy->dev);
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout);
@ -2026,16 +2038,8 @@ void mt7615_tx_token_put(struct mt7615_dev *dev)
int id;
spin_lock_bh(&dev->mt76.token_lock);
idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7615_txp_skb_unmap(&dev->mt76, txwi);
if (txwi->skb) {
struct ieee80211_hw *hw;
hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
ieee80211_free_txskb(hw, txwi->skb);
}
mt76_put_txwi(&dev->mt76, txwi);
}
idr_for_each_entry(&dev->mt76.token, txwi, id)
mt7615_txwi_free(dev, txwi);
spin_unlock_bh(&dev->mt76.token_lock);
idr_destroy(&dev->mt76.token);
}

View File

@ -231,6 +231,8 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.ext_phy = mvif->mt76.band_idx;
mvif->sta.wcid.hw_key_idx = -1;
mt76_packet_id_init(&mvif->sta.wcid);
mt7615_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@ -281,6 +283,8 @@ static void mt7615_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, &mvif->sta.wcid);
}
static void mt7615_init_dfs_state(struct mt7615_phy *phy)
@ -567,8 +571,8 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
mt7615_mcu_add_bss_info(phy, vif, NULL, true);
mt7615_mcu_sta_add(phy, vif, NULL, true);
if (vif->p2p)
mt7615_mcu_set_p2p_oppps(hw, vif);
if (mt7615_firmware_offload(dev) && vif->p2p)
mt76_connac_mcu_set_p2p_oppps(hw, vif);
}
if (changed & (BSS_CHANGED_BEACON |
@ -858,8 +862,6 @@ mt7615_get_stats(struct ieee80211_hw *hw,
stats->dot11FCSErrorCount = mib->fcs_err_cnt;
stats->dot11ACKFailureCount = mib->ack_fail_cnt;
memset(mib, 0, sizeof(*mib));
mt7615_mutex_release(phy->dev);
return 0;

View File

@ -808,7 +808,8 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
static int
mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable)
struct ieee80211_sta *sta, struct mt7615_phy *phy,
bool enable)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA;
@ -821,6 +822,7 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MONITOR:
break;
case NL80211_IFTYPE_STATION:
/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
@ -840,14 +842,19 @@ mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
}
bss = (struct bss_info_basic *)tlv;
memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
bss->network_type = cpu_to_le32(type);
bss->dtim_period = vif->bss_conf.dtim_period;
bss->bmc_tx_wlan_idx = wlan_idx;
bss->wmm_idx = mvif->mt76.wmm_idx;
bss->active = enable;
if (vif->type != NL80211_IFTYPE_MONITOR) {
memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
bss->dtim_period = vif->bss_conf.dtim_period;
} else {
memcpy(bss->bssid, phy->mt76->macaddr, ETH_ALEN);
}
return 0;
}
@ -863,6 +870,7 @@ mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac));
switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
if (vif->p2p)
@ -929,7 +937,7 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
if (enable)
mt7615_mcu_bss_omac_tlv(skb, vif);
mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable);
mt7615_mcu_bss_basic_tlv(skb, vif, sta, phy, enable);
if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START &&
mvif->mt76.omac_idx < REPEATER_BSSID_START)
@ -2761,53 +2769,3 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req,
sizeof(req), false);
}
int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct {
__le32 ct_win;
u8 bss_idx;
u8 rsv[3];
} __packed req = {
.ct_win = cpu_to_le32(ct_window),
.bss_idx = mvif->mt76.idx,
};
if (!mt7615_firmware_offload(dev))
return -ENOTSUPP;
return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, &req,
sizeof(req), false);
}
u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset)
{
struct {
__le32 addr;
__le32 val;
} __packed req = {
.addr = cpu_to_le32(offset),
};
return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req),
true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr);
void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
struct {
__le32 addr;
__le32 val;
} __packed req = {
.addr = cpu_to_le32(offset),
.val = cpu_to_le32(val),
};
mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr);

View File

@ -107,6 +107,18 @@ struct mt7615_wtbl_rate_desc {
struct mt7615_sta *sta;
};
struct mt7663s_intr {
u32 isr;
struct {
u32 wtqcr[8];
} tx;
struct {
u16 num[2];
u16 len[2][16];
} rx;
u32 rec_mb[2];
} __packed;
struct mt7615_sta {
struct mt76_wcid wcid; /* must be first */
@ -541,8 +553,6 @@ int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy);
int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy);
int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy);
int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration);
@ -555,8 +565,6 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
bool enable);
int __mt7663_load_firmware(struct mt7615_dev *dev);
u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset);
void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
void mt7615_coredump_work(struct work_struct *work);
void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en);
@ -573,10 +581,6 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
int mt7663u_mcu_init(struct mt7615_dev *dev);
/* sdio */
u32 mt7663s_read_pcr(struct mt7615_dev *dev);
int mt7663s_mcu_init(struct mt7615_dev *dev);
void mt7663s_txrx_worker(struct mt76_worker *w);
void mt7663s_rx_work(struct work_struct *work);
void mt7663s_sdio_irq(struct sdio_func *func);
#endif

View File

@ -39,7 +39,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
if (ret < 0)
return ret;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
goto error;
@ -164,12 +164,14 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
dev_err(mdev->dev, "PDMA engine must be reinitialized\n");
mt76_worker_enable(&mdev->tx_worker);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
}
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
local_bh_enable();
if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
mt7615_firmware_offload(dev))

View File

@ -198,7 +198,7 @@ void mt7615_dma_reset(struct mt7615_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);
mt7615_dma_start(dev);
}
@ -326,6 +326,8 @@ void mt7615_mac_reset_work(struct work_struct *work)
clear_bit(MT76_RESET, &phy2->mt76->state);
mt76_worker_enable(&dev->mt76.tx_worker);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
@ -334,6 +336,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
napi_enable(&dev->mt76.napi[1]);
napi_schedule(&dev->mt76.napi[1]);
local_bh_enable();
ieee80211_wake_queues(mt76_hw(dev));
if (ext_phy)

View File

@ -14,8 +14,8 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include "../sdio.h"
#include "mt7615.h"
#include "sdio.h"
#include "mac.h"
#include "mcu.h"
@ -24,200 +24,19 @@ static const struct sdio_device_id mt7663s_table[] = {
{ } /* Terminating entry */
};
static u32 mt7663s_read_whisr(struct mt76_dev *dev)
static void mt7663s_txrx_worker(struct mt76_worker *w)
{
return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
}
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
u32 mt7663s_read_pcr(struct mt7615_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
}
static u32 mt7663s_read_mailbox(struct mt76_dev *dev, u32 offset)
{
struct sdio_func *func = dev->sdio.func;
u32 val = ~0, status;
int err;
sdio_claim_host(func);
sdio_writel(func, offset, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting address [err=%d]\n", err);
goto out;
if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(mdev->wq, &dev->pm.wake_work);
return;
}
sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
goto out;
}
err = readx_poll_timeout(mt7663s_read_whisr, dev, status,
status & H2D_SW_INT_READ, 0, 1000000);
if (err < 0) {
dev_err(dev->dev, "query whisr timeout\n");
goto out;
}
sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
goto out;
}
val = sdio_readl(func, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
goto out;
}
if (val != offset) {
dev_err(dev->dev, "register mismatch\n");
val = ~0;
goto out;
}
val = sdio_readl(func, MCR_D2HRM1R, &err);
if (err < 0)
dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err);
out:
sdio_release_host(func);
return val;
}
static void mt7663s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val)
{
struct sdio_func *func = dev->sdio.func;
u32 status;
int err;
sdio_claim_host(func);
sdio_writel(func, offset, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting address [err=%d]\n", err);
goto out;
}
sdio_writel(func, val, MCR_H2DSM1R, &err);
if (err < 0) {
dev_err(dev->dev,
"failed setting write value [err=%d]\n", err);
goto out;
}
sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
goto out;
}
err = readx_poll_timeout(mt7663s_read_whisr, dev, status,
status & H2D_SW_INT_WRITE, 0, 1000000);
if (err < 0) {
dev_err(dev->dev, "query whisr timeout\n");
goto out;
}
sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
goto out;
}
val = sdio_readl(func, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
goto out;
}
if (val != offset)
dev_err(dev->dev, "register mismatch\n");
out:
sdio_release_host(func);
}
static u32 mt7663s_rr(struct mt76_dev *dev, u32 offset)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
return dev->mcu_ops->mcu_rr(dev, offset);
else
return mt7663s_read_mailbox(dev, offset);
}
static void mt7663s_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
dev->mcu_ops->mcu_wr(dev, offset, val);
else
mt7663s_write_mailbox(dev, offset, val);
}
static u32 mt7663s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
{
val |= mt7663s_rr(dev, offset) & ~mask;
mt7663s_wr(dev, offset, val);
return val;
}
static void mt7663s_write_copy(struct mt76_dev *dev, u32 offset,
const void *data, int len)
{
const u32 *val = data;
int i;
for (i = 0; i < len / sizeof(u32); i++) {
mt7663s_wr(dev, offset, val[i]);
offset += sizeof(u32);
}
}
static void mt7663s_read_copy(struct mt76_dev *dev, u32 offset,
void *data, int len)
{
u32 *val = data;
int i;
for (i = 0; i < len / sizeof(u32); i++) {
val[i] = mt7663s_rr(dev, offset);
offset += sizeof(u32);
}
}
static int mt7663s_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data,
int len)
{
int i;
for (i = 0; i < len; i++) {
mt7663s_wr(dev, data->reg, data->value);
data++;
}
return 0;
}
static int mt7663s_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data,
int len)
{
int i;
for (i = 0; i < len; i++) {
data->value = mt7663s_rr(dev, data->reg);
data++;
}
return 0;
mt76s_txrx_worker(sdio);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
static void mt7663s_init_work(struct work_struct *work)
@ -231,64 +50,24 @@ static void mt7663s_init_work(struct work_struct *work)
mt7615_init_work(dev);
}
static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func)
static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
{
u32 status, ctrl;
int ret;
struct mt76_sdio *sdio = &dev->sdio;
struct mt7663s_intr *irq_data = sdio->intr_data;
int i, err;
sdio_claim_host(func);
err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
if (err)
return err;
ret = sdio_enable_func(func);
if (ret < 0)
goto release;
/* Get ownership from the device */
sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR,
MCR_WHLPCR, &ret);
if (ret < 0)
goto disable_func;
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot get ownership from device");
goto disable_func;
}
ret = sdio_set_block_size(func, 512);
if (ret < 0)
goto disable_func;
/* Enable interrupt */
sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret);
if (ret < 0)
goto disable_func;
ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN;
sdio_writel(func, ctrl, MCR_WHIER, &ret);
if (ret < 0)
goto disable_func;
/* set WHISR as read clear and Rx aggregation number as 16 */
ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16);
sdio_writel(func, ctrl, MCR_WHCR, &ret);
if (ret < 0)
goto disable_func;
ret = sdio_claim_irq(func, mt7663s_sdio_irq);
if (ret < 0)
goto disable_func;
sdio_release_host(func);
intr->isr = irq_data->isr;
intr->rec_mb = irq_data->rec_mb;
intr->tx.wtqcr = irq_data->tx.wtqcr;
intr->rx.num = irq_data->rx.num;
for (i = 0; i < 2 ; i++)
intr->rx.len[i] = irq_data->rx.len[i];
return 0;
disable_func:
sdio_disable_func(func);
release:
sdio_release_host(func);
return ret;
}
static int mt7663s_probe(struct sdio_func *func,
@ -307,13 +86,13 @@ static int mt7663s_probe(struct sdio_func *func,
.update_survey = mt7615_update_channel,
};
static const struct mt76_bus_ops mt7663s_ops = {
.rr = mt7663s_rr,
.rmw = mt7663s_rmw,
.wr = mt7663s_wr,
.write_copy = mt7663s_write_copy,
.read_copy = mt7663s_read_copy,
.wr_rp = mt7663s_wr_rp,
.rd_rp = mt7663s_rd_rp,
.rr = mt76s_rr,
.rmw = mt76s_rmw,
.wr = mt76s_wr,
.write_copy = mt76s_write_copy,
.read_copy = mt76s_read_copy,
.wr_rp = mt76s_wr_rp,
.rd_rp = mt76s_rd_rp,
.type = MT76_BUS_SDIO,
};
struct ieee80211_ops *ops;
@ -341,7 +120,7 @@ static int mt7663s_probe(struct sdio_func *func,
if (ret < 0)
goto error;
ret = mt7663s_hw_init(dev, func);
ret = mt76s_hw_init(mdev, func, MT76_CONNAC_SDIO);
if (ret)
goto error;
@ -349,8 +128,9 @@ static int mt7663s_probe(struct sdio_func *func,
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
mdev->sdio.parse_irq = mt7663s_parse_intr;
mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
sizeof(struct mt76s_intr),
sizeof(struct mt7663s_intr),
GFP_KERNEL);
if (!mdev->sdio.intr_data) {
ret = -ENOMEM;
@ -367,7 +147,11 @@ static int mt7663s_probe(struct sdio_func *func,
}
}
ret = mt76s_alloc_queues(&dev->mt76);
ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
if (ret)
goto error;
ret = mt76s_alloc_tx(mdev);
if (ret)
goto error;
@ -432,7 +216,7 @@ static int mt7663s_suspend(struct device *dev)
cancel_work_sync(&mdev->mt76.sdio.stat_work);
clear_bit(MT76_READING_STATS, &mdev->mphy.state);
mt76_tx_status_check(&mdev->mt76, NULL, true);
mt76_tx_status_check(&mdev->mt76, true);
return 0;
}

View File

@ -10,11 +10,11 @@
#include <linux/module.h>
#include <linux/iopoll.h>
#include "../sdio.h"
#include "mt7615.h"
#include "mac.h"
#include "mcu.h"
#include "regs.h"
#include "sdio.h"
static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
{
@ -27,6 +27,7 @@ static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
MT_HIF1_MIN_QUOTA);
sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP,
MT_HIF0_MIN_QUOTA);
sdio->sched.pse_page_size = MT_PSE_PAGE_SZ;
txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT,
MT_PP_TXDWCNT_TX1_ADD_DW_CNT);
sdio->sched.deficit = txdwcnt << 2;
@ -63,7 +64,7 @@ static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot get ownership from device");
@ -111,7 +112,7 @@ static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)
sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
ret = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
if (ret < 0) {
dev_err(dev->mt76.dev, "Cannot set ownership to device");
@ -137,8 +138,8 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.mcu_skb_send_msg = mt7663s_mcu_send_message,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
.mcu_rr = mt7615_mcu_reg_rr,
.mcu_wr = mt7615_mcu_reg_wr,
.mcu_rr = mt76_connac_mcu_reg_rr,
.mcu_wr = mt76_connac_mcu_reg_wr,
};
struct mt7615_mcu_ops *mcu_ops;
int ret;

View File

@ -169,7 +169,7 @@ bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
mt7615_mac_sta_poll(dev);
mt7615_mutex_release(dev);
return 0;
return false;
}
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data);

View File

@ -85,9 +85,14 @@ struct mt76_connac_coredump {
extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;
static inline bool is_mt7922(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7922;
}
static inline bool is_mt7921(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7961;
return mt76_chip(dev) == 0x7961 || is_mt7922(dev);
}
static inline bool is_mt7663(struct mt76_dev *dev)

View File

@ -74,7 +74,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download);
int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0;
struct mt76_connac_mcu_channel_domain {
u8 alpha2[4]; /* regulatory_request.alpha2 */
u8 bw_2g; /* BW_20_40M 0
@ -84,25 +84,29 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy)
* BW_20_40_80_8080M 4
*/
u8 bw_5g;
__le16 pad;
u8 bw_6g;
u8 pad;
u8 n_2ch;
u8 n_5ch;
__le16 pad2;
u8 n_6ch;
u8 pad2;
} __packed hdr = {
.bw_2g = 0,
.bw_5g = 3,
.bw_5g = 3, /* BW_20_40_80_160M */
.bw_6g = 3,
};
struct mt76_connac_mcu_chan {
__le16 hw_value;
__le16 pad;
__le32 flags;
} __packed channel;
int len, i, n_max_channels, n_2ch = 0, n_5ch = 0;
struct mt76_dev *dev = phy->dev;
struct ieee80211_channel *chan;
struct sk_buff *skb;
n_max_channels = phy->sband_2g.sband.n_channels +
phy->sband_5g.sband.n_channels;
phy->sband_5g.sband.n_channels +
phy->sband_6g.sband.n_channels;
len = sizeof(hdr) + n_max_channels * sizeof(channel);
skb = mt76_mcu_msg_alloc(dev, NULL, len);
@ -135,11 +139,24 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy)
skb_put_data(skb, &channel, sizeof(channel));
n_5ch++;
}
for (i = 0; i < phy->sband_6g.sband.n_channels; i++) {
chan = &phy->sband_6g.sband.channels[i];
if (chan->flags & IEEE80211_CHAN_DISABLED)
continue;
channel.hw_value = cpu_to_le16(chan->hw_value);
channel.flags = cpu_to_le32(chan->flags);
channel.pad = 0;
skb_put_data(skb, &channel, sizeof(channel));
n_6ch++;
}
BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(hdr.alpha2));
memcpy(hdr.alpha2, dev->alpha2, sizeof(dev->alpha2));
hdr.n_2ch = n_2ch;
hdr.n_5ch = n_5ch;
hdr.n_6ch = n_6ch;
memcpy(__skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
@ -689,9 +706,9 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
if (ht_cap->ht_supported)
mode |= PHY_TYPE_BIT_HT;
if (he_cap->has_he)
if (he_cap && he_cap->has_he)
mode |= PHY_TYPE_BIT_HE;
} else if (band == NL80211_BAND_5GHZ) {
} else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
mode |= PHY_TYPE_BIT_OFDM;
if (ht_cap->ht_supported)
@ -700,7 +717,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
if (vht_cap->vht_supported)
mode |= PHY_TYPE_BIT_VHT;
if (he_cap->has_he)
if (he_cap && he_cap->has_he)
mode |= PHY_TYPE_BIT_HE;
}
@ -719,6 +736,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
struct sta_rec_state *state;
struct sta_rec_phy *phy;
struct tlv *tlv;
u16 supp_rates;
/* starec ht */
if (sta->ht_cap.ht_supported) {
@ -748,12 +766,22 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
if (!is_mt7921(dev))
return;
if (sta->ht_cap.ht_supported)
if (sta->ht_cap.ht_supported || sta->he_cap.has_he)
mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif);
/* starec he */
if (sta->he_cap.has_he)
if (sta->he_cap.has_he) {
mt76_connac_mcu_sta_he_tlv(skb, sta);
if (band == NL80211_BAND_6GHZ &&
sta_state == MT76_STA_INFO_STATE_ASSOC) {
struct sta_rec_he_6g_capa *he_6g_capa;
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G,
sizeof(*he_6g_capa));
he_6g_capa = (struct sta_rec_he_6g_capa *)tlv;
he_6g_capa->capa = sta->he_6ghz_capa.capa;
}
}
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));
phy = (struct sta_rec_phy *)tlv;
@ -767,7 +795,15 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));
ra_info = (struct sta_rec_ra_info *)tlv;
ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]);
supp_rates = sta->supp_rates[band];
if (band == NL80211_BAND_2GHZ)
supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) |
FIELD_PREP(RA_LEGACY_CCK, supp_rates & 0xf);
else
supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates);
ra_info->legacy = cpu_to_le16(supp_rates);
if (sta->ht_cap.ht_supported)
memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask,
@ -1145,7 +1181,7 @@ mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
if (he_cap->has_he)
mode |= PHY_MODE_AX_24G;
} else if (band == NL80211_BAND_5GHZ) {
} else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) {
mode |= PHY_MODE_A;
if (ht_cap->ht_supported)
@ -1154,8 +1190,12 @@ mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
if (vht_cap->vht_supported)
mode |= PHY_MODE_AC;
if (he_cap->has_he)
mode |= PHY_MODE_AX_5G;
if (he_cap->has_he) {
if (band == NL80211_BAND_6GHZ)
mode |= PHY_MODE_AX_6G;
else
mode |= PHY_MODE_AX_5G;
}
}
return mode;
@ -1252,7 +1292,8 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
u8 short_st;
u8 ht_op_info;
u8 sco;
u8 pad[3];
u8 band;
u8 pad[2];
} __packed rlm;
} __packed rlm_req = {
.hdr = {
@ -1268,13 +1309,19 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
.ht_op_info = 4, /* set HT 40M allowed */
.rx_streams = phy->chainmask,
.short_st = true,
.band = band,
},
};
int err, conn_type;
u8 idx;
u8 idx, basic_phy;
idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
basic_req.basic.hw_bss_idx = idx;
if (band == NL80211_BAND_6GHZ)
basic_req.basic.phymode_ext = BIT(0);
basic_phy = mt76_connac_get_phy_mode_v2(phy, vif, band, NULL);
basic_req.basic.nonht_basic_phy = cpu_to_le16(basic_phy);
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
@ -1445,7 +1492,17 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif,
else
chan = &req->channels[i];
chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2;
switch (scan_list[i]->band) {
case NL80211_BAND_2GHZ:
chan->band = 1;
break;
case NL80211_BAND_6GHZ:
chan->band = 3;
break;
default:
chan->band = 2;
break;
}
chan->channel_num = scan_list[i]->hw_value;
}
req->channel_type = sreq->n_channels ? 4 : 0;
@ -1531,8 +1588,10 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
get_random_mask_addr(addr, sreq->mac_addr,
sreq->mac_addr_mask);
}
if (is_mt7921(phy->dev))
if (is_mt7921(phy->dev)) {
req->mt7921.bss_idx = mvif->idx;
req->mt7921.delay = cpu_to_le32(sreq->delay);
}
req->ssids_num = sreq->n_ssids;
for (i = 0; i < req->ssids_num; i++) {
@ -1554,7 +1613,18 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
req->channels_num = min_t(u8, sreq->n_channels, 64);
for (i = 0; i < req->channels_num; i++) {
chan = &req->channels[i];
chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2;
switch (scan_list[i]->band) {
case NL80211_BAND_2GHZ:
chan->band = 1;
break;
case NL80211_BAND_6GHZ:
chan->band = 3;
break;
default:
chan->band = 2;
break;
}
chan->channel_num = scan_list[i]->hw_value;
}
@ -1652,6 +1722,61 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);
static void mt76_connac_mcu_parse_tx_resource(struct mt76_dev *dev,
struct sk_buff *skb)
{
struct mt76_sdio *sdio = &dev->sdio;
struct mt76_connac_tx_resource {
__le32 version;
__le32 pse_data_quota;
__le32 pse_mcu_quota;
__le32 ple_data_quota;
__le32 ple_mcu_quota;
__le16 pse_page_size;
__le16 ple_page_size;
u8 pp_padding;
u8 pad[3];
} __packed * tx_res;
tx_res = (struct mt76_connac_tx_resource *)skb->data;
sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota);
sdio->sched.pse_mcu_quota = le32_to_cpu(tx_res->pse_mcu_quota);
sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota);
sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size);
sdio->sched.deficit = tx_res->pp_padding;
}
static void mt76_connac_mcu_parse_phy_cap(struct mt76_dev *dev,
struct sk_buff *skb)
{
struct mt76_connac_phy_cap {
u8 ht;
u8 vht;
u8 _5g;
u8 max_bw;
u8 nss;
u8 dbdc;
u8 tx_ldpc;
u8 rx_ldpc;
u8 tx_stbc;
u8 rx_stbc;
u8 hw_path;
u8 he;
} __packed * cap;
enum {
WF0_24G,
WF0_5G
};
cap = (struct mt76_connac_phy_cap *)skb->data;
dev->phy.antenna_mask = BIT(cap->nss) - 1;
dev->phy.chainmask = dev->phy.antenna_mask;
dev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G);
dev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G);
}
int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
{
struct mt76_connac_cap_hdr {
@ -1694,6 +1819,17 @@ int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
case MT_NIC_CAP_6G:
phy->cap.has_6ghz = skb->data[0];
break;
case MT_NIC_CAP_MAC_ADDR:
memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN);
break;
case MT_NIC_CAP_PHY:
mt76_connac_mcu_parse_phy_cap(phy->dev, skb);
break;
case MT_NIC_CAP_TX_RESOURCE:
if (mt76_is_sdio(phy->dev))
mt76_connac_mcu_parse_tx_resource(phy->dev,
skb);
break;
default:
break;
}
@ -1749,6 +1885,70 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
}
}
static s8 mt76_connac_get_sar_power(struct mt76_phy *phy,
struct ieee80211_channel *chan,
s8 target_power)
{
const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
struct mt76_freq_range_power *frp = phy->frp;
int freq, i;
if (!capa || !frp)
return target_power;
freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
for (i = 0 ; i < capa->num_freq_ranges; i++) {
if (frp[i].range &&
freq >= frp[i].range->start_freq &&
freq < frp[i].range->end_freq) {
target_power = min_t(s8, frp[i].power, target_power);
break;
}
}
return target_power;
}
static s8 mt76_connac_get_ch_power(struct mt76_phy *phy,
struct ieee80211_channel *chan,
s8 target_power)
{
struct mt76_dev *dev = phy->dev;
struct ieee80211_supported_band *sband;
int i;
switch (chan->band) {
case NL80211_BAND_2GHZ:
sband = &phy->sband_2g.sband;
break;
case NL80211_BAND_5GHZ:
sband = &phy->sband_5g.sband;
break;
case NL80211_BAND_6GHZ:
sband = &phy->sband_6g.sband;
break;
default:
return target_power;
}
for (i = 0; i < sband->n_channels; i++) {
struct ieee80211_channel *ch = &sband->channels[i];
if (ch->hw_value == chan->hw_value) {
if (!(ch->flags & IEEE80211_CHAN_DISABLED)) {
int power = 2 * ch->max_reg_power;
if (is_mt7663(dev) && (power > 63 || power < -64))
power = 63;
target_power = min_t(s8, power, target_power);
}
break;
}
}
return target_power;
}
static int
mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
enum nl80211_band band)
@ -1768,6 +1968,24 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
142, 144, 149, 151, 153, 155, 157,
159, 161, 165
};
static const u8 chan_list_6ghz[] = {
1, 3, 5, 7, 9, 11, 13,
15, 17, 19, 21, 23, 25, 27,
29, 33, 35, 37, 39, 41, 43,
45, 47, 49, 51, 53, 55, 57,
59, 61, 65, 67, 69, 71, 73,
75, 77, 79, 81, 83, 85, 87,
89, 91, 93, 97, 99, 101, 103,
105, 107, 109, 111, 113, 115, 117,
119, 121, 123, 125, 129, 131, 133,
135, 137, 139, 141, 143, 145, 147,
149, 151, 153, 155, 157, 161, 163,
165, 167, 169, 171, 173, 175, 177,
179, 181, 183, 185, 187, 189, 193,
195, 197, 199, 201, 203, 205, 207,
209, 211, 213, 215, 217, 219, 221,
225, 227, 229, 233
};
int i, n_chan, batch_size, idx = 0, tx_power, last_ch;
struct mt76_connac_sku_tlv sku_tlbv;
struct mt76_power_limits limits;
@ -1781,6 +1999,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
if (band == NL80211_BAND_2GHZ) {
n_chan = ARRAY_SIZE(chan_list_2ghz);
ch_list = chan_list_2ghz;
} else if (band == NL80211_BAND_6GHZ) {
n_chan = ARRAY_SIZE(chan_list_6ghz);
ch_list = chan_list_6ghz;
} else {
n_chan = ARRAY_SIZE(chan_list_5ghz);
ch_list = chan_list_5ghz;
@ -1789,13 +2010,13 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
if (!phy->cap.has_5ghz)
last_ch = chan_list_2ghz[n_chan - 1];
else if (phy->cap.has_6ghz)
last_ch = chan_list_6ghz[n_chan - 1];
else
last_ch = chan_list_5ghz[n_chan - 1];
for (i = 0; i < batch_size; i++) {
struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
.band = band == NL80211_BAND_2GHZ ? 1 : 2,
};
struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {};
int j, err, msg_len, num_ch;
struct sk_buff *skb;
@ -1811,14 +2032,32 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));
tx_power_tlv.n_chan = num_ch;
switch (band) {
case NL80211_BAND_2GHZ:
tx_power_tlv.band = 1;
break;
case NL80211_BAND_6GHZ:
tx_power_tlv.band = 3;
break;
default:
tx_power_tlv.band = 2;
break;
}
for (j = 0; j < num_ch; j++, idx++) {
struct ieee80211_channel chan = {
.hw_value = ch_list[idx],
.band = band,
};
s8 reg_power, sar_power;
reg_power = mt76_connac_get_ch_power(phy, &chan,
tx_power);
sar_power = mt76_connac_get_sar_power(phy, &chan,
reg_power);
mt76_get_rate_power_limits(phy, &chan, &limits,
tx_power);
sar_power);
tx_power_tlv.last_msg = ch_list[idx] == last_ch;
sku_tlbv.channel = ch_list[idx];
@ -1855,6 +2094,12 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
if (err < 0)
return err;
}
if (phy->cap.has_6ghz) {
err = mt76_connac_mcu_rate_txpower_band(phy,
NL80211_BAND_6GHZ);
if (err < 0)
return err;
}
return 0;
}
@ -1902,6 +2147,26 @@ int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_arp_filter);
int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
int ct_window = vif->bss_conf.p2p_noa_attr.oppps_ctwindow;
struct mt76_phy *phy = hw->priv;
struct {
__le32 ct_win;
u8 bss_idx;
u8 rsv[3];
} __packed req = {
.ct_win = cpu_to_le32(ct_window),
.bss_idx = mvif->idx,
};
return mt76_mcu_send_msg(phy->dev, MCU_CMD_SET_P2P_OPPPS, &req,
sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_p2p_oppps);
#ifdef CONFIG_PM
const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
@ -1929,19 +2194,22 @@ mt76_connac_mcu_key_iter(struct ieee80211_hw *hw,
key->cipher != WLAN_CIPHER_SUITE_TKIP)
return;
if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
cipher = BIT(3);
} else {
gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);
else
cipher = BIT(4);
}
/* we are assuming here to have a single pairwise key */
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_1);
else
gtk_tlv->proto = cpu_to_le32(NL80211_WPA_VERSION_2);
gtk_tlv->pairwise_cipher = cpu_to_le32(cipher);
gtk_tlv->group_cipher = cpu_to_le32(cipher);
gtk_tlv->keyid = key->keyidx;
} else {
gtk_tlv->group_cipher = cpu_to_le32(cipher);
}
}
@ -2210,6 +2478,33 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter);
u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset)
{
struct {
__le32 addr;
__le32 val;
} __packed req = {
.addr = cpu_to_le32(offset),
};
return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req),
true);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_rr);
void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
struct {
__le32 addr;
__le32 val;
} __packed req = {
.addr = cpu_to_le32(offset),
.val = cpu_to_le32(val),
};
mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_wr);
#endif /* CONFIG_PM */
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");

View File

@ -124,6 +124,8 @@ struct sta_rec_state {
u8 rsv[1];
} __packed;
#define RA_LEGACY_OFDM GENMASK(13, 6)
#define RA_LEGACY_CCK GENMASK(3, 0)
#define HT_MCS_MASK_NUM 10
struct sta_rec_ra_info {
__le16 tag;
@ -143,6 +145,13 @@ struct sta_rec_phy {
u8 rsv[2];
} __packed;
struct sta_rec_he_6g_capa {
__le16 tag;
__le16 len;
__le16 capa;
u8 rsv[2];
} __packed;
/* wtbl_rec */
struct wtbl_req_hdr {
@ -301,6 +310,7 @@ struct wtbl_raw {
sizeof(struct sta_rec_vht) + \
sizeof(struct sta_rec_uapsd) + \
sizeof(struct sta_rec_amsdu) + \
sizeof(struct sta_rec_he_6g_capa) + \
sizeof(struct tlv) + \
MT76_CONNAC_WTBL_UPDATE_MAX_SIZE)
@ -327,6 +337,7 @@ enum {
STA_REC_MUEDCA,
STA_REC_BFEE,
STA_REC_PHY = 0x15,
STA_REC_HE_6G = 0x17,
STA_REC_MAX_NUM
};
@ -548,6 +559,7 @@ enum {
/* offload mcu commands */
enum {
MCU_CMD_TEST_CTRL = MCU_CE_PREFIX | 0x01,
MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03,
MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05,
MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f,
@ -560,6 +572,7 @@ enum {
MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62,
MCU_CMD_GET_NIC_CAPAB = MCU_CE_PREFIX | 0x8a,
MCU_CMD_SET_MU_EDCA_PARMS = MCU_CE_PREFIX | 0xb0,
MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0,
MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0,
MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca,
@ -656,10 +669,14 @@ struct mt76_connac_bss_basic_tlv {
* bit(3): GN
* bit(4): AN
* bit(5): AC
* bit(6): AX2
* bit(7): AX5
* bit(8): AX6
*/
__le16 sta_idx;
u8 nonht_basic_phy;
u8 pad[3];
__le16 nonht_basic_phy;
u8 phymode_ext; /* bit(0) AX_6G */
u8 pad[1];
} __packed;
struct mt76_connac_bss_qos_tlv {
@ -802,7 +819,9 @@ struct mt76_connac_sched_scan_req {
} mt7663;
struct {
u8 bss_idx;
u8 pad2[19];
u8 pad1[3];
__le32 delay;
u8 pad2[12];
u8 random_mac[ETH_ALEN];
u8 pad3[38];
} mt7921;
@ -844,14 +863,14 @@ struct mt76_connac_gtk_rekey_tlv {
* 2: rekey update
*/
u8 keyid;
u8 pad[2];
u8 option; /* 1: rekey data update without enabling offload */
u8 pad[1];
__le32 proto; /* WPA-RSN-WAPI-OPSN */
__le32 pairwise_cipher;
__le32 group_cipher;
__le32 key_mgmt; /* NONE-PSK-IEEE802.1X */
__le32 mgmt_group_cipher;
u8 option; /* 1: rekey data update without enabling offload */
u8 reserverd[3];
u8 reserverd[4];
} __packed;
#define MT76_CONNAC_WOW_MASK_MAX_LEN 16
@ -961,7 +980,7 @@ struct mt76_connac_tx_power_limit_tlv {
__le16 len;
/* DW1 - cmd hint */
u8 n_chan; /* # channel */
u8 band; /* 2.4GHz - 5GHz */
u8 band; /* 2.4GHz - 5GHz - 6GHz */
u8 last_msg;
u8 pad1;
/* DW3 */
@ -1093,4 +1112,8 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump);
int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy);
int mt76_connac_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
u32 mt76_connac_mcu_reg_rr(struct mt76_dev *dev, u32 offset);
void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
#endif /* __MT76_CONNAC_MCU_H */

View File

@ -201,7 +201,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev,
t->stbc[6] = t->stbc[7] = s6_to_s8(val >> 8);
/* vht mcs 8, 9 5GHz */
val = mt76x02_eeprom_get(dev, 0x132);
val = mt76x02_eeprom_get(dev, 0x12c);
t->vht[8] = s6_to_s8(val);
t->vht[9] = s6_to_s8(val >> 8);

View File

@ -176,7 +176,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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;
@ -276,6 +276,7 @@ static int mt76x0e_resume(struct pci_dev *pdev)
mt76_worker_enable(&mdev->tx_worker);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
mt76_queue_rx_reset(dev, i);
napi_enable(&mdev->napi[i]);
@ -284,6 +285,7 @@ static int mt76x0e_resume(struct pci_dev *pdev)
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
local_bh_enable();
return mt76x0e_init_hardware(dev, true);
}

View File

@ -176,7 +176,7 @@ void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
}
static __le16
static u16
mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val)
{
@ -222,14 +222,14 @@ mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
rateval |= MT_RXWI_RATE_SGI;
*nss_val = nss;
return cpu_to_le16(rateval);
return rateval;
}
void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate)
{
s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
__le16 rateval;
u16 rateval;
u32 tx_info;
s8 nss;
@ -342,7 +342,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
struct ieee80211_key_conf *key = info->control.hw_key;
u32 wcid_tx_info;
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
u16 txwi_flags = 0;
u16 txwi_flags = 0, rateval;
u8 nss;
s8 txpwr_adj, max_txpwr_adj;
u8 ccmp_pn[8], nstreams = dev->mphy.chainmask & 0xf;
@ -380,14 +380,15 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
if (wcid && (rate->idx < 0 || !rate->count)) {
wcid_tx_info = wcid->tx_info;
txwi->rate = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
rateval = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ,
wcid_tx_info);
nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info);
} else {
txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss);
rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
}
txwi->rate = cpu_to_le16(rateval);
txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf,
max_txpwr_adj);
@ -1185,7 +1186,7 @@ void mt76x02_mac_work(struct work_struct *work)
mutex_unlock(&dev->mt76.mutex);
mt76_tx_status_check(&dev->mt76, NULL, false);
mt76_tx_status_check(&dev->mt76, false);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
MT_MAC_WORK_INTERVAL);

View File

@ -53,7 +53,7 @@ static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t)
mt76_skb_set_moredata(data.tail[i], false);
}
spin_lock_bh(&q->lock);
spin_lock(&q->lock);
while ((skb = __skb_dequeue(&data.q)) != NULL) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
@ -61,7 +61,7 @@ static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t)
mt76_tx_queue_skb(dev, q, skb, &mvif->group_wcid, NULL);
}
spin_unlock_bh(&q->lock);
spin_unlock(&q->lock);
}
static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
@ -472,7 +472,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
mt76_queue_rx_reset(dev, i);
}
mt76_tx_status_check(&dev->mt76, NULL, true);
mt76_tx_status_check(&dev->mt76, true);
mt76x02_mac_start(dev);
@ -491,15 +491,17 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
clear_bit(MT76_RESET, &dev->mphy.state);
mt76_worker_enable(&dev->mt76.tx_worker);
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
mt76_for_each_q_rx(&dev->mt76, i) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
local_bh_enable();
if (restart) {
set_bit(MT76_RESTART, &dev->mphy.state);

View File

@ -287,6 +287,8 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
mvif->idx = idx;
mvif->group_wcid.idx = MT_VIF_WCID(idx);
mvif->group_wcid.hw_key_idx = -1;
mt76_packet_id_init(&mvif->group_wcid);
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->group_wcid;
}
@ -341,6 +343,7 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw,
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
dev->mt76.vif_mask &= ~BIT(mvif->idx);
mt76_packet_id_flush(&dev->mt76, &mvif->group_wcid);
}
EXPORT_SYMBOL_GPL(mt76x02_remove_interface);

View File

@ -47,7 +47,7 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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;
@ -149,12 +149,15 @@ mt76x2e_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
mt76_worker_enable(&mdev->tx_worker);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
}
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
local_bh_enable();
return mt76x2_resume_device(dev);
}

View File

@ -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];
}
}
static int
mt7915_read_rate_txpower(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
mt7915_puts_rate_txpower(s, &dev->phy);
mt7915_puts_rate_txpower(s, mt7915_ext_phy(dev));
return 0;
}
int mt7915_init_debugfs(struct mt7915_dev *dev)
DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower);
static int
mt7915_twt_stats(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
struct mt7915_twt_flow *iter;
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_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

View File

@ -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)

View File

@ -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();
@ -228,12 +267,51 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
}
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--;
}

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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,21 +271,31 @@ 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,
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
};
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,
@ -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 {
@ -1115,17 +1087,22 @@ enum {
THERMAL_PROTECT_STATE_ACT,
};
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))

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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_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_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
#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

View File

@ -165,6 +165,22 @@ mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs)
sizeof(req), false);
}
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;

View File

@ -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

View File

@ -1,11 +1,25 @@
# SPDX-License-Identifier: ISC
config MT7921E
tristate "MediaTek MT7921E (PCIe) support"
config MT7921_COMMON
tristate
select MT76_CONNAC_LIB
select WANT_DEV_COREDUMP
config MT7921E
tristate "MediaTek MT7921E (PCIe) support"
select MT7921_COMMON
depends on MAC80211
depends on PCI
help
This adds support for MT7921E 802.11ax 2x2:2SS wireless devices.
To compile this driver as a module, choose M here.
config MT7921S
tristate "MediaTek MT7921S (SDIO) support"
select MT76_SDIO
select MT7921_COMMON
depends on MAC80211
help
This adds support for MT7921S 802.11ax 2x2:2SS wireless devices.
To compile this driver as a module, choose M here.

View File

@ -1,7 +1,12 @@
# SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7921_COMMON) += mt7921-common.o
obj-$(CONFIG_MT7921E) += mt7921e.o
obj-$(CONFIG_MT7921S) += mt7921s.o
CFLAGS_trace.o := -I$(src)
mt7921e-y := pci.o mac.o mcu.o dma.o eeprom.o main.o init.o debugfs.o trace.o
mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o trace.o
mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7921e-y := pci.o pci_mac.o pci_mcu.o dma.o
mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o

View File

@ -4,6 +4,32 @@
#include "mt7921.h"
#include "eeprom.h"
static int
mt7921_reg_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
mt7921_mutex_acquire(dev);
mt76_wr(dev, dev->mt76.debugfs_reg, val);
mt7921_mutex_release(dev);
return 0;
}
static int
mt7921_reg_get(void *data, u64 *val)
{
struct mt7921_dev *dev = data;
mt7921_mutex_acquire(dev);
*val = mt76_rr(dev, dev->mt76.debugfs_reg);
mt7921_mutex_release(dev);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7921_reg_get, mt7921_reg_set,
"0x%08llx\n");
static int
mt7921_fw_debug_set(void *data, u64 val)
{
@ -42,6 +68,8 @@ mt7921_ampdu_stat_read_phy(struct mt7921_phy *phy,
if (!phy)
return;
mt7921_mac_update_mib_stats(phy);
/* Tx ampdu stat */
for (i = 0; i < ARRAY_SIZE(range); i++)
range[i] = mt76_rr(dev, MT_MIB_ARNG(0, i));
@ -67,26 +95,27 @@ static int
mt7921_tx_stats_show(struct seq_file *file, void *data)
{
struct mt7921_dev *dev = file->private;
int stat[8], i, n;
struct mt7921_phy *phy = &dev->phy;
struct mib_stats *mib = &phy->mib;
int i;
mt7921_ampdu_stat_read_phy(&dev->phy, file);
mt7921_mutex_acquire(dev);
mt7921_ampdu_stat_read_phy(phy, file);
/* Tx amsdu info */
seq_puts(file, "Tx MSDU stat:\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");
}
mt7921_mutex_release(dev);
return 0;
}
@ -98,6 +127,8 @@ mt7921_queues_acq(struct seq_file *s, void *data)
struct mt7921_dev *dev = dev_get_drvdata(s->private);
int i;
mt7921_mutex_acquire(dev);
for (i = 0; i < 16; i++) {
int j, acs = i / 4, index = i % 4;
u32 ctrl, val, qlen = 0;
@ -117,6 +148,8 @@ mt7921_queues_acq(struct seq_file *s, void *data)
seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
}
mt7921_mutex_release(dev);
return 0;
}
@ -229,30 +262,38 @@ mt7921_txpwr(struct seq_file *s, void *data)
return 0;
}
static void
mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt7921_dev *dev = priv;
mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable);
}
static int
mt7921_pm_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_phy *mphy = dev->phy.mt76;
if (val == pm->enable)
return 0;
mt7921_mutex_acquire(dev);
if (val == pm->enable)
goto out;
if (!pm->enable) {
pm->stats.last_wake_event = jiffies;
pm->stats.last_doze_event = jiffies;
}
pm->enable = val;
ieee80211_iterate_active_interfaces(mphy->hw,
ieee80211_iterate_active_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_pm_interface_iter, mphy->priv);
mt7921_pm_interface_iter, dev);
mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable);
out:
mt7921_mutex_release(dev);
return 0;
@ -369,11 +410,25 @@ static int mt7921_chip_reset(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n");
static int
mt7921s_sched_quota_read(struct seq_file *s, void *data)
{
struct mt7921_dev *dev = dev_get_drvdata(s->private);
struct mt76_sdio *sdio = &dev->mt76.sdio;
seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota);
seq_printf(s, "ple_data_quota\t%d\n", sdio->sched.ple_data_quota);
seq_printf(s, "pse_mcu_quota\t%d\n", sdio->sched.pse_mcu_quota);
seq_printf(s, "sched_deficit\t%d\n", sdio->sched.deficit);
return 0;
}
int mt7921_init_debugfs(struct mt7921_dev *dev)
{
struct dentry *dir;
dir = mt76_register_debugfs(&dev->mt76);
dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
if (!dir)
return -ENOMEM;
@ -392,6 +447,8 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
mt7921_pm_stats);
debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds);
if (mt76_is_sdio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir,
mt7921s_sched_quota_read);
return 0;
}

View File

@ -19,46 +19,6 @@ int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc)
return 0;
}
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
__le32 *rxd = (__le32 *)skb->data;
enum rx_pkt_type type;
u16 flag;
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0]));
if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
type = PKT_TYPE_NORMAL_MCU;
switch (type) {
case PKT_TYPE_TXRX_NOTIFY:
mt7921_mac_tx_free(dev, skb);
break;
case PKT_TYPE_RX_EVENT:
mt7921_mcu_rx_event(dev, skb);
break;
case PKT_TYPE_NORMAL_MCU:
case PKT_TYPE_NORMAL:
if (!mt7921_mac_fill_rx(dev, skb)) {
mt76_rx(&dev->mt76, q, skb);
return;
}
fallthrough;
default:
dev_kfree_skb(skb);
break;
}
}
void mt7921_tx_cleanup(struct mt7921_dev *dev)
{
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
}
static int mt7921_poll_tx(struct napi_struct *napi, int budget)
{
struct mt7921_dev *dev;
@ -71,7 +31,7 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)
return 0;
}
mt7921_tx_cleanup(dev);
mt7921_mcu_tx_cleanup(dev);
if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
@ -125,36 +85,37 @@ static u32 __mt7921_reg_addr(struct mt7921_dev *dev, u32 addr)
u32 mapped;
u32 size;
} fixed_map[] = {
{ 0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */
{ 0x00410000, 0x90000, 0x10000}, /* WF_MCU_SYSRAM (configure register) */
{ 0x40000000, 0x70000, 0x10000}, /* WF_UMAC_SYSRAM */
{ 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
{ 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
{ 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
{ 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
{ 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
{ 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
{ 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
{ 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
{ 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */
{ 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */
{ 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */
{ 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */
{ 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */
{ 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */
{ 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */
{ 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */
{ 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */
{ 0x7c060000, 0xe0000, 0x10000}, /* CONN_INFRA, conn_host_csr_top */
{ 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */
{ 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */
{ 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
{ 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */
{ 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */
{ 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */
{ 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */
{ 0x820cd000, 0x0f000, 0x1000 }, /* WF_MDP_TOP */
{ 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */
{ 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */
{ 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
{ 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
{ 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
{ 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
{ 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
{ 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
{ 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
{ 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
{ 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
{ 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
{ 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
{ 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
{ 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
{ 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
{ 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
{ 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
@ -306,7 +267,7 @@ static int mt7921_dma_reset(struct mt7921_dev *dev, bool force)
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
mt76_tx_status_check(&dev->mt76, NULL, true);
mt76_tx_status_check(&dev->mt76, true);
return mt7921_dma_enable(dev);
}
@ -383,6 +344,9 @@ int mt7921_dma_init(struct mt7921_dev *dev)
struct mt76_bus_ops *bus_ops;
int ret;
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
dev->bus_ops = dev->mt76.bus;
bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
GFP_KERNEL);

View File

@ -1,100 +0,0 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7921.h"
#include "eeprom.h"
static u32 mt7921_eeprom_read(struct mt7921_dev *dev, u32 offset)
{
u8 *data = dev->mt76.eeprom.data;
if (data[offset] == 0xff)
mt7921_mcu_get_eeprom(dev, offset);
return data[offset];
}
static int mt7921_eeprom_load(struct mt7921_dev *dev)
{
int ret;
ret = mt76_eeprom_init(&dev->mt76, MT7921_EEPROM_SIZE);
if (ret < 0)
return ret;
memset(dev->mt76.eeprom.data, -1, MT7921_EEPROM_SIZE);
return 0;
}
static int mt7921_check_eeprom(struct mt7921_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
u16 val;
mt7921_eeprom_read(dev, MT_EE_CHIP_ID);
val = get_unaligned_le16(eeprom);
switch (val) {
case 0x7961:
return 0;
default:
return -EINVAL;
}
}
void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy)
{
struct mt7921_dev *dev = phy->dev;
u32 val;
val = mt7921_eeprom_read(dev, MT_EE_WIFI_CONF);
val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
switch (val) {
case MT_EE_5GHZ:
phy->mt76->cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
phy->mt76->cap.has_2ghz = true;
break;
default:
phy->mt76->cap.has_2ghz = true;
phy->mt76->cap.has_5ghz = true;
break;
}
}
static void mt7921_eeprom_parse_hw_cap(struct mt7921_dev *dev)
{
u8 tx_mask;
mt7921_eeprom_parse_band_config(&dev->phy);
/* TODO: read NSS with MCU_CMD_NIC_CAPV2 */
tx_mask = 2;
dev->chainmask = BIT(tx_mask) - 1;
dev->mphy.antenna_mask = dev->chainmask;
dev->mphy.chainmask = dev->mphy.antenna_mask;
}
int mt7921_eeprom_init(struct mt7921_dev *dev)
{
int ret;
ret = mt7921_eeprom_load(dev);
if (ret < 0)
return ret;
ret = mt7921_check_eeprom(dev);
if (ret)
return ret;
mt7921_eeprom_parse_hw_cap(dev);
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mt76_eeprom_override(&dev->mphy);
return 0;
}

View File

@ -41,7 +41,7 @@ mt7921_regd_notifier(struct wiphy *wiphy,
mt7921_mutex_release(dev);
}
static void
static int
mt7921_init_wiphy(struct ieee80211_hw *hw)
{
struct mt7921_phy *phy = mt7921_hw_phy(hw);
@ -75,6 +75,14 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
wiphy->max_sched_scan_reqs = 1;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
wiphy->reg_notifier = mt7921_regd_notifier;
wiphy->sar_capa = &mt76_sar_capa;
phy->mt76->frp = devm_kcalloc(dev->mt76.dev,
wiphy->sar_capa->num_freq_ranges,
sizeof(struct mt76_freq_range_power),
GFP_KERNEL);
if (!phy->mt76->frp)
return -ENOMEM;
wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
@ -92,6 +100,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
ieee80211_hw_set(hw, CONNECTION_MONITOR);
hw->max_tx_fragments = 4;
return 0;
}
static void
@ -106,6 +116,10 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
/* enable MIB tx-rx time reporting */
mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_TXDUR_EN);
mt76_set(dev, MT_MIB_SCR1(band), MT_MIB_RXDUR_EN);
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
/* disable rx rate report by default due to hw issues */
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
@ -127,35 +141,53 @@ int mt7921_mac_init(struct mt7921_dev *dev)
for (i = 0; i < 2; i++)
mt7921_mac_init_band(dev, i);
dev->mt76.rxfilter = mt76_rr(dev, MT_WF_RFCR(0));
return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
EXPORT_SYMBOL_GPL(mt7921_mac_init);
static int mt7921_init_hardware(struct mt7921_dev *dev)
static int __mt7921_init_hardware(struct mt7921_dev *dev)
{
int ret, idx;
ret = mt7921_dma_init(dev);
if (ret)
return ret;
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
int ret;
/* force firmware operation mode into normal state,
* which should be set before firmware download stage.
*/
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
ret = mt7921_mcu_init(dev);
if (ret)
return ret;
goto out;
ret = mt7921_eeprom_init(dev);
if (ret < 0)
return ret;
mt76_eeprom_override(&dev->mphy);
ret = mt7921_mcu_set_eeprom(dev);
if (ret)
goto out;
ret = mt7921_mac_init(dev);
out:
return ret;
}
static int mt7921_init_hardware(struct mt7921_dev *dev)
{
int ret, idx, i;
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
for (i = 0; i < MT7921_MCU_INIT_RETRY_COUNT; i++) {
ret = __mt7921_init_hardware(dev);
if (!ret)
break;
mt7921_init_reset(dev);
}
if (i == MT7921_MCU_INIT_RETRY_COUNT) {
dev_err(dev->mt76.dev, "hardware init failed\n");
return ret;
}
/* Beacon and mgmt frames should occupy wcid 0 */
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1);
@ -167,7 +199,7 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
return mt7921_mac_init(dev);
return 0;
}
int mt7921_register_device(struct mt7921_dev *dev)
@ -185,8 +217,9 @@ int mt7921_register_device(struct mt7921_dev *dev)
spin_lock_init(&dev->pm.wake.lock);
mutex_init(&dev->pm.mutex);
init_waitqueue_head(&dev->pm.wait);
if (mt76_is_sdio(&dev->mt76))
init_waitqueue_head(&dev->mt76.sdio.wait);
spin_lock_init(&dev->pm.txq_lock);
INIT_LIST_HEAD(&dev->phy.stats_list);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work);
@ -200,14 +233,24 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
dev->pm.enable = true;
dev->pm.ds_enable = true;
/* TODO: mt7921s run sleep mode on default */
if (mt76_is_mmio(&dev->mt76)) {
dev->pm.enable = true;
dev->pm.ds_enable = true;
}
if (mt76_is_sdio(&dev->mt76))
hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;
ret = mt7921_init_hardware(dev);
if (ret)
return ret;
mt7921_init_wiphy(hw);
ret = mt7921_init_wiphy(hw);
if (ret)
return ret;
dev->mphy.sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
@ -244,14 +287,4 @@ int mt7921_register_device(struct mt7921_dev *dev)
return 0;
}
void mt7921_unregister_device(struct mt7921_dev *dev)
{
mt76_unregister_device(&dev->mt76);
mt7921_tx_token_put(dev);
mt7921_dma_cleanup(dev);
mt7921_mcu_exit(dev);
tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
}
EXPORT_SYMBOL_GPL(mt7921_register_device);

File diff suppressed because it is too large Load Diff

View File

@ -116,6 +116,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_FRAME_MODE GENMASK(14, 12)
#define MT_PRXV_SGI GENMASK(16, 15)
@ -138,8 +139,15 @@ 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)
#define MT_CRXV_HE_SR2_MASK GENMASK(20, 17)
@ -191,6 +199,10 @@ enum tx_mcu_port_q_idx {
#define MT_TXD_SIZE (8 * 4)
#define MT_SDIO_TXD_SIZE (MT_TXD_SIZE + 8 * 4)
#define MT_SDIO_TAIL_SIZE 8
#define MT_SDIO_HDR_SIZE 4
#define MT_TXD0_Q_IDX GENMASK(31, 25)
#define MT_TXD0_PKT_FMT GENMASK(24, 23)
#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
@ -309,6 +321,15 @@ struct mt7921_tx_free {
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
#define MT_TXS0_BW GENMASK(30, 29)
#define MT_TXS0_TXS_FORMAT GENMASK(24, 23)
#define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16)
#define MT_TXS0_TX_RATE GENMASK(13, 0)
#define MT_TXS2_WCID GENMASK(25, 16)
#define MT_TXS3_PID GENMASK(31, 24)
static inline struct mt7921_txp_common *
mt7921_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
@ -350,4 +371,15 @@ struct mt7921_txp_common {
};
};
#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7
#define MT_WTBL_TXRX_RATE_G2_HE 24
#define MT_WTBL_TXRX_RATE_G2 12
#define MT_WTBL_AC0_CTT_OFFSET 20
static inline u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset)
{
return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4;
}
#endif

View File

@ -72,7 +72,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
else if (band == NL80211_BAND_5GHZ)
else
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
@ -93,7 +93,7 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
else if (band == NL80211_BAND_5GHZ)
else
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
@ -142,6 +142,32 @@ mt7921_init_he_caps(struct mt7921_phy *phy, enum nl80211_band band,
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
}
if (band == NL80211_BAND_6GHZ) {
struct ieee80211_supported_band *sband =
&phy->mt76->sband_5g.sband;
struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
u32 exp;
u16 cap;
cap = u16_encode_bits(ht_cap->ampdu_density,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
exp = u32_get_bits(vht_cap->cap,
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
cap |= u16_encode_bits(exp,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
exp = u32_get_bits(vht_cap->cap,
IEEE80211_VHT_CAP_MAX_MPDU_MASK);
cap |= u16_encode_bits(exp,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
if (vht_cap->cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN)
cap |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS;
if (vht_cap->cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN)
cap |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
data->he_6ghz_capa.capa = cpu_to_le16(cap);
}
idx++;
}
@ -170,6 +196,15 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy)
band = &phy->mt76->sband_5g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
if (phy->mt76->cap.has_6ghz) {
data = phy->iftype[NL80211_BAND_6GHZ];
n = mt7921_init_he_caps(phy, NL80211_BAND_6GHZ, data);
band = &phy->mt76->sband_6g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
}
}
@ -202,6 +237,7 @@ int __mt7921_start(struct mt7921_phy *phy)
return 0;
}
EXPORT_SYMBOL_GPL(__mt7921_start);
static int mt7921_start(struct ieee80211_hw *hw)
{
@ -243,10 +279,6 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
mt7921_mutex_acquire(dev);
if (vif->type == NL80211_IFTYPE_MONITOR &&
is_zero_ether_addr(vif->addr))
phy->monitor_vif = vif;
mvif->mt76.idx = ffs(~dev->mt76.vif_mask) - 1;
if (mvif->mt76.idx >= MT7921_MAX_INTERFACES) {
ret = -ENOSPC;
@ -268,12 +300,13 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
idx = MT7921_WTBL_RESERVED - mvif->mt76.idx;
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->mt76.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);
mt7921_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@ -306,9 +339,6 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
struct mt7921_phy *phy = mt7921_hw_phy(hw);
int idx = msta->wcid.idx;
if (vif == phy->monitor_vif)
phy->monitor_vif = NULL;
mt7921_mutex_acquire(dev);
mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, false);
@ -323,6 +353,8 @@ static void mt7921_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 int mt7921_set_channel(struct mt7921_phy *phy)
@ -533,36 +565,6 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
mt7921_mutex_release(dev);
}
static int
mt7921_bss_bcnft_apply(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool assoc)
{
int ret;
if (!dev->pm.enable)
return 0;
if (assoc) {
ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
if (ret)
return ret;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
return 0;
}
ret = mt7921_mcu_set_bss_pm(dev, vif, false);
if (ret)
return ret;
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
return 0;
}
static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@ -592,7 +594,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
mt7921_mcu_sta_update(dev, NULL, vif, true,
MT76_STA_INFO_STATE_ASSOC);
mt7921_bss_bcnft_apply(dev, vif, info->assoc);
if (dev->pm.enable)
mt7921_mcu_set_beacon_filter(dev, vif, info->assoc);
}
if (changed & BSS_CHANGED_ARP_FILTER) {
@ -617,14 +620,13 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
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->mt76.band_idx;
msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
msta->stats.jiffies = jiffies;
msta->last_txs = jiffies;
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
@ -645,6 +647,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
return 0;
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_add);
void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@ -666,6 +669,7 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7921_mutex_release(dev);
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_assoc);
void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@ -693,12 +697,11 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
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);
spin_unlock_bh(&dev->sta_poll_lock);
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);
void mt7921_tx_worker(struct mt76_worker *w)
{
@ -853,13 +856,175 @@ mt7921_get_stats(struct ieee80211_hw *hw,
stats->dot11FCSErrorCount = mib->fcs_err_cnt;
stats->dot11ACKFailureCount = mib->ack_fail_cnt;
memset(mib, 0, sizeof(*mib));
mt7921_mutex_release(phy->dev);
return 0;
}
static const char mt7921_gstrings_stats[][ETH_GSTRING_LEN] = {
/* tx counters */
"tx_ampdu_cnt",
"tx_mpdu_attempts",
"tx_mpdu_success",
"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_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_mpdu_cnt",
"rx_ampdu_cnt",
"rx_ampdu_bytes_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",
};
static void
mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 sset, u8 *data)
{
if (sset != ETH_SS_STATS)
return;
memcpy(data, *mt7921_gstrings_stats, sizeof(mt7921_gstrings_stats));
}
static int
mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int sset)
{
return sset == ETH_SS_STATS ? ARRAY_SIZE(mt7921_gstrings_stats) : 0;
}
static void
mt7921_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
{
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
struct mt76_ethtool_worker_info *wi = wi_data;
if (msta->vif->mt76.idx != wi->idx)
return;
mt76_ethtool_worker(wi, &msta->stats);
}
static
void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct mt7921_phy *phy = mt7921_hw_phy(hw);
struct mt7921_dev *dev = phy->dev;
struct mib_stats *mib = &phy->mib;
struct mt76_ethtool_worker_info wi = {
.data = data,
.idx = mvif->mt76.idx,
};
int i, ei = 0;
mt7921_mutex_acquire(dev);
mt7921_mac_update_mib_stats(phy);
data[ei++] = mib->tx_ampdu_cnt;
data[ei++] = mib->tx_mpdu_attempts_cnt;
data[ei++] = mib->tx_mpdu_success_cnt;
data[ei++] = mib->tx_pkt_ebf_cnt;
data[ei++] = mib->tx_pkt_ibf_cnt;
/* Tx ampdu stat */
for (i = 0; i < 15; i++)
data[ei++] = dev->mt76.aggr_stats[i];
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;
/* 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_mpdu_cnt;
data[ei++] = mib->rx_ampdu_cnt;
data[ei++] = mib->rx_ampdu_bytes_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, mt7921_ethtool_worker, &wi);
mt7921_mutex_release(dev);
if (!wi.sta_count)
return;
ei += wi.worker_stat_count;
if (ei != ARRAY_SIZE(mt7921_gstrings_stats))
dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %lu",
ei, ARRAY_SIZE(mt7921_gstrings_stats));
}
static u64
mt7921_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
@ -1048,22 +1213,22 @@ static void mt7921_sta_statistics(struct ieee80211_hw *hw,
struct station_info *sinfo)
{
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
struct mt7921_sta_stats *stats = &msta->stats;
struct rate_info *txrate = &msta->wcid.rate;
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);
}
@ -1172,6 +1337,43 @@ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw,
MCU_UNI_CMD_STA_REC_UPDATE);
}
static int mt7921_set_sar_specs(struct ieee80211_hw *hw,
const struct cfg80211_sar_specs *sar)
{
const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
struct mt7921_dev *dev = mt7921_hw_dev(hw);
struct mt76_freq_range_power *data, *frp;
struct mt76_phy *mphy = hw->priv;
int err;
u32 i;
if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
return -EINVAL;
mt7921_mutex_acquire(dev);
data = mphy->frp;
for (i = 0; i < sar->num_sub_specs; i++) {
u32 index = sar->sub_specs[i].freq_range_index;
/* SAR specifies power limitaton in 0.25dbm */
s32 power = sar->sub_specs[i].power >> 1;
if (power > 127 || power < -127)
power = 127;
frp = &data[index];
frp->range = &capa->freq_ranges[index];
frp->power = power;
}
err = mt76_connac_mcu_set_rate_txpower(mphy);
mt7921_mutex_release(dev);
return err;
}
const struct ieee80211_ops mt7921_ops = {
.tx = mt7921_tx,
.start = mt7921_start,
@ -1192,6 +1394,9 @@ const struct ieee80211_ops mt7921_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt76_get_txpower,
.get_stats = mt7921_get_stats,
.get_et_sset_count = mt7921_get_et_sset_count,
.get_et_strings = mt7921_get_et_strings,
.get_et_stats = mt7921_get_et_stats,
.get_tsf = mt7921_get_tsf,
.set_tsf = mt7921_set_tsf,
.get_survey = mt76_get_survey,
@ -1203,6 +1408,8 @@ const struct ieee80211_ops mt7921_ops = {
.sta_statistics = mt7921_sta_statistics,
.sched_scan_start = mt7921_start_sched_scan,
.sched_scan_stop = mt7921_stop_sched_scan,
CFG80211_TESTMODE_CMD(mt7921_testmode_cmd)
CFG80211_TESTMODE_DUMP(mt7921_testmode_dump)
#ifdef CONFIG_PM
.suspend = mt7921_suspend,
.resume = mt7921_resume,
@ -1210,4 +1417,9 @@ const struct ieee80211_ops mt7921_ops = {
.set_rekey_data = mt7921_set_rekey_data,
#endif /* CONFIG_PM */
.flush = mt7921_flush,
.set_sar_specs = mt7921_set_sar_specs,
};
EXPORT_SYMBOL_GPL(mt7921_ops);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");

View File

@ -82,9 +82,17 @@ struct mt7921_fw_region {
#define FW_START_OVERRIDE BIT(0)
#define FW_START_WORKING_PDA_CR4 BIT(2)
#define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0)
#define PATCH_SEC_TYPE_MASK GENMASK(15, 0)
#define PATCH_SEC_TYPE_INFO 0x2
#define PATCH_SEC_ENC_TYPE_MASK GENMASK(31, 24)
#define PATCH_SEC_ENC_TYPE_PLAIN 0x00
#define PATCH_SEC_ENC_TYPE_AES 0x01
#define PATCH_SEC_ENC_TYPE_SCRAMBLE 0x02
#define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0)
#define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0)
#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id)
#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id)
@ -152,11 +160,11 @@ mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
return 0;
}
static int
mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
struct mt7921_mcu_rxd *rxd;
int mcu_cmd = cmd & MCU_CMD_MASK;
int ret = 0;
if (!skb) {
@ -194,6 +202,9 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
skb_pull(skb, sizeof(*rxd));
event = (struct mt7921_mcu_uni_event *)skb->data;
ret = le32_to_cpu(event->status);
/* skip invalid event */
if (mcu_cmd != event->cid)
ret = -EAGAIN;
break;
}
case MCU_CMD_REG_READ: {
@ -211,14 +222,13 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
return ret;
}
EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);
static int
mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *wait_seq)
int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *wait_seq)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
int txd_len, mcu_cmd = cmd & MCU_CMD_MASK;
enum mt76_mcuq_id txq = MT_MCUQ_WM;
struct mt7921_uni_txd *uni_txd;
struct mt7921_mcu_txd *mcu_txd;
__le32 *txd;
@ -240,10 +250,8 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
if (!seq)
seq = ++dev->mt76.mcu.msg_seq & 0xf;
if (cmd == MCU_CMD_FW_SCATTER) {
txq = MT_MCUQ_FWDL;
if (cmd == MCU_CMD_FW_SCATTER)
goto exit;
}
txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd);
txd = (__le32 *)skb_push(skb, txd_len);
@ -307,96 +315,9 @@ exit:
if (wait_seq)
*wait_seq = seq;
return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
}
static void
mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy,
struct mt7921_mcu_peer_cap *peer,
struct rate_info *rate, u16 r)
{
struct ieee80211_supported_band *sband;
u16 flags = 0;
u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r);
u8 gi = 0;
u8 bw = 0;
rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r);
rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1;
switch (peer->bw) {
case IEEE80211_STA_RX_BW_160:
gi = peer->g16;
break;
case IEEE80211_STA_RX_BW_80:
gi = peer->g8;
break;
case IEEE80211_STA_RX_BW_40:
gi = peer->g4;
break;
default:
gi = peer->g2;
break;
}
gi = txmode >= MT_PHY_TYPE_HE_SU ?
FIELD_GET(MT_WTBL_RATE_HE_GI, gi) :
FIELD_GET(MT_WTBL_RATE_GI, gi);
switch (txmode) {
case MT_PHY_TYPE_CCK:
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->legacy = sband->bitrates[rate->mcs].bitrate;
break;
case MT_PHY_TYPE_HT:
case MT_PHY_TYPE_HT_GF:
flags |= RATE_INFO_FLAGS_MCS;
if (gi)
flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case MT_PHY_TYPE_VHT:
flags |= RATE_INFO_FLAGS_VHT_MCS;
if (gi)
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:
rate->he_gi = gi;
rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r);
flags |= RATE_INFO_FLAGS_HE_MCS;
break;
default:
break;
}
rate->flags = flags;
bw = mt7921_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;
}
EXPORT_SYMBOL_GPL(mt7921_mcu_fill_message);
static void
mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
@ -497,49 +418,6 @@ mt7921_mcu_low_power_event(struct mt7921_dev *dev, struct sk_buff *skb)
trace_lp_event(dev, event->state);
}
static void
mt7921_mcu_tx_done_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_tx_done_event *event;
struct mt7921_sta *msta;
struct mt7921_phy *mphy = &dev->phy;
struct mt7921_mcu_peer_cap peer;
struct ieee80211_sta *sta;
LIST_HEAD(list);
skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
event = (struct mt7921_mcu_tx_done_event *)skb->data;
spin_lock_bh(&dev->sta_poll_lock);
list_splice_init(&mphy->stats_list, &list);
while (!list_empty(&list)) {
msta = list_first_entry(&list, struct mt7921_sta, stats_list);
list_del_init(&msta->stats_list);
if (msta->wcid.idx != event->wlan_idx)
continue;
spin_unlock_bh(&dev->sta_poll_lock);
sta = wcid_to_sta(&msta->wcid);
/* peer config based on IEEE SPEC */
memset(&peer, 0x0, sizeof(peer));
peer.bw = event->bw;
peer.g2 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
peer.g4 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
peer.g8 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80);
peer.g16 = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160);
mt7921_mcu_tx_rate_parse(mphy->mt76, &peer,
&msta->stats.tx_rate, event->tx_rate);
spin_lock_bh(&dev->sta_poll_lock);
break;
}
spin_unlock_bh(&dev->sta_poll_lock);
}
static void
mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
@ -560,15 +438,13 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
mt7921_mcu_debug_msg_event(dev, skb);
break;
case MCU_EVENT_COREDUMP:
dev->fw_assert = true;
mt76_connac_mcu_coredump_event(&dev->mt76, skb,
&dev->coredump);
return;
case MCU_EVENT_LP_INFO:
mt7921_mcu_low_power_event(dev, skb);
break;
case MCU_EVENT_TX_DONE:
mt7921_mcu_tx_done_event(dev, skb);
break;
default:
break;
}
@ -577,7 +453,12 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
struct mt7921_mcu_rxd *rxd;
if (skb_linearize(skb))
return;
rxd = (struct mt7921_mcu_rxd *)skb->data;
if (rxd->eid == 0x6) {
mt76_mcu_rx_event(&dev->mt76, skb);
@ -619,7 +500,7 @@ mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb,
u8 cipher;
cipher = mt7921_mcu_get_cipher(key->cipher);
if (cipher == MT_CIPHER_NONE)
if (cipher == MCU_CIPHER_NONE)
return -EOPNOTSUPP;
sec_key = &sec->key[0];
@ -712,7 +593,7 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
enable, false);
}
static int mt7921_mcu_restart(struct mt76_dev *dev)
int mt7921_mcu_restart(struct mt76_dev *dev)
{
struct {
u8 power_mode;
@ -724,26 +605,55 @@ static int mt7921_mcu_restart(struct mt76_dev *dev)
return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req,
sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt7921_mcu_restart);
static int mt7921_driver_own(struct mt7921_dev *dev)
static u32 mt7921_get_data_mode(struct mt7921_dev *dev, u32 info)
{
u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
u32 mode = DL_MODE_NEED_RSP;
mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN);
if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN,
0, 500)) {
dev_err(dev->mt76.dev, "Timeout for driver own\n");
return -EIO;
if (info == PATCH_SEC_NOT_SUPPORT)
return mode;
switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {
case PATCH_SEC_ENC_TYPE_PLAIN:
break;
case PATCH_SEC_ENC_TYPE_AES:
mode |= DL_MODE_ENCRYPT;
mode |= FIELD_PREP(DL_MODE_KEY_IDX,
(info & PATCH_SEC_ENC_AES_KEY_MASK)) & DL_MODE_KEY_IDX;
mode |= DL_MODE_RESET_SEC_IV;
break;
case PATCH_SEC_ENC_TYPE_SCRAMBLE:
mode |= DL_MODE_ENCRYPT;
mode |= DL_CONFIG_ENCRY_MODE_SEL;
mode |= DL_MODE_RESET_SEC_IV;
break;
default:
dev_err(dev->mt76.dev, "Encryption type not support!\n");
}
return 0;
return mode;
}
static char *mt7921_patch_name(struct mt7921_dev *dev)
{
char *ret;
if (is_mt7922(&dev->mt76))
ret = MT7922_ROM_PATCH;
else
ret = MT7921_ROM_PATCH;
return ret;
}
static int mt7921_load_patch(struct mt7921_dev *dev)
{
const struct mt7921_patch_hdr *hdr;
const struct firmware *fw = NULL;
int i, ret, sem;
int i, ret, sem, max_len;
max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096;
sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
switch (sem) {
@ -756,7 +666,7 @@ static int mt7921_load_patch(struct mt7921_dev *dev)
return -EAGAIN;
}
ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev);
ret = request_firmware(&fw, mt7921_patch_name(dev), dev->mt76.dev);
if (ret)
goto out;
@ -774,7 +684,8 @@ static int mt7921_load_patch(struct mt7921_dev *dev)
for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
struct mt7921_patch_sec *sec;
const u8 *dl;
u32 len, addr;
u32 len, addr, mode;
u32 sec_info = 0;
sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) +
i * sizeof(*sec));
@ -787,16 +698,18 @@ static int mt7921_load_patch(struct mt7921_dev *dev)
addr = be32_to_cpu(sec->info.addr);
len = be32_to_cpu(sec->info.len);
dl = fw->data + be32_to_cpu(sec->offs);
sec_info = be32_to_cpu(sec->info.sec_key_idx);
mode = mt7921_get_data_mode(dev, sec_info);
ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
DL_MODE_NEED_RSP);
mode);
if (ret) {
dev_err(dev->mt76.dev, "Download request failed\n");
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, max_len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send patch\n");
goto out;
@ -815,7 +728,7 @@ out:
default:
ret = -EAGAIN;
dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
goto out;
break;
}
release_firmware(fw);
@ -843,9 +756,11 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev,
const struct mt7921_fw_trailer *hdr,
const u8 *data, bool is_wa)
{
int i, offset = 0;
int i, offset = 0, max_len;
u32 override = 0, option = 0;
max_len = mt76_is_sdio(&dev->mt76) ? 2048 : 4096;
for (i = 0; i < hdr->n_region; i++) {
const struct mt7921_fw_region *region;
int err;
@ -867,8 +782,8 @@ mt7921_mcu_send_ram_firmware(struct mt7921_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, max_len);
if (err) {
dev_err(dev->mt76.dev, "Failed to send firmware.\n");
return err;
@ -886,13 +801,25 @@ mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev,
return mt76_connac_mcu_start_firmware(&dev->mt76, override, option);
}
static char *mt7921_ram_name(struct mt7921_dev *dev)
{
char *ret;
if (is_mt7922(&dev->mt76))
ret = MT7922_FIRMWARE_WM;
else
ret = MT7921_FIRMWARE_WM;
return ret;
}
static int mt7921_load_ram(struct mt7921_dev *dev)
{
const struct mt7921_fw_trailer *hdr;
const struct firmware *fw;
int ret;
ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev);
ret = request_firmware(&fw, mt7921_ram_name(dev), dev->mt76.dev);
if (ret)
return ret;
@ -929,7 +856,7 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
int ret;
ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
if (ret) {
if (ret && mt76_is_mmio(&dev->mt76)) {
dev_dbg(dev->mt76.dev, "Firmware is already download\n");
goto fw_loaded;
}
@ -950,7 +877,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
}
fw_loaded:
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
#ifdef CONFIG_PM
dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
@ -978,39 +904,24 @@ int mt7921_run_firmware(struct mt7921_dev *dev)
{
int err;
err = mt7921_driver_own(dev);
if (err)
return err;
err = mt7921_load_firmware(dev);
if (err)
return err;
err = mt76_connac_mcu_get_nic_capability(&dev->mphy);
if (err)
return err;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt7921_mcu_fw_log_2_host(dev, 1);
return mt76_connac_mcu_get_nic_capability(&dev->mphy);
}
int mt7921_mcu_init(struct mt7921_dev *dev)
{
static const struct mt76_mcu_ops mt7921_mcu_ops = {
.headroom = sizeof(struct mt7921_mcu_txd),
.mcu_skb_send_msg = mt7921_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_restart = mt7921_mcu_restart,
};
dev->mt76.mcu_ops = &mt7921_mcu_ops;
return mt7921_run_firmware(dev);
return mt7921_mcu_fw_log_2_host(dev, 1);
}
EXPORT_SYMBOL_GPL(mt7921_run_firmware);
void mt7921_mcu_exit(struct mt7921_dev *dev)
{
mt7921_wfsys_reset(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
}
EXPORT_SYMBOL_GPL(mt7921_mcu_exit);
int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
{
@ -1041,7 +952,30 @@ int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
.total = IEEE80211_NUM_ACS,
};
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
int ac;
struct mu_edca {
u8 cw_min;
u8 cw_max;
u8 aifsn;
u8 acm;
u8 timer;
u8 padding[3];
};
struct mt7921_mcu_mu_tx {
u8 ver;
u8 pad0;
__le16 len;
u8 bss_idx;
u8 qos;
u8 wmm_idx;
u8 pad1;
struct mu_edca edca[IEEE80211_NUM_ACS];
u8 pad3[32];
} __packed req_mu = {
.bss_idx = mvif->mt76.idx,
.qos = vif->bss_conf.qos,
.wmm_idx = mvif->mt76.wmm_idx,
};
int ac, ret;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
@ -1062,8 +996,34 @@ int mt7921_mcu_set_tx(struct mt7921_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);
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req,
sizeof(req), true);
if (ret)
return ret;
if (!vif->bss_conf.he_support)
return 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
struct ieee80211_he_mu_edca_param_ac_rec *q;
struct mu_edca *e;
int to_aci[] = {1, 0, 2, 3};
if (!mvif->queue_params[ac].mu_edca)
break;
q = &mvif->queue_params[ac].mu_edca_param_rec;
e = &(req_mu.edca[to_aci[ac]]);
e->cw_min = q->ecw_min_max & 0xf;
e->cw_max = (q->ecw_min_max & 0xf0) >> 4;
e->aifsn = q->aifsn;
e->timer = q->mu_edca_timer;
}
return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_MU_EDCA_PARMS, &req_mu,
sizeof(req_mu), false);
}
int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd)
@ -1095,9 +1055,13 @@ int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd)
.tx_streams_num = hweight8(phy->mt76->antenna_mask),
.rx_streams = phy->mt76->antenna_mask,
.band_idx = phy != &dev->phy,
.channel_band = chandef->chan->band,
};
if (chandef->chan->band == NL80211_BAND_6GHZ)
req.channel_band = 2;
else
req.channel_band = chandef->chan->band;
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
@ -1132,6 +1096,7 @@ int mt7921_mcu_set_eeprom(struct mt7921_dev *dev)
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
&req, sizeof(req), true);
}
EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);
int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset)
{
@ -1193,8 +1158,9 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
&ps_req, sizeof(ps_req), true);
}
int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable)
static int
mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct {
@ -1228,8 +1194,9 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
&bcnft_req, sizeof(bcnft_req), true);
}
int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable)
static int
mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct {
@ -1292,35 +1259,6 @@ int mt7921_mcu_sta_update(struct mt7921_dev *dev, struct ieee80211_sta *sta,
return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
}
int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 0, 50))
break;
}
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
err = -EIO;
goto out;
}
mt7921_wpdma_reinit_cond(dev);
clear_bit(MT76_STATE_PM, &mphy->state);
pm->stats.last_wake_event = jiffies;
pm->stats.doze_time += pm->stats.last_wake_event -
pm->stats.last_doze_event;
out:
return err;
}
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
@ -1341,34 +1279,20 @@ out:
return err;
}
EXPORT_SYMBOL_GPL(mt7921_mcu_drv_pmctrl);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;
int err = 0;
mutex_lock(&pm->mutex);
if (mt76_connac_skip_fw_pmctrl(mphy, pm))
goto out;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 4, 50))
break;
}
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "firmware own failed\n");
clear_bit(MT76_STATE_PM, &mphy->state);
err = -EIO;
}
pm->stats.last_doze_event = jiffies;
pm->stats.awake_time += pm->stats.last_doze_event -
pm->stats.last_wake_event;
err = __mt7921_mcu_fw_pmctrl(dev);
out:
mutex_unlock(&pm->mutex);
@ -1377,32 +1301,36 @@ out:
return err;
}
EXPORT_SYMBOL_GPL(mt7921_mcu_fw_pmctrl);
void
mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
struct ieee80211_vif *vif,
bool enable)
{
struct mt7921_phy *phy = priv;
struct mt7921_dev *dev = phy->dev;
struct ieee80211_hw *hw = mt76_hw(dev);
int ret;
int err;
if (dev->pm.enable)
ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
else
ret = mt7921_mcu_set_bss_pm(dev, vif, false);
if (enable) {
err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
if (err)
return err;
if (ret)
return;
if (dev->pm.enable) {
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
ieee80211_hw_set(hw, CONNECTION_MONITOR);
mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
} else {
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
__clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
return 0;
}
err = mt7921_mcu_set_bss_pm(dev, vif, false);
if (err)
return err;
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
__clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags);
mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
return 0;
}
int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)

View File

@ -259,25 +259,6 @@ struct mt7921_mcu_ant_id_config {
u8 ant_id[4];
} __packed;
struct mt7921_mcu_peer_cap {
struct mt7921_mcu_ant_id_config ant_id_config;
u8 power_offset;
u8 bw_selector;
u8 change_bw_rate_n;
u8 bw;
u8 spe_idx;
u8 g2;
u8 g4;
u8 g8;
u8 g16;
u8 mmss;
u8 ampdu_factor;
u8 rsv[1];
} __packed;
struct mt7921_txpwr_req {
u8 ver;
u8 action;
@ -293,31 +274,29 @@ struct mt7921_txpwr_event {
struct mt7921_txpwr txpwr;
} __packed;
struct mt7921_mcu_tx_done_event {
u8 pid;
u8 status;
u16 seq;
enum {
TM_SWITCH_MODE,
TM_SET_AT_CMD,
TM_QUERY_AT_CMD,
};
u8 wlan_idx;
u8 tx_cnt;
u16 tx_rate;
enum {
MT7921_TM_NORMAL,
MT7921_TM_TESTMODE,
MT7921_TM_ICAP,
MT7921_TM_ICAP_OVERLAP,
MT7921_TM_WIFISPECTRUM,
};
u8 flag;
u8 tid;
u8 rsp_rate;
u8 mcs;
struct mt7921_rftest_cmd {
u8 action;
u8 rsv[3];
__le32 param0;
__le32 param1;
} __packed;
u8 bw;
u8 tx_pwr;
u8 reason;
u8 rsv0[1];
u32 delay;
u32 timestamp;
u32 applied_flag;
u8 txs[28];
u8 rsv1[32];
struct mt7921_rftest_evt {
__le32 param0;
__le32 param1;
} __packed;
#endif

View File

@ -29,22 +29,47 @@
#define MT7921_RX_MCU_RING_SIZE 512
#define MT7921_DRV_OWN_RETRY_COUNT 10
#define MT7921_MCU_INIT_RETRY_COUNT 10
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
#define MT7921_EEPROM_SIZE 3584
#define MT7921_TOKEN_SIZE 8192
#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
#define MT7921_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
#define MT7921_2G_RATE_DEFAULT 0x0 /* CCK 1M */
#define MT7921_SKU_RATE_NUM 161
#define MT7921_SKU_MAX_DELTA_IDX MT7921_SKU_RATE_NUM
#define MT7921_SKU_TABLE_SIZE (MT7921_SKU_RATE_NUM + 1)
#define MT7921_SDIO_HDR_TX_BYTES GENMASK(15, 0)
#define MT7921_SDIO_HDR_PKT_TYPE GENMASK(17, 16)
enum mt7921_sdio_pkt_type {
MT7921_SDIO_TXD,
MT7921_SDIO_DATA,
MT7921_SDIO_CMD,
MT7921_SDIO_FWDL,
};
struct mt7921_sdio_intr {
u32 isr;
struct {
u32 wtqcr[16];
} tx;
struct {
u16 num[2];
u16 len0[16];
u16 len1[128];
} rx;
u32 rec_mb[2];
} __packed;
#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)
#define to_rcpi(rssi) (2 * (rssi) + 220)
@ -64,15 +89,6 @@ enum mt7921_rxq_id {
MT7921_RXQ_MCU_WM = 0,
};
struct mt7921_sta_stats {
struct rate_info prob_rate;
struct rate_info tx_rate;
unsigned long per;
unsigned long changed;
unsigned long jiffies;
};
struct mt7921_sta_key_conf {
s8 keyidx;
u8 key[16];
@ -83,17 +99,14 @@ struct mt7921_sta {
struct mt7921_vif *vif;
struct list_head stats_list;
struct list_head poll_list;
u32 airtime_ac[8];
struct mt7921_sta_stats stats;
unsigned long last_txs;
unsigned long ampdu_state;
struct mt76_sta_stats stats;
struct mt7921_sta_key_conf bip;
unsigned long next_txs_ts;
};
DECLARE_EWMA(rssi, 10, 8);
@ -117,15 +130,34 @@ struct mib_stats {
u32 rts_cnt;
u32 rts_retries_cnt;
u32 ba_miss_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_ampdu_cnt;
u32 tx_mpdu_attempts_cnt;
u32 tx_mpdu_success_cnt;
u32 tx_pkt_ebf_cnt;
u32 tx_pkt_ibf_cnt;
u32 rx_mpdu_cnt;
u32 rx_ampdu_cnt;
u32 rx_ampdu_bytes_cnt;
u32 rx_ba_cnt;
u32 tx_amsdu[8];
u32 tx_amsdu_cnt;
};
struct mt7921_phy {
struct mt76_phy *mt76;
struct mt7921_dev *dev;
struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES];
struct ieee80211_vif *monitor_vif;
struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
u32 rxfilter;
u64 omac_mask;
@ -139,7 +171,6 @@ struct mt7921_phy {
u32 ampdu_ref;
struct mib_stats mib;
struct list_head stats_list;
u8 sta_work_count;
@ -147,6 +178,19 @@ struct mt7921_phy {
struct delayed_work scan_work;
};
#define mt7921_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
#define mt7921_dev_reset(dev) ((dev)->hif_ops->reset(dev))
#define mt7921_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
#define __mt7921_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev))
#define __mt7921_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev))
struct mt7921_hif_ops {
int (*init_reset)(struct mt7921_dev *dev);
int (*reset)(struct mt7921_dev *dev);
int (*mcu_init)(struct mt7921_dev *dev);
int (*drv_own)(struct mt7921_dev *dev);
int (*fw_own)(struct mt7921_dev *dev);
};
struct mt7921_dev {
union { /* must be first */
struct mt76_dev mt76;
@ -157,11 +201,10 @@ struct mt7921_dev {
struct mt7921_phy phy;
struct tasklet_struct irq_tasklet;
u16 chainmask;
struct work_struct reset_work;
bool hw_full_reset:1;
bool hw_init_done:1;
bool fw_assert:1;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
@ -170,6 +213,7 @@ struct mt7921_dev {
struct mt76_connac_pm pm;
struct mt76_connac_coredump coredump;
const struct mt7921_hif_ops *hif_ops;
};
enum {
@ -247,18 +291,11 @@ u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr);
int __mt7921_start(struct mt7921_phy *phy);
int mt7921_register_device(struct mt7921_dev *dev);
void mt7921_unregister_device(struct mt7921_dev *dev);
int mt7921_eeprom_init(struct mt7921_dev *dev);
void mt7921_eeprom_parse_band_config(struct mt7921_phy *phy);
int mt7921_eeprom_get_target_power(struct mt7921_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx);
void mt7921_eeprom_init_sku(struct mt7921_dev *dev);
int mt7921_dma_init(struct mt7921_dev *dev);
int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force);
int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev);
void mt7921_dma_cleanup(struct mt7921_dev *dev);
int mt7921_run_firmware(struct mt7921_dev *dev);
int mt7921_mcu_init(struct mt7921_dev *dev);
int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif,
struct mt7921_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
@ -324,16 +361,27 @@ static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev)
return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
}
static inline void mt7921_mcu_tx_cleanup(struct mt7921_dev *dev)
{
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
}
static inline void mt7921_skb_add_sdio_hdr(struct sk_buff *skb,
enum mt7921_sdio_pkt_type type)
{
u32 hdr;
hdr = FIELD_PREP(MT7921_SDIO_HDR_TX_BYTES, skb->len + sizeof(hdr)) |
FIELD_PREP(MT7921_SDIO_HDR_PKT_TYPE, type);
put_unaligned_le32(hdr, skb_push(skb, sizeof(hdr)));
}
int mt7921_mac_init(struct mt7921_dev *dev);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
void mt7921_mac_reset_counters(struct mt7921_phy *phy);
void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon);
void mt7921_mac_set_timing(struct mt7921_phy *phy);
int mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb);
void mt7921_mac_fill_rx_vector(struct mt7921_dev *dev, struct sk_buff *skb);
void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb);
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@ -342,27 +390,28 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7921_mac_work(struct work_struct *work);
void mt7921_mac_reset_work(struct work_struct *work);
void mt7921_mac_update_mib_stats(struct mt7921_phy *phy);
void mt7921_reset(struct mt76_dev *mdev);
void mt7921_tx_cleanup(struct mt7921_dev *dev);
int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7921_tx_worker(struct mt76_worker *w);
void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc);
void mt7921_tx_token_put(struct mt7921_dev *dev);
void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
void mt7921_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7921_stats_work(struct work_struct *work);
void mt7921_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *txwi);
void mt7921_set_stream_he_caps(struct mt7921_phy *phy);
void mt7921_update_channel(struct mt76_phy *mphy);
int mt7921_init_debugfs(struct mt7921_dev *dev);
int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
struct ieee80211_vif *vif,
bool enable);
int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
struct ieee80211_ampdu_params *params,
bool enable);
@ -371,21 +420,47 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
bool enable);
void mt7921_scan_work(struct work_struct *work);
int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif);
int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
void mt7921_pm_wake_work(struct work_struct *work);
void mt7921_pm_power_save_work(struct work_struct *work);
bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev);
int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
struct ieee80211_vif *vif,
bool enable);
void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
void mt7921_coredump_work(struct work_struct *work);
int mt7921_wfsys_reset(struct mt7921_dev *dev);
int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr);
int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len);
int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
struct netlink_callback *cb, void *data, int len);
void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
bool beacon);
void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
void mt7921_mac_sta_poll(struct mt7921_dev *dev);
int mt7921_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *wait_seq);
int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq);
int mt7921_mcu_restart(struct mt76_dev *dev);
void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
int mt7921e_mac_reset(struct mt7921_dev *dev);
int mt7921e_mcu_init(struct mt7921_dev *dev);
int mt7921s_wfsys_reset(struct mt7921_dev *dev);
int mt7921s_mac_reset(struct mt7921_dev *dev);
int mt7921s_init_reset(struct mt7921_dev *dev);
int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev);
int mt7921s_mcu_init(struct mt7921_dev *dev);
int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev);
int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update);
#endif

View File

@ -14,9 +14,14 @@
static const struct pci_device_id mt7921_pci_device_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961) },
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922) },
{ },
};
static bool mt7921_disable_aspm;
module_param_named(disable_aspm, mt7921_disable_aspm, bool, 0644);
MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support");
static void
mt7921_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
@ -88,21 +93,46 @@ static void mt7921_irq_tasklet(unsigned long data)
napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
}
static int mt7921e_init_reset(struct mt7921_dev *dev)
{
return mt7921_wpdma_reset(dev, true);
}
static void mt7921e_unregister_device(struct mt7921_dev *dev)
{
int i;
struct mt76_connac_pm *pm = &dev->pm;
mt76_unregister_device(&dev->mt76);
mt76_for_each_q_rx(&dev->mt76, i)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
mt7921_tx_token_put(dev);
mt7921_mcu_drv_pmctrl(dev);
mt7921_dma_cleanup(dev);
mt7921_wfsys_reset(dev);
mt7921_mcu_exit(dev);
tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
}
static int mt7921_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7921_txp_common),
.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,
.token_size = MT7921_TOKEN_SIZE,
.tx_prepare_skb = mt7921_tx_prepare_skb,
.tx_complete_skb = mt7921_tx_complete_skb,
.rx_skb = mt7921_queue_rx_skb,
.tx_prepare_skb = mt7921e_tx_prepare_skb,
.tx_complete_skb = mt7921e_tx_complete_skb,
.rx_skb = mt7921e_queue_rx_skb,
.rx_poll_complete = mt7921_rx_poll_complete,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
@ -110,6 +140,15 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.sta_remove = mt7921_mac_sta_remove,
.update_survey = mt7921_update_channel,
};
static const struct mt7921_hif_ops mt7921_pcie_ops = {
.init_reset = mt7921e_init_reset,
.reset = mt7921e_mac_reset,
.mcu_init = mt7921e_mcu_init,
.drv_own = mt7921e_mcu_drv_pmctrl,
.fw_own = mt7921e_mcu_fw_pmctrl,
};
struct mt7921_dev *dev;
struct mt76_dev *mdev;
int ret;
@ -128,11 +167,12 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (ret < 0)
return ret;
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
goto err_free_pci_vec;
mt76_pci_disable_aspm(pdev);
if (mt7921_disable_aspm)
mt76_pci_disable_aspm(pdev);
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7921_ops,
&drv_ops);
@ -142,6 +182,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
}
dev = container_of(mdev, struct mt7921_dev, mt76);
dev->hif_ops = &mt7921_pcie_ops;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
tasklet_init(&dev->irq_tasklet, mt7921_irq_tasklet, (unsigned long)dev);
@ -158,6 +199,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
if (ret)
goto err_free_dev;
ret = mt7921_dma_init(dev);
if (ret)
goto err_free_irq;
ret = mt7921_register_device(dev);
if (ret)
goto err_free_irq;
@ -179,7 +224,7 @@ static void mt7921_pci_remove(struct pci_dev *pdev)
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
mt7921_unregister_device(dev);
mt7921e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
pci_free_irq_vectors(pdev);
}
@ -297,12 +342,15 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
mt76_worker_enable(&mdev->tx_worker);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
}
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
local_bh_enable();
/* restore previous ds setting */
if (!pm->ds_enable)
@ -331,6 +379,8 @@ module_pci_driver(mt7921_pci_driver);
MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table);
MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
MODULE_FIRMWARE(MT7921_ROM_PATCH);
MODULE_FIRMWARE(MT7922_FIRMWARE_WM);
MODULE_FIRMWARE(MT7922_ROM_PATCH);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,348 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc. */
#include "mt7921.h"
#include "../dma.h"
#include "mac.h"
static void
mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info,
void *txp_ptr, u32 id)
{
struct mt7921_hw_txp *txp = txp_ptr;
struct mt7921_txp_ptr *ptr = &txp->ptr[0];
int i, nbuf = tx_info->nbuf - 1;
tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
tx_info->nbuf = 1;
txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
for (i = 0; i < nbuf; i++) {
u16 len = tx_info->buf[i + 1].len & MT_TXD_LEN_MASK;
u32 addr = tx_info->buf[i + 1].addr;
if (i == nbuf - 1)
len |= MT_TXD_LEN_LAST;
if (i & 1) {
ptr->buf1 = cpu_to_le32(addr);
ptr->len1 = cpu_to_le16(len);
ptr++;
} else {
ptr->buf0 = cpu_to_le32(addr);
ptr->len0 = cpu_to_le16(len);
}
}
}
int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct mt76_txwi_cache *t;
struct mt7921_txp_common *txp;
int id, pid;
u8 *txwi = (u8 *)txwi_ptr;
if (unlikely(tx_info->skb->len <= ETH_HLEN))
return -EINVAL;
if (!wcid)
wcid = &dev->mt76.global_wcid;
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
t->skb = tx_info->skb;
id = mt76_token_consume(mdev, &t);
if (id < 0)
return id;
if (sta) {
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
if (time_after(jiffies, msta->last_txs + HZ / 4)) {
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
msta->last_txs = jiffies;
}
}
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
mt7921_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
pid, false);
txp = (struct mt7921_txp_common *)(txwi + MT_TXD_SIZE);
memset(txp, 0, sizeof(struct mt7921_txp_common));
mt7921_write_hw_txp(dev, tx_info, txp, id);
tx_info->skb = DMA_DUMMY_DATA;
return 0;
}
static void
mt7921_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
struct mt7921_txp_common *txp;
int i;
txp = mt7921_txwi_to_txp(dev, t);
for (i = 0; i < ARRAY_SIZE(txp->hw.ptr); i++) {
struct mt7921_txp_ptr *ptr = &txp->hw.ptr[i];
bool last;
u16 len;
len = le16_to_cpu(ptr->len0);
last = len & MT_TXD_LEN_LAST;
len &= MT_TXD_LEN_MASK;
dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,
DMA_TO_DEVICE);
if (last)
break;
len = le16_to_cpu(ptr->len1);
last = len & MT_TXD_LEN_LAST;
len &= MT_TXD_LEN_MASK;
dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,
DMA_TO_DEVICE);
if (last)
break;
}
}
static void
mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
struct ieee80211_sta *sta, bool clear_status,
struct list_head *free_list)
{
struct mt76_dev *mdev = &dev->mt76;
__le32 *txwi;
u16 wcid_idx;
mt7921_txp_skb_unmap(mdev, t);
if (!t->skb)
goto out;
txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
if (sta) {
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
mt7921_tx_check_aggr(sta, txwi);
wcid_idx = wcid->idx;
} else {
wcid_idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
}
__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
out:
t->skb = NULL;
mt76_put_txwi(mdev, t);
}
static void
mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
{
struct mt7921_tx_free *free = (struct mt7921_tx_free *)skb->data;
struct mt76_dev *mdev = &dev->mt76;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
LIST_HEAD(free_list);
struct sk_buff *tmp;
bool wake = false;
u8 i, count;
/* clean DMA queues and unmap buffers first */
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
/* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
* to the time ack is received or dropped by hw (air + hw queue time).
* Should avoid accessing WTBL to get Tx airtime, and use it instead.
*/
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.
* 1'b0: msdu_id with the same 'wcid pair' as above.
*/
if (info & MT_TX_FREE_PAIR) {
struct mt7921_sta *msta;
struct mt76_wcid *wcid;
u16 idx;
count++;
idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
wcid = rcu_dereference(dev->mt76.wcid[idx]);
sta = wcid_to_sta(wcid);
if (!sta)
continue;
msta = container_of(wcid, struct mt7921_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);
spin_unlock_bh(&dev->sta_poll_lock);
continue;
}
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;
mt7921_txwi_free(dev, txwi, sta, stat, &free_list);
}
if (wake)
mt76_set_tx_blocked(&dev->mt76, false);
napi_consume_skb(skb, 1);
list_for_each_entry_safe(skb, tmp, &free_list, list) {
skb_list_del_init(skb);
napi_consume_skb(skb, 1);
}
rcu_read_lock();
mt7921_mac_sta_poll(dev);
rcu_read_unlock();
mt76_worker_schedule(&dev->mt76.tx_worker);
}
void mt7921e_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
__le32 *rxd = (__le32 *)skb->data;
enum rx_pkt_type type;
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
switch (type) {
case PKT_TYPE_TXRX_NOTIFY:
mt7921_mac_tx_free(dev, skb);
break;
default:
mt7921_queue_rx_skb(mdev, q, skb);
break;
}
}
void mt7921e_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
if (!e->txwi) {
dev_kfree_skb_any(e->skb);
return;
}
/* error path */
if (e->skb == DMA_DUMMY_DATA) {
struct mt76_txwi_cache *t;
struct mt7921_txp_common *txp;
u16 token;
txp = mt7921_txwi_to_txp(mdev, e->txwi);
token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID;
t = mt76_token_put(mdev, token);
e->skb = t ? t->skb : NULL;
}
if (e->skb)
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
void mt7921_tx_token_put(struct mt7921_dev *dev)
{
struct mt76_txwi_cache *txwi;
int id;
spin_lock_bh(&dev->mt76.token_lock);
idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7921_txwi_free(dev, txwi, NULL, false, NULL);
dev->mt76.token_count--;
}
spin_unlock_bh(&dev->mt76.token_lock);
idr_destroy(&dev->mt76.token);
}
int mt7921e_mac_reset(struct mt7921_dev *dev)
{
int i, err;
mt7921e_mcu_drv_pmctrl(dev);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]);
napi_disable(&dev->mt76.napi[MT_RXQ_MCU]);
napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
napi_disable(&dev->mt76.tx_napi);
mt7921_tx_token_put(dev);
idr_init(&dev->mt76.token);
mt7921_wpdma_reset(dev, true);
local_bh_disable();
mt76_for_each_q_rx(&dev->mt76, i) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
local_bh_enable();
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA,
MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
err = mt7921_run_firmware(dev);
if (err)
goto out;
err = mt7921_mcu_set_eeprom(dev);
if (err)
goto out;
err = mt7921_mac_init(dev);
if (err)
goto out;
err = __mt7921_start(&dev->phy);
out:
clear_bit(MT76_RESET, &dev->mphy.state);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
local_bh_enable();
mt76_worker_enable(&dev->mt76.tx_worker);
return err;
}

View File

@ -0,0 +1,115 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc. */
#include "mt7921.h"
#include "mcu.h"
static int mt7921e_driver_own(struct mt7921_dev *dev)
{
u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN);
if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN,
0, 500)) {
dev_err(dev->mt76.dev, "Timeout for driver own\n");
return -EIO;
}
return 0;
}
static int
mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *seq)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
enum mt76_mcuq_id txq = MT_MCUQ_WM;
int ret;
ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
if (ret)
return ret;
if (cmd == MCU_CMD_FW_SCATTER)
txq = MT_MCUQ_FWDL;
return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
}
int mt7921e_mcu_init(struct mt7921_dev *dev)
{
static const struct mt76_mcu_ops mt7921_mcu_ops = {
.headroom = sizeof(struct mt7921_mcu_txd),
.mcu_skb_send_msg = mt7921_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_restart = mt7921_mcu_restart,
};
int err;
dev->mt76.mcu_ops = &mt7921_mcu_ops;
err = mt7921e_driver_own(dev);
if (err)
return err;
err = mt7921_run_firmware(dev);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
return err;
}
int mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 0, 50))
break;
}
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
err = -EIO;
goto out;
}
mt7921_wpdma_reinit_cond(dev);
clear_bit(MT76_STATE_PM, &mphy->state);
pm->stats.last_wake_event = jiffies;
pm->stats.doze_time += pm->stats.last_wake_event -
pm->stats.last_doze_event;
out:
return err;
}
int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int i, err = 0;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 4, 50))
break;
}
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "firmware own failed\n");
clear_bit(MT76_STATE_PM, &mphy->state);
err = -EIO;
}
pm->stats.last_doze_event = jiffies;
pm->stats.awake_time += pm->stats.last_doze_event -
pm->stats.last_wake_event;
return err;
}

View File

@ -14,7 +14,7 @@
#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
#define MT_PLE_BASE 0x8000
#define MT_PLE_BASE 0x820c0000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
@ -26,7 +26,7 @@
((n) << 2))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
#define MT_MDP_BASE 0xf000
#define MT_MDP_BASE 0x820cd000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
#define MT_MDP_DCR0 MT_MDP(0x000)
@ -49,7 +49,7 @@
#define MT_MDP_TO_WM 1
/* TMAC: band 0(0x21000), band 1(0xa1000) */
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
@ -74,7 +74,7 @@
#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)
#define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000)
#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
@ -82,7 +82,7 @@
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
/* LPON: band 0(0x24200), band 1(0xa4200) */
#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200)
#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))
#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x080)
@ -92,25 +92,57 @@
#define MT_LPON_TCR_SW_MODE GENMASK(1, 0)
#define MT_LPON_TCR_SW_WRITE BIT(0)
/* ETBF: band 0(0x24000), band 1(0xa4000) */
#define MT_WF_ETBF_BASE(_band) ((_band) ? 0x820fa000 : 0x820ea000)
#define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs))
#define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x150)
#define MT_ETBF_TX_IBF_CNT GENMASK(31, 16)
#define MT_ETBF_TX_EBF_CNT GENMASK(15, 0)
#define MT_ETBF_RX_FB_CNT(_band) MT_WF_ETBF(_band, 0x158)
#define MT_ETBF_RX_FB_ALL GENMASK(31, 24)
#define MT_ETBF_RX_FB_HE GENMASK(23, 16)
#define MT_ETBF_RX_FB_VHT GENMASK(15, 8)
#define MT_ETBF_RX_FB_HT GENMASK(7, 0)
/* MIB: band 0(0x24800), band 1(0xa4800) */
#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
#define MT_WF_MIB_BASE(_band) ((_band) ? 0x820fd000 : 0x820ed000)
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
#define MT_MIB_SCR1(_band) MT_WF_MIB(_band, 0x004)
#define MT_MIB_TXDUR_EN BIT(8)
#define MT_MIB_RXDUR_EN BIT(9)
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x698)
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(31, 16)
#define MT_MIB_SDR5(_band) MT_WF_MIB(_band, 0x780)
#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR12(_band) MT_WF_MIB(_band, 0x558)
#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x564)
#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x568)
#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR22(_band) MT_WF_MIB(_band, 0x770)
#define MT_MIB_SDR23(_band) MT_WF_MIB(_band, 0x774)
#define MT_MIB_SDR31(_band) MT_WF_MIB(_band, 0x55c)
#define MT_MIB_SDR32(_band) MT_WF_MIB(_band, 0x7a8)
#define MT_MIB_SDR9_IBF_CNT_MASK GENMASK(31, 16)
#define MT_MIB_SDR9_EBF_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)
#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x054)
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x058)
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0)
@ -138,7 +170,7 @@
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
#define MT_WTBLON_TOP_BASE 0x34000
#define MT_WTBLON_TOP_BASE 0x820d4000
#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x200)
#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
@ -148,7 +180,7 @@
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
#define MT_WTBL_UPDATE_BUSY BIT(31)
#define MT_WTBL_BASE 0x38000
#define MT_WTBL_BASE 0x820d8000
#define MT_WTBL_LMAC_ID GENMASK(14, 8)
#define MT_WTBL_LMAC_DW GENMASK(7, 2)
#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
@ -156,7 +188,7 @@
FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
/* AGG: band 0(0x20800), band 1(0xa0800) */
#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
#define MT_WF_AGG_BASE(_band) ((_band) ? 0x820f2000 : 0x820e2000)
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
@ -187,7 +219,7 @@
#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
/* ARB: band 0(0x20c00), band 1(0xa0c00) */
#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
#define MT_WF_ARB_BASE(_band) ((_band) ? 0x820f3000 : 0x820e3000)
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
@ -197,7 +229,7 @@
#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
/* RMAC: band 0(0x21400), band 1(0xa1400) */
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0x820f5000 : 0x820e5000)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)

View File

@ -0,0 +1,317 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc.
*
*/
#include <linux/kernel.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include "mt7921.h"
#include "../sdio.h"
#include "mac.h"
#include "mcu.h"
static const struct sdio_device_id mt7921s_table[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901) },
{ } /* Terminating entry */
};
static void mt7921s_txrx_worker(struct mt76_worker *w)
{
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(mdev->wq, &dev->pm.wake_work);
return;
}
mt76s_txrx_worker(sdio);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
static void mt7921s_unregister_device(struct mt7921_dev *dev)
{
struct mt76_connac_pm *pm = &dev->pm;
mt76_unregister_device(&dev->mt76);
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
mt76s_deinit(&dev->mt76);
mt7921s_wfsys_reset(dev);
mt7921_mcu_exit(dev);
mt76_free_device(&dev->mt76);
}
static int mt7921s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr)
{
struct mt76_sdio *sdio = &dev->sdio;
struct mt7921_sdio_intr *irq_data = sdio->intr_data;
int i, err;
err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data));
if (err < 0)
return err;
intr->isr = irq_data->isr;
intr->rec_mb = irq_data->rec_mb;
intr->tx.wtqcr = irq_data->tx.wtqcr;
intr->rx.num = irq_data->rx.num;
for (i = 0; i < 2 ; i++) {
if (!i)
intr->rx.len[0] = irq_data->rx.len0;
else
intr->rx.len[1] = irq_data->rx.len1;
}
return 0;
}
static int mt7921s_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.txwi_size = MT_SDIO_TXD_SIZE,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
.tx_prepare_skb = mt7921s_tx_prepare_skb,
.tx_complete_skb = mt7921s_tx_complete_skb,
.tx_status_data = mt7921s_tx_status_data,
.rx_skb = mt7921_queue_rx_skb,
.sta_ps = mt7921_sta_ps,
.sta_add = mt7921_mac_sta_add,
.sta_assoc = mt7921_mac_sta_assoc,
.sta_remove = mt7921_mac_sta_remove,
.update_survey = mt7921_update_channel,
};
static const struct mt76_bus_ops mt7921s_ops = {
.rr = mt76s_rr,
.rmw = mt76s_rmw,
.wr = mt76s_wr,
.write_copy = mt76s_write_copy,
.read_copy = mt76s_read_copy,
.wr_rp = mt76s_wr_rp,
.rd_rp = mt76s_rd_rp,
.type = MT76_BUS_SDIO,
};
static const struct mt7921_hif_ops mt7921_sdio_ops = {
.init_reset = mt7921s_init_reset,
.reset = mt7921s_mac_reset,
.mcu_init = mt7921s_mcu_init,
.drv_own = mt7921s_mcu_drv_pmctrl,
.fw_own = mt7921s_mcu_fw_pmctrl,
};
struct mt7921_dev *dev;
struct mt76_dev *mdev;
int ret, i;
mdev = mt76_alloc_device(&func->dev, sizeof(*dev), &mt7921_ops,
&drv_ops);
if (!mdev)
return -ENOMEM;
dev = container_of(mdev, struct mt7921_dev, mt76);
dev->hif_ops = &mt7921_sdio_ops;
sdio_set_drvdata(func, dev);
ret = mt76s_init(mdev, func, &mt7921s_ops);
if (ret < 0)
goto error;
ret = mt76s_hw_init(mdev, func, MT76_CONNAC2_SDIO);
if (ret)
goto error;
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
mdev->sdio.parse_irq = mt7921s_parse_intr;
mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
sizeof(struct mt7921_sdio_intr),
GFP_KERNEL);
if (!mdev->sdio.intr_data) {
ret = -ENOMEM;
goto error;
}
for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
mdev->sdio.xmit_buf[i] = devm_kmalloc(mdev->dev,
MT76S_XMIT_BUF_SZ,
GFP_KERNEL);
if (!mdev->sdio.xmit_buf[i]) {
ret = -ENOMEM;
goto error;
}
}
ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN);
if (ret)
goto error;
ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MCU);
if (ret)
goto error;
ret = mt76s_alloc_tx(mdev);
if (ret)
goto error;
ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
mt7921s_txrx_worker, "sdio-txrx");
if (ret)
goto error;
sched_set_fifo_low(mdev->sdio.txrx_worker.task);
ret = mt7921_register_device(dev);
if (ret)
goto error;
return 0;
error:
mt76s_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
return ret;
}
static void mt7921s_remove(struct sdio_func *func)
{
struct mt7921_dev *dev = sdio_get_drvdata(func);
mt7921s_unregister_device(dev);
}
#ifdef CONFIG_PM
static int mt7921s_suspend(struct device *__dev)
{
struct sdio_func *func = dev_to_sdio_func(__dev);
struct mt7921_dev *dev = sdio_get_drvdata(func);
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_dev *mdev = &dev->mt76;
bool hif_suspend;
int err;
pm->suspended = true;
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
err = mt7921_mcu_drv_pmctrl(dev);
if (err < 0)
goto restore_suspend;
hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state);
if (hif_suspend) {
err = mt76_connac_mcu_set_hif_suspend(mdev, true);
if (err)
goto restore_suspend;
}
/* always enable deep sleep during suspend to reduce
* power consumption
*/
mt76_connac_mcu_set_deep_sleep(mdev, true);
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&mdev->tx_worker);
mt76_worker_disable(&mdev->sdio.txrx_worker);
mt76_worker_disable(&mdev->sdio.status_worker);
mt76_worker_disable(&mdev->sdio.net_worker);
cancel_work_sync(&mdev->sdio.stat_work);
clear_bit(MT76_READING_STATS, &dev->mphy.state);
mt76_tx_status_check(mdev, true);
err = mt7921_mcu_fw_pmctrl(dev);
if (err)
goto restore_worker;
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
return 0;
restore_worker:
mt76_worker_enable(&mdev->tx_worker);
mt76_worker_enable(&mdev->sdio.txrx_worker);
mt76_worker_enable(&mdev->sdio.status_worker);
mt76_worker_enable(&mdev->sdio.net_worker);
if (!pm->ds_enable)
mt76_connac_mcu_set_deep_sleep(mdev, false);
if (hif_suspend)
mt76_connac_mcu_set_hif_suspend(mdev, false);
restore_suspend:
pm->suspended = false;
return err;
}
static int mt7921s_resume(struct device *__dev)
{
struct sdio_func *func = dev_to_sdio_func(__dev);
struct mt7921_dev *dev = sdio_get_drvdata(func);
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_dev *mdev = &dev->mt76;
int err;
pm->suspended = false;
err = mt7921_mcu_drv_pmctrl(dev);
if (err < 0)
return err;
mt76_worker_enable(&mdev->tx_worker);
mt76_worker_enable(&mdev->sdio.txrx_worker);
mt76_worker_enable(&mdev->sdio.status_worker);
mt76_worker_enable(&mdev->sdio.net_worker);
/* restore previous ds setting */
if (!pm->ds_enable)
mt76_connac_mcu_set_deep_sleep(mdev, false);
if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state))
err = mt76_connac_mcu_set_hif_suspend(mdev, false);
return err;
}
static const struct dev_pm_ops mt7921s_pm_ops = {
.suspend = mt7921s_suspend,
.resume = mt7921s_resume,
};
#endif
MODULE_DEVICE_TABLE(sdio, mt7921s_table);
MODULE_FIRMWARE(MT7921_FIRMWARE_WM);
MODULE_FIRMWARE(MT7921_ROM_PATCH);
static struct sdio_driver mt7921s_driver = {
.name = KBUILD_MODNAME,
.probe = mt7921s_probe,
.remove = mt7921s_remove,
.id_table = mt7921s_table,
#ifdef CONFIG_PM
.drv = {
.pm = &mt7921s_pm_ops,
}
#endif
};
module_sdio_driver(mt7921s_driver);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,220 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc. */
#include <linux/iopoll.h>
#include <linux/mmc/sdio_func.h>
#include "mt7921.h"
#include "mac.h"
#include "../sdio.h"
static void mt7921s_enable_irq(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
}
static void mt7921s_disable_irq(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
}
static u32 mt7921s_read_whcr(struct mt76_dev *dev)
{
return sdio_readl(dev->sdio.func, MCR_WHCR, NULL);
}
int mt7921s_wfsys_reset(struct mt7921_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
u32 val, status;
mt7921s_mcu_drv_pmctrl(dev);
sdio_claim_host(sdio->func);
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
val &= ~WF_WHOLE_PATH_RSTB;
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
msleep(50);
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
val &= ~WF_SDIO_WF_PATH_RSTB;
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
usleep_range(1000, 2000);
val = sdio_readl(sdio->func, MCR_WHCR, NULL);
val |= WF_WHOLE_PATH_RSTB;
sdio_writel(sdio->func, val, MCR_WHCR, NULL);
readx_poll_timeout(mt7921s_read_whcr, &dev->mt76, status,
status & WF_RST_DONE, 50000, 2000000);
sdio_release_host(sdio->func);
/* activate mt7921s again */
mt7921s_mcu_fw_pmctrl(dev);
mt7921s_mcu_drv_pmctrl(dev);
return 0;
}
int mt7921s_init_reset(struct mt7921_dev *dev)
{
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
wait_event_timeout(dev->mt76.sdio.wait,
mt76s_txqs_empty(&dev->mt76), 5 * HZ);
mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
mt7921s_disable_irq(&dev->mt76);
mt7921s_wfsys_reset(dev);
mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
mt7921s_enable_irq(&dev->mt76);
return 0;
}
int mt7921s_mac_reset(struct mt7921_dev *dev)
{
int err;
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
wait_event_timeout(dev->mt76.sdio.wait,
mt76s_txqs_empty(&dev->mt76), 5 * HZ);
mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
mt76_worker_disable(&dev->mt76.sdio.status_worker);
mt76_worker_disable(&dev->mt76.sdio.net_worker);
cancel_work_sync(&dev->mt76.sdio.stat_work);
mt7921s_disable_irq(&dev->mt76);
mt7921s_wfsys_reset(dev);
mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
mt76_worker_enable(&dev->mt76.sdio.status_worker);
mt76_worker_enable(&dev->mt76.sdio.net_worker);
dev->fw_assert = false;
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
mt7921s_enable_irq(&dev->mt76);
err = mt7921_run_firmware(dev);
if (err)
goto out;
err = mt7921_mcu_set_eeprom(dev);
if (err)
goto out;
err = mt7921_mac_init(dev);
if (err)
goto out;
err = __mt7921_start(&dev->phy);
out:
clear_bit(MT76_RESET, &dev->mphy.state);
mt76_worker_enable(&dev->mt76.tx_worker);
return err;
}
static void
mt7921s_write_txwi(struct mt7921_dev *dev, struct mt76_wcid *wcid,
enum mt76_txq_id qid, struct ieee80211_sta *sta,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_key_conf *key = info->control.hw_key;
__le32 *txwi;
int pid;
pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);
txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE);
memset(txwi, 0, MT_SDIO_TXD_SIZE);
mt7921_mac_write_txwi(dev, txwi, skb, wcid, key, pid, false);
skb_push(skb, MT_SDIO_TXD_SIZE);
}
int mt7921s_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct sk_buff *skb = tx_info->skb;
int pad;
if (unlikely(tx_info->skb->len <= ETH_HLEN))
return -EINVAL;
if (!wcid)
wcid = &dev->mt76.global_wcid;
if (sta) {
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
if (time_after(jiffies, msta->last_txs + HZ / 4)) {
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
msta->last_txs = jiffies;
}
}
mt7921s_write_txwi(dev, wcid, qid, sta, skb);
mt7921_skb_add_sdio_hdr(skb, MT7921_SDIO_DATA);
pad = round_up(skb->len, 4) - skb->len;
return mt76_skb_adjust_pad(skb, pad);
}
void mt7921s_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
__le32 *txwi = (__le32 *)(e->skb->data + MT_SDIO_HDR_SIZE);
unsigned int headroom = MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE;
struct ieee80211_sta *sta;
struct mt76_wcid *wcid;
u16 idx;
idx = FIELD_GET(MT_TXD1_WLAN_IDX, le32_to_cpu(txwi[1]));
wcid = rcu_dereference(mdev->wcid[idx]);
sta = wcid_to_sta(wcid);
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
mt7921_tx_check_aggr(sta, txwi);
skb_pull(e->skb, headroom);
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
bool mt7921s_tx_status_data(struct mt76_dev *mdev, u8 *update)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
mt7921_mutex_acquire(dev);
mt7921_mac_sta_poll(dev);
mt7921_mutex_release(dev);
return 0;
}

View File

@ -0,0 +1,135 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc. */
#include <linux/kernel.h>
#include <linux/mmc/sdio_func.h>
#include <linux/module.h>
#include <linux/iopoll.h>
#include "mt7921.h"
#include "../sdio.h"
#include "mac.h"
#include "mcu.h"
#include "regs.h"
static int
mt7921s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *seq)
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
enum mt7921_sdio_pkt_type type = MT7921_SDIO_CMD;
enum mt76_mcuq_id txq = MT_MCUQ_WM;
int ret, pad;
/* We just return in case firmware assertion to avoid blocking the
* common workqueue to run, for example, the coredump work might be
* blocked by mt7921_mac_work that is excuting register access via sdio
* bus.
*/
if (dev->fw_assert)
return -EBUSY;
ret = mt7921_mcu_fill_message(mdev, skb, cmd, seq);
if (ret)
return ret;
if (cmd == MCU_CMD_FW_SCATTER)
type = MT7921_SDIO_FWDL;
mt7921_skb_add_sdio_hdr(skb, type);
pad = round_up(skb->len, 4) - skb->len;
__skb_put_zero(skb, pad);
ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
if (ret)
return ret;
mt76_queue_kick(dev, mdev->q_mcu[txq]);
return ret;
}
int mt7921s_mcu_init(struct mt7921_dev *dev)
{
static const struct mt76_mcu_ops mt7921s_mcu_ops = {
.headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt7921_mcu_txd),
.tailroom = MT_SDIO_TAIL_SIZE,
.mcu_skb_send_msg = mt7921s_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_rr = mt76_connac_mcu_reg_rr,
.mcu_wr = mt76_connac_mcu_reg_wr,
};
int ret;
mt7921s_mcu_drv_pmctrl(dev);
dev->mt76.mcu_ops = &mt7921s_mcu_ops;
ret = mt7921_run_firmware(dev);
if (ret)
return ret;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
return 0;
}
int mt7921s_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int err = 0;
u32 status;
sdio_claim_host(func);
sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
sdio_release_host(func);
if (err < 0) {
dev_err(dev->mt76.dev, "driver own failed\n");
err = -EIO;
goto out;
}
clear_bit(MT76_STATE_PM, &mphy->state);
pm->stats.last_wake_event = jiffies;
pm->stats.doze_time += pm->stats.last_wake_event -
pm->stats.last_doze_event;
out:
return err;
}
int mt7921s_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
struct mt76_connac_pm *pm = &dev->pm;
int err = 0;
u32 status;
sdio_claim_host(func);
sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
err = readx_poll_timeout(mt76s_read_pcr, &dev->mt76, status,
!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
sdio_release_host(func);
if (err < 0) {
dev_err(dev->mt76.dev, "firmware own failed\n");
clear_bit(MT76_STATE_PM, &mphy->state);
err = -EIO;
}
pm->stats.last_doze_event = jiffies;
pm->stats.awake_time += pm->stats.last_doze_event -
pm->stats.last_wake_event;
return err;
}

View File

@ -0,0 +1,197 @@
// SPDX-License-Identifier: ISC
#include "mt7921.h"
#include "mcu.h"
enum mt7921_testmode_attr {
MT7921_TM_ATTR_UNSPEC,
MT7921_TM_ATTR_SET,
MT7921_TM_ATTR_QUERY,
MT7921_TM_ATTR_RSP,
/* keep last */
NUM_MT7921_TM_ATTRS,
MT7921_TM_ATTR_MAX = NUM_MT7921_TM_ATTRS - 1,
};
struct mt7921_tm_cmd {
u8 action;
u32 param0;
u32 param1;
};
struct mt7921_tm_evt {
u32 param0;
u32 param1;
};
static const struct nla_policy mt7921_tm_policy[NUM_MT7921_TM_ATTRS] = {
[MT7921_TM_ATTR_SET] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)),
[MT7921_TM_ATTR_QUERY] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7921_tm_cmd)),
};
static int
mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
{
struct mt7921_rftest_cmd cmd = {
.action = req->action,
.param0 = cpu_to_le32(req->param0),
.param1 = cpu_to_le32(req->param1),
};
bool testmode = false, normal = false;
struct mt76_connac_pm *pm = &dev->pm;
struct mt76_phy *phy = &dev->mphy;
int ret = -ENOTCONN;
mutex_lock(&dev->mt76.mutex);
if (req->action == TM_SWITCH_MODE) {
if (req->param0 == MT7921_TM_NORMAL)
normal = true;
else
testmode = true;
}
if (testmode) {
/* Make sure testmode running on full power mode */
pm->enable = false;
cancel_delayed_work_sync(&pm->ps_work);
cancel_work_sync(&pm->wake_work);
__mt7921_mcu_drv_pmctrl(dev);
mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
phy->test.state = MT76_TM_STATE_ON;
}
if (!mt76_testmode_enabled(phy))
goto out;
ret = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TEST_CTRL, &cmd,
sizeof(cmd), false);
if (ret)
goto out;
if (normal) {
/* Switch back to the normal world */
phy->test.state = MT76_TM_STATE_OFF;
pm->enable = true;
}
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static int
mt7921_tm_query(struct mt7921_dev *dev, struct mt7921_tm_cmd *req,
struct mt7921_tm_evt *evt_resp)
{
struct mt7921_rftest_cmd cmd = {
.action = req->action,
.param0 = cpu_to_le32(req->param0),
.param1 = cpu_to_le32(req->param1),
};
struct mt7921_rftest_evt *evt;
struct sk_buff *skb;
int ret;
ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_TEST_CTRL,
&cmd, sizeof(cmd), true, &skb);
if (ret)
goto out;
evt = (struct mt7921_rftest_evt *)skb->data;
evt_resp->param0 = le32_to_cpu(evt->param0);
evt_resp->param1 = le32_to_cpu(evt->param1);
out:
dev_kfree_skb(skb);
return ret;
}
int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len)
{
struct nlattr *tb[NUM_MT76_TM_ATTRS];
struct mt76_phy *mphy = hw->priv;
struct mt7921_phy *phy = mphy->priv;
int err;
if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
!(hw->conf.flags & IEEE80211_CONF_MONITOR))
return -ENOTCONN;
err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
mt76_tm_policy, NULL);
if (err)
return err;
if (tb[MT76_TM_ATTR_DRV_DATA]) {
struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
int ret;
data = tb[MT76_TM_ATTR_DRV_DATA];
ret = nla_parse_nested_deprecated(drv_tb,
MT7921_TM_ATTR_MAX,
data, mt7921_tm_policy,
NULL);
if (ret)
return ret;
data = drv_tb[MT7921_TM_ATTR_SET];
if (data)
return mt7921_tm_set(phy->dev, nla_data(data));
}
return -EINVAL;
}
int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
struct netlink_callback *cb, void *data, int len)
{
struct nlattr *tb[NUM_MT76_TM_ATTRS];
struct mt76_phy *mphy = hw->priv;
struct mt7921_phy *phy = mphy->priv;
int err;
if (!test_bit(MT76_STATE_RUNNING, &mphy->state) ||
!(hw->conf.flags & IEEE80211_CONF_MONITOR) ||
!mt76_testmode_enabled(mphy))
return -ENOTCONN;
if (cb->args[2]++ > 0)
return -ENOENT;
err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len,
mt76_tm_policy, NULL);
if (err)
return err;
if (tb[MT76_TM_ATTR_DRV_DATA]) {
struct nlattr *drv_tb[NUM_MT7921_TM_ATTRS], *data;
int ret;
data = tb[MT76_TM_ATTR_DRV_DATA];
ret = nla_parse_nested_deprecated(drv_tb,
MT7921_TM_ATTR_MAX,
data, mt7921_tm_policy,
NULL);
if (ret)
return ret;
data = drv_tb[MT7921_TM_ATTR_QUERY];
if (data) {
struct mt7921_tm_evt evt_resp;
err = mt7921_tm_query(phy->dev, nla_data(data),
&evt_resp);
if (err)
return err;
return nla_put(msg, MT7921_TM_ATTR_RSP,
sizeof(evt_resp), &evt_resp);
}
}
return -EINVAL;
}

View File

@ -16,9 +16,290 @@
#include <linux/kthread.h>
#include "mt76.h"
#include "sdio.h"
static int
mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
static u32 mt76s_read_whisr(struct mt76_dev *dev)
{
return sdio_readl(dev->sdio.func, MCR_WHISR, NULL);
}
u32 mt76s_read_pcr(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
return sdio_readl(sdio->func, MCR_WHLPCR, NULL);
}
EXPORT_SYMBOL_GPL(mt76s_read_pcr);
static u32 mt76s_read_mailbox(struct mt76_dev *dev, u32 offset)
{
struct sdio_func *func = dev->sdio.func;
u32 val = ~0, status;
int err;
sdio_claim_host(func);
sdio_writel(func, offset, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting address [err=%d]\n", err);
goto out;
}
sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
goto out;
}
err = readx_poll_timeout(mt76s_read_whisr, dev, status,
status & H2D_SW_INT_READ, 0, 1000000);
if (err < 0) {
dev_err(dev->dev, "query whisr timeout\n");
goto out;
}
sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting read mode [err=%d]\n", err);
goto out;
}
val = sdio_readl(func, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
goto out;
}
if (val != offset) {
dev_err(dev->dev, "register mismatch\n");
val = ~0;
goto out;
}
val = sdio_readl(func, MCR_D2HRM1R, &err);
if (err < 0)
dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err);
out:
sdio_release_host(func);
return val;
}
static void mt76s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val)
{
struct sdio_func *func = dev->sdio.func;
u32 status;
int err;
sdio_claim_host(func);
sdio_writel(func, offset, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting address [err=%d]\n", err);
goto out;
}
sdio_writel(func, val, MCR_H2DSM1R, &err);
if (err < 0) {
dev_err(dev->dev,
"failed setting write value [err=%d]\n", err);
goto out;
}
sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
goto out;
}
err = readx_poll_timeout(mt76s_read_whisr, dev, status,
status & H2D_SW_INT_WRITE, 0, 1000000);
if (err < 0) {
dev_err(dev->dev, "query whisr timeout\n");
goto out;
}
sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err);
if (err < 0) {
dev_err(dev->dev, "failed setting write mode [err=%d]\n", err);
goto out;
}
val = sdio_readl(func, MCR_H2DSM0R, &err);
if (err < 0) {
dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err);
goto out;
}
if (val != offset)
dev_err(dev->dev, "register mismatch\n");
out:
sdio_release_host(func);
}
u32 mt76s_rr(struct mt76_dev *dev, u32 offset)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
return dev->mcu_ops->mcu_rr(dev, offset);
else
return mt76s_read_mailbox(dev, offset);
}
EXPORT_SYMBOL_GPL(mt76s_rr);
void mt76s_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state))
dev->mcu_ops->mcu_wr(dev, offset, val);
else
mt76s_write_mailbox(dev, offset, val);
}
EXPORT_SYMBOL_GPL(mt76s_wr);
u32 mt76s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
{
val |= mt76s_rr(dev, offset) & ~mask;
mt76s_wr(dev, offset, val);
return val;
}
EXPORT_SYMBOL_GPL(mt76s_rmw);
void mt76s_write_copy(struct mt76_dev *dev, u32 offset,
const void *data, int len)
{
const u32 *val = data;
int i;
for (i = 0; i < len / sizeof(u32); i++) {
mt76s_wr(dev, offset, val[i]);
offset += sizeof(u32);
}
}
EXPORT_SYMBOL_GPL(mt76s_write_copy);
void mt76s_read_copy(struct mt76_dev *dev, u32 offset,
void *data, int len)
{
u32 *val = data;
int i;
for (i = 0; i < len / sizeof(u32); i++) {
val[i] = mt76s_rr(dev, offset);
offset += sizeof(u32);
}
}
EXPORT_SYMBOL_GPL(mt76s_read_copy);
int mt76s_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data,
int len)
{
int i;
for (i = 0; i < len; i++) {
mt76s_wr(dev, data->reg, data->value);
data++;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76s_wr_rp);
int mt76s_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data, int len)
{
int i;
for (i = 0; i < len; i++) {
data->value = mt76s_rr(dev, data->reg);
data++;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76s_rd_rp);
int mt76s_hw_init(struct mt76_dev *dev, struct sdio_func *func, int hw_ver)
{
u32 status, ctrl;
int ret;
dev->sdio.hw_ver = hw_ver;
sdio_claim_host(func);
ret = sdio_enable_func(func);
if (ret < 0)
goto release;
/* Get ownership from the device */
sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR,
MCR_WHLPCR, &ret);
if (ret < 0)
goto disable_func;
ret = readx_poll_timeout(mt76s_read_pcr, dev, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
if (ret < 0) {
dev_err(dev->dev, "Cannot get ownership from device");
goto disable_func;
}
ret = sdio_set_block_size(func, 512);
if (ret < 0)
goto disable_func;
/* Enable interrupt */
sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret);
if (ret < 0)
goto disable_func;
ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN;
if (hw_ver == MT76_CONNAC2_SDIO)
ctrl |= WHIER_RX1_DONE_INT_EN;
sdio_writel(func, ctrl, MCR_WHIER, &ret);
if (ret < 0)
goto disable_func;
switch (hw_ver) {
case MT76_CONNAC_SDIO:
/* set WHISR as read clear and Rx aggregation number as 16 */
ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16);
break;
default:
ctrl = sdio_readl(func, MCR_WHCR, &ret);
if (ret < 0)
goto disable_func;
ctrl &= ~MAX_HIF_RX_LEN_NUM_CONNAC2;
ctrl &= ~W_INT_CLR_CTRL; /* read clear */
ctrl |= FIELD_PREP(MAX_HIF_RX_LEN_NUM_CONNAC2, 0);
break;
}
sdio_writel(func, ctrl, MCR_WHCR, &ret);
if (ret < 0)
goto disable_func;
ret = sdio_claim_irq(func, mt76s_sdio_irq);
if (ret < 0)
goto disable_func;
sdio_release_host(func);
return 0;
disable_func:
sdio_disable_func(func);
release:
sdio_release_host(func);
return ret;
}
EXPORT_SYMBOL_GPL(mt76s_hw_init);
int mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
{
struct mt76_queue *q = &dev->q_rx[qid];
@ -35,6 +316,7 @@ mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
return 0;
}
EXPORT_SYMBOL_GPL(mt76s_alloc_rx_queue);
static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev)
{
@ -56,7 +338,7 @@ static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev)
return q;
}
static int mt76s_alloc_tx(struct mt76_dev *dev)
int mt76s_alloc_tx(struct mt76_dev *dev)
{
struct mt76_queue *q;
int i;
@ -79,18 +361,7 @@ static int mt76s_alloc_tx(struct mt76_dev *dev)
return 0;
}
int mt76s_alloc_queues(struct mt76_dev *dev)
{
int err;
err = mt76s_alloc_rx_queue(dev, MT_RXQ_MAIN);
if (err < 0)
return err;
return mt76s_alloc_tx(dev);
}
EXPORT_SYMBOL_GPL(mt76s_alloc_queues);
EXPORT_SYMBOL_GPL(mt76s_alloc_tx);
static struct mt76_queue_entry *
mt76s_get_next_rx_entry(struct mt76_queue *q)
@ -328,7 +599,7 @@ void mt76s_deinit(struct mt76_dev *dev)
cancel_work_sync(&sdio->stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
mt76_tx_status_check(dev, NULL, true);
mt76_tx_status_check(dev, true);
sdio_claim_host(sdio->func);
sdio_release_irq(sdio->func);

View File

@ -21,7 +21,12 @@
#define MCR_WHCR 0x000C
#define W_INT_CLR_CTRL BIT(1)
#define RECV_MAILBOX_RD_CLR_EN BIT(2)
#define WF_SYS_RSTB BIT(4) /* supported in CONNAC2 */
#define WF_WHOLE_PATH_RSTB BIT(5) /* supported in CONNAC2 */
#define WF_SDIO_WF_PATH_RSTB BIT(6) /* supported in CONNAC2 */
#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8)
#define MAX_HIF_RX_LEN_NUM_CONNAC2 GENMASK(14, 8) /* supported in CONNAC2 */
#define WF_RST_DONE BIT(15) /* supported in CONNAC2 */
#define RX_ENHANCE_MODE BIT(16)
#define MCR_WHISR 0x0010
@ -29,6 +34,7 @@
#define WHIER_D2H_SW_INT GENMASK(31, 8)
#define WHIER_FW_OWN_BACK_INT_EN BIT(7)
#define WHIER_ABNORMAL_INT_EN BIT(6)
#define WHIER_WDT_INT_EN BIT(5) /* supported in CONNAC2 */
#define WHIER_RX1_DONE_INT_EN BIT(2)
#define WHIER_RX0_DONE_INT_EN BIT(1)
#define WHIER_TX_DONE_INT_EN BIT(0)
@ -100,16 +106,33 @@
#define MCR_SWPCDBGR 0x0154
#define MCR_H2DSM2R 0x0160 /* supported in CONNAC2 */
#define MCR_H2DSM3R 0x0164 /* supported in CONNAC2 */
#define MCR_D2HRM3R 0x0174 /* supported in CONNAC2 */
#define MCR_WTQCR8 0x0190 /* supported in CONNAC2 */
#define MCR_WTQCR9 0x0194 /* supported in CONNAC2 */
#define MCR_WTQCR10 0x0198 /* supported in CONNAC2 */
#define MCR_WTQCR11 0x019C /* supported in CONNAC2 */
#define MCR_WTQCR12 0x01A0 /* supported in CONNAC2 */
#define MCR_WTQCR13 0x01A4 /* supported in CONNAC2 */
#define MCR_WTQCR14 0x01A8 /* supported in CONNAC2 */
#define MCR_WTQCR15 0x01AC /* supported in CONNAC2 */
enum mt76_connac_sdio_ver {
MT76_CONNAC_SDIO,
MT76_CONNAC2_SDIO,
};
struct mt76s_intr {
u32 isr;
u32 *rec_mb;
struct {
u32 wtqcr[8];
u32 *wtqcr;
} tx;
struct {
u16 num[2];
u16 len[2][16];
u16 *len[2];
u16 *num;
} rx;
u32 rec_mb[2];
} __packed;
};
#endif

View File

@ -14,12 +14,11 @@
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio_func.h>
#include "../trace.h"
#include "mt7615.h"
#include "trace.h"
#include "sdio.h"
#include "mac.h"
#include "mt76.h"
static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
static int mt76s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
{
u32 ple_ac_data_quota[] = {
FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
@ -53,8 +52,8 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
return pse_data_quota + ple_data_quota + pse_mcu_quota;
}
static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
int buf_len)
static struct sk_buff *
mt76s_build_rx_skb(void *data, int data_len, int buf_len)
{
int len = min_t(int, data_len, MT_SKB_HEAD_LEN);
struct sk_buff *skb;
@ -78,8 +77,9 @@ static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
return skb;
}
static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
struct mt76s_intr *intr)
static int
mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
struct mt76s_intr *intr)
{
struct mt76_queue *q = &dev->q_rx[qid];
struct mt76_sdio *sdio = &dev->sdio;
@ -112,9 +112,11 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
for (i = 0; i < intr->rx.num[qid]; i++) {
int index = (q->head + i) % q->ndesc;
struct mt76_queue_entry *e = &q->entry[index];
__le32 *rxd = (__le32 *)buf;
len = intr->rx.len[qid][i];
e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4));
/* parse rxd to get the actual packet length */
len = FIELD_GET(GENMASK(15, 0), le32_to_cpu(rxd[0]));
e->skb = mt76s_build_rx_skb(buf, len, round_up(len + 4, 4));
if (!e->skb)
break;
@ -132,45 +134,50 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
return i;
}
static int mt7663s_rx_handler(struct mt76_dev *dev)
static int mt76s_rx_handler(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
struct mt76s_intr *intr = sdio->intr_data;
struct mt76s_intr intr;
int nframes = 0, ret;
ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
if (ret < 0)
ret = sdio->parse_irq(dev, &intr);
if (ret)
return ret;
trace_dev_irq(dev, intr->isr, 0);
trace_dev_irq(dev, intr.isr, 0);
if (intr->isr & WHIER_RX0_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 0, intr);
if (intr.isr & WHIER_RX0_DONE_INT_EN) {
ret = mt76s_rx_run_queue(dev, 0, &intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}
if (intr->isr & WHIER_RX1_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 1, intr);
if (intr.isr & WHIER_RX1_DONE_INT_EN) {
ret = mt76s_rx_run_queue(dev, 1, &intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}
nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr);
return nframes;
}
static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
int *pse_size, int *ple_size)
static int
mt76s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
int *pse_size, int *ple_size)
{
int pse_sz;
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit,
sdio->sched.pse_page_size);
if (mcu && sdio->hw_ver == MT76_CONNAC2_SDIO)
pse_sz = 1;
if (mcu) {
if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
@ -187,8 +194,9 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
return 0;
}
static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
int pse_size, int ple_size)
static void
mt76s_tx_update_quota(struct mt76_sdio *sdio, bool mcu, int pse_size,
int ple_size)
{
if (mcu) {
sdio->sched.pse_mcu_quota -= pse_size;
@ -198,7 +206,7 @@ static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
}
}
static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
{
struct mt76_sdio *sdio = &dev->sdio;
int err;
@ -213,7 +221,7 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
return err;
}
static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
@ -227,10 +235,13 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
smp_rmb();
if (test_bit(MT76_MCU_RESET, &dev->phy.state))
goto next;
if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
__skb_put_zero(e->skb, 4);
err = __mt7663s_xmit_queue(dev, e->skb->data,
e->skb->len);
err = __mt76s_xmit_queue(dev, e->skb->data,
e->skb->len);
if (err)
return err;
@ -241,8 +252,8 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
if (len + e->skb->len + pad + 4 > MT76S_XMIT_BUF_SZ)
break;
if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
&ple_sz))
if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
&ple_sz))
break;
memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
@ -268,30 +279,22 @@ next:
if (nframes) {
memset(sdio->xmit_buf[qid] + len, 0, 4);
err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
err = __mt76s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
if (err)
return err;
}
mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
mt76_worker_schedule(&sdio->status_worker);
return nframes;
}
void mt7663s_txrx_worker(struct mt76_worker *w)
void mt76s_txrx_worker(struct mt76_sdio *sdio)
{
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
struct mt76_dev *mdev = container_of(sdio, struct mt76_dev, sdio);
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes, ret;
if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(mdev->wq, &dev->pm.wake_work);
return;
}
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
@ -301,34 +304,61 @@ void mt7663s_txrx_worker(struct mt76_worker *w)
/* tx */
for (i = 0; i <= MT_TXQ_PSD; i++) {
ret = mt7663s_tx_run_queue(mdev, mdev->phy.q_tx[i]);
ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]);
if (ret > 0)
nframes += ret;
}
ret = mt7663s_tx_run_queue(mdev, mdev->q_mcu[MT_MCUQ_WM]);
ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
if (ret > 0)
nframes += ret;
/* rx */
ret = mt7663s_rx_handler(mdev);
ret = mt76s_rx_handler(dev);
if (ret > 0)
nframes += ret;
if (test_bit(MT76_MCU_RESET, &dev->phy.state)) {
if (!mt76s_txqs_empty(dev))
continue;
else
wake_up(&sdio->wait);
}
} while (nframes > 0);
/* enable interrupt */
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
mt76_connac_pm_unref(&dev->mphy, &dev->pm);
}
EXPORT_SYMBOL_GPL(mt76s_txrx_worker);
void mt7663s_sdio_irq(struct sdio_func *func)
void mt76s_sdio_irq(struct sdio_func *func)
{
struct mt7615_dev *dev = sdio_get_drvdata(func);
struct mt76_sdio *sdio = &dev->mt76.sdio;
struct mt76_dev *dev = sdio_get_drvdata(func);
struct mt76_sdio *sdio = &dev->sdio;
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) ||
test_bit(MT76_MCU_RESET, &dev->phy.state))
return;
mt76_worker_schedule(&sdio->txrx_worker);
}
EXPORT_SYMBOL_GPL(mt76s_sdio_irq);
bool mt76s_txqs_empty(struct mt76_dev *dev)
{
struct mt76_queue *q;
int i;
for (i = 0; i <= MT_TXQ_PSD + 1; i++) {
if (i <= MT_TXQ_PSD)
q = dev->phy.q_tx[i];
else
q = dev->q_mcu[MT_MCUQ_WM];
if (q->first != q->head)
return false;
}
return true;
}
EXPORT_SYMBOL_GPL(mt76s_txqs_empty);

View File

@ -2,7 +2,7 @@
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#include "mt76.h"
static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_RESET] = { .type = NLA_FLAG },
[MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
@ -21,7 +21,9 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },
[MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
[MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
[MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED },
};
EXPORT_SYMBOL_GPL(mt76_tm_policy);
void mt76_testmode_tx_pending(struct mt76_phy *phy)
{

View File

@ -44,6 +44,7 @@
* @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_DRV_DATA: driver specific netlink attrs (nested)
*/
enum mt76_testmode_attr {
MT76_TM_ATTR_UNSPEC,
@ -78,6 +79,8 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_TX_IPG,
MT76_TM_ATTR_TX_TIME,
MT76_TM_ATTR_DRV_DATA,
/* keep last */
NUM_MT76_TM_ATTRS,
MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1,
@ -144,6 +147,7 @@ enum mt76_testmode_rx_attr {
* @MT76_TM_STATE_TX_FRAMES: send a fixed number of test frames
* @MT76_TM_STATE_RX_FRAMES: receive packets and keep statistics
* @MT76_TM_STATE_TX_CONT: waveform tx without time gap
* @MT76_TM_STATE_ON: test mode enabled used in offload firmware
*/
enum mt76_testmode_state {
MT76_TM_STATE_OFF,
@ -151,6 +155,7 @@ enum mt76_testmode_state {
MT76_TM_STATE_TX_FRAMES,
MT76_TM_STATE_RX_FRAMES,
MT76_TM_STATE_TX_CONT,
MT76_TM_STATE_ON,
/* keep last */
NUM_MT76_TM_STATES,
@ -184,4 +189,6 @@ enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1,
};
extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS];
#endif

View File

@ -38,21 +38,21 @@ EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
void
mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
__acquires(&dev->status_list.lock)
__acquires(&dev->status_lock)
{
__skb_queue_head_init(list);
spin_lock_bh(&dev->status_list.lock);
spin_lock_bh(&dev->status_lock);
}
EXPORT_SYMBOL_GPL(mt76_tx_status_lock);
void
mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
__releases(&dev->status_list.lock)
__releases(&dev->status_lock)
{
struct ieee80211_hw *hw;
struct sk_buff *skb;
spin_unlock_bh(&dev->status_list.lock);
spin_unlock_bh(&dev->status_lock);
rcu_read_lock();
while ((skb = __skb_dequeue(list)) != NULL) {
@ -64,9 +64,13 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
struct mt76_wcid *wcid;
wcid = rcu_dereference(dev->wcid[cb->wcid]);
if (wcid)
if (wcid) {
status.sta = wcid_to_sta(wcid);
if (status.sta)
status.rate = &wcid->rate;
}
hw = mt76_tx_status_get_hw(dev, skb);
ieee80211_tx_status_ext(hw, &status);
}
@ -88,8 +92,6 @@ __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags,
if ((flags & done) != done)
return;
__skb_unlink(skb, &dev->status_list);
/* Tx status can be unreliable. if it fails, mark the frame as ACKed */
if (flags & MT_TX_CB_TXS_FAILED) {
info->status.rates[0].count = 0;
@ -116,6 +118,8 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
int pid;
memset(cb, 0, sizeof(*cb));
if (!wcid)
return MT_PACKET_ID_NO_ACK;
@ -126,16 +130,23 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
IEEE80211_TX_CTL_RATE_CTRL_PROBE)))
return MT_PACKET_ID_NO_SKB;
spin_lock_bh(&dev->status_list.lock);
spin_lock_bh(&dev->status_lock);
pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST,
MT_PACKET_ID_MASK, GFP_ATOMIC);
if (pid < 0) {
pid = MT_PACKET_ID_NO_SKB;
goto out;
}
memset(cb, 0, sizeof(*cb));
pid = mt76_get_next_pkt_id(wcid);
cb->wcid = wcid->idx;
cb->pktid = pid;
cb->jiffies = jiffies;
__skb_queue_tail(&dev->status_list, skb);
spin_unlock_bh(&dev->status_list.lock);
if (list_empty(&wcid->list))
list_add_tail(&wcid->list, &dev->wcid_list);
out:
spin_unlock_bh(&dev->status_lock);
return pid;
}
@ -145,36 +156,53 @@ struct sk_buff *
mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid,
struct sk_buff_head *list)
{
struct sk_buff *skb, *tmp;
struct sk_buff *skb;
int id;
skb_queue_walk_safe(&dev->status_list, skb, tmp) {
lockdep_assert_held(&dev->status_lock);
skb = idr_remove(&wcid->pktid, pktid);
if (skb)
goto out;
/* look for stale entries in the wcid idr queue */
idr_for_each_entry(&wcid->pktid, skb, id) {
struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
if (wcid && cb->wcid != wcid->idx)
continue;
if (pktid >= 0) {
if (!(cb->flags & MT_TX_CB_DMA_DONE))
continue;
if (cb->pktid == pktid)
return skb;
if (pktid >= 0 && !time_after(jiffies, cb->jiffies +
MT_TX_STATUS_SKB_TIMEOUT))
continue;
if (!time_is_after_jiffies(cb->jiffies +
MT_TX_STATUS_SKB_TIMEOUT))
continue;
}
/* It has been too long since DMA_DONE, time out this packet
* and stop waiting for TXS callback.
*/
idr_remove(&wcid->pktid, cb->pktid);
__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED |
MT_TX_CB_TXS_DONE, list);
}
return NULL;
out:
if (idr_is_empty(&wcid->pktid))
list_del_init(&wcid->list);
return skb;
}
EXPORT_SYMBOL_GPL(mt76_tx_status_skb_get);
void
mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush)
mt76_tx_status_check(struct mt76_dev *dev, bool flush)
{
struct mt76_wcid *wcid, *tmp;
struct sk_buff_head list;
mt76_tx_status_lock(dev, &list);
mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list);
list_for_each_entry_safe(wcid, tmp, &dev->wcid_list, list)
mt76_tx_status_skb_get(dev, wcid, flush ? -1 : 0, &list);
mt76_tx_status_unlock(dev, &list);
}
EXPORT_SYMBOL_GPL(mt76_tx_status_check);
@ -197,6 +225,7 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid,
void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb,
struct list_head *free_list)
{
struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
struct ieee80211_tx_status status = {
.skb = skb,
.free_list = free_list,
@ -226,7 +255,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
}
#endif
if (!skb->prev) {
if (cb->pktid < MT_PACKET_ID_FIRST) {
hw = mt76_tx_status_get_hw(dev, skb);
status.sta = wcid_to_sta(wcid);
ieee80211_tx_status_ext(hw, &status);
@ -234,6 +263,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
}
mt76_tx_status_lock(dev, &list);
cb->jiffies = jiffies;
__mt76_tx_status_skb_done(dev, skb, MT_TX_CB_DMA_DONE, &list);
mt76_tx_status_unlock(dev, &list);

View File

@ -1081,7 +1081,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
mt76_worker_enable(&dev->usb.status_worker);
mt76_tx_status_check(dev, NULL, true);
mt76_tx_status_check(dev, true);
}
EXPORT_SYMBOL_GPL(mt76u_stop_tx);