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:
commit
9bc0b1aa8b
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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>");
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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--;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
@ -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))
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
@ -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
@ -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
|
||||
|
@ -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>");
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
348
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
Normal file
348
drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c
Normal 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;
|
||||
}
|
115
drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
Normal file
115
drivers/net/wireless/mediatek/mt76/mt7921/pci_mcu.c
Normal 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;
|
||||
}
|
@ -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)
|
||||
|
317
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
Normal file
317
drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
Normal 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");
|
220
drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
Normal file
220
drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
Normal 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;
|
||||
}
|
135
drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
Normal file
135
drivers/net/wireless/mediatek/mt76/mt7921/sdio_mcu.c
Normal 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;
|
||||
}
|
197
drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
Normal file
197
drivers/net/wireless/mediatek/mt76/mt7921/testmode.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
@ -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);
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user