aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c228
1 files changed, 194 insertions, 34 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 619561606f96..5c3a81e5f559 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req);
void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- bool enable)
+ bool enable, bool newly)
{
struct sta_rec_basic *basic;
struct tlv *tlv;
@@ -316,7 +316,8 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
basic->extra_info = cpu_to_le16(EXTRA_INFO_VER);
if (enable) {
- basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
+ if (newly)
+ basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
basic->conn_state = CONN_STATE_PORT_SECURE;
} else {
basic->conn_state = CONN_STATE_DISCONNECT;
@@ -393,6 +394,7 @@ mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif,
}
void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
+ struct ieee80211_vif *vif,
struct mt76_wcid *wcid,
void *sta_wtbl, void *wtbl_tlv)
{
@@ -404,9 +406,46 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
wtbl_tlv, sta_wtbl);
htr = (struct wtbl_hdr_trans *)tlv;
htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ htr->to_ds = true;
+ else
+ htr->from_ds = true;
+
+ if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
+ htr->to_ds = true;
+ htr->from_ds = true;
+ }
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv);
+int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev,
+ struct ieee80211_vif *vif,
+ struct mt76_wcid *wcid, int cmd)
+{
+ struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+
+ skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
+ sizeof(struct tlv));
+
+ wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET,
+ sta_wtbl, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, sta_wtbl, wtbl_hdr);
+
+ return mt76_mcu_skb_send_msg(dev, skb, cmd, true);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_update_hdr_trans);
+
void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev,
struct sk_buff *skb,
struct ieee80211_vif *vif,
@@ -671,7 +710,7 @@ mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif,
void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
struct ieee80211_sta *sta,
struct ieee80211_vif *vif,
- u8 rcpi)
+ u8 rcpi, u8 sta_state)
{
struct cfg80211_chan_def *chandef = &mphy->chandef;
enum nl80211_band band = chandef->chan->band;
@@ -736,7 +775,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb,
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));
state = (struct sta_rec_state *)tlv;
- state->state = 2;
+ state->state = sta_state;
if (sta->vht_cap.vht_supported) {
state->vht_opmode = sta->bandwidth;
@@ -828,8 +867,8 @@ void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv);
-int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
- struct mt76_sta_cmd_info *info)
+int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
+ struct mt76_sta_cmd_info *info)
{
struct mt76_vif *mvif = (struct mt76_vif *)info->vif->drv_priv;
struct mt76_dev *dev = phy->dev;
@@ -841,10 +880,13 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
if (IS_ERR(skb))
return PTR_ERR(skb);
- mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta, info->enable);
- if (info->enable && info->sta)
- mt76_connac_mcu_sta_tlv(phy, skb, info->sta, info->vif,
- info->rcpi);
+ if (info->sta || !info->offload_fw)
+ mt76_connac_mcu_sta_basic_tlv(skb, info->vif, info->sta,
+ info->enable, info->newly);
+ if (info->sta && info->enable)
+ mt76_connac_mcu_sta_tlv(phy, skb, info->sta,
+ info->vif, info->rcpi,
+ info->state);
sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
sizeof(struct tlv));
@@ -859,6 +901,8 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
mt76_connac_mcu_wtbl_generic_tlv(dev, skb, info->vif,
info->sta, sta_wtbl,
wtbl_hdr);
+ mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, info->vif, info->wcid,
+ sta_wtbl, wtbl_hdr);
if (info->sta)
mt76_connac_mcu_wtbl_ht_tlv(dev, skb, info->sta,
sta_wtbl, wtbl_hdr);
@@ -866,7 +910,7 @@ int mt76_connac_mcu_add_sta_cmd(struct mt76_phy *phy,
return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true);
}
-EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_sta_cmd);
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_cmd);
void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,
struct ieee80211_ampdu_params *params,
@@ -895,8 +939,10 @@ void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb,
ba->rst_ba_sb = 1;
}
- if (is_mt7921(dev))
+ if (is_mt7921(dev)) {
+ ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0;
return;
+ }
if (enable && tx) {
u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };
@@ -1271,6 +1317,7 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
u8 pad[3];
} __packed hdr;
struct bss_info_uni_he he;
+ struct bss_info_uni_bss_color bss_color;
} he_req = {
.hdr = {
.bss_idx = mvif->idx,
@@ -1279,8 +1326,21 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy,
.tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC),
.len = cpu_to_le16(sizeof(struct bss_info_uni_he)),
},
+ .bss_color = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_BSS_COLOR),
+ .len = cpu_to_le16(sizeof(struct bss_info_uni_bss_color)),
+ .enable = 0,
+ .bss_color = 0,
+ },
};
+ if (enable) {
+ he_req.bss_color.enable =
+ vif->bss_conf.he_bss_color.enabled;
+ he_req.bss_color.bss_color =
+ vif->bss_conf.he_bss_color.color;
+ }
+
mt76_connac_mcu_uni_bss_he_tlv(phy, vif,
(struct tlv *)&he_req.he);
err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD_BSS_INFO_UPDATE,
@@ -1463,14 +1523,16 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
req->version = 1;
req->seq_num = mvif->scan_seq_num | ext_phy << 7;
- if (is_mt7663(phy->dev) &&
- (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) {
- get_random_mask_addr(req->mt7663.random_mac, sreq->mac_addr,
- sreq->mac_addr_mask);
+ if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
+ u8 *addr = is_mt7663(phy->dev) ? req->mt7663.random_mac
+ : req->mt7921.random_mac;
+
req->scan_func = 1;
- } else if (is_mt7921(phy->dev)) {
- req->mt7921.bss_idx = mvif->idx;
+ get_random_mask_addr(addr, sreq->mac_addr,
+ sreq->mac_addr_mask);
}
+ if (is_mt7921(phy->dev))
+ req->mt7921.bss_idx = mvif->idx;
req->ssids_num = sreq->n_ssids;
for (i = 0; i < req->ssids_num; i++) {
@@ -1556,6 +1618,26 @@ int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);
+int mt76_connac_sta_state_dp(struct mt76_dev *dev,
+ enum ieee80211_sta_state old_state,
+ enum ieee80211_sta_state new_state)
+{
+ if ((old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTHORIZED) ||
+ (old_state == IEEE80211_STA_NONE &&
+ new_state == IEEE80211_STA_NOTEXIST))
+ mt76_connac_mcu_set_deep_sleep(dev, true);
+
+ if ((old_state == IEEE80211_STA_NOTEXIST &&
+ new_state == IEEE80211_STA_NONE) ||
+ (old_state == IEEE80211_STA_AUTHORIZED &&
+ new_state == IEEE80211_STA_ASSOC))
+ mt76_connac_mcu_set_deep_sleep(dev, false);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_sta_state_dp);
+
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump)
{
@@ -1570,6 +1652,60 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);
+int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy)
+{
+ struct mt76_connac_cap_hdr {
+ __le16 n_element;
+ u8 rsv[2];
+ } __packed * hdr;
+ struct sk_buff *skb;
+ int ret, i;
+
+ ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CMD_GET_NIC_CAPAB, NULL,
+ 0, true, &skb);
+ if (ret)
+ return ret;
+
+ hdr = (struct mt76_connac_cap_hdr *)skb->data;
+ if (skb->len < sizeof(*hdr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ skb_pull(skb, sizeof(*hdr));
+
+ for (i = 0; i < le16_to_cpu(hdr->n_element); i++) {
+ struct tlv_hdr {
+ __le32 type;
+ __le32 len;
+ } __packed * tlv = (struct tlv_hdr *)skb->data;
+ int len;
+
+ if (skb->len < sizeof(*tlv))
+ break;
+
+ skb_pull(skb, sizeof(*tlv));
+
+ len = le32_to_cpu(tlv->len);
+ if (skb->len < len)
+ break;
+
+ switch (le32_to_cpu(tlv->type)) {
+ case MT_NIC_CAP_6G:
+ phy->cap.has_6ghz = skb->data[0];
+ break;
+ default:
+ break;
+ }
+ skb_pull(skb, len);
+ }
+out:
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_get_nic_capability);
+
static void
mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
struct mt76_power_limits *limits,
@@ -1632,12 +1768,15 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
142, 144, 149, 151, 153, 155, 157,
159, 161, 165
};
+ int i, n_chan, batch_size, idx = 0, tx_power, last_ch;
struct mt76_connac_sku_tlv sku_tlbv;
- int i, n_chan, batch_size, idx = 0;
struct mt76_power_limits limits;
const u8 *ch_list;
sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
+ tx_power = 2 * phy->hw->conf.power_level;
+ if (!tx_power)
+ tx_power = 127;
if (band == NL80211_BAND_2GHZ) {
n_chan = ARRAY_SIZE(chan_list_2ghz);
@@ -1648,39 +1787,48 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
}
batch_size = DIV_ROUND_UP(n_chan, batch_len);
+ if (!phy->cap.has_5ghz)
+ last_ch = chan_list_2ghz[n_chan - 1];
+ else
+ last_ch = chan_list_5ghz[n_chan - 1];
+
for (i = 0; i < batch_size; i++) {
- bool last_msg = i == batch_size - 1;
- int num_ch = last_msg ? n_chan % batch_len : batch_len;
struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
.band = band == NL80211_BAND_2GHZ ? 1 : 2,
- .n_chan = num_ch,
- .last_msg = last_msg,
};
+ int j, err, msg_len, num_ch;
struct sk_buff *skb;
- int j, err, msg_len;
+ num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len;
msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);
skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);
if (!skb)
return -ENOMEM;
+ skb_reserve(skb, sizeof(tx_power_tlv));
+
BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));
memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));
+ tx_power_tlv.n_chan = num_ch;
- skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv));
for (j = 0; j < num_ch; j++, idx++) {
struct ieee80211_channel chan = {
.hw_value = ch_list[idx],
.band = band,
};
- mt76_get_rate_power_limits(phy, &chan, &limits, 127);
+ mt76_get_rate_power_limits(phy, &chan, &limits,
+ tx_power);
+ tx_power_tlv.last_msg = ch_list[idx] == last_ch;
sku_tlbv.channel = ch_list[idx];
+
mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,
&limits, band);
skb_put_data(skb, &sku_tlbv, sku_len);
}
+ __skb_push(skb, sizeof(tx_power_tlv));
+ memcpy(skb->data, &tx_power_tlv, sizeof(tx_power_tlv));
err = mt76_mcu_skb_send_msg(dev, skb,
MCU_CMD_SET_RATE_TX_POWER, false);
@@ -1695,11 +1843,20 @@ int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
{
int err;
- err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ);
- if (err < 0)
- return err;
+ if (phy->cap.has_2ghz) {
+ err = mt76_connac_mcu_rate_txpower_band(phy,
+ NL80211_BAND_2GHZ);
+ if (err < 0)
+ return err;
+ }
+ if (phy->cap.has_5ghz) {
+ err = mt76_connac_mcu_rate_txpower_band(phy,
+ NL80211_BAND_5GHZ);
+ if (err < 0)
+ return err;
+ }
- return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ);
+ return 0;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
@@ -1939,7 +2096,7 @@ mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev,
ptlv->index = index;
memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len);
- memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8);
+ memcpy(ptlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8));
return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_SUSPEND, true);
}
@@ -1974,14 +2131,17 @@ mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif,
};
if (wowlan->magic_pkt)
- req.wow_ctrl_tlv.trigger |= BIT(0);
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC;
if (wowlan->disconnect)
- req.wow_ctrl_tlv.trigger |= BIT(2);
+ req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT |
+ UNI_WOW_DETECT_TYPE_BCN_LOST);
if (wowlan->nd_config) {
mt76_connac_mcu_sched_scan_req(phy, vif, wowlan->nd_config);
- req.wow_ctrl_tlv.trigger |= BIT(5);
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT;
mt76_connac_mcu_sched_scan_enable(phy, vif, suspend);
}
+ if (wowlan->n_patterns)
+ req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_BITMAP;
if (mt76_is_mmio(dev))
req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;