diff --git a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h index 74038f0e7520..903053e7f6e8 100644 --- a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h +++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h @@ -1,61 +1,62 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2022-2023 Bjoern A. Zeeb * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H #define _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H struct mtk_wed_device { }; #define WED_WO_STA_REC 0x6 #define mtk_wed_device_start(_dev, _mask) do { } while(0) #define mtk_wed_device_detach(_dev) do { } while(0) #define mtk_wed_device_irq_get(_dev, _mask) 0 #define mtk_wed_device_irq_set_mask(_dev, _mask) do { } while(0) #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) (-ENODEV) #define mtk_wed_device_dma_reset(_dev) do {} while (0) #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _entry) \ do {} while (0) #define mtk_wed_device_stop(_dev) do { } while(0) #define mtk_wed_device_start_hw_rro(_dev, _mask, _b) do { } while(0) +#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _tdata) (-EOPNOTSUPP) static inline bool mtk_wed_device_active(struct mtk_wed_device *dev __unused) { return (false); } static inline bool mtk_wed_get_rx_capa(struct mtk_wed_device *dev __unused) { return (false); } #endif /* _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H */ diff --git a/sys/contrib/dev/mediatek/mt76/agg-rx.c b/sys/contrib/dev/mediatek/mt76/agg-rx.c index 10cbd9e560e7..07c386c7b4d0 100644 --- a/sys/contrib/dev/mediatek/mt76/agg-rx.c +++ b/sys/contrib/dev/mediatek/mt76/agg-rx.c @@ -1,301 +1,301 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Felix Fietkau */ #include "mt76.h" static unsigned long mt76_aggr_tid_to_timeo(u8 tidno) { /* Currently voice traffic (AC_VO) always runs without aggregation, * no special handling is needed. AC_BE/AC_BK use tids 0-3. Just check * for non AC_BK/AC_BE and set smaller timeout for it. */ return HZ / (tidno >= 4 ? 25 : 10); } static void mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx) { struct sk_buff *skb; tid->head = ieee80211_sn_inc(tid->head); skb = tid->reorder_buf[idx]; if (!skb) return; tid->reorder_buf[idx] = NULL; tid->nframes--; __skb_queue_tail(frames, skb); } static void mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, struct sk_buff_head *frames, u16 head) { int idx; while (ieee80211_sn_less(tid->head, head)) { idx = tid->head % tid->size; mt76_aggr_release(tid, frames, idx); } } static void mt76_rx_aggr_release_head(struct mt76_rx_tid *tid, struct sk_buff_head *frames) { int idx = tid->head % tid->size; while (tid->reorder_buf[idx]) { mt76_aggr_release(tid, frames, idx); idx = tid->head % tid->size; } } static void mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames) { struct mt76_rx_status *status; struct sk_buff *skb; int start, idx, nframes; if (!tid->nframes) return; mt76_rx_aggr_release_head(tid, frames); start = tid->head % tid->size; nframes = tid->nframes; for (idx = (tid->head + 1) % tid->size; idx != start && nframes; idx = (idx + 1) % tid->size) { skb = tid->reorder_buf[idx]; if (!skb) continue; nframes--; status = (struct mt76_rx_status *)skb->cb; if (!time_after32(jiffies, status->reorder_time + mt76_aggr_tid_to_timeo(tid->num))) continue; mt76_rx_aggr_release_frames(tid, frames, status->seqno); } mt76_rx_aggr_release_head(tid, frames); } static void mt76_rx_aggr_reorder_work(struct work_struct *work) { struct mt76_rx_tid *tid = container_of(work, struct mt76_rx_tid, reorder_work.work); struct mt76_dev *dev = tid->dev; struct sk_buff_head frames; int nframes; __skb_queue_head_init(&frames); local_bh_disable(); rcu_read_lock(); spin_lock(&tid->lock); mt76_rx_aggr_check_release(tid, &frames); nframes = tid->nframes; spin_unlock(&tid->lock); if (nframes) ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, mt76_aggr_tid_to_timeo(tid->num)); mt76_rx_complete(dev, &frames, NULL); rcu_read_unlock(); local_bh_enable(); } static void mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ieee80211_bar *bar = mt76_skb_get_hdr(skb); struct mt76_wcid *wcid = status->wcid; struct mt76_rx_tid *tid; - u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + u8 tidno; u16 seqno; if (!ieee80211_is_ctl(bar->frame_control)) return; if (!ieee80211_is_back_req(bar->frame_control)) return; status->qos_ctl = tidno = le16_to_cpu(bar->control) >> 12; seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); tid = rcu_dereference(wcid->aggr[tidno]); if (!tid) return; spin_lock_bh(&tid->lock); if (!tid->stopped) { mt76_rx_aggr_release_frames(tid, frames, seqno); mt76_rx_aggr_release_head(tid, frames); } spin_unlock_bh(&tid->lock); } void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; struct ieee80211_sta *sta; struct mt76_rx_tid *tid; bool sn_less; u16 seqno, head, size, idx; u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; u8 ackp; __skb_queue_tail(frames, skb); sta = wcid_to_sta(wcid); if (!sta) return; if (!status->aggr) { if (!(status->flag & RX_FLAG_8023)) mt76_rx_aggr_check_ctl(skb, frames); return; } /* not part of a BA session */ ackp = status->qos_ctl & IEEE80211_QOS_CTL_ACK_POLICY_MASK; if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK) return; tid = rcu_dereference(wcid->aggr[tidno]); if (!tid) return; status->flag |= RX_FLAG_DUP_VALIDATED; spin_lock_bh(&tid->lock); if (tid->stopped) goto out; head = tid->head; seqno = status->seqno; size = tid->size; sn_less = ieee80211_sn_less(seqno, head); if (!tid->started) { if (sn_less) goto out; tid->started = true; } if (sn_less) { __skb_unlink(skb, frames); dev_kfree_skb(skb); goto out; } if (seqno == head) { tid->head = ieee80211_sn_inc(head); if (tid->nframes) mt76_rx_aggr_release_head(tid, frames); goto out; } __skb_unlink(skb, frames); /* * Frame sequence number exceeds buffering window, free up some space * by releasing previous frames */ if (!ieee80211_sn_less(seqno, head + size)) { head = ieee80211_sn_inc(ieee80211_sn_sub(seqno, size)); mt76_rx_aggr_release_frames(tid, frames, head); } idx = seqno % size; /* Discard if the current slot is already in use */ if (tid->reorder_buf[idx]) { dev_kfree_skb(skb); goto out; } status->reorder_time = jiffies; tid->reorder_buf[idx] = skb; tid->nframes++; mt76_rx_aggr_release_head(tid, frames); ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, mt76_aggr_tid_to_timeo(tid->num)); out: spin_unlock_bh(&tid->lock); } int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno, u16 ssn, u16 size) { struct mt76_rx_tid *tid; mt76_rx_aggr_stop(dev, wcid, tidno); tid = kzalloc(struct_size(tid, reorder_buf, size), GFP_KERNEL); if (!tid) return -ENOMEM; tid->dev = dev; tid->head = ssn; tid->size = size; tid->num = tidno; INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work); spin_lock_init(&tid->lock); rcu_assign_pointer(wcid->aggr[tidno], tid); return 0; } EXPORT_SYMBOL_GPL(mt76_rx_aggr_start); static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) { u16 size = tid->size; int i; spin_lock_bh(&tid->lock); tid->stopped = true; for (i = 0; tid->nframes && i < size; i++) { struct sk_buff *skb = tid->reorder_buf[i]; if (!skb) continue; tid->reorder_buf[i] = NULL; tid->nframes--; dev_kfree_skb(skb); } spin_unlock_bh(&tid->lock); cancel_delayed_work_sync(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) { struct mt76_rx_tid *tid = NULL; tid = rcu_replace_pointer(wcid->aggr[tidno], tid, lockdep_is_held(&dev->mutex)); if (tid) { mt76_rx_aggr_shutdown(dev, tid); kfree_rcu(tid, rcu_head); } } EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); diff --git a/sys/contrib/dev/mediatek/mt76/channel.c b/sys/contrib/dev/mediatek/mt76/channel.c new file mode 100644 index 000000000000..6a35c6ebd823 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/channel.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2024 Felix Fietkau + */ +#include "mt76.h" + +static struct mt76_vif_link * +mt76_alloc_mlink(struct mt76_dev *dev, struct mt76_vif_data *mvif) +{ + struct mt76_vif_link *mlink; + + mlink = kzalloc(dev->drv->link_data_size, GFP_KERNEL); + if (!mlink) + return NULL; + + mlink->mvif = mvif; + + return mlink; +} + +static int +mt76_phy_update_channel(struct mt76_phy *phy, + struct ieee80211_chanctx_conf *conf) +{ + phy->radar_enabled = conf->radar_enabled; + phy->main_chandef = conf->def; + phy->chanctx = (struct mt76_chanctx *)conf->drv_priv; + + return __mt76_set_channel(phy, &phy->main_chandef, false); +} + +int mt76_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + int ret = -EINVAL; + + phy = ctx->phy = dev->band_phys[conf->def.chan->band]; + if (WARN_ON_ONCE(!phy)) + return ret; + + if (dev->scan.phy == phy) + mt76_abort_scan(dev); + + mutex_lock(&dev->mutex); + if (!phy->chanctx) + ret = mt76_phy_update_channel(phy, conf); + else + ret = 0; + mutex_unlock(&dev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_add_chanctx); + +void mt76_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + + phy = ctx->phy; + if (WARN_ON_ONCE(!phy)) + return; + + if (dev->scan.phy == phy) + mt76_abort_scan(dev); + + mutex_lock(&dev->mutex); + if (phy->chanctx == ctx) + phy->chanctx = NULL; + mutex_unlock(&dev->mutex); +} +EXPORT_SYMBOL_GPL(mt76_remove_chanctx); + +void mt76_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ + struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; + struct mt76_phy *phy = ctx->phy; + struct mt76_dev *dev = phy->dev; + + if (!(changed & (IEEE80211_CHANCTX_CHANGE_WIDTH | + IEEE80211_CHANCTX_CHANGE_RADAR))) + return; + + cancel_delayed_work_sync(&phy->mac_work); + + mutex_lock(&dev->mutex); + mt76_phy_update_channel(phy, conf); + mutex_unlock(&dev->mutex); +} +EXPORT_SYMBOL_GPL(mt76_change_chanctx); + + +int mt76_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf) +{ + struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + int link_id = link_conf->link_id; + struct mt76_phy *phy = ctx->phy; + struct mt76_dev *dev = phy->dev; + bool mlink_alloc = false; + int ret = 0; + + if (dev->scan.vif == vif) + mt76_abort_scan(dev); + + mutex_lock(&dev->mutex); + + if (vif->type == NL80211_IFTYPE_MONITOR && + is_zero_ether_addr(vif->addr)) + goto out; + + mlink = mt76_vif_conf_link(dev, vif, link_conf); + if (!mlink) { + mlink = mt76_alloc_mlink(dev, mvif); + if (!mlink) { + ret = -ENOMEM; + goto out; + } + mlink_alloc = true; + } + + mlink->ctx = conf; + ret = dev->drv->vif_link_add(phy, vif, link_conf, mlink); + if (ret) { + if (mlink_alloc) + kfree(mlink); + goto out; + } + + if (link_conf != &vif->bss_conf) + rcu_assign_pointer(mvif->link[link_id], mlink); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_assign_vif_chanctx); + +void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf) +{ + struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + int link_id = link_conf->link_id; + struct mt76_phy *phy = ctx->phy; + struct mt76_dev *dev = phy->dev; + + if (dev->scan.vif == vif) + mt76_abort_scan(dev); + + mutex_lock(&dev->mutex); + + if (vif->type == NL80211_IFTYPE_MONITOR && + is_zero_ether_addr(vif->addr)) + goto out; + + mlink = mt76_vif_conf_link(dev, vif, link_conf); + if (!mlink) + goto out; + + if (link_conf != &vif->bss_conf) + rcu_assign_pointer(mvif->link[link_id], NULL); + + dev->drv->vif_link_remove(phy, vif, link_conf, mlink); + mlink->ctx = NULL; + + if (link_conf != &vif->bss_conf) + kfree_rcu(mlink, rcu_head); + +out: + mutex_unlock(&dev->mutex); +} +EXPORT_SYMBOL_GPL(mt76_unassign_vif_chanctx); + +int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv; + struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv; + struct ieee80211_chanctx_conf *conf = vifs->new_ctx; + struct mt76_phy *old_phy = old_ctx->phy; + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_vif_link *mlink; + bool update_chan; + int i, ret = 0; + + if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) + phy = new_ctx->phy = dev->band_phys[conf->def.chan->band]; + else + phy = new_ctx->phy; + if (!phy) + return -EINVAL; + + update_chan = phy->chanctx != new_ctx; + if (update_chan) { + if (dev->scan.phy == phy) + mt76_abort_scan(dev); + + cancel_delayed_work_sync(&phy->mac_work); + } + + mutex_lock(&dev->mutex); + + if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && + phy != old_phy && old_phy->chanctx == old_ctx) + old_phy->chanctx = NULL; + + if (update_chan) + ret = mt76_phy_update_channel(phy, vifs->new_ctx); + + if (ret) + goto out; + + if (old_phy == phy) + goto skip_link_replace; + + for (i = 0; i < n_vifs; i++) { + mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf); + if (!mlink) + continue; + + dev->drv->vif_link_remove(old_phy, vifs[i].vif, + vifs[i].link_conf, mlink); + + ret = dev->drv->vif_link_add(phy, vifs[i].vif, + vifs[i].link_conf, mlink); + if (ret) + goto out; + + } + +skip_link_replace: + for (i = 0; i < n_vifs; i++) { + mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf); + if (!mlink) + continue; + + mlink->ctx = vifs->new_ctx; + } + +out: + mutex_unlock(&dev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_switch_vif_chanctx); + +struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, + struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + struct mt76_dev *dev = phy->dev; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(mvif->link); i++) { + mlink = mt76_dereference(mvif->link[i], dev); + if (!mlink) + continue; + + if (mt76_vif_link_phy(mlink) == phy) + return mlink; + } + + if (!dev->drv->vif_link_add) + return ERR_PTR(-EINVAL); + + mlink = mt76_alloc_mlink(dev, mvif); + if (!mlink) + return ERR_PTR(-ENOMEM); + + mlink->offchannel = true; + ret = dev->drv->vif_link_add(phy, vif, &vif->bss_conf, mlink); + if (ret) { + kfree(mlink); + return ERR_PTR(ret); + } + + return mlink; +} + +void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct mt76_vif_link *mlink) +{ + struct mt76_dev *dev = phy->dev; + + if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel) + return; + + dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink); + kfree(mlink); +} + +static void mt76_roc_complete(struct mt76_phy *phy) +{ + struct mt76_vif_link *mlink = phy->roc_link; + + if (!phy->roc_vif) + return; + + if (mlink) + mlink->mvif->roc_phy = NULL; + if (phy->main_chandef.chan) + mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); + phy->roc_vif = NULL; + phy->roc_link = NULL; + ieee80211_remain_on_channel_expired(phy->hw); +} + +void mt76_roc_complete_work(struct work_struct *work) +{ + struct mt76_phy *phy = container_of(work, struct mt76_phy, roc_work.work); + struct mt76_dev *dev = phy->dev; + + mutex_lock(&dev->mutex); + mt76_roc_complete(phy); + mutex_unlock(&dev->mutex); +} + +void mt76_abort_roc(struct mt76_phy *phy) +{ + struct mt76_dev *dev = phy->dev; + + cancel_delayed_work_sync(&phy->roc_work); + + mutex_lock(&dev->mutex); + mt76_roc_complete(phy); + mutex_unlock(&dev->mutex); +} + +int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type) +{ + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_vif_link *mlink; + int ret = 0; + + phy = dev->band_phys[chan->band]; + if (!phy) + return -EINVAL; + + mutex_lock(&dev->mutex); + + if (phy->roc_vif || dev->scan.phy == phy) { + ret = -EBUSY; + goto out; + } + + mlink = mt76_get_vif_phy_link(phy, vif); + if (IS_ERR(mlink)) { + ret = PTR_ERR(mlink); + goto out; + } + + mlink->mvif->roc_phy = phy; + phy->roc_vif = vif; + phy->roc_link = mlink; + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + mt76_set_channel(phy, &chandef, true); + ieee80211_ready_on_channel(hw); + ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, + msecs_to_jiffies(duration)); + +out: + mutex_unlock(&dev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(mt76_remain_on_channel); + +int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + struct mt76_phy *phy = mvif->roc_phy; + + if (!phy) + return 0; + + mt76_abort_roc(phy); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_cancel_remain_on_channel); diff --git a/sys/contrib/dev/mediatek/mt76/debugfs.c b/sys/contrib/dev/mediatek/mt76/debugfs.c index 57fbcc83e074..b6a2746c187d 100644 --- a/sys/contrib/dev/mediatek/mt76/debugfs.c +++ b/sys/contrib/dev/mediatek/mt76/debugfs.c @@ -1,128 +1,126 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include "mt76.h" static int mt76_reg_set(void *data, u64 val) { struct mt76_dev *dev = data; __mt76_wr(dev, dev->debugfs_reg, val); return 0; } static int mt76_reg_get(void *data, u64 *val) { struct mt76_dev *dev = data; *val = __mt76_rr(dev, dev->debugfs_reg); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); static int mt76_napi_threaded_set(void *data, u64 val) { struct mt76_dev *dev = data; if (!mt76_is_mmio(dev)) return -EOPNOTSUPP; - if (dev->napi_dev.threaded != val) - return dev_set_threaded(&dev->napi_dev, val); + if (dev->napi_dev->threaded != val) + return dev_set_threaded(dev->napi_dev, val); return 0; } static int mt76_napi_threaded_get(void *data, u64 *val) { struct mt76_dev *dev = data; - *val = dev->napi_dev.threaded; + *val = dev->napi_dev->threaded; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_napi_threaded, mt76_napi_threaded_get, mt76_napi_threaded_set, "%llu\n"); 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, " %9d | %9d | %9d | %9d |\n", i, q->queued, q->head, q->tail); } return 0; } EXPORT_SYMBOL_GPL(mt76_queues_read); 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, " %9d | %9d | %9d | %9d |\n", i, queued, q->head, q->tail); } return 0; } void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) { int i; seq_printf(file, "%10s:", str); for (i = 0; i < len; i++) seq_printf(file, " %2d", val[i]); seq_puts(file, "\n"); } EXPORT_SYMBOL_GPL(mt76_seq_puts_array); 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", phy->hw->wiphy->debugfsdir); - if (!dir) - return NULL; debugfs_create_u8("led_pin", 0600, dir, &phy->leds.pin); debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); 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); if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir, mt76_rx_queues_read); return dir; } EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops); diff --git a/sys/contrib/dev/mediatek/mt76/dma.c b/sys/contrib/dev/mediatek/mt76/dma.c index eaa793e4b18e..6765e1281ac3 100644 --- a/sys/contrib/dev/mediatek/mt76/dma.c +++ b/sys/contrib/dev/mediatek/mt76/dma.c @@ -1,1004 +1,1066 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #if defined(__FreeBSD__) #include #include #endif #include "mt76.h" #include "dma.h" #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) -#define Q_READ(_dev, _q, _field) ({ \ +#define Q_READ(_q, _field) ({ \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ u32 _val; \ if ((_q)->flags & MT_QFLAG_WED) \ - _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \ + _val = mtk_wed_device_reg_read((_q)->wed, \ ((_q)->wed_regs + \ _offset)); \ else \ _val = readl(&(_q)->regs->_field); \ _val; \ }) -#define Q_WRITE(_dev, _q, _field, _val) do { \ +#define Q_WRITE(_q, _field, _val) do { \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ if ((_q)->flags & MT_QFLAG_WED) \ - mtk_wed_device_reg_write(&(_dev)->mmio.wed, \ + mtk_wed_device_reg_write((_q)->wed, \ ((_q)->wed_regs + _offset), \ _val); \ else \ writel(_val, &(_q)->regs->_field); \ } while (0) #else -#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field) -#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field) +#define Q_READ(_q, _field) readl(&(_q)->regs->_field) +#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) #endif static struct mt76_txwi_cache * mt76_alloc_txwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t; dma_addr_t addr; u8 *txwi; int size; size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t)); txwi = kzalloc(size, GFP_ATOMIC); if (!txwi) return NULL; addr = dma_map_single(dev->dma_dev, txwi, dev->drv->txwi_size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev->dma_dev, addr))) { + kfree(txwi); + return NULL; + } + t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size); t->dma_addr = addr; return t; } static struct mt76_txwi_cache * mt76_alloc_rxwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t; t = kzalloc(L1_CACHE_ALIGN(sizeof(*t)), GFP_ATOMIC); if (!t) return NULL; t->ptr = NULL; return t; } static struct mt76_txwi_cache * __mt76_get_txwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t = NULL; spin_lock(&dev->lock); if (!list_empty(&dev->txwi_cache)) { t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache, list); list_del(&t->list); } spin_unlock(&dev->lock); return t; } static struct mt76_txwi_cache * __mt76_get_rxwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t = NULL; - spin_lock(&dev->wed_lock); + spin_lock_bh(&dev->wed_lock); if (!list_empty(&dev->rxwi_cache)) { t = list_first_entry(&dev->rxwi_cache, struct mt76_txwi_cache, list); list_del(&t->list); } - spin_unlock(&dev->wed_lock); + spin_unlock_bh(&dev->wed_lock); return t; } static struct mt76_txwi_cache * mt76_get_txwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t = __mt76_get_txwi(dev); if (t) return t; return mt76_alloc_txwi(dev); } struct mt76_txwi_cache * mt76_get_rxwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t = __mt76_get_rxwi(dev); if (t) return t; return mt76_alloc_rxwi(dev); } EXPORT_SYMBOL_GPL(mt76_get_rxwi); void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t) { if (!t) return; spin_lock(&dev->lock); list_add(&t->list, &dev->txwi_cache); spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(mt76_put_txwi); void mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t) { if (!t) return; - spin_lock(&dev->wed_lock); + spin_lock_bh(&dev->wed_lock); list_add(&t->list, &dev->rxwi_cache); - spin_unlock(&dev->wed_lock); + spin_unlock_bh(&dev->wed_lock); } EXPORT_SYMBOL_GPL(mt76_put_rxwi); static void mt76_free_pending_txwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t; local_bh_disable(); while ((t = __mt76_get_txwi(dev)) != NULL) { dma_unmap_single(dev->dma_dev, t->dma_addr, dev->drv->txwi_size, DMA_TO_DEVICE); kfree(mt76_get_txwi_ptr(dev, t)); } local_bh_enable(); } void mt76_free_pending_rxwi(struct mt76_dev *dev) { struct mt76_txwi_cache *t; local_bh_disable(); while ((t = __mt76_get_rxwi(dev)) != NULL) { if (t->ptr) mt76_put_page_pool_buf(t->ptr, false); kfree(t); } local_bh_enable(); } EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { - Q_WRITE(dev, q, desc_base, q->desc_dma); - Q_WRITE(dev, q, ring_size, q->ndesc); - q->head = Q_READ(dev, q, dma_idx); + Q_WRITE(q, desc_base, q->desc_dma); + if (q->flags & MT_QFLAG_WED_RRO_EN) + Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); + else + Q_WRITE(q, ring_size, q->ndesc); + q->head = Q_READ(q, dma_idx); q->tail = q->head; } -static void -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { - int i; - if (!q || !q->ndesc) return; - /* clear descriptors */ - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + /* clear descriptors */ + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } - Q_WRITE(dev, q, cpu_idx, 0); - Q_WRITE(dev, q, dma_idx, 0); + if (reset_idx) { + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); + } mt76_dma_sync_idx(dev, q); } +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +{ + __mt76_dma_queue_reset(dev, q, true); +} + static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) { - struct mt76_desc *desc = &q->desc[q->head]; struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; - u32 buf1 = 0, ctrl; + struct mt76_desc *desc; int idx = q->head; + u32 buf1 = 0, ctrl; int rx_token; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + data = &rro_desc[q->head]; + goto done; + } + + desc = &q->desc[q->head]; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32); +#endif if (mt76_queue_is_wed_rx(q)) { txwi = mt76_get_rxwi(dev); if (!txwi) return -ENOMEM; rx_token = mt76_rx_token_consume(dev, data, txwi, buf->addr); if (rx_token < 0) { mt76_put_rxwi(dev, txwi); return -ENOMEM; } buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token); ctrl |= MT_DMA_CTL_TO_HOST; } WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr)); WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); WRITE_ONCE(desc->info, 0); +done: entry->dma_addr[0] = buf->addr; entry->dma_len[0] = buf->len; entry->txwi = txwi; entry->buf = data; entry->wcid = 0xffff; entry->skip_buf1 = true; q->head = (q->head + 1) % q->ndesc; q->queued++; return idx; } static int mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, int nbufs, u32 info, struct sk_buff *skb, void *txwi) { struct mt76_queue_entry *entry; struct mt76_desc *desc; int i, idx = -1; u32 ctrl, next; if (txwi) { q->entry[q->head].txwi = DMA_DUMMY_DATA; q->entry[q->head].skip_buf0 = true; } for (i = 0; i < nbufs; i += 2, buf += 2) { u32 buf0 = buf[0].addr, buf1 = 0; idx = q->head; next = (q->head + 1) % q->ndesc; desc = &q->desc[idx]; entry = &q->entry[idx]; if (buf[0].skip_unmap) entry->skip_buf0 = true; entry->skip_buf1 = i == nbufs - 1; entry->dma_addr[0] = buf[0].addr; entry->dma_len[0] = buf[0].len; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32); +#endif if (i < nbufs - 1) { entry->dma_addr[1] = buf[1].addr; entry->dma_len[1] = buf[1].len; buf1 = buf[1].addr; ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP1_H, + buf[1].addr >> 32); +#endif if (buf[1].skip_unmap) entry->skip_buf1 = true; } if (i == nbufs - 1) ctrl |= MT_DMA_CTL_LAST_SEC0; else if (i == nbufs - 2) ctrl |= MT_DMA_CTL_LAST_SEC1; WRITE_ONCE(desc->buf0, cpu_to_le32(buf0)); WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); WRITE_ONCE(desc->info, cpu_to_le32(info)); WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); q->head = next; q->queued++; } q->entry[idx].txwi = txwi; q->entry[idx].skb = skb; q->entry[idx].wcid = 0xffff; return idx; } static void mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx, struct mt76_queue_entry *prev_e) { struct mt76_queue_entry *e = &q->entry[idx]; if (!e->skip_buf0) dma_unmap_single(dev->dma_dev, e->dma_addr[0], e->dma_len[0], DMA_TO_DEVICE); if (!e->skip_buf1) dma_unmap_single(dev->dma_dev, e->dma_addr[1], e->dma_len[1], DMA_TO_DEVICE); if (e->txwi == DMA_DUMMY_DATA) e->txwi = NULL; - if (e->skb == DMA_DUMMY_DATA) - e->skb = NULL; - *prev_e = *e; memset(e, 0, sizeof(*e)); } static void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) { wmb(); - Q_WRITE(dev, q, cpu_idx, q->head); + Q_WRITE(q, cpu_idx, q->head); } static void mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) { struct mt76_queue_entry entry; int last; if (!q || !q->ndesc) return; spin_lock_bh(&q->cleanup_lock); if (flush) last = -1; else - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); mt76_queue_tx_complete(dev, q, &entry); if (entry.txwi) { if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE)) mt76_put_txwi(dev, entry.txwi); } if (!flush && q->tail == last) - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); } spin_unlock_bh(&q->cleanup_lock); if (flush) { spin_lock_bh(&q->lock); mt76_dma_sync_idx(dev, q); mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); } if (!q->queued) wake_up(&dev->tx_wait); } static void * mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, int *len, u32 *info, bool *more, bool *drop) { struct mt76_queue_entry *e = &q->entry[idx]; struct mt76_desc *desc = &q->desc[idx]; - void *buf; + u32 ctrl, desc_info, buf1; + void *buf = e->buf; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; + ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); if (len) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); *more = !(ctrl & MT_DMA_CTL_LAST_SEC0); } + desc_info = le32_to_cpu(desc->info); if (info) - *info = le32_to_cpu(desc->info); + *info = desc_info; + + buf1 = le32_to_cpu(desc->buf1); + mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info); if (mt76_queue_is_wed_rx(q)) { - u32 buf1 = le32_to_cpu(desc->buf1); u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1); struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token); if (!t) return NULL; dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, SKB_WITH_OVERHEAD(q->buf_size), page_pool_get_dma_dir(q->page_pool)); buf = t->ptr; t->dma_addr = 0; t->ptr = NULL; mt76_put_rxwi(dev, t); - - if (drop) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); - - *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | - MT_DMA_CTL_DROP)); - + if (drop) *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); - } } else { - buf = e->buf; - e->buf = NULL; dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size), page_pool_get_dma_dir(q->page_pool)); } +done: + e->buf = NULL; return buf; } static void * mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, int *len, u32 *info, bool *more, bool *drop) { int idx = q->tail; *more = false; if (!q->queued) return NULL; - if (flush) - q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); - else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + if (mt76_queue_is_wed_rro_data(q)) return NULL; + if (!mt76_queue_is_wed_rro_ind(q)) { + if (flush) + q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); + else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + return NULL; + } + q->tail = (q->tail + 1) % q->ndesc; q->queued--; return mt76_dma_get_buf(dev, q, idx, len, info, more, drop); } static int mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, u32 tx_info) { struct mt76_queue_buf buf = {}; dma_addr_t addr; if (test_bit(MT76_MCU_RESET, &dev->phy.state)) goto error; if (q->queued + 1 >= q->ndesc - 1) goto error; addr = dma_map_single(dev->dma_dev, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev->dma_dev, addr))) goto error; buf.addr = addr; buf.len = skb->len; spin_lock_bh(&q->lock); mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); return 0; error: dev_kfree_skb(skb); return -ENOMEM; } static int -mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, +mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct ieee80211_tx_status status = { .sta = sta, }; struct mt76_tx_info tx_info = { .skb = skb, }; + struct mt76_dev *dev = phy->dev; struct ieee80211_hw *hw; int len, n = 0, ret = -ENOMEM; struct mt76_txwi_cache *t; struct sk_buff *iter; dma_addr_t addr; u8 *txwi; - if (test_bit(MT76_RESET, &dev->phy.state)) + if (test_bit(MT76_RESET, &phy->state)) goto free_skb; t = mt76_get_txwi(dev); if (!t) goto free_skb; txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS) mt76_insert_hdr_pad(skb); len = skb_headlen(skb); addr = dma_map_single(dev->dma_dev, skb->data, len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev->dma_dev, addr))) goto free; tx_info.buf[n].addr = t->dma_addr; tx_info.buf[n++].len = dev->drv->txwi_size; tx_info.buf[n].addr = addr; tx_info.buf[n++].len = len; skb_walk_frags(skb, iter) { if (n == ARRAY_SIZE(tx_info.buf)) goto unmap; addr = dma_map_single(dev->dma_dev, iter->data, iter->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev->dma_dev, addr))) goto unmap; tx_info.buf[n].addr = addr; tx_info.buf[n++].len = iter->len; } tx_info.nbuf = n; if (q->queued + (tx_info.nbuf + 1) / 2 >= q->ndesc - 1) { ret = -ENOMEM; goto unmap; } dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, dev->drv->txwi_size, DMA_TO_DEVICE); ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info); dma_sync_single_for_device(dev->dma_dev, t->dma_addr, dev->drv->txwi_size, DMA_TO_DEVICE); if (ret < 0) goto unmap; return mt76_dma_add_buf(dev, q, tx_info.buf, tx_info.nbuf, tx_info.info, tx_info.skb, t); unmap: for (n--; n > 0; n--) dma_unmap_single(dev->dma_dev, tx_info.buf[n].addr, tx_info.buf[n].len, DMA_TO_DEVICE); free: #ifdef CONFIG_NL80211_TESTMODE /* fix tx_done accounting on queue overflow */ if (mt76_is_testmode_skb(dev, skb, &hw)) { struct mt76_phy *phy = hw->priv; if (tx_info.skb == phy->test.tx_skb) phy->test.tx_done--; } #endif mt76_put_txwi(dev, t); free_skb: status.skb = tx_info.skb; hw = mt76_tx_status_get_hw(dev, tx_info.skb); spin_lock_bh(&dev->rx_lock); ieee80211_tx_status_ext(hw, &status); spin_unlock_bh(&dev->rx_lock); return ret; } static int -mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, - bool allow_direct) +mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q, + bool allow_direct) { int len = SKB_WITH_OVERHEAD(q->buf_size); int frames = 0; if (!q->ndesc) return 0; - spin_lock_bh(&q->lock); - while (q->queued < q->ndesc - 1) { + struct mt76_queue_buf qbuf = {}; enum dma_data_direction dir; - struct mt76_queue_buf qbuf; dma_addr_t addr; int offset; - void *buf; + void *buf = NULL; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); if (!buf) break; addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; dir = page_pool_get_dma_dir(q->page_pool); dma_sync_single_for_device(dev->dma_dev, addr, len, dir); qbuf.addr = addr + q->buf_offset; +done: qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false; if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { mt76_put_page_pool_buf(buf, allow_direct); break; } frames++; } - if (frames) + if (frames || mt76_queue_is_wed_rx(q)) mt76_dma_kick_queue(dev, q); - spin_unlock_bh(&q->lock); - return frames; } -int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) +int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, + bool allow_direct) { -#ifdef CONFIG_NET_MEDIATEK_SOC_WED - struct mtk_wed_device *wed = &dev->mmio.wed; - int ret, type, ring; - u8 flags; + int frames; - if (!q || !q->ndesc) - return -EINVAL; - - flags = q->flags; - if (!mtk_wed_device_active(wed)) - q->flags &= ~MT_QFLAG_WED; - - if (!(q->flags & MT_QFLAG_WED)) + if (!q->ndesc) return 0; - type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags); - ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags); - - switch (type) { - case MT76_WED_Q_TX: - ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset); - if (!ret) - q->wed_regs = wed->tx_ring[ring].reg_base; - break; - case MT76_WED_Q_TXFREE: - /* WED txfree queue needs ring to be initialized before setup */ - q->flags = 0; - mt76_dma_queue_reset(dev, q); - mt76_dma_rx_fill(dev, q, false); - q->flags = flags; - - ret = mtk_wed_device_txfree_ring_setup(wed, q->regs); - if (!ret) - q->wed_regs = wed->txfree_ring.reg_base; - break; - case MT76_WED_Q_RX: - ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset); - if (!ret) - q->wed_regs = wed->rx_ring[ring].reg_base; - break; - default: - ret = -EINVAL; - } + spin_lock_bh(&q->lock); + frames = mt76_dma_rx_fill_buf(dev, q, allow_direct); + spin_unlock_bh(&q->lock); - return ret; -#else - return 0; -#endif + return frames; } -EXPORT_SYMBOL_GPL(mt76_dma_wed_setup); static int mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize, u32 ring_base) { int ret, size; spin_lock_init(&q->lock); spin_lock_init(&q->cleanup_lock); #if defined(__linux__) q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE; #elif defined(__FreeBSD__) q->regs = (void *)((u8 *)dev->mmio.regs + ring_base + idx * MT_RING_SIZE); #endif q->ndesc = n_desc; q->buf_size = bufsize; q->hw_idx = idx; - size = q->ndesc * sizeof(struct mt76_desc); - q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL); + size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) + : sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, + &q->desc_dma, GFP_KERNEL); if (!q->desc) return -ENOMEM; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + int i; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + for (i = 0; i < q->ndesc; i++) { + struct mt76_wed_rro_ind *cmd; + + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; + cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; + } + } + size = q->ndesc * sizeof(*q->entry); q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (!q->entry) return -ENOMEM; ret = mt76_create_page_pool(dev, q); if (ret) return ret; - ret = mt76_dma_wed_setup(dev, q, false); + ret = mt76_wed_dma_setup(dev, q, false); if (ret) return ret; - if (q->flags != MT_WED_Q_TXFREE) - mt76_dma_queue_reset(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) { + if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) || + mt76_queue_is_wed_tx_free(q)) + return 0; + } + + mt76_dma_queue_reset(dev, q); return 0; } static void mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) { void *buf; bool more; if (!q->ndesc) return; - spin_lock_bh(&q->lock); - do { + spin_lock_bh(&q->lock); buf = mt76_dma_dequeue(dev, q, true, NULL, NULL, &more, NULL); + spin_unlock_bh(&q->lock); + if (!buf) break; - mt76_put_page_pool_buf(buf, false); + if (!mt76_queue_is_wed_rro(q)) + mt76_put_page_pool_buf(buf, false); } while (1); + spin_lock_bh(&q->lock); if (q->rx_head) { dev_kfree_skb(q->rx_head); q->rx_head = NULL; } spin_unlock_bh(&q->lock); } static void mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; - int i; if (!q->ndesc) return; - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } mt76_dma_rx_cleanup(dev, q); /* reset WED rx queues */ - mt76_dma_wed_setup(dev, q, true); - if (q->flags != MT_WED_Q_TXFREE) { - mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill(dev, q, false); - } + mt76_wed_dma_setup(dev, q, true); + + if (mt76_queue_is_wed_tx_free(q)) + return; + + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + return; + + mt76_dma_sync_idx(dev, q); + mt76_dma_rx_fill_buf(dev, q, false); } static void mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data, - int len, bool more, u32 info) + int len, bool more, u32 info, bool allow_direct) { struct sk_buff *skb = q->rx_head; struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; if (nr_frags < ARRAY_SIZE(shinfo->frags)) { struct page *page = virt_to_head_page(data); #if defined(__linux__) int offset = data - page_address(page) + q->buf_offset; #elif defined(__FreeBSD__) int offset = (u8 *)data - (u8 *)page_address(page) + q->buf_offset; #endif skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size); } else { - mt76_put_page_pool_buf(data, true); + mt76_put_page_pool_buf(data, allow_direct); } if (more) return; q->rx_head = NULL; if (nr_frags < ARRAY_SIZE(shinfo->frags)) dev->drv->rx_skb(dev, q - dev->q_rx, skb, &info); else dev_kfree_skb(skb); } static int mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) { int len, data_len, done = 0, dma_idx; struct sk_buff *skb; unsigned char *data; bool check_ddone = false; + bool allow_direct = !mt76_queue_is_wed_rx(q); bool more; if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && - q->flags == MT_WED_Q_TXFREE) { - dma_idx = Q_READ(dev, q, dma_idx); + mt76_queue_is_wed_tx_free(q)) { + dma_idx = Q_READ(q, dma_idx); check_ddone = true; } while (done < budget) { bool drop = false; u32 info; if (check_ddone) { if (q->tail == dma_idx) - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); if (q->tail == dma_idx) break; } data = mt76_dma_dequeue(dev, q, false, &len, &info, &more, &drop); if (!data) break; if (drop) goto free_frag; if (q->rx_head) data_len = q->buf_size; else data_len = SKB_WITH_OVERHEAD(q->buf_size); if (data_len < len + q->buf_offset) { dev_kfree_skb(q->rx_head); q->rx_head = NULL; goto free_frag; } if (q->rx_head) { - mt76_add_fragment(dev, q, data, len, more, info); + mt76_add_fragment(dev, q, data, len, more, info, + allow_direct); continue; } if (!more && dev->drv->rx_check && !(dev->drv->rx_check(dev, data, len))) goto free_frag; skb = napi_build_skb(data, q->buf_size); if (!skb) goto free_frag; skb_reserve(skb, q->buf_offset); skb_mark_for_recycle(skb); *(u32 *)skb->cb = info; __skb_put(skb, len); done++; if (more) { q->rx_head = skb; continue; } dev->drv->rx_skb(dev, q - dev->q_rx, skb, &info); continue; free_frag: - mt76_put_page_pool_buf(data, true); + mt76_put_page_pool_buf(data, allow_direct); } mt76_dma_rx_fill(dev, q, true); return done; } int mt76_dma_rx_poll(struct napi_struct *napi, int budget) { struct mt76_dev *dev; int qid, done = 0, cur; - dev = container_of(napi->dev, struct mt76_dev, napi_dev); + dev = mt76_priv(napi->dev); qid = napi - dev->napi; rcu_read_lock(); do { cur = mt76_dma_rx_process(dev, &dev->q_rx[qid], budget - done); mt76_rx_poll_complete(dev, qid, napi); done += cur; } while (cur && done < budget); rcu_read_unlock(); if (done < budget && napi_complete(napi)) dev->drv->rx_poll_complete(dev, qid); return done; } EXPORT_SYMBOL_GPL(mt76_dma_rx_poll); static int mt76_dma_init(struct mt76_dev *dev, int (*poll)(struct napi_struct *napi, int budget)) { + struct mt76_dev **priv; int i; - init_dummy_netdev(&dev->napi_dev); - init_dummy_netdev(&dev->tx_napi_dev); - snprintf(dev->napi_dev.name, sizeof(dev->napi_dev.name), "%s", + dev->napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *)); + if (!dev->napi_dev) + return -ENOMEM; + + /* napi_dev private data points to mt76_dev parent, so, mt76_dev + * can be retrieved given napi_dev + */ + priv = netdev_priv(dev->napi_dev); + *priv = dev; + + dev->tx_napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *)); + if (!dev->tx_napi_dev) { + free_netdev(dev->napi_dev); + return -ENOMEM; + } + priv = netdev_priv(dev->tx_napi_dev); + *priv = dev; + + snprintf(dev->napi_dev->name, sizeof(dev->napi_dev->name), "%s", wiphy_name(dev->hw->wiphy)); - dev->napi_dev.threaded = 1; + dev->napi_dev->threaded = 1; init_completion(&dev->mmio.wed_reset); init_completion(&dev->mmio.wed_reset_complete); mt76_for_each_q_rx(dev, i) { - netif_napi_add(&dev->napi_dev, &dev->napi[i], poll); - mt76_dma_rx_fill(dev, &dev->q_rx[i], false); + netif_napi_add(dev->napi_dev, &dev->napi[i], poll); + mt76_dma_rx_fill_buf(dev, &dev->q_rx[i], false); napi_enable(&dev->napi[i]); } return 0; } static const struct mt76_queue_ops mt76_dma_ops = { .init = mt76_dma_init, .alloc = mt76_dma_alloc_queue, .reset_q = mt76_dma_queue_reset, .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, .tx_queue_skb = mt76_dma_tx_queue_skb, .tx_cleanup = mt76_dma_tx_cleanup, .rx_cleanup = mt76_dma_rx_cleanup, .rx_reset = mt76_dma_rx_reset, .kick = mt76_dma_kick_queue, }; void mt76_dma_attach(struct mt76_dev *dev) { dev->queue_ops = &mt76_dma_ops; } EXPORT_SYMBOL_GPL(mt76_dma_attach); void mt76_dma_cleanup(struct mt76_dev *dev) { int i; mt76_worker_disable(&dev->tx_worker); netif_napi_del(&dev->tx_napi); for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { struct mt76_phy *phy = dev->phys[i]; int j; if (!phy) continue; for (j = 0; j < ARRAY_SIZE(phy->q_tx); j++) mt76_dma_tx_cleanup(dev, phy->q_tx[j], true); } for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++) mt76_dma_tx_cleanup(dev, dev->q_mcu[i], true); mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + continue; + netif_napi_del(&dev->napi[i]); mt76_dma_rx_cleanup(dev, q); page_pool_destroy(q->page_pool); } - mt76_free_pending_txwi(dev); - mt76_free_pending_rxwi(dev); - if (mtk_wed_device_active(&dev->mmio.wed)) mtk_wed_device_detach(&dev->mmio.wed); + + if (mtk_wed_device_active(&dev->mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mmio.wed_hif2); + + mt76_free_pending_txwi(dev); + mt76_free_pending_rxwi(dev); + free_netdev(dev->napi_dev); + free_netdev(dev->tx_napi_dev); } EXPORT_SYMBOL_GPL(mt76_dma_cleanup); diff --git a/sys/contrib/dev/mediatek/mt76/dma.h b/sys/contrib/dev/mediatek/mt76/dma.h index 1b090d78cd05..e3ddc7a83757 100644 --- a/sys/contrib/dev/mediatek/mt76/dma.h +++ b/sys/contrib/dev/mediatek/mt76/dma.h @@ -1,62 +1,128 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau */ #ifndef __MT76_DMA_H #define __MT76_DMA_H #define DMA_DUMMY_DATA ((void *)~0) #define MT_RING_SIZE 0x10 #define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0) #define MT_DMA_CTL_LAST_SEC1 BIT(14) #define MT_DMA_CTL_BURST BIT(15) #define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16) #define MT_DMA_CTL_LAST_SEC0 BIT(30) #define MT_DMA_CTL_DMA_DONE BIT(31) #define MT_DMA_CTL_TO_HOST BIT(8) #define MT_DMA_CTL_TO_HOST_A BIT(12) #define MT_DMA_CTL_DROP BIT(14) #define MT_DMA_CTL_TOKEN GENMASK(31, 16) +#define MT_DMA_CTL_SDP1_H GENMASK(19, 16) +#define MT_DMA_CTL_SDP0_H GENMASK(3, 0) #define MT_DMA_CTL_WO_DROP BIT(8) #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11) #define MT_DMA_PPE_ENTRY GENMASK(30, 16) +#define MT_DMA_INFO_DMA_FRAG BIT(9) #define MT_DMA_INFO_PPE_VLD BIT(31) +#define MT_DMA_CTL_PN_CHK_FAIL BIT(13) +#define MT_DMA_CTL_VER_MASK BIT(7) + +#define MT_DMA_RRO_EN BIT(13) + +#define MT_DMA_WED_IND_CMD_CNT 8 +#define MT_DMA_WED_IND_REASON GENMASK(15, 12) + #define MT_DMA_HDR_LEN 4 #define MT_RX_INFO_LEN 4 #define MT_FCE_INFO_LEN 4 #define MT_RX_RXWI_LEN 32 struct mt76_desc { __le32 buf0; __le32 ctrl; __le32 buf1; __le32 info; } __packed __aligned(4); +struct mt76_wed_rro_desc { + __le32 buf0; + __le32 buf1; +} __packed __aligned(4); + enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, MT_QSEL_EDCA, MT_QSEL_EDCA_2, }; enum mt76_mcu_evt_type { EVT_CMD_DONE, EVT_CMD_ERROR, EVT_CMD_RETRY, EVT_EVENT_PWR_RSP, EVT_EVENT_WOW_RSP, EVT_EVENT_CARRIER_DETECT_RSP, EVT_EVENT_DFS_DETECT_RSP, }; +enum mt76_dma_wed_ind_reason { + MT_DMA_WED_IND_REASON_NORMAL, + MT_DMA_WED_IND_REASON_REPEAT, + MT_DMA_WED_IND_REASON_OLDPKT, +}; + int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); -int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, + bool allow_direct); +void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx); +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q); + +static inline void +mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + dev->queue_ops->reset_q(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) + mt76_wed_dma_setup(dev, q, true); +} + +static inline void +mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) +{ + if (!drop) + return; + + *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP)); + if (!(ctrl & MT_DMA_CTL_VER_MASK)) + return; + + switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) { + case MT_DMA_WED_IND_REASON_REPEAT: + *drop = true; + break; + case MT_DMA_WED_IND_REASON_OLDPKT: + *drop = !(info & MT_DMA_INFO_DMA_FRAG); + break; + default: + *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL); + break; + } +} + +static inline void *mt76_priv(struct net_device *dev) +{ + struct mt76_dev **priv; + + priv = netdev_priv(dev); + + return *priv; +} #endif diff --git a/sys/contrib/dev/mediatek/mt76/eeprom.c b/sys/contrib/dev/mediatek/mt76/eeprom.c index 91483ad5fe79..eb25879e2021 100644 --- a/sys/contrib/dev/mediatek/mt76/eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/eeprom.c @@ -1,436 +1,452 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #if defined(CONFIG_OF) && defined(CONFIG_MTD) #include #include #include #include #include #endif #include #include "mt76.h" #if defined(CONFIG_OF) static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; const void *data; int size; data = of_get_property(np, "mediatek,eeprom-data", &size); if (!data) return -ENOENT; if (size > len) return -EINVAL; memcpy(eep, data, size); return 0; } #endif -#if defined(CONFIG_MTD) && defined(CONFIG_OF) -static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) { +#if !defined(CONFIG_MTD) || !defined(CONFIG_OF) + return -ENOENT; +#else struct device_node *np = dev->dev->of_node; struct mtd_info *mtd; const __be32 *list; const char *part; phandle phandle; size_t retlen; int size; int ret; list = of_get_property(np, "mediatek,mtd-eeprom", &size); if (!list) return -ENOENT; phandle = be32_to_cpup(list++); if (!phandle) return -ENOENT; np = of_find_node_by_phandle(phandle); if (!np) return -EINVAL; part = of_get_property(np, "label", NULL); if (!part) part = np->name; mtd = get_mtd_device_nm(part); if (IS_ERR(mtd)) { ret = PTR_ERR(mtd); goto out_put_node; } if (size <= sizeof(*list)) { ret = -EINVAL; goto out_put_node; } - offset = be32_to_cpup(list); + offset += be32_to_cpup(list); ret = mtd_read(mtd, offset, len, &retlen, eep); put_mtd_device(mtd); if (mtd_is_bitflip(ret)) ret = 0; if (ret) { dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n", part, ret); goto out_put_node; } if (retlen < len) { ret = -EINVAL; goto out_put_node; } if (of_property_read_bool(dev->dev->of_node, "big-endian")) { u8 *data = (u8 *)eep; int i; /* convert eeprom data in Little Endian */ for (i = 0; i < round_down(len, 2); i += 2) put_unaligned_le16(get_unaligned_be16(&data[i]), &data[i]); } #ifdef CONFIG_NL80211_TESTMODE dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL); dev->test_mtd.offset = offset; #endif out_put_node: of_node_put(np); return ret; -} #endif +} +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); -#if defined(CONFIG_OF) -static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len) { +#if !defined(CONFIG_OF) + return -EOPNOTSUPP; +#else struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; const void *data; size_t retlen; int ret = 0; - cell = of_nvmem_cell_get(np, "eeprom"); + cell = of_nvmem_cell_get(np, cell_name); if (IS_ERR(cell)) return PTR_ERR(cell); data = nvmem_cell_read(cell, &retlen); nvmem_cell_put(cell); if (IS_ERR(data)) return PTR_ERR(data); if (retlen < len) { ret = -EINVAL; goto exit; } memcpy(eep, data, len); exit: kfree(data); return ret; -} #endif +} +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) +static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { -#if defined(CONFIG_MTD) && defined(CONFIG_OF) +#if !defined(CONFIG_MTD) || !defined(CONFIG_OF) + return -ENOENT; +#else struct device_node *np = dev->dev->of_node; int ret; if (!np) return -ENOENT; ret = mt76_get_of_eeprom_data(dev, eep, len); if (!ret) return 0; - ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, 0, len); if (!ret) return 0; - return mt76_get_of_epprom_from_nvmem(dev, eep, len); -#else - return -ENOENT; + return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len); #endif } -EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); void mt76_eeprom_override(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; #if defined(CONFIG_OF) struct device_node *np = dev->dev->of_node; of_get_mac_address(np, phy->macaddr); if (!is_valid_ether_addr(phy->macaddr)) { #endif eth_random_addr(phy->macaddr); dev_info(dev->dev, "Invalid MAC address, using random address %pM\n", phy->macaddr); #if defined(CONFIG_OF) } #endif } EXPORT_SYMBOL_GPL(mt76_eeprom_override); #if defined(CONFIG_OF) static bool mt76_string_prop_find(struct property *prop, const char *str) { const char *cp = NULL; if (!prop || !str || !str[0]) return false; while ((cp = of_prop_next_string(prop, cp)) != NULL) if (!strcasecmp(cp, str)) return true; - return false; } +#endif -static struct device_node * +struct device_node * mt76_find_power_limits_node(struct mt76_dev *dev) { +#if !defined(CONFIG_OF) + return NULL; +#else struct device_node *np = dev->dev->of_node; const char *const region_names[] = { [NL80211_DFS_UNSET] = "ww", [NL80211_DFS_ETSI] = "etsi", [NL80211_DFS_FCC] = "fcc", [NL80211_DFS_JP] = "jp", }; struct device_node *cur, *fallback = NULL; const char *region_name = NULL; if (dev->region < ARRAY_SIZE(region_names)) region_name = region_names[dev->region]; np = of_get_child_by_name(np, "power-limits"); if (!np) return NULL; for_each_child_of_node(np, cur) { struct property *country = of_find_property(cur, "country", NULL); struct property *regd = of_find_property(cur, "regdomain", NULL); if (!country && !regd) { fallback = cur; continue; } if (mt76_string_prop_find(country, dev->alpha2) || mt76_string_prop_find(regd, region_name)) { of_node_put(np); return cur; } } of_node_put(np); return fallback; +#endif } +EXPORT_SYMBOL_GPL(mt76_find_power_limits_node); +#if defined(CONFIG_OF) static const __be32 * mt76_get_of_array(struct device_node *np, char *name, size_t *len, int min) { struct property *prop = of_find_property(np, name, NULL); if (!prop || !prop->value || prop->length < min * 4) return NULL; *len = prop->length; return prop->value; } +#endif -static struct device_node * +struct device_node * mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) { +#if defined(CONFIG_OF) struct device_node *cur; const __be32 *val; size_t len; for_each_child_of_node(np, cur) { val = mt76_get_of_array(cur, "channels", &len, 2); if (!val) continue; while (len >= 2 * sizeof(*val)) { if (chan->hw_value >= be32_to_cpu(val[0]) && chan->hw_value <= be32_to_cpu(val[1])) return cur; val += 2; len -= 2 * sizeof(*val); } } - +#endif return NULL; } +EXPORT_SYMBOL_GPL(mt76_find_channel_node); +#if defined(CONFIG_OF) static s8 mt76_get_txs_delta(struct device_node *np, u8 nss) { const __be32 *val; size_t len; val = mt76_get_of_array(np, "txs-delta", &len, nss); if (!val) return 0; return be32_to_cpu(val[nss - 1]); } static void mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data, s8 target_power, s8 nss_delta, s8 *max_power) { int i; if (!data) return; for (i = 0; i < pwr_len; i++) { pwr[i] = min_t(s8, target_power, be32_to_cpu(data[i]) + nss_delta); *max_power = max(*max_power, pwr[i]); } } static void mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, const __be32 *data, size_t len, s8 target_power, s8 nss_delta, s8 *max_power) { int i, cur; if (!data) return; len /= 4; cur = be32_to_cpu(data[0]); for (i = 0; i < pwr_num; i++) { if (len < pwr_len + 1) break; mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1, target_power, nss_delta, max_power); if (--cur > 0) continue; data += pwr_len + 1; len -= pwr_len + 1; if (!len) break; cur = be32_to_cpu(data[0]); } } #endif s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct ieee80211_channel *chan, struct mt76_power_limits *dest, s8 target_power) { struct mt76_dev *dev = phy->dev; #if defined(CONFIG_OF) struct device_node *np; const __be32 *val; char name[16]; #endif u32 mcs_rates = dev->drv->mcs_rates; #if defined(CONFIG_OF) u32 ru_rates = ARRAY_SIZE(dest->ru[0]); char band; size_t len; #endif s8 max_power = 0; #if defined(CONFIG_OF) s8 txs_delta; #endif if (!mcs_rates) mcs_rates = 10; memset(dest, target_power, sizeof(*dest)); if (!IS_ENABLED(CONFIG_OF)) return target_power; #if defined(CONFIG_OF) np = mt76_find_power_limits_node(dev); if (!np) return target_power; switch (chan->band) { case NL80211_BAND_2GHZ: band = '2'; break; case NL80211_BAND_5GHZ: band = '5'; break; case NL80211_BAND_6GHZ: band = '6'; break; default: return target_power; } snprintf(name, sizeof(name), "txpower-%cg", band); np = of_get_child_by_name(np, name); if (!np) return target_power; np = mt76_find_channel_node(np, chan); if (!np) return target_power; - txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask)); + txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, target_power, txs_delta, &max_power); val = mt76_get_of_array(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm)); mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, target_power, txs_delta, &max_power); val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1); mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), ARRAY_SIZE(dest->mcs), val, len, target_power, txs_delta, &max_power); val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1); mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), ARRAY_SIZE(dest->ru), val, len, target_power, txs_delta, &max_power); #endif return max_power; } EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits); int mt76_eeprom_init(struct mt76_dev *dev, int len) { dev->eeprom.size = len; dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); if (!dev->eeprom.data) return -ENOMEM; - return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len); + return !mt76_get_of_eeprom(dev, dev->eeprom.data, len); } EXPORT_SYMBOL_GPL(mt76_eeprom_init); diff --git a/sys/contrib/dev/mediatek/mt76/mac80211.c b/sys/contrib/dev/mediatek/mt76/mac80211.c index b12d891ddd54..f4a714c57f82 100644 --- a/sys/contrib/dev/mediatek/mt76/mac80211.c +++ b/sys/contrib/dev/mediatek/mt76/mac80211.c @@ -1,1827 +1,2042 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #if defined(CONFIG_OF) #include #endif -#include #if defined(__FreeBSD__) #include #include #endif #include "mt76.h" #define CHAN2G(_idx, _freq) { \ .band = NL80211_BAND_2GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ .max_power = 30, \ } #define CHAN5G(_idx, _freq) { \ .band = NL80211_BAND_5GHZ, \ .center_freq = (_freq), \ .hw_value = (_idx), \ .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), CHAN2G(3, 2422), CHAN2G(4, 2427), CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447), CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467), CHAN2G(13, 2472), CHAN2G(14, 2484), }; static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(36, 5180), CHAN5G(40, 5200), CHAN5G(44, 5220), CHAN5G(48, 5240), CHAN5G(52, 5260), CHAN5G(56, 5280), CHAN5G(60, 5300), CHAN5G(64, 5320), CHAN5G(100, 5500), CHAN5G(104, 5520), CHAN5G(108, 5540), CHAN5G(112, 5560), CHAN5G(116, 5580), CHAN5G(120, 5600), CHAN5G(124, 5620), CHAN5G(128, 5640), CHAN5G(132, 5660), CHAN5G(136, 5680), CHAN5G(140, 5700), CHAN5G(144, 5720), CHAN5G(149, 5745), CHAN5G(153, 5765), CHAN5G(157, 5785), CHAN5G(161, 5805), CHAN5G(165, 5825), CHAN5G(169, 5845), CHAN5G(173, 5865), CHAN5G(177, 5885), }; 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), }; #if defined(CONFIG_MT76_LEDS) static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { { .throughput = 0 * 1024, .blink_time = 334 }, { .throughput = 1 * 1024, .blink_time = 260 }, { .throughput = 5 * 1024, .blink_time = 220 }, { .throughput = 10 * 1024, .blink_time = 190 }, { .throughput = 20 * 1024, .blink_time = 170 }, { .throughput = 50 * 1024, .blink_time = 150 }, { .throughput = 70 * 1024, .blink_time = 130 }, { .throughput = 100 * 1024, .blink_time = 110 }, { .throughput = 200 * 1024, .blink_time = 80 }, { .throughput = 300 * 1024, .blink_time = 50 }, }; #endif struct ieee80211_rate mt76_rates[] = { CCK_RATE(0, 10), CCK_RATE(1, 20), CCK_RATE(2, 55), CCK_RATE(3, 110), OFDM_RATE(11, 60), OFDM_RATE(15, 90), OFDM_RATE(10, 120), OFDM_RATE(14, 180), OFDM_RATE(9, 240), OFDM_RATE(13, 360), OFDM_RATE(8, 480), OFDM_RATE(12, 540), }; 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, }, { .start_freq = 5945, .end_freq = 6165, }, { .start_freq = 6165, .end_freq = 6405, }, { .start_freq = 6405, .end_freq = 6525, }, { .start_freq = 6525, .end_freq = 6705, }, { .start_freq = 6705, .end_freq = 6865, }, { .start_freq = 6865, .end_freq = 7125, }, }; static 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], }; #if defined(CONFIG_MT76_LEDS) static int mt76_led_init(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; struct ieee80211_hw *hw = phy->hw; + struct device_node *np = dev->dev->of_node; if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return 0; + np = of_get_child_by_name(np, "led"); + if (np) { + if (!of_device_is_available(np)) { + of_node_put(np); + dev_info(dev->dev, + "led registration was explicitly disabled by dts\n"); + return 0; + } + + if (phy == &dev->phy) { + int led_pin; + + if (!of_property_read_u32(np, "led-sources", &led_pin)) + phy->leds.pin = led_pin; + + phy->leds.al = + of_property_read_bool(np, "led-active-low"); + } + + of_node_put(np); + } + snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", wiphy_name(hw->wiphy)); phy->leds.cdev.name = phy->leds.name; phy->leds.cdev.default_trigger = ieee80211_create_tpt_led_trigger(hw, IEEE80211_TPT_LEDTRIG_FL_RADIO, mt76_tpt_blink, ARRAY_SIZE(mt76_tpt_blink)); -#if defined(CONFIG_OF) - if (phy == &dev->phy) { - struct device_node *np = dev->dev->of_node; - - np = of_get_child_by_name(np, "led"); - if (np) { - int led_pin; - - if (!of_property_read_u32(np, "led-sources", &led_pin)) - phy->leds.pin = led_pin; - phy->leds.al = of_property_read_bool(np, - "led-active-low"); - of_node_put(np); - } - } -#endif + dev_info(dev->dev, + "registering led '%s'\n", phy->leds.name); return led_classdev_register(dev->dev, &phy->leds.cdev); } static void mt76_led_cleanup(struct mt76_phy *phy) { if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return; led_classdev_unregister(&phy->leds.cdev); } #endif static void mt76_init_stream_cap(struct mt76_phy *phy, struct ieee80211_supported_band *sband, bool vht) { struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; int i, nstream = hweight8(phy->antenna_mask); struct ieee80211_sta_vht_cap *vht_cap; u16 mcs_map = 0; if (nstream > 1) ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; else ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; if (!vht) return; vht_cap = &sband->vht_cap; if (nstream > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; for (i = 0; i < 8; i++) { if (i < nstream) mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); else mcs_map |= (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); } vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) vht_cap->vht_mcs.tx_highest |= cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); } void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) { if (phy->cap.has_2ghz) 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 ht, bool vht) { struct ieee80211_supported_band *sband = &msband->sband; struct ieee80211_sta_vht_cap *vht_cap; struct ieee80211_sta_ht_cap *ht_cap; struct mt76_dev *dev = phy->dev; void *chanlist; int size; size = n_chan * sizeof(*chan); chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); if (!chanlist) return -ENOMEM; msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), GFP_KERNEL); if (!msband->chan) return -ENOMEM; sband->channels = chanlist; sband->n_channels = n_chan; 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 | IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; mt76_init_stream_cap(phy, sband, vht); if (!vht) return 0; vht_cap = &sband->vht_cap; vht_cap->vht_supported = true; vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_SHORT_GI_80 | (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); return 0; } static int mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, int n_rates) { phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz), rates, n_rates, true, false); } static int mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, int n_rates, bool vht) { phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz), rates, 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 mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, enum nl80211_band band) { struct ieee80211_supported_band *sband = &msband->sband; bool found = false; int i; if (!sband) return; for (i = 0; i < sband->n_channels; i++) { if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) continue; found = true; break; } if (found) { - phy->chandef.chan = &sband->channels[0]; + cfg80211_chandef_create(&phy->chandef, &sband->channels[0], + NL80211_CHAN_HT20); phy->chan_state = &msband->chan[0]; + phy->dev->band_phys[band] = phy; return; } sband->n_channels = 0; - phy->hw->wiphy->bands[band] = NULL; + if (phy->hw->wiphy->bands[band] == sband) + phy->hw->wiphy->bands[band] = NULL; } static int mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) { struct mt76_dev *dev = phy->dev; struct wiphy *wiphy = hw->wiphy; + INIT_LIST_HEAD(&phy->tx_list); + spin_lock_init(&phy->tx_lock); + INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work); + + if ((void *)phy != hw->priv) + return 0; + SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_AP_UAPSD; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); wiphy->available_antennas_tx = phy->antenna_mask; wiphy->available_antennas_rx = phy->antenna_mask; wiphy->sar_capa = &mt76_sar_capa; phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, sizeof(struct mt76_freq_range_power), GFP_KERNEL); if (!phy->frp) return -ENOMEM; hw->txq_data_size = sizeof(struct mt76_txq); hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; if (!hw->max_tx_fragments) hw->max_tx_fragments = 16; ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); + ieee80211_hw_set(hw, SPECTRUM_MGMT); - if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { + if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) && + hw->max_tx_fragments > 1) { 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); return 0; } +struct mt76_phy * +mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size, + u8 band_idx) +{ + struct ieee80211_hw *hw = dev->phy.hw; + unsigned int phy_size; + struct mt76_phy *phy; + + phy_size = ALIGN(sizeof(*phy), 8); + phy = devm_kzalloc(dev->dev, size + phy_size, GFP_KERNEL); + if (!phy) + return NULL; + + phy->dev = dev; + phy->hw = hw; +#if defined(__linux__) + phy->priv = (void *)phy + phy_size; +#elif defined(__FreeBSD__) + phy->priv = (u8 *)phy + phy_size; +#endif + phy->band_idx = band_idx; + + return phy; +} +EXPORT_SYMBOL_GPL(mt76_alloc_radio_phy); + struct mt76_phy * mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, const struct ieee80211_ops *ops, u8 band_idx) { struct ieee80211_hw *hw; unsigned int phy_size; struct mt76_phy *phy; phy_size = ALIGN(sizeof(*phy), 8); hw = ieee80211_alloc_hw(size + phy_size, ops); if (!hw) return NULL; phy = hw->priv; phy->dev = dev; phy->hw = hw; #if defined(__linux__) phy->priv = hw->priv + phy_size; #elif defined(__FreeBSD__) phy->priv = (u8 *)hw->priv + phy_size; #endif phy->band_idx = band_idx; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC); return phy; } EXPORT_SYMBOL_GPL(mt76_alloc_phy); int mt76_register_phy(struct mt76_phy *phy, bool vht, struct ieee80211_rate *rates, int n_rates) { int ret; ret = mt76_phy_init(phy, phy->hw); if (ret) return ret; if (phy->cap.has_2ghz) { ret = mt76_init_sband_2g(phy, rates, n_rates); if (ret) return ret; } if (phy->cap.has_5ghz) { ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); if (ret) return ret; } if (phy->cap.has_6ghz) { ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); if (ret) return ret; } #if defined(CONFIG_MT76_LEDS) if (IS_ENABLED(CONFIG_MT76_LEDS)) { ret = mt76_led_init(phy); if (ret) return ret; } #endif 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) - return ret; + if ((void *)phy == phy->hw->priv) { + ret = ieee80211_register_hw(phy->hw); + if (ret) + return ret; + } set_bit(MT76_STATE_REGISTERED, &phy->state); phy->dev->phys[phy->band_idx] = phy; return 0; } EXPORT_SYMBOL_GPL(mt76_register_phy); void mt76_unregister_phy(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; if (!test_bit(MT76_STATE_REGISTERED, &phy->state)) return; #if defined(CONFIG_MT76_LEDS) if (IS_ENABLED(CONFIG_MT76_LEDS)) mt76_led_cleanup(phy); #endif mt76_tx_status_check(dev, true); ieee80211_unregister_hw(phy->hw); dev->phys[phy->band_idx] = NULL; } EXPORT_SYMBOL_GPL(mt76_unregister_phy); int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) { + bool is_qrx = mt76_queue_is_rx(dev, q); struct page_pool_params pp_params = { .order = 0, - .flags = PP_FLAG_PAGE_FRAG, + .flags = 0, .nid = NUMA_NO_NODE, .dev = dev->dma_dev, }; - int idx = q - dev->q_rx; + int idx = is_qrx ? q - dev->q_rx : -1; + + /* Allocate page_pools just for rx/wed_tx_free queues */ + if (!is_qrx && !mt76_queue_is_wed_tx_free(q)) + return 0; switch (idx) { case MT_RXQ_MAIN: case MT_RXQ_BAND1: case MT_RXQ_BAND2: pp_params.pool_size = 256; break; default: pp_params.pool_size = 16; break; } if (mt76_is_mmio(dev)) { /* rely on page_pool for DMA mapping */ pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; pp_params.dma_dir = DMA_FROM_DEVICE; pp_params.max_len = PAGE_SIZE; pp_params.offset = 0; + /* NAPI is available just for rx queues */ + if (idx >= 0 && idx < ARRAY_SIZE(dev->napi)) + pp_params.napi = &dev->napi[idx]; } q->page_pool = page_pool_create(&pp_params); if (IS_ERR(q->page_pool)) { int err = PTR_ERR(q->page_pool); q->page_pool = NULL; return err; } return 0; } EXPORT_SYMBOL_GPL(mt76_create_page_pool); struct mt76_dev * mt76_alloc_device(struct device *pdev, unsigned int size, const struct ieee80211_ops *ops, const struct mt76_driver_ops *drv_ops) { struct ieee80211_hw *hw; struct mt76_phy *phy; struct mt76_dev *dev; int i; hw = ieee80211_alloc_hw(size, ops); if (!hw) return NULL; dev = hw->priv; dev->hw = hw; dev->dev = pdev; dev->drv = drv_ops; dev->dma_dev = pdev; phy = &dev->phy; phy->dev = dev; phy->hw = hw; phy->band_idx = MT_BAND0; dev->phys[phy->band_idx] = phy; spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); spin_lock_init(&dev->cc_lock); spin_lock_init(&dev->status_lock); spin_lock_init(&dev->wed_lock); mutex_init(&dev->mutex); init_waitqueue_head(&dev->tx_wait); skb_queue_head_init(&dev->mcu.res_q); init_waitqueue_head(&dev->mcu.wait); mutex_init(&dev->mcu.mutex); dev->tx_worker.fn = mt76_tx_worker; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_ADHOC); spin_lock_init(&dev->token_lock); idr_init(&dev->token); spin_lock_init(&dev->rx_token_lock); idr_init(&dev->rx_token); INIT_LIST_HEAD(&dev->wcid_list); INIT_LIST_HEAD(&dev->sta_poll_list); spin_lock_init(&dev->sta_poll_lock); INIT_LIST_HEAD(&dev->txwi_cache); INIT_LIST_HEAD(&dev->rxwi_cache); dev->token_size = dev->drv->token_size; + INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) skb_queue_head_init(&dev->rx_skb[i]); dev->wq = alloc_ordered_workqueue("mt76", 0); if (!dev->wq) { ieee80211_free_hw(hw); return NULL; } return dev; } EXPORT_SYMBOL_GPL(mt76_alloc_device); int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates) { struct ieee80211_hw *hw = dev->hw; struct mt76_phy *phy = &dev->phy; int ret; dev_set_drvdata(dev->dev, dev); + mt76_wcid_init(&dev->global_wcid, phy->band_idx); ret = mt76_phy_init(phy, hw); if (ret) return ret; if (phy->cap.has_2ghz) { ret = mt76_init_sband_2g(phy, rates, n_rates); if (ret) return ret; } if (phy->cap.has_5ghz) { ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); if (ret) 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 defined(CONFIG_MT76_LEDS) if (IS_ENABLED(CONFIG_MT76_LEDS)) { ret = mt76_led_init(phy); if (ret) return ret; } #endif ret = ieee80211_register_hw(hw); if (ret) return ret; WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); set_bit(MT76_STATE_REGISTERED, &phy->state); sched_set_fifo_low(dev->tx_worker.task); return 0; } EXPORT_SYMBOL_GPL(mt76_register_device); void mt76_unregister_device(struct mt76_dev *dev) { #if defined(__linux__) struct ieee80211_hw *hw = dev->hw; #endif if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state)) return; #if defined(CONFIG_MT76_LEDS) if (IS_ENABLED(CONFIG_MT76_LEDS)) mt76_led_cleanup(&dev->phy); #endif mt76_tx_status_check(dev, true); + mt76_wcid_cleanup(dev, &dev->global_wcid); #if defined(__linux__) ieee80211_unregister_hw(hw); #elif defined(__FreeBSD__) ieee80211_unregister_hw(dev->hw); #endif } EXPORT_SYMBOL_GPL(mt76_unregister_device); void mt76_free_device(struct mt76_dev *dev) { mt76_worker_teardown(&dev->tx_worker); if (dev->wq) { destroy_workqueue(dev->wq); dev->wq = NULL; } ieee80211_free_hw(dev->hw); } EXPORT_SYMBOL_GPL(mt76_free_device); +static struct mt76_phy * +mt76_vif_phy(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_chanctx *ctx; + + if (!hw->wiphy->n_radio) + return hw->priv; + + if (!mlink->ctx) + return NULL; + + ctx = (struct mt76_chanctx *)mlink->ctx->drv_priv; + return ctx->phy; +} + static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) { struct sk_buff *skb = phy->rx_amsdu[q].head; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_dev *dev = phy->dev; phy->rx_amsdu[q].head = NULL; phy->rx_amsdu[q].tail = NULL; /* * Validate if the amsdu has a proper first subframe. * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU * flag of the QoS header gets flipped. In such cases, the first * subframe has a LLC/SNAP header in the location of the destination * address. */ if (skb_shinfo(skb)->frag_list) { int offset = 0; if (!(status->flag & RX_FLAG_8023)) { offset = ieee80211_get_hdrlen_from_skb(skb); if ((status->flag & (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == RX_FLAG_DECRYPTED) offset += 8; } if (ether_addr_equal(skb->data + offset, rfc1042_header)) { dev_kfree_skb(skb); return; } } __skb_queue_tail(&dev->rx_skb[q], skb); } static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; if (phy->rx_amsdu[q].head && (!status->amsdu || status->first_amsdu || status->seqno != phy->rx_amsdu[q].seqno)) mt76_rx_release_amsdu(phy, q); if (!phy->rx_amsdu[q].head) { phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; phy->rx_amsdu[q].seqno = status->seqno; phy->rx_amsdu[q].head = skb; } else { *phy->rx_amsdu[q].tail = skb; phy->rx_amsdu[q].tail = &skb->next; } if (!status->amsdu || status->last_amsdu) mt76_rx_release_amsdu(phy, q); } void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { dev_kfree_skb(skb); return; } #ifdef CONFIG_NL80211_TESTMODE if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { phy->test.rx_stats.packets[q]++; if (status->flag & RX_FLAG_FAILED_FCS_CRC) phy->test.rx_stats.fcs_error[q]++; } #endif mt76_rx_release_burst(phy, q, skb); } EXPORT_SYMBOL_GPL(mt76_rx); bool mt76_has_tx_pending(struct mt76_phy *phy) { struct mt76_queue *q; int i; for (i = 0; i < __MT_TXQ_MAX; i++) { q = phy->q_tx[i]; if (q && q->queued) return true; } return false; } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); static struct mt76_channel_state * mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) { struct mt76_sband *msband; int idx; 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; idx = c - &msband->sband.channels[0]; return &msband->chan[idx]; } void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) { struct mt76_channel_state *state = phy->chan_state; state->cc_active += ktime_to_us(ktime_sub(time, phy->survey_time)); phy->survey_time = time; } EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); void mt76_update_survey(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; ktime_t cur_time; if (dev->drv->update_survey) dev->drv->update_survey(phy); cur_time = ktime_get_boottime(); mt76_update_survey_active_time(phy, cur_time); if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { struct mt76_channel_state *state = phy->chan_state; spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; dev->cur_cc_bss_rx = 0; spin_unlock_bh(&dev->cc_lock); } } EXPORT_SYMBOL_GPL(mt76_update_survey); -void mt76_set_channel(struct mt76_phy *phy) +int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + bool offchannel) { struct mt76_dev *dev = phy->dev; - struct ieee80211_hw *hw = phy->hw; - struct cfg80211_chan_def *chandef = &hw->conf.chandef; - bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; int timeout = HZ / 5; + int ret; + set_bit(MT76_RESET, &phy->state); + + mt76_worker_disable(&dev->tx_worker); wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); mt76_update_survey(phy); if (phy->chandef.chan->center_freq != chandef->chan->center_freq || phy->chandef.width != chandef->width) phy->dfs_state = MT_DFS_STATE_UNKNOWN; phy->chandef = *chandef; phy->chan_state = mt76_channel_state(phy, chandef->chan); + phy->offchannel = offchannel; if (!offchannel) - phy->main_chan = chandef->chan; + phy->main_chandef = *chandef; - if (chandef->chan != phy->main_chan) + if (chandef->chan != phy->main_chandef.chan) memset(phy->chan_state, 0, sizeof(*phy->chan_state)); + + ret = dev->drv->set_channel(phy); + + clear_bit(MT76_RESET, &phy->state); + mt76_worker_enable(&dev->tx_worker); + mt76_worker_schedule(&dev->tx_worker); + + return ret; +} + +int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + bool offchannel) +{ + struct mt76_dev *dev = phy->dev; + int ret; + + cancel_delayed_work_sync(&phy->mac_work); + + mutex_lock(&dev->mutex); + ret = __mt76_set_channel(phy, chandef, offchannel); + mutex_unlock(&dev->mutex); + + return ret; +} + +int mt76_update_channel(struct mt76_phy *phy) +{ + struct ieee80211_hw *hw = phy->hw; + struct cfg80211_chan_def *chandef = &hw->conf.chandef; + bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; + + phy->radar_enabled = hw->conf.radar_enabled; + + return mt76_set_channel(phy, chandef, offchannel); +} +EXPORT_SYMBOL_GPL(mt76_update_channel); + +static struct mt76_sband * +mt76_get_survey_sband(struct mt76_phy *phy, int *idx) +{ + if (*idx < phy->sband_2g.sband.n_channels) + return &phy->sband_2g; + + *idx -= phy->sband_2g.sband.n_channels; + if (*idx < phy->sband_5g.sband.n_channels) + return &phy->sband_5g; + + *idx -= phy->sband_5g.sband.n_channels; + if (*idx < phy->sband_6g.sband.n_channels) + return &phy->sband_6g; + + *idx -= phy->sband_6g.sband.n_channels; + return NULL; } -EXPORT_SYMBOL_GPL(mt76_set_channel); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - struct mt76_sband *sband; + struct mt76_sband *sband = NULL; struct ieee80211_channel *chan; struct mt76_channel_state *state; + int phy_idx = 0; int ret = 0; mutex_lock(&dev->mutex); - if (idx == 0 && dev->drv->update_survey) - mt76_update_survey(phy); - - 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; + + for (phy_idx = 0; phy_idx < ARRAY_SIZE(dev->phys); phy_idx++) { + sband = NULL; + phy = dev->phys[phy_idx]; + if (!phy || phy->hw != hw) + continue; + + sband = mt76_get_survey_sband(phy, &idx); + + if (idx == 0 && phy->dev->drv->update_survey) + mt76_update_survey(phy); + + if (sband || !hw->wiphy->n_radio) + break; } - if (idx >= sband->sband.n_channels) { + if (!sband) { ret = -ENOENT; goto out; } chan = &sband->sband.channels[idx]; state = mt76_channel_state(phy, chan); memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; survey->filled |= dev->drv->survey_flags; if (state->noise) survey->filled |= SURVEY_INFO_NOISE_DBM; - if (chan == phy->main_chan) { + if (chan == phy->main_chandef.chan) { survey->filled |= SURVEY_INFO_IN_USE; if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) survey->filled |= SURVEY_INFO_TIME_BSS_RX; } survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_rx = div_u64(state->cc_rx, 1000); survey->time = div_u64(state->cc_active, 1000); survey->noise = state->noise; spin_lock_bh(&dev->cc_lock); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); out: mutex_unlock(&dev->mutex); return ret; } EXPORT_SYMBOL_GPL(mt76_get_survey); void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key) { struct ieee80211_key_seq seq; int i; wcid->rx_check_pn = false; if (!key) return; if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 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); int mt76_rx_signal(u8 chain_mask, s8 *chain_signal) { int signal = -128; u8 chains; for (chains = chain_mask; chains; chains >>= 1, chain_signal++) { int cur, diff; cur = *chain_signal; if (!(chains & BIT(0)) || cur > 0) continue; if (cur > signal) swap(cur, signal); diff = signal - cur; if (diff == 0) signal += 3; else if (diff <= 2) signal += 2; else if (diff <= 6) signal += 1; } return signal; } EXPORT_SYMBOL(mt76_rx_signal); static void mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_hw **hw, 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); memset(status, 0, sizeof(*status)); status->flag = mstat.flag; status->freq = mstat.freq; status->enc_flags = mstat.enc_flags; status->encoding = mstat.encoding; status->bw = mstat.bw; if (status->encoding == RX_ENC_EHT) { status->eht.ru = mstat.eht.ru; status->eht.gi = mstat.eht.gi; } else { status->he_ru = mstat.he_ru; status->he_gi = mstat.he_gi; status->he_dcm = mstat.he_dcm; } status->rate_idx = mstat.rate_idx; status->nss = mstat.nss; status->band = mstat.band; status->signal = mstat.signal; status->chains = mstat.chains; status->ampdu_reference = mstat.ampdu_ref; status->device_timestamp = mstat.timestamp; status->mactime = mstat.timestamp; status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal); if (status->signal <= -128) status->flag |= RX_FLAG_NO_SIGNAL_VAL; 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)); memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal)); + if (mstat.wcid) { + status->link_valid = mstat.wcid->link_valid; + status->link_id = mstat.wcid->link_id; + } + *sta = wcid_to_sta(mstat.wcid); *hw = mt76_phy_hw(dev, mstat.phy_idx); } static void 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; int security_idx; int ret; if (!(status->flag & RX_FLAG_DECRYPTED)) return; if (status->flag & RX_FLAG_ONLY_MONITOR) return; if (!wcid || !wcid->rx_check_pn) return; 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. */ if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) return; } /* 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[security_idx], sizeof(status->iv)); if (ret <= 0) { status->flag |= RX_FLAG_ONLY_MONITOR; return; } 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; } static void mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, int len) { struct mt76_wcid *wcid = status->wcid; struct ieee80211_rx_status info = { .enc_flags = status->enc_flags, .rate_idx = status->rate_idx, .encoding = status->encoding, .band = status->band, .nss = status->nss, .bw = status->bw, }; struct ieee80211_sta *sta; u32 airtime; u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); spin_lock(&dev->cc_lock); dev->cur_cc_bss_rx += airtime; spin_unlock(&dev->cc_lock); if (!wcid || !wcid->sta) return; sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); ieee80211_sta_register_airtime(sta, tidno, 0, airtime); } static void mt76_airtime_flush_ampdu(struct mt76_dev *dev) { struct mt76_wcid *wcid; int wcid_idx; if (!dev->rx_ampdu_len) return; wcid_idx = dev->rx_ampdu_status.wcid_idx; if (wcid_idx < ARRAY_SIZE(dev->wcid)) wcid = rcu_dereference(dev->wcid[wcid_idx]); else wcid = NULL; dev->rx_ampdu_status.wcid = wcid; mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); dev->rx_ampdu_len = 0; dev->rx_ampdu_ref = 0; } static void mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) return; if (!wcid || !wcid->sta) { struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); if (status->flag & RX_FLAG_8023) return; if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) return; wcid = NULL; } if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || status->ampdu_ref != dev->rx_ampdu_ref) mt76_airtime_flush_ampdu(dev); if (status->flag & RX_FLAG_AMPDU_DETAILS) { if (!dev->rx_ampdu_len || status->ampdu_ref != dev->rx_ampdu_ref) { dev->rx_ampdu_status = *status; dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; dev->rx_ampdu_ref = status->ampdu_ref; } dev->rx_ampdu_len += skb->len; return; } mt76_airtime_report(dev, status, skb->len); } static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); struct ieee80211_sta *sta; struct ieee80211_hw *hw; struct mt76_wcid *wcid = status->wcid; u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; bool ps; hw = mt76_phy_hw(dev, status->phy_idx); if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && !(status->flag & RX_FLAG_8023)) { sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); if (sta) wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; } mt76_airtime_check(dev, skb); if (!wcid || !wcid->sta) return; sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); if (status->signal <= 0) ewma_signal_add(&wcid->rssi, -status->signal); wcid->inactive_count = 0; if (status->flag & RX_FLAG_8023) return; if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) return; if (ieee80211_is_pspoll(hdr->frame_control)) { ieee80211_sta_pspoll(sta); return; } if (ieee80211_has_morefrags(hdr->frame_control) || !(ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_data(hdr->frame_control))) return; ps = ieee80211_has_pm(hdr->frame_control); if (ps && (ieee80211_is_data_qos(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control))) ieee80211_sta_uapsd_trigger(sta, tidno); if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) return; if (ps) set_bit(MT_WCID_FLAG_PS, &wcid->flags); if (dev->drv->sta_ps) dev->drv->sta_ps(dev, sta, ps); if (!ps) clear_bit(MT_WCID_FLAG_PS, &wcid->flags); ieee80211_sta_ps_transition(sta, ps); } void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, struct napi_struct *napi) { struct ieee80211_sta *sta; struct ieee80211_hw *hw; struct sk_buff *skb, *tmp; #if defined(__linux__) LIST_HEAD(list); #elif defined(__FreeBSD__) LINUX_LIST_HEAD(list); #endif spin_lock(&dev->rx_lock); while ((skb = __skb_dequeue(frames)) != NULL) { struct sk_buff *nskb = skb_shinfo(skb)->frag_list; mt76_check_ccmp_pn(skb); skb_shinfo(skb)->frag_list = NULL; mt76_rx_convert(dev, skb, &hw, &sta); ieee80211_rx_list(hw, sta, skb, &list); /* subsequent amsdu frames */ while (nskb) { skb = nskb; nskb = nskb->next; skb->next = NULL; mt76_rx_convert(dev, skb, &hw, &sta); ieee80211_rx_list(hw, sta, skb, &list); } } spin_unlock(&dev->rx_lock); if (!napi) { netif_receive_skb_list(&list); return; } list_for_each_entry_safe(skb, tmp, &list, list) { skb_list_del_init(skb); napi_gro_receive(napi, skb); } } void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi) { struct sk_buff_head frames; struct sk_buff *skb; __skb_queue_head_init(&frames); while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { mt76_check_sta(dev, skb); if (mtk_wed_device_active(&dev->mmio.wed)) __skb_queue_tail(&frames, skb); else mt76_rx_aggr_reorder(skb, &frames); } mt76_rx_complete(dev, &frames, napi); } EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); static int mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct mt76_dev *dev = phy->dev; int ret; int i; mutex_lock(&dev->mutex); ret = dev->drv->sta_add(dev, vif, sta); if (ret) goto out; for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { struct mt76_txq *mtxq; if (!sta->txq[i]) continue; mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; mtxq->wcid = wcid->idx; } ewma_signal_init(&wcid->rssi); - if (phy->band_idx == MT_BAND1) - mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); - wcid->phy_idx = phy->band_idx; rcu_assign_pointer(dev->wcid[wcid->idx], wcid); + phy->num_sta++; - mt76_packet_id_init(wcid); + mt76_wcid_init(wcid, phy->band_idx); out: mutex_unlock(&dev->mutex); return ret; } -void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, +void __mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt76_dev *dev = phy->dev; struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; int i, idx = wcid->idx; for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) mt76_rx_aggr_stop(dev, wcid, i); if (dev->drv->sta_remove) dev->drv->sta_remove(dev, vif, sta); - mt76_packet_id_flush(dev, wcid); + mt76_wcid_cleanup(dev, wcid); mt76_wcid_mask_clear(dev->wcid_mask, idx); - mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); + phy->num_sta--; } EXPORT_SYMBOL_GPL(__mt76_sta_remove); static void -mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, +mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct mt76_dev *dev = phy->dev; + mutex_lock(&dev->mutex); - __mt76_sta_remove(dev, vif, sta); + __mt76_sta_remove(phy, vif, sta); mutex_unlock(&dev->mutex); } int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; + enum mt76_sta_event ev; + + phy = mt76_vif_phy(hw, vif); + if (!phy) + return -EINVAL; if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) return mt76_sta_add(phy, vif, sta); - if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC && - dev->drv->sta_assoc) - dev->drv->sta_assoc(dev, vif, sta); - if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) - mt76_sta_remove(dev, vif, sta); + mt76_sta_remove(phy, vif, sta); - return 0; + if (!dev->drv->sta_event) + return 0; + + if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) + ev = MT76_STA_EVENT_ASSOC; + else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) + ev = MT76_STA_EVENT_AUTHORIZE; + else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) + ev = MT76_STA_EVENT_DISASSOC; + else + return 0; + + return dev->drv->sta_event(dev, vif, sta, ev); } EXPORT_SYMBOL_GPL(mt76_sta_state); void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; mutex_lock(&dev->mutex); spin_lock_bh(&dev->status_lock); rcu_assign_pointer(dev->wcid[wcid->idx], NULL); spin_unlock_bh(&dev->status_lock); mutex_unlock(&dev->mutex); } EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); +void mt76_wcid_init(struct mt76_wcid *wcid, u8 band_idx) +{ + wcid->hw_key_idx = -1; + wcid->phy_idx = band_idx; + + INIT_LIST_HEAD(&wcid->tx_list); + skb_queue_head_init(&wcid->tx_pending); + skb_queue_head_init(&wcid->tx_offchannel); + + INIT_LIST_HEAD(&wcid->list); + idr_init(&wcid->pktid); + + INIT_LIST_HEAD(&wcid->poll_list); +} +EXPORT_SYMBOL_GPL(mt76_wcid_init); + +void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) +{ + struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx); + struct ieee80211_hw *hw; + struct sk_buff_head list; + struct sk_buff *skb; + + 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); + + spin_lock_bh(&phy->tx_lock); + + if (!list_empty(&wcid->tx_list)) + list_del_init(&wcid->tx_list); + + spin_lock(&wcid->tx_pending.lock); + skb_queue_splice_tail_init(&wcid->tx_pending, &list); + spin_unlock(&wcid->tx_pending.lock); + + spin_unlock_bh(&phy->tx_lock); + + while ((skb = __skb_dequeue(&list)) != NULL) { + hw = mt76_tx_status_get_hw(dev, skb); + ieee80211_free_txskb(hw, skb); + } +} +EXPORT_SYMBOL_GPL(mt76_wcid_cleanup); + +void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid) +{ + if (test_bit(MT76_MCU_RESET, &dev->phy.state)) + return; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&wcid->poll_list)) + list_add_tail(&wcid->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); +} +EXPORT_SYMBOL_GPL(mt76_wcid_add_poll); + int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - int *dbm) + unsigned int link_id, int *dbm) { - struct mt76_phy *phy = hw->priv; - int n_chains = hweight8(phy->antenna_mask); - int delta = mt76_tx_power_nss_delta(n_chains); + struct mt76_phy *phy = mt76_vif_phy(hw, vif); + int n_chains, delta; + + if (!phy) + return -EINVAL; + n_chains = hweight16(phy->chainmask); + delta = mt76_tx_power_nss_delta(n_chains); *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); return 0; } EXPORT_SYMBOL_GPL(mt76_get_txpower); int mt76_init_sar_power(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt76_phy *phy = hw->priv; const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; int i; if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) return -EINVAL; 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; phy->frp[index].range = &capa->freq_ranges[index]; phy->frp[index].power = power; } return 0; } EXPORT_SYMBOL_GPL(mt76_init_sar_power); int mt76_get_sar_power(struct mt76_phy *phy, struct ieee80211_channel *chan, int power) { const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; int freq, i; if (!capa || !phy->frp) return power; if (power > 127 || power < -127) power = 127; freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); for (i = 0 ; i < capa->num_freq_ranges; i++) { if (phy->frp[i].range && freq >= phy->frp[i].range->start_freq && freq < phy->frp[i].range->end_freq) { power = min_t(int, phy->frp[i].power, power); break; } } return power; } EXPORT_SYMBOL_GPL(mt76_get_sar_power); static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) - ieee80211_csa_finish(vif); + if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0)) + ieee80211_csa_finish(vif, 0); } void mt76_csa_finish(struct mt76_dev *dev) { if (!dev->csa_complete) return; ieee80211_iterate_active_interfaces_atomic(dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, __mt76_csa_finish, dev); dev->csa_complete = 0; } EXPORT_SYMBOL_GPL(mt76_csa_finish); static void __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76_dev *dev = priv; if (!vif->bss_conf.csa_active) return; - dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); + dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0); } void mt76_csa_check(struct mt76_dev *dev) { ieee80211_iterate_active_interfaces_atomic(dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, __mt76_csa_check, dev); } EXPORT_SYMBOL_GPL(mt76_csa_check); int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { return 0; } EXPORT_SYMBOL_GPL(mt76_set_tim); void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; int hdr_len = ieee80211_get_hdrlen_from_skb(skb); u8 *hdr, *pn = status->iv; __skb_push(skb, 8); memmove(skb->data, skb->data + 8, hdr_len); hdr = skb->data + hdr_len; hdr[0] = pn[5]; hdr[1] = pn[4]; hdr[2] = 0; hdr[3] = 0x20 | (key_id << 6); hdr[4] = pn[3]; hdr[5] = pn[2]; hdr[6] = pn[1]; hdr[7] = pn[0]; status->flag &= ~RX_FLAG_IV_STRIPPED; } EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); int mt76_get_rate(struct mt76_dev *dev, struct ieee80211_supported_band *sband, int idx, bool cck) { + bool is_2g = sband->band == NL80211_BAND_2GHZ; int i, offset = 0, len = sband->n_bitrates; if (cck) { - if (sband != &dev->phy.sband_2g.sband) + if (!is_2g) return 0; idx &= ~BIT(2); /* short preamble */ - } else if (sband == &dev->phy.sband_2g.sband) { + } else if (is_2g) { offset = 4; } for (i = offset; i < len; i++) { if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) return i; } return 0; } EXPORT_SYMBOL_GPL(mt76_get_rate); void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) { struct mt76_phy *phy = hw->priv; set_bit(MT76_SCANNING, &phy->state); } EXPORT_SYMBOL_GPL(mt76_sw_scan); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76_phy *phy = hw->priv; clear_bit(MT76_SCANNING, &phy->state); } EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; + int i; mutex_lock(&dev->mutex); - *tx_ant = phy->antenna_mask; - *rx_ant = phy->antenna_mask; + *tx_ant = 0; + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) + if (dev->phys[i] && dev->phys[i]->hw == hw) + *tx_ant |= dev->phys[i]->chainmask; + *rx_ant = *tx_ant; mutex_unlock(&dev->mutex); return 0; } EXPORT_SYMBOL_GPL(mt76_get_antenna); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { struct mt76_queue *hwq; int err; hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); if (!hwq) return ERR_PTR(-ENOMEM); hwq->flags = flags; + hwq->wed = wed; err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); if (err < 0) return ERR_PTR(err); return hwq; } EXPORT_SYMBOL_GPL(mt76_init_queue); -u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) -{ - int offset = 0; - - if (phy->chandef.chan->band != NL80211_BAND_2GHZ) - offset = 4; - - /* pick the lowest rate for hidden nodes */ - if (rateidx < 0) - rateidx = 0; - - rateidx += offset; - if (rateidx >= ARRAY_SIZE(mt76_rates)) - rateidx = offset; - - return mt76_rates[rateidx].hw_value; -} -EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); - void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, struct mt76_sta_stats *stats, bool eht) { 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]; if (eht) { data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU]; data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG]; data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU]; } for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++) data[ei++] += stats->tx_bw[i]; for (i = 0; i < (eht ? 14 : 12); i++) data[ei++] += stats->tx_mcs[i]; for (i = 0; i < 4; i++) data[ei++] += stats->tx_nss[i]; wi->worker_stat_count = ei - wi->initial_stat_idx; } EXPORT_SYMBOL_GPL(mt76_ethtool_worker); void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index) { #ifdef CONFIG_PAGE_POOL_STATS struct page_pool_stats stats = {}; int i; mt76_for_each_q_rx(dev, i) page_pool_get_stats(dev->q_rx[i].page_pool, &stats); page_pool_ethtool_stats_get(data, &stats); *index += page_pool_ethtool_stats_get_count(); #endif } EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats); enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) { struct ieee80211_hw *hw = phy->hw; struct mt76_dev *dev = phy->dev; if (dev->region == NL80211_DFS_UNSET || test_bit(MT76_SCANNING, &phy->state)) return MT_DFS_STATE_DISABLED; - if (!hw->conf.radar_enabled) { + if (!phy->radar_enabled) { if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) return MT_DFS_STATE_ACTIVE; return MT_DFS_STATE_DISABLED; } if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) return MT_DFS_STATE_CAC; return MT_DFS_STATE_ACTIVE; } EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); + +void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + + rcu_assign_pointer(mvif->link[0], NULL); + mt76_abort_scan(dev); + if (mvif->roc_phy) + mt76_abort_roc(mvif->roc_phy); +} +EXPORT_SYMBOL_GPL(mt76_vif_cleanup); diff --git a/sys/contrib/dev/mediatek/mt76/mcu.c b/sys/contrib/dev/mediatek/mt76/mcu.c index 8ff8b0f1de7b..f8f47a40d3be 100644 --- a/sys/contrib/dev/mediatek/mt76/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mcu.c @@ -1,138 +1,161 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2019 Lorenzo Bianconi */ #include "mt76.h" struct sk_buff * __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, int len, int data_len, gfp_t gfp) { const struct mt76_mcu_ops *ops = dev->mcu_ops; struct sk_buff *skb; len = max_t(int, len, data_len); len = ops->headroom + len + ops->tailroom; skb = alloc_skb(len, gfp); if (!skb) return NULL; memset(skb->head, 0, len); skb_reserve(skb, ops->headroom); if (data && data_len) skb_put_data(skb, data, data_len); return skb; } EXPORT_SYMBOL_GPL(__mt76_mcu_msg_alloc); struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, unsigned long expires) { unsigned long timeout; if (!time_is_after_jiffies(expires)) return NULL; timeout = expires - jiffies; wait_event_timeout(dev->mcu.wait, (!skb_queue_empty(&dev->mcu.res_q) || test_bit(MT76_MCU_RESET, &dev->phy.state)), timeout); return skb_dequeue(&dev->mcu.res_q); } EXPORT_SYMBOL_GPL(mt76_mcu_get_response); void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb) { skb_queue_tail(&dev->mcu.res_q, skb); wake_up(&dev->mcu.wait); } EXPORT_SYMBOL_GPL(mt76_mcu_rx_event); 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_skb) { struct sk_buff *skb; if (dev->mcu_ops->mcu_send_msg) return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp); skb = mt76_mcu_msg_alloc(dev, data, len); if (!skb) return -ENOMEM; return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb); } EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg); 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_skb) { + unsigned int retry = 0; + struct sk_buff *orig_skb = NULL; unsigned long expires; int ret, seq; if (ret_skb) *ret_skb = NULL; mutex_lock(&dev->mcu.mutex); + if (dev->mcu_ops->mcu_skb_prepare_msg) { + orig_skb = skb; + ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq); + if (ret < 0) + goto out; + } + +retry: + /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ + if (orig_skb) + skb_get(orig_skb); ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); if (ret < 0) goto out; if (!wait_resp) { ret = 0; goto out; } expires = jiffies + dev->mcu.timeout; do { skb = mt76_mcu_get_response(dev, expires); + if (!skb && !test_bit(MT76_MCU_RESET, &dev->phy.state) && + orig_skb && retry++ < dev->mcu_ops->max_retry) { + dev_err(dev->dev, "Retry message %08x (seq %d)\n", + cmd, seq); + skb = orig_skb; + goto retry; + } + ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq); if (!ret && ret_skb) *ret_skb = skb; else dev_kfree_skb(skb); } while (ret == -EAGAIN); + out: + dev_kfree_skb(orig_skb); mutex_unlock(&dev->mcu.mutex); return ret; } EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg); #if defined(__linux__) int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, #elif defined(__FreeBSD__) int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const u8 *data, #endif int len, int max_len) { int err, cur_len; while (len > 0) { cur_len = min_t(int, max_len, len); err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false); if (err) return err; data += cur_len; len -= cur_len; if (dev->queue_ops->tx_cleanup) dev->queue_ops->tx_cleanup(dev, dev->q_mcu[MT_MCUQ_FWDL], false); } return 0; } EXPORT_SYMBOL_GPL(__mt76_mcu_send_firmware); diff --git a/sys/contrib/dev/mediatek/mt76/mmio.c b/sys/contrib/dev/mediatek/mt76/mmio.c index 5176b497f5f6..48943686003c 100644 --- a/sys/contrib/dev/mediatek/mt76/mmio.c +++ b/sys/contrib/dev/mediatek/mt76/mmio.c @@ -1,121 +1,122 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include "mt76.h" +#include "dma.h" #include "trace.h" static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) { u32 val; #if defined(__linux__) val = readl(dev->mmio.regs + offset); #elif defined(__FreeBSD__) val = readl((u8 *)dev->mmio.regs + offset); #endif trace_reg_rr(dev, offset, val); return val; } static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val) { trace_reg_wr(dev, offset, val); #if defined(__linux__) writel(val, dev->mmio.regs + offset); #elif defined(__FreeBSD__) writel(val, (u8 *)dev->mmio.regs + offset); #endif } static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) { val |= mt76_mmio_rr(dev, offset) & ~mask; mt76_mmio_wr(dev, offset, val); return val; } static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { #if defined(__linux__) __iowrite32_copy(dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4)); #elif defined(__FreeBSD__) __iowrite32_copy((u8 *)dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4)); #endif } static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset, void *data, int len) { #if defined(__linux__) __ioread32_copy(data, dev->mmio.regs + offset, DIV_ROUND_UP(len, 4)); #elif defined(__FreeBSD__) __ioread32_copy(data, (u8 *)dev->mmio.regs + offset, DIV_ROUND_UP(len, 4)); #endif } static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *data, int len) { while (len > 0) { mt76_mmio_wr(dev, data->reg, data->value); data++; len--; } return 0; } static int mt76_mmio_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, int len) { while (len > 0) { data->value = mt76_mmio_rr(dev, data->reg); data++; len--; } return 0; } void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set) { unsigned long flags; spin_lock_irqsave(&dev->mmio.irq_lock, flags); dev->mmio.irqmask &= ~clear; dev->mmio.irqmask |= set; if (addr) { if (mtk_wed_device_active(&dev->mmio.wed)) mtk_wed_device_irq_set_mask(&dev->mmio.wed, dev->mmio.irqmask); else mt76_mmio_wr(dev, addr, dev->mmio.irqmask); } spin_unlock_irqrestore(&dev->mmio.irq_lock, flags); } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { .rr = mt76_mmio_rr, .rmw = mt76_mmio_rmw, .wr = mt76_mmio_wr, .write_copy = mt76_mmio_write_copy, .read_copy = mt76_mmio_read_copy, .wr_rp = mt76_mmio_wr_rp, .rd_rp = mt76_mmio_rd_rp, .type = MT76_BUS_MMIO, }; dev->bus = &mt76_mmio_ops; dev->mmio.regs = regs; spin_lock_init(&dev->mmio.irq_lock); } EXPORT_SYMBOL_GPL(mt76_mmio_init); diff --git a/sys/contrib/dev/mediatek/mt76/mt76.h b/sys/contrib/dev/mediatek/mt76/mt76.h index 72e47f9d6b05..c54d02346262 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76.h +++ b/sys/contrib/dev/mediatek/mt76/mt76.h @@ -1,1638 +1,1896 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau */ #ifndef __MT76_H #define __MT76_H #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #include #include #include #include #endif #include +#include #include "util.h" #include "testmode.h" #define MT_MCU_RING_SIZE 32 #define MT_RX_BUF_SIZE 2048 #define MT_SKB_HEAD_LEN 256 #define MT_MAX_NON_AQL_PKT 16 #define MT_TXQ_FREE_THR 32 #define MT76_TOKEN_FREE_THR 64 #define MT_QFLAG_WED_RING GENMASK(1, 0) -#define MT_QFLAG_WED_TYPE GENMASK(3, 2) -#define MT_QFLAG_WED BIT(4) +#define MT_QFLAG_WED_TYPE GENMASK(4, 2) +#define MT_QFLAG_WED BIT(5) +#define MT_QFLAG_WED_RRO BIT(6) +#define MT_QFLAG_WED_RRO_EN BIT(7) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ FIELD_PREP(MT_QFLAG_WED_RING, _n)) +#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n)) + #define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n) #define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n) #define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0) +#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) +#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) +#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) struct mt76_dev; struct mt76_phy; struct mt76_wcid; struct mt76s_intr; +struct mt76_chanctx; +struct mt76_vif_link; struct mt76_reg_pair { u32 reg; u32 value; }; enum mt76_bus_type { MT76_BUS_MMIO, MT76_BUS_USB, MT76_BUS_SDIO, }; enum mt76_wed_type { MT76_WED_Q_TX, MT76_WED_Q_TXFREE, MT76_WED_Q_RX, + MT76_WED_RRO_Q_DATA, + MT76_WED_RRO_Q_MSDU_PG, + MT76_WED_RRO_Q_IND, }; struct mt76_bus_ops { u32 (*rr)(struct mt76_dev *dev, u32 offset); void (*wr)(struct mt76_dev *dev, u32 offset, u32 val); u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val); void (*write_copy)(struct mt76_dev *dev, u32 offset, const void *data, int len); void (*read_copy)(struct mt76_dev *dev, u32 offset, void *data, int len); int (*wr_rp)(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *rp, int len); int (*rd_rp)(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *rp, int len); enum mt76_bus_type type; }; #define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB) #define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO) #define mt76_is_sdio(dev) ((dev)->bus->type == MT76_BUS_SDIO) enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, MT_TXQ_VI = IEEE80211_AC_VI, MT_TXQ_BE = IEEE80211_AC_BE, MT_TXQ_BK = IEEE80211_AC_BK, MT_TXQ_PSD, MT_TXQ_BEACON, MT_TXQ_CAB, __MT_TXQ_MAX }; enum mt76_mcuq_id { MT_MCUQ_WM, MT_MCUQ_WA, MT_MCUQ_FWDL, __MT_MCUQ_MAX }; enum mt76_rxq_id { MT_RXQ_MAIN, MT_RXQ_MCU, MT_RXQ_MCU_WA, MT_RXQ_BAND1, MT_RXQ_BAND1_WA, MT_RXQ_MAIN_WA, MT_RXQ_BAND2, MT_RXQ_BAND2_WA, + MT_RXQ_RRO_BAND0, + MT_RXQ_RRO_BAND1, + MT_RXQ_RRO_BAND2, + MT_RXQ_MSDU_PAGE_BAND0, + MT_RXQ_MSDU_PAGE_BAND1, + MT_RXQ_MSDU_PAGE_BAND2, + MT_RXQ_TXFREE_BAND0, + MT_RXQ_TXFREE_BAND1, + MT_RXQ_TXFREE_BAND2, + MT_RXQ_RRO_IND, __MT_RXQ_MAX }; enum mt76_band_id { MT_BAND0, MT_BAND1, MT_BAND2, __MT_MAX_BAND }; enum mt76_cipher_type { MT_CIPHER_NONE, MT_CIPHER_WEP40, MT_CIPHER_TKIP, MT_CIPHER_TKIP_NO_MIC, MT_CIPHER_AES_CCMP, MT_CIPHER_WEP104, MT_CIPHER_BIP_CMAC_128, MT_CIPHER_WEP128, MT_CIPHER_WAPI, MT_CIPHER_CCMP_CCX, MT_CIPHER_CCMP_256, MT_CIPHER_GCMP, MT_CIPHER_GCMP_256, }; enum mt76_dfs_state { MT_DFS_STATE_UNKNOWN, MT_DFS_STATE_DISABLED, MT_DFS_STATE_CAC, MT_DFS_STATE_ACTIVE, }; struct mt76_queue_buf { dma_addr_t addr; - u16 len; - bool skip_unmap; + u16 len:15, + skip_unmap:1; }; struct mt76_tx_info { struct mt76_queue_buf buf[32]; struct sk_buff *skb; int nbuf; u32 info; }; struct mt76_queue_entry { union { void *buf; struct sk_buff *skb; }; union { struct mt76_txwi_cache *txwi; struct urb *urb; int buf_sz; }; - u32 dma_addr[2]; + dma_addr_t dma_addr[2]; u16 dma_len[2]; u16 wcid; bool skip_buf0:1; bool skip_buf1:1; bool done:1; }; struct mt76_queue_regs { u32 desc_base; u32 ring_size; u32 cpu_idx; u32 dma_idx; } __packed __aligned(4); struct mt76_queue { struct mt76_queue_regs __iomem *regs; spinlock_t lock; spinlock_t cleanup_lock; struct mt76_queue_entry *entry; + struct mt76_rro_desc *rro_desc; struct mt76_desc *desc; u16 first; u16 head; u16 tail; + u8 hw_idx; + u8 ep; int ndesc; int queued; int buf_size; bool stopped; bool blocked; u8 buf_offset; - u8 hw_idx; - u8 flags; + u16 flags; + struct mtk_wed_device *wed; u32 wed_regs; dma_addr_t desc_dma; struct sk_buff *rx_head; struct page_pool *page_pool; }; struct mt76_mcu_ops { + unsigned int max_retry; u32 headroom; u32 tailroom; int (*mcu_send_msg)(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp); + int (*mcu_skb_prepare_msg)(struct mt76_dev *dev, struct sk_buff *skb, + int cmd, int *seq); int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, int cmd, int *seq); int (*mcu_parse_response)(struct mt76_dev *dev, int cmd, struct sk_buff *skb, int seq); u32 (*mcu_rr)(struct mt76_dev *dev, u32 offset); void (*mcu_wr)(struct mt76_dev *dev, u32 offset, u32 val); int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *rp, int len); int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *rp, int len); int (*mcu_restart)(struct mt76_dev *dev); }; struct mt76_queue_ops { int (*init)(struct mt76_dev *dev, int (*poll)(struct napi_struct *napi, int budget)); int (*alloc)(struct mt76_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize, u32 ring_base); - int (*tx_queue_skb)(struct mt76_dev *dev, struct mt76_queue *q, + int (*tx_queue_skb)(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta); int (*tx_queue_skb_raw)(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, u32 tx_info); void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush, int *len, u32 *info, bool *more); void (*rx_reset)(struct mt76_dev *dev, enum mt76_rxq_id qid); void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q, bool flush); void (*rx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q); void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q); }; enum mt76_phy_type { MT_PHY_TYPE_CCK, MT_PHY_TYPE_OFDM, MT_PHY_TYPE_HT, MT_PHY_TYPE_HT_GF, MT_PHY_TYPE_VHT, MT_PHY_TYPE_HE_SU = 8, MT_PHY_TYPE_HE_EXT_SU, MT_PHY_TYPE_HE_TB, MT_PHY_TYPE_HE_MU, MT_PHY_TYPE_EHT_SU = 13, MT_PHY_TYPE_EHT_TRIG, MT_PHY_TYPE_EHT_MU, __MT_PHY_TYPE_MAX, }; struct mt76_sta_stats { u64 tx_mode[__MT_PHY_TYPE_MAX]; u64 tx_bw[5]; /* 20, 40, 80, 160, 320 */ u64 tx_nss[4]; /* 1, 2, 3, 4 */ u64 tx_mcs[16]; /* mcs idx */ u64 tx_bytes; /* WED TX */ u32 tx_packets; /* unit: MSDU */ u32 tx_retries; u32 tx_failed; /* WED RX */ u64 rx_bytes; u32 rx_packets; u32 rx_errors; u32 rx_drops; }; enum mt76_wcid_flags { MT_WCID_FLAG_CHECK_PS, MT_WCID_FLAG_PS, MT_WCID_FLAG_4ADDR, MT_WCID_FLAG_HDR_TRANS, }; #define MT76_N_WCIDS 1088 /* stored in ieee80211_tx_info::hw_queue */ #define MT_TX_HW_QUEUE_PHY GENMASK(3, 2) DECLARE_EWMA(signal, 10, 8); #define MT_WCID_TX_INFO_RATE GENMASK(15, 0) #define MT_WCID_TX_INFO_NSS GENMASK(17, 16) #define MT_WCID_TX_INFO_TXPWR_ADJ GENMASK(25, 18) #define MT_WCID_TX_INFO_SET BIT(31) struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; atomic_t non_aql_packets; unsigned long flags; struct ewma_signal rssi; int inactive_count; struct rate_info rate; unsigned long ampdu_state; u16 idx; u8 hw_key_idx; u8 hw_key_idx2; u8 sta:1; + u8 sta_disabled:1; u8 amsdu:1; u8 phy_idx:2; + u8 link_id:4; + bool link_valid; u8 rx_check_pn; u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6]; u16 cipher; u32 tx_info; bool sw_iv; + struct list_head tx_list; + struct sk_buff_head tx_pending; + struct sk_buff_head tx_offchannel; + struct list_head list; struct idr pktid; struct mt76_sta_stats stats; struct list_head poll_list; + + struct mt76_wcid *def_wcid; }; struct mt76_txq { u16 wcid; u16 agg_ssn; bool send_bar; bool aggr; }; +struct mt76_wed_rro_ind { + u32 se_id : 12; + u32 rsv : 4; + u32 start_sn : 12; + u32 ind_reason : 4; + u32 ind_cnt : 13; + u32 win_sz : 3; + u32 rsv2 : 13; + u32 magic_cnt : 3; +}; + struct mt76_txwi_cache { struct list_head list; dma_addr_t dma_addr; union { struct sk_buff *skb; void *ptr; }; }; struct mt76_rx_tid { struct rcu_head rcu_head; struct mt76_dev *dev; spinlock_t lock; struct delayed_work reorder_work; + u16 id; u16 head; u16 size; u16 nframes; u8 num; u8 started:1, stopped:1, timer_pending:1; - struct sk_buff *reorder_buf[]; + struct sk_buff *reorder_buf[] __counted_by(size); }; #define MT_TX_CB_DMA_DONE BIT(0) #define MT_TX_CB_TXS_DONE BIT(1) #define MT_TX_CB_TXS_FAILED BIT(2) #define MT_PACKET_ID_MASK GENMASK(6, 0) #define MT_PACKET_ID_NO_ACK 0 #define MT_PACKET_ID_NO_SKB 1 #define MT_PACKET_ID_WED 2 #define MT_PACKET_ID_FIRST 3 #define MT_PACKET_ID_HAS_RATE BIT(7) /* 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; u16 wcid; u8 pktid; u8 flags; }; enum { MT76_STATE_INITIALIZED, MT76_STATE_REGISTERED, MT76_STATE_RUNNING, MT76_STATE_MCU_RUNNING, MT76_SCANNING, MT76_HW_SCANNING, MT76_HW_SCHED_SCANNING, MT76_RESTART, MT76_RESET, MT76_MCU_RESET, MT76_REMOVED, MT76_READING_STATS, MT76_STATE_POWER_OFF, MT76_STATE_SUSPEND, MT76_STATE_ROC, MT76_STATE_PM, MT76_STATE_WED_RESET, }; +enum mt76_sta_event { + MT76_STA_EVENT_ASSOC, + MT76_STA_EVENT_AUTHORIZE, + MT76_STA_EVENT_DISASSOC, +}; + struct mt76_hw_cap { bool has_2ghz; bool has_5ghz; bool has_6ghz; }; #define MT_DRV_TXWI_NO_FREE BIT(0) #define MT_DRV_TX_ALIGNED4_SKBS BIT(1) #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; u32 survey_flags; u16 txwi_size; u16 token_size; u8 mcs_rates; + unsigned int link_data_size; + void (*update_survey)(struct mt76_phy *phy); + int (*set_channel)(struct mt76_phy *phy); int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info); void (*tx_complete_skb)(struct mt76_dev *dev, struct mt76_queue_entry *e); bool (*tx_status_data)(struct mt76_dev *dev, u8 *update); bool (*rx_check)(struct mt76_dev *dev, void *data, int len); void (*rx_skb)(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q); void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); int (*sta_add)(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); - void (*sta_assoc)(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + int (*sta_event)(struct mt76_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); void (*sta_remove)(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); + + int (*vif_link_add)(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); + + void (*vif_link_remove)(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); }; struct mt76_channel_state { u64 cc_active; u64 cc_busy; u64 cc_rx; u64 cc_bss_rx; u64 cc_tx; s8 noise; }; struct mt76_sband { struct ieee80211_supported_band sband; struct mt76_channel_state *chan; }; /* addr req mask */ #define MT_VEND_TYPE_EEPROM BIT(31) #define MT_VEND_TYPE_CFG BIT(30) #define MT_VEND_TYPE_MASK (MT_VEND_TYPE_EEPROM | MT_VEND_TYPE_CFG) #define MT_VEND_ADDR(type, n) (MT_VEND_TYPE_##type | (n)) enum mt_vendor_req { MT_VEND_DEV_MODE = 0x1, MT_VEND_WRITE = 0x2, MT_VEND_POWER_ON = 0x4, MT_VEND_MULTI_WRITE = 0x6, MT_VEND_MULTI_READ = 0x7, MT_VEND_READ_EEPROM = 0x9, MT_VEND_WRITE_FCE = 0x42, MT_VEND_WRITE_CFG = 0x46, MT_VEND_READ_CFG = 0x47, MT_VEND_READ_EXT = 0x63, MT_VEND_WRITE_EXT = 0x66, MT_VEND_FEATURE_SET = 0x91, }; enum mt76u_in_ep { MT_EP_IN_PKT_RX, MT_EP_IN_CMD_RESP, __MT_EP_IN_MAX, }; enum mt76u_out_ep { MT_EP_OUT_INBAND_CMD, MT_EP_OUT_AC_BE, MT_EP_OUT_AC_BK, MT_EP_OUT_AC_VI, MT_EP_OUT_AC_VO, MT_EP_OUT_HCCA, __MT_EP_OUT_MAX, }; struct mt76_mcu { struct mutex mutex; u32 msg_seq; int timeout; struct sk_buff_head res_q; wait_queue_head_t wait; }; #define MT_TX_SG_MAX_SIZE 8 #define MT_RX_SG_MAX_SIZE 4 #define MT_NUM_TX_ENTRIES 256 #define MT_NUM_RX_ENTRIES 128 #define MCU_RESP_URB_SIZE 1024 struct mt76_usb { struct mutex usb_ctrl_mtx; u8 *data; u16 data_len; struct mt76_worker status_worker; struct mt76_worker rx_worker; struct work_struct stat_work; u8 out_ep[__MT_EP_OUT_MAX]; u8 in_ep[__MT_EP_IN_MAX]; bool sg_en; struct mt76u_mcu { u8 *data; /* multiple reads */ struct mt76_reg_pair *rp; int rp_len; u32 base; } mcu; }; #define MT76S_XMIT_BUF_SZ 0x3fe00 #define MT76S_NUM_TX_ENTRIES 256 #define MT76S_NUM_RX_ENTRIES 512 struct mt76_sdio { struct mt76_worker txrx_worker; struct mt76_worker status_worker; struct mt76_worker net_worker; - - struct work_struct stat_work; + struct mt76_worker stat_worker; u8 *xmit_buf; u32 xmit_buf_sz; struct sdio_func *func; void *intr_data; u8 hw_ver; wait_queue_head_t wait; + int pse_mcu_quota_max; 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 { void __iomem *regs; spinlock_t irq_lock; u32 irqmask; struct mtk_wed_device wed; + struct mtk_wed_device wed_hif2; struct completion wed_reset; struct completion wed_reset_complete; }; struct mt76_rx_status { union { struct mt76_wcid *wcid; u16 wcid_idx; }; u32 reorder_time; u32 ampdu_ref; u32 timestamp; u8 iv[6]; u8 phy_idx:2; u8 aggr:1; u8 qos_ctl; u16 seqno; u16 freq; u32 flag; u8 enc_flags; u8 encoding:3, bw:4; union { struct { u8 he_ru:3; u8 he_gi:2; u8 he_dcm:1; }; struct { u8 ru:4; u8 gi:2; } eht; }; u8 amsdu:1, first_amsdu:1, last_amsdu:1; u8 rate_idx; u8 nss:5, band:3; s8 signal; u8 chains; 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, enum mt76_testmode_state new_state); int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg); }; struct mt76_testmode_data { enum mt76_testmode_state state; u32 param_set[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)]; struct sk_buff *tx_skb; u32 tx_count; u16 tx_mpdu_len; u8 tx_rate_mode; u8 tx_rate_idx; u8 tx_rate_nss; u8 tx_rate_sgi; u8 tx_rate_ldpc; u8 tx_rate_stbc; u8 tx_ltf; u8 tx_antenna_mask; u8 tx_spe_idx; u8 tx_duty_cycle; u32 tx_time; u32 tx_ipg; u32 freq_offset; u8 tx_power[4]; u8 tx_power_control; u8 addr[3][ETH_ALEN]; u32 tx_pending; u32 tx_queued; u16 tx_queued_limit; u32 tx_done; struct { u64 packets[__MT_RXQ_MAX]; u64 fcs_error[__MT_RXQ_MAX]; } rx_stats; }; -struct mt76_vif { +struct mt76_vif_link { u8 idx; u8 omac_idx; u8 band_idx; u8 wmm_idx; u8 scan_seq_num; u8 cipher; u8 basic_rates_idx; u8 mcast_rates_idx; u8 beacon_rates_idx; + bool offchannel; + struct ieee80211_chanctx_conf *ctx; + struct mt76_wcid *wcid; + struct mt76_vif_data *mvif; + struct rcu_head rcu_head; +}; + +struct mt76_vif_data { + struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + + struct mt76_phy *roc_phy; + u16 valid_links; + u8 deflink_id; }; struct mt76_phy { struct ieee80211_hw *hw; struct mt76_dev *dev; void *priv; unsigned long state; + unsigned int num_sta; u8 band_idx; + spinlock_t tx_lock; + struct list_head tx_list; struct mt76_queue *q_tx[__MT_TXQ_MAX]; struct cfg80211_chan_def chandef; - struct ieee80211_channel *main_chan; + struct cfg80211_chan_def main_chandef; + bool offchannel; + bool radar_enabled; + + struct delayed_work roc_work; + struct ieee80211_vif *roc_vif; + struct mt76_vif_link *roc_link; + + struct mt76_chanctx *chanctx; struct mt76_channel_state *chan_state; enum mt76_dfs_state dfs_state; ktime_t survey_time; u32 aggr_stats[32]; struct mt76_hw_cap cap; struct mt76_sband sband_2g; struct mt76_sband sband_5g; struct mt76_sband sband_6g; u8 macaddr[ETH_ALEN]; int txpower_cur; u8 antenna_mask; u16 chainmask; #ifdef CONFIG_NL80211_TESTMODE struct mt76_testmode_data test; #endif struct delayed_work mac_work; u8 mac_work_count; struct { struct sk_buff *head; struct sk_buff **tail; u16 seqno; } rx_amsdu[__MT_RXQ_MAX]; struct mt76_freq_range_power *frp; struct { struct led_classdev cdev; char name[32]; bool al; u8 pin; } leds; }; struct mt76_dev { struct mt76_phy phy; /* must be first */ struct mt76_phy *phys[__MT_MAX_BAND]; + struct mt76_phy *band_phys[NUM_NL80211_BANDS]; struct ieee80211_hw *hw; spinlock_t wed_lock; spinlock_t lock; spinlock_t cc_lock; u32 cur_cc_bss_rx; struct mt76_rx_status rx_ampdu_status; u32 rx_ampdu_len; u32 rx_ampdu_ref; struct mutex mutex; const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; const struct mt76_mcu_ops *mcu_ops; struct device *dev; struct device *dma_dev; struct mt76_mcu mcu; - struct net_device napi_dev; - struct net_device tx_napi_dev; + struct net_device *napi_dev; + struct net_device *tx_napi_dev; spinlock_t rx_lock; struct napi_struct napi[__MT_RXQ_MAX]; struct sk_buff_head rx_skb[__MT_RXQ_MAX]; struct tasklet_struct irq_tasklet; struct list_head txwi_cache; struct list_head rxwi_cache; struct mt76_queue *q_mcu[__MT_MCUQ_MAX]; struct mt76_queue q_rx[__MT_RXQ_MAX]; const struct mt76_queue_ops *queue_ops; int tx_dma_idx[4]; struct mt76_worker tx_worker; struct napi_struct tx_napi; spinlock_t token_lock; struct idr token; u16 wed_token_count; u16 token_count; u16 token_size; spinlock_t rx_token_lock; struct idr rx_token; u16 rx_token_size; wait_queue_head_t tx_wait; /* 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)]; u64 vif_mask; struct mt76_wcid global_wcid; struct mt76_wcid __rcu *wcid[MT76_N_WCIDS]; struct list_head wcid_list; struct list_head sta_poll_list; spinlock_t sta_poll_lock; u32 rev; struct tasklet_struct pre_tbtt_tasklet; int beacon_int; u8 beacon_mask; struct debugfs_blob_wrapper eeprom; struct debugfs_blob_wrapper otp; char alpha2[3]; enum nl80211_dfs_regions region; u32 debugfs_reg; u8 csa_complete; u32 rxfilter; + struct delayed_work scan_work; + struct { + struct cfg80211_scan_request *req; + struct ieee80211_channel *chan; + struct ieee80211_vif *vif; + struct mt76_vif_link *mlink; + struct mt76_phy *phy; + int chan_idx; + } scan; + #ifdef CONFIG_NL80211_TESTMODE const struct mt76_testmode_ops *test_ops; struct { const char *name; u32 offset; } test_mtd; #endif struct workqueue_struct *wq; union { struct mt76_mmio mmio; struct mt76_usb usb; struct mt76_sdio sdio; }; }; /* per-phy stats. */ struct mt76_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_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_eht_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 primary_cca_busy_time; u32 secondary_cca_busy_time; u32 primary_energy_detect_time; u32 cck_mdrdy_time; u32 ofdm_mdrdy_time; u32 green_mdrdy_time; u32 rx_vector_mismatch_cnt; u32 rx_delimiter_fail_cnt; u32 rx_mrdy_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; /* mcu_muru_stats */ u32 dl_cck_cnt; u32 dl_ofdm_cnt; u32 dl_htmix_cnt; u32 dl_htgf_cnt; u32 dl_vht_su_cnt; u32 dl_vht_2mu_cnt; u32 dl_vht_3mu_cnt; u32 dl_vht_4mu_cnt; u32 dl_he_su_cnt; u32 dl_he_ext_su_cnt; u32 dl_he_2ru_cnt; u32 dl_he_2mu_cnt; u32 dl_he_3ru_cnt; u32 dl_he_3mu_cnt; u32 dl_he_4ru_cnt; u32 dl_he_4mu_cnt; u32 dl_he_5to8ru_cnt; u32 dl_he_9to16ru_cnt; u32 dl_he_gtr16ru_cnt; u32 ul_hetrig_su_cnt; u32 ul_hetrig_2ru_cnt; u32 ul_hetrig_3ru_cnt; u32 ul_hetrig_4ru_cnt; u32 ul_hetrig_5to8ru_cnt; u32 ul_hetrig_9to16ru_cnt; u32 ul_hetrig_gtr16ru_cnt; u32 ul_hetrig_2mu_cnt; u32 ul_hetrig_3mu_cnt; u32 ul_hetrig_4mu_cnt; }; struct mt76_power_limits { s8 cck[4]; s8 ofdm[8]; s8 mcs[4][10]; s8 ru[7][12]; + s8 eht[16][16]; }; struct mt76_ethtool_worker_info { u64 *data; int idx; int initial_stat_idx; int worker_stat_count; int sta_count; }; +struct mt76_chanctx { + struct mt76_phy *phy; +}; + #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + _idx), \ } #define OFDM_RATE(_idx, _rate) { \ .bitrate = _rate, \ .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ } extern struct ieee80211_rate mt76_rates[12]; #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) #define __mt76_wr_copy(dev, ...) (dev)->bus->write_copy((dev), __VA_ARGS__) #define __mt76_rr_copy(dev, ...) (dev)->bus->read_copy((dev), __VA_ARGS__) #define __mt76_set(dev, offset, val) __mt76_rmw(dev, offset, 0, val) #define __mt76_clear(dev, offset, val) __mt76_rmw(dev, offset, val, 0) #define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) #define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) #define mt76_wr_copy(dev, ...) (dev)->mt76.bus->write_copy(&((dev)->mt76), __VA_ARGS__) #define mt76_rr_copy(dev, ...) (dev)->mt76.bus->read_copy(&((dev)->mt76), __VA_ARGS__) #define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__) #define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__) #define mt76_mcu_restart(dev, ...) (dev)->mt76.mcu_ops->mcu_restart(&((dev)->mt76)) #define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val) #define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0) #define mt76_get_field(_dev, _reg, _field) \ FIELD_GET(_field, mt76_rr(dev, _reg)) #define mt76_rmw_field(_dev, _reg, _field, _val) \ mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) #define __mt76_rmw_field(_dev, _reg, _field, _val) \ __mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val)) #define mt76_hw(dev) (dev)->mphy.hw bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, int timeout); #define mt76_poll(dev, ...) __mt76_poll(&((dev)->mt76), __VA_ARGS__) bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, int timeout, int kick); #define __mt76_poll_msec(...) ____mt76_poll_msec(__VA_ARGS__, 10) #define mt76_poll_msec(dev, ...) ____mt76_poll_msec(&((dev)->mt76), __VA_ARGS__, 10) #define mt76_poll_msec_tick(dev, ...) ____mt76_poll_msec(&((dev)->mt76), __VA_ARGS__) void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); +bool mt76_pci_aspm_supported(struct pci_dev *pdev); static inline u16 mt76_chip(struct mt76_dev *dev) { return dev->rev >> 16; } static inline u16 mt76_rev(struct mt76_dev *dev) { return dev->rev & 0xffff; } +void mt76_wed_release_rx_buf(struct mtk_wed_device *wed); +void mt76_wed_offload_disable(struct mtk_wed_device *wed); +void mt76_wed_reset_complete(struct mtk_wed_device *wed); +void mt76_wed_dma_reset(struct mt76_dev *dev); +int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size); +int mt76_wed_offload_enable(struct mtk_wed_device *wed); +int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +#else +static inline u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + return 0; +} + +static inline int mt76_wed_offload_enable(struct mtk_wed_device *wed) +{ + return 0; +} + +static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, + bool reset) +{ + return 0; +} +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) #define mt76_init_queues(dev, ...) (dev)->mt76.queue_ops->init(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__) #define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__) -#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mt76), __VA_ARGS__) +#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mphy), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_cleanup(dev, ...) (dev)->mt76.queue_ops->rx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__) #define mt76_for_each_q_rx(dev, i) \ for (i = 0; i < ARRAY_SIZE((dev)->q_rx); i++) \ if ((dev)->q_rx[i].ndesc) + +#define mt76_dereference(p, dev) \ + rcu_dereference_protected(p, lockdep_is_held(&(dev)->mutex)) + struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size, const struct ieee80211_ops *ops, const struct mt76_driver_ops *drv_ops); int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); void mt76_free_device(struct mt76_dev *dev); void mt76_unregister_phy(struct mt76_phy *phy); +struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size, + u8 band_idx); struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, const struct ieee80211_ops *ops, u8 band_idx); int mt76_register_phy(struct mt76_phy *phy, bool vht, struct ieee80211_rate *rates, int n_rates); 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); int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags); -u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx); + int ring_base, void *wed, u32 flags); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, - int n_desc, int ring_base, u32 flags) + int n_desc, int ring_base, void *wed, + u32 flags) { struct mt76_queue *q; - q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags); + q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags); if (IS_ERR(q)) return PTR_ERR(q); phy->q_tx[qid] = q; return 0; } static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, int ring_base) { struct mt76_queue *q; - q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0); + q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0); if (IS_ERR(q)) return PTR_ERR(q); dev->q_mcu[qid] = q; return 0; } static inline struct mt76_phy * mt76_dev_phy(struct mt76_dev *dev, u8 phy_idx) { if ((phy_idx == MT_BAND1 && dev->phys[phy_idx]) || (phy_idx == MT_BAND2 && dev->phys[phy_idx])) return dev->phys[phy_idx]; return &dev->phy; } static inline struct ieee80211_hw * mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx) { return mt76_dev_phy(dev, phy_idx)->hw; } static inline u8 * mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t) { return (u8 *)t - dev->drv->txwi_size; } /* increment with wrap-around */ static inline int mt76_incr(int val, int size) { return (val + 1) & (size - 1); } /* decrement with wrap-around */ static inline int mt76_decr(int val, int size) { return (val - 1) & (size - 1); } u8 mt76_ac_to_hwq(u8 ac); static inline struct ieee80211_txq * mtxq_to_txq(struct mt76_txq *mtxq) { void *ptr = mtxq; return container_of(ptr, struct ieee80211_txq, drv_priv); } static inline struct ieee80211_sta * wcid_to_sta(struct mt76_wcid *wcid) { void *ptr = wcid; if (!wcid || !wcid->sta) return NULL; + if (wcid->def_wcid) + ptr = wcid->def_wcid; + return container_of(ptr, struct ieee80211_sta, drv_priv); } static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb) { BUILD_BUG_ON(sizeof(struct mt76_tx_cb) > sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data)); return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data); } static inline void *mt76_skb_get_hdr(struct sk_buff *skb) { struct mt76_rx_status mstat; u8 *data = skb->data; /* Alignment concerns */ BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4); BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4); mstat = *((struct mt76_rx_status *)skb->cb); if (mstat.flag & RX_FLAG_RADIOTAP_HE) data += sizeof(struct ieee80211_radiotap_he); if (mstat.flag & RX_FLAG_RADIOTAP_HE_MU) data += sizeof(struct ieee80211_radiotap_he_mu); return data; } static inline void mt76_insert_hdr_pad(struct sk_buff *skb) { int len = ieee80211_get_hdrlen_from_skb(skb); if (len % 4 == 0) return; skb_push(skb, 2); memmove(skb->data, skb->data + 2, len); skb->data[len] = 0; skb->data[len + 1] = 0; } static inline bool mt76_is_skb_pktid(u8 pktid) { if (pktid & MT_PACKET_ID_HAS_RATE) return false; return pktid >= MT_PACKET_ID_FIRST; } static inline u8 mt76_tx_power_nss_delta(u8 nss) { static const u8 nss_delta[4] = { 0, 6, 9, 12 }; u8 idx = nss - 1; return (idx < ARRAY_SIZE(nss_delta)) ? nss_delta[idx] : 0; } static inline bool mt76_testmode_enabled(struct mt76_phy *phy) { #ifdef CONFIG_NL80211_TESTMODE return phy->test.state != MT76_TM_STATE_OFF; #else return false; #endif } static inline bool mt76_is_testmode_skb(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_hw **hw) { #ifdef CONFIG_NL80211_TESTMODE int i; for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { struct mt76_phy *phy = dev->phys[i]; if (phy && skb == phy->test.tx_skb) { *hw = dev->phys[i]->hw; return true; } } return false; #else return false; #endif } void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb); void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb); void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq); void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, bool send_bar); void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); void mt76_txq_schedule_all(struct mt76_phy *phy); void mt76_tx_worker_run(struct mt76_dev *dev); void mt76_tx_worker(struct mt76_worker *w); void mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data); bool mt76_has_tx_pending(struct mt76_phy *phy); -void mt76_set_channel(struct mt76_phy *phy); +int mt76_update_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_phy *phy); void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); int mt76_rx_signal(u8 chain_mask, s8 *chain_signal); void mt76_set_stream_caps(struct mt76_phy *phy, bool vht); int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid, u16 ssn, u16 size); void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid); 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_lock); void mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list) __releases(&dev->status_lock); int mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb); struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, struct sk_buff_head *list); void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, struct sk_buff_head *list); void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb, struct list_head *free_list); static inline void 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, bool flush); int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state); -void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, +void __mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy); +int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx); int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - int *dbm); + unsigned int link_id, int *dbm); int mt76_init_sar_power(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); int mt76_get_sar_power(struct mt76_phy *phy, struct ieee80211_channel *chan, int power); void mt76_csa_check(struct mt76_dev *dev); void mt76_csa_finish(struct mt76_dev *dev); int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); int mt76_get_rate(struct mt76_dev *dev, struct ieee80211_supported_band *sband, int idx, bool cck); +int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req); +void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy); +int mt76_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void mt76_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void mt76_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed); +int mt76_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf); +void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *conf); +int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode); +int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_channel *chan, int duration, + enum ieee80211_roc_type type); +int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len); int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state); int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len); static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable) { #ifdef CONFIG_NL80211_TESTMODE enum mt76_testmode_state state = MT76_TM_STATE_IDLE; if (disable || phy->test.state == MT76_TM_STATE_OFF) state = MT76_TM_STATE_OFF; mt76_testmode_set_state(phy, state); #endif } /* internal */ static inline struct ieee80211_hw * mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; struct ieee80211_hw *hw = mt76_phy_hw(dev, phy_idx); info->hw_queue &= ~MT_TX_HW_QUEUE_PHY; return hw; } void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t); void mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t); struct mt76_txwi_cache *mt76_get_rxwi(struct mt76_dev *dev); void mt76_free_pending_rxwi(struct mt76_dev *dev); void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, struct napi_struct *napi); void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi); void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames); void mt76_testmode_tx_pending(struct mt76_phy *phy); void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *e); +int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + bool offchannel); +int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, + bool offchannel); +void mt76_scan_work(struct work_struct *work); +void mt76_abort_scan(struct mt76_dev *dev); +void mt76_roc_complete_work(struct work_struct *work); +void mt76_abort_roc(struct mt76_phy *phy); +struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, + struct ieee80211_vif *vif); +void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct mt76_vif_link *mlink); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) { return urb->status && urb->status != -ECONNRESET && urb->status != -ESHUTDOWN && urb->status != -ENOENT; } -/* Map hardware queues to usb endpoints */ -static inline u8 q2ep(u8 qid) -{ - /* TODO: take management packets to queue 5 */ - return qid + 1; -} - static inline int mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, int timeout, int ep) { #if defined(__FreeBSD__) && !defined(CONFIG_USB) return (0); #else struct usb_interface *uintf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(uintf); struct mt76_usb *usb = &dev->usb; unsigned int pipe; if (actual_len) pipe = usb_rcvbulkpipe(udev, usb->in_ep[ep]); else pipe = usb_sndbulkpipe(udev, usb->out_ep[ep]); return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout); #endif } void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index); void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, struct mt76_sta_stats *stats, bool eht); 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, void *buf, size_t len); int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len); void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val); void mt76u_read_copy(struct mt76_dev *dev, u32 offset, void *data, int len); u32 ___mt76u_rr(struct mt76_dev *dev, u8 req, u8 req_type, u32 addr); void ___mt76u_wr(struct mt76_dev *dev, u8 req, u8 req_type, u32 addr, u32 val); int __mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, struct mt76_bus_ops *ops); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf); int mt76u_alloc_mcu_queue(struct mt76_dev *dev); int mt76u_alloc_queues(struct mt76_dev *dev); void mt76u_stop_tx(struct mt76_dev *dev); void mt76u_stop_rx(struct mt76_dev *dev); int mt76u_resume_rx(struct mt76_dev *dev); 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_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, int len, int data_len, gfp_t gfp); static inline struct sk_buff * mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, int data_len) { return __mt76_mcu_msg_alloc(dev, data, data_len, data_len, GFP_KERNEL); } void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb); struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev, unsigned long expires); 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); #if defined(__linux__) int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data, #elif defined(__FreeBSD__) int __mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const u8 *data, #endif 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) { return mt76_mcu_send_and_get_msg(dev, cmd, data, len, wait_resp, NULL); } static inline int mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp) { return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, NULL); } void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set); +struct device_node * +mt76_find_power_limits_node(struct mt76_dev *dev); +struct device_node * +mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan); + s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct ieee80211_channel *chan, struct mt76_power_limits *dest, s8 target_power); -static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +static inline bool mt76_queue_is_rx(struct mt76_dev *dev, struct mt76_queue *q) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) { + if (q == &dev->q_rx[i]) + return true; + } + + return false; +} + +static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) { return (q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; +} + +static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_WED_RRO; +} + +static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; +} + +static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); +} + +static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +{ + if (!(q->flags & MT_QFLAG_WED)) + return false; + + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || + mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); + } struct mt76_txwi_cache * mt76_token_release(struct mt76_dev *dev, int token, bool *wake); int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi); void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked); struct mt76_txwi_cache *mt76_rx_token_release(struct mt76_dev *dev, int token); int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr, struct mt76_txwi_cache *r, dma_addr_t phys); int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q); static inline void mt76_put_page_pool_buf(void *buf, bool allow_direct) { struct page *page = virt_to_head_page(buf); page_pool_put_full_page(page->pp, page, allow_direct); } static inline void * mt76_get_page_pool_buf(struct mt76_queue *q, u32 *offset, u32 size) { struct page *page; page = page_pool_dev_alloc_frag(q->page_pool, offset, size); if (!page) return NULL; #if defined(__linux__) return page_address(page) + *offset; #elif defined(__FreeBSD__) return (void *)((uintptr_t)page_address(page) + *offset); #endif } static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked) { spin_lock_bh(&dev->token_lock); __mt76_set_tx_blocked(dev, blocked); spin_unlock_bh(&dev->token_lock); } static inline int mt76_token_get(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi) { int token; spin_lock_bh(&dev->token_lock); token = idr_alloc(&dev->token, *ptxwi, 0, dev->token_size, GFP_ATOMIC); spin_unlock_bh(&dev->token_lock); return token; } static inline struct mt76_txwi_cache * mt76_token_put(struct mt76_dev *dev, int token) { struct mt76_txwi_cache *txwi; spin_lock_bh(&dev->token_lock); txwi = idr_remove(&dev->token, token); spin_unlock_bh(&dev->token_lock); return txwi; } -static inline void mt76_packet_id_init(struct mt76_wcid *wcid) +void mt76_wcid_init(struct mt76_wcid *wcid, u8 band_idx); +void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid); +void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid); + +static inline void +mt76_vif_init(struct ieee80211_vif *vif, struct mt76_vif_data *mvif) { - INIT_LIST_HEAD(&wcid->list); - idr_init(&wcid->pktid); + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + + mlink->mvif = mvif; + rcu_assign_pointer(mvif->link[0], mlink); } -static inline void -mt76_packet_id_flush(struct mt76_dev *dev, struct mt76_wcid *wcid) +void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif); + +static inline struct mt76_vif_link * +mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + + return mt76_dereference(mvif->link[link_id], dev); +} + +static inline struct mt76_vif_link * +mt76_vif_conf_link(struct mt76_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { - struct sk_buff_head list; + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + + if (link_conf == &vif->bss_conf) + return mlink; + + return mt76_dereference(mvif->link[link_conf->link_id], dev); +} + +static inline struct mt76_phy * +mt76_vif_link_phy(struct mt76_vif_link *mlink) +{ + struct mt76_chanctx *ctx; + + if (!mlink->ctx) + return NULL; - mt76_tx_status_lock(dev, &list); - mt76_tx_status_skb_get(dev, wcid, -1, &list); - mt76_tx_status_unlock(dev, &list); + ctx = (struct mt76_chanctx *)mlink->ctx->drv_priv; - idr_destroy(&wcid->pktid); + return ctx->phy; } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/beacon.c b/sys/contrib/dev/mediatek/mt76/mt7603/beacon.c index 888678732f29..6457ee06bb5a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/beacon.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/beacon.c @@ -1,191 +1,225 @@ // SPDX-License-Identifier: ISC #include "mt7603.h" struct beacon_bc_data { struct mt7603_dev *dev; struct sk_buff_head q; struct sk_buff *tail[MT7603_MAX_INTERFACES]; int count[MT7603_MAX_INTERFACES]; }; +static void +mt7603_mac_stuck_beacon_recovery(struct mt7603_dev *dev) +{ + if (dev->beacon_check % 5 != 4) + return; + + mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); + mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET); + mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET); + mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); + + mt76_set(dev, MT_WF_CFG_OFF_WOCCR, MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS); + mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE); + mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE); + mt76_clear(dev, MT_WF_CFG_OFF_WOCCR, MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS); +} + static void mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7603_dev *dev = (struct mt7603_dev *)priv; struct mt76_dev *mdev = &dev->mt76; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct sk_buff *skb = NULL; + u32 om_idx = mvif->idx; + u32 val; if (!(mdev->beacon_mask & BIT(mvif->idx))) return; skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; - mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], - MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL); + if (om_idx) + om_idx |= 0x10; + val = MT_DMA_FQCR0_BUSY | MT_DMA_FQCR0_MODE | + FIELD_PREP(MT_DMA_FQCR0_TARGET_BSS, om_idx) | + FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) | + FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8); spin_lock_bh(&dev->ps_lock); - mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY | - FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) | - FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, - dev->mphy.q_tx[MT_TXQ_CAB]->hw_idx) | - FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) | - FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8)); - if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) + mt76_wr(dev, MT_DMA_FQCR0, val | + FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BCN)); + if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) { dev->beacon_check = MT7603_WATCHDOG_TIMEOUT; + goto out; + } + + mt76_wr(dev, MT_DMA_FQCR0, val | + FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BMC)); + if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) { + dev->beacon_check = MT7603_WATCHDOG_TIMEOUT; + goto out; + } + mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], + MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL); + +out: spin_unlock_bh(&dev->ps_lock); } static void mt7603_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct beacon_bc_data *data = priv; struct mt7603_dev *dev = data->dev; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct ieee80211_tx_info *info; struct sk_buff *skb; if (!(dev->mt76.beacon_mask & BIT(mvif->idx))) return; skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); if (!skb) return; info = IEEE80211_SKB_CB(skb); info->control.vif = vif; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; mt76_skb_set_moredata(skb, true); __skb_queue_tail(&data->q, skb); data->tail[mvif->idx] = skb; data->count[mvif->idx]++; } void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t) { struct mt7603_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet); struct mt76_dev *mdev = &dev->mt76; struct mt76_queue *q; struct beacon_bc_data data = {}; struct sk_buff *skb; int i, nframes; - if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) + if (dev->mphy.offchannel) return; data.dev = dev; __skb_queue_head_init(&data.q); + /* Flush all previous CAB queue packets and beacons */ + mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0)); + + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false); + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false); + + if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > 0) + dev->beacon_check++; + else + dev->beacon_check = 0; + mt7603_mac_stuck_beacon_recovery(dev); + q = dev->mphy.q_tx[MT_TXQ_BEACON]; spin_lock(&q->lock); ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt7603_update_beacon_iter, dev); mt76_queue_kick(dev, q); spin_unlock(&q->lock); - /* Flush all previous CAB queue packets */ - mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0)); - - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false); - mt76_csa_check(mdev); if (mdev->csa_complete) - goto out; + return; q = dev->mphy.q_tx[MT_TXQ_CAB]; do { nframes = skb_queue_len(&data.q); ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt7603_add_buffered_bc, &data); } while (nframes != skb_queue_len(&data.q) && skb_queue_len(&data.q) < 8); if (skb_queue_empty(&data.q)) - goto out; + return; for (i = 0; i < ARRAY_SIZE(data.tail); i++) { if (!data.tail[i]) continue; mt76_skb_set_moredata(data.tail[i], false); } 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; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; mt76_tx_queue_skb(dev, q, MT_TXQ_CAB, skb, &mvif->sta.wcid, NULL); } mt76_queue_kick(dev, q); spin_unlock(&q->lock); for (i = 0; i < ARRAY_SIZE(data.count); i++) mt76_wr(dev, MT_WF_ARB_CAB_COUNT_B0_REG(i), data.count[i] << MT_WF_ARB_CAB_COUNT_B0_SHIFT(i)); mt76_wr(dev, MT_WF_ARB_CAB_START, MT_WF_ARB_CAB_START_BSSn(0) | (MT_WF_ARB_CAB_START_BSS0n(1) * ((1 << (MT7603_MAX_INTERFACES - 1)) - 1))); - -out: - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false); - if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > hweight8(mdev->beacon_mask)) - dev->beacon_check++; } void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval) { u32 pre_tbtt = MT7603_PRE_TBTT_TIME / 64; if (idx >= 0) { if (intval) dev->mt76.beacon_mask |= BIT(idx); else dev->mt76.beacon_mask &= ~BIT(idx); } if (!dev->mt76.beacon_mask || (!intval && idx < 0)) { mt7603_irq_disable(dev, MT_INT_MAC_IRQ3); mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK); mt76_wr(dev, MT_HW_INT_MASK(3), 0); return; } if (intval) dev->mt76.beacon_int = intval; mt76_wr(dev, MT_TBTT, FIELD_PREP(MT_TBTT_PERIOD, intval) | MT_TBTT_CAL_ENABLE); mt76_wr(dev, MT_TBTT_TIMER_CFG, 0x99); /* start timer */ mt76_rmw_field(dev, MT_ARB_SCR, MT_ARB_SCR_BCNQ_OPMODE_MASK, MT_BCNQ_OPMODE_AP); mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TBTT_BCN_PRIO); mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TBTT_BCAST_PRIO); mt76_wr(dev, MT_PRE_TBTT, pre_tbtt); mt76_set(dev, MT_HW_INT_MASK(3), MT_HW_INT3_PRE_TBTT0 | MT_HW_INT3_TBTT0); mt76_set(dev, MT_WF_ARB_BCN_START, MT_WF_ARB_BCN_START_BSSn(0) | ((dev->mt76.beacon_mask >> 1) * MT_WF_ARB_BCN_START_BSS0n(1))); mt7603_irq_enable(dev, MT_INT_MAC_IRQ3); if (dev->mt76.beacon_mask & ~BIT(0)) mt76_set(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN); else mt76_clear(dev, MT_LPON_SBTOR(0), MT_LPON_SBTOR_SUB_BSS_EN); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/core.c b/sys/contrib/dev/mediatek/mt76/mt7603/core.c index 60a996b63c0c..915b8349146a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/core.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/core.c @@ -1,65 +1,67 @@ // SPDX-License-Identifier: ISC #include "mt7603.h" #include "../trace.h" void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); mt7603_irq_enable(dev, MT_INT_RX_DONE(q)); } irqreturn_t mt7603_irq_handler(int irq, void *dev_instance) { struct mt7603_dev *dev = dev_instance; u32 intr; intr = mt76_rr(dev, MT_INT_SOURCE_CSR); mt76_wr(dev, MT_INT_SOURCE_CSR, intr); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); intr &= dev->mt76.mmio.irqmask; if (intr & MT_INT_MAC_IRQ3) { u32 hwintr = mt76_rr(dev, MT_HW_INT_STATUS(3)); mt76_wr(dev, MT_HW_INT_STATUS(3), hwintr); if (hwintr & MT_HW_INT3_PRE_TBTT0) tasklet_schedule(&dev->mt76.pre_tbtt_tasklet); if ((hwintr & MT_HW_INT3_TBTT0) && dev->mt76.csa_complete) mt76_csa_finish(&dev->mt76); } if (intr & MT_INT_TX_DONE_ALL) { mt7603_irq_disable(dev, MT_INT_TX_DONE_ALL); napi_schedule(&dev->mt76.tx_napi); } if (intr & MT_INT_RX_DONE(0)) { + dev->rx_pse_check = 0; mt7603_irq_disable(dev, MT_INT_RX_DONE(0)); napi_schedule(&dev->mt76.napi[0]); } if (intr & MT_INT_RX_DONE(1)) { + dev->rx_pse_check = 0; mt7603_irq_disable(dev, MT_INT_RX_DONE(1)); napi_schedule(&dev->mt76.napi[1]); } return IRQ_HANDLED; } u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr) { u32 base = addr & MT_MCU_PCIE_REMAP_2_BASE; u32 offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET; dev->bus_ops->wr(&dev->mt76, MT_MCU_PCIE_REMAP_2, base); return MT_PCIE_REMAP_BASE_2 + offset; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/dma.c b/sys/contrib/dev/mediatek/mt76/mt7603/dma.c index 03ba11a61c90..863e5770df51 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/dma.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/dma.c @@ -1,241 +1,260 @@ // SPDX-License-Identifier: ISC #include "mt7603.h" #include "mac.h" #include "../dma.h" +static const u8 wmm_queue_map[] = { + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, +}; + static void mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) { static const u8 tid_to_ac[8] = { IEEE80211_AC_BE, IEEE80211_AC_BK, IEEE80211_AC_BK, IEEE80211_AC_BE, IEEE80211_AC_VI, IEEE80211_AC_VI, IEEE80211_AC_VO, IEEE80211_AC_VO }; __le32 *txd = (__le32 *)skb->data; struct ieee80211_hdr *hdr; struct ieee80211_sta *sta; struct mt7603_sta *msta; struct mt76_wcid *wcid; + u8 qid, tid = 0, hwq = 0; void *priv; int idx; u32 val; - u8 tid = 0; if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr)) goto free; val = le32_to_cpu(txd[1]); idx = FIELD_GET(MT_TXD1_WLAN_IDX, val); skb->priority = FIELD_GET(MT_TXD1_TID, val); if (idx >= MT7603_WTBL_STA - 1) goto free; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (!wcid) goto free; priv = msta = container_of(wcid, struct mt7603_sta, wcid); - val = le32_to_cpu(txd[0]); - val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX); - val |= FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_HW_QUEUE_MGMT); - txd[0] = cpu_to_le32(val); sta = container_of(priv, struct ieee80211_sta, drv_priv); hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; - if (ieee80211_is_data_qos(hdr->frame_control)) + + hwq = wmm_queue_map[IEEE80211_AC_BE]; + if (ieee80211_is_data_qos(hdr->frame_control)) { tid = *ieee80211_get_qos_ctl(hdr) & - IEEE80211_QOS_CTL_TAG1D_MASK; - skb_set_queue_mapping(skb, tid_to_ac[tid]); + IEEE80211_QOS_CTL_TAG1D_MASK; + qid = tid_to_ac[tid]; + hwq = wmm_queue_map[qid]; + skb_set_queue_mapping(skb, qid); + } else if (ieee80211_is_data(hdr->frame_control)) { + skb_set_queue_mapping(skb, IEEE80211_AC_BE); + hwq = wmm_queue_map[IEEE80211_AC_BE]; + } else { + skb_pull(skb, MT_TXD_SIZE); + if (!ieee80211_is_bufferable_mmpdu(skb)) + goto free; + skb_push(skb, MT_TXD_SIZE); + skb_set_queue_mapping(skb, MT_TXQ_PSD); + hwq = MT_TX_HW_QUEUE_MGMT; + } + ieee80211_sta_set_buffered(sta, tid, true); + val = le32_to_cpu(txd[0]); + val &= ~(MT_TXD0_P_IDX | MT_TXD0_Q_IDX); + val |= FIELD_PREP(MT_TXD0_Q_IDX, hwq); + txd[0] = cpu_to_le32(val); + spin_lock_bh(&dev->ps_lock); __skb_queue_tail(&msta->psq, skb); if (skb_queue_len(&msta->psq) >= 64) { skb = __skb_dequeue(&msta->psq); dev_kfree_skb(skb); } spin_unlock_bh(&dev->ps_lock); return; free: dev_kfree_skb(skb); } void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); __le32 *rxd = (__le32 *)skb->data; __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); if (q == MT_RXQ_MCU) { if (type == PKT_TYPE_RX_EVENT) mt76_mcu_rx_event(&dev->mt76, skb); else mt7603_rx_loopback_skb(dev, skb); return; } switch (type) { case PKT_TYPE_TXS: for (rxd++; rxd + 5 <= end; rxd += 5) mt7603_mac_add_txs(dev, rxd); dev_kfree_skb(skb); break; case PKT_TYPE_RX_EVENT: mt76_mcu_rx_event(&dev->mt76, skb); return; case PKT_TYPE_NORMAL: if (mt7603_mac_fill_rx(dev, skb) == 0) { mt76_rx(&dev->mt76, q, skb); return; } fallthrough; default: dev_kfree_skb(skb); break; } } static int mt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize) { int err; err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize, MT_RX_RING_BASE); if (err < 0) return err; mt7603_irq_enable(dev, MT_INT_RX_DONE(idx)); return 0; } static int mt7603_poll_tx(struct napi_struct *napi, int budget) { struct mt7603_dev *dev; int i; dev = container_of(napi, struct mt7603_dev, mt76.tx_napi); dev->tx_dma_check = 0; mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); for (i = MT_TXQ_PSD; i >= 0; i--) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); if (napi_complete_done(napi, 0)) mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); for (i = MT_TXQ_PSD; i >= 0; i--) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); mt7603_mac_sta_poll(dev); mt76_worker_schedule(&dev->mt76.tx_worker); return 0; } int mt7603_dma_init(struct mt7603_dev *dev) { - static const u8 wmm_queue_map[] = { - [IEEE80211_AC_BK] = 0, - [IEEE80211_AC_BE] = 1, - [IEEE80211_AC_VI] = 2, - [IEEE80211_AC_VO] = 3, - }; int ret; int i; mt76_dma_attach(&dev->mt76); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); mt7603_pse_client_reset(dev); for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], - MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_TX_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; mt7603_irq_enable(dev, MT_INT_TX_DONE(IEEE80211_AC_VO) | MT_INT_TX_DONE(IEEE80211_AC_VI) | MT_INT_TX_DONE(IEEE80211_AC_BE) | MT_INT_TX_DONE(IEEE80211_AC_BK) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_BCN) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_BMC)); ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, MT7603_MCU_RX_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, MT7603_RX_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; mt76_wr(dev, MT_DELAY_INT_CFG, 0); ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt7603_poll_tx); napi_enable(&dev->mt76.tx_napi); return 0; } void mt7603_dma_cleanup(struct mt7603_dev *dev) { mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); mt76_dma_cleanup(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c b/sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c index d951cb81df83..f5a6b03bc61d 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c @@ -1,187 +1,188 @@ // SPDX-License-Identifier: ISC #include #include "mt7603.h" #include "eeprom.h" static int mt7603_efuse_read(struct mt7603_dev *dev, u32 base, u16 addr, u8 *data) { u32 val; int i; val = mt76_rr(dev, base + MT_EFUSE_CTRL); val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE); val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); val |= MT_EFUSE_CTRL_KICK; mt76_wr(dev, base + MT_EFUSE_CTRL, val); if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) return -ETIMEDOUT; udelay(2); val = mt76_rr(dev, base + MT_EFUSE_CTRL); if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT || WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) { memset(data, 0xff, 16); return 0; } for (i = 0; i < 4; i++) { val = mt76_rr(dev, base + MT_EFUSE_RDATA(i)); put_unaligned_le32(val, data + 4 * i); } return 0; } static int mt7603_efuse_init(struct mt7603_dev *dev) { u32 base = mt7603_reg_map(dev, MT_EFUSE_BASE); int len = MT7603_EEPROM_SIZE; void *buf; int ret, i; if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY) return 0; dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL); dev->mt76.otp.size = len; if (!dev->mt76.otp.data) return -ENOMEM; buf = dev->mt76.otp.data; for (i = 0; i + 16 <= len; i += 16) { ret = mt7603_efuse_read(dev, base, i, buf + i); if (ret) return ret; } return 0; } static bool mt7603_has_cal_free_data(struct mt7603_dev *dev, u8 *efuse) { if (!efuse[MT_EE_TEMP_SENSOR_CAL]) return false; if (get_unaligned_le16(efuse + MT_EE_TX_POWER_0_START_2G) == 0) return false; if (get_unaligned_le16(efuse + MT_EE_TX_POWER_1_START_2G) == 0) return false; if (!efuse[MT_EE_CP_FT_VERSION]) return false; if (!efuse[MT_EE_XTAL_FREQ_OFFSET]) return false; if (!efuse[MT_EE_XTAL_WF_RFCAL]) return false; return true; } static void mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse) { static const u8 cal_free_bytes[] = { MT_EE_TEMP_SENSOR_CAL, MT_EE_CP_FT_VERSION, MT_EE_XTAL_FREQ_OFFSET, MT_EE_XTAL_WF_RFCAL, /* Skip for MT7628 */ MT_EE_TX_POWER_0_START_2G, MT_EE_TX_POWER_0_START_2G + 1, MT_EE_TX_POWER_1_START_2G, MT_EE_TX_POWER_1_START_2G + 1, }; struct device_node *np = dev->mt76.dev->of_node; u8 *eeprom = dev->mt76.eeprom.data; int n = ARRAY_SIZE(cal_free_bytes); int i; if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) return; if (!mt7603_has_cal_free_data(dev, efuse)) return; if (is_mt7628(dev)) n -= 4; for (i = 0; i < n; i++) { int offset = cal_free_bytes[i]; eeprom[offset] = efuse[offset]; } } static int mt7603_eeprom_load(struct mt7603_dev *dev) { int ret; ret = mt76_eeprom_init(&dev->mt76, MT7603_EEPROM_SIZE); if (ret < 0) return ret; return mt7603_efuse_init(dev); } static int mt7603_check_eeprom(struct mt76_dev *dev) { u16 val = get_unaligned_le16(dev->eeprom.data); switch (val) { case 0x7628: case 0x7603: case 0x7600: return 0; default: return -EINVAL; } } static inline bool is_mt7688(struct mt7603_dev *dev) { return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4); } int mt7603_eeprom_init(struct mt7603_dev *dev) { u8 *eeprom; int ret; ret = mt7603_eeprom_load(dev); if (ret < 0) return ret; if (dev->mt76.otp.data) { if (mt7603_check_eeprom(&dev->mt76) == 0) mt7603_apply_cal_free_data(dev, dev->mt76.otp.data); else memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, MT7603_EEPROM_SIZE); } eeprom = (u8 *)dev->mt76.eeprom.data; dev->mphy.cap.has_2ghz = true; memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN); /* Check for 1SS devices */ dev->mphy.antenna_mask = 3; if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 || FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 || is_mt7688(dev)) dev->mphy.antenna_mask = 1; + dev->mphy.chainmask = dev->mphy.antenna_mask; mt76_eeprom_override(&dev->mphy); return 0; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/init.c b/sys/contrib/dev/mediatek/mt76/mt7603/init.c index 0762de3ce5ac..86617a3e4328 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/init.c @@ -1,560 +1,571 @@ // SPDX-License-Identifier: ISC #include #include "mt7603.h" #include "mac.h" #include "eeprom.h" const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, .drv_flags = MT_DRV_SW_RX_AIRTIME, .survey_flags = SURVEY_INFO_TIME_TX, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, .rx_poll_complete = mt7603_rx_poll_complete, .sta_ps = mt7603_sta_ps, .sta_add = mt7603_sta_add, - .sta_assoc = mt7603_sta_assoc, + .sta_event = mt7603_sta_event, .sta_remove = mt7603_sta_remove, .update_survey = mt7603_update_channel, + .set_channel = mt7603_set_channel, }; static void mt7603_set_tmac_template(struct mt7603_dev *dev) { u32 desc[5] = { [1] = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 0xf), [3] = MT_TXD5_SW_POWER_MGMT }; u32 addr; int i; addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR); addr += MT_CLIENT_TMAC_INFO_TEMPLATE; for (i = 0; i < ARRAY_SIZE(desc); i++) mt76_wr(dev, addr + 4 * i, desc[i]); } static void mt7603_dma_sched_init(struct mt7603_dev *dev) { int page_size = 128; int page_count; int max_len = 1792; int max_amsdu_pages = 4096 / page_size; int max_mcu_len = 4096; int max_beacon_len = 512 * 4 + max_len; int max_mcast_pages = 4 * max_len / page_size; int reserved_count = 0; int beacon_pages; int mcu_pages; int i; page_count = mt76_get_field(dev, MT_PSE_FC_P0, MT_PSE_FC_P0_MAX_QUOTA); beacon_pages = 4 * (max_beacon_len / page_size); mcu_pages = max_mcu_len / page_size; mt76_wr(dev, MT_PSE_FRP, FIELD_PREP(MT_PSE_FRP_P0, 7) | FIELD_PREP(MT_PSE_FRP_P1, 6) | FIELD_PREP(MT_PSE_FRP_P2_RQ2, 4)); mt76_wr(dev, MT_HIGH_PRIORITY_1, 0x55555553); mt76_wr(dev, MT_HIGH_PRIORITY_2, 0x78555555); mt76_wr(dev, MT_QUEUE_PRIORITY_1, 0x2b1a096e); mt76_wr(dev, MT_QUEUE_PRIORITY_2, 0x785f4d3c); mt76_wr(dev, MT_PRIORITY_MASK, 0xffffffff); mt76_wr(dev, MT_SCH_1, page_count | (2 << 28)); mt76_wr(dev, MT_SCH_2, max_amsdu_pages); for (i = 0; i <= 4; i++) mt76_wr(dev, MT_PAGE_COUNT(i), max_amsdu_pages); reserved_count += 5 * max_amsdu_pages; mt76_wr(dev, MT_PAGE_COUNT(5), mcu_pages); reserved_count += mcu_pages; mt76_wr(dev, MT_PAGE_COUNT(7), beacon_pages); reserved_count += beacon_pages; mt76_wr(dev, MT_PAGE_COUNT(8), max_mcast_pages); reserved_count += max_mcast_pages; if (is_mt7603(dev)) reserved_count = 0; mt76_wr(dev, MT_RSV_MAX_THRESH, page_count - reserved_count); if (is_mt7603(dev) && mt76xx_rev(dev) >= MT7603_REV_E2) { mt76_wr(dev, MT_GROUP_THRESH(0), page_count - beacon_pages - mcu_pages); mt76_wr(dev, MT_GROUP_THRESH(1), beacon_pages); mt76_wr(dev, MT_BMAP_0, 0x0080ff5f); mt76_wr(dev, MT_GROUP_THRESH(2), mcu_pages); mt76_wr(dev, MT_BMAP_1, 0x00000020); } else { mt76_wr(dev, MT_GROUP_THRESH(0), page_count); mt76_wr(dev, MT_BMAP_0, 0xffff); } mt76_wr(dev, MT_SCH_4, 0); for (i = 0; i <= 15; i++) mt76_wr(dev, MT_TXTIME_THRESH(i), 0xfffff); mt76_set(dev, MT_SCH_4, BIT(6)); } static void mt7603_phy_init(struct mt7603_dev *dev) { int rx_chains = dev->mphy.antenna_mask; int tx_chains = hweight8(rx_chains) - 1; mt76_rmw(dev, MT_WF_RMAC_RMCR, (MT_WF_RMAC_RMCR_SMPS_MODE | MT_WF_RMAC_RMCR_RX_STREAMS), (FIELD_PREP(MT_WF_RMAC_RMCR_SMPS_MODE, 3) | FIELD_PREP(MT_WF_RMAC_RMCR_RX_STREAMS, rx_chains))); mt76_rmw_field(dev, MT_TMAC_TCR, MT_TMAC_TCR_TX_STREAMS, tx_chains); dev->agc0 = mt76_rr(dev, MT_AGC(0)); dev->agc3 = mt76_rr(dev, MT_AGC(3)); } static void mt7603_mac_init(struct mt7603_dev *dev) { u8 bc_addr[ETH_ALEN]; u32 addr; int i; mt76_wr(dev, MT_AGG_BA_SIZE_LIMIT_0, (MT_AGG_SIZE_LIMIT(0) << 0 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(1) << 1 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(2) << 2 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(3) << 3 * MT_AGG_BA_SIZE_LIMIT_SHIFT)); mt76_wr(dev, MT_AGG_BA_SIZE_LIMIT_1, (MT_AGG_SIZE_LIMIT(4) << 0 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(5) << 1 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(6) << 2 * MT_AGG_BA_SIZE_LIMIT_SHIFT) | (MT_AGG_SIZE_LIMIT(7) << 3 * MT_AGG_BA_SIZE_LIMIT_SHIFT)); mt76_wr(dev, MT_AGG_LIMIT, FIELD_PREP(MT_AGG_LIMIT_AC(0), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(1), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(2), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(3), 24)); mt76_wr(dev, MT_AGG_LIMIT_1, FIELD_PREP(MT_AGG_LIMIT_AC(0), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(1), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(2), 24) | FIELD_PREP(MT_AGG_LIMIT_AC(3), 24)); mt76_wr(dev, MT_AGG_CONTROL, FIELD_PREP(MT_AGG_CONTROL_BAR_RATE, 0x4b) | FIELD_PREP(MT_AGG_CONTROL_CFEND_RATE, 0x69) | MT_AGG_CONTROL_NO_BA_AR_RULE); mt76_wr(dev, MT_AGG_RETRY_CONTROL, FIELD_PREP(MT_AGG_RETRY_CONTROL_BAR_LIMIT, 1) | FIELD_PREP(MT_AGG_RETRY_CONTROL_RTS_LIMIT, 15)); mt76_wr(dev, MT_DMA_DCR0, MT_DMA_DCR0_RX_VEC_DROP | FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 4096)); mt76_rmw(dev, MT_DMA_VCFR0, BIT(0), BIT(13)); mt76_rmw(dev, MT_DMA_TMCFR0, BIT(0) | BIT(1), BIT(13)); mt76_clear(dev, MT_WF_RMAC_TMR_PA, BIT(31)); mt76_set(dev, MT_WF_RMACDR, MT_WF_RMACDR_MAXLEN_20BIT); mt76_rmw(dev, MT_WF_RMAC_MAXMINLEN, 0xffffff, 0x19000); mt76_wr(dev, MT_WF_RFCR1, 0); mt76_set(dev, MT_TMAC_TCR, MT_TMAC_TCR_RX_RIFS_MODE); + if (is_mt7628(dev)) { + mt76_set(dev, MT_TMAC_TCR, + MT_TMAC_TCR_TXOP_BURST_STOP | BIT(1) | BIT(0)); + mt76_set(dev, MT_TXREQ, BIT(27)); + mt76_set(dev, MT_AGG_TMP, GENMASK(4, 2)); + } + mt7603_set_tmac_template(dev); /* Enable RX group to HIF */ addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR); mt76_set(dev, addr + MT_CLIENT_RXINF, MT_CLIENT_RXINF_RXSH_GROUPS); /* Enable RX group to MCU */ mt76_set(dev, MT_DMA_DCR1, GENMASK(13, 11)); mt76_rmw_field(dev, MT_AGG_PCR_RTS, MT_AGG_PCR_RTS_PKT_THR, 3); mt76_set(dev, MT_TMAC_PCR, MT_TMAC_PCR_SPE_EN); /* include preamble detection in CCA trigger signal */ mt76_rmw_field(dev, MT_TXREQ, MT_TXREQ_CCA_SRC_SEL, 2); mt76_wr(dev, MT_RXREQ, 4); /* Configure all rx packets to HIF */ mt76_wr(dev, MT_DMA_RCFR0, 0xc0000000); /* Configure MCU txs selection with aggregation */ mt76_wr(dev, MT_DMA_TCFR0, FIELD_PREP(MT_DMA_TCFR_TXS_AGGR_TIMEOUT, 1) | /* 32 us */ MT_DMA_TCFR_TXS_AGGR_COUNT); /* Configure HIF txs selection with aggregation */ mt76_wr(dev, MT_DMA_TCFR1, FIELD_PREP(MT_DMA_TCFR_TXS_AGGR_TIMEOUT, 1) | /* 32 us */ MT_DMA_TCFR_TXS_AGGR_COUNT | /* Maximum count */ MT_DMA_TCFR_TXS_BIT_MAP); mt76_wr(dev, MT_MCU_PCIE_REMAP_1, MT_PSE_WTBL_2_PHYS_ADDR); for (i = 0; i < MT7603_WTBL_SIZE; i++) mt7603_wtbl_clear(dev, i); eth_broadcast_addr(bc_addr); mt7603_wtbl_init(dev, MT7603_WTBL_RESERVED, -1, bc_addr); dev->global_sta.wcid.idx = MT7603_WTBL_RESERVED; rcu_assign_pointer(dev->mt76.wcid[MT7603_WTBL_RESERVED], &dev->global_sta.wcid); mt76_rmw_field(dev, MT_LPON_BTEIR, MT_LPON_BTEIR_MBSS_MODE, 2); mt76_rmw_field(dev, MT_WF_RMACDR, MT_WF_RMACDR_MBSSID_MASK, 2); mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1)); mt76_wr(dev, MT_AGG_ARDCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7603_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7603_RATE_RETRY - 1)); mt76_wr(dev, MT_AGG_ARCR, (FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | MT_AGG_ARCR_RATE_DOWN_RATIO_EN | FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) | FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4))); mt76_set(dev, MT_WTBL_RMVTCR, MT_WTBL_RMVTCR_RX_MV_MODE); mt76_clear(dev, MT_SEC_SCR, MT_SEC_SCR_MASK_ORDER); mt76_clear(dev, MT_SEC_SCR, BIT(18)); /* Set secondary beacon time offsets */ for (i = 0; i <= 4; i++) mt76_rmw_field(dev, MT_LPON_SBTOR(i), MT_LPON_SBTOR_TIME_OFFSET, (i + 1) * (20 + 4096)); } static int mt7603_init_hardware(struct mt7603_dev *dev) { int i, ret; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); ret = mt7603_eeprom_init(dev); if (ret < 0) return ret; ret = mt7603_dma_init(dev); if (ret) return ret; mt76_wr(dev, MT_WPDMA_GLO_CFG, 0x52000850); mt7603_mac_dma_start(dev); dev->rxfilter = mt76_rr(dev, MT_WF_RFCR); set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); for (i = 0; i < MT7603_WTBL_SIZE; i++) { mt76_wr(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY | MT_PSE_RTA_WRITE | FIELD_PREP(MT_PSE_RTA_TAG_ID, i)); mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000); } ret = mt7603_mcu_init(dev); if (ret) return ret; mt7603_dma_sched_init(dev); mt7603_mcu_set_eeprom(dev); mt7603_phy_init(dev); mt7603_mac_init(dev); return 0; } static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, { .max = MT7603_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_STATION) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = 4, .num_different_channels = 1, .beacon_int_infra_match = true, } }; static void mt7603_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) { struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); u32 val, addr; val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); addr = mt7603_reg_map(dev, MT_LED_STATUS_0(mphy->leds.pin)); mt76_wr(dev, addr, val); addr = mt7603_reg_map(dev, MT_LED_STATUS_1(mphy->leds.pin)); mt76_wr(dev, addr, val); val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | MT_LED_CTRL_KICK(mphy->leds.pin); if (mphy->leds.al) val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); addr = mt7603_reg_map(dev, MT_LED_CTRL); mt76_wr(dev, addr, val); } static int mt7603_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); u8 delta_on, delta_off; delta_off = max_t(u8, *delay_off / 10, 1); delta_on = max_t(u8, *delay_on / 10, 1); mt7603_led_set_config(mphy, delta_on, delta_off); return 0; } static void mt7603_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); if (!brightness) mt7603_led_set_config(mphy, 0, 0xff); else mt7603_led_set_config(mphy, 0xff, 0); } static u32 __mt7603_reg_addr(struct mt7603_dev *dev, u32 addr) { if (addr < 0x100000) return addr; return mt7603_reg_map(dev, addr); } static u32 mt7603_rr(struct mt76_dev *mdev, u32 offset) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); u32 addr = __mt7603_reg_addr(dev, offset); return dev->bus_ops->rr(mdev, addr); } static void mt7603_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); u32 addr = __mt7603_reg_addr(dev, offset); dev->bus_ops->wr(mdev, addr, val); } static u32 mt7603_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); u32 addr = __mt7603_reg_addr(dev, offset); return dev->bus_ops->rmw(mdev, addr, mask, val); } static void mt7603_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7603_dev *dev = hw->priv; dev->mt76.region = request->dfs_region; dev->ed_monitor = dev->ed_monitor_enabled && dev->mt76.region == NL80211_DFS_ETSI; } static int mt7603_txpower_signed(int val) { bool sign = val & BIT(6); if (!(val & BIT(7))) return 0; val &= GENMASK(5, 0); if (!sign) val = -val; return val; } static void mt7603_init_txpower(struct mt7603_dev *dev, struct ieee80211_supported_band *sband) { struct ieee80211_channel *chan; u8 *eeprom = (u8 *)dev->mt76.eeprom.data; int target_power = eeprom[MT_EE_TX_POWER_0_START_2G + 2] & ~BIT(7); u8 *rate_power = &eeprom[MT_EE_TX_POWER_CCK]; bool ext_pa = eeprom[MT_EE_NIC_CONF_0 + 1] & BIT(1); + u8 ext_pa_pwr; int max_offset, cur_offset; int i; - if (ext_pa && is_mt7603(dev)) - target_power = eeprom[MT_EE_TX_POWER_TSSI_OFF] & ~BIT(7); + ext_pa_pwr = eeprom[MT_EE_TX_POWER_TSSI_OFF]; + if (ext_pa && is_mt7603(dev) && ext_pa_pwr != 0 && ext_pa_pwr != 0xff) + target_power = ext_pa_pwr & ~BIT(7); if (target_power & BIT(6)) target_power = -(target_power & GENMASK(5, 0)); max_offset = 0; for (i = 0; i < 14; i++) { cur_offset = mt7603_txpower_signed(rate_power[i]); max_offset = max(max_offset, cur_offset); } target_power += max_offset; dev->tx_power_limit = target_power; dev->mphy.txpower_cur = target_power; target_power = DIV_ROUND_UP(target_power, 2); /* add 3 dBm for 2SS devices (combined output) */ if (dev->mphy.antenna_mask & BIT(1)) target_power += 3; for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; chan->max_power = min_t(int, chan->max_reg_power, target_power); chan->orig_mpwr = target_power; } } int mt7603_register_device(struct mt7603_dev *dev) { struct mt76_bus_ops *bus_ops; struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; int ret; dev->bus_ops = dev->mt76.bus; bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), GFP_KERNEL); if (!bus_ops) return -ENOMEM; bus_ops->rr = mt7603_rr; bus_ops->wr = mt7603_wr; bus_ops->rmw = mt7603_rmw; dev->mt76.bus = bus_ops; spin_lock_init(&dev->ps_lock); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7603_mac_work); tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet); dev->slottime = 9; dev->sensitivity_limit = 28; dev->dynamic_sensitivity = true; ret = mt7603_init_hardware(dev); if (ret) return ret; hw->queues = 4; hw->max_rates = 3; hw->max_report_rates = 7; hw->max_rate_tries = 11; + hw->max_tx_fragments = 1; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; hw->sta_data_size = sizeof(struct mt7603_sta); hw->vif_data_size = sizeof(struct mt7603_vif); wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { dev->mphy.leds.cdev.brightness_set = mt7603_led_set_brightness; dev->mphy.leds.cdev.blink_set = mt7603_led_set_blink; } wiphy->reg_notifier = mt7603_regd_notifier; ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) return ret; mt7603_init_debugfs(dev); mt7603_init_txpower(dev, &dev->mphy.sband_2g.sband); return 0; } void mt7603_unregister_device(struct mt7603_dev *dev) { tasklet_disable(&dev->mt76.pre_tbtt_tasklet); mt76_unregister_device(&dev->mt76); mt7603_mcu_exit(dev); mt7603_dma_cleanup(dev); mt76_free_device(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/mac.c b/sys/contrib/dev/mediatek/mt76/mt7603/mac.c index 99ae080502d8..413973d05b43 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/mac.c @@ -1,1892 +1,1891 @@ // SPDX-License-Identifier: ISC #include #include #include "mt7603.h" #include "mac.h" #include "../trace.h" #define MT_PSE_PAGE_SIZE 128 static u32 mt7603_ac_queue_mask0(u32 mask) { u32 ret = 0; ret |= GENMASK(3, 0) * !!(mask & BIT(0)); ret |= GENMASK(8, 5) * !!(mask & BIT(1)); ret |= GENMASK(13, 10) * !!(mask & BIT(2)); ret |= GENMASK(19, 16) * !!(mask & BIT(3)); return ret; } static void mt76_stop_tx_ac(struct mt7603_dev *dev, u32 mask) { mt76_set(dev, MT_WF_ARB_TX_STOP_0, mt7603_ac_queue_mask0(mask)); } static void mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) { mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); } void mt7603_mac_reset_counters(struct mt7603_dev *dev) { int i; for (i = 0; i < 2; i++) mt76_rr(dev, MT_TX_AGG_CNT(i)); memset(dev->mphy.aggr_stats, 0, sizeof(dev->mphy.aggr_stats)); } void mt7603_mac_set_timing(struct mt7603_dev *dev) { u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24); int offset = 3 * dev->coverage_class; u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); bool is_5ghz = dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ; int sifs; u32 val; if (is_5ghz) sifs = 16; else sifs = 10; mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); udelay(1); mt76_wr(dev, MT_TIMEOUT_CCK, cck + reg_offset); mt76_wr(dev, MT_TIMEOUT_OFDM, ofdm + reg_offset); mt76_wr(dev, MT_IFS, FIELD_PREP(MT_IFS_EIFS, 360) | FIELD_PREP(MT_IFS_RIFS, 2) | FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, dev->slottime)); if (dev->slottime < 20 || is_5ghz) val = MT7603_CFEND_RATE_DEFAULT; else val = MT7603_CFEND_RATE_11B; mt76_rmw_field(dev, MT_AGG_CONTROL, MT_AGG_CONTROL_CFEND_RATE, val); mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); } static void mt7603_wtbl_update(struct mt7603_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); } static u32 mt7603_wtbl1_addr(int idx) { return MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; } static u32 mt7603_wtbl2_addr(int idx) { /* Mapped to WTBL2 */ return MT_PCIE_REMAP_BASE_1 + idx * MT_WTBL2_SIZE; } static u32 mt7603_wtbl3_addr(int idx) { u32 base = mt7603_wtbl2_addr(MT7603_WTBL_SIZE); return base + idx * MT_WTBL3_SIZE; } static u32 mt7603_wtbl4_addr(int idx) { u32 base = mt7603_wtbl3_addr(MT7603_WTBL_SIZE); return base + idx * MT_WTBL4_SIZE; } void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, const u8 *mac_addr) { const void *_mac = mac_addr; u32 addr = mt7603_wtbl1_addr(idx); u32 w0 = 0, w1 = 0; int i; if (_mac) { w0 = FIELD_PREP(MT_WTBL1_W0_ADDR_HI, get_unaligned_le16(_mac + 4)); w1 = FIELD_PREP(MT_WTBL1_W1_ADDR_LO, get_unaligned_le32(_mac)); } if (vif < 0) vif = 0; else w0 |= MT_WTBL1_W0_RX_CHECK_A1; w0 |= FIELD_PREP(MT_WTBL1_W0_MUAR_IDX, vif); mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); mt76_set(dev, addr + 0 * 4, w0); mt76_set(dev, addr + 1 * 4, w1); mt76_set(dev, addr + 2 * 4, MT_WTBL1_W2_ADMISSION_CONTROL); mt76_stop_tx_ac(dev, GENMASK(3, 0)); addr = mt7603_wtbl2_addr(idx); for (i = 0; i < MT_WTBL2_SIZE; i += 4) mt76_wr(dev, addr + i, 0); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); mt76_start_tx_ac(dev, GENMASK(3, 0)); addr = mt7603_wtbl3_addr(idx); for (i = 0; i < MT_WTBL3_SIZE; i += 4) mt76_wr(dev, addr + i, 0); addr = mt7603_wtbl4_addr(idx); for (i = 0; i < MT_WTBL4_SIZE; i += 4) mt76_wr(dev, addr + i, 0); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } static void mt7603_wtbl_set_skip_tx(struct mt7603_dev *dev, int idx, bool enabled) { u32 addr = mt7603_wtbl1_addr(idx); u32 val = mt76_rr(dev, addr + 3 * 4); val &= ~MT_WTBL1_W3_SKIP_TX; val |= enabled * MT_WTBL1_W3_SKIP_TX; mt76_wr(dev, addr + 3 * 4, val); } void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort) { u32 flush_mask; int i, port, queue; if (abort) { port = 3; /* PSE */ queue = 8; /* free queue */ } else { port = 0; /* HIF */ queue = 1; /* MCU queue */ } mt7603_wtbl_set_skip_tx(dev, idx, true); mt76_wr(dev, MT_TX_ABORT, MT_TX_ABORT_EN | FIELD_PREP(MT_TX_ABORT_WCID, idx)); flush_mask = MT_WF_ARB_TX_FLUSH_AC0 | MT_WF_ARB_TX_FLUSH_AC1 | MT_WF_ARB_TX_FLUSH_AC2 | MT_WF_ARB_TX_FLUSH_AC3; flush_mask <<= mac_idx; mt76_wr(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask); mt76_poll(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask, 0, 20000); mt76_wr(dev, MT_WF_ARB_TX_START_0, flush_mask); mt76_wr(dev, MT_TX_ABORT, 0); for (i = 0; i < 4; i++) { mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY | FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, idx) | FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, i) | FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, port) | FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, queue)); mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000); } WARN_ON_ONCE(mt76_rr(dev, MT_DMA_FQCR0) & MT_DMA_FQCR0_BUSY); mt7603_wtbl_set_skip_tx(dev, idx, false); } void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled) { u32 addr = mt7603_wtbl1_addr(sta->wcid.idx); if (sta->smps == enabled) return; mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_SMPS, enabled); sta->smps = enabled; } void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled) { int idx = sta->wcid.idx; u32 addr; spin_lock_bh(&dev->ps_lock); if (sta->ps == enabled) goto out; mt76_wr(dev, MT_PSE_RTA, FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) | FIELD_PREP(MT_PSE_RTA_PORT_ID, 0) | FIELD_PREP(MT_PSE_RTA_QUEUE_ID, 1) | FIELD_PREP(MT_PSE_RTA_REDIRECT_EN, enabled) | MT_PSE_RTA_WRITE | MT_PSE_RTA_BUSY); mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000); if (enabled) mt7603_filter_tx(dev, sta->vif->idx, idx, false); addr = mt7603_wtbl1_addr(idx); mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); mt76_rmw(dev, addr + 3 * 4, MT_WTBL1_W3_POWER_SAVE, enabled * MT_WTBL1_W3_POWER_SAVE); mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); sta->ps = enabled; out: spin_unlock_bh(&dev->ps_lock); } void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx) { int wtbl2_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL2_SIZE; int wtbl2_frame = idx / wtbl2_frame_size; int wtbl2_entry = idx % wtbl2_frame_size; int wtbl3_base_frame = MT_WTBL3_OFFSET / MT_PSE_PAGE_SIZE; int wtbl3_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL3_SIZE; int wtbl3_frame = wtbl3_base_frame + idx / wtbl3_frame_size; int wtbl3_entry = (idx % wtbl3_frame_size) * 2; int wtbl4_base_frame = MT_WTBL4_OFFSET / MT_PSE_PAGE_SIZE; int wtbl4_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL4_SIZE; int wtbl4_frame = wtbl4_base_frame + idx / wtbl4_frame_size; int wtbl4_entry = idx % wtbl4_frame_size; u32 addr = MT_WTBL1_BASE + idx * MT_WTBL1_SIZE; int i; mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); mt76_wr(dev, addr + 0 * 4, MT_WTBL1_W0_RX_CHECK_A1 | MT_WTBL1_W0_RX_CHECK_A2 | MT_WTBL1_W0_RX_VALID); mt76_wr(dev, addr + 1 * 4, 0); mt76_wr(dev, addr + 2 * 4, 0); mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); mt76_wr(dev, addr + 3 * 4, FIELD_PREP(MT_WTBL1_W3_WTBL2_FRAME_ID, wtbl2_frame) | FIELD_PREP(MT_WTBL1_W3_WTBL2_ENTRY_ID, wtbl2_entry) | FIELD_PREP(MT_WTBL1_W3_WTBL4_FRAME_ID, wtbl4_frame) | MT_WTBL1_W3_I_PSM | MT_WTBL1_W3_KEEP_I_PSM); mt76_wr(dev, addr + 4 * 4, FIELD_PREP(MT_WTBL1_W4_WTBL3_FRAME_ID, wtbl3_frame) | FIELD_PREP(MT_WTBL1_W4_WTBL3_ENTRY_ID, wtbl3_entry) | FIELD_PREP(MT_WTBL1_W4_WTBL4_ENTRY_ID, wtbl4_entry)); mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); addr = mt7603_wtbl2_addr(idx); /* Clear BA information */ mt76_wr(dev, addr + (15 * 4), 0); mt76_stop_tx_ac(dev, GENMASK(3, 0)); for (i = 2; i <= 4; i++) mt76_wr(dev, addr + (i * 4), 0); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2); mt76_start_tx_ac(dev, GENMASK(3, 0)); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_RX_COUNT_CLEAR); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_TX_COUNT_CLEAR); mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta) { struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; int idx = msta->wcid.idx; u8 ampdu_density; u32 addr; u32 val; addr = mt7603_wtbl1_addr(idx); ampdu_density = sta->deflink.ht_cap.ampdu_density; if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4) ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; val = mt76_rr(dev, addr + 2 * 4); val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL; val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR, sta->deflink.ht_cap.ampdu_factor) | FIELD_PREP(MT_WTBL1_W2_MPDU_DENSITY, sta->deflink.ht_cap.ampdu_density) | MT_WTBL1_W2_TXS_BAF_REPORT; if (sta->deflink.ht_cap.cap) val |= MT_WTBL1_W2_HT; if (sta->deflink.vht_cap.cap) val |= MT_WTBL1_W2_VHT; mt76_wr(dev, addr + 2 * 4, val); addr = mt7603_wtbl2_addr(idx); val = mt76_rr(dev, addr + 9 * 4); val &= ~(MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | MT_WTBL2_W9_SHORT_GI_80); if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) val |= MT_WTBL2_W9_SHORT_GI_20; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) val |= MT_WTBL2_W9_SHORT_GI_40; mt76_wr(dev, addr + 9 * 4, val); } void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid) { mt76_wr(dev, MT_BA_CONTROL_0, get_unaligned_le32(addr)); mt76_wr(dev, MT_BA_CONTROL_1, (get_unaligned_le16(addr + 4) | FIELD_PREP(MT_BA_CONTROL_1_TID, tid) | MT_BA_CONTROL_1_RESET)); } void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size) { u32 addr = mt7603_wtbl2_addr(wcid); u32 tid_mask = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | (MT_WTBL2_W15_BA_WIN_SIZE << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT)); u32 tid_val; int i; if (ba_size < 0) { /* disable */ mt76_clear(dev, addr + (15 * 4), tid_mask); return; } for (i = 7; i > 0; i--) { if (ba_size >= MT_AGG_SIZE_LIMIT(i)) break; } tid_val = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) | i << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT); mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); } void mt7603_mac_sta_poll(struct mt7603_dev *dev) { static const u8 ac_to_tid[4] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; struct ieee80211_sta *sta; struct mt7603_sta *msta; u32 total_airtime = 0; u32 airtime[4]; u32 addr; int i; rcu_read_lock(); while (1) { bool clear = false; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&dev->mt76.sta_poll_list)) { spin_unlock_bh(&dev->mt76.sta_poll_lock); break; } msta = list_first_entry(&dev->mt76.sta_poll_list, struct mt7603_sta, wcid.poll_list); list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); addr = mt7603_wtbl4_addr(msta->wcid.idx); for (i = 0; i < 4; i++) { u32 airtime_last = msta->tx_airtime_ac[i]; msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); airtime[i] = msta->tx_airtime_ac[i] - airtime_last; airtime[i] *= 32; total_airtime += airtime[i]; if (msta->tx_airtime_ac[i] & BIT(22)) clear = true; } if (clear) { mt7603_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(msta->tx_airtime_ac, 0, sizeof(msta->tx_airtime_ac)); } if (!msta->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < 4; i++) { struct mt76_queue *q = dev->mphy.q_tx[i]; u8 qidx = q->hw_idx; u8 tid = ac_to_tid[i]; u32 txtime = airtime[qidx]; if (!txtime) continue; ieee80211_sta_register_airtime(sta, tid, txtime, 0); } } rcu_read_unlock(); if (!total_airtime) return; spin_lock_bh(&dev->mt76.cc_lock); dev->mphy.chan_state->cc_tx += total_airtime; spin_unlock_bh(&dev->mt76.cc_lock); } static struct mt76_wcid * mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) { struct mt7603_sta *sta; struct mt76_wcid *wcid; if (idx >= MT7603_WTBL_SIZE) return NULL; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (unicast || !wcid) return wcid; if (!wcid->sta) return NULL; sta = container_of(wcid, struct mt7603_sta, wcid); if (!sta->vif) return NULL; return &sta->vif->sta.wcid; } int mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; __le32 *rxd = (__le32 *)skb->data; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); bool unicast = rxd1 & MT_RXD1_NORMAL_U2M; bool insert_ccmp_hdr = false; bool remove_pad; int idx; int i; memset(status, 0, sizeof(*status)); i = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); sband = (i & 1) ? &dev->mphy.sband_5g.sband : &dev->mphy.sband_2g.sband; i >>= 1; idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); status->wcid = mt7603_rx_get_wcid(dev, idx, unicast); status->band = sband->band; if (i < sband->n_channels) status->freq = sband->channels[i].center_freq; if (rxd2 & MT_RXD2_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR) status->flag |= RX_FLAG_MMIC_ERROR; /* ICV error or CCMP/BIP/WPI MIC error */ if (rxd2 & MT_RXD2_NORMAL_ICV_ERR) status->flag |= RX_FLAG_ONLY_MONITOR; if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED; status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) return -EINVAL; if (!sband->channels) return -EINVAL; rxd += 4; if (rxd0 & MT_RXD0_NORMAL_GROUP_4) { rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_1) { u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { case MT_CIPHER_AES_CCMP: case MT_CIPHER_CCMP_CCX: case MT_CIPHER_CCMP_256: insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); fallthrough; case MT_CIPHER_TKIP: case MT_CIPHER_TKIP_NO_MIC: case MT_CIPHER_GCMP: case MT_CIPHER_GCMP_256: status->iv[0] = data[5]; status->iv[1] = data[4]; status->iv[2] = data[3]; status->iv[3] = data[2]; status->iv[4] = data[1]; status->iv[5] = data[0]; break; default: break; } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_2) { status->timestamp = le32_to_cpu(rxd[0]); status->flag |= RX_FLAG_MACTIME_START; if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | MT_RXD2_NORMAL_NON_AMPDU))) { status->flag |= RX_FLAG_AMPDU_DETAILS; /* all subframes of an A-MPDU have the same timestamp */ if (dev->rx_ampdu_ts != status->timestamp) { if (!++dev->ampdu_ref) dev->ampdu_ref++; } dev->rx_ampdu_ts = status->timestamp; status->ampdu_ref = dev->ampdu_ref; } rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { u32 rxdg0 = le32_to_cpu(rxd[0]); u32 rxdg3 = le32_to_cpu(rxd[3]); bool cck = false; i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0); switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: i = mt76_get_rate(&dev->mt76, sband, i, cck); break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: status->encoding = RX_ENC_HT; if (i > 15) return -EINVAL; break; default: return -EINVAL; } if (rxdg0 & MT_RXV1_HT_SHORT_GI) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (rxdg0 & MT_RXV1_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; status->enc_flags |= RX_ENC_FLAG_STBC_MASK * FIELD_GET(MT_RXV1_HT_STBC, rxdg0); status->rate_idx = i; status->chains = dev->mphy.antenna_mask; status->chain_signal[0] = FIELD_GET(MT_RXV4_IB_RSSI0, rxdg3) + dev->rssi_offset[0]; status->chain_signal[1] = FIELD_GET(MT_RXV4_IB_RSSI1, rxdg3) + dev->rssi_offset[1]; if (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0) == 1) status->bw = RATE_INFO_BW_40; rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } else { return -EINVAL; } skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad); if (insert_ccmp_hdr) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); mt76_insert_ccmp_hdr(skb, key_id); } hdr = (struct ieee80211_hdr *)skb->data; if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) return 0; status->aggr = unicast && !ieee80211_is_qos_nullfunc(hdr->frame_control); status->qos_ctl = *ieee80211_get_qos_ctl(hdr); status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); return 0; } static u16 mt7603_mac_tx_rate_val(struct mt7603_dev *dev, const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw) { u8 phy, nss, rate_idx; u16 rateval; *bw = 0; if (rate->flags & IEEE80211_TX_RC_MCS) { rate_idx = rate->idx; nss = 1 + (rate->idx >> 3); phy = MT_PHY_TYPE_HT; if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) phy = MT_PHY_TYPE_HT_GF; if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) *bw = 1; } else { const struct ieee80211_rate *r; int band = dev->mphy.chandef.chan->band; u16 val; nss = 1; r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx]; if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) val = r->hw_value_short; else val = r->hw_value; phy = val >> 8; rate_idx = val & 0xff; } rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | FIELD_PREP(MT_TX_RATE_MODE, phy)); if (stbc && nss == 1) rateval |= MT_TX_RATE_STBC; return rateval; } void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) { struct ieee80211_tx_rate *ref; int wcid = sta->wcid.idx; u32 addr = mt7603_wtbl2_addr(wcid); bool stbc = false; int n_rates = sta->n_rates; u8 bw, bw_prev, bw_idx = 0; u16 val[4]; u16 probe_val; u32 w9 = mt76_rr(dev, addr + 9 * 4); bool rateset; int i, k; if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) return; for (i = n_rates; i < 4; i++) rates[i] = rates[n_rates - 1]; rateset = !(sta->rate_set_tsf & BIT(0)); memcpy(sta->rateset[rateset].rates, rates, sizeof(sta->rateset[rateset].rates)); if (probe_rate) { sta->rateset[rateset].probe_rate = *probe_rate; ref = &sta->rateset[rateset].probe_rate; } else { sta->rateset[rateset].probe_rate.idx = -1; ref = &sta->rateset[rateset].rates[0]; } rates = sta->rateset[rateset].rates; for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) { /* * We don't support switching between short and long GI * within the rate set. For accurate tx status reporting, we * need to make sure that flags match. * For improved performance, avoid duplicate entries by * decrementing the MCS index if necessary */ if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; for (k = 0; k < i; k++) { if (rates[i].idx != rates[k].idx) continue; if ((rates[i].flags ^ rates[k].flags) & IEEE80211_TX_RC_40_MHZ_WIDTH) continue; if (!rates[i].idx) continue; rates[i].idx--; } } w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | MT_WTBL2_W9_SHORT_GI_80; val[0] = mt7603_mac_tx_rate_val(dev, &rates[0], stbc, &bw); bw_prev = bw; if (probe_rate) { probe_val = mt7603_mac_tx_rate_val(dev, probe_rate, stbc, &bw); if (bw) bw_idx = 1; else bw_prev = 0; } else { probe_val = val[0]; } w9 |= FIELD_PREP(MT_WTBL2_W9_CC_BW_SEL, bw); w9 |= FIELD_PREP(MT_WTBL2_W9_BW_CAP, bw); val[1] = mt7603_mac_tx_rate_val(dev, &rates[1], stbc, &bw); if (bw_prev) { bw_idx = 3; bw_prev = bw; } val[2] = mt7603_mac_tx_rate_val(dev, &rates[2], stbc, &bw); if (bw_prev) { bw_idx = 5; bw_prev = bw; } val[3] = mt7603_mac_tx_rate_val(dev, &rates[3], stbc, &bw); if (bw_prev) bw_idx = 7; w9 |= FIELD_PREP(MT_WTBL2_W9_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7); mt76_wr(dev, MT_WTBL_RIUCR0, w9); mt76_wr(dev, MT_WTBL_RIUCR1, FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1])); mt76_wr(dev, MT_WTBL_RIUCR2, FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) | FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); mt76_wr(dev, MT_WTBL_RIUCR3, FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) | FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset; mt76_wr(dev, MT_WTBL_UPDATE, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | MT_WTBL_UPDATE_RATE_UPDATE | MT_WTBL_UPDATE_TX_COUNT_CLEAR); if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); sta->rate_count = 2 * MT7603_RATE_RETRY * n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; } static enum mt76_cipher_type mt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { memset(key_data, 0, 32); if (!key) return MT_CIPHER_NONE; if (key->keylen > 32) return MT_CIPHER_NONE; memcpy(key_data, key->key, key->keylen); switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: return MT_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: return MT_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: /* Rx/Tx MIC keys are swapped */ memcpy(key_data + 16, key->key + 24, 8); memcpy(key_data + 24, key->key + 16, 8); return MT_CIPHER_TKIP; case WLAN_CIPHER_SUITE_CCMP: return MT_CIPHER_AES_CCMP; default: return MT_CIPHER_NONE; } } int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, struct ieee80211_key_conf *key) { enum mt76_cipher_type cipher; u32 addr = mt7603_wtbl3_addr(wcid); u8 key_data[32]; int key_len = sizeof(key_data); cipher = mt7603_mac_get_key_info(key, key_data); if (cipher == MT_CIPHER_NONE && key) return -EOPNOTSUPP; if (key && (cipher == MT_CIPHER_WEP40 || cipher == MT_CIPHER_WEP104)) { addr += key->keyidx * 16; key_len = 16; } mt76_wr_copy(dev, addr, key_data, key_len); addr = mt7603_wtbl1_addr(wcid); mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_KEY_TYPE, cipher); if (key) mt76_rmw_field(dev, addr, MT_WTBL1_W0_KEY_IDX, key->keyidx); mt76_rmw_field(dev, addr, MT_WTBL1_W0_RX_KEY_VALID, !!key); return 0; } static int mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi, struct sk_buff *skb, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; struct ieee80211_vif *vif = info->control.vif; struct mt76_queue *q = dev->mphy.q_tx[qid]; struct mt7603_vif *mvif; int wlan_idx; int hdr_len = ieee80211_get_hdrlen_from_skb(skb); int tx_count = 8; u8 frame_type, frame_subtype; u16 fc = le16_to_cpu(hdr->frame_control); u16 seqno = 0; u8 vif_idx = 0; u32 val; u8 bw; if (vif) { mvif = (struct mt7603_vif *)vif->drv_priv; vif_idx = mvif->idx; if (vif_idx && qid >= MT_TXQ_BEACON) vif_idx += 0x10; } if (sta) { struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; tx_count = msta->rate_count; } if (wcid) wlan_idx = wcid->idx; else wlan_idx = MT7603_WTBL_RESERVED; frame_type = (fc & IEEE80211_FCTL_FTYPE) >> 2; frame_subtype = (fc & IEEE80211_FCTL_STYPE) >> 4; val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | FIELD_PREP(MT_TXD0_Q_IDX, q->hw_idx); txwi[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_OWN_MAC, vif_idx) | FIELD_PREP(MT_TXD1_TID, skb->priority & IEEE80211_QOS_CTL_TID_MASK) | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, hdr_len / 2) | FIELD_PREP(MT_TXD1_WLAN_IDX, wlan_idx) | FIELD_PREP(MT_TXD1_PROTECTED, !!key); txwi[1] = cpu_to_le32(val); if (info->flags & IEEE80211_TX_CTL_NO_ACK) txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK); val = FIELD_PREP(MT_TXD2_FRAME_TYPE, frame_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, frame_subtype) | FIELD_PREP(MT_TXD2_MULTICAST, is_multicast_ether_addr(hdr->addr1)); txwi[2] = cpu_to_le32(val); if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); txwi[4] = 0; val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT | FIELD_PREP(MT_TXD5_PID, pid); txwi[5] = cpu_to_le32(val); txwi[6] = 0; if (rate->idx >= 0 && rate->count && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { bool stbc = info->flags & IEEE80211_TX_CTL_STBC; u16 rateval = mt7603_mac_tx_rate_val(dev, rate, stbc, &bw); txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); val = MT_TXD6_FIXED_BW | FIELD_PREP(MT_TXD6_BW, bw) | FIELD_PREP(MT_TXD6_TX_RATE, rateval); txwi[6] |= cpu_to_le32(val); if (rate->flags & IEEE80211_TX_RC_SHORT_GI) txwi[6] |= cpu_to_le32(MT_TXD6_SGI); if (!(rate->flags & IEEE80211_TX_RC_MCS)) txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); tx_count = rate->count; } /* use maximum tx count for beacons and buffered multicast */ if (qid >= MT_TXQ_BEACON) tx_count = 0x1f; val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count) | MT_TXD3_SN_VALID; if (ieee80211_is_data_qos(hdr->frame_control)) seqno = le16_to_cpu(hdr->seq_ctrl); else if (ieee80211_is_back_req(hdr->frame_control)) seqno = le16_to_cpu(bar->start_seq_num); else val &= ~MT_TXD3_SN_VALID; val |= FIELD_PREP(MT_TXD3_SEQ, seqno >> 4); txwi[3] = cpu_to_le32(val); if (key) { u64 pn = atomic64_inc_return(&key->tx_pn); txwi[3] |= cpu_to_le32(MT_TXD3_PN_VALID); txwi[4] = cpu_to_le32(pn & GENMASK(31, 0)); txwi[5] |= cpu_to_le32(FIELD_PREP(MT_TXD5_PN_HIGH, pn >> 32)); } txwi[7] = 0; return 0; } int mt7603_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 mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; int pid; if (!wcid) wcid = &dev->global_sta.wcid; if (sta) { msta = (struct mt7603_sta *)sta->drv_priv; if ((info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER | IEEE80211_TX_CTL_CLEAR_PS_FILT)) || (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) mt7603_wtbl_set_ps(dev, msta, false); mt76_tx_check_agg_ssn(sta, tx_info->skb); } pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { spin_lock_bh(&dev->mt76.lock); mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0], msta->rates); msta->rate_probe = true; spin_unlock_bh(&dev->mt76.lock); } mt7603_mac_write_txwi(dev, txwi_ptr, tx_info->skb, qid, wcid, sta, pid, key); return 0; } static bool mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, struct ieee80211_tx_info *info, __le32 *txs_data) { struct ieee80211_supported_band *sband; struct mt7603_rate_set *rs; int first_idx = 0, last_idx; u32 rate_set_tsf; u32 final_rate; u32 final_rate_flags; bool rs_idx; bool ack_timeout; bool fixed_rate; bool probe; bool ampdu; bool cck = false; int count; u32 txs; int idx; int i; fixed_rate = info->status.rates[0].count; probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); txs = le32_to_cpu(txs_data[4]); ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU); count = FIELD_GET(MT_TXS4_TX_COUNT, txs); last_idx = FIELD_GET(MT_TXS4_LAST_TX_RATE, txs); txs = le32_to_cpu(txs_data[0]); final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT)) return false; if (txs & MT_TXS0_QUEUE_TIMEOUT) return false; if (!ack_timeout) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; info->status.ampdu_ack_len = !!(info->flags & IEEE80211_TX_STAT_ACK); if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY); if (fixed_rate && !probe) { info->status.rates[0].count = count; i = 0; goto out; } rate_set_tsf = READ_ONCE(sta->rate_set_tsf); rs_idx = !((u32)(le32_get_bits(txs_data[1], MT_TXS1_F0_TIMESTAMP) - rate_set_tsf) < 1000000); rs_idx ^= rate_set_tsf & BIT(0); rs = &sta->rateset[rs_idx]; if (!first_idx && rs->probe_rate.idx >= 0) { info->status.rates[0] = rs->probe_rate; spin_lock_bh(&dev->mt76.lock); if (sta->rate_probe) { mt7603_wtbl_set_rates(dev, sta, NULL, sta->rates); sta->rate_probe = false; } spin_unlock_bh(&dev->mt76.lock); } else { info->status.rates[0] = rs->rates[first_idx / 2]; } info->status.rates[0].count = 0; for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { struct ieee80211_tx_rate *cur_rate; int cur_count; cur_rate = &rs->rates[idx / 2]; cur_count = min_t(int, MT7603_RATE_RETRY, count); count -= cur_count; if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; if (i == ARRAY_SIZE(info->status.rates)) { i--; break; } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; } info->status.rates[i].count += cur_count; } out: final_rate_flags = info->status.rates[i].flags; switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ) sband = &dev->mphy.sband_5g.sband; else sband = &dev->mphy.sband_2g.sband; final_rate &= GENMASK(5, 0); final_rate = mt76_get_rate(&dev->mt76, sband, final_rate, cck); final_rate_flags = 0; break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: final_rate_flags |= IEEE80211_TX_RC_MCS; final_rate &= GENMASK(5, 0); if (final_rate > 15) return false; break; default: return false; } info->status.rates[i].idx = final_rate; info->status.rates[i].flags = final_rate_flags; return true; } static bool mt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid, __le32 *txs_data) { struct mt76_dev *mdev = &dev->mt76; struct sk_buff_head list; struct sk_buff *skb; if (pid < MT_PACKET_ID_FIRST) return false; trace_mac_txdone(mdev, sta->wcid.idx, pid); mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list); if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7603_fill_txs(dev, sta, info, txs_data)) { info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } mt76_tx_status_skb_done(mdev, skb, &list); } mt76_tx_status_unlock(mdev, &list); return !!skb; } void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; struct mt7603_sta *msta = NULL; struct mt76_wcid *wcid; __le32 *txs_data = data; u8 wcidx; u8 pid; pid = le32_get_bits(txs_data[4], MT_TXS4_PID); wcidx = le32_get_bits(txs_data[3], MT_TXS3_WCID); if (pid == MT_PACKET_ID_NO_ACK) return; if (wcidx >= MT7603_WTBL_SIZE) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wcidx]); if (!wcid) goto out; msta = container_of(wcid, struct mt7603_sta, wcid); sta = wcid_to_sta(wcid); - - if (list_empty(&msta->wcid.poll_list)) { - spin_lock_bh(&dev->mt76.sta_poll_lock); - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); - } + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; if (wcidx >= MT7603_WTBL_STA || !sta) goto out; if (mt7603_fill_txs(dev, msta, &info, txs_data)) { spin_lock_bh(&dev->mt76.rx_lock); ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info); spin_unlock_bh(&dev->mt76.rx_lock); } out: rcu_read_unlock(); } void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct sk_buff *skb = e->skb; if (!e->txwi) { dev_kfree_skb_any(skb); return; } dev->tx_hang_check = 0; mt76_tx_complete_skb(mdev, e->wcid, skb); } static bool wait_for_wpdma(struct mt7603_dev *dev) { return mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000); } static void mt7603_pse_reset(struct mt7603_dev *dev) { /* Clear previous reset result */ if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED]) mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE_S); /* Reset PSE */ mt76_set(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE); if (!mt76_poll_msec(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE_S, MT_MCU_DEBUG_RESET_PSE_S, 500)) { dev->reset_cause[RESET_CAUSE_RESET_FAILED]++; mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE); } else { dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0; mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_QUEUES); } if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] >= 3) dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0; } void mt7603_mac_dma_start(struct mt7603_dev *dev) { mt7603_mac_start(dev); wait_for_wpdma(dev); usleep_range(50, 100); mt76_set(dev, MT_WPDMA_GLO_CFG, (MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN | FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE)); mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL); } void mt7603_mac_start(struct mt7603_dev *dev) { mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); mt76_wr(dev, MT_WF_ARB_TX_START_0, ~0); mt76_set(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); } void mt7603_mac_stop(struct mt7603_dev *dev) { mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); mt76_wr(dev, MT_WF_ARB_TX_START_0, 0); mt76_clear(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START); } void mt7603_pse_client_reset(struct mt7603_dev *dev) { u32 addr; addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_RESET_TX); /* Clear previous reset state */ mt76_clear(dev, addr, MT_CLIENT_RESET_TX_R_E_1 | MT_CLIENT_RESET_TX_R_E_2 | MT_CLIENT_RESET_TX_R_E_1_S | MT_CLIENT_RESET_TX_R_E_2_S); /* Start PSE client TX abort */ + mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_1); mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_1_S, MT_CLIENT_RESET_TX_R_E_1_S, 500); mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_2); mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET); /* Wait for PSE client to clear TX FIFO */ mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_2_S, MT_CLIENT_RESET_TX_R_E_2_S, 500); /* Clear PSE client TX abort state */ mt76_clear(dev, addr, MT_CLIENT_RESET_TX_R_E_1 | MT_CLIENT_RESET_TX_R_E_2); } static void mt7603_dma_sched_reset(struct mt7603_dev *dev) { if (!is_mt7628(dev)) return; mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET); mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET); } static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev) { int beacon_int = dev->mt76.beacon_int; u32 mask = dev->mt76.mmio.irqmask; int i; ieee80211_stop_queues(dev->mt76.hw); set_bit(MT76_RESET, &dev->mphy.state); /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&dev->mt76.tx_worker); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); napi_disable(&dev->mt76.napi[0]); napi_disable(&dev->mt76.napi[1]); napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); mt7603_beacon_set_timer(dev, -1, 0); - if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] || - dev->cur_reset_cause == RESET_CAUSE_RX_PSE_BUSY || - dev->cur_reset_cause == RESET_CAUSE_BEACON_STUCK || - dev->cur_reset_cause == RESET_CAUSE_TX_HANG) - mt7603_pse_reset(dev); - - if (dev->reset_cause[RESET_CAUSE_RESET_FAILED]) - goto skip_dma_reset; - mt7603_mac_stop(dev); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); usleep_range(1000, 2000); mt7603_irq_disable(dev, mask); - mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); - mt7603_pse_client_reset(dev); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true); for (i = 0; i < __MT_TXQ_MAX; i++) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); + mt7603_dma_sched_reset(dev); + + mt76_tx_status_check(&dev->mt76, true); + mt76_for_each_q_rx(&dev->mt76, i) { mt76_queue_rx_reset(dev, i); } - mt76_tx_status_check(&dev->mt76, true); + if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] || + dev->cur_reset_cause == RESET_CAUSE_RX_PSE_BUSY) + mt7603_pse_reset(dev); - mt7603_dma_sched_reset(dev); + if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED]) { + mt7603_mac_dma_start(dev); - mt7603_mac_dma_start(dev); + mt7603_irq_enable(dev, mask); - mt7603_irq_enable(dev, mask); + clear_bit(MT76_RESET, &dev->mphy.state); + } -skip_dma_reset: - clear_bit(MT76_RESET, &dev->mphy.state); mutex_unlock(&dev->mt76.mutex); mt76_worker_enable(&dev->mt76.tx_worker); 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]); + + local_bh_disable(); + napi_schedule(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.napi[0]); napi_schedule(&dev->mt76.napi[1]); local_bh_enable(); ieee80211_wake_queues(dev->mt76.hw); mt76_txq_schedule_all(&dev->mphy); } static u32 mt7603_dma_debug(struct mt7603_dev *dev, u8 index) { u32 val; mt76_wr(dev, MT_WPDMA_DEBUG, FIELD_PREP(MT_WPDMA_DEBUG_IDX, index) | MT_WPDMA_DEBUG_SEL); val = mt76_rr(dev, MT_WPDMA_DEBUG); return FIELD_GET(MT_WPDMA_DEBUG_VALUE, val); } static bool mt7603_rx_fifo_busy(struct mt7603_dev *dev) { if (is_mt7628(dev)) return mt7603_dma_debug(dev, 9) & BIT(9); return mt7603_dma_debug(dev, 2) & BIT(8); } static bool mt7603_rx_dma_busy(struct mt7603_dev *dev) { if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_RX_DMA_BUSY)) return false; return mt7603_rx_fifo_busy(dev); } static bool mt7603_tx_dma_busy(struct mt7603_dev *dev) { u32 val; if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_TX_DMA_BUSY)) return false; val = mt7603_dma_debug(dev, 9); return (val & BIT(8)) && (val & 0xf) != 0xf; } static bool mt7603_tx_hang(struct mt7603_dev *dev) { struct mt76_queue *q; u32 dma_idx, prev_dma_idx; int i; for (i = 0; i < 4; i++) { q = dev->mphy.q_tx[i]; if (!q->queued) continue; prev_dma_idx = dev->tx_dma_idx[i]; dma_idx = readl(&q->regs->dma_idx); dev->tx_dma_idx[i] = dma_idx; if (dma_idx == prev_dma_idx && dma_idx != readl(&q->regs->cpu_idx)) break; } return i < 4; } static bool mt7603_rx_pse_busy(struct mt7603_dev *dev) { u32 addr, val; - if (mt76_rr(dev, MT_MCU_DEBUG_RESET) & MT_MCU_DEBUG_RESET_QUEUES) - return true; - if (mt7603_rx_fifo_busy(dev)) - return false; + goto out; addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_STATUS); mt76_wr(dev, addr, 3); val = mt76_rr(dev, addr) >> 16; - if (is_mt7628(dev) && (val & 0x4001) == 0x4001) - return true; + if (!(val & BIT(0))) + return false; + + if (is_mt7628(dev)) + val &= 0xa000; + else + val &= 0x8000; + if (!val) + return false; + +out: + if (mt76_rr(dev, MT_INT_SOURCE_CSR) & + (MT_INT_RX_DONE(0) | MT_INT_RX_DONE(1))) + return false; - return (val & 0x8001) == 0x8001 || (val & 0xe001) == 0xe001; + return true; } static bool mt7603_watchdog_check(struct mt7603_dev *dev, u8 *counter, enum mt7603_reset_cause cause, bool (*check)(struct mt7603_dev *dev)) { if (dev->reset_test == cause + 1) { dev->reset_test = 0; goto trigger; } if (check) { if (!check(dev) && *counter < MT7603_WATCHDOG_TIMEOUT) { *counter = 0; return false; } (*counter)++; } if (*counter < MT7603_WATCHDOG_TIMEOUT) return false; trigger: dev->cur_reset_cause = cause; dev->reset_cause[cause]++; return true; } void mt7603_update_channel(struct mt76_phy *mphy) { struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); struct mt76_channel_state *state; state = mphy->chan_state; state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val) { u32 rxtd_6 = 0xd7c80000; if (val == dev->ed_strict_mode) return; dev->ed_strict_mode = val; /* Ensure that ED/CCA does not trigger if disabled */ if (!dev->ed_monitor) rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x34); else rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x7d); if (dev->ed_monitor && !dev->ed_strict_mode) rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x0f); else rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x10); mt76_wr(dev, MT_RXTD(6), rxtd_6); mt76_rmw_field(dev, MT_RXTD(13), MT_RXTD_13_ACI_TH_EN, dev->ed_monitor && !dev->ed_strict_mode); } static void mt7603_edcca_check(struct mt7603_dev *dev) { u32 val = mt76_rr(dev, MT_AGC(41)); ktime_t cur_time; int rssi0, rssi1; u32 active; u32 ed_busy; if (!dev->ed_monitor) return; rssi0 = FIELD_GET(MT_AGC_41_RSSI_0, val); if (rssi0 > 128) rssi0 -= 256; if (dev->mphy.antenna_mask & BIT(1)) { rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val); if (rssi1 > 128) rssi1 -= 256; } else { rssi1 = rssi0; } if (max(rssi0, rssi1) >= -40 && dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH) dev->ed_strong_signal++; else if (dev->ed_strong_signal > 0) dev->ed_strong_signal--; cur_time = ktime_get_boottime(); ed_busy = mt76_rr(dev, MT_MIB_STAT_ED) & MT_MIB_STAT_ED_MASK; active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); dev->ed_time = cur_time; if (!active) return; if (100 * ed_busy / active > 90) { if (dev->ed_trigger < 0) dev->ed_trigger = 0; dev->ed_trigger++; } else { if (dev->ed_trigger > 0) dev->ed_trigger = 0; dev->ed_trigger--; } if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH || dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH / 2) { mt7603_edcca_set_strict(dev, true); } else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) { mt7603_edcca_set_strict(dev, false); } if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH) dev->ed_trigger = MT7603_EDCCA_BLOCK_TH; else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) dev->ed_trigger = -MT7603_EDCCA_BLOCK_TH; } void mt7603_cca_stats_reset(struct mt7603_dev *dev) { mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET); mt76_clear(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET); mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_EN); } static void mt7603_adjust_sensitivity(struct mt7603_dev *dev) { u32 agc0 = dev->agc0, agc3 = dev->agc3; u32 adj; if (!dev->sensitivity || dev->sensitivity < -100) { dev->sensitivity = 0; } else if (dev->sensitivity <= -84) { adj = 7 + (dev->sensitivity + 92) / 2; agc0 = 0x56f0076f; agc0 |= adj << 12; agc0 |= adj << 16; agc3 = 0x81d0d5e3; } else if (dev->sensitivity <= -72) { adj = 7 + (dev->sensitivity + 80) / 2; agc0 = 0x6af0006f; agc0 |= adj << 8; agc0 |= adj << 12; agc0 |= adj << 16; agc3 = 0x8181d5e3; } else { if (dev->sensitivity > -54) dev->sensitivity = -54; adj = 7 + (dev->sensitivity + 80) / 2; agc0 = 0x7ff0000f; agc0 |= adj << 4; agc0 |= adj << 8; agc0 |= adj << 12; agc0 |= adj << 16; agc3 = 0x818181e3; } mt76_wr(dev, MT_AGC(0), agc0); mt76_wr(dev, MT_AGC1(0), agc0); mt76_wr(dev, MT_AGC(3), agc3); mt76_wr(dev, MT_AGC1(3), agc3); } static void mt7603_false_cca_check(struct mt7603_dev *dev) { int pd_cck, pd_ofdm, mdrdy_cck, mdrdy_ofdm; int false_cca; int min_signal; u32 val; if (!dev->dynamic_sensitivity) return; val = mt76_rr(dev, MT_PHYCTRL_STAT_PD); pd_cck = FIELD_GET(MT_PHYCTRL_STAT_PD_CCK, val); pd_ofdm = FIELD_GET(MT_PHYCTRL_STAT_PD_OFDM, val); val = mt76_rr(dev, MT_PHYCTRL_STAT_MDRDY); mdrdy_cck = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_CCK, val); mdrdy_ofdm = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_OFDM, val); dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm; dev->false_cca_cck = pd_cck - mdrdy_cck; mt7603_cca_stats_reset(dev); - min_signal = mt76_get_min_avg_rssi(&dev->mt76, false); + min_signal = mt76_get_min_avg_rssi(&dev->mt76, 0); if (!min_signal) { dev->sensitivity = 0; dev->last_cca_adj = jiffies; goto out; } min_signal -= 15; false_cca = dev->false_cca_ofdm + dev->false_cca_cck; if (false_cca > 600 && dev->sensitivity < -100 + dev->sensitivity_limit) { if (!dev->sensitivity) dev->sensitivity = -92; else dev->sensitivity += 2; dev->last_cca_adj = jiffies; } else if (false_cca < 100 || time_after(jiffies, dev->last_cca_adj + 10 * HZ)) { dev->last_cca_adj = jiffies; if (!dev->sensitivity) goto out; dev->sensitivity -= 2; } if (dev->sensitivity && dev->sensitivity > min_signal) { dev->sensitivity = min_signal; dev->last_cca_adj = jiffies; } out: mt7603_adjust_sensitivity(dev); } void mt7603_mac_work(struct work_struct *work) { struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mphy.mac_work.work); bool reset = false; int i, idx; mt76_tx_status_check(&dev->mt76, false); mutex_lock(&dev->mt76.mutex); dev->mphy.mac_work_count++; mt76_update_survey(&dev->mphy); mt7603_edcca_check(dev); for (i = 0, idx = 0; i < 2; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); dev->mphy.aggr_stats[idx++] += val & 0xffff; dev->mphy.aggr_stats[idx++] += val >> 16; } if (dev->mphy.mac_work_count == 10) mt7603_false_cca_check(dev); if (mt7603_watchdog_check(dev, &dev->rx_pse_check, RESET_CAUSE_RX_PSE_BUSY, mt7603_rx_pse_busy) || mt7603_watchdog_check(dev, &dev->beacon_check, RESET_CAUSE_BEACON_STUCK, NULL) || mt7603_watchdog_check(dev, &dev->tx_hang_check, RESET_CAUSE_TX_HANG, mt7603_tx_hang) || mt7603_watchdog_check(dev, &dev->tx_dma_check, RESET_CAUSE_TX_BUSY, mt7603_tx_dma_busy) || mt7603_watchdog_check(dev, &dev->rx_dma_check, RESET_CAUSE_RX_BUSY, mt7603_rx_dma_busy) || mt7603_watchdog_check(dev, &dev->mcu_hang, RESET_CAUSE_MCU_HANG, NULL) || dev->reset_cause[RESET_CAUSE_RESET_FAILED]) { dev->beacon_check = 0; dev->tx_dma_check = 0; dev->tx_hang_check = 0; dev->rx_dma_check = 0; dev->rx_pse_check = 0; dev->mcu_hang = 0; dev->rx_dma_idx = ~0; memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx)); reset = true; dev->mphy.mac_work_count = 0; } if (dev->mphy.mac_work_count >= 10) dev->mphy.mac_work_count = 0; mutex_unlock(&dev->mt76.mutex); if (reset) mt7603_mac_watchdog_reset(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, msecs_to_jiffies(MT7603_WATCHDOG_TIME)); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/main.c b/sys/contrib/dev/mediatek/mt76/mt7603/main.c index c213fd2a5216..3e8b1ec76169 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/main.c @@ -1,758 +1,754 @@ // SPDX-License-Identifier: ISC #include #include #include #include #include "mt7603.h" #include "mac.h" #include "eeprom.h" static int mt7603_start(struct ieee80211_hw *hw) { struct mt7603_dev *dev = hw->priv; mt7603_mac_reset_counters(dev); mt7603_mac_start(dev); dev->mphy.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); mt7603_mac_work(&dev->mphy.mac_work.work); return 0; } static void -mt7603_stop(struct ieee80211_hw *hw) +mt7603_stop(struct ieee80211_hw *hw, bool suspend) { struct mt7603_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); cancel_delayed_work_sync(&dev->mphy.mac_work); mt7603_mac_stop(dev); } static int mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct mt7603_dev *dev = hw->priv; struct mt76_txq *mtxq; u8 bc_addr[ETH_ALEN]; int idx; int ret = 0; mutex_lock(&dev->mt76.mutex); mvif->idx = __ffs64(~dev->mt76.vif_mask); if (mvif->idx >= MT7603_MAX_INTERFACES) { ret = -ENOSPC; goto out; } mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), get_unaligned_le32(vif->addr)); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), (get_unaligned_le16(vif->addr + 4) | MT_MAC_ADDR1_VALID)); if (vif->type == NL80211_IFTYPE_AP) { mt76_wr(dev, MT_BSSID0(mvif->idx), get_unaligned_le32(vif->addr)); mt76_wr(dev, MT_BSSID1(mvif->idx), (get_unaligned_le16(vif->addr + 4) | MT_BSSID1_VALID)); } idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; dev->mt76.vif_mask |= BIT_ULL(mvif->idx); - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.hw_key_idx = -1; mvif->sta.vif = mvif; - mt76_packet_id_init(&mvif->sta.wcid); + mt76_wcid_init(&mvif->sta.wcid, 0); eth_broadcast_addr(bc_addr); mt7603_wtbl_init(dev, idx, mvif->idx, bc_addr); mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); out: mutex_unlock(&dev->mt76.mutex); return ret; } static void mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct mt7603_sta *msta = &mvif->sta; struct mt7603_dev *dev = hw->priv; int idx = msta->wcid.idx; mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0); mt76_wr(dev, MT_BSSID0(mvif->idx), 0); mt76_wr(dev, MT_BSSID1(mvif->idx), 0); mt7603_beacon_set_timer(dev, mvif->idx, 0); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); mutex_lock(&dev->mt76.mutex); dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx); mutex_unlock(&dev->mt76.mutex); - mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid); + mt76_wcid_cleanup(&dev->mt76, &mvif->sta.wcid); } void mt7603_init_edcca(struct mt7603_dev *dev) { /* Set lower signal level to -65dBm */ mt76_rmw_field(dev, MT_RXTD(8), MT_RXTD_8_LOWER_SIGNAL, 0x23); /* clear previous energy detect monitor results */ mt76_rr(dev, MT_MIB_STAT_ED); if (dev->ed_monitor) mt76_set(dev, MT_MIB_CTL, MT_MIB_CTL_ED_TIME); else mt76_clear(dev, MT_MIB_CTL, MT_MIB_CTL_ED_TIME); dev->ed_strict_mode = 0xff; dev->ed_strong_signal = 0; dev->ed_time = ktime_get_boottime(); mt7603_edcca_set_strict(dev, false); } -static int -mt7603_set_channel(struct ieee80211_hw *hw, struct cfg80211_chan_def *def) +int mt7603_set_channel(struct mt76_phy *mphy) { - struct mt7603_dev *dev = hw->priv; + struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76); + struct cfg80211_chan_def *def = &mphy->chandef; + u8 *rssi_data = (u8 *)dev->mt76.eeprom.data; int idx, ret; u8 bw = MT_BW_20; bool failed = false; - ieee80211_stop_queues(hw); - cancel_delayed_work_sync(&dev->mphy.mac_work); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); - mutex_lock(&dev->mt76.mutex); - set_bit(MT76_RESET, &dev->mphy.state); - mt7603_beacon_set_timer(dev, -1, 0); - mt76_set_channel(&dev->mphy); mt7603_mac_stop(dev); if (def->width == NL80211_CHAN_WIDTH_40) bw = MT_BW_40; - dev->mphy.chandef = *def; mt76_rmw_field(dev, MT_AGG_BWCR, MT_AGG_BWCR_BW, bw); ret = mt7603_mcu_set_channel(dev); if (ret) { failed = true; goto out; } if (def->chan->band == NL80211_BAND_5GHZ) { idx = 1; rssi_data += MT_EE_RSSI_OFFSET_5G; } else { idx = 0; rssi_data += MT_EE_RSSI_OFFSET_2G; } memcpy(dev->rssi_offset, rssi_data, sizeof(dev->rssi_offset)); idx |= (def->chan - mt76_hw(dev)->wiphy->bands[def->chan->band]->channels) << 1; mt76_wr(dev, MT_WF_RMAC_CH_FREQ, idx); mt7603_mac_set_timing(dev); mt7603_mac_start(dev); - clear_bit(MT76_RESET, &dev->mphy.state); - - mt76_txq_schedule_all(&dev->mphy); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, msecs_to_jiffies(MT7603_WATCHDOG_TIME)); /* reset channel stats */ mt76_clear(dev, MT_MIB_CTL, MT_MIB_CTL_READ_CLR_DIS); mt76_set(dev, MT_MIB_CTL, MT_MIB_CTL_CCA_NAV_TX | MT_MIB_CTL_PSCCA_TIME); mt76_rr(dev, MT_MIB_STAT_CCA); mt7603_cca_stats_reset(dev); dev->mphy.survey_time = ktime_get_boottime(); mt7603_init_edcca(dev); out: - if (!(mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + if (!mphy->offchannel) mt7603_beacon_set_timer(dev, -1, dev->mt76.beacon_int); - mutex_unlock(&dev->mt76.mutex); tasklet_enable(&dev->mt76.pre_tbtt_tasklet); if (failed) mt7603_mac_work(&dev->mphy.mac_work.work); - ieee80211_wake_queues(hw); - return ret; } static int mt7603_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt7603_dev *dev = hw->priv; struct mt76_phy *mphy = &dev->mphy; int err; if (!cfg80211_chandef_valid(&mphy->chandef)) return -EINVAL; err = mt76_init_sar_power(hw, sar); if (err) return err; - return mt7603_set_channel(hw, &mphy->chandef); + return mt76_update_channel(mphy); } static int mt7603_config(struct ieee80211_hw *hw, u32 changed) { struct mt7603_dev *dev = hw->priv; int ret = 0; if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_POWER)) - ret = mt7603_set_channel(hw, &hw->conf.chandef); + ret = mt76_update_channel(&dev->mphy); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { mutex_lock(&dev->mt76.mutex); if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) dev->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; else dev->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; mt76_wr(dev, MT_WF_RFCR, dev->rxfilter); mutex_unlock(&dev->mt76.mutex); } return ret; } static void mt7603_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mt7603_dev *dev = hw->priv; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ dev->rxfilter &= ~(_hw); \ dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ } while (0) dev->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | MT_WF_RFCR_DROP_OTHER_BEACON | MT_WF_RFCR_DROP_FRAME_REPORT | MT_WF_RFCR_DROP_PROBEREQ | MT_WF_RFCR_DROP_MCAST_FILTERED | MT_WF_RFCR_DROP_MCAST | MT_WF_RFCR_DROP_BCAST | MT_WF_RFCR_DROP_DUPLICATE | MT_WF_RFCR_DROP_A2_BSSID | MT_WF_RFCR_DROP_UNWANTED_CTL | MT_WF_RFCR_DROP_STBC_MULTI); MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | MT_WF_RFCR_DROP_A3_MAC | MT_WF_RFCR_DROP_A3_BSSID); MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | MT_WF_RFCR_DROP_RTS | MT_WF_RFCR_DROP_CTL_RSV | MT_WF_RFCR_DROP_NDPA); *total_flags = flags; mt76_wr(dev, MT_WF_RFCR, dev->rxfilter); } static void mt7603_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { struct mt7603_dev *dev = hw->priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; mutex_lock(&dev->mt76.mutex); if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID)) { if (vif->cfg.assoc || vif->cfg.ibss_joined) { mt76_wr(dev, MT_BSSID0(mvif->idx), get_unaligned_le32(info->bssid)); mt76_wr(dev, MT_BSSID1(mvif->idx), (get_unaligned_le16(info->bssid + 4) | MT_BSSID1_VALID)); } else { mt76_wr(dev, MT_BSSID0(mvif->idx), 0); mt76_wr(dev, MT_BSSID1(mvif->idx), 0); } } if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; if (slottime != dev->slottime) { dev->slottime = slottime; mt7603_mac_set_timing(dev); } } if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON_INT)) { int beacon_int = !!info->enable_beacon * info->beacon_int; tasklet_disable(&dev->mt76.pre_tbtt_tasklet); mt7603_beacon_set_timer(dev, mvif->idx, beacon_int); tasklet_enable(&dev->mt76.pre_tbtt_tasklet); } mutex_unlock(&dev->mt76.mutex); } int mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; int idx; int ret = 0; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7603_WTBL_STA - 1); if (idx < 0) return -ENOSPC; INIT_LIST_HEAD(&msta->wcid.poll_list); __skb_queue_head_init(&msta->psq); msta->ps = ~0; msta->smps = ~0; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->vif = mvif; mt7603_wtbl_init(dev, idx, mvif->idx, sta->addr); mt7603_wtbl_set_ps(dev, msta, false); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); return ret; } -void -mt7603_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int +mt7603_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); - mt7603_wtbl_update_cap(dev, sta); + if (ev == MT76_STA_EVENT_ASSOC) { + mutex_lock(&dev->mt76.mutex); + mt7603_wtbl_update_cap(dev, sta); + mutex_unlock(&dev->mt76.mutex); + } + + return 0; } void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; spin_lock_bh(&dev->ps_lock); __skb_queue_purge(&msta->psq); mt7603_filter_tx(dev, mvif->idx, wcid->idx, true); spin_unlock_bh(&dev->ps_lock); spin_lock_bh(&mdev->sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&mdev->sta_poll_lock); mt7603_wtbl_clear(dev, wcid->idx); } static void mt7603_ps_tx_list(struct mt7603_dev *dev, struct sk_buff_head *list) { struct sk_buff *skb; while ((skb = __skb_dequeue(list)) != NULL) { int qid = skb_get_queue_mapping(skb); mt76_tx_queue_skb_raw(dev, dev->mphy.q_tx[qid], skb, 0); } } void mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct sk_buff_head list; mt76_stop_tx_queues(&dev->mphy, sta, true); mt7603_wtbl_set_ps(dev, msta, ps); if (ps) return; __skb_queue_head_init(&list); spin_lock_bh(&dev->ps_lock); skb_queue_splice_tail_init(&msta->psq, &list); spin_unlock_bh(&dev->ps_lock); mt7603_ps_tx_list(dev, &list); } static void mt7603_ps_set_more_data(struct sk_buff *skb) { struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } static void mt7603_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data) { struct mt7603_dev *dev = hw->priv; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct sk_buff_head list; struct sk_buff *skb, *tmp; __skb_queue_head_init(&list); mt7603_wtbl_set_ps(dev, msta, false); spin_lock_bh(&dev->ps_lock); skb_queue_walk_safe(&msta->psq, skb, tmp) { if (!nframes) break; if (!(tids & BIT(skb->priority))) continue; skb_set_queue_mapping(skb, MT_TXQ_PSD); __skb_unlink(skb, &msta->psq); mt7603_ps_set_more_data(skb); __skb_queue_tail(&list, skb); nframes--; } spin_unlock_bh(&dev->ps_lock); if (!skb_queue_empty(&list)) ieee80211_sta_eosp(sta); mt7603_ps_tx_list(dev, &list); if (nframes) mt76_release_buffered_frames(hw, sta, tids, nframes, reason, more_data); } static int mt7603_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mt7603_dev *dev = hw->priv; struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; struct mt7603_sta *msta = sta ? (struct mt7603_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->wcid; int idx = key->keyidx; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: break; default: return -EOPNOTSUPP; } /* * The hardware does not support per-STA RX GTK, fall back * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; if (cmd != SET_KEY) { if (idx == wcid->hw_key_idx) wcid->hw_key_idx = -1; return 0; } key->hw_key_idx = wcid->idx; wcid->hw_key_idx = idx; mt76_wcid_key_setup(&dev->mt76, wcid, key); return mt7603_wtbl_set_key(dev, wcid->idx, key); } static int mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt7603_dev *dev = hw->priv; u16 cw_min = (1 << 5) - 1; u16 cw_max = (1 << 10) - 1; u32 val; queue = dev->mphy.q_tx[queue]->hw_idx; if (params->cw_min) cw_min = params->cw_min; if (params->cw_max) cw_max = params->cw_max; mutex_lock(&dev->mt76.mutex); mt7603_mac_stop(dev); val = mt76_rr(dev, MT_WMM_TXOP(queue)); val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(queue)); val |= params->txop << MT_WMM_TXOP_SHIFT(queue); mt76_wr(dev, MT_WMM_TXOP(queue), val); val = mt76_rr(dev, MT_WMM_AIFSN); val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(queue)); val |= params->aifs << MT_WMM_AIFSN_SHIFT(queue); mt76_wr(dev, MT_WMM_AIFSN, val); val = mt76_rr(dev, MT_WMM_CWMIN); val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(queue)); val |= cw_min << MT_WMM_CWMIN_SHIFT(queue); mt76_wr(dev, MT_WMM_CWMIN, val); val = mt76_rr(dev, MT_WMM_CWMAX(queue)); val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(queue)); val |= cw_max << MT_WMM_CWMAX_SHIFT(queue); mt76_wr(dev, MT_WMM_CWMAX(queue), val); mt7603_mac_start(dev); mutex_unlock(&dev->mt76.mutex); return 0; } static void mt7603_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { } static int mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct mt7603_dev *dev = hw->priv; struct ieee80211_sta *sta = params->sta; struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; u16 tid = params->tid; u16 ssn = params->ssn; u8 ba_size = params->buf_size; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); mt7603_mac_rx_ba_reset(dev, sta->addr, tid); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, ba_size); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1); break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mutex_unlock(&dev->mt76.mutex); return ret; } static void mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7603_dev *dev = hw->priv; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; if (!sta_rates) return; spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; msta->rates[i].count = sta_rates->rate[i].count; msta->rates[i].flags = sta_rates->rate[i].flags; if (msta->rates[i].idx < 0 || !msta->rates[i].count) break; } msta->n_rates = i; mt7603_wtbl_set_rates(dev, msta, NULL, msta->rates); msta->rate_probe = false; mt7603_wtbl_set_smps(dev, msta, sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC); spin_unlock_bh(&dev->mt76.lock); } static void mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7603_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); dev->coverage_class = max_t(s16, coverage_class, 0); mt7603_mac_set_timing(dev); mutex_unlock(&dev->mt76.mutex); } static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt7603_dev *dev = hw->priv; struct mt76_wcid *wcid = &dev->global_sta.wcid; if (control->sta) { struct mt7603_sta *msta; msta = (struct mt7603_sta *)control->sta->drv_priv; wcid = &msta->wcid; } else if (vif) { struct mt7603_vif *mvif; mvif = (struct mt7603_vif *)vif->drv_priv; wcid = &mvif->sta.wcid; } mt76_tx(&dev->mphy, control->sta, wcid, skb); } const struct ieee80211_ops mt7603_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7603_tx, .start = mt7603_start, .stop = mt7603_stop, .add_interface = mt7603_add_interface, .remove_interface = mt7603_remove_interface, .config = mt7603_config, .configure_filter = mt7603_configure_filter, .bss_info_changed = mt7603_bss_info_changed, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7603_set_key, .conf_tx = mt7603_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76_sw_scan_complete, .flush = mt7603_flush, .ampdu_action = mt7603_ampdu_action, .get_txpower = mt76_get_txpower, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt7603_sta_rate_tbl_update, .release_buffered_frames = mt7603_release_buffered_frames, .set_coverage_class = mt7603_set_coverage_class, .set_tim = mt76_set_tim, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_sar_specs = mt7603_set_sar_specs, }; +MODULE_DESCRIPTION("MediaTek MT7603E and MT76x8 wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static int __init mt7603_init(void) { int ret; ret = platform_driver_register(&mt76_wmac_driver); if (ret) return ret; #ifdef CONFIG_PCI ret = pci_register_driver(&mt7603_pci_driver); if (ret) platform_driver_unregister(&mt76_wmac_driver); #endif return ret; } static void __exit mt7603_exit(void) { #ifdef CONFIG_PCI pci_unregister_driver(&mt7603_pci_driver); #endif platform_driver_unregister(&mt76_wmac_driver); } module_init(mt7603_init); module_exit(mt7603_exit); diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/mt7603.h b/sys/contrib/dev/mediatek/mt76/mt7603/mt7603.h index 9e58df7042ad..55a034ccbacd 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/mt7603.h +++ b/sys/contrib/dev/mediatek/mt76/mt7603/mt7603.h @@ -1,261 +1,262 @@ /* SPDX-License-Identifier: ISC */ #ifndef __MT7603_H #define __MT7603_H #include #include #include "../mt76.h" #include "regs.h" #define MT7603_MAX_INTERFACES 4 #define MT7603_WTBL_SIZE 128 #define MT7603_WTBL_RESERVED (MT7603_WTBL_SIZE - 1) #define MT7603_WTBL_STA (MT7603_WTBL_RESERVED - MT7603_MAX_INTERFACES) #define MT7603_RATE_RETRY 2 #define MT7603_MCU_RX_RING_SIZE 64 #define MT7603_RX_RING_SIZE 128 #define MT7603_TX_RING_SIZE 256 #define MT7603_PSD_RING_SIZE 128 #define MT7603_FIRMWARE_E1 "mt7603_e1.bin" #define MT7603_FIRMWARE_E2 "mt7603_e2.bin" #define MT7628_FIRMWARE_E1 "mt7628_e1.bin" #define MT7628_FIRMWARE_E2 "mt7628_e2.bin" #define MT7603_EEPROM_SIZE 1024 #define MT_AGG_SIZE_LIMIT(_n) (((_n) + 1) * 4) #define MT7603_PRE_TBTT_TIME 5000 /* ms */ #define MT7603_WATCHDOG_TIME 100 /* ms */ #define MT7603_WATCHDOG_TIMEOUT 10 /* number of checks */ #define MT7603_EDCCA_BLOCK_TH 10 #define MT7603_CFEND_RATE_DEFAULT 0x69 /* chip default (24M) */ #define MT7603_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ struct mt7603_vif; struct mt7603_sta; enum { MT7603_REV_E1 = 0x00, MT7603_REV_E2 = 0x10, MT7628_REV_E1 = 0x8a00, }; enum mt7603_bw { MT_BW_20, MT_BW_40, MT_BW_80, }; struct mt7603_rate_set { struct ieee80211_tx_rate probe_rate; struct ieee80211_tx_rate rates[4]; }; struct mt7603_sta { struct mt76_wcid wcid; /* must be first */ struct mt7603_vif *vif; u32 tx_airtime_ac[4]; struct sk_buff_head psq; struct ieee80211_tx_rate rates[4]; struct mt7603_rate_set rateset[2]; u32 rate_set_tsf; u8 rate_count; u8 n_rates; u8 rate_probe; u8 smps; u8 ps; }; struct mt7603_vif { struct mt7603_sta sta; /* must be first */ u8 idx; }; enum mt7603_reset_cause { RESET_CAUSE_TX_HANG, RESET_CAUSE_TX_BUSY, RESET_CAUSE_RX_BUSY, RESET_CAUSE_BEACON_STUCK, RESET_CAUSE_RX_PSE_BUSY, RESET_CAUSE_MCU_HANG, RESET_CAUSE_RESET_FAILED, __RESET_CAUSE_MAX }; struct mt7603_dev { union { /* must be first */ struct mt76_dev mt76; struct mt76_phy mphy; }; const struct mt76_bus_ops *bus_ops; u32 rxfilter; struct mt7603_sta global_sta; u32 agc0, agc3; u32 false_cca_ofdm, false_cca_cck; unsigned long last_cca_adj; u32 ampdu_ref; u32 rx_ampdu_ts; u8 rssi_offset[3]; u8 slottime; s16 coverage_class; s8 tx_power_limit; ktime_t ed_time; spinlock_t ps_lock; u8 mcu_running; u8 ed_monitor_enabled; u8 ed_monitor; s8 ed_trigger; u8 ed_strict_mode; u8 ed_strong_signal; bool dynamic_sensitivity; s8 sensitivity; u8 sensitivity_limit; u8 beacon_check; u8 tx_hang_check; u8 tx_dma_check; u8 rx_dma_check; u8 rx_pse_check; u8 mcu_hang; enum mt7603_reset_cause cur_reset_cause; u16 tx_dma_idx[4]; u16 rx_dma_idx; u32 reset_test; unsigned int reset_cause[__RESET_CAUSE_MAX]; }; extern const struct mt76_driver_ops mt7603_drv_ops; extern const struct ieee80211_ops mt7603_ops; extern struct pci_driver mt7603_pci_driver; extern struct platform_driver mt76_wmac_driver; static inline bool is_mt7603(struct mt7603_dev *dev) { return mt76xx_chip(dev) == 0x7603; } static inline bool is_mt7628(struct mt7603_dev *dev) { return mt76xx_chip(dev) == 0x7628; } /* need offset to prevent conflict with ampdu_ack_len */ #define MT_RATE_DRIVER_DATA_OFFSET 4 u32 mt7603_reg_map(struct mt7603_dev *dev, u32 addr); irqreturn_t mt7603_irq_handler(int irq, void *dev_instance); int mt7603_register_device(struct mt7603_dev *dev); void mt7603_unregister_device(struct mt7603_dev *dev); int mt7603_eeprom_init(struct mt7603_dev *dev); int mt7603_dma_init(struct mt7603_dev *dev); void mt7603_dma_cleanup(struct mt7603_dev *dev); int mt7603_mcu_init(struct mt7603_dev *dev); void mt7603_init_debugfs(struct mt7603_dev *dev); static inline void mt7603_irq_enable(struct mt7603_dev *dev, u32 mask) { mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask); } static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) { mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } void mt7603_mac_reset_counters(struct mt7603_dev *dev); void mt7603_mac_dma_start(struct mt7603_dev *dev); void mt7603_mac_start(struct mt7603_dev *dev); void mt7603_mac_stop(struct mt7603_dev *dev); void mt7603_mac_work(struct work_struct *work); void mt7603_mac_set_timing(struct mt7603_dev *dev); void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval); int mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb); void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size); void mt7603_mac_sta_poll(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev); +int mt7603_set_channel(struct mt76_phy *mphy); int mt7603_mcu_set_channel(struct mt7603_dev *dev); int mt7603_mcu_set_eeprom(struct mt7603_dev *dev); void mt7603_mcu_exit(struct mt7603_dev *dev); void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, const u8 *mac_addr); void mt7603_wtbl_clear(struct mt7603_dev *dev, int idx); void mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta); void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, struct ieee80211_key_conf *key); void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled); void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled); void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort); int mt7603_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 mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); void mt7603_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); void mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); int mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -void mt7603_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); +int mt7603_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t); void mt7603_update_channel(struct mt76_phy *mphy); void mt7603_edcca_set_strict(struct mt7603_dev *dev, bool val); void mt7603_cca_stats_reset(struct mt7603_dev *dev); void mt7603_init_edcca(struct mt7603_dev *dev); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/regs.h b/sys/contrib/dev/mediatek/mt76/mt7603/regs.h index a39c9a0fcb1c..524bceb8e958 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/regs.h +++ b/sys/contrib/dev/mediatek/mt76/mt7603/regs.h @@ -1,775 +1,780 @@ /* SPDX-License-Identifier: ISC */ #ifndef __MT7603_REGS_H #define __MT7603_REGS_H #define MT_HW_REV 0x1000 #define MT_HW_CHIPID 0x1008 #define MT_TOP_MISC2 0x1134 #define MT_MCU_BASE 0x2000 #define MT_MCU(ofs) (MT_MCU_BASE + (ofs)) #define MT_MCU_PCIE_REMAP_1 MT_MCU(0x500) #define MT_MCU_PCIE_REMAP_1_OFFSET GENMASK(17, 0) #define MT_MCU_PCIE_REMAP_1_BASE GENMASK(31, 18) #define MT_MCU_PCIE_REMAP_2 MT_MCU(0x504) #define MT_MCU_PCIE_REMAP_2_OFFSET GENMASK(18, 0) #define MT_MCU_PCIE_REMAP_2_BASE GENMASK(31, 19) #define MT_HIF_BASE 0x4000 #define MT_HIF(ofs) (MT_HIF_BASE + (ofs)) #define MT_INT_SOURCE_CSR MT_HIF(0x200) #define MT_INT_MASK_CSR MT_HIF(0x204) #define MT_DELAY_INT_CFG MT_HIF(0x210) #define MT_INT_RX_DONE(_n) BIT(_n) #define MT_INT_RX_DONE_ALL GENMASK(1, 0) #define MT_INT_TX_DONE_ALL GENMASK(19, 4) #define MT_INT_TX_DONE(_n) BIT((_n) + 4) #define MT_INT_RX_COHERENT BIT(20) #define MT_INT_TX_COHERENT BIT(21) #define MT_INT_MAC_IRQ3 BIT(27) #define MT_INT_MCU_CMD BIT(30) #define MT_WPDMA_GLO_CFG MT_HIF(0x208) #define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) #define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) #define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) #define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) #define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) #define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) #define MT_WPDMA_GLO_CFG_SW_RESET BIT(24) #define MT_WPDMA_GLO_CFG_FORCE_TX_EOF BIT(25) #define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) #define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) #define MT_WPDMA_RST_IDX MT_HIF(0x20c) #define MT_WPDMA_DEBUG MT_HIF(0x244) #define MT_WPDMA_DEBUG_VALUE GENMASK(17, 0) #define MT_WPDMA_DEBUG_SEL BIT(27) #define MT_WPDMA_DEBUG_IDX GENMASK(31, 28) #define MT_TX_RING_BASE MT_HIF(0x300) #define MT_RX_RING_BASE MT_HIF(0x400) #define MT_TXTIME_THRESH_BASE MT_HIF(0x500) #define MT_TXTIME_THRESH(n) (MT_TXTIME_THRESH_BASE + ((n) * 4)) #define MT_PAGE_COUNT_BASE MT_HIF(0x540) #define MT_PAGE_COUNT(n) (MT_PAGE_COUNT_BASE + ((n) * 4)) #define MT_SCH_1 MT_HIF(0x588) #define MT_SCH_2 MT_HIF(0x58c) #define MT_SCH_3 MT_HIF(0x590) #define MT_SCH_4 MT_HIF(0x594) #define MT_SCH_4_FORCE_QID GENMASK(4, 0) #define MT_SCH_4_BYPASS BIT(5) #define MT_SCH_4_RESET BIT(8) #define MT_GROUP_THRESH_BASE MT_HIF(0x598) #define MT_GROUP_THRESH(n) (MT_GROUP_THRESH_BASE + ((n) * 4)) #define MT_QUEUE_PRIORITY_1 MT_HIF(0x580) #define MT_QUEUE_PRIORITY_2 MT_HIF(0x584) #define MT_BMAP_0 MT_HIF(0x5b0) #define MT_BMAP_1 MT_HIF(0x5b4) #define MT_BMAP_2 MT_HIF(0x5b8) #define MT_HIGH_PRIORITY_1 MT_HIF(0x5bc) #define MT_HIGH_PRIORITY_2 MT_HIF(0x5c0) #define MT_PRIORITY_MASK MT_HIF(0x5c4) #define MT_RSV_MAX_THRESH MT_HIF(0x5c8) #define MT_PSE_BASE 0x8000 #define MT_PSE(ofs) (MT_PSE_BASE + (ofs)) #define MT_MCU_DEBUG_RESET MT_PSE(0x16c) #define MT_MCU_DEBUG_RESET_PSE BIT(0) #define MT_MCU_DEBUG_RESET_PSE_S BIT(1) #define MT_MCU_DEBUG_RESET_QUEUES GENMASK(6, 2) #define MT_PSE_FC_P0 MT_PSE(0x120) #define MT_PSE_FC_P0_MIN_RESERVE GENMASK(11, 0) #define MT_PSE_FC_P0_MAX_QUOTA GENMASK(27, 16) #define MT_PSE_FRP MT_PSE(0x138) #define MT_PSE_FRP_P0 GENMASK(2, 0) #define MT_PSE_FRP_P1 GENMASK(5, 3) #define MT_PSE_FRP_P2_RQ0 GENMASK(8, 6) #define MT_PSE_FRP_P2_RQ1 GENMASK(11, 9) #define MT_PSE_FRP_P2_RQ2 GENMASK(14, 12) #define MT_FC_RSV_COUNT_0 MT_PSE(0x13c) #define MT_FC_RSV_COUNT_0_P0 GENMASK(11, 0) #define MT_FC_RSV_COUNT_0_P1 GENMASK(27, 16) #define MT_FC_SP2_Q0Q1 MT_PSE(0x14c) #define MT_FC_SP2_Q0Q1_SRC_COUNT_Q0 GENMASK(11, 0) #define MT_FC_SP2_Q0Q1_SRC_COUNT_Q1 GENMASK(27, 16) #define MT_PSE_FW_SHARED MT_PSE(0x17c) #define MT_PSE_RTA MT_PSE(0x194) #define MT_PSE_RTA_QUEUE_ID GENMASK(4, 0) #define MT_PSE_RTA_PORT_ID GENMASK(6, 5) #define MT_PSE_RTA_REDIRECT_EN BIT(7) #define MT_PSE_RTA_TAG_ID GENMASK(15, 8) #define MT_PSE_RTA_WRITE BIT(16) #define MT_PSE_RTA_BUSY BIT(31) #define MT_WF_PHY_BASE 0x10000 #define MT_WF_PHY_OFFSET 0x1000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) #define MT_AGC_BASE MT_WF_PHY(0x500) #define MT_AGC(n) (MT_AGC_BASE + ((n) * 4)) #define MT_AGC1_BASE MT_WF_PHY(0x1500) #define MT_AGC1(n) (MT_AGC1_BASE + ((n) * 4)) #define MT_AGC_41_RSSI_0 GENMASK(23, 16) #define MT_AGC_41_RSSI_1 GENMASK(7, 0) #define MT_RXTD_BASE MT_WF_PHY(0x600) #define MT_RXTD(n) (MT_RXTD_BASE + ((n) * 4)) #define MT_RXTD_6_ACI_TH GENMASK(4, 0) #define MT_RXTD_6_CCAED_TH GENMASK(14, 8) #define MT_RXTD_8_LOWER_SIGNAL GENMASK(5, 0) #define MT_RXTD_13_ACI_TH_EN BIT(0) #define MT_WF_PHY_CR_TSSI_BASE MT_WF_PHY(0xd00) #define MT_WF_PHY_CR_TSSI(phy, n) (MT_WF_PHY_CR_TSSI_BASE + \ ((phy) * MT_WF_PHY_OFFSET) + \ ((n) * 4)) #define MT_PHYCTRL_BASE MT_WF_PHY(0x4100) #define MT_PHYCTRL(n) (MT_PHYCTRL_BASE + ((n) * 4)) #define MT_PHYCTRL_2_STATUS_RESET BIT(6) #define MT_PHYCTRL_2_STATUS_EN BIT(7) #define MT_PHYCTRL_STAT_PD MT_PHYCTRL(3) #define MT_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16) #define MT_PHYCTRL_STAT_PD_CCK GENMASK(15, 0) #define MT_PHYCTRL_STAT_MDRDY MT_PHYCTRL(8) #define MT_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16) #define MT_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0) #define MT_WF_AGG_BASE 0x21200 #define MT_WF_AGG(ofs) (MT_WF_AGG_BASE + (ofs)) #define MT_AGG_ARCR MT_WF_AGG(0x010) #define MT_AGG_ARCR_INIT_RATE1 BIT(0) #define MT_AGG_ARCR_FB_SGI_DISABLE BIT(1) #define MT_AGG_ARCR_RATE8_DOWN_WRAP BIT(2) #define MT_AGG_ARCR_RTS_RATE_THR GENMASK(12, 8) #define MT_AGG_ARCR_RATE_DOWN_RATIO GENMASK(17, 16) #define MT_AGG_ARCR_RATE_DOWN_RATIO_EN BIT(19) #define MT_AGG_ARCR_RATE_UP_EXTRA_TH GENMASK(22, 20) #define MT_AGG_ARCR_SPE_DIS_TH GENMASK(27, 24) #define MT_AGG_ARUCR MT_WF_AGG(0x014) #define MT_AGG_ARDCR MT_WF_AGG(0x018) #define MT_AGG_ARxCR_LIMIT_SHIFT(_n) (4 * (_n)) #define MT_AGG_ARxCR_LIMIT(_n) GENMASK(2 + \ MT_AGG_ARxCR_LIMIT_SHIFT(_n), \ MT_AGG_ARxCR_LIMIT_SHIFT(_n)) #define MT_AGG_LIMIT MT_WF_AGG(0x040) #define MT_AGG_LIMIT_1 MT_WF_AGG(0x044) #define MT_AGG_LIMIT_AC(_n) GENMASK(((_n) + 1) * 8 - 1, (_n) * 8) #define MT_AGG_BA_SIZE_LIMIT_0 MT_WF_AGG(0x048) #define MT_AGG_BA_SIZE_LIMIT_1 MT_WF_AGG(0x04c) #define MT_AGG_BA_SIZE_LIMIT_SHIFT 8 #define MT_AGG_PCR MT_WF_AGG(0x050) #define MT_AGG_PCR_MM BIT(16) #define MT_AGG_PCR_GF BIT(17) #define MT_AGG_PCR_BW40 BIT(18) #define MT_AGG_PCR_RIFS BIT(19) #define MT_AGG_PCR_BW80 BIT(20) #define MT_AGG_PCR_BW160 BIT(21) #define MT_AGG_PCR_ERP BIT(22) #define MT_AGG_PCR_RTS MT_WF_AGG(0x054) #define MT_AGG_PCR_RTS_THR GENMASK(19, 0) #define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25) #define MT_AGG_ASRCR MT_WF_AGG(0x060) #define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) #define MT_AGG_CONTROL MT_WF_AGG(0x070) #define MT_AGG_CONTROL_NO_BA_RULE BIT(0) #define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1) #define MT_AGG_CONTROL_CFEND_SPE_EN BIT(3) #define MT_AGG_CONTROL_CFEND_RATE GENMASK(15, 4) #define MT_AGG_CONTROL_BAR_SPE_EN BIT(19) #define MT_AGG_CONTROL_BAR_RATE GENMASK(31, 20) #define MT_AGG_TMP MT_WF_AGG(0x0d8) #define MT_AGG_BWCR MT_WF_AGG(0x0ec) #define MT_AGG_BWCR_BW GENMASK(3, 2) #define MT_AGG_RETRY_CONTROL MT_WF_AGG(0x0f4) #define MT_AGG_RETRY_CONTROL_RTS_LIMIT GENMASK(11, 7) #define MT_AGG_RETRY_CONTROL_BAR_LIMIT GENMASK(15, 12) #define MT_WF_DMA_BASE 0x21c00 #define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) #define MT_DMA_DCR0 MT_WF_DMA(0x000) #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 0) #define MT_DMA_DCR0_DAMSDU BIT(16) #define MT_DMA_DCR0_RX_VEC_DROP BIT(17) #define MT_DMA_DCR1 MT_WF_DMA(0x004) #define MT_DMA_FQCR0 MT_WF_DMA(0x008) #define MT_DMA_FQCR0_TARGET_WCID GENMASK(7, 0) #define MT_DMA_FQCR0_TARGET_BSS GENMASK(13, 8) #define MT_DMA_FQCR0_TARGET_QID GENMASK(20, 16) #define MT_DMA_FQCR0_DEST_PORT_ID GENMASK(23, 22) #define MT_DMA_FQCR0_DEST_QUEUE_ID GENMASK(28, 24) #define MT_DMA_FQCR0_MODE BIT(29) #define MT_DMA_FQCR0_STATUS BIT(30) #define MT_DMA_FQCR0_BUSY BIT(31) #define MT_DMA_RCFR0 MT_WF_DMA(0x070) #define MT_DMA_VCFR0 MT_WF_DMA(0x07c) #define MT_DMA_TCFR0 MT_WF_DMA(0x080) #define MT_DMA_TCFR1 MT_WF_DMA(0x084) #define MT_DMA_TCFR_TXS_AGGR_TIMEOUT GENMASK(27, 16) #define MT_DMA_TCFR_TXS_QUEUE BIT(14) #define MT_DMA_TCFR_TXS_AGGR_COUNT GENMASK(12, 8) #define MT_DMA_TCFR_TXS_BIT_MAP GENMASK(6, 0) #define MT_DMA_TMCFR0 MT_WF_DMA(0x088) #define MT_WF_ARB_BASE 0x21400 #define MT_WF_ARB(ofs) (MT_WF_ARB_BASE + (ofs)) #define MT_WMM_AIFSN MT_WF_ARB(0x020) #define MT_WMM_AIFSN_MASK GENMASK(3, 0) #define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) #define MT_WMM_CWMAX_BASE MT_WF_ARB(0x028) #define MT_WMM_CWMAX(_n) (MT_WMM_CWMAX_BASE + (((_n) / 2) << 2)) #define MT_WMM_CWMAX_SHIFT(_n) (((_n) & 1) * 16) #define MT_WMM_CWMAX_MASK GENMASK(15, 0) #define MT_WMM_CWMIN MT_WF_ARB(0x040) #define MT_WMM_CWMIN_MASK GENMASK(7, 0) #define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 8) #define MT_WF_ARB_RQCR MT_WF_ARB(0x070) #define MT_WF_ARB_RQCR_RX_START BIT(0) #define MT_WF_ARB_RQCR_RXV_START BIT(4) #define MT_WF_ARB_RQCR_RXV_R_EN BIT(7) #define MT_WF_ARB_RQCR_RXV_T_EN BIT(8) #define MT_ARB_SCR MT_WF_ARB(0x080) #define MT_ARB_SCR_BCNQ_OPMODE_MASK GENMASK(1, 0) #define MT_ARB_SCR_BCNQ_OPMODE_SHIFT(n) ((n) * 2) #define MT_ARB_SCR_TX_DISABLE BIT(8) #define MT_ARB_SCR_RX_DISABLE BIT(9) #define MT_ARB_SCR_BCNQ_EMPTY_SKIP BIT(28) #define MT_ARB_SCR_TTTT_BTIM_PRIO BIT(29) #define MT_ARB_SCR_TBTT_BCN_PRIO BIT(30) #define MT_ARB_SCR_TBTT_BCAST_PRIO BIT(31) enum { MT_BCNQ_OPMODE_STA = 0, MT_BCNQ_OPMODE_AP = 1, MT_BCNQ_OPMODE_ADHOC = 2, }; #define MT_WF_ARB_TX_START_0 MT_WF_ARB(0x100) #define MT_WF_ARB_TX_START_1 MT_WF_ARB(0x104) #define MT_WF_ARB_TX_FLUSH_0 MT_WF_ARB(0x108) #define MT_WF_ARB_TX_FLUSH_1 MT_WF_ARB(0x10c) #define MT_WF_ARB_TX_STOP_0 MT_WF_ARB(0x110) #define MT_WF_ARB_TX_STOP_1 MT_WF_ARB(0x114) #define MT_WF_ARB_TX_FLUSH_AC0 BIT(0) #define MT_WF_ARB_TX_FLUSH_AC1 BIT(5) #define MT_WF_ARB_TX_FLUSH_AC2 BIT(10) #define MT_WF_ARB_TX_FLUSH_AC3 BIT(16) #define MT_WF_ARB_TX_FLUSH_AC4 BIT(21) #define MT_WF_ARB_TX_FLUSH_AC5 BIT(26) #define MT_WF_ARB_BCN_START MT_WF_ARB(0x118) #define MT_WF_ARB_BCN_START_BSSn(n) BIT(0 + (n)) #define MT_WF_ARB_BCN_START_T_PRE_TTTT BIT(10) #define MT_WF_ARB_BCN_START_T_TTTT BIT(11) #define MT_WF_ARB_BCN_START_T_PRE_TBTT BIT(12) #define MT_WF_ARB_BCN_START_T_TBTT BIT(13) #define MT_WF_ARB_BCN_START_T_SLOT_IDLE BIT(14) #define MT_WF_ARB_BCN_START_T_TX_START BIT(15) #define MT_WF_ARB_BCN_START_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) #define MT_WF_ARB_BCN_FLUSH MT_WF_ARB(0x11c) #define MT_WF_ARB_BCN_FLUSH_BSSn(n) BIT(0 + (n)) #define MT_WF_ARB_BCN_FLUSH_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) #define MT_WF_ARB_CAB_START MT_WF_ARB(0x120) #define MT_WF_ARB_CAB_START_BSSn(n) BIT(0 + (n)) #define MT_WF_ARB_CAB_START_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) #define MT_WF_ARB_CAB_FLUSH MT_WF_ARB(0x124) #define MT_WF_ARB_CAB_FLUSH_BSSn(n) BIT(0 + (n)) #define MT_WF_ARB_CAB_FLUSH_BSS0n(n) BIT((n) ? 16 + ((n) - 1) : 0) #define MT_WF_ARB_CAB_COUNT(n) MT_WF_ARB(0x128 + (n) * 4) #define MT_WF_ARB_CAB_COUNT_SHIFT 4 #define MT_WF_ARB_CAB_COUNT_MASK GENMASK(3, 0) #define MT_WF_ARB_CAB_COUNT_B0_REG(n) MT_WF_ARB_CAB_COUNT(((n) > 12 ? 2 : \ ((n) > 4 ? 1 : 0))) #define MT_WF_ARB_CAB_COUNT_B0_SHIFT(n) (((n) > 12 ? (n) - 12 : \ ((n) > 4 ? (n) - 4 : \ (n) ? (n) + 3 : 0)) * 4) #define MT_TX_ABORT MT_WF_ARB(0x134) #define MT_TX_ABORT_EN BIT(0) #define MT_TX_ABORT_WCID GENMASK(15, 8) #define MT_WF_TMAC_BASE 0x21600 #define MT_WF_TMAC(ofs) (MT_WF_TMAC_BASE + (ofs)) #define MT_TMAC_TCR MT_WF_TMAC(0x000) #define MT_TMAC_TCR_BLINK_SEL GENMASK(7, 6) #define MT_TMAC_TCR_PRE_RTS_GUARD GENMASK(11, 8) #define MT_TMAC_TCR_PRE_RTS_SEC_IDLE GENMASK(13, 12) #define MT_TMAC_TCR_RTS_SIGTA BIT(14) #define MT_TMAC_TCR_LDPC_OFS BIT(15) #define MT_TMAC_TCR_TX_STREAMS GENMASK(17, 16) #define MT_TMAC_TCR_SCH_IDLE_SEL GENMASK(19, 18) #define MT_TMAC_TCR_SCH_DET_PER_IOD BIT(20) #define MT_TMAC_TCR_DCH_DET_DISABLE BIT(21) #define MT_TMAC_TCR_TX_RIFS BIT(22) #define MT_TMAC_TCR_RX_RIFS_MODE BIT(23) #define MT_TMAC_TCR_TXOP_TBTT_CTL BIT(24) #define MT_TMAC_TCR_TBTT_TX_STOP_CTL BIT(25) #define MT_TMAC_TCR_TXOP_BURST_STOP BIT(26) #define MT_TMAC_TCR_RDG_RA_MODE BIT(27) #define MT_TMAC_TCR_RDG_RESP BIT(29) #define MT_TMAC_TCR_RDG_NO_PENDING BIT(30) #define MT_TMAC_TCR_SMOOTHING BIT(31) #define MT_WMM_TXOP_BASE MT_WF_TMAC(0x010) #define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + \ ((((_n) / 2) ^ 0x1) << 2)) #define MT_WMM_TXOP_SHIFT(_n) (((_n) & 1) * 16) #define MT_WMM_TXOP_MASK GENMASK(15, 0) #define MT_TIMEOUT_CCK MT_WF_TMAC(0x090) #define MT_TIMEOUT_OFDM MT_WF_TMAC(0x094) #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) #define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) #define MT_TXREQ MT_WF_TMAC(0x09c) #define MT_TXREQ_CCA_SRC_SEL GENMASK(31, 30) #define MT_RXREQ MT_WF_TMAC(0x0a0) #define MT_RXREQ_DELAY GENMASK(8, 0) #define MT_IFS MT_WF_TMAC(0x0a4) #define MT_IFS_EIFS 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_PCR MT_WF_TMAC(0x0b4) #define MT_TMAC_PCR_RATE GENMASK(8, 0) #define MT_TMAC_PCR_RATE_FIXED BIT(15) #define MT_TMAC_PCR_ANT_ID GENMASK(21, 16) #define MT_TMAC_PCR_ANT_ID_SEL BIT(22) #define MT_TMAC_PCR_SPE_EN BIT(23) #define MT_TMAC_PCR_ANT_PRI GENMASK(26, 24) #define MT_TMAC_PCR_ANT_PRI_SEL GENMASK(27) #define MT_WF_RMAC_BASE 0x21800 #define MT_WF_RMAC(ofs) (MT_WF_RMAC_BASE + (ofs)) #define MT_WF_RFCR MT_WF_RMAC(0x000) #define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) #define MT_WF_RFCR_DROP_FCSFAIL BIT(1) #define MT_WF_RFCR_DROP_VERSION BIT(3) #define MT_WF_RFCR_DROP_PROBEREQ BIT(4) #define MT_WF_RFCR_DROP_MCAST BIT(5) #define MT_WF_RFCR_DROP_BCAST BIT(6) #define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) #define MT_WF_RFCR_DROP_A3_MAC BIT(8) #define MT_WF_RFCR_DROP_A3_BSSID BIT(9) #define MT_WF_RFCR_DROP_A2_BSSID BIT(10) #define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) #define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) #define MT_WF_RFCR_DROP_CTL_RSV BIT(13) #define MT_WF_RFCR_DROP_CTS BIT(14) #define MT_WF_RFCR_DROP_RTS BIT(15) #define MT_WF_RFCR_DROP_DUPLICATE BIT(16) #define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) #define MT_WF_RFCR_DROP_OTHER_UC BIT(18) #define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) #define MT_BSSID0(idx) MT_WF_RMAC(0x004 + (idx) * 8) #define MT_BSSID1(idx) MT_WF_RMAC(0x008 + (idx) * 8) #define MT_BSSID1_VALID BIT(16) #define MT_MAC_ADDR0(idx) MT_WF_RMAC(0x024 + (idx) * 8) #define MT_MAC_ADDR1(idx) MT_WF_RMAC(0x028 + (idx) * 8) #define MT_MAC_ADDR1_ADDR GENMASK(15, 0) #define MT_MAC_ADDR1_VALID BIT(16) #define MT_BA_CONTROL_0 MT_WF_RMAC(0x068) #define MT_BA_CONTROL_1 MT_WF_RMAC(0x06c) #define MT_BA_CONTROL_1_ADDR GENMASK(15, 0) #define MT_BA_CONTROL_1_TID GENMASK(19, 16) #define MT_BA_CONTROL_1_IGNORE_TID BIT(20) #define MT_BA_CONTROL_1_IGNORE_ALL BIT(21) #define MT_BA_CONTROL_1_RESET BIT(22) #define MT_WF_RMACDR MT_WF_RMAC(0x078) #define MT_WF_RMACDR_TSF_PROBERSP_DIS BIT(0) #define MT_WF_RMACDR_TSF_TIM BIT(4) #define MT_WF_RMACDR_MBSSID_MASK GENMASK(25, 24) #define MT_WF_RMACDR_CHECK_HTC_BY_RATE BIT(26) #define MT_WF_RMACDR_MAXLEN_20BIT BIT(30) #define MT_WF_RMAC_RMCR MT_WF_RMAC(0x080) #define MT_WF_RMAC_RMCR_SMPS_MODE GENMASK(21, 20) #define MT_WF_RMAC_RMCR_RX_STREAMS GENMASK(24, 22) #define MT_WF_RMAC_RMCR_SMPS_RTS BIT(25) #define MT_WF_RMAC_CH_FREQ MT_WF_RMAC(0x090) #define MT_WF_RMAC_MAXMINLEN MT_WF_RMAC(0x098) #define MT_WF_RFCR1 MT_WF_RMAC(0x0a4) #define MT_WF_RMAC_TMR_PA MT_WF_RMAC(0x0e0) #define MT_WF_SEC_BASE 0x21a00 #define MT_WF_SEC(ofs) (MT_WF_SEC_BASE + (ofs)) +#define MT_WF_CFG_OFF_BASE 0x21e00 +#define MT_WF_CFG_OFF(ofs) (MT_WF_CFG_OFF_BASE + (ofs)) +#define MT_WF_CFG_OFF_WOCCR MT_WF_CFG_OFF(0x004) +#define MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS BIT(4) + #define MT_SEC_SCR MT_WF_SEC(0x004) #define MT_SEC_SCR_MASK_ORDER GENMASK(1, 0) #define MT_WTBL_OFF_BASE 0x23000 #define MT_WTBL_OFF(n) (MT_WTBL_OFF_BASE + (n)) #define MT_WTBL_UPDATE MT_WTBL_OFF(0x000) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0) #define MT_WTBL_UPDATE_WTBL2 BIT(11) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) #define MT_WTBL_UPDATE_RATE_UPDATE BIT(13) #define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14) #define MT_WTBL_UPDATE_RX_COUNT_CLEAR BIT(15) #define MT_WTBL_UPDATE_BUSY BIT(16) #define MT_WTBL_RMVTCR MT_WTBL_OFF(0x008) #define MT_WTBL_RMVTCR_RX_MV_MODE BIT(23) #define MT_LPON_BASE 0x24000 #define MT_LPON(n) (MT_LPON_BASE + (n)) #define MT_LPON_T0CR MT_LPON(0x010) #define MT_LPON_T0CR_MODE GENMASK(1, 0) #define MT_LPON_UTTR0 MT_LPON(0x018) #define MT_LPON_UTTR1 MT_LPON(0x01c) #define MT_LPON_BTEIR MT_LPON(0x020) #define MT_LPON_BTEIR_MBSS_MODE GENMASK(31, 29) #define MT_PRE_TBTT MT_LPON(0x030) #define MT_PRE_TBTT_MASK GENMASK(7, 0) #define MT_PRE_TBTT_SHIFT 8 #define MT_TBTT MT_LPON(0x034) #define MT_TBTT_PERIOD GENMASK(15, 0) #define MT_TBTT_DTIM_PERIOD GENMASK(23, 16) #define MT_TBTT_TBTT_WAKE_PERIOD GENMASK(27, 24) #define MT_TBTT_DTIM_WAKE_PERIOD GENMASK(30, 28) #define MT_TBTT_CAL_ENABLE BIT(31) #define MT_TBTT_TIMER_CFG MT_LPON(0x05c) #define MT_LPON_SBTOR(n) MT_LPON(0x0a0) #define MT_LPON_SBTOR_SUB_BSS_EN BIT(29) #define MT_LPON_SBTOR_TIME_OFFSET GENMASK(19, 0) #define MT_INT_WAKEUP_BASE 0x24400 #define MT_INT_WAKEUP(n) (MT_INT_WAKEUP_BASE + (n)) #define MT_HW_INT_STATUS(n) MT_INT_WAKEUP(0x3c + (n) * 8) #define MT_HW_INT_MASK(n) MT_INT_WAKEUP(0x40 + (n) * 8) #define MT_HW_INT3_TBTT0 BIT(15) #define MT_HW_INT3_PRE_TBTT0 BIT(31) #define MT_WTBL1_BASE 0x28000 #define MT_WTBL_ON_BASE (MT_WTBL1_BASE + 0x2000) #define MT_WTBL_ON(_n) (MT_WTBL_ON_BASE + (_n)) #define MT_WTBL_RIUCR0 MT_WTBL_ON(0x200) #define MT_WTBL_RIUCR1 MT_WTBL_ON(0x204) #define MT_WTBL_RIUCR1_RATE0 GENMASK(11, 0) #define MT_WTBL_RIUCR1_RATE1 GENMASK(23, 12) #define MT_WTBL_RIUCR1_RATE2_LO GENMASK(31, 24) #define MT_WTBL_RIUCR2 MT_WTBL_ON(0x208) #define MT_WTBL_RIUCR2_RATE2_HI GENMASK(3, 0) #define MT_WTBL_RIUCR2_RATE3 GENMASK(15, 4) #define MT_WTBL_RIUCR2_RATE4 GENMASK(27, 16) #define MT_WTBL_RIUCR2_RATE5_LO GENMASK(31, 28) #define MT_WTBL_RIUCR3 MT_WTBL_ON(0x20c) #define MT_WTBL_RIUCR3_RATE5_HI GENMASK(7, 0) #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) #define MT_MIB_BASE 0x2c000 #define MT_MIB(_n) (MT_MIB_BASE + (_n)) #define MT_MIB_CTL MT_MIB(0x00) #define MT_MIB_CTL_PSCCA_TIME GENMASK(13, 11) #define MT_MIB_CTL_CCA_NAV_TX GENMASK(16, 14) #define MT_MIB_CTL_ED_TIME GENMASK(30, 28) #define MT_MIB_CTL_READ_CLR_DIS BIT(31) #define MT_MIB_STAT(_n) MT_MIB(0x08 + (_n) * 4) #define MT_MIB_STAT_CCA MT_MIB_STAT(9) #define MT_MIB_STAT_CCA_MASK GENMASK(23, 0) #define MT_MIB_STAT_PSCCA MT_MIB_STAT(16) #define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0) #define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2)) #define MT_MIB_STAT_ED MT_MIB_STAT(18) #define MT_MIB_STAT_ED_MASK GENMASK(23, 0) #define MT_PCIE_REMAP_BASE_1 0x40000 #define MT_PCIE_REMAP_BASE_2 0x80000 #define MT_TX_HW_QUEUE_MGMT 4 #define MT_TX_HW_QUEUE_MCU 5 #define MT_TX_HW_QUEUE_BCN 7 #define MT_TX_HW_QUEUE_BMC 8 #define MT_LED_BASE_PHYS 0x80024000 #define MT_LED_PHYS(_n) (MT_LED_BASE_PHYS + (_n)) #define MT_LED_CTRL MT_LED_PHYS(0x00) #define MT_LED_CTRL_REPLAY(_n) BIT(0 + (8 * (_n))) #define MT_LED_CTRL_POLARITY(_n) BIT(1 + (8 * (_n))) #define MT_LED_CTRL_TX_BLINK_MODE(_n) BIT(2 + (8 * (_n))) #define MT_LED_CTRL_TX_MANUAL_BLINK(_n) BIT(3 + (8 * (_n))) #define MT_LED_CTRL_TX_OVER_BLINK(_n) BIT(5 + (8 * (_n))) #define MT_LED_CTRL_KICK(_n) BIT(7 + (8 * (_n))) #define MT_LED_STATUS_0(_n) MT_LED_PHYS(0x10 + ((_n) * 8)) #define MT_LED_STATUS_1(_n) MT_LED_PHYS(0x14 + ((_n) * 8)) #define MT_LED_STATUS_OFF GENMASK(31, 24) #define MT_LED_STATUS_ON GENMASK(23, 16) #define MT_LED_STATUS_DURATION GENMASK(15, 0) #define MT_CLIENT_BASE_PHYS_ADDR 0x800c0000 #define MT_CLIENT_TMAC_INFO_TEMPLATE 0x040 #define MT_CLIENT_STATUS 0x06c #define MT_CLIENT_RESET_TX 0x070 #define MT_CLIENT_RESET_TX_R_E_1 BIT(16) #define MT_CLIENT_RESET_TX_R_E_2 BIT(17) #define MT_CLIENT_RESET_TX_R_E_1_S BIT(20) #define MT_CLIENT_RESET_TX_R_E_2_S BIT(21) #define MT_EFUSE_BASE 0x81070000 #define MT_EFUSE_BASE_CTRL 0x000 #define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) #define MT_EFUSE_CTRL 0x008 #define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) #define MT_EFUSE_CTRL_MODE GENMASK(7, 6) #define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) #define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) #define MT_EFUSE_CTRL_AIN GENMASK(25, 16) #define MT_EFUSE_CTRL_VALID BIT(29) #define MT_EFUSE_CTRL_KICK BIT(30) #define MT_EFUSE_CTRL_SEL BIT(31) #define MT_EFUSE_WDATA(_i) (0x010 + ((_i) * 4)) #define MT_EFUSE_RDATA(_i) (0x030 + ((_i) * 4)) #define MT_CLIENT_RXINF 0x068 #define MT_CLIENT_RXINF_RXSH_GROUPS GENMASK(2, 0) #define MT_PSE_BASE_PHYS_ADDR 0xa0000000 #define MT_PSE_WTBL_2_PHYS_ADDR 0xa5000000 #define MT_WTBL1_SIZE (8 * 4) #define MT_WTBL2_SIZE (16 * 4) #define MT_WTBL3_OFFSET (MT7603_WTBL_SIZE * MT_WTBL2_SIZE) #define MT_WTBL3_SIZE (16 * 4) #define MT_WTBL4_OFFSET (MT7603_WTBL_SIZE * MT_WTBL3_SIZE + \ MT_WTBL3_OFFSET) #define MT_WTBL4_SIZE (8 * 4) #define MT_WTBL1_W0_ADDR_HI GENMASK(15, 0) #define MT_WTBL1_W0_MUAR_IDX GENMASK(21, 16) #define MT_WTBL1_W0_RX_CHECK_A1 BIT(22) #define MT_WTBL1_W0_KEY_IDX GENMASK(24, 23) #define MT_WTBL1_W0_RX_CHECK_KEY_IDX BIT(25) #define MT_WTBL1_W0_RX_KEY_VALID BIT(26) #define MT_WTBL1_W0_RX_IK_VALID BIT(27) #define MT_WTBL1_W0_RX_VALID BIT(28) #define MT_WTBL1_W0_RX_CHECK_A2 BIT(29) #define MT_WTBL1_W0_RX_DATA_VALID BIT(30) #define MT_WTBL1_W0_WRITE_BURST BIT(31) #define MT_WTBL1_W1_ADDR_LO GENMASK(31, 0) #define MT_WTBL1_W2_MPDU_DENSITY GENMASK(2, 0) #define MT_WTBL1_W2_KEY_TYPE GENMASK(6, 3) #define MT_WTBL1_W2_EVEN_PN BIT(7) #define MT_WTBL1_W2_TO_DS BIT(8) #define MT_WTBL1_W2_FROM_DS BIT(9) #define MT_WTBL1_W2_HEADER_TRANS BIT(10) #define MT_WTBL1_W2_AMPDU_FACTOR GENMASK(13, 11) #define MT_WTBL1_W2_PWR_MGMT BIT(14) #define MT_WTBL1_W2_RDG BIT(15) #define MT_WTBL1_W2_RTS BIT(16) #define MT_WTBL1_W2_CFACK BIT(17) #define MT_WTBL1_W2_RDG_BA BIT(18) #define MT_WTBL1_W2_SMPS BIT(19) #define MT_WTBL1_W2_TXS_BAF_REPORT BIT(20) #define MT_WTBL1_W2_DYN_BW BIT(21) #define MT_WTBL1_W2_LDPC BIT(22) #define MT_WTBL1_W2_ITXBF BIT(23) #define MT_WTBL1_W2_ETXBF BIT(24) #define MT_WTBL1_W2_TXOP_PS BIT(25) #define MT_WTBL1_W2_MESH BIT(26) #define MT_WTBL1_W2_QOS BIT(27) #define MT_WTBL1_W2_HT BIT(28) #define MT_WTBL1_W2_VHT BIT(29) #define MT_WTBL1_W2_ADMISSION_CONTROL BIT(30) #define MT_WTBL1_W2_GROUP_ID BIT(31) #define MT_WTBL1_W3_WTBL2_FRAME_ID GENMASK(10, 0) #define MT_WTBL1_W3_WTBL2_ENTRY_ID GENMASK(15, 11) #define MT_WTBL1_W3_WTBL4_FRAME_ID GENMASK(26, 16) #define MT_WTBL1_W3_CHECK_PER BIT(27) #define MT_WTBL1_W3_KEEP_I_PSM BIT(28) #define MT_WTBL1_W3_I_PSM BIT(29) #define MT_WTBL1_W3_POWER_SAVE BIT(30) #define MT_WTBL1_W3_SKIP_TX BIT(31) #define MT_WTBL1_W4_WTBL3_FRAME_ID GENMASK(10, 0) #define MT_WTBL1_W4_WTBL3_ENTRY_ID GENMASK(16, 11) #define MT_WTBL1_W4_WTBL4_ENTRY_ID GENMASK(22, 17) #define MT_WTBL1_W4_PARTIAL_AID GENMASK(31, 23) #define MT_WTBL2_W0_PN_LO GENMASK(31, 0) #define MT_WTBL2_W1_PN_HI GENMASK(15, 0) #define MT_WTBL2_W1_NON_QOS_SEQNO GENMASK(27, 16) #define MT_WTBL2_W2_TID0_SN GENMASK(11, 0) #define MT_WTBL2_W2_TID1_SN GENMASK(23, 12) #define MT_WTBL2_W2_TID2_SN_LO GENMASK(31, 24) #define MT_WTBL2_W3_TID2_SN_HI GENMASK(3, 0) #define MT_WTBL2_W3_TID3_SN GENMASK(15, 4) #define MT_WTBL2_W3_TID4_SN GENMASK(27, 16) #define MT_WTBL2_W3_TID5_SN_LO GENMASK(31, 28) #define MT_WTBL2_W4_TID5_SN_HI GENMASK(7, 0) #define MT_WTBL2_W4_TID6_SN GENMASK(19, 8) #define MT_WTBL2_W4_TID7_SN GENMASK(31, 20) #define MT_WTBL2_W5_TX_COUNT_RATE1 GENMASK(15, 0) #define MT_WTBL2_W5_FAIL_COUNT_RATE1 GENAMSK(31, 16) #define MT_WTBL2_W6_TX_COUNT_RATE2 GENMASK(7, 0) #define MT_WTBL2_W6_TX_COUNT_RATE3 GENMASK(15, 8) #define MT_WTBL2_W6_TX_COUNT_RATE4 GENMASK(23, 16) #define MT_WTBL2_W6_TX_COUNT_RATE5 GENMASK(31, 24) #define MT_WTBL2_W7_TX_COUNT_CUR_BW GENMASK(15, 0) #define MT_WTBL2_W7_FAIL_COUNT_CUR_BW GENMASK(31, 16) #define MT_WTBL2_W8_TX_COUNT_OTHER_BW GENMASK(15, 0) #define MT_WTBL2_W8_FAIL_COUNT_OTHER_BW GENMASK(31, 16) #define MT_WTBL2_W9_POWER_OFFSET GENMASK(4, 0) #define MT_WTBL2_W9_SPATIAL_EXT BIT(5) #define MT_WTBL2_W9_ANT_PRIORITY GENMASK(8, 6) #define MT_WTBL2_W9_CC_BW_SEL GENMASK(10, 9) #define MT_WTBL2_W9_CHANGE_BW_RATE GENMASK(13, 11) #define MT_WTBL2_W9_BW_CAP GENMASK(15, 14) #define MT_WTBL2_W9_SHORT_GI_20 BIT(16) #define MT_WTBL2_W9_SHORT_GI_40 BIT(17) #define MT_WTBL2_W9_SHORT_GI_80 BIT(18) #define MT_WTBL2_W9_SHORT_GI_160 BIT(19) #define MT_WTBL2_W9_MPDU_FAIL_COUNT GENMASK(25, 23) #define MT_WTBL2_W9_MPDU_OK_COUNT GENMASK(28, 26) #define MT_WTBL2_W9_RATE_IDX GENMASK(31, 29) #define MT_WTBL2_W10_RATE1 GENMASK(11, 0) #define MT_WTBL2_W10_RATE2 GENMASK(23, 12) #define MT_WTBL2_W10_RATE3_LO GENMASK(31, 24) #define MT_WTBL2_W11_RATE3_HI GENMASK(3, 0) #define MT_WTBL2_W11_RATE4 GENMASK(15, 4) #define MT_WTBL2_W11_RATE5 GENMASK(27, 16) #define MT_WTBL2_W11_RATE6_LO GENMASK(31, 28) #define MT_WTBL2_W12_RATE6_HI GENMASK(7, 0) #define MT_WTBL2_W12_RATE7 GENMASK(19, 8) #define MT_WTBL2_W12_RATE8 GENMASK(31, 20) #define MT_WTBL2_W13_AVG_RCPI0 GENMASK(7, 0) #define MT_WTBL2_W13_AVG_RCPI1 GENMASK(15, 8) #define MT_WTBL2_W13_AVG_RCPI2 GENAMSK(23, 16) #define MT_WTBL2_W14_CC_NOISE_1S GENMASK(6, 0) #define MT_WTBL2_W14_CC_NOISE_2S GENMASK(13, 7) #define MT_WTBL2_W14_CC_NOISE_3S GENMASK(20, 14) #define MT_WTBL2_W14_CHAN_EST_RMS GENMASK(24, 21) #define MT_WTBL2_W14_CC_NOISE_SEL BIT(15) #define MT_WTBL2_W14_ANT_SEL GENMASK(31, 26) #define MT_WTBL2_W15_BA_WIN_SIZE GENMASK(2, 0) #define MT_WTBL2_W15_BA_WIN_SIZE_SHIFT 3 #define MT_WTBL2_W15_BA_EN_TIDS GENMASK(31, 24) #define MT_WTBL1_OR (MT_WTBL1_BASE + 0x2300) #define MT_WTBL1_OR_PSM_WRITE BIT(31) #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7603/soc.c b/sys/contrib/dev/mediatek/mt76/mt7603/soc.c index ba927033bbe8..08590aa68356 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7603/soc.c +++ b/sys/contrib/dev/mediatek/mt76/mt7603/soc.c @@ -1,82 +1,79 @@ // SPDX-License-Identifier: ISC #include #include #include #include "mt7603.h" static int mt76_wmac_probe(struct platform_device *pdev) { struct mt7603_dev *dev; void __iomem *mem_base; struct mt76_dev *mdev; int irq; int ret; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; mem_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem_base)) return PTR_ERR(mem_base); mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops, &mt7603_drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt7603_dev, mt76); mt76_mmio_init(mdev, mem_base); mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); mt76_wr(dev, MT_INT_MASK_CSR, 0); ret = devm_request_irq(mdev->dev, irq, mt7603_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; ret = mt7603_register_device(dev); if (ret) goto error; return 0; error: ieee80211_free_hw(mt76_hw(dev)); return ret; } -static int -mt76_wmac_remove(struct platform_device *pdev) +static void mt76_wmac_remove(struct platform_device *pdev) { struct mt76_dev *mdev = platform_get_drvdata(pdev); struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); mt7603_unregister_device(dev); - - return 0; } static const struct of_device_id of_wmac_match[] = { { .compatible = "mediatek,mt7628-wmac" }, {}, }; MODULE_DEVICE_TABLE(of, of_wmac_match); MODULE_FIRMWARE(MT7628_FIRMWARE_E1); MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, .remove = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, }, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/dma.c b/sys/contrib/dev/mediatek/mt76/mt7615/dma.c index 0ce01ccc5dce..bcf7864312d7 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/dma.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/dma.c @@ -1,316 +1,316 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Ryder Lee * Roy Luo * Lorenzo Bianconi * Felix Fietkau */ #include "mt7615.h" #include "../dma.h" #include "mac.h" static int mt7622_init_tx_queues_multi(struct mt7615_dev *dev) { static const u8 wmm_queue_map[] = { [IEEE80211_AC_BK] = MT7622_TXQ_AC0, [IEEE80211_AC_BE] = MT7622_TXQ_AC1, [IEEE80211_AC_VI] = MT7622_TXQ_AC2, [IEEE80211_AC_VO] = MT7622_TXQ_AC3, }; int ret; int i; for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], MT7615_TX_RING_SIZE / 2, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7622_TXQ_MCU, MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE); } static int mt7615_init_tx_queues(struct mt7615_dev *dev) { int ret; ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7615_TXQ_FWDL, MT7615_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; if (!is_mt7615(&dev->mt76)) return mt7622_init_tx_queues_multi(dev); ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7615_TXQ_MCU, MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE); } static int mt7615_poll_tx(struct napi_struct *napi, int budget) { struct mt7615_dev *dev; - dev = container_of(napi, struct mt7615_dev, mt76.tx_napi); + dev = mt76_priv(napi->dev); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { napi_complete(napi); queue_work(dev->mt76.wq, &dev->pm.wake_work); return 0; } mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); if (napi_complete(napi)) mt76_connac_irq_enable(&dev->mt76, mt7615_tx_mcu_int_mask(dev)); mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } static int mt7615_poll_rx(struct napi_struct *napi, int budget) { struct mt7615_dev *dev; int done; - dev = container_of(napi->dev, struct mt7615_dev, mt76.napi_dev); + dev = mt76_priv(napi->dev); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { napi_complete(napi); queue_work(dev->mt76.wq, &dev->pm.wake_work); return 0; } done = mt76_dma_rx_poll(napi, budget); mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } int mt7615_wait_pdma_busy(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; if (!is_mt7663(mdev)) { u32 mask = MT_PDMA_TX_BUSY | MT_PDMA_RX_BUSY; u32 reg = mt7615_reg_map(dev, MT_PDMA_BUSY); if (!mt76_poll_msec(dev, reg, mask, 0, 1000)) { dev_err(mdev->dev, "PDMA engine busy\n"); return -EIO; } return 0; } if (!mt76_poll_msec(dev, MT_PDMA_BUSY_STATUS, MT_PDMA_TX_IDX_BUSY, 0, 1000)) { dev_err(mdev->dev, "PDMA engine tx busy\n"); return -EIO; } if (!mt76_poll_msec(dev, MT_PSE_PG_INFO, MT_PSE_SRC_CNT, 0, 1000)) { dev_err(mdev->dev, "PSE engine busy\n"); return -EIO; } if (!mt76_poll_msec(dev, MT_PDMA_BUSY_STATUS, MT_PDMA_BUSY_IDX, 0, 1000)) { dev_err(mdev->dev, "PDMA engine busy\n"); return -EIO; } return 0; } static void mt7622_dma_sched_init(struct mt7615_dev *dev) { u32 reg = mt7615_reg_map(dev, MT_DMASHDL_BASE); int i; mt76_rmw(dev, reg + MT_DMASHDL_PKT_MAX_SIZE, MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); for (i = 0; i <= 5; i++) mt76_wr(dev, reg + MT_DMASHDL_GROUP_QUOTA(i), FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x10) | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x800)); mt76_wr(dev, reg + MT_DMASHDL_Q_MAP(0), 0x42104210); mt76_wr(dev, reg + MT_DMASHDL_Q_MAP(1), 0x42104210); mt76_wr(dev, reg + MT_DMASHDL_Q_MAP(2), 0x5); mt76_wr(dev, reg + MT_DMASHDL_Q_MAP(3), 0); mt76_wr(dev, reg + MT_DMASHDL_SCHED_SET0, 0x6012345f); mt76_wr(dev, reg + MT_DMASHDL_SCHED_SET1, 0xedcba987); } static void mt7663_dma_sched_init(struct mt7615_dev *dev) { int i; mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); /* enable refill control group 0, 1, 2, 4, 5 */ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffc80000); /* enable group 0, 1, 2, 4, 5, 15 */ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x70068037); /* each group min quota must larger then PLE_PKT_MAX_SIZE_NUM */ for (i = 0; i < 5; i++) mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x40) | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x800)); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(5)), FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x40) | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x40)); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(15)), FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x20) | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x20)); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x00050005); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(3)), 0); /* ALTX0 and ALTX1 QID mapping to group 5 */ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6012345f); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); } void mt7615_dma_start(struct mt7615_dev *dev) { /* start dma engine */ mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); if (is_mt7622(&dev->mt76)) mt7622_dma_sched_init(dev); if (is_mt7663(&dev->mt76)) { mt7663_dma_sched_init(dev); mt76_wr(dev, MT_MCU2HOST_INT_ENABLE, MT7663_MCU_CMD_ERROR_MASK); } } int mt7615_dma_init(struct mt7615_dev *dev) { int rx_ring_size = MT7615_RX_RING_SIZE; u32 mask; int ret; mt76_dma_attach(&dev->mt76); mt76_wr(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE | MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN | MT_WPDMA_GLO_CFG_OMIT_TX_INFO); mt76_rmw_field(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT0, 0x1); mt76_rmw_field(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT21, 0x1); mt76_rmw_field(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 0x3); mt76_rmw_field(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_MULTI_DMA_EN, 0x3); if (is_mt7615(&dev->mt76)) { mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY); mt76_wr(dev, MT_WPDMA_GLO_CFG1, 0x1); mt76_wr(dev, MT_WPDMA_TX_PRE_CFG, 0xf0000); mt76_wr(dev, MT_WPDMA_RX_PRE_CFG, 0xf7f0000); mt76_wr(dev, MT_WPDMA_ABT_CFG, 0x4000026); mt76_wr(dev, MT_WPDMA_ABT_CFG1, 0x18811881); mt76_set(dev, 0x7158, BIT(16)); mt76_clear(dev, 0x7000, BIT(23)); } mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); ret = mt7615_init_tx_queues(dev); if (ret) return ret; /* init rx queues */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; if (!is_mt7615(&dev->mt76)) rx_ring_size /= 2; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0, rx_ring_size, MT_RX_BUF_SIZE, MT_RX_RING_BASE); if (ret) return ret; mt76_wr(dev, MT_DELAY_INT_CFG, 0); ret = mt76_init_queues(dev, mt7615_poll_rx); if (ret < 0) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt7615_poll_tx); napi_enable(&dev->mt76.tx_napi); mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000); /* enable interrupts for TX/RX rings */ mask = MT_INT_RX_DONE_ALL | mt7615_tx_mcu_int_mask(dev); if (is_mt7663(&dev->mt76)) mask |= MT7663_INT_MCU_CMD; else mask |= MT_INT_MCU_CMD; mt76_connac_irq_enable(&dev->mt76, mask); mt7615_dma_start(dev); return 0; } void mt7615_dma_cleanup(struct mt7615_dev *dev) { mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET); mt76_dma_cleanup(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/init.c b/sys/contrib/dev/mediatek/mt76/mt7615/init.c index 517a9ec9e07f..1e55e600981b 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/init.c @@ -1,653 +1,653 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Roy Luo * Ryder Lee * Felix Fietkau * Lorenzo Bianconi */ #include #include #include #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "eeprom.h" #if defined(__linux__) static ssize_t mt7615_thermal_show_temp(struct device *dev, struct device_attribute *attr, char *buf) { struct mt7615_dev *mdev = dev_get_drvdata(dev); int temperature; if (!mt7615_wait_for_mcu_init(mdev)) return 0; mt7615_mutex_acquire(mdev); temperature = mt7615_mcu_get_temperature(mdev); mt7615_mutex_release(mdev); if (temperature < 0) return temperature; /* display in millidegree celcius */ return sprintf(buf, "%u\n", temperature * 1000); } static SENSOR_DEVICE_ATTR(temp1_input, 0444, mt7615_thermal_show_temp, NULL, 0); static struct attribute *mt7615_hwmon_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, NULL, }; ATTRIBUTE_GROUPS(mt7615_hwmon); 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; name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7615_%s", wiphy_name(wiphy)); + if (!name) + return -ENOMEM; + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, dev, mt7615_hwmon_groups); - if (IS_ERR(hwmon)) - return PTR_ERR(hwmon); - - return 0; + return PTR_ERR_OR_ZERO(hwmon); } EXPORT_SYMBOL_GPL(mt7615_thermal_init); #endif static void mt7615_phy_init(struct mt7615_dev *dev) { /* disable rf low power beacon mode */ mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(0), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(1), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN); } static void mt7615_init_mac_chain(struct mt7615_dev *dev, int chain) { u32 val; if (!chain) val = MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN; else val = MT_CFG_CCR_MAC_D1_1X_GC_EN | MT_CFG_CCR_MAC_D1_2X_GC_EN; /* enable band 0/1 clk */ mt76_set(dev, MT_CFG_CCR, val); mt76_rmw(dev, MT_TMAC_TRCR(chain), MT_TMAC_TRCR_CCA_SEL | MT_TMAC_TRCR_SEC_CCA_SEL, FIELD_PREP(MT_TMAC_TRCR_CCA_SEL, 2) | FIELD_PREP(MT_TMAC_TRCR_SEC_CCA_SEL, 0)); mt76_wr(dev, MT_AGG_ACR(chain), MT_AGG_ACR_PKT_TIME_EN | MT_AGG_ACR_NO_BA_AR_RULE | FIELD_PREP(MT_AGG_ACR_CFEND_RATE, MT7615_CFEND_RATE_DEFAULT) | FIELD_PREP(MT_AGG_ACR_BAR_RATE, MT7615_BAR_RATE_DEFAULT)); mt76_wr(dev, MT_AGG_ARUCR(chain), FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1)); mt76_wr(dev, MT_AGG_ARDCR(chain), FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1)); mt76_clear(dev, MT_DMA_RCFR0(chain), MT_DMA_RCFR0_MCU_RX_TDLS); if (!mt7615_firmware_offload(dev)) { u32 mask, set; mask = MT_DMA_RCFR0_MCU_RX_MGMT | MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR | MT_DMA_RCFR0_MCU_RX_CTL_BAR | MT_DMA_RCFR0_MCU_RX_BYPASS | MT_DMA_RCFR0_RX_DROPPED_UCAST | MT_DMA_RCFR0_RX_DROPPED_MCAST; set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) | FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); mt76_rmw(dev, MT_DMA_RCFR0(chain), mask, set); } } static void mt7615_mac_init(struct mt7615_dev *dev) { int i; mt7615_init_mac_chain(dev, 0); mt76_rmw_field(dev, MT_TMAC_CTCR0, MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); mt76_rmw_field(dev, MT_TMAC_CTCR0, MT_TMAC_CTCR0_INS_DDLMT_DENSITY, 0x3); mt76_rmw(dev, MT_TMAC_CTCR0, MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN, MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); mt7615_mac_set_scs(&dev->phy, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, MT_AGG_SCR_NLNAV_MID_PTEC_DIS); mt76_wr(dev, MT_AGG_ARCR, FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | MT_AGG_ARCR_RATE_DOWN_RATIO_EN | FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) | FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)); for (i = 0; i < MT7615_WTBL_SIZE; i++) mt7615_mac_wtbl_update(dev, i, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN); mt76_wr(dev, MT_DMA_DCR0, FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) | MT_DMA_DCR0_RX_VEC_DROP | MT_DMA_DCR0_DAMSDU_EN | MT_DMA_DCR0_RX_HDR_TRANS_EN); /* disable TDLS filtering */ mt76_clear(dev, MT_WF_PFCR, MT_WF_PFCR_TDLS_EN); mt76_set(dev, MT_WF_MIB_SCR0, MT_MIB_SCR0_AGG_CNT_RANGE_EN); if (is_mt7663(&dev->mt76)) { mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02); mt76_wr(dev, MT_WF_AGG(0x164), 0x70708040); } else { mt7615_init_mac_chain(dev, 1); } mt7615_mcu_set_rx_hdr_trans_blacklist(dev); } static void mt7615_check_offload_capability(struct mt7615_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; if (mt7615_firmware_offload(dev)) { ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); wiphy->flags &= ~WIPHY_FLAG_4ADDR_STATION; wiphy->max_remain_on_channel_duration = 5000; wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | NL80211_FEATURE_P2P_GO_CTWIN | NL80211_FEATURE_P2P_GO_OPPPS; } else { dev->ops->hw_scan = NULL; dev->ops->cancel_hw_scan = NULL; dev->ops->sched_scan_start = NULL; dev->ops->sched_scan_stop = NULL; dev->ops->set_rekey_data = NULL; dev->ops->remain_on_channel = NULL; dev->ops->cancel_remain_on_channel = NULL; wiphy->max_sched_scan_plan_interval = 0; wiphy->max_sched_scan_ie_len = 0; wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_sched_scan_ssids = 0; wiphy->max_match_sets = 0; wiphy->max_sched_scan_reqs = 0; } } bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev) { flush_work(&dev->mcu_work); return test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); } EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init); static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, { .max = MT7615_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION) } }; static const struct ieee80211_iface_combination if_comb_radar[] = { { .limits = if_limits, .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = MT7615_MAX_INTERFACES, .num_different_channels = 1, .beacon_int_infra_match = true, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80) | BIT(NL80211_CHAN_WIDTH_160) | BIT(NL80211_CHAN_WIDTH_80P80), } }; static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = MT7615_MAX_INTERFACES, .num_different_channels = 1, .beacon_int_infra_match = true, } }; void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband) { int i, n_chains = hweight8(dev->mphy.antenna_mask), target_chains; int delta_idx, delta = mt76_tx_power_nss_delta(n_chains); u8 *eep = (u8 *)dev->mt76.eeprom.data; enum nl80211_band band = sband->band; struct mt76_power_limits limits; u8 rate_val; delta_idx = mt7615_eeprom_get_power_delta_index(dev, band); rate_val = eep[delta_idx]; if ((rate_val & ~MT_EE_RATE_POWER_MASK) == (MT_EE_RATE_POWER_EN | MT_EE_RATE_POWER_SIGN)) delta += rate_val & MT_EE_RATE_POWER_MASK; if (!is_mt7663(&dev->mt76) && mt7615_ext_pa_enabled(dev, band)) target_chains = 1; else target_chains = n_chains; for (i = 0; i < sband->n_channels; i++) { struct ieee80211_channel *chan = &sband->channels[i]; u8 target_power = 0; int j; for (j = 0; j < target_chains; j++) { int index; index = mt7615_eeprom_get_target_power_index(dev, chan, j); if (index < 0) continue; target_power = max(target_power, eep[index]); } target_power = mt76_get_rate_power_limits(&dev->mphy, chan, &limits, target_power); target_power += delta; target_power = DIV_ROUND_UP(target_power, 2); chan->max_power = min_t(int, chan->max_reg_power, target_power); chan->orig_mpwr = target_power; } } EXPORT_SYMBOL_GPL(mt7615_init_txpower); void mt7615_init_work(struct mt7615_dev *dev) { mt7615_mcu_set_eeprom(dev); mt7615_mac_init(dev); mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); + mt76_connac_mcu_del_wtbl_all(&dev->mt76); mt7615_check_offload_capability(dev); } EXPORT_SYMBOL_GPL(mt7615_init_work); static void mt7615_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct mt7615_phy *phy = mphy->priv; struct cfg80211_chan_def *chandef = &mphy->chandef; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; mt7615_init_txpower(dev, &mphy->sband_2g.sband); mt7615_init_txpower(dev, &mphy->sband_5g.sband); mt7615_mutex_acquire(dev); if (chandef->chan->flags & IEEE80211_CHAN_RADAR) mt7615_dfs_init_radar_detector(phy); if (mt7615_firmware_offload(phy->dev)) { mt76_connac_mcu_set_channel_domain(mphy); mt76_connac_mcu_set_rate_txpower(mphy); } mt7615_mutex_release(dev); } static void mt7615_init_wiphy(struct ieee80211_hw *hw) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct wiphy *wiphy = hw->wiphy; hw->queues = 4; hw->max_rates = 3; hw->max_report_rates = 7; hw->max_rate_tries = 11; hw->netdev_features = NETIF_F_RXCSUM; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; hw->sta_data_size = sizeof(struct mt7615_sta); hw->vif_data_size = sizeof(struct mt7615_vif); if (is_mt7663(&phy->dev->mt76)) { wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } else { wiphy->iface_combinations = if_comb_radar; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_radar); } wiphy->reg_notifier = mt7615_regd_notifier; wiphy->max_sched_scan_plan_interval = MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; wiphy->max_sched_scan_reqs = 1; wiphy->max_scan_ssids = 4; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); if (!is_mt7622(&phy->dev->mt76)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); if (is_mt7615(&phy->dev->mt76)) hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM; else hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM; phy->mt76->sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; phy->mt76->sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; phy->mt76->sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; } static void mt7615_cap_dbdc_enable(struct mt7615_dev *dev) { dev->mphy.sband_5g.sband.vht_cap.cap &= ~(IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); if (dev->chainmask == 0xf) dev->mphy.antenna_mask = dev->chainmask >> 2; else dev->mphy.antenna_mask = dev->chainmask >> 1; dev->mphy.chainmask = dev->mphy.antenna_mask; dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; mt76_set_stream_caps(&dev->mphy, true); } static void mt7615_cap_dbdc_disable(struct mt7615_dev *dev) { dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; dev->mphy.antenna_mask = dev->chainmask; dev->mphy.chainmask = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask; mt76_set_stream_caps(&dev->mphy, true); } u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr) { u32 base, offset; if (is_mt7663(&dev->mt76)) { base = addr & MT7663_MCU_PCIE_REMAP_2_BASE; offset = addr & MT7663_MCU_PCIE_REMAP_2_OFFSET; } else { base = addr & MT_MCU_PCIE_REMAP_2_BASE; offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET; } mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base); return MT_PCIE_REMAP_BASE_2 + offset; } EXPORT_SYMBOL_GPL(mt7615_reg_map); static void mt7615_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { struct mt7615_dev *dev; struct mt76_phy *mphy; u32 val, addr; u8 index; mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); dev = container_of(mphy->dev, struct mt7615_dev, mt76); if (!mt76_connac_pm_ref(mphy, &dev->pm)) return; val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); index = dev->dbdc_support ? mphy->band_idx : mphy->leds.pin; addr = mt7615_reg_map(dev, MT_LED_STATUS_0(index)); mt76_wr(dev, addr, val); addr = mt7615_reg_map(dev, MT_LED_STATUS_1(index)); mt76_wr(dev, addr, val); val = MT_LED_CTRL_REPLAY(index) | MT_LED_CTRL_KICK(index); if (dev->mphy.leds.al) val |= MT_LED_CTRL_POLARITY(index); if (mphy->band_idx) val |= MT_LED_CTRL_BAND(index); addr = mt7615_reg_map(dev, MT_LED_CTRL); mt76_wr(dev, addr, val); mt76_connac_pm_unref(mphy, &dev->pm); } int mt7615_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { u8 delta_on, delta_off; delta_off = max_t(u8, *delay_off / 10, 1); delta_on = max_t(u8, *delay_on / 10, 1); mt7615_led_set_config(led_cdev, delta_on, delta_off); return 0; } EXPORT_SYMBOL_GPL(mt7615_led_set_blink); void mt7615_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { if (!brightness) mt7615_led_set_config(led_cdev, 0, 0xff); else mt7615_led_set_config(led_cdev, 0xff, 0); } EXPORT_SYMBOL_GPL(mt7615_led_set_brightness); int mt7615_register_ext_phy(struct mt7615_dev *dev) { struct mt7615_phy *phy = mt7615_ext_phy(dev); struct mt76_phy *mphy; int i, ret; if (!is_mt7615(&dev->mt76)) return -EOPNOTSUPP; if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) return -EINVAL; if (phy) return 0; mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops, MT_BAND1); if (!mphy) return -ENOMEM; phy = mphy->priv; phy->dev = dev; phy->mt76 = mphy; mphy->chainmask = dev->chainmask & ~dev->mphy.chainmask; mphy->antenna_mask = BIT(hweight8(mphy->chainmask)) - 1; mt7615_init_wiphy(mphy->hw); INIT_DELAYED_WORK(&mphy->mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&phy->scan_work, mt7615_scan_work); skb_queue_head_init(&phy->scan_event_list); INIT_WORK(&phy->roc_work, mt7615_roc_work); timer_setup(&phy->roc_timer, mt7615_roc_timer, 0); init_waitqueue_head(&phy->roc_wait); mt7615_mac_set_scs(phy, true); /* * Make the secondary PHY MAC address local without overlapping with * the usual MAC address allocation scheme on multiple virtual interfaces */ #if defined(__linux__) memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #elif defined(__FreeBSD__) memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #endif ETH_ALEN); mphy->macaddr[0] |= 2; mphy->macaddr[0] ^= BIT(7); mt76_eeprom_override(mphy); /* second phy can only handle 5 GHz */ mphy->cap.has_5ghz = true; /* mt7615 second phy shares the same hw queues with the primary one */ for (i = 0; i <= MT_TXQ_PSD ; i++) mphy->q_tx[i] = dev->mphy.q_tx[i]; /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { mphy->leds.cdev.brightness_set = mt7615_led_set_brightness; mphy->leds.cdev.blink_set = mt7615_led_set_blink; } ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) ieee80211_free_hw(mphy->hw); return ret; } EXPORT_SYMBOL_GPL(mt7615_register_ext_phy); void mt7615_unregister_ext_phy(struct mt7615_dev *dev) { struct mt7615_phy *phy = mt7615_ext_phy(dev); struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1]; if (!phy) return; mt7615_cap_dbdc_disable(dev); mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); } EXPORT_SYMBOL_GPL(mt7615_unregister_ext_phy); void mt7615_init_device(struct mt7615_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; dev->mt76.tx_worker.fn = mt7615_tx_worker; INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work); INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); spin_lock_init(&dev->pm.wake.lock); mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); spin_lock_init(&dev->pm.txq_lock); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work); skb_queue_head_init(&dev->phy.scan_event_list); skb_queue_head_init(&dev->coredump.msg_list); init_waitqueue_head(&dev->reset_wait); init_waitqueue_head(&dev->phy.roc_wait); INIT_WORK(&dev->phy.roc_work, mt7615_roc_work); timer_setup(&dev->phy.roc_timer, mt7615_roc_timer, 0); mt7615_init_wiphy(hw); dev->pm.idle_timeout = MT7615_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; mt7615_cap_dbdc_disable(dev); #ifdef CONFIG_NL80211_TESTMODE dev->mt76.test_ops = &mt7615_testmode_ops; #endif } EXPORT_SYMBOL_GPL(mt7615_init_device); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/mac.c b/sys/contrib/dev/mediatek/mt76/mt7615/mac.c index 5037104ed1a4..994f6f8ccd87 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/mac.c @@ -1,2382 +1,2374 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Ryder Lee * Roy Luo * Felix Fietkau * Lorenzo Bianconi */ #include #include #include #if defined(__FreeBSD__) #include #endif #include "mt7615.h" #include "../trace.h" #include "../dma.h" #include "mt7615_trace.h" #include "mac.h" #include "mcu.h" #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) static const struct mt7615_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [5] = { 1, 0, 6, 32, 28, 0, 17, 990, 5010, 1, 1 }, [6] = { 1, 0, 9, 32, 28, 0, 27, 615, 5010, 1, 1 }, [7] = { 1, 0, 15, 32, 28, 0, 27, 240, 445, 1, 1 }, [8] = { 1, 0, 12, 32, 28, 0, 42, 240, 510, 1, 1 }, [9] = { 1, 1, 0, 0, 0, 0, 14, 2490, 3343, 0, 0, 12, 32, 28 }, [10] = { 1, 1, 0, 0, 0, 0, 14, 2490, 3343, 0, 0, 15, 32, 24 }, [11] = { 1, 1, 0, 0, 0, 0, 14, 823, 2510, 0, 0, 18, 32, 28 }, [12] = { 1, 1, 0, 0, 0, 0, 14, 823, 2510, 0, 0, 27, 32, 24 }, }, }; static const struct mt7615_dfs_radar_spec fcc_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 9, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 22, 190, 510, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 32, 190, 510, 1, 1 }, [4] = { 1, 0, 9, 255, 28, 0, 13, 323, 343, 1, 32 }, }, }; static const struct mt7615_dfs_radar_spec jp_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 13, 508, 3076, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 17, 140, 240, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 22, 190, 510, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 32, 190, 510, 1, 1 }, [4] = { 1, 0, 9, 32, 28, 0, 13, 323, 343, 1, 32 }, [13] = { 1, 0, 8, 32, 28, 0, 14, 3836, 3856, 1, 1 }, [14] = { 1, 0, 8, 32, 28, 0, 14, 3990, 4010, 1, 1 }, }, }; static enum mt76_cipher_type mt7615_mac_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: return MT_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: return MT_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: return MT_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: return MT_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: return MT_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: return MT_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: return MT_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: return MT_CIPHER_GCMP_256; case WLAN_CIPHER_SUITE_SMS4: return MT_CIPHER_WAPI; default: return MT_CIPHER_NONE; } } static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, u8 idx, bool unicast) { struct mt7615_sta *sta; struct mt76_wcid *wcid; if (idx >= MT7615_WTBL_SIZE) return NULL; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (unicast || !wcid) return wcid; if (!wcid->sta) return NULL; sta = container_of(wcid, struct mt7615_sta, wcid); if (!sta->vif) return NULL; return &sta->vif->sta.wcid; } void mt7615_mac_reset_counters(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; int i; for (i = 0; i < 4; i++) { mt76_rr(dev, MT_TX_AGG_CNT(0, i)); mt76_rr(dev, MT_TX_AGG_CNT(1, i)); } memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); phy->mt76->survey_time = ktime_get_boottime(); /* reset airtime counters */ mt76_rr(dev, MT_MIB_SDR9(0)); mt76_rr(dev, MT_MIB_SDR9(1)); mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR36(1)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_rr(dev, MT_MIB_SDR37(1)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } void mt7615_mac_set_timing(struct mt7615_phy *phy) { s16 coverage_class = phy->coverage_class; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; u32 val, reg_offset; u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | 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; 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); mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE); } else { struct mt7615_phy *phy_ext = mt7615_ext_phy(dev); if (phy_ext) coverage_class = max_t(s16, phy_ext->coverage_class, coverage_class); mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE); } udelay(1); offset = 3 * coverage_class; reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); mt76_wr(dev, MT_TMAC_CDTR, cck + reg_offset); mt76_wr(dev, MT_TMAC_ODTR, ofdm + reg_offset); mt76_wr(dev, MT_TMAC_ICR(ext_phy), FIELD_PREP(MT_IFS_EIFS, 360) | FIELD_PREP(MT_IFS_RIFS, 2) | FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); if (phy->slottime < 20 || is_5ghz) val = MT7615_CFEND_RATE_DEFAULT; else val = MT7615_CFEND_RATE_11B; mt76_rmw_field(dev, MT_AGG_ACR(ext_phy), MT_AGG_ACR_CFEND_RATE, val); if (ext_phy) mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE); else mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE); } static void mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, struct mt76_rx_status *status, u8 chfreq) { if (!test_bit(MT76_HW_SCANNING, &mphy->state) && !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) && !test_bit(MT76_STATE_ROC, &mphy->state)) { status->freq = mphy->chandef.chan->center_freq; status->band = mphy->chandef.chan->band; return; } status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } static void mt7615_mac_fill_tm_rx(struct mt7615_phy *phy, __le32 *rxv) { #ifdef CONFIG_NL80211_TESTMODE u32 rxv1 = le32_to_cpu(rxv[0]); u32 rxv3 = le32_to_cpu(rxv[2]); u32 rxv4 = le32_to_cpu(rxv[3]); u32 rxv5 = le32_to_cpu(rxv[4]); u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1); u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1); s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5); u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000; if (!mode) { /* CCK */ foe &= ~BIT(11); foe *= 1000; foe >>= 11; } else { if (foe > 2048) foe -= 4096; foe = (foe * foe_const) >> 15; } phy->test.last_freq_offset = foe; phy->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); phy->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); phy->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); phy->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); phy->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); phy->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); #endif } /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7615_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); struct mt7615_sta *msta = (struct mt7615_sta *)status->wcid; __le32 *rxd = (__le32 *)skb->data; struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct ieee80211_hdr hdr; u16 frame_control; if (le32_get_bits(rxd[1], MT_RXD1_NORMAL_ADDR_TYPE) != MT_RXD1_NORMAL_U2M) return -EINVAL; if (!(le32_to_cpu(rxd[0]) & MT_RXD0_NORMAL_GROUP_4)) return -EINVAL; if (!msta || !msta->vif) return -EINVAL; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); /* store the info from RXD and ethhdr to avoid being overridden */ frame_control = le32_get_bits(rxd[4], MT_RXD4_FRAME_CONTROL); hdr.frame_control = cpu_to_le16(frame_control); hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[6], MT_RXD6_SEQ_CTRL)); hdr.duration_id = 0; ether_addr_copy(hdr.addr1, vif->addr); ether_addr_copy(hdr.addr2, sta->addr); switch (frame_control & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case 0: ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); break; case IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_source); break; case IEEE80211_FCTL_TODS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); break; case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); ether_addr_copy(hdr.addr4, eth_hdr->h_source); break; default: break; } skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); else skb_pull(skb, 2); if (ieee80211_has_order(hdr.frame_control)) memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[7], IEEE80211_HT_CTL_LEN); if (ieee80211_is_data_qos(hdr.frame_control)) { __le16 qos_ctrl; qos_ctrl = cpu_to_le16(le32_get_bits(rxd[6], MT_RXD6_QOS_CTL)); memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, IEEE80211_QOS_CTL_LEN); } if (ieee80211_has_a4(hdr.frame_control)) memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); else memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); status->flag &= ~(RX_FLAG_RADIOTAP_HE | RX_FLAG_RADIOTAP_HE_MU); return 0; } static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7615_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; struct mt7615_phy *phy2; __le32 *rxd = (__le32 *)skb->data; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; u32 csum_status = *(u32 *)skb->cb; bool unicast, hdr_trans, remove_pad, insert_ccmp_hdr = false; u16 hdr_gap; int phy_idx; int i, idx; u8 chfreq, amsdu_info, qos_ctl = 0; u16 seq_ctrl = 0; __le16 fc = 0; memset(status, 0, sizeof(*status)); chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1); phy2 = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; if (!phy2) phy_idx = 0; else if (phy2->chfreq == phy->chfreq) phy_idx = -1; else if (phy->chfreq == chfreq) phy_idx = 0; else if (phy2->chfreq == chfreq) phy_idx = 1; else phy_idx = -1; if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) return -EINVAL; hdr_trans = rxd1 & MT_RXD1_NORMAL_HDR_TRANS; if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_CM)) return -EINVAL; /* ICV error or CCMP/BIP/WPI MIC error */ if (rxd2 & MT_RXD2_NORMAL_ICV_ERR) status->flag |= RX_FLAG_ONLY_MONITOR; unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M; idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); status->wcid = mt7615_rx_get_wcid(dev, idx, unicast); if (status->wcid) { struct mt7615_sta *msta; msta = container_of(status->wcid, struct mt7615_sta, wcid); - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); } if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask && !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; if (rxd2 & MT_RXD2_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR) status->flag |= RX_FLAG_MMIC_ERROR; if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED; status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) return -EINVAL; rxd += 4; if (rxd0 & MT_RXD0_NORMAL_GROUP_4) { u32 v0 = le32_to_cpu(rxd[0]); u32 v2 = le32_to_cpu(rxd[2]); fc = cpu_to_le16(FIELD_GET(MT_RXD4_FRAME_CONTROL, v0)); qos_ctl = FIELD_GET(MT_RXD6_QOS_CTL, v2); seq_ctrl = FIELD_GET(MT_RXD6_SEQ_CTRL, v2); rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_1) { u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { case MT_CIPHER_AES_CCMP: case MT_CIPHER_CCMP_CCX: case MT_CIPHER_CCMP_256: insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); fallthrough; case MT_CIPHER_TKIP: case MT_CIPHER_TKIP_NO_MIC: case MT_CIPHER_GCMP: case MT_CIPHER_GCMP_256: status->iv[0] = data[5]; status->iv[1] = data[4]; status->iv[2] = data[3]; status->iv[3] = data[2]; status->iv[4] = data[1]; status->iv[5] = data[0]; break; default: break; } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_2) { status->timestamp = le32_to_cpu(rxd[0]); status->flag |= RX_FLAG_MACTIME_START; if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | MT_RXD2_NORMAL_NON_AMPDU))) { status->flag |= RX_FLAG_AMPDU_DETAILS; /* all subframes of an A-MPDU have the same timestamp */ if (phy->rx_ampdu_ts != status->timestamp) { if (!++phy->ampdu_ref) phy->ampdu_ref++; } phy->rx_ampdu_ts = status->timestamp; status->ampdu_ref = phy->ampdu_ref; } rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { u32 rxdg5 = le32_to_cpu(rxd[5]); /* * If both PHYs are on the same channel and we don't have a WCID, * we need to figure out which PHY this packet was received on. * On the primary PHY, the noise value for the chains belonging to the * second PHY will be set to the noise value of the last packet from * that PHY. */ if (phy_idx < 0) { int first_chain = ffs(phy2->mt76->chainmask) - 1; phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0; } } if (phy_idx == 1 && phy2) { mphy = dev->mt76.phys[MT_BAND1]; phy = phy2; status->phy_idx = phy_idx; } if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq) return -EINVAL; mt7615_get_status_freq_info(dev, mphy, status, chfreq); if (status->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else sband = &mphy->sband_2g.sband; if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; if (!sband->channels) return -EINVAL; if (rxd0 & MT_RXD0_NORMAL_GROUP_3) { u32 rxdg0 = le32_to_cpu(rxd[0]); u32 rxdg1 = le32_to_cpu(rxd[1]); u32 rxdg3 = le32_to_cpu(rxd[3]); u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0); bool cck = false; i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0); switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: i = mt76_get_rate(&dev->mt76, sband, i, cck); break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: status->encoding = RX_ENC_HT; if (i > 31) return -EINVAL; break; case MT_PHY_TYPE_VHT: status->nss = FIELD_GET(MT_RXV2_NSTS, rxdg1) + 1; status->encoding = RX_ENC_VHT; break; default: return -EINVAL; } status->rate_idx = i; switch (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0)) { case MT_PHY_BW_20: break; case MT_PHY_BW_40: status->bw = RATE_INFO_BW_40; break; case MT_PHY_BW_80: status->bw = RATE_INFO_BW_80; break; case MT_PHY_BW_160: status->bw = RATE_INFO_BW_160; break; default: return -EINVAL; } if (rxdg0 & MT_RXV1_HT_SHORT_GI) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (rxdg0 & MT_RXV1_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; status->chains = mphy->antenna_mask; status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3); status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3); status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3); status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3); mt7615_mac_fill_tm_rx(mphy->priv, rxd); rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } amsdu_info = FIELD_GET(MT_RXD1_NORMAL_PAYLOAD_FORMAT, rxd1); status->amsdu = !!amsdu_info; if (status->amsdu) { status->first_amsdu = amsdu_info == MT_RXD1_FIRST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD1_LAST_AMSDU_FRAME; } hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { if (mt7615_reverse_frag0_hdr_trans(skb, hdr_gap)) return -EINVAL; hdr_trans = false; } else { int pad_start = 0; skb_pull(skb, hdr_gap); if (!hdr_trans && status->amsdu) { pad_start = ieee80211_get_hdrlen_from_skb(skb); } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { /* * When header translation failure is indicated, * the hardware will insert an extra 2-byte field * containing the data length after the protocol * type field. This happens either when the LLC-SNAP * pattern did not match, or if a VLAN header was * detected. */ pad_start = 12; if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) pad_start += 4; else pad_start = 0; } if (pad_start) { memmove(skb->data + 2, skb->data, pad_start); skb_pull(skb, 2); } } if (insert_ccmp_hdr && !hdr_trans) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); mt76_insert_ccmp_hdr(skb, key_id); } if (!hdr_trans) { hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; if (ieee80211_is_data_qos(fc)) { seq_ctrl = le16_to_cpu(hdr->seq_ctrl); qos_ctl = *ieee80211_get_qos_ctl(hdr); } } else { status->flag |= RX_FLAG_8023; } if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); status->qos_ctl = qos_ctl; status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); return 0; } static u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev, struct mt76_phy *mphy, const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw) { u8 phy, nss, rate_idx; u16 rateval = 0; *bw = 0; if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { rate_idx = ieee80211_rate_get_vht_mcs(rate); nss = ieee80211_rate_get_vht_nss(rate); phy = MT_PHY_TYPE_VHT; if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) *bw = 1; else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) *bw = 2; else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) *bw = 3; } else if (rate->flags & IEEE80211_TX_RC_MCS) { rate_idx = rate->idx; nss = 1 + (rate->idx >> 3); phy = MT_PHY_TYPE_HT; if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) phy = MT_PHY_TYPE_HT_GF; if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) *bw = 1; } else { const struct ieee80211_rate *r; int band = mphy->chandef.chan->band; u16 val; nss = 1; r = &mphy->hw->wiphy->bands[band]->bitrates[rate->idx]; if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) val = r->hw_value_short; else val = r->hw_value; phy = val >> 8; rate_idx = val & 0xff; } if (stbc && nss == 1) { nss++; rateval |= MT_TX_RATE_STBC; } rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | FIELD_PREP(MT_TX_RATE_MODE, phy) | FIELD_PREP(MT_TX_RATE_NSS, nss - 1)); return rateval; } int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key, enum mt76_txq_id qid, bool beacon) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; bool is_mmio = mt76_is_mmio(&dev->mt76); u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE; struct mt76_phy *mphy = &dev->mphy; __le16 fc = hdr->frame_control; int tx_count = 8; u16 seqno = 0; if (vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; omac_idx = mvif->omac_idx; wmm_idx = mvif->wmm_idx; } if (sta) { struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; tx_count = msta->rate_count; } if (phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = phy_idx ? MT_LMAC_BCN1 : MT_LMAC_BCN0; } else if (qid >= MT_TXQ_PSD) { p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = phy_idx ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7615_MAX_WMM_SETS + mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, ieee80211_get_hdrlen_from_skb(skb) / 2) | FIELD_PREP(MT_TXD1_TID, skb->priority & IEEE80211_QOS_CTL_TID_MASK) | FIELD_PREP(MT_TXD1_PKT_FMT, p_fmt) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); txwi[1] = cpu_to_le32(val); val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | FIELD_PREP(MT_TXD2_MULTICAST, multicast); if (key) { if (multicast && ieee80211_is_robust_mgmt_frame(skb) && key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { val |= MT_TXD2_BIP; txwi[3] = 0; } else { txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME); } } else { txwi[3] = 0; } txwi[2] = cpu_to_le32(val); if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); txwi[4] = 0; txwi[6] = 0; if (rate->idx >= 0 && rate->count && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) { bool stbc = info->flags & IEEE80211_TX_CTL_STBC; u8 bw; u16 rateval = mt7615_mac_tx_rate_val(dev, mphy, rate, stbc, &bw); txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); val = MT_TXD6_FIXED_BW | FIELD_PREP(MT_TXD6_BW, bw) | FIELD_PREP(MT_TXD6_TX_RATE, rateval); txwi[6] |= cpu_to_le32(val); if (rate->flags & IEEE80211_TX_RC_SHORT_GI) txwi[6] |= cpu_to_le32(MT_TXD6_SGI); if (info->flags & IEEE80211_TX_CTL_LDPC) txwi[6] |= cpu_to_le32(MT_TXD6_LDPC); if (!(rate->flags & (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE); tx_count = rate->count; } if (!ieee80211_is_beacon(fc)) { struct ieee80211_hw *hw = mt76_hw(dev); val = MT_TXD5_TX_STATUS_HOST | FIELD_PREP(MT_TXD5_PID, pid); if (!ieee80211_hw_check(hw, SUPPORTS_PS)) val |= MT_TXD5_SW_POWER_MGMT; txwi[5] = cpu_to_le32(val); } else { txwi[5] = 0; /* use maximum tx count for beacons */ tx_count = 0x1f; } val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); if (info->flags & IEEE80211_TX_CTL_INJECTED) { seqno = le16_to_cpu(hdr->seq_ctrl); if (ieee80211_is_back_req(hdr->frame_control)) { struct ieee80211_bar *bar; bar = (struct ieee80211_bar *)skb->data; seqno = le16_to_cpu(bar->start_seq_num); } val |= MT_TXD3_SN_VALID | FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); } txwi[3] |= cpu_to_le32(val); if (info->flags & IEEE80211_TX_CTL_NO_ACK) txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); 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; } EXPORT_SYMBOL_GPL(mt7615_mac_write_txwi); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); } void mt7615_mac_sta_poll(struct mt7615_dev *dev) { static const u8 ac_to_tid[4] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; static const u8 hw_queue_map[] = { [IEEE80211_AC_BK] = 0, [IEEE80211_AC_BE] = 1, [IEEE80211_AC_VI] = 2, [IEEE80211_AC_VO] = 3, }; struct ieee80211_sta *sta; struct mt7615_sta *msta; u32 addr, tx_time[4], rx_time[4]; struct list_head sta_poll_list; int i; INIT_LIST_HEAD(&sta_poll_list); spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); while (!list_empty(&sta_poll_list)) { bool clear = false; msta = list_first_entry(&sta_poll_list, struct mt7615_sta, wcid.poll_list); spin_lock_bh(&dev->mt76.sta_poll_lock); list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4; for (i = 0; i < 4; i++, addr += 8) { u32 tx_last = msta->airtime_ac[i]; u32 rx_last = msta->airtime_ac[i + 4]; msta->airtime_ac[i] = mt76_rr(dev, addr); msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); tx_time[i] = msta->airtime_ac[i] - tx_last; rx_time[i] = msta->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; } if (clear) { mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); } if (!msta->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < 4; i++) { u32 tx_cur = tx_time[i]; u32 rx_cur = rx_time[hw_queue_map[i]]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) continue; ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } } } EXPORT_SYMBOL_GPL(mt7615_mac_sta_poll); static void mt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates, struct mt7615_rate_desc *rd) { struct mt7615_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_tx_rate *ref; bool rateset, stbc = false; int n_rates = sta->n_rates; u8 bw, bw_prev; int i, j; for (i = n_rates; i < 4; i++) rates[i] = rates[n_rates - 1]; rateset = !(sta->rate_set_tsf & BIT(0)); memcpy(sta->rateset[rateset].rates, rates, sizeof(sta->rateset[rateset].rates)); if (probe_rate) { sta->rateset[rateset].probe_rate = *probe_rate; ref = &sta->rateset[rateset].probe_rate; } else { sta->rateset[rateset].probe_rate.idx = -1; ref = &sta->rateset[rateset].rates[0]; } rates = sta->rateset[rateset].rates; for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) { /* * We don't support switching between short and long GI * within the rate set. For accurate tx status reporting, we * need to make sure that flags match. * For improved performance, avoid duplicate entries by * decrementing the MCS index if necessary */ if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; for (j = 0; j < i; j++) { if (rates[i].idx != rates[j].idx) continue; if ((rates[i].flags ^ rates[j].flags) & (IEEE80211_TX_RC_40_MHZ_WIDTH | IEEE80211_TX_RC_80_MHZ_WIDTH | IEEE80211_TX_RC_160_MHZ_WIDTH)) continue; if (!rates[i].idx) continue; rates[i].idx--; } } rd->val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw); bw_prev = bw; if (probe_rate) { rd->probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate, stbc, &bw); if (bw) rd->bw_idx = 1; else bw_prev = 0; } else { rd->probe_val = rd->val[0]; } rd->val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw); if (bw_prev) { rd->bw_idx = 3; bw_prev = bw; } rd->val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw); if (bw_prev) { rd->bw_idx = 5; bw_prev = bw; } rd->val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw); if (bw_prev) rd->bw_idx = 7; rd->rateset = rateset; rd->bw = bw; } static int mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) { struct mt7615_dev *dev = phy->dev; struct mt7615_wtbl_rate_desc *wrd; if (work_pending(&dev->rate_work)) return -EBUSY; wrd = kzalloc(sizeof(*wrd), GFP_ATOMIC); if (!wrd) return -ENOMEM; wrd->sta = sta; mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &wrd->rate); list_add_tail(&wrd->node, &dev->wrd_head); queue_work(dev->mt76.wq, &dev->rate_work); return 0; } u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid) { u32 addr, val, val2; u8 offset; addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4; offset = tid * 12; addr += 4 * (offset / 32); offset %= 32; val = mt76_rr(dev, addr); val >>= offset; if (offset > 20) { addr += 4; val2 = mt76_rr(dev, addr); val |= val2 << (32 - offset); } return val & GENMASK(11, 0); } void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) { int wcid = sta->wcid.idx, n_rates = sta->n_rates; struct mt7615_dev *dev = phy->dev; struct mt7615_rate_desc rd; u32 w5, w27, addr; u16 idx = sta->vif->mt76.omac_idx; if (!mt76_is_mmio(&dev->mt76)) { mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates); return; } if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) return; memset(&rd, 0, sizeof(struct mt7615_rate_desc)); mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &rd); addr = mt7615_mac_wtbl_addr(dev, wcid); w27 = mt76_rr(dev, addr + 27 * 4); w27 &= ~MT_WTBL_W27_CC_BW_SEL; w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rd.bw); w5 = mt76_rr(dev, addr + 5 * 4); w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | MT_WTBL_W5_MPDU_OK_COUNT | MT_WTBL_W5_MPDU_FAIL_COUNT | MT_WTBL_W5_RATE_IDX); w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rd.bw) | FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, rd.bw_idx ? rd.bw_idx - 1 : 7); mt76_wr(dev, MT_WTBL_RIUCR0, w5); mt76_wr(dev, MT_WTBL_RIUCR1, FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rd.probe_val) | FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rd.val[0]) | FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rd.val[1])); mt76_wr(dev, MT_WTBL_RIUCR2, FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rd.val[1] >> 8) | FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rd.val[1]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rd.val[2]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rd.val[2])); mt76_wr(dev, MT_WTBL_RIUCR3, FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rd.val[2] >> 4) | FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rd.val[3]) | FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rd.val[3])); mt76_wr(dev, MT_WTBL_UPDATE, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | MT_WTBL_UPDATE_RATE_UPDATE | MT_WTBL_UPDATE_TX_COUNT_CLEAR); mt76_wr(dev, addr + 27 * 4, w27); idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0); sta->rate_set_tsf |= rd.rateset; if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; sta->rate_probe = !!probe_rate; } EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; u32 addr; addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; if (enable) mt76_set(dev, addr, MT_WTBL_W3_RTS); else mt76_clear(dev, addr, MT_WTBL_W3_RTS); } EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, enum mt76_cipher_type cipher, u16 cipher_mask) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4; u8 data[32] = {}; if (key->keylen > sizeof(data)) return -EINVAL; mt76_rr_copy(dev, addr, data, sizeof(data)); if (cipher == MT_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(data, key->key, 16); memcpy(data + 16, key->key + 24, 8); memcpy(data + 24, key->key + 16, 8); } else { if (cipher_mask == BIT(cipher)) memcpy(data, key->key, key->keylen); else if (cipher != MT_CIPHER_BIP_CMAC_128) memcpy(data, key->key, 16); if (cipher == MT_CIPHER_BIP_CMAC_128) memcpy(data + 16, key->key, 16); } mt76_wr_copy(dev, addr, data, sizeof(data)); return 0; } static int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, enum mt76_cipher_type cipher, u16 cipher_mask, int keyidx) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1; if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) return -ETIMEDOUT; w0 = mt76_rr(dev, addr); w1 = mt76_rr(dev, addr + 4); if (cipher_mask) w0 |= MT_WTBL_W0_RX_KEY_VALID; else w0 &= ~(MT_WTBL_W0_RX_KEY_VALID | MT_WTBL_W0_KEY_IDX); if (cipher_mask & BIT(MT_CIPHER_BIP_CMAC_128)) w0 |= MT_WTBL_W0_RX_IK_VALID; else w0 &= ~MT_WTBL_W0_RX_IK_VALID; if (cipher != MT_CIPHER_BIP_CMAC_128 || cipher_mask == BIT(cipher)) { w0 &= ~MT_WTBL_W0_KEY_IDX; w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx); } mt76_wr(dev, MT_WTBL_RICR0, w0); mt76_wr(dev, MT_WTBL_RICR1, w1); if (!mt7615_mac_wtbl_update(dev, wcid->idx, MT_WTBL_UPDATE_RXINFO_UPDATE)) return -ETIMEDOUT; return 0; } static void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, enum mt76_cipher_type cipher, u16 cipher_mask) { u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx); if (cipher == MT_CIPHER_BIP_CMAC_128 && cipher_mask & ~BIT(MT_CIPHER_BIP_CMAC_128)) return; mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE, FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher)); } int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key) { enum mt76_cipher_type cipher; u16 cipher_mask = wcid->cipher; int err; cipher = mt7615_mac_get_cipher(key->cipher); if (cipher == MT_CIPHER_NONE) return -EOPNOTSUPP; cipher_mask |= BIT(cipher); mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask); err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask); if (err < 0) return err; err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, cipher_mask, key->keyidx); if (err < 0) return err; wcid->cipher = cipher_mask; return 0; } int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key) { int err; spin_lock_bh(&dev->mt76.lock); err = __mt7615_mac_wtbl_set_key(dev, wcid, key); spin_unlock_bh(&dev->mt76.lock); return err; } static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_info *info, __le32 *txs_data) { struct ieee80211_supported_band *sband; struct mt7615_rate_set *rs; struct mt76_phy *mphy; int first_idx = 0, last_idx; int i, idx, count; bool fixed_rate, ack_timeout; bool ampdu, cck = false; bool rs_idx; u32 rate_set_tsf; u32 final_rate, final_rate_flags, final_nss, txs; txs = le32_to_cpu(txs_data[1]); ampdu = txs & MT_TXS1_AMPDU; txs = le32_to_cpu(txs_data[3]); count = FIELD_GET(MT_TXS3_TX_COUNT, txs); last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs); txs = le32_to_cpu(txs_data[0]); fixed_rate = txs & MT_TXS0_FIXED_RATE; final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); ack_timeout = txs & MT_TXS0_ACK_TIMEOUT; if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT)) return false; if (txs & MT_TXS0_QUEUE_TIMEOUT) return false; if (!ack_timeout) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; info->status.ampdu_ack_len = !!(info->flags & IEEE80211_TX_STAT_ACK); if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY); if (fixed_rate) { info->status.rates[0].count = count; i = 0; goto out; } rate_set_tsf = READ_ONCE(sta->rate_set_tsf); rs_idx = !((u32)(le32_get_bits(txs_data[4], MT_TXS4_F0_TIMESTAMP) - rate_set_tsf) < 1000000); rs_idx ^= rate_set_tsf & BIT(0); rs = &sta->rateset[rs_idx]; if (!first_idx && rs->probe_rate.idx >= 0) { info->status.rates[0] = rs->probe_rate; spin_lock_bh(&dev->mt76.lock); if (sta->rate_probe) { struct mt7615_phy *phy = &dev->phy; if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1]) phy = dev->mt76.phys[MT_BAND1]->priv; mt7615_mac_set_rates(phy, sta, NULL, sta->rates); } spin_unlock_bh(&dev->mt76.lock); } else { info->status.rates[0] = rs->rates[first_idx / 2]; } info->status.rates[0].count = 0; for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { struct ieee80211_tx_rate *cur_rate; int cur_count; cur_rate = &rs->rates[idx / 2]; cur_count = min_t(int, MT7615_RATE_RETRY, count); count -= cur_count; if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; if (i == ARRAY_SIZE(info->status.rates)) { i--; break; } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; } info->status.rates[i].count += cur_count; } out: final_rate_flags = info->status.rates[i].flags; switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: mphy = &dev->mphy; if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else sband = &mphy->sband_2g.sband; final_rate &= MT_TX_RATE_IDX; final_rate = mt76_get_rate(&dev->mt76, sband, final_rate, cck); final_rate_flags = 0; break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: final_rate_flags |= IEEE80211_TX_RC_MCS; final_rate &= MT_TX_RATE_IDX; if (final_rate > 31) return false; break; case MT_PHY_TYPE_VHT: final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate); if ((final_rate & MT_TX_RATE_STBC) && final_nss) final_nss--; final_rate_flags |= IEEE80211_TX_RC_VHT_MCS; final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4); break; default: return false; } info->status.rates[i].idx = final_rate; info->status.rates[i].flags = final_rate_flags; return true; } static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, struct mt7615_sta *sta, int pid, __le32 *txs_data) { struct mt76_dev *mdev = &dev->mt76; struct sk_buff_head list; struct sk_buff *skb; if (pid < MT_PACKET_ID_FIRST) return false; trace_mac_txdone(mdev, sta->wcid.idx, pid); mt76_tx_status_lock(mdev, &list); skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list); if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!mt7615_fill_txs(dev, sta, info, txs_data)) { info->status.rates[0].count = 0; info->status.rates[0].idx = -1; } mt76_tx_status_skb_done(mdev, skb, &list); } mt76_tx_status_unlock(mdev, &list); return !!skb; } static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) { struct ieee80211_tx_info info = {}; struct ieee80211_sta *sta = NULL; struct mt7615_sta *msta = NULL; struct mt76_wcid *wcid; struct mt76_phy *mphy = &dev->mt76.phy; __le32 *txs_data = data; u8 wcidx; u8 pid; pid = le32_get_bits(txs_data[0], MT_TXS0_PID); wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); if (pid == MT_PACKET_ID_NO_ACK) return; if (wcidx >= MT7615_WTBL_SIZE) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wcidx]); if (!wcid) goto out; msta = container_of(wcid, struct mt7615_sta, wcid); sta = wcid_to_sta(wcid); - - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; if (wcidx >= MT7615_WTBL_STA || !sta) goto out; if (wcid->phy_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (mt7615_fill_txs(dev, msta, &info, txs_data)) { spin_lock_bh(&dev->mt76.rx_lock); ieee80211_tx_status_noskb(mphy->hw, sta, &info); spin_unlock_bh(&dev->mt76.rx_lock); } 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; mt76_connac_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; trace_mac_tx_free(dev, token); txwi = mt76_token_put(mdev, token); if (!txwi) return; mt7615_txwi_free(dev, txwi); } #if defined(__linux__) static void mt7615_mac_tx_free(struct mt7615_dev *dev, void *data, int len) #elif defined(__FreeBSD__) static void mt7615_mac_tx_free(struct mt7615_dev *dev, u8 *data, int len) #endif { #if defined(__linux__) struct mt76_connac_tx_free *free = data; #elif defined(__FreeBSD__) struct mt76_connac_tx_free *free = (void *)data; #endif void *tx_token = data + sizeof(*free); void *end = data + len; u8 i, count; mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); if (is_mt7615(&dev->mt76)) { mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false); } else { for (i = 0; i < IEEE80211_NUM_ACS; i++) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); } count = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_ID_CNT); if (is_mt7615(&dev->mt76)) { __le16 *token = tx_token; if (WARN_ON_ONCE((void *)&token[count] > end)) return; for (i = 0; i < count; i++) mt7615_mac_tx_free_token(dev, le16_to_cpu(token[i])); } else { __le32 *token = tx_token; if (WARN_ON_ONCE((void *)&token[count] > end)) return; for (i = 0; i < count; i++) mt7615_mac_tx_free_token(dev, le32_to_cpu(token[i])); } rcu_read_lock(); mt7615_mac_sta_poll(dev); rcu_read_unlock(); mt76_worker_schedule(&dev->mt76.tx_worker); } bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); __le32 *rxd = (__le32 *)data; __le32 *end = (__le32 *)&rxd[len / 4]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); switch (type) { case PKT_TYPE_TXRX_NOTIFY: mt7615_mac_tx_free(dev, data, len); return false; case PKT_TYPE_TXS: for (rxd++; rxd + 7 <= end; rxd += 7) mt7615_mac_add_txs(dev, rxd); return false; default: return true; } } EXPORT_SYMBOL_GPL(mt7615_rx_check); void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); __le32 *rxd = (__le32 *)skb->data; __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; u16 flag; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG); if (type == PKT_TYPE_RX_EVENT && flag == 0x1) type = PKT_TYPE_NORMAL_MCU; switch (type) { case PKT_TYPE_TXS: for (rxd++; rxd + 7 <= end; rxd += 7) mt7615_mac_add_txs(dev, rxd); dev_kfree_skb(skb); break; case PKT_TYPE_TXRX_NOTIFY: mt7615_mac_tx_free(dev, skb->data, skb->len); dev_kfree_skb(skb); break; case PKT_TYPE_RX_EVENT: mt7615_mcu_rx_event(dev, skb); break; case PKT_TYPE_NORMAL_MCU: case PKT_TYPE_NORMAL: if (!mt7615_mac_fill_rx(dev, skb)) { mt76_rx(&dev->mt76, q, skb); return; } fallthrough; default: dev_kfree_skb(skb); break; } } EXPORT_SYMBOL_GPL(mt7615_queue_rx_skb); static void mt7615_mac_set_sensitivity(struct mt7615_phy *phy, int val, bool ofdm) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; if (is_mt7663(&dev->mt76)) { if (ofdm) mt76_rmw(dev, MT7663_WF_PHY_MIN_PRI_PWR(ext_phy), MT_WF_PHY_PD_OFDM_MASK(0), MT_WF_PHY_PD_OFDM(0, val)); else mt76_rmw(dev, MT7663_WF_PHY_RXTD_CCK_PD(ext_phy), MT_WF_PHY_PD_CCK_MASK(ext_phy), MT_WF_PHY_PD_CCK(ext_phy, val)); return; } if (ofdm) mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy), MT_WF_PHY_PD_OFDM_MASK(ext_phy), MT_WF_PHY_PD_OFDM(ext_phy, val)); else mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy), MT_WF_PHY_PD_CCK_MASK(ext_phy), MT_WF_PHY_PD_CCK(ext_phy, val)); } static void mt7615_mac_set_default_sensitivity(struct mt7615_phy *phy) { /* ofdm */ mt7615_mac_set_sensitivity(phy, 0x13c, true); /* cck */ mt7615_mac_set_sensitivity(phy, 0x92, false); phy->ofdm_sensitivity = -98; phy->cck_sensitivity = -110; phy->last_cca_adj = jiffies; } void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; u32 reg, mask; mt7615_mutex_acquire(dev); if (phy->scs_en == enable) goto out; if (is_mt7663(&dev->mt76)) { reg = MT7663_WF_PHY_MIN_PRI_PWR(ext_phy); mask = MT_WF_PHY_PD_BLK(0); } else { reg = MT_WF_PHY_MIN_PRI_PWR(ext_phy); mask = MT_WF_PHY_PD_BLK(ext_phy); } if (enable) { mt76_set(dev, reg, mask); if (is_mt7622(&dev->mt76)) { mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8); mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7); } } else { mt76_clear(dev, reg, mask); } mt7615_mac_set_default_sensitivity(phy); phy->scs_en = enable; out: mt7615_mutex_release(dev); } void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) { u32 rxtd, reg; if (is_mt7663(&dev->mt76)) reg = MT7663_WF_PHY_R0_PHYMUX_5; else reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); if (ext_phy) rxtd = MT_WF_PHY_RXTD2(10); else rxtd = MT_WF_PHY_RXTD(12); mt76_set(dev, rxtd, BIT(18) | BIT(29)); mt76_set(dev, reg, 0x5 << 12); } void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; u32 reg; if (is_mt7663(&dev->mt76)) reg = MT7663_WF_PHY_R0_PHYMUX_5; else reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy); /* reset PD and MDRDY counters */ mt76_clear(dev, reg, GENMASK(22, 20)); mt76_set(dev, reg, BIT(22) | BIT(20)); } static void mt7615_mac_adjust_sensitivity(struct mt7615_phy *phy, u32 rts_err_rate, bool ofdm) { struct mt7615_dev *dev = phy->dev; int false_cca = ofdm ? phy->false_cca_ofdm : phy->false_cca_cck; bool ext_phy = phy != &dev->phy; s16 def_th = ofdm ? -98 : -110; bool update = false; s8 *sensitivity; int signal; sensitivity = ofdm ? &phy->ofdm_sensitivity : &phy->cck_sensitivity; signal = mt76_get_min_avg_rssi(&dev->mt76, ext_phy); if (!signal) { mt7615_mac_set_default_sensitivity(phy); return; } signal = min(signal, -72); if (false_cca > 500) { if (rts_err_rate > MT_FRAC(40, 100)) return; /* decrease coverage */ if (*sensitivity == def_th && signal > -90) { *sensitivity = -90; update = true; } else if (*sensitivity + 2 < signal) { *sensitivity += 2; update = true; } } else if ((false_cca > 0 && false_cca < 50) || rts_err_rate > MT_FRAC(60, 100)) { /* increase coverage */ if (*sensitivity - 2 >= def_th) { *sensitivity -= 2; update = true; } } if (*sensitivity > signal) { *sensitivity = signal; update = true; } if (update) { u16 val = ofdm ? *sensitivity * 2 + 512 : *sensitivity + 256; mt7615_mac_set_sensitivity(phy, val, ofdm); phy->last_cca_adj = jiffies; } } static void mt7615_mac_scs_check(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; u32 val, rts_err_rate = 0; u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm; bool ext_phy = phy != &dev->phy; if (!phy->scs_en) return; if (is_mt7663(&dev->mt76)) val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); else val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy)); pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val); pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val); if (is_mt7663(&dev->mt76)) val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); else val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy)); mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val); mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val); phy->false_cca_ofdm = pd_ofdm - mdrdy_ofdm; phy->false_cca_cck = pd_cck - mdrdy_cck; mt7615_mac_cca_stats_reset(phy); if (mib->rts_cnt + mib->rts_retries_cnt) rts_err_rate = MT_FRAC(mib->rts_retries_cnt, mib->rts_cnt + mib->rts_retries_cnt); /* cck */ mt7615_mac_adjust_sensitivity(phy, rts_err_rate, false); /* ofdm */ mt7615_mac_adjust_sensitivity(phy, rts_err_rate, true); if (time_after(jiffies, phy->last_cca_adj + 10 * HZ)) mt7615_mac_set_default_sensitivity(phy); } static u8 mt7615_phy_get_nf(struct mt7615_dev *dev, int idx) { static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; u32 reg, val, sum = 0, n = 0; int i; if (is_mt7663(&dev->mt76)) reg = MT7663_WF_PHY_RXTD(20); else reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20); for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { val = mt76_rr(dev, reg); sum += val * nf_power[i]; n += val; } if (!n) return 0; return sum / n; } static void mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) { struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76); struct mt7615_phy *phy = mphy->priv; struct mt76_channel_state *state; u64 busy_time, tx_time, rx_time, obss_time; u32 obss_reg = idx ? MT_WF_RMAC_MIB_TIME6 : MT_WF_RMAC_MIB_TIME5; int nf; busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), MT_MIB_SDR9_BUSY_MASK); tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), MT_MIB_SDR36_TXTIME_MASK); rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), MT_MIB_SDR37_RXTIME_MASK); obss_time = mt76_get_field(dev, obss_reg, MT_MIB_OBSSTIME_MASK); nf = mt7615_phy_get_nf(dev, idx); if (!phy->noise) phy->noise = nf << 4; else if (nf) phy->noise += nf - (phy->noise >> 4); state = mphy->chan_state; state->cc_busy += busy_time; state->cc_tx += tx_time; state->cc_rx += rx_time + obss_time; state->cc_bss_rx += rx_time; state->noise = -(phy->noise >> 4); } static void mt7615_update_survey(struct mt7615_dev *dev) { struct mt76_dev *mdev = &dev->mt76; struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1]; ktime_t cur_time; /* MT7615 can only update both phys simultaneously * since some reisters are shared across bands. */ mt7615_phy_update_channel(&mdev->phy, 0); if (mphy_ext) mt7615_phy_update_channel(mphy_ext, 1); cur_time = ktime_get_boottime(); mt76_update_survey_active_time(&mdev->phy, cur_time); if (mphy_ext) mt76_update_survey_active_time(mphy_ext, cur_time); /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } void mt7615_update_channel(struct mt76_phy *mphy) { struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76); if (mt76_connac_pm_wake(&dev->mphy, &dev->pm)) return; mt7615_update_survey(dev); mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7615_update_channel); static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; bool ext_phy = phy != &dev->phy; int i, aggr = 0; u32 val, val2; mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy), MT_MIB_SDR3_FCS_ERR_MASK); val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy), MT_MIB_AMPDU_MPDU_COUNT); if (val) { val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy), MT_MIB_AMPDU_ACK_COUNT); mib->aggr_per = 1000 * (val - val2) / val; } for (i = 0; i < 4; i++) { val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i)); mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i)); mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i)); phy->mt76->aggr_stats[aggr++] += val & 0xffff; phy->mt76->aggr_stats[aggr++] += val >> 16; } } void mt7615_pm_wake_work(struct work_struct *work) { struct mt7615_dev *dev; struct mt76_phy *mphy; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, pm.wake_work); mphy = dev->phy.mt76; if (!mt7615_mcu_set_drv_ctrl(dev)) { struct mt76_dev *mdev = &dev->mt76; int i; if (mt76_is_sdio(mdev)) { mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_worker_schedule(&mdev->sdio.txrx_worker); } else { local_bh_disable(); mt76_for_each_q_rx(mdev, i) napi_schedule(&mdev->napi[i]); local_bh_enable(); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM], false); } if (test_bit(MT76_STATE_RUNNING, &mphy->state)) { unsigned long timeout; timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout); } } ieee80211_wake_queues(mphy->hw); wake_up(&dev->pm.wait); } void mt7615_pm_power_save_work(struct work_struct *work) { struct mt7615_dev *dev; unsigned long delta; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, pm.ps_work.work); delta = dev->pm.idle_timeout; if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) || test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state)) goto out; if (mutex_is_locked(&dev->mt76.mutex)) /* if mt76 mutex is held we should not put the device * to sleep since we are currently accessing device * register map. We need to wait for the next power_save * trigger. */ goto out; if (time_is_after_jiffies(dev->pm.last_activity + delta)) { delta = dev->pm.last_activity + delta - jiffies; goto out; } if (!mt7615_mcu_set_fw_ctrl(dev)) return; out: queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; struct mt76_phy *mphy; unsigned long timeout; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); phy = mphy->priv; mt7615_mutex_acquire(phy->dev); mt7615_update_survey(phy->dev); if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; mt7615_mac_update_mib_stats(phy); mt7615_mac_scs_check(phy); } mt7615_mutex_release(phy->dev); mt76_tx_status_check(mphy->dev, false); timeout = mt7615_get_macwork_timeout(phy->dev); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout); } void mt7615_tx_token_put(struct mt7615_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) mt7615_txwi_free(dev, txwi); spin_unlock_bh(&dev->mt76.token_lock); idr_destroy(&dev->mt76.token); } EXPORT_SYMBOL_GPL(mt7615_tx_token_put); static void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; if (phy->rdd_state & BIT(0)) mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0, MT_RX_SEL0, 0); if (phy->rdd_state & BIT(1)) mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1, MT_RX_SEL0, 0); } static int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain) { int err; err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain, MT_RX_SEL0, 0); if (err < 0) return err; return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain, MT_RX_SEL0, 1); } static int mt7615_dfs_start_radar_detector(struct mt7615_phy *phy) { struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; int err; /* start CAC */ err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, ext_phy, MT_RX_SEL0, 0); if (err < 0) return err; err = mt7615_dfs_start_rdd(dev, ext_phy); if (err < 0) return err; phy->rdd_state |= BIT(ext_phy); if (chandef->width == NL80211_CHAN_WIDTH_160 || chandef->width == NL80211_CHAN_WIDTH_80P80) { err = mt7615_dfs_start_rdd(dev, 1); if (err < 0) return err; phy->rdd_state |= BIT(1); } return 0; } static int mt7615_dfs_init_radar_specs(struct mt7615_phy *phy) { const struct mt7615_dfs_radar_spec *radar_specs; struct mt7615_dev *dev = phy->dev; int err, i, lpn = 500; switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs; lpn = 8; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs; break; case NL80211_DFS_JP: radar_specs = &jp_radar_specs; break; default: return -EINVAL; } /* avoid FCC radar detection in non-FCC region */ err = mt7615_mcu_set_fcc5_lpn(dev, lpn); if (err < 0) return err; for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { err = mt7615_mcu_set_radar_th(dev, i, &radar_specs->radar_pattern[i]); if (err < 0) return err; } return mt7615_mcu_set_pulse_th(dev, &radar_specs->pulse_th); } int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy) { struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; enum mt76_dfs_state dfs_state, prev_state; int err; if (is_mt7663(&dev->mt76)) return 0; prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && dfs_state < MT_DFS_STATE_CAC) dfs_state = MT_DFS_STATE_ACTIVE; if (prev_state == dfs_state) return 0; if (dfs_state == MT_DFS_STATE_DISABLED) goto stop; if (prev_state <= MT_DFS_STATE_DISABLED) { err = mt7615_dfs_init_radar_specs(phy); if (err < 0) return err; err = mt7615_dfs_start_radar_detector(phy); if (err < 0) return err; phy->mt76->dfs_state = MT_DFS_STATE_CAC; } if (dfs_state == MT_DFS_STATE_CAC) return 0; err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, ext_phy, MT_RX_SEL0, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; } phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE; return 0; stop: err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, ext_phy, MT_RX_SEL0, 0); if (err < 0) return err; mt7615_dfs_stop_radar_detector(phy); phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; return 0; } int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; int err; if (!mt7615_firmware_offload(dev)) return -EOPNOTSUPP; switch (vif->type) { case NL80211_IFTYPE_MONITOR: return 0; case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: if (enable) phy->n_beacon_vif++; else phy->n_beacon_vif--; fallthrough; default: break; } err = mt7615_mcu_set_bss_pm(dev, vif, !phy->n_beacon_vif); if (err) return err; if (phy->n_beacon_vif) { vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); } else { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; mt76_set(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); } return 0; } void mt7615_coredump_work(struct work_struct *work) { struct mt7615_dev *dev; char *dump, *data; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, coredump.work.work); if (time_is_after_jiffies(dev->coredump.last_activity + 4 * MT76_CONNAC_COREDUMP_TIMEOUT)) { queue_delayed_work(dev->mt76.wq, &dev->coredump.work, MT76_CONNAC_COREDUMP_TIMEOUT); return; } dump = vzalloc(MT76_CONNAC_COREDUMP_SZ); data = dump; while (true) { struct sk_buff *skb; spin_lock_bh(&dev->mt76.lock); skb = __skb_dequeue(&dev->coredump.msg_list); spin_unlock_bh(&dev->mt76.lock); if (!skb) break; skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { dev_kfree_skb(skb); continue; } memcpy(data, skb->data, skb->len); data += skb->len; dev_kfree_skb(skb); } if (dump) dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, GFP_KERNEL); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/main.c b/sys/contrib/dev/mediatek/mt76/mt7615/main.c index 200b1752ca77..2e7b05eeef7a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/main.c @@ -1,1378 +1,1369 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Roy Luo * Ryder Lee * Felix Fietkau * Lorenzo Bianconi */ #include #include #include "mt7615.h" #include "mcu.h" static bool mt7615_dev_running(struct mt7615_dev *dev) { struct mt7615_phy *phy; if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) return true; phy = mt7615_ext_phy(dev); return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); } static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); unsigned long timeout; bool running; int ret; if (!mt7615_wait_for_mcu_init(dev)) return -EIO; mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); if (!running) { ret = mt7615_mcu_set_pm(dev, 0, 0); if (ret) goto out; ret = mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); if (ret) goto out; mt7615_mac_enable_nf(dev, 0); } if (phy != &dev->phy) { ret = mt7615_mcu_set_pm(dev, 1, 0); if (ret) goto out; ret = mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, true, false); if (ret) goto out; mt7615_mac_enable_nf(dev, 1); } if (mt7615_firmware_offload(dev)) { ret = mt76_connac_mcu_set_channel_domain(phy->mt76); if (ret) goto out; ret = mt76_connac_mcu_set_rate_txpower(phy->mt76); if (ret) goto out; } ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); if (ret) goto out; set_bit(MT76_STATE_RUNNING, &phy->mt76->state); timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); if (!running) mt7615_mac_reset_counters(phy); out: mt7615_mutex_release(dev); return ret; } -static void mt7615_stop(struct ieee80211_hw *hw) +static void mt7615_stop(struct ieee80211_hw *hw, bool suspend) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); cancel_delayed_work_sync(&phy->mt76->mac_work); del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); cancel_delayed_work_sync(&dev->pm.ps_work); cancel_work_sync(&dev->pm.wake_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt7615_mutex_acquire(dev); mt76_testmode_reset(phy->mt76, true); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); if (phy != &dev->phy) { mt7615_mcu_set_pm(dev, 1, 1); mt76_connac_mcu_set_mac_enable(&dev->mt76, 1, false, false); } if (!mt7615_dev_running(dev)) { mt7615_mcu_set_pm(dev, 0, 1); mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); } mt7615_mutex_release(dev); } static inline int get_free_idx(u32 mask, u8 start, u8 end) { return ffs(~mask & GENMASK(end, start)); } static int get_omac_idx(enum nl80211_iftype type, u64 mask) { int i; switch (type) { case NL80211_IFTYPE_STATION: /* prefer hw bssid slot 1-3 */ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); if (i) return i - 1; /* next, try to find a free repeater entry for the sta */ i = get_free_idx(mask >> REPEATER_BSSID_START, 0, REPEATER_BSSID_MAX - REPEATER_BSSID_START); if (i) return i + 32 - 1; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP: /* ap uses hw bssid 0 and ext bssid */ if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; break; default: WARN_ON(1); break; } return -1; } static int mt7615_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt76_txq *mtxq; bool ext_phy = phy != &dev->phy; int idx, ret = 0; mt7615_mutex_acquire(dev); mt76_testmode_reset(phy->mt76, true); if (vif->type == NL80211_IFTYPE_MONITOR && is_zero_ether_addr(vif->addr)) phy->monitor_vif = vif; mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); if (mvif->mt76.idx >= MT7615_MAX_INTERFACES) { ret = -ENOSPC; goto out; } idx = get_omac_idx(vif->type, dev->omac_mask); if (idx < 0) { ret = -ENOSPC; goto out; } mvif->mt76.omac_idx = idx; mvif->mt76.band_idx = ext_phy; mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; + mvif->mt76.wcid = &mvif->sta.wcid; if (ext_phy) mvif->mt76.wmm_idx += 2; dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); dev->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); ret = mt7615_mcu_set_dbdc(dev); if (ret) goto out; idx = MT7615_WTBL_RESERVED - mvif->mt76.idx; INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = mvif->mt76.band_idx; - mvif->sta.wcid.hw_key_idx = -1; - mt76_packet_id_init(&mvif->sta.wcid); + mt76_wcid_init(&mvif->sta.wcid, mvif->mt76.band_idx); mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; } ret = mt7615_mcu_add_dev_info(phy, vif, true); out: mt7615_mutex_release(dev); return ret; } static void mt7615_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_sta *msta = &mvif->sta; struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); int idx = msta->wcid.idx; mt7615_mutex_acquire(dev); mt7615_mcu_add_bss_info(phy, vif, NULL, false); mt7615_mcu_sta_add(phy, vif, NULL, false); mt76_testmode_reset(phy->mt76, true); if (vif == phy->monitor_vif) phy->monitor_vif = NULL; mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); mt7615_mcu_add_dev_info(phy, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); dev->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); mt7615_mutex_release(dev); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid); + mt76_wcid_cleanup(&dev->mt76, &mvif->sta.wcid); } -int mt7615_set_channel(struct mt7615_phy *phy) +int mt7615_set_channel(struct mt76_phy *mphy) { + struct mt7615_phy *phy = mphy->priv; struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; int ret; - cancel_delayed_work_sync(&phy->mt76->mac_work); - - mt7615_mutex_acquire(dev); - - set_bit(MT76_RESET, &phy->mt76->state); - - mt76_set_channel(phy->mt76); + mt76_connac_pm_wake(mphy, &dev->pm); if (is_mt7615(&dev->mt76) && dev->flash_eeprom) { ret = mt7615_mcu_apply_rx_dcoc(phy); if (ret) goto out; ret = mt7615_mcu_apply_tx_dpd(phy); if (ret) goto out; } ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH)); if (ret) goto out; mt7615_mac_set_timing(phy); ret = mt7615_dfs_init_radar_detector(phy); if (ret) goto out; mt7615_mac_cca_stats_reset(phy); ret = mt7615_mcu_set_sku_en(phy, true); if (ret) goto out; mt7615_mac_reset_counters(phy); phy->noise = 0; phy->chfreq = mt76_rr(dev, MT_CHFREQ(ext_phy)); out: - clear_bit(MT76_RESET, &phy->mt76->state); + mt76_connac_power_save_sched(mphy, &dev->pm); - mt7615_mutex_release(dev); - - mt76_worker_schedule(&dev->mt76.tx_worker); if (!mt76_testmode_enabled(phy->mt76)) { unsigned long timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work, timeout); } return ret; } +EXPORT_SYMBOL_GPL(mt7615_set_channel); static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->wcid; int idx = key->keyidx, err = 0; u8 *wcid_keyidx = &wcid->hw_key_idx; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_AES_CMAC: wcid_keyidx = &wcid->hw_key_idx2; key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; break; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: default: return -EOPNOTSUPP; } mt7615_mutex_acquire(dev); if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); mt7615_mcu_add_bss_info(phy, vif, NULL, true); } if (cmd == SET_KEY) *wcid_keyidx = idx; else { if (idx == *wcid_keyidx) *wcid_keyidx = -1; goto out; } mt76_wcid_key_setup(&dev->mt76, wcid, key); if (mt76_is_mmio(&dev->mt76)) err = mt7615_mac_wtbl_set_key(dev, wcid, key); else err = __mt7615_mac_wtbl_set_key(dev, wcid, key); out: mt7615_mutex_release(dev); return err; } static int mt7615_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt7615_phy *phy = mt7615_hw_phy(hw); int err; if (!cfg80211_chandef_valid(&phy->mt76->chandef)) return -EINVAL; err = mt76_init_sar_power(hw, sar); if (err) return err; if (mt7615_firmware_offload(phy->dev)) return mt76_connac_mcu_set_rate_txpower(phy->mt76); - ieee80211_stop_queues(hw); - err = mt7615_set_channel(phy); - ieee80211_wake_queues(hw); - - return err; + return mt76_update_channel(phy->mt76); } static int mt7615_config(struct ieee80211_hw *hw, u32 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); bool band = phy != &dev->phy; int ret = 0; if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_POWER)) { #ifdef CONFIG_NL80211_TESTMODE if (phy->mt76->test.state != MT76_TM_STATE_OFF) { mt7615_mutex_acquire(dev); mt76_testmode_reset(phy->mt76, false); mt7615_mutex_release(dev); } #endif - ieee80211_stop_queues(hw); - ret = mt7615_set_channel(phy); - ieee80211_wake_queues(hw); + ret = mt76_update_channel(phy->mt76); } mt7615_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { mt76_testmode_reset(phy->mt76, true); if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; else phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); } mt7615_mutex_release(dev); return ret; } static int mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); int err; mt7615_mutex_acquire(dev); queue = mt7615_lmac_mapping(dev, queue); queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; err = mt7615_mcu_set_wmm(dev, queue, params); mt7615_mutex_release(dev); return err; } static void mt7615_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); bool band = phy != &dev->phy; u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | MT_WF_RFCR1_DROP_BF_POLL | MT_WF_RFCR1_DROP_BA | MT_WF_RFCR1_DROP_CFEND | MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; mt7615_mutex_acquire(dev); #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ phy->rxfilter &= ~(_hw); \ if (!mt76_testmode_enabled(phy->mt76)) \ phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\ } while (0) phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | MT_WF_RFCR_DROP_FRAME_REPORT | MT_WF_RFCR_DROP_PROBEREQ | MT_WF_RFCR_DROP_MCAST_FILTERED | MT_WF_RFCR_DROP_MCAST | MT_WF_RFCR_DROP_BCAST | MT_WF_RFCR_DROP_DUPLICATE | MT_WF_RFCR_DROP_A2_BSSID | MT_WF_RFCR_DROP_UNWANTED_CTL | MT_WF_RFCR_DROP_STBC_MULTI); if (phy->n_beacon_vif || !mt7615_firmware_offload(dev)) phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_BEACON; MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | MT_WF_RFCR_DROP_A3_MAC | MT_WF_RFCR_DROP_A3_BSSID); MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | MT_WF_RFCR_DROP_RTS | MT_WF_RFCR_DROP_CTL_RSV | MT_WF_RFCR_DROP_NDPA); *total_flags = flags; mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); if (*total_flags & FIF_CONTROL) mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); mt7615_mutex_release(dev); } static void mt7615_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); u8 i, band = mvif->mt76.band_idx; u32 *mu; mu = (u32 *)info->mu_group.membership; for (i = 0; i < WLAN_MEMBERSHIP_LEN / sizeof(*mu); i++) { if (is_mt7663(&dev->mt76)) mt76_wr(dev, MT7663_WF_PHY_GID_TAB_VLD(band, i), mu[i]); else mt76_wr(dev, MT_WF_PHY_GID_TAB_VLD(band, i), mu[i]); } mu = (u32 *)info->mu_group.position; for (i = 0; i < WLAN_USER_POSITION_LEN / sizeof(*mu); i++) { if (is_mt7663(&dev->mt76)) mt76_wr(dev, MT7663_WF_PHY_GID_TAB_POS(band, i), mu[i]); else mt76_wr(dev, MT_WF_PHY_GID_TAB_POS(band, i), mu[i]); } } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); mt7615_mutex_acquire(dev); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; if (slottime != phy->slottime) { phy->slottime = slottime; mt7615_mac_set_timing(phy); } } if (changed & BSS_CHANGED_ERP_CTS_PROT) mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { mt7615_mcu_add_bss_info(phy, vif, NULL, true); mt7615_mcu_sta_add(phy, vif, NULL, true); if (mt7615_firmware_offload(dev) && vif->p2p) mt76_connac_mcu_set_p2p_oppps(hw, vif); } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); if (changed & BSS_CHANGED_PS) mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); if ((changed & BSS_CHANGED_ARP_FILTER) && mt7615_firmware_offload(dev)) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76, info); } if (changed & BSS_CHANGED_ASSOC) mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc); if (changed & BSS_CHANGED_MU_GROUPS) mt7615_update_mu_group(hw, vif, info); mt7615_mutex_release(dev); } static void mt7615_channel_switch_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_chan_def *chandef) { struct mt7615_dev *dev = mt7615_hw_dev(hw); mt7615_mutex_acquire(dev); mt7615_mcu_add_beacon(dev, hw, vif, true); mt7615_mutex_release(dev); } int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_phy *phy; int idx, err; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); if (idx < 0) return -ENOSPC; INIT_LIST_HEAD(&msta->wcid.poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.phy_idx = mvif->mt76.band_idx; phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy; err = mt76_connac_pm_wake(phy->mt76, &dev->pm); if (err) return err; if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { err = mt7615_mcu_add_bss_info(phy, vif, sta, true); if (err) return err; } mt7615_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); err = mt7615_mcu_sta_add(&dev->phy, vif, sta, true); if (err) return err; mt76_connac_power_save_sched(phy->mt76, &dev->pm); return err; } EXPORT_SYMBOL_GPL(mt7615_mac_sta_add); void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_phy *phy; mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); phy = mvif->mt76.band_idx ? mt7615_ext_phy(dev) : &dev->phy; mt76_connac_pm_wake(phy->mt76, &dev->pm); mt7615_mcu_sta_add(&dev->phy, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) mt7615_mcu_add_bss_info(phy, vif, sta, false); spin_lock_bh(&mdev->sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&mdev->sta_poll_lock); mt76_connac_power_save_sched(phy->mt76, &dev->pm); } EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove); static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); int i; if (!sta_rates) return; spin_lock_bh(&dev->mt76.lock); for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { msta->rates[i].idx = sta_rates->rate[i].idx; msta->rates[i].count = sta_rates->rate[i].count; msta->rates[i].flags = sta_rates->rate[i].flags; if (msta->rates[i].idx < 0 || !msta->rates[i].count) break; } msta->n_rates = i; if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) { mt7615_mac_set_rates(phy, msta, NULL, msta->rates); mt76_connac_pm_unref(phy->mt76, &dev->pm); } spin_unlock_bh(&dev->mt76.lock); } void mt7615_tx_worker(struct mt76_worker *w) { struct mt7615_dev *dev = container_of(w, struct mt7615_dev, mt76.tx_worker); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { queue_work(dev->mt76.wq, &dev->pm.wake_work); return; } mt76_tx_worker_run(&dev->mt76); mt76_connac_pm_unref(&dev->mphy, &dev->pm); } static void mt7615_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct mt7615_sta *msta = NULL; int qid; if (control->sta) { msta = (struct mt7615_sta *)control->sta->drv_priv; wcid = &msta->wcid; } if (vif && !control->sta) { struct mt7615_vif *mvif; mvif = (struct mt7615_vif *)vif->drv_priv; msta = &mvif->sta; wcid = &msta->wcid; } if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); mt76_connac_pm_unref(mphy, &dev->pm); return; } qid = skb_get_queue_mapping(skb); if (qid >= MT_TXQ_PSD) { qid = IEEE80211_AC_BE; skb_set_queue_mapping(skb, qid); } mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); } static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); int err, band = phy != &dev->phy; mt7615_mutex_acquire(dev); err = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, band); mt7615_mutex_release(dev); return err; } static int mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct mt7615_dev *dev = mt7615_hw_dev(hw); struct ieee80211_sta *sta = params->sta; struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mt7615_mutex_acquire(dev); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); ret = mt7615_mcu_add_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); ret = mt7615_mcu_add_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; ret = mt7615_mcu_add_tx_ba(dev, params, true); ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); ieee80211_send_bar(vif, sta->addr, tid, IEEE80211_SN_TO_SEQ(ssn)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; ret = mt7615_mcu_add_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); params->ssn = ssn; ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ret = mt7615_mcu_add_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mt7615_mutex_release(dev); return ret; } static int mt7615_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, IEEE80211_STA_NONE); } static int mt7615_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, IEEE80211_STA_NOTEXIST); } static int mt7615_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mib_stats *mib = &phy->mib; mt7615_mutex_acquire(phy->dev); stats->dot11RTSSuccessCount = mib->rts_cnt; stats->dot11RTSFailureCount = mib->rts_retries_cnt; stats->dot11FCSErrorCount = mib->fcs_err_cnt; stats->dot11ACKFailureCount = mib->ack_fail_cnt; mt7615_mutex_release(phy->dev); return 0; } static u64 mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); union { u64 t64; u32 t32[2]; } tsf; u16 idx = mvif->mt76.omac_idx; u32 reg; idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); mt7615_mutex_acquire(dev); /* TSF read */ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1); mt7615_mutex_release(dev); return tsf.t64; } static void mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 timestamp) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 idx = mvif->mt76.omac_idx; u32 reg; idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); mt7615_mutex_acquire(dev); mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); /* TSF software overwrite */ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_WRITE); mt7615_mutex_release(dev); } static void mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, s64 timestamp) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 idx = mvif->mt76.omac_idx; u32 reg; idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; reg = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); mt7615_mutex_acquire(dev); mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); /* TSF software adjust*/ mt76_rmw(dev, reg, MT_LPON_TCR_MODE, MT_LPON_TCR_ADJUST); mt7615_mutex_release(dev); } static void mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = phy->dev; mt7615_mutex_acquire(dev); phy->coverage_class = max_t(s16, coverage_class, 0); mt7615_mac_set_timing(phy); mt7615_mutex_release(dev); } static int mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); int max_nss = hweight8(hw->wiphy->available_antennas_tx); bool ext_phy = phy != &dev->phy; if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) return -EINVAL; if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) tx_ant = BIT(ffs(tx_ant) - 1) - 1; mt7615_mutex_acquire(dev); phy->mt76->antenna_mask = tx_ant; if (ext_phy) { if (dev->chainmask == 0xf) tx_ant <<= 2; else tx_ant <<= 1; } phy->mt76->chainmask = tx_ant; mt76_set_stream_caps(phy->mt76, true); mt7615_mutex_release(dev); return 0; } static void mt7615_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt7615_phy *phy = priv; mt7615_mcu_set_roc(phy, vif, NULL, 0); } void mt7615_roc_work(struct work_struct *work) { struct mt7615_phy *phy; phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, roc_work); if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) return; mt7615_mutex_acquire(phy->dev); ieee80211_iterate_active_interfaces(phy->mt76->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_roc_iter, phy); mt7615_mutex_release(phy->dev); ieee80211_remain_on_channel_expired(phy->mt76->hw); } void mt7615_roc_timer(struct timer_list *timer) { struct mt7615_phy *phy = from_timer(phy, timer, roc_timer); ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); } void mt7615_scan_work(struct work_struct *work) { struct mt7615_phy *phy; phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy, scan_work.work); while (true) { struct mt7615_mcu_rxd *rxd; struct sk_buff *skb; spin_lock_bh(&phy->dev->mt76.lock); skb = __skb_dequeue(&phy->scan_event_list); spin_unlock_bh(&phy->dev->mt76.lock); if (!skb) break; rxd = (struct mt7615_mcu_rxd *)skb->data; if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { ieee80211_sched_scan_results(phy->mt76->hw); } else if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { struct cfg80211_scan_info info = { .aborted = false, }; ieee80211_scan_completed(phy->mt76->hw, &info); } dev_kfree_skb(skb); } } static int mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; /* fall-back to sw-scan */ if (!mt7615_firmware_offload(dev)) return 1; mt7615_mutex_acquire(dev); err = mt76_connac_mcu_hw_scan(mphy, vif, req); mt7615_mutex_release(dev); return err; } static void mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; mt7615_mutex_acquire(dev); mt76_connac_mcu_cancel_hw_scan(mphy, vif); mt7615_mutex_release(dev); } static int mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; if (!mt7615_firmware_offload(dev)) return -EOPNOTSUPP; mt7615_mutex_acquire(dev); err = mt76_connac_mcu_sched_scan_req(mphy, vif, req); if (err < 0) goto out; err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true); out: mt7615_mutex_release(dev); return err; } static int mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; if (!mt7615_firmware_offload(dev)) return -EOPNOTSUPP; mt7615_mutex_acquire(dev); err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false); mt7615_mutex_release(dev); return err; } static int mt7615_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration, enum ieee80211_roc_type type) { struct mt7615_phy *phy = mt7615_hw_phy(hw); int err; if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) return 0; mt7615_mutex_acquire(phy->dev); err = mt7615_mcu_set_roc(phy, vif, chan, duration); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); goto out; } if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) { mt7615_mcu_set_roc(phy, vif, NULL, 0); clear_bit(MT76_STATE_ROC, &phy->mt76->state); err = -ETIMEDOUT; } out: mt7615_mutex_release(phy->dev); return err; } static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_phy *phy = mt7615_hw_phy(hw); int err; if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) return 0; del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); mt7615_mutex_acquire(phy->dev); err = mt7615_mcu_set_roc(phy, vif, NULL, 0); mt7615_mutex_release(phy->dev); return err; } static void mt7615_sta_set_decap_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; mt7615_mutex_acquire(dev); if (enabled) set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); mt7615_mcu_set_sta_decap_offload(dev, vif, sta); mt7615_mutex_release(dev); } #ifdef CONFIG_PM static int mt7615_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = mt7615_hw_dev(hw); int err = 0; cancel_delayed_work_sync(&dev->pm.ps_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); cancel_delayed_work_sync(&phy->mt76->mac_work); set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt76_connac_mcu_set_suspend_iter, phy->mt76); if (!mt7615_dev_running(dev)) - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true); mt7615_mutex_release(dev); return err; } static int mt7615_resume(struct ieee80211_hw *hw) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = mt7615_hw_dev(hw); unsigned long timeout; bool running; mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); if (!running) { int err; - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true); if (err < 0) { mt7615_mutex_release(dev); return err; } } clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt76_connac_mcu_set_suspend_iter, phy->mt76); timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, timeout); mt7615_mutex_release(dev); return 0; } static void mt7615_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_dev *mdev = &dev->mt76; device_set_wakeup_enable(mdev->dev, enabled); } static void mt7615_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { struct mt7615_dev *dev = mt7615_hw_dev(hw); mt7615_mutex_acquire(dev); mt76_connac_mcu_update_gtk_rekey(hw, vif, data); mt7615_mutex_release(dev); } #endif /* CONFIG_PM */ const struct ieee80211_ops mt7615_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7615_tx, .start = mt7615_start, .stop = mt7615_stop, .add_interface = mt7615_add_interface, .remove_interface = mt7615_remove_interface, .config = mt7615_config, .conf_tx = mt7615_conf_tx, .configure_filter = mt7615_configure_filter, .bss_info_changed = mt7615_bss_info_changed, .sta_add = mt7615_sta_add, .sta_remove = mt7615_sta_remove, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7615_set_key, .sta_set_decap_offload = mt7615_sta_set_decap_offload, .ampdu_action = mt7615_ampdu_action, .set_rts_threshold = mt7615_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt7615_sta_rate_tbl_update, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76_sw_scan_complete, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7615_channel_switch_beacon, .get_stats = mt7615_get_stats, .get_tsf = mt7615_get_tsf, .set_tsf = mt7615_set_tsf, .offset_tsf = mt7615_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7615_set_antenna, .set_coverage_class = mt7615_set_coverage_class, .hw_scan = mt7615_hw_scan, .cancel_hw_scan = mt7615_cancel_hw_scan, .sched_scan_start = mt7615_start_sched_scan, .sched_scan_stop = mt7615_stop_sched_scan, .remain_on_channel = mt7615_remain_on_channel, .cancel_remain_on_channel = mt7615_cancel_remain_on_channel, CFG80211_TESTMODE_CMD(mt76_testmode_cmd) CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_PM .suspend = mt7615_suspend, .resume = mt7615_resume, .set_wakeup = mt7615_set_wakeup, .set_rekey_data = mt7615_set_rekey_data, #endif /* CONFIG_PM */ .set_sar_specs = mt7615_set_sar_specs, }; EXPORT_SYMBOL_GPL(mt7615_ops); +MODULE_DESCRIPTION("MediaTek MT7615E and MT7663E wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7615/mcu.c index 704faf50f4f9..ccc36ee0900c 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/mcu.c @@ -1,2574 +1,2568 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Roy Luo * Ryder Lee */ #include #include "mt7615.h" #include "mcu.h" #include "mac.h" #include "eeprom.h" static bool prefer_offload_fw = true; module_param(prefer_offload_fw, bool, 0644); MODULE_PARM_DESC(prefer_offload_fw, "Prefer client mode offload firmware (MT7663)"); struct mt7615_patch_hdr { char build_date[16]; char platform[4]; __be32 hw_sw_ver; __be32 patch_ver; __be16 checksum; } __packed; struct mt7615_fw_trailer { __le32 addr; u8 chip_id; u8 feature_set; u8 eco_code; char fw_ver[10]; char build_date[15]; __le32 len; } __packed; #define FW_V3_COMMON_TAILER_SIZE 36 #define FW_V3_REGION_TAILER_SIZE 40 #define FW_START_OVERRIDE BIT(0) #define FW_START_DLYCAL BIT(1) #define FW_START_WORKING_PDA_CR4 BIT(2) struct mt7663_fw_buf { __le32 crc; __le32 d_img_size; __le32 block_size; u8 rsv[4]; __le32 img_dest_addr; __le32 img_size; u8 feature_set; }; #define MT7615_PATCH_ADDRESS 0x80000 #define MT7622_PATCH_ADDRESS 0x9c000 #define MT7663_PATCH_ADDRESS 0xdc000 #define N9_REGION_NUM 2 #define CR4_REGION_NUM 1 #define IMG_CRC_LEN 4 void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq) { int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); struct mt7615_uni_txd *uni_txd; struct mt7615_mcu_txd *mcu_txd; u8 seq, q_idx, pkt_fmt; __le32 *txd; u32 val; /* TODO: make dynamic based on msg type */ dev->mt76.mcu.timeout = 20 * HZ; seq = ++dev->mt76.mcu.msg_seq & 0xf; if (!seq) seq = ++dev->mt76.mcu.msg_seq & 0xf; if (wait_seq) *wait_seq = seq; txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); txd = (__le32 *)skb_push(skb, txd_len); if (cmd != MCU_CMD(FW_SCATTER)) { q_idx = MT_TX_MCU_PORT_RX_Q0; pkt_fmt = MT_TX_TYPE_CMD; } else { q_idx = MT_TX_MCU_PORT_RX_FWDL; pkt_fmt = MT_TX_TYPE_FW; } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txd[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) | FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt); txd[1] = cpu_to_le32(val); if (cmd & __MCU_CMD_FIELD_UNI) { uni_txd = (struct mt7615_uni_txd *)txd; uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); uni_txd->option = MCU_CMD_UNI_EXT_ACK; uni_txd->cid = cpu_to_le16(mcu_cmd); uni_txd->s2d_index = MCU_S2D_H2N; uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; return; } mcu_txd = (struct mt7615_mcu_txd *)txd; mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx)); mcu_txd->s2d_index = MCU_S2D_H2N; mcu_txd->pkt_type = MCU_PKT_ID; mcu_txd->seq = seq; mcu_txd->cid = mcu_cmd; mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { if (cmd & __MCU_CMD_FIELD_QUERY) mcu_txd->set_query = MCU_Q_QUERY; else mcu_txd->set_query = MCU_Q_SET; mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; } else { mcu_txd->set_query = MCU_Q_NA; } } EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg); int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { struct mt7615_mcu_rxd *rxd; int ret = 0; if (!skb) { dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); return -ETIMEDOUT; } rxd = (struct mt7615_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)skb->data); } else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) { skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)&skb->data[8]); } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || cmd == MCU_UNI_CMD(STA_REC_UPDATE) || cmd == MCU_UNI_CMD(HIF_CTRL) || cmd == MCU_UNI_CMD(OFFLOAD) || cmd == MCU_UNI_CMD(SUSPEND)) { struct mt76_connac_mcu_uni_event *event; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); } else if (cmd == MCU_CE_QUERY(REG_READ)) { struct mt76_connac_mcu_reg_event *event; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_reg_event *)skb->data; ret = (int)le32_to_cpu(event->val); } return ret; } EXPORT_SYMBOL_GPL(mt7615_mcu_parse_response); static int mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *seq) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); enum mt76_mcuq_id qid; mt7615_mcu_fill_msg(dev, skb, cmd, seq); if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WM; else qid = MT_MCUQ_FWDL; return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0); } u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg) { struct { __le32 wifi_stream; __le32 address; __le32 data; } req = { .wifi_stream = cpu_to_le32(wf), .address = cpu_to_le32(reg), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS), &req, sizeof(req), true); } int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val) { struct { __le32 wifi_stream; __le32 address; __le32 data; } req = { .wifi_stream = cpu_to_le32(wf), .address = cpu_to_le32(reg), .data = cpu_to_le32(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS), &req, sizeof(req), false); } void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) { if (!is_mt7622(&dev->mt76)) return; #if defined(__linux__) regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC, MT_INFRACFG_MISC_AP2CONN_WAKE, !en * MT_INFRACFG_MISC_AP2CONN_WAKE); #elif defined(__FreeBSD__) panic("%s: LinuxKPI needs regmap\n", __func__); #endif } EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int); static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; struct mt76_dev *mdev = &dev->mt76; u32 addr; int err; if (is_mt7663(mdev)) { /* Clear firmware own via N9 eint */ mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN); mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000); addr = MT_CONN_HIF_ON_LPCTL; } else { addr = MT_CFG_LPCR_HOST; } mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); mt7622_trigger_hif_int(dev, true); err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000); mt7622_trigger_hif_int(dev, false); if (err) { dev_err(mdev->dev, "driver own failed\n"); return -ETIMEDOUT; } 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; return 0; } static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int i, err = 0; mutex_lock(&pm->mutex); if (!test_bit(MT76_STATE_PM, &mphy->state)) goto out; for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN); if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL, MT_CFG_LPCR_HOST_FW_OWN, 0, 50)) break; } if (i == MT7615_DRV_OWN_RETRY_COUNT) { 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: mutex_unlock(&pm->mutex); return err; } static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int err = 0; u32 addr; mutex_lock(&pm->mutex); if (mt76_connac_skip_fw_pmctrl(mphy, pm)) goto out; mt7622_trigger_hif_int(dev, true); addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); if (is_mt7622(&dev->mt76) && !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, MT_CFG_LPCR_HOST_FW_OWN, 3000)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); clear_bit(MT76_STATE_PM, &mphy->state); err = -EIO; } mt7622_trigger_hif_int(dev, false); if (!err) { pm->stats.last_doze_event = jiffies; pm->stats.awake_time += pm->stats.last_doze_event - pm->stats.last_wake_event; } out: mutex_unlock(&pm->mutex); return err; } static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (vif->bss_conf.csa_active) - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif, 0); } static void mt7615_mcu_rx_csa_notify(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_phy *ext_phy = mt7615_ext_phy(dev); struct mt76_phy *mphy = &dev->mt76.phy; struct mt7615_mcu_csa_notify *c; c = (struct mt7615_mcu_csa_notify *)skb->data; if (c->omac_idx > EXT_BSSID_MAX) return; if (ext_phy && ext_phy->omac_mask & BIT_ULL(c->omac_idx)) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_mcu_csa_finish, mphy->hw); } static void mt7615_mcu_rx_radar_detected(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7615_mcu_rdd_report *r; r = (struct mt7615_mcu_rdd_report *)skb->data; if (!dev->radar_pattern.n_pulses && !r->long_detected && !r->constant_prf_detected && !r->staggered_prf_detected) return; if (r->band_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (mt76_phy_dfs_state(mphy) < MT_DFS_STATE_CAC) return; - ieee80211_radar_detected(mphy->hw); + ieee80211_radar_detected(mphy->hw, NULL); dev->hw_pattern++; } static void mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; const char *data = (char *)&rxd[1]; const char *type; switch (rxd->s2d_index) { case 0: type = "N9"; break; case 2: type = "CR4"; break; default: type = "unknown"; break; } wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, (int)(skb->len - sizeof(*rxd)), data); } static void mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; switch (rxd->ext_eid) { case MCU_EXT_EVENT_RDD_REPORT: mt7615_mcu_rx_radar_detected(dev, skb); break; case MCU_EXT_EVENT_CSA_NOTIFY: mt7615_mcu_rx_csa_notify(dev, skb); break; case MCU_EXT_EVENT_FW_LOG_2_HOST: mt7615_mcu_rx_log_message(dev, skb); break; default: break; } } static void mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) { u8 *seq_num = skb->data + sizeof(struct mt7615_mcu_rxd); struct mt7615_phy *phy; struct mt76_phy *mphy; if (*seq_num & BIT(7) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); spin_unlock_bh(&dev->mt76.lock); ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, MT7615_HW_SCAN_TIMEOUT); } static void mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_roc_tlv *event; struct mt7615_phy *phy; struct mt76_phy *mphy; int duration; skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt7615_roc_tlv *)skb->data; if (event->dbdc_band && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; ieee80211_ready_on_channel(mphy->hw); - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; phy->roc_grant = true; wake_up(&phy->roc_wait); duration = le32_to_cpu(event->max_interval); mod_timer(&phy->roc_timer, round_jiffies_up(jiffies + msecs_to_jiffies(duration))); } static void mt7615_mcu_beacon_loss_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_connac_beacon_loss_event *event; struct mt76_phy *mphy; u8 band_idx = 0; /* DBDC support */ skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; if (band_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt76_connac_mcu_beacon_loss_iter, event); } static void mt7615_mcu_bss_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_connac_mcu_bss_event *event; struct mt76_phy *mphy; u8 band_idx = 0; /* DBDC support */ skb_pull(skb, sizeof(struct mt7615_mcu_rxd)); event = (struct mt76_connac_mcu_bss_event *)skb->data; if (band_idx && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; else mphy = &dev->mt76.phy; if (event->is_absent) ieee80211_stop_queues(mphy->hw); else ieee80211_wake_queues(mphy->hw); } static void mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_EXT: mt7615_mcu_rx_ext_event(dev, skb); break; case MCU_EVENT_BSS_BEACON_LOSS: mt7615_mcu_beacon_loss_event(dev, skb); break; case MCU_EVENT_ROC: mt7615_mcu_roc_event(dev, skb); break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: mt7615_mcu_scan_event(dev, skb); return; case MCU_EVENT_BSS_ABSENCE: mt7615_mcu_bss_event(dev, skb); break; case MCU_EVENT_COREDUMP: mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); return; default: break; } dev_kfree_skb(skb); } void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || rxd->eid == MCU_EVENT_BSS_ABSENCE || rxd->eid == MCU_EVENT_SCAN_DONE || rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_ROC || !rxd->seq) mt7615_mcu_rx_unsolicited_event(dev, skb); else mt76_mcu_rx_event(&dev->mt76, skb); } static int mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool bssid, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START; u32 mask = dev->omac_mask >> 32 & ~BIT(idx); const u8 *addr = vif->addr; struct { u8 mode; u8 force_clear; u8 clear_bitmap[8]; u8 entry_count; u8 write; u8 index; u8 bssid; u8 addr[ETH_ALEN]; } __packed req = { .mode = !!mask || enable, .entry_count = 1, .write = 1, .index = idx * 2 + bssid, }; if (bssid) addr = vif->bss_conf.bssid; if (enable) ether_addr_copy(req.addr, addr); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req, sizeof(req), true); } static int mt7615_mcu_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; struct { struct req_hdr { u8 omac_idx; u8 band_idx; __le16 tlv_num; u8 is_tlv_append; u8 rsv[3]; } __packed hdr; struct req_tlv { __le16 tag; __le16 len; u8 active; u8 band_idx; u8 omac_addr[ETH_ALEN]; } __packed tlv; } data = { .hdr = { .omac_idx = mvif->mt76.omac_idx, .band_idx = mvif->mt76.band_idx, .tlv_num = cpu_to_le16(1), .is_tlv_append = 1, }, .tlv = { .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, .band_idx = mvif->mt76.band_idx, }, }; if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) return mt7615_mcu_muar_config(dev, vif, false, enable); memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); } static int mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct req { u8 omac_idx; u8 enable; u8 wlan_idx; u8 band_idx; u8 pkt_type; u8 need_pre_tbtt_int; __le16 csa_ie_pos; __le16 pkt_len; __le16 tim_ie_pos; u8 pkt[512]; u8 csa_cnt; /* bss color change */ u8 bcc_cnt; __le16 bcc_ie_pos; } __packed req = { .omac_idx = mvif->mt76.omac_idx, .enable = enable, .wlan_idx = wcid->idx, .band_idx = mvif->mt76.band_idx, }; struct sk_buff *skb; if (!enable) goto out; skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!skb) return -EINVAL; if (skb->len > 512 - MT_TXD_SIZE) { dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); dev_kfree_skb(skb); return -EINVAL; } info = IEEE80211_SKB_CB(skb); info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mvif->mt76.band_idx); mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL, 0, NULL, 0, true); memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len); req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); if (offs.cntdwn_counter_offs[0]) { u16 csa_offs; csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; req.csa_ie_pos = cpu_to_le16(csa_offs); req.csa_cnt = skb->data[offs.cntdwn_counter_offs[0]]; } dev_kfree_skb(skb); out: return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(BCN_OFFLOAD), &req, sizeof(req), true); } static int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) { return mt76_connac_mcu_set_pm(&dev->mt76, band, state); } static int mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; struct sk_buff *skb; if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) mt7615_mcu_muar_config(dev, vif, true, enable); skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL); if (IS_ERR(skb)) return PTR_ERR(skb); if (enable) mt76_connac_mcu_bss_omac_tlv(skb, vif); mt76_connac_mcu_bss_basic_tlv(skb, vif, sta, phy->mt76, mvif->sta.wcid.idx, enable); if (enable && mvif->mt76.omac_idx >= EXT_BSSID_START && mvif->mt76.omac_idx < REPEATER_BSSID_START) mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(BSS_INFO_UPDATE), true); } static int mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; struct mt7615_vif *mvif = msta->vif; struct wtbl_req_hdr *wtbl_hdr; struct sk_buff *skb = NULL; int err; wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_SET, NULL, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, true, NULL, wtbl_hdr); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(WTBL_UPDATE), true); if (err < 0) return err; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); mt76_connac_mcu_sta_ba_tlv(skb, params, enable, true); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } static int mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; struct mt7615_vif *mvif = msta->vif; struct wtbl_req_hdr *wtbl_hdr; struct sk_buff *skb; int err; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); if (err < 0 || !enable) return err; skb = NULL; wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_SET, NULL, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false, NULL, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(WTBL_UPDATE), true); } static int mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct sk_buff *skb, *sskb, *wskb = NULL; + struct ieee80211_link_sta *link_sta; struct mt7615_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct mt7615_sta *msta; bool new_entry = true; + int conn_state; int cmd, err; msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; + link_sta = sta ? &sta->deflink : NULL; sskb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(sskb)) return PTR_ERR(sskb); if (!sta) { if (mvif->sta_added) new_entry = false; else mvif->sta_added = true; } - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable, - new_entry); + conn_state = enable ? CONN_STATE_PORT_SECURE : CONN_STATE_DISCONNECT; + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, &vif->bss_conf, + link_sta, conn_state, new_entry); if (enable && sta) mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0, MT76_STA_INFO_STATE_ASSOC); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_RESET_AND_SET, NULL, &wskb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); if (enable) { mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, wskb, vif, sta, NULL, wtbl_hdr); if (sta) mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, wskb, sta, NULL, wtbl_hdr, true, true); mt76_connac_mcu_wtbl_hdr_trans_tlv(wskb, vif, &msta->wcid, NULL, wtbl_hdr); } cmd = enable ? MCU_EXT_CMD(WTBL_UPDATE) : MCU_EXT_CMD(STA_REC_UPDATE); skb = enable ? wskb : sskb; err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); if (err < 0) { skb = enable ? sskb : wskb; dev_kfree_skb(skb); return err; } cmd = enable ? MCU_EXT_CMD(STA_REC_UPDATE) : MCU_EXT_CMD(WTBL_UPDATE); skb = enable ? sskb : wskb; return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); } static int mt7615_mcu_wtbl_update_hdr_trans(struct mt7615_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { return mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } static const struct mt7615_mcu_ops wtbl_update_ops = { .add_beacon_offload = mt7615_mcu_add_beacon_offload, .set_pm_state = mt7615_mcu_ctrl_pm_state, .add_dev_info = mt7615_mcu_add_dev, .add_bss_info = mt7615_mcu_add_bss, .add_tx_ba = mt7615_mcu_wtbl_tx_ba, .add_rx_ba = mt7615_mcu_wtbl_rx_ba, .sta_add = mt7615_mcu_wtbl_sta_add, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, .set_sta_decap_offload = mt7615_mcu_wtbl_update_hdr_trans, }; static int mt7615_mcu_sta_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable, bool tx) { struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; struct mt7615_vif *mvif = msta->vif; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_SET, sta_wtbl, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, tx, sta_wtbl, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } static int mt7615_mcu_sta_tx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { return mt7615_mcu_sta_ba(dev, params, enable, true); } static int mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { return mt7615_mcu_sta_ba(dev, params, enable, false); } static int __mt7615_mcu_add_sta(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable, int cmd, bool offload_fw) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, .offload_fw = offload_fw, .enable = enable, .newly = true, .cmd = cmd, }; info.wcid = sta ? (struct mt76_wcid *)sta->drv_priv : &mvif->sta.wcid; return mt76_connac_mcu_sta_cmd(phy, &info); } static int mt7615_mcu_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, MCU_EXT_CMD(STA_REC_UPDATE), false); } static int mt7615_mcu_sta_update_hdr_trans(struct mt7615_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, MCU_EXT_CMD(STA_REC_UPDATE)); } static const struct mt7615_mcu_ops sta_update_ops = { .add_beacon_offload = mt7615_mcu_add_beacon_offload, .set_pm_state = mt7615_mcu_ctrl_pm_state, .add_dev_info = mt7615_mcu_add_dev, .add_bss_info = mt7615_mcu_add_bss, .add_tx_ba = mt7615_mcu_sta_tx_ba, .add_rx_ba = mt7615_mcu_sta_rx_ba, .sta_add = mt7615_mcu_add_sta, .set_drv_ctrl = mt7615_mcu_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, .set_sta_decap_offload = mt7615_mcu_sta_update_hdr_trans, }; static int mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state) { return 0; } static int mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct ieee80211_mutable_offsets offs; struct { struct req_hdr { u8 bss_idx; u8 pad[3]; } __packed hdr; struct bcn_content_tlv { __le16 tag; __le16 len; __le16 tim_ie_pos; __le16 csa_ie_pos; __le16 bcc_ie_pos; /* 0: disable beacon offload * 1: enable beacon offload * 2: update probe respond offload */ u8 enable; /* 0: legacy format (TXD + payload) * 1: only cap field IE */ u8 type; __le16 pkt_len; u8 pkt[512]; } __packed beacon_tlv; } req = { .hdr = { .bss_idx = mvif->mt76.idx, }, .beacon_tlv = { .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), .len = cpu_to_le16(sizeof(struct bcn_content_tlv)), .enable = enable, }, }; struct sk_buff *skb; if (!enable) goto out; skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; if (skb->len > 512 - MT_TXD_SIZE) { dev_err(dev->mt76.dev, "beacon size limit exceed\n"); dev_kfree_skb(skb); return -EINVAL; } mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb, wcid, NULL, 0, NULL, 0, true); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); if (offs.cntdwn_counter_offs[0]) { u16 csa_offs; csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs); } dev_kfree_skb(skb); out: return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), &req, sizeof(req), true); } static int mt7615_mcu_uni_add_dev(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - return mt76_connac_mcu_uni_add_dev(phy->mt76, vif, &mvif->sta.wcid, - enable); + return mt76_connac_mcu_uni_add_dev(phy->mt76, &vif->bss_conf, &mvif->mt76, + &mvif->sta.wcid, enable); } static int mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; return mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, enable, NULL); } static inline int mt7615_mcu_uni_add_sta(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { return __mt7615_mcu_add_sta(phy->mt76, vif, sta, enable, MCU_UNI_CMD(STA_REC_UPDATE), true); } static int mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7615_sta *sta = (struct mt7615_sta *)params->sta->drv_priv; return mt76_connac_mcu_sta_ba(&dev->mt76, &sta->vif->mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), enable, true); } static int mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv; struct mt7615_vif *mvif = msta->vif; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; int err; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); mt76_connac_mcu_sta_ba_tlv(skb, params, enable, false); err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(STA_REC_UPDATE), true); if (err < 0 || !enable) return err; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->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->mt76, &msta->wcid, WTBL_SET, sta_wtbl, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_ba_tlv(&dev->mt76, skb, params, enable, false, sta_wtbl, wtbl_hdr); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(STA_REC_UPDATE), true); } static int mt7615_mcu_sta_uni_update_hdr_trans(struct mt7615_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; return mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, MCU_UNI_CMD(STA_REC_UPDATE)); } static const struct mt7615_mcu_ops uni_update_ops = { .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload, .set_pm_state = mt7615_mcu_uni_ctrl_pm_state, .add_dev_info = mt7615_mcu_uni_add_dev, .add_bss_info = mt7615_mcu_uni_add_bss, .add_tx_ba = mt7615_mcu_uni_tx_ba, .add_rx_ba = mt7615_mcu_uni_rx_ba, .sta_add = mt7615_mcu_uni_add_sta, .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl, .set_fw_ctrl = mt7615_mcu_fw_pmctrl, .set_sta_decap_offload = mt7615_mcu_sta_uni_update_hdr_trans, }; int mt7615_mcu_restart(struct mt76_dev *dev) { return mt76_mcu_send_msg(dev, MCU_CMD(RESTART_DL_REQ), NULL, 0, true); } EXPORT_SYMBOL_GPL(mt7615_mcu_restart); static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name) { const struct mt7615_patch_hdr *hdr; const struct firmware *fw = NULL; int len, ret, sem; ret = firmware_request_nowarn(&fw, name, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto release_fw; } sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true); switch (sem) { case PATCH_IS_DL: goto release_fw; case PATCH_NOT_DL_SEM_SUCCESS: break; default: dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); ret = -EAGAIN; goto release_fw; } hdr = (const struct mt7615_patch_hdr *)(fw->data); dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); len = fw->size - sizeof(*hdr); ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, DL_MODE_NEED_RSP); if (ret) { dev_err(dev->mt76.dev, "Download request failed\n"); goto out; } ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), fw->data + sizeof(*hdr), len); if (ret) { dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); goto out; } ret = mt76_connac_mcu_start_patch(&dev->mt76); if (ret) dev_err(dev->mt76.dev, "Failed to start patch\n"); out: sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); switch (sem) { case PATCH_REL_SEM_SUCCESS: break; default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); break; } release_fw: release_firmware(fw); return ret; } static int mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, const struct mt7615_fw_trailer *hdr, const u8 *data, bool is_cr4) { int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM; int err, i, offset = 0; u32 len, addr, mode; for (i = 0; i < n_region; i++) { mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, hdr[i].feature_set, is_cr4); len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; addr = le32_to_cpu(hdr[i].addr); err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, mode); if (err) { dev_err(dev->mt76.dev, "Download request failed\n"); return err; } err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), data + offset, len); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); return err; } offset += len; } return 0; } static int mt7615_load_n9(struct mt7615_dev *dev, const char *name) { const struct mt7615_fw_trailer *hdr; const struct firmware *fw; int ret; ret = request_firmware(&fw, name, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - N9_REGION_NUM * sizeof(*hdr)); dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false); if (ret) goto out; ret = mt76_connac_mcu_start_firmware(&dev->mt76, le32_to_cpu(hdr->addr), FW_START_OVERRIDE); if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); goto out; } snprintf(dev->mt76.hw->wiphy->fw_version, sizeof(dev->mt76.hw->wiphy->fw_version), "%.10s-%.15s", hdr->fw_ver, hdr->build_date); if (!is_mt7615(&dev->mt76)) { dev->fw_ver = MT7615_FIRMWARE_V2; dev->mcu_ops = &sta_update_ops; } else { dev->fw_ver = MT7615_FIRMWARE_V1; dev->mcu_ops = &wtbl_update_ops; } out: release_firmware(fw); return ret; } static int mt7615_load_cr4(struct mt7615_dev *dev, const char *name) { const struct mt7615_fw_trailer *hdr; const struct firmware *fw; int ret; ret = request_firmware(&fw, name, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size - CR4_REGION_NUM * sizeof(*hdr)); dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true); if (ret) goto out; ret = mt76_connac_mcu_start_firmware(&dev->mt76, 0, FW_START_WORKING_PDA_CR4); if (ret) { dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n"); goto out; } out: release_firmware(fw); return ret; } static int mt7615_load_ram(struct mt7615_dev *dev) { int ret; ret = mt7615_load_n9(dev, MT7615_FIRMWARE_N9); if (ret) return ret; return mt7615_load_cr4(dev, MT7615_FIRMWARE_CR4); } static int mt7615_load_firmware(struct mt7615_dev *dev) { int ret; u32 val; val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE); if (val != FW_STATE_FW_DOWNLOAD) { dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); return -EIO; } ret = mt7615_load_patch(dev, MT7615_PATCH_ADDRESS, MT7615_ROM_PATCH); if (ret) return ret; ret = mt7615_load_ram(dev); if (ret) return ret; if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE, FIELD_PREP(MT_TOP_MISC2_FW_STATE, FW_STATE_RDY), 500)) { dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } return 0; } static int mt7622_load_firmware(struct mt7615_dev *dev) { int ret; u32 val; mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); val = mt76_get_field(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE); if (val != FW_STATE_FW_DOWNLOAD) { dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); return -EIO; } ret = mt7615_load_patch(dev, MT7622_PATCH_ADDRESS, MT7622_ROM_PATCH); if (ret) return ret; ret = mt7615_load_n9(dev, MT7622_FIRMWARE_N9); if (ret) return ret; if (!mt76_poll_msec(dev, MT_TOP_OFF_RSV, MT_TOP_OFF_RSV_FW_STATE, FIELD_PREP(MT_TOP_OFF_RSV_FW_STATE, FW_STATE_NORMAL_TRX), 1500)) { dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); return 0; } int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl) { struct { u8 ctrl_val; u8 pad[3]; } data = { .ctrl_val = ctrl }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data, sizeof(data), true); } static int mt7615_mcu_cal_cache_apply(struct mt7615_dev *dev) { struct { bool cache_enable; u8 pad[3]; } data = { .cache_enable = true }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(CAL_CACHE), &data, sizeof(data), false); } static int mt7663_load_n9(struct mt7615_dev *dev, const char *name) { u32 offset = 0, override_addr = 0, flag = FW_START_DLYCAL; const struct mt76_connac2_fw_trailer *hdr; const struct mt7663_fw_buf *buf; const struct firmware *fw; const u8 *base_addr; int i, ret; ret = request_firmware(&fw, name, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)(fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE); dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region); base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE; for (i = 0; i < hdr->n_region; i++) { u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE; u32 len, addr, mode; dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i); buf = (const struct mt7663_fw_buf *)(base_addr - shift); mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, buf->feature_set, false); addr = le32_to_cpu(buf->img_dest_addr); len = le32_to_cpu(buf->img_size); ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 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), fw->data + offset, len); if (ret) { dev_err(dev->mt76.dev, "Failed to send firmware\n"); goto out; } offset += le32_to_cpu(buf->img_size); if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) { override_addr = le32_to_cpu(buf->img_dest_addr); dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n", i, override_addr); } } if (override_addr) flag |= FW_START_OVERRIDE; dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n", override_addr, flag); ret = mt76_connac_mcu_start_firmware(&dev->mt76, override_addr, flag); if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); goto out; } snprintf(dev->mt76.hw->wiphy->fw_version, sizeof(dev->mt76.hw->wiphy->fw_version), "%.10s-%.15s", hdr->fw_ver, hdr->build_date); out: release_firmware(fw); return ret; } static int mt7663_load_rom_patch(struct mt7615_dev *dev, const char **n9_firmware) { const char *selected_rom, *secondary_rom = MT7663_ROM_PATCH; const char *primary_rom = MT7663_OFFLOAD_ROM_PATCH; int ret; if (!prefer_offload_fw) { secondary_rom = MT7663_OFFLOAD_ROM_PATCH; primary_rom = MT7663_ROM_PATCH; } selected_rom = primary_rom; ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, primary_rom); if (ret) { dev_info(dev->mt76.dev, "%s not found, switching to %s", primary_rom, secondary_rom); ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, secondary_rom); if (ret) { dev_err(dev->mt76.dev, "failed to load %s", secondary_rom); return ret; } selected_rom = secondary_rom; } if (!strcmp(selected_rom, MT7663_OFFLOAD_ROM_PATCH)) { *n9_firmware = MT7663_OFFLOAD_FIRMWARE_N9; dev->fw_ver = MT7615_FIRMWARE_V3; dev->mcu_ops = &uni_update_ops; } else { *n9_firmware = MT7663_FIRMWARE_N9; dev->fw_ver = MT7615_FIRMWARE_V2; dev->mcu_ops = &sta_update_ops; } return 0; } int __mt7663_load_firmware(struct mt7615_dev *dev) { const char *n9_firmware; int ret; ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); if (ret) { dev_dbg(dev->mt76.dev, "Firmware is already download\n"); return -EIO; } ret = mt7663_load_rom_patch(dev, &n9_firmware); if (ret) return ret; ret = mt7663_load_n9(dev, n9_firmware); if (ret) return ret; if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, MT_TOP_MISC2_FW_N9_RDY, 1500)) { ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT7663_TOP_MISC2_FW_STATE); dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } #ifdef CONFIG_PM if (mt7615_firmware_offload(dev)) dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; #endif /* CONFIG_PM */ dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; } EXPORT_SYMBOL_GPL(__mt7663_load_firmware); static int mt7663_load_firmware(struct mt7615_dev *dev) { int ret; mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); ret = __mt7663_load_firmware(dev); if (ret) return ret; mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH); return 0; } int mt7615_mcu_init(struct mt7615_dev *dev) { static const struct mt76_mcu_ops mt7615_mcu_ops = { .headroom = sizeof(struct mt7615_mcu_txd), .mcu_skb_send_msg = mt7615_mcu_send_message, .mcu_parse_response = mt7615_mcu_parse_response, }; int ret; - dev->mt76.mcu_ops = &mt7615_mcu_ops, + dev->mt76.mcu_ops = &mt7615_mcu_ops; ret = mt7615_mcu_drv_pmctrl(dev); if (ret) return ret; switch (mt76_chip(&dev->mt76)) { case 0x7622: ret = mt7622_load_firmware(dev); break; case 0x7663: ret = mt7663_load_firmware(dev); break; default: ret = mt7615_load_firmware(dev); break; } if (ret) return ret; mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); dev_dbg(dev->mt76.dev, "Firmware init done\n"); set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); if (dev->dbdc_support) { ret = mt7615_mcu_cal_cache_apply(dev); if (ret) return ret; } return mt7615_mcu_fw_log_2_host(dev, 0); } EXPORT_SYMBOL_GPL(mt7615_mcu_init); void mt7615_mcu_exit(struct mt7615_dev *dev) { mt7615_mcu_restart(&dev->mt76); mt7615_mcu_set_fw_ctrl(dev); skb_queue_purge(&dev->mt76.mcu.res_q); } EXPORT_SYMBOL_GPL(mt7615_mcu_exit); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev) { struct { u8 buffer_mode; u8 content_format; __le16 len; } __packed req_hdr = { .buffer_mode = 1, }; u8 *eep = (u8 *)dev->mt76.eeprom.data; struct sk_buff *skb; int eep_len, offset; switch (mt76_chip(&dev->mt76)) { case 0x7622: eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0; offset = MT_EE_NIC_CONF_0; break; case 0x7663: eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID; req_hdr.content_format = 1; offset = MT_EE_CHIP_ID; break; default: eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0; offset = MT_EE_NIC_CONF_0; break; } req_hdr.len = cpu_to_le16(eep_len); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + eep_len); if (!skb) return -ENOMEM; skb_put_data(skb, &req_hdr, sizeof(req_hdr)); skb_put_data(skb, eep + offset, eep_len); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(EFUSE_BUFFER_MODE), true); } int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, const struct ieee80211_tx_queue_params *params) { #define WMM_AIFS_SET BIT(0) #define WMM_CW_MIN_SET BIT(1) #define WMM_CW_MAX_SET BIT(2) #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ WMM_CW_MAX_SET | WMM_TXOP_SET) struct req_data { u8 number; u8 rsv[3]; u8 queue; u8 valid; u8 aifs; u8 cw_min; __le16 cw_max; __le16 txop; } __packed req = { .number = 1, .queue = queue, .valid = WMM_PARAM_SET, .aifs = params->aifs, .cw_min = 5, .cw_max = cpu_to_le16(10), .txop = cpu_to_le16(params->txop), }; if (params->cw_min) req.cw_min = fls(params->cw_min); if (params->cw_max) req.cw_max = cpu_to_le16(fls(params->cw_max)); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), &req, sizeof(req), true); } int mt7615_mcu_set_dbdc(struct mt7615_dev *dev) { struct mt7615_phy *ext_phy = mt7615_ext_phy(dev); struct dbdc_entry { u8 type; u8 index; u8 band; u8 _rsv; }; struct { u8 enable; u8 num; u8 _rsv[2]; struct dbdc_entry entry[64]; } req = { .enable = !!ext_phy, }; int i; if (!ext_phy) goto out; #define ADD_DBDC_ENTRY(_type, _idx, _band) \ do { \ req.entry[req.num].type = _type; \ req.entry[req.num].index = _idx; \ req.entry[req.num++].band = _band; \ } while (0) for (i = 0; i < 4; i++) { bool band = !!(ext_phy->omac_mask & BIT_ULL(i)); ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band); } for (i = 0; i < 14; i++) { bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i)); ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band); } ADD_DBDC_ENTRY(DBDC_TYPE_MU, 0, 1); for (i = 0; i < 3; i++) ADD_DBDC_ENTRY(DBDC_TYPE_BF, i, 1); ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 0, 0); ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 1, 0); ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 2, 1); ADD_DBDC_ENTRY(DBDC_TYPE_WMM, 3, 1); ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 0, 0); ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1); out: return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DBDC_CTRL), &req, sizeof(req), true); } -int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev) -{ - struct wtbl_req_hdr req = { - .operation = WTBL_RESET_ALL, - }; - - return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WTBL_UPDATE), - &req, sizeof(req), true); -} - int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val) { struct { __le16 tag; __le16 min_lpn; } req = { .tag = cpu_to_le16(0x1), .min_lpn = cpu_to_le16(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH), &req, sizeof(req), true); } int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, const struct mt7615_dfs_pulse *pulse) { struct { __le16 tag; __le32 max_width; /* us */ __le32 max_pwr; /* dbm */ __le32 min_pwr; /* dbm */ __le32 min_stgr_pri; /* us */ __le32 max_stgr_pri; /* us */ __le32 min_cr_pri; /* us */ __le32 max_cr_pri; /* us */ } req = { .tag = cpu_to_le16(0x3), #define __req_field(field) .field = cpu_to_le32(pulse->field) __req_field(max_width), __req_field(max_pwr), __req_field(min_pwr), __req_field(min_stgr_pri), __req_field(max_stgr_pri), __req_field(min_cr_pri), __req_field(max_cr_pri), #undef __req_field }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH), &req, sizeof(req), true); } int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern) { struct { __le16 tag; __le16 radar_type; u8 enb; u8 stgr; u8 min_crpn; u8 max_crpn; u8 min_crpr; u8 min_pw; u8 max_pw; __le32 min_pri; __le32 max_pri; u8 min_crbn; u8 max_crbn; u8 min_stgpn; u8 max_stgpn; u8 min_stgpr; } req = { .tag = cpu_to_le16(0x2), .radar_type = cpu_to_le16(index), #define __req_field_u8(field) .field = pattern->field #define __req_field_u32(field) .field = cpu_to_le32(pattern->field) __req_field_u8(enb), __req_field_u8(stgr), __req_field_u8(min_crpn), __req_field_u8(max_crpn), __req_field_u8(min_crpr), __req_field_u8(min_pw), __req_field_u8(max_pw), __req_field_u32(min_pri), __req_field_u32(max_pri), __req_field_u8(min_crbn), __req_field_u8(max_crbn), __req_field_u8(min_stgpn), __req_field_u8(max_stgpn), __req_field_u8(min_stgpr), #undef __req_field_u8 #undef __req_field_u32 }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RADAR_TH), &req, sizeof(req), true); } int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev) { struct { u8 pulse_num; u8 rsv[3]; struct { __le32 start_time; __le16 width; __le16 power; } pattern[32]; } req = { .pulse_num = dev->radar_pattern.n_pulses, }; u32 start_time = ktime_to_ms(ktime_get_boottime()); int i; if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern)) return -EINVAL; /* TODO: add some noise here */ for (i = 0; i < dev->radar_pattern.n_pulses; i++) { u32 ts = start_time + i * dev->radar_pattern.period; req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width); req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power); req.pattern[i].start_time = cpu_to_le32(ts); } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_PATTERN), &req, sizeof(req), false); } static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku) { struct mt76_phy *mphy = phy->mt76; struct ieee80211_hw *hw = mphy->hw; struct mt76_power_limits limits; s8 *limits_array = (s8 *)&limits; int n_chains = hweight8(mphy->antenna_mask); int tx_power = hw->conf.power_level * 2; int i; static const u8 sku_mapping[] = { #define SKU_FIELD(_type, _field) \ [MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field) SKU_FIELD(CCK_1_2, cck[0]), SKU_FIELD(CCK_55_11, cck[2]), SKU_FIELD(OFDM_6_9, ofdm[0]), SKU_FIELD(OFDM_12_18, ofdm[2]), SKU_FIELD(OFDM_24_36, ofdm[4]), SKU_FIELD(OFDM_48, ofdm[6]), SKU_FIELD(OFDM_54, ofdm[7]), SKU_FIELD(HT20_0_8, mcs[0][0]), SKU_FIELD(HT20_32, ofdm[0]), SKU_FIELD(HT20_1_2_9_10, mcs[0][1]), SKU_FIELD(HT20_3_4_11_12, mcs[0][3]), SKU_FIELD(HT20_5_13, mcs[0][5]), SKU_FIELD(HT20_6_14, mcs[0][6]), SKU_FIELD(HT20_7_15, mcs[0][7]), SKU_FIELD(HT40_0_8, mcs[1][0]), SKU_FIELD(HT40_32, ofdm[0]), SKU_FIELD(HT40_1_2_9_10, mcs[1][1]), SKU_FIELD(HT40_3_4_11_12, mcs[1][3]), SKU_FIELD(HT40_5_13, mcs[1][5]), SKU_FIELD(HT40_6_14, mcs[1][6]), SKU_FIELD(HT40_7_15, mcs[1][7]), SKU_FIELD(VHT20_0, mcs[0][0]), SKU_FIELD(VHT20_1_2, mcs[0][1]), SKU_FIELD(VHT20_3_4, mcs[0][3]), SKU_FIELD(VHT20_5_6, mcs[0][5]), SKU_FIELD(VHT20_7, mcs[0][7]), SKU_FIELD(VHT20_8, mcs[0][8]), SKU_FIELD(VHT20_9, mcs[0][9]), SKU_FIELD(VHT40_0, mcs[1][0]), SKU_FIELD(VHT40_1_2, mcs[1][1]), SKU_FIELD(VHT40_3_4, mcs[1][3]), SKU_FIELD(VHT40_5_6, mcs[1][5]), SKU_FIELD(VHT40_7, mcs[1][7]), SKU_FIELD(VHT40_8, mcs[1][8]), SKU_FIELD(VHT40_9, mcs[1][9]), SKU_FIELD(VHT80_0, mcs[2][0]), SKU_FIELD(VHT80_1_2, mcs[2][1]), SKU_FIELD(VHT80_3_4, mcs[2][3]), SKU_FIELD(VHT80_5_6, mcs[2][5]), SKU_FIELD(VHT80_7, mcs[2][7]), SKU_FIELD(VHT80_8, mcs[2][8]), SKU_FIELD(VHT80_9, mcs[2][9]), SKU_FIELD(VHT160_0, mcs[3][0]), SKU_FIELD(VHT160_1_2, mcs[3][1]), SKU_FIELD(VHT160_3_4, mcs[3][3]), SKU_FIELD(VHT160_5_6, mcs[3][5]), SKU_FIELD(VHT160_7, mcs[3][7]), SKU_FIELD(VHT160_8, mcs[3][8]), SKU_FIELD(VHT160_9, mcs[3][9]), #undef SKU_FIELD }; tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power); tx_power -= mt76_tx_power_nss_delta(n_chains); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits, tx_power); mphy->txpower_cur = tx_power; if (is_mt7663(mphy->dev)) { memset(sku, tx_power, MT_SKU_4SS_DELTA + 1); return; } for (i = 0; i < MT_SKU_1SS_DELTA; i++) sku[i] = limits_array[sku_mapping[i]]; for (i = 0; i < 4; i++) { int delta = 0; if (i < n_chains - 1) delta = mt76_tx_power_nss_delta(n_chains) - mt76_tx_power_nss_delta(i + 1); sku[MT_SKU_1SS_DELTA + i] = delta; } } static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef) { static const u8 width_to_bw[] = { [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, }; if (chandef->width >= ARRAY_SIZE(width_to_bw)) return 0; return width_to_bw[chandef->width]; } int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) { struct mt7615_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; struct { u8 control_chan; u8 center_chan; u8 bw; u8 tx_streams; u8 rx_streams_mask; u8 switch_reason; u8 band_idx; /* for 80+80 only */ u8 center_chan2; __le16 cac_case; u8 channel_band; u8 rsv0; __le32 outband_freq; u8 txpower_drop; u8 rsv1[3]; u8 txpower_sku[53]; u8 rsv2[3]; } req = { .control_chan = chandef->chan->hw_value, .center_chan = ieee80211_frequency_to_channel(freq1), .tx_streams = hweight8(phy->mt76->antenna_mask), .rx_streams_mask = phy->mt76->chainmask, .center_chan2 = ieee80211_frequency_to_channel(freq2), }; if (cmd == MCU_EXT_CMD(SET_RX_PATH) || - dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) + phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; - else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + else if (phy->mt76->offchannel) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, NL80211_IFTYPE_AP)) req.switch_reason = CH_SWITCH_DFS; else req.switch_reason = CH_SWITCH_NORMAL; req.band_idx = phy != &dev->phy; req.bw = mt7615_mcu_chan_bw(chandef); if (mt76_testmode_enabled(phy->mt76)) memset(req.txpower_sku, 0x3f, 49); else mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } int mt7615_mcu_get_temperature(struct mt7615_dev *dev) { struct { u8 action; u8 rsv[3]; } req = {}; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, sizeof(req), true); } int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, u32 val) { struct { u8 test_mode_en; u8 param_idx; u8 _rsv[2]; __le32 value; u8 pad[8]; } req = { .test_mode_en = test_mode, .param_idx = param, .value = cpu_to_le32(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) { struct mt7615_dev *dev = phy->dev; struct { u8 format_id; u8 sku_enable; u8 band_idx; u8 rsv; } req = { .format_id = 0, .band_idx = phy != &dev->phy, .sku_enable = enable, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) { int i; for (i = 0; i < n_freqs; i++) if (cur == freqs[i]) return i; return -1; } static int mt7615_dcoc_freq_idx(u16 freq, u8 bw) { static const u16 freq_list[] = { 4980, 5805, 5905, 5190, 5230, 5270, 5310, 5350, 5390, 5430, 5470, 5510, 5550, 5590, 5630, 5670, 5710, 5755, 5795, 5835, 5875, 5210, 5290, 5370, 5450, 5530, 5610, 5690, 5775, 5855 }; static const u16 freq_bw40[] = { 5190, 5230, 5270, 5310, 5350, 5390, 5430, 5470, 5510, 5550, 5590, 5630, 5670, 5710, 5755, 5795, 5835, 5875 }; int offset_2g = ARRAY_SIZE(freq_list); int idx; if (freq < 4000) { if (freq < 2427) return offset_2g; if (freq < 2442) return offset_2g + 1; if (freq < 2457) return offset_2g + 2; return offset_2g + 3; } switch (bw) { case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: break; default: idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), freq + 10); if (idx >= 0) { freq = freq_bw40[idx]; break; } idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), freq - 10); if (idx >= 0) { freq = freq_bw40[idx]; break; } fallthrough; case NL80211_CHAN_WIDTH_40: idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40), freq); if (idx >= 0) break; return -1; } return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); } int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq2 = chandef->center_freq2; int ret; struct { u8 direction; u8 runtime_calibration; u8 _rsv[2]; __le16 center_freq; u8 bw; u8 band; u8 is_freq2; u8 success; u8 dbdc_en; u8 _rsv2; struct { __le32 sx0_i_lna[4]; __le32 sx0_q_lna[4]; __le32 sx2_i_lna[4]; __le32 sx2_q_lna[4]; } dcoc_data[4]; } req = { .direction = 1, .bw = mt7615_mcu_chan_bw(chandef), .band = chandef->center_freq1 > 4000, .dbdc_en = !!dev->mt76.phys[MT_BAND1], }; u16 center_freq = chandef->center_freq1; int freq_idx; u8 *eep = dev->mt76.eeprom.data; if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL)) return 0; if (chandef->width == NL80211_CHAN_WIDTH_160) { freq2 = center_freq + 40; center_freq -= 40; } again: req.runtime_calibration = 1; freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width); if (freq_idx < 0) goto out; memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET + freq_idx * MT7615_EEPROM_DCOC_SIZE, sizeof(req.dcoc_data)); req.runtime_calibration = 0; out: req.center_freq = cpu_to_le16(center_freq); ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RXDCOC_CAL), &req, sizeof(req), true); if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { req.is_freq2 = true; center_freq = freq2; goto again; } return ret; } static int mt7615_dpd_freq_idx(u16 freq, u8 bw) { static const u16 freq_list[] = { 4920, 4940, 4960, 4980, 5040, 5060, 5080, 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5340, 5360, 5380, 5400, 5420, 5440, 5460, 5480, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5720, 5745, 5765, 5785, 5805, 5825, 5845, 5865, 5885, 5905 }; int offset_2g = ARRAY_SIZE(freq_list); int idx; if (freq < 4000) { if (freq < 2432) return offset_2g; if (freq < 2457) return offset_2g + 1; return offset_2g + 2; } if (bw != NL80211_CHAN_WIDTH_20) { idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq + 10); if (idx >= 0) return idx; idx = mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq - 10); if (idx >= 0) return idx; } return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); } int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq2 = chandef->center_freq2; int ret; struct { u8 direction; u8 runtime_calibration; u8 _rsv[2]; __le16 center_freq; u8 bw; u8 band; u8 is_freq2; u8 success; u8 dbdc_en; u8 _rsv2; struct { struct { u32 dpd_g0; u8 data[32]; } wf0, wf1; struct { u32 dpd_g0_prim; u32 dpd_g0_sec; u8 data_prim[32]; u8 data_sec[32]; } wf2, wf3; } dpd_data; } req = { .direction = 1, .bw = mt7615_mcu_chan_bw(chandef), .band = chandef->center_freq1 > 4000, .dbdc_en = !!dev->mt76.phys[MT_BAND1], }; u16 center_freq = chandef->center_freq1; int freq_idx; u8 *eep = dev->mt76.eeprom.data; if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_TX_DPD)) return 0; if (chandef->width == NL80211_CHAN_WIDTH_160) { freq2 = center_freq + 40; center_freq -= 40; } again: req.runtime_calibration = 1; freq_idx = mt7615_dpd_freq_idx(center_freq, chandef->width); if (freq_idx < 0) goto out; memcpy(&req.dpd_data, eep + MT7615_EEPROM_TXDPD_OFFSET + freq_idx * MT7615_EEPROM_TXDPD_SIZE, sizeof(req.dpd_data)); req.runtime_calibration = 0; out: req.center_freq = cpu_to_le16(center_freq); ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXDPD_CAL), &req, sizeof(req), true); if ((chandef->width == NL80211_CHAN_WIDTH_80P80 || chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) { req.is_freq2 = true; center_freq = freq2; goto again; } return ret; } int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev) { struct { u8 operation; u8 count; u8 _rsv[2]; u8 index; u8 enable; __le16 etype; } req = { .operation = 1, .count = 1, .enable = 1, .etype = cpu_to_le16(ETH_P_PAE), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), &req, sizeof(req), false); } int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct { u8 bss_idx; u8 dtim_period; __le16 aid; __le16 bcn_interval; __le16 atim_window; u8 uapsd; u8 bmc_delivered_ac; u8 bmc_triggered_ac; u8 pad; } req = { .bss_idx = mvif->mt76.idx, .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; struct { u8 bss_idx; u8 pad[3]; } req_hdr = { .bss_idx = mvif->mt76.idx, }; int err; if (vif->type != NL80211_IFTYPE_STATION) return 0; err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT), &req_hdr, sizeof(req_hdr), false); if (err < 0 || !enable) return err; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED), &req, sizeof(req), false); } int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = phy->dev; struct mt7615_roc_tlv req = { .bss_idx = mvif->mt76.idx, .active = !chan, .max_interval = cpu_to_le32(duration), .primary_chan = chan ? chan->hw_value : 0, .band = chan ? chan->band : 0, .req_type = 2, }; phy->roc_grant = false; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), &req, sizeof(req), false); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/mmio.c b/sys/contrib/dev/mediatek/mt76/mt7615/mmio.c index ac036a072439..dbb2c82407df 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/mmio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/mmio.c @@ -1,273 +1,275 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include "mt7615.h" #include "regs.h" #include "mac.h" #include "../trace.h" const u32 mt7615e_reg_map[] = { [MT_TOP_CFG_BASE] = 0x01000, [MT_HW_BASE] = 0x01000, [MT_PCIE_REMAP_2] = 0x02504, [MT_ARB_BASE] = 0x20c00, [MT_HIF_BASE] = 0x04000, [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, [MT_CFG_BASE] = 0x20200, [MT_AGG_BASE] = 0x20a00, [MT_TMAC_BASE] = 0x21000, [MT_RMAC_BASE] = 0x21200, [MT_DMA_BASE] = 0x21800, [MT_PF_BASE] = 0x22000, [MT_WTBL_BASE_ON] = 0x23000, [MT_WTBL_BASE_OFF] = 0x23400, [MT_LPON_BASE] = 0x24200, [MT_MIB_BASE] = 0x24800, [MT_WTBL_BASE_ADDR] = 0x30000, [MT_PCIE_REMAP_BASE2] = 0x80000, [MT_TOP_MISC_BASE] = 0xc0000, [MT_EFUSE_ADDR_BASE] = 0x81070000, }; const u32 mt7663e_reg_map[] = { [MT_TOP_CFG_BASE] = 0x01000, [MT_HW_BASE] = 0x02000, [MT_DMA_SHDL_BASE] = 0x06000, [MT_PCIE_REMAP_2] = 0x0700c, [MT_ARB_BASE] = 0x20c00, [MT_HIF_BASE] = 0x04000, [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, [MT_PP_BASE] = 0x0e000, [MT_CFG_BASE] = 0x20000, [MT_AGG_BASE] = 0x22000, [MT_TMAC_BASE] = 0x24000, [MT_RMAC_BASE] = 0x25000, [MT_DMA_BASE] = 0x27000, [MT_PF_BASE] = 0x28000, [MT_WTBL_BASE_ON] = 0x29000, [MT_WTBL_BASE_OFF] = 0x29800, [MT_LPON_BASE] = 0x2b000, [MT_MIB_BASE] = 0x2d000, [MT_WTBL_BASE_ADDR] = 0x30000, [MT_PCIE_REMAP_BASE2] = 0x90000, [MT_TOP_MISC_BASE] = 0xc0000, [MT_EFUSE_ADDR_BASE] = 0x78011000, }; static void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { mt76_connac_irq_enable(mdev, MT_INT_RX_DONE(q)); } static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance) { struct mt7615_dev *dev = dev_instance; mt76_wr(dev, MT_INT_MASK_CSR, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; tasklet_schedule(&dev->mt76.irq_tasklet); return IRQ_HANDLED; } static void mt7615_irq_tasklet(struct tasklet_struct *t) { struct mt7615_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev); u32 mcu_int; mt76_wr(dev, MT_INT_MASK_CSR, 0); intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask |= intr & MT_INT_RX_DONE_ALL; if (intr & tx_mcu_mask) mask |= tx_mcu_mask; mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); if (intr & tx_mcu_mask) napi_schedule(&dev->mt76.tx_napi); if (intr & MT_INT_RX_DONE(0)) napi_schedule(&dev->mt76.napi[0]); if (intr & MT_INT_RX_DONE(1)) napi_schedule(&dev->mt76.napi[1]); if (!(intr & (MT_INT_MCU_CMD | MT7663_INT_MCU_CMD))) return; if (is_mt7663(&dev->mt76)) { mcu_int = mt76_rr(dev, MT_MCU2HOST_INT_STATUS); mcu_int &= MT7663_MCU_CMD_ERROR_MASK; mt76_wr(dev, MT_MCU2HOST_INT_STATUS, mcu_int); } else { mcu_int = mt76_rr(dev, MT_MCU_CMD); mcu_int &= MT_MCU_CMD_ERROR_MASK; } if (!mcu_int) return; dev->reset_state = mcu_int; queue_work(dev->mt76.wq, &dev->reset_work); wake_up(&dev->reset_wait); } static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr) { if (addr < 0x100000) return addr; return mt7615_reg_map(dev, addr); } static u32 mt7615_rr(struct mt76_dev *mdev, u32 offset) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); u32 addr = __mt7615_reg_addr(dev, offset); return dev->bus_ops->rr(mdev, addr); } static void mt7615_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); u32 addr = __mt7615_reg_addr(dev, offset); dev->bus_ops->wr(mdev, addr, val); } static u32 mt7615_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); u32 addr = __mt7615_reg_addr(dev, offset); return dev->bus_ops->rmw(mdev, addr, mask, val); } int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map) { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_txp_common), .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 = MT7615_TOKEN_SIZE, .tx_prepare_skb = mt7615_tx_prepare_skb, .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_check = mt7615_rx_check, .rx_skb = mt7615_queue_rx_skb, .rx_poll_complete = mt7615_rx_poll_complete, .sta_add = mt7615_mac_sta_add, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, + .set_channel = mt7615_set_channel, }; struct mt76_bus_ops *bus_ops; struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; int ret; ops = devm_kmemdup(pdev, &mt7615_ops, sizeof(mt7615_ops), GFP_KERNEL); if (!ops) return -ENOMEM; mdev = mt76_alloc_device(pdev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt7615_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); tasklet_setup(&mdev->irq_tasklet, mt7615_irq_tasklet); dev->reg_map = map; dev->ops = ops; 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); dev->bus_ops = dev->mt76.bus; bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), GFP_KERNEL); if (!bus_ops) { ret = -ENOMEM; goto err_free_dev; } bus_ops->rr = mt7615_rr; bus_ops->wr = mt7615_wr; bus_ops->rmw = mt7615_rmw; dev->mt76.bus = bus_ops; mt76_wr(dev, MT_INT_MASK_CSR, 0); ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto err_free_dev; if (is_mt7663(mdev)) mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); ret = mt7615_register_device(dev); if (ret) goto err_free_irq; return 0; err_free_irq: devm_free_irq(pdev, irq, dev); err_free_dev: mt76_free_device(&dev->mt76); return ret; } static int __init mt7615_init(void) { int ret; ret = pci_register_driver(&mt7615_pci_driver); if (ret) return ret; if (IS_ENABLED(CONFIG_MT7622_WMAC)) { ret = platform_driver_register(&mt7622_wmac_driver); if (ret) pci_unregister_driver(&mt7615_pci_driver); } return ret; } static void __exit mt7615_exit(void) { if (IS_ENABLED(CONFIG_MT7622_WMAC)) platform_driver_unregister(&mt7622_wmac_driver); pci_unregister_driver(&mt7615_pci_driver); } module_init(mt7615_init); module_exit(mt7615_exit); +MODULE_DESCRIPTION("MediaTek MT7615E MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/mt7615.h b/sys/contrib/dev/mediatek/mt76/mt7615/mt7615.h index a20322aae967..9bdd29e8d25e 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/mt7615.h +++ b/sys/contrib/dev/mediatek/mt76/mt7615/mt7615.h @@ -1,558 +1,557 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2019 MediaTek Inc. */ #ifndef __MT7615_H #define __MT7615_H #include #include #include #include #include "../mt76_connac_mcu.h" #include "regs.h" #define MT7615_MAX_INTERFACES 16 #define MT7615_MAX_WMM_SETS 4 #define MT7663_WTBL_SIZE 32 #define MT7615_WTBL_SIZE 128 #define MT7615_WTBL_RESERVED (mt7615_wtbl_size(dev) - 1) #define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \ MT7615_MAX_INTERFACES) #define MT7615_PM_TIMEOUT (HZ / 12) #define MT7615_HW_SCAN_TIMEOUT (HZ / 10) #define MT7615_RESET_TIMEOUT (30 * HZ) #define MT7615_RATE_RETRY 2 #define MT7615_TX_RING_SIZE 1024 #define MT7615_TX_MGMT_RING_SIZE 128 #define MT7615_TX_MCU_RING_SIZE 128 #define MT7615_TX_FWDL_RING_SIZE 128 #define MT7615_RX_RING_SIZE 1024 #define MT7615_RX_MCU_RING_SIZE 512 #define MT7615_DRV_OWN_RETRY_COUNT 10 #define MT7615_FIRMWARE_CR4 "mediatek/mt7615_cr4.bin" #define MT7615_FIRMWARE_N9 "mediatek/mt7615_n9.bin" #define MT7615_ROM_PATCH "mediatek/mt7615_rom_patch.bin" #define MT7622_FIRMWARE_N9 "mediatek/mt7622_n9.bin" #define MT7622_ROM_PATCH "mediatek/mt7622_rom_patch.bin" #define MT7615_FIRMWARE_V1 1 #define MT7615_FIRMWARE_V2 2 #define MT7615_FIRMWARE_V3 3 #define MT7663_OFFLOAD_ROM_PATCH "mediatek/mt7663pr2h.bin" #define MT7663_OFFLOAD_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin" #define MT7663_ROM_PATCH "mediatek/mt7663pr2h_rebb.bin" #define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_rebb.bin" #define MT7615_EEPROM_SIZE 1024 #define MT7663_EEPROM_SIZE 1536 #define MT7615_TOKEN_SIZE 4096 #define MT_FRAC_SCALE 12 #define MT_FRAC(val, div) (((val) << MT_FRAC_SCALE) / (div)) #define MT_CHFREQ_VALID BIT(7) #define MT_CHFREQ_DBDC_IDX BIT(6) #define MT_CHFREQ_SEQ GENMASK(5, 0) #define MT7615_BAR_RATE_DEFAULT 0x4b /* OFDM 6M */ #define MT7615_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ struct mt7615_vif; struct mt7615_sta; struct mt7615_dfs_pulse; struct mt7615_dfs_pattern; enum mt7615_cipher_type; enum mt7615_hw_txq_id { MT7615_TXQ_MAIN, MT7615_TXQ_EXT, MT7615_TXQ_MCU, MT7615_TXQ_FWDL, }; enum mt7622_hw_txq_id { MT7622_TXQ_AC0, MT7622_TXQ_AC1, MT7622_TXQ_AC2, MT7622_TXQ_FWDL = MT7615_TXQ_FWDL, MT7622_TXQ_AC3, MT7622_TXQ_MGMT, MT7622_TXQ_MCU = 15, }; struct mt7615_rate_set { struct ieee80211_tx_rate probe_rate; struct ieee80211_tx_rate rates[4]; }; struct mt7615_rate_desc { bool rateset; u16 probe_val; u16 val[4]; u8 bw_idx; u8 bw; }; struct mt7615_wtbl_rate_desc { struct list_head node; struct mt7615_rate_desc rate; 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 */ struct mt7615_vif *vif; u32 airtime_ac[8]; struct ieee80211_tx_rate rates[4]; struct mt7615_rate_set rateset[2]; u32 rate_set_tsf; u8 rate_count; u8 n_rates; u8 rate_probe; }; struct mt7615_vif { - struct mt76_vif mt76; /* must be first */ + struct mt76_vif_link mt76; /* must be first */ struct mt7615_sta sta; bool sta_added; }; struct mib_stats { u32 ack_fail_cnt; u32 fcs_err_cnt; u32 rts_cnt; u32 rts_retries_cnt; u32 ba_miss_cnt; unsigned long aggr_per; }; struct mt7615_phy { struct mt76_phy *mt76; struct mt7615_dev *dev; struct ieee80211_vif *monitor_vif; u8 n_beacon_vif; u32 rxfilter; u64 omac_mask; u16 noise; bool scs_en; unsigned long last_cca_adj; int false_cca_ofdm, false_cca_cck; s8 ofdm_sensitivity; s8 cck_sensitivity; s16 coverage_class; u8 slottime; u8 chfreq; u8 rdd_state; u32 rx_ampdu_ts; u32 ampdu_ref; struct mib_stats mib; struct sk_buff_head scan_event_list; struct delayed_work scan_work; struct work_struct roc_work; struct timer_list roc_timer; wait_queue_head_t roc_wait; bool roc_grant; #ifdef CONFIG_NL80211_TESTMODE struct { u32 *reg_backup; s16 last_freq_offset; u8 last_rcpi[4]; s8 last_ib_rssi[4]; s8 last_wb_rssi[4]; } test; #endif }; #define mt7615_mcu_add_tx_ba(dev, ...) (dev)->mcu_ops->add_tx_ba((dev), __VA_ARGS__) #define mt7615_mcu_add_rx_ba(dev, ...) (dev)->mcu_ops->add_rx_ba((dev), __VA_ARGS__) #define mt7615_mcu_sta_add(phy, ...) ((phy)->dev)->mcu_ops->sta_add((phy), __VA_ARGS__) #define mt7615_mcu_add_dev_info(phy, ...) ((phy)->dev)->mcu_ops->add_dev_info((phy), __VA_ARGS__) #define mt7615_mcu_add_bss_info(phy, ...) ((phy)->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__) #define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__) #define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__) #define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev)) #define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev)) #define mt7615_mcu_set_sta_decap_offload(dev, ...) (dev)->mcu_ops->set_sta_decap_offload((dev), __VA_ARGS__) struct mt7615_mcu_ops { int (*add_tx_ba)(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable); int (*add_rx_ba)(struct mt7615_dev *dev, struct ieee80211_ampdu_params *params, bool enable); int (*sta_add)(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); int (*add_dev_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable); int (*add_bss_info)(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable); int (*add_beacon_offload)(struct mt7615_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable); int (*set_pm_state)(struct mt7615_dev *dev, int band, int state); int (*set_drv_ctrl)(struct mt7615_dev *dev); int (*set_fw_ctrl)(struct mt7615_dev *dev); int (*set_sta_decap_offload)(struct mt7615_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); }; struct mt7615_dev { union { /* must be first */ struct mt76_dev mt76; struct mt76_phy mphy; }; const struct mt76_bus_ops *bus_ops; struct mt7615_phy phy; u64 omac_mask; u16 chainmask; struct ieee80211_ops *ops; const struct mt7615_mcu_ops *mcu_ops; struct regmap *infracfg; const u32 *reg_map; struct work_struct mcu_work; struct work_struct reset_work; wait_queue_head_t reset_wait; u32 reset_state; struct { u8 n_pulses; u32 period; u16 width; s16 power; } radar_pattern; u32 hw_pattern; bool fw_debug; bool flash_eeprom; bool dbdc_support; u8 fw_ver; struct work_struct rate_work; struct list_head wrd_head; u32 debugfs_rf_wf; u32 debugfs_rf_reg; u32 muar_mask; struct mt76_connac_pm pm; struct mt76_connac_coredump coredump; }; enum tx_pkt_queue_idx { MT_LMAC_AC00, MT_LMAC_AC01, MT_LMAC_AC02, MT_LMAC_AC03, MT_LMAC_ALTX0 = 0x10, MT_LMAC_BMC0, MT_LMAC_BCN0, MT_LMAC_PSMP0, MT_LMAC_ALTX1, MT_LMAC_BMC1, MT_LMAC_BCN1, MT_LMAC_PSMP1, }; enum { MT_RX_SEL0, MT_RX_SEL1, }; enum mt7615_rdd_cmd { RDD_STOP, RDD_START, RDD_DET_MODE, RDD_DET_STOP, RDD_CAC_START, RDD_CAC_END, RDD_NORMAL_START, RDD_DISABLE_DFS_CAL, RDD_PULSE_DBG, RDD_READ_PULSE, RDD_RESUME_BF, }; static inline struct mt7615_phy * mt7615_hw_phy(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return phy->priv; } static inline struct mt7615_dev * mt7615_hw_dev(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return container_of(phy->dev, struct mt7615_dev, mt76); } static inline struct mt7615_phy * mt7615_ext_phy(struct mt7615_dev *dev) { struct mt76_phy *phy = dev->mt76.phys[MT_BAND1]; if (!phy) return NULL; return phy->priv; } extern struct ieee80211_rate mt7615_rates[12]; extern const struct ieee80211_ops mt7615_ops; extern const u32 mt7615e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663_usb_sdio_reg_map[__MT_BASE_MAX]; extern struct pci_driver mt7615_pci_driver; extern struct platform_driver mt7622_wmac_driver; extern const struct mt76_testmode_ops mt7615_testmode_ops; #ifdef CONFIG_MT7622_WMAC int mt7622_wmac_init(struct mt7615_dev *dev); #else static inline int mt7622_wmac_init(struct mt7615_dev *dev) { return 0; } #endif int mt7615_thermal_init(struct mt7615_dev *dev); int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr); int mt7615_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off); void mt7615_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness); void mt7615_init_device(struct mt7615_dev *dev); int mt7615_register_device(struct mt7615_dev *dev); void mt7615_unregister_device(struct mt7615_dev *dev); int mt7615_register_ext_phy(struct mt7615_dev *dev); void mt7615_unregister_ext_phy(struct mt7615_dev *dev); int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr); int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); int mt7615_eeprom_get_power_delta_index(struct mt7615_dev *dev, enum nl80211_band band); int mt7615_wait_pdma_busy(struct mt7615_dev *dev); int mt7615_dma_init(struct mt7615_dev *dev); void mt7615_dma_start(struct mt7615_dev *dev); void mt7615_dma_cleanup(struct mt7615_dev *dev); int mt7615_mcu_init(struct mt7615_dev *dev); bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev); void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); void mt7615_pm_wake_work(struct work_struct *work); void mt7615_pm_power_save_work(struct work_struct *work); -int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev); int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd); int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, const struct ieee80211_tx_queue_params *params); void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb); int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev); int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl); static inline bool mt7615_firmware_offload(struct mt7615_dev *dev) { return dev->fw_ver > MT7615_FIRMWARE_V2; } static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) { if (is_mt7663(&dev->mt76) && mt7615_firmware_offload(dev)) return MT7663_WTBL_SIZE; else return MT7615_WTBL_SIZE; } #define mt7615_mutex_acquire(dev) \ mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm) #define mt7615_mutex_release(dev) \ mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac) { static const u8 lmac_queue_map[] = { [IEEE80211_AC_BK] = MT_LMAC_AC00, [IEEE80211_AC_BE] = MT_LMAC_AC01, [IEEE80211_AC_VI] = MT_LMAC_AC02, [IEEE80211_AC_VO] = MT_LMAC_AC03, }; if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map))) return MT_LMAC_AC01; /* BE */ return lmac_queue_map[ac]; } static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev) { return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx); } static inline unsigned long mt7615_get_macwork_timeout(struct mt7615_dev *dev) { return dev->pm.enable ? HZ / 3 : HZ / 10; } void mt7615_dma_reset(struct mt7615_dev *dev); void mt7615_scan_work(struct work_struct *work); void mt7615_roc_work(struct work_struct *work); void mt7615_roc_timer(struct timer_list *timer); void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband); -int mt7615_set_channel(struct mt7615_phy *phy); +int mt7615_set_channel(struct mt76_phy *mphy); void mt7615_init_work(struct mt7615_dev *dev); int mt7615_mcu_restart(struct mt76_dev *dev); void mt7615_update_channel(struct mt76_phy *mphy); bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_phy *phy); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key, enum mt76_txq_id qid, bool beacon); void mt7615_mac_set_timing(struct mt7615_phy *phy); int __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key); int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key); void mt7615_mac_reset_work(struct work_struct *work); u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid); int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq); u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg); int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); int mt7615_mcu_get_temperature(struct mt7615_dev *dev); int mt7615_mcu_set_tx_power(struct mt7615_phy *phy); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq); int mt7615_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 mt7615_tx_worker(struct mt76_worker *w); void mt7615_tx_token_put(struct mt7615_dev *dev); bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7615_mac_work(struct work_struct *work); int mt7615_mcu_set_rx_hdr_trans_blacklist(struct mt7615_dev *dev); int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val); int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, const struct mt7615_dfs_pulse *pulse); int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern); int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, u32 val); int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); 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_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration); int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool enable); int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); int __mt7663_load_firmware(struct mt7615_dev *dev); void mt7615_coredump_work(struct work_struct *work); void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en); /* usb */ int mt7663_usb_sdio_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); bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update); void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); int mt7663_usb_sdio_register_device(struct mt7615_dev *dev); int mt7663u_mcu_init(struct mt7615_dev *dev); int mt7663u_mcu_power_on(struct mt7615_dev *dev); /* sdio */ int mt7663s_mcu_init(struct mt7615_dev *dev); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/pci.c b/sys/contrib/dev/mediatek/mt76/mt7615/pci.c index 9f43e673518b..053faacd715a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/pci.c @@ -1,202 +1,212 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Ryder Lee * Felix Fietkau */ #include #include #include #include "mt7615.h" #include "mcu.h" static const struct pci_device_id mt7615_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7615) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7663) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7611) }, { }, }; static int mt7615_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const u32 *map; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_set_master(pdev); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto error; mt76_pci_disable_aspm(pdev); map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map; ret = mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], pdev->irq, map); if (ret) goto error; return 0; error: pci_free_irq_vectors(pdev); return ret; } static void mt7615_pci_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); mt7615_unregister_device(dev); devm_free_irq(&pdev->dev, pdev->irq, dev); pci_free_irq_vectors(pdev); } #ifdef CONFIG_PM static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); bool hif_suspend; int i, err; err = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (err < 0) return err; hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev); if (hif_suspend) { - err = mt76_connac_mcu_set_hif_suspend(mdev, true); + err = mt76_connac_mcu_set_hif_suspend(mdev, true, true); if (err) return err; } napi_disable(&mdev->tx_napi); mt76_worker_disable(&mdev->tx_worker); mt76_for_each_q_rx(mdev, i) { napi_disable(&mdev->napi[i]); } tasklet_kill(&mdev->irq_tasklet); mt7615_dma_reset(dev); err = mt7615_wait_pdma_busy(dev); if (err) goto restore; if (is_mt7663(mdev)) { mt76_set(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); if (!mt76_poll_msec(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_RDY, MT_PDMA_AXI_SLPPROT_RDY, 1000)) { dev_err(mdev->dev, "PDMA sleep protection failed\n"); err = -EIO; goto restore; } } pci_enable_wake(pdev, pci_choose_state(pdev, state), true); pci_save_state(pdev); err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); if (err) goto restore; err = mt7615_mcu_set_fw_ctrl(dev); if (err) goto restore; return 0; restore: mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); if (hif_suspend) - mt76_connac_mcu_set_hif_suspend(mdev, false); + mt76_connac_mcu_set_hif_suspend(mdev, false, true); return err; } static int mt7615_pci_resume(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); bool pdma_reset; int i, err; err = mt7615_mcu_set_drv_ctrl(dev); if (err < 0) return err; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; pci_restore_state(pdev); if (is_mt7663(&dev->mt76)) { mt76_clear(dev, MT_PDMA_SLP_PROT, MT_PDMA_AXI_SLPPROT_ENABLE); mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1); } pdma_reset = !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL0) && !mt76_rr(dev, MT_WPDMA_TX_RING0_CTRL1); if (pdma_reset) 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); + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + napi_schedule(&mdev->napi[i]); + } napi_schedule(&mdev->tx_napi); local_bh_enable(); if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) - err = mt76_connac_mcu_set_hif_suspend(mdev, false); + err = mt76_connac_mcu_set_hif_suspend(mdev, false, true); return err; } #endif /* CONFIG_PM */ struct pci_driver mt7615_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7615_pci_device_table, .probe = mt7615_pci_probe, .remove = mt7615_pci_remove, #ifdef CONFIG_PM .suspend = mt7615_pci_suspend, .resume = mt7615_pci_resume, #endif /* CONFIG_PM */ }; MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table); MODULE_FIRMWARE(MT7615_FIRMWARE_CR4); MODULE_FIRMWARE(MT7615_FIRMWARE_N9); MODULE_FIRMWARE(MT7615_ROM_PATCH); MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); MODULE_FIRMWARE(MT7663_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_ROM_PATCH); +#if defined(__FreeBSD__) +MODULE_VERSION(mt7615_pci, 1); +MODULE_DEPEND(mt7615_pci, linuxkpi, 1, 1, 1); +MODULE_DEPEND(mt7615_pci, linuxkpi_wlan, 1, 1, 1); +MODULE_DEPEND(mt7615_pci, mt76_core, 1, 1, 1); +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/pci_init.c b/sys/contrib/dev/mediatek/mt76/mt7615/pci_init.c index 68f628c6f24e..ec1ae85f8de1 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/pci_init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/pci_init.c @@ -1,133 +1,137 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Roy Luo * Ryder Lee * Felix Fietkau * Lorenzo Bianconi */ #include #if defined(__FreeBSD__) #include #endif #include "mt7615.h" #include "mac.h" #include "eeprom.h" static void mt7615_pci_init_work(struct work_struct *work) { struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work); int i, ret; ret = mt7615_mcu_init(dev); for (i = 0; (ret == -EAGAIN) && (i < 10); i++) { msleep(200); ret = mt7615_mcu_init(dev); } if (ret) return; mt7615_init_work(dev); } static int mt7615_init_hardware(struct mt7615_dev *dev) { u32 addr = mt7615_reg_map(dev, MT_EFUSE_BASE); int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); INIT_WORK(&dev->mcu_work, mt7615_pci_init_work); ret = mt7615_eeprom_init(dev, addr); if (ret < 0) return ret; if (is_mt7663(&dev->mt76)) { /* Reset RGU */ mt76_clear(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1)); mt76_set(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1)); } ret = mt7615_dma_init(dev); if (ret) return ret; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); if (idx) return -ENOSPC; dev->mt76.global_wcid.idx = idx; dev->mt76.global_wcid.hw_key_idx = -1; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); return 0; } int mt7615_register_device(struct mt7615_dev *dev) { int ret; mt7615_init_device(dev); INIT_WORK(&dev->reset_work, mt7615_mac_reset_work); /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { dev->mphy.leds.cdev.brightness_set = mt7615_led_set_brightness; dev->mphy.leds.cdev.blink_set = mt7615_led_set_blink; } ret = mt7622_wmac_init(dev); if (ret) return ret; ret = mt7615_init_hardware(dev); if (ret) return ret; ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) return ret; #if defined(__linux__) ret = mt7615_thermal_init(dev); if (ret) return ret; #endif ieee80211_queue_work(mt76_hw(dev), &dev->mcu_work); mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); if (dev->dbdc_support) { ret = mt7615_register_ext_phy(dev); if (ret) return ret; } +#if defined(CONFIG_MT7615_DEBUGFS) return mt7615_init_debugfs(dev); +#else + return 0; +#endif } void mt7615_unregister_device(struct mt7615_dev *dev) { bool mcu_running; mcu_running = mt7615_wait_for_mcu_init(dev); mt7615_unregister_ext_phy(dev); mt76_unregister_device(&dev->mt76); if (mcu_running) mt7615_mcu_exit(dev); mt7615_tx_token_put(dev); mt7615_dma_cleanup(dev); tasklet_disable(&dev->mt76.irq_tasklet); mt76_free_device(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/pci_mac.c b/sys/contrib/dev/mediatek/mt76/mt7615/pci_mac.c index fe6bd71c7d97..5da2bf332af0 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/pci_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/pci_mac.c @@ -1,296 +1,298 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * Author: Ryder Lee * Roy Luo * Felix Fietkau * Lorenzo Bianconi */ #include #include #if defined(__FreeBSD__) #include #endif #include "mt7615.h" #include "../dma.h" #include "mac.h" static void mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; struct mt76_connac_fw_txp *txp = txp_ptr; u8 *rept_wds_wcid = (u8 *)&txp->rept_wds_wcid; int nbuf = tx_info->nbuf - 1; int i; for (i = 0; i < nbuf; i++) { txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); } txp->nbuf = nbuf; /* pass partial skb header to fw */ tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp); tx_info->buf[1].len = MT_CT_PARSE_LEN; tx_info->buf[1].skip_unmap = true; tx_info->nbuf = MT_CT_DMA_BUF_NUM; txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD); if (!key) txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); if (ieee80211_is_mgmt(hdr->frame_control)) txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); if (vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; txp->bss_idx = mvif->idx; } txp->token = cpu_to_le16(id); *rept_wds_wcid = 0xff; } int mt7615_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 mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; int pid, id; u8 *txwi = (u8 *)txwi_ptr; struct mt76_txwi_cache *t; struct mt7615_sta *msta; void *txp; msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if (!wcid) wcid = &dev->mt76.global_wcid; if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta) { struct mt7615_phy *phy = &dev->phy; u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; if (phy_idx && mdev->phys[MT_BAND1]) phy = mdev->phys[MT_BAND1]->priv; spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(phy, msta, &info->control.rates[0], msta->rates); spin_unlock_bh(&dev->mt76.lock); } t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size); t->skb = tx_info->skb; id = mt76_token_get(mdev, &t); if (id < 0) return id; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta, pid, key, qid, false); txp = txwi + MT_TXD_SIZE; memset(txp, 0, sizeof(struct mt76_connac_txp_common)); if (is_mt7615(&dev->mt76)) mt7615_write_fw_txp(dev, tx_info, txp, id); else mt76_connac_write_hw_txp(mdev, tx_info, txp, id); - tx_info->skb = DMA_DUMMY_DATA; + tx_info->skb = NULL; return 0; } void mt7615_dma_reset(struct mt7615_dev *dev) { int i; mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); usleep_range(1000, 2000); for (i = 0; i < __MT_TXQ_MAX; i++) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); mt76_tx_status_check(&dev->mt76, true); mt7615_dma_start(dev); } EXPORT_SYMBOL_GPL(mt7615_dma_reset); static void mt7615_hif_int_event_trigger(struct mt7615_dev *dev, u8 event) { u32 reg = MT_MCU_INT_EVENT; if (is_mt7663(&dev->mt76)) reg = MT7663_MCU_INT_EVENT; mt76_wr(dev, reg, event); mt7622_trigger_hif_int(dev, true); mt7622_trigger_hif_int(dev, false); } static bool mt7615_wait_reset_state(struct mt7615_dev *dev, u32 state) { bool ret; ret = wait_event_timeout(dev->reset_wait, (READ_ONCE(dev->reset_state) & state), MT7615_RESET_TIMEOUT); WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); return ret; } static void mt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: mt7615_mcu_add_beacon(dev, hw, vif, vif->bss_conf.enable_beacon); break; default: break; } } static void mt7615_update_beacons(struct mt7615_dev *dev) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_update_vif_beacon, dev->mt76.hw); if (!mphy_ext) return; ieee80211_iterate_active_interfaces(mphy_ext->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_update_vif_beacon, mphy_ext->hw); } void mt7615_mac_reset_work(struct work_struct *work) { struct mt7615_phy *phy2; struct mt76_phy *ext_phy; struct mt7615_dev *dev; unsigned long timeout; int i; dev = container_of(work, struct mt7615_dev, reset_work); ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA)) return; ieee80211_stop_queues(mt76_hw(dev)); if (ext_phy) ieee80211_stop_queues(ext_phy->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); cancel_delayed_work_sync(&dev->mphy.mac_work); del_timer_sync(&dev->phy.roc_timer); cancel_work_sync(&dev->phy.roc_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); cancel_delayed_work_sync(&phy2->mt76->mac_work); del_timer_sync(&phy2->roc_timer); cancel_work_sync(&phy2->roc_work); } /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); if (ext_phy) mt76_txq_schedule_all(ext_phy); mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(&dev->mt76, i) napi_disable(&dev->mt76.napi[i]); napi_disable(&dev->mt76.tx_napi); mt7615_mutex_acquire(dev); mt7615_hif_int_event_trigger(dev, MT_MCU_INT_EVENT_PDMA_STOPPED); if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { mt7615_dma_reset(dev); mt7615_tx_token_put(dev); idr_init(&dev->mt76.token); mt76_wr(dev, MT_WPDMA_MEM_RNG_ERR, 0); mt7615_hif_int_event_trigger(dev, MT_MCU_INT_EVENT_PDMA_INIT); mt7615_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); } clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) 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); - mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + + local_bh_disable(); + napi_schedule(&dev->mt76.tx_napi); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) ieee80211_wake_queues(ext_phy->hw); mt7615_hif_int_event_trigger(dev, MT_MCU_INT_EVENT_RESET_DONE); mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); mt7615_update_beacons(dev); mt7615_mutex_release(dev); timeout = mt7615_get_macwork_timeout(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, timeout); if (phy2) ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mt76->mac_work, timeout); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c b/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c index fc547a0031ea..f56038cd4d3a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/sdio.c @@ -1,256 +1,258 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * Author: Felix Fietkau * Lorenzo Bianconi * Sean Wang */ #include #include #include #include #include #include #include "../sdio.h" #include "mt7615.h" #include "mac.h" #include "mcu.h" static const struct sdio_device_id mt7663s_table[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) }, { } /* Terminating entry */ }; static void mt7663s_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 mt7615_dev *dev = container_of(mdev, struct mt7615_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 mt7663s_init_work(struct work_struct *work) { struct mt7615_dev *dev; dev = container_of(work, struct mt7615_dev, mcu_work); if (mt7663s_mcu_init(dev)) return; mt7615_init_work(dev); } static int mt7663s_parse_intr(struct mt76_dev *dev, struct mt76s_intr *intr) { struct mt76_sdio *sdio = &dev->sdio; struct mt7663s_intr *irq_data = sdio->intr_data; int i, err; sdio_claim_host(sdio->func); err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); sdio_release_host(sdio->func); if (err) 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++) intr->rx.len[i] = irq_data->rx.len[i]; return 0; } static int mt7663s_probe(struct sdio_func *func, const struct sdio_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_USB_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR, .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, .tx_status_data = mt7663_usb_sdio_tx_status_data, .rx_skb = mt7615_queue_rx_skb, .rx_check = mt7615_rx_check, .sta_add = mt7615_mac_sta_add, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, + .set_channel = mt7615_set_channel, }; static const struct mt76_bus_ops mt7663s_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, }; struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; int ret; ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops), GFP_KERNEL); if (!ops) return -ENOMEM; mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt7615_dev, mt76); INIT_WORK(&dev->mcu_work, mt7663s_init_work); dev->reg_map = mt7663_usb_sdio_reg_map; dev->ops = ops; sdio_set_drvdata(func, dev); ret = mt76s_init(mdev, func, &mt7663s_ops); if (ret < 0) goto error; ret = mt76s_hw_init(mdev, func, MT76_CONNAC_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 = mt7663s_parse_intr; mdev->sdio.intr_data = devm_kmalloc(mdev->dev, sizeof(struct mt7663s_intr), GFP_KERNEL); if (!mdev->sdio.intr_data) { ret = -ENOMEM; goto error; } ret = mt76s_alloc_rx_queue(mdev, MT_RXQ_MAIN); if (ret) goto error; ret = mt76s_alloc_tx(mdev); if (ret) goto error; ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker, mt7663s_txrx_worker, "sdio-txrx"); if (ret) goto error; sched_set_fifo_low(mdev->sdio.txrx_worker.task); ret = mt7663_usb_sdio_register_device(dev); if (ret) goto error; return 0; error: mt76s_deinit(&dev->mt76); mt76_free_device(&dev->mt76); return ret; } static void mt7663s_remove(struct sdio_func *func) { struct mt7615_dev *dev = sdio_get_drvdata(func); if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return; ieee80211_unregister_hw(dev->mt76.hw); mt76s_deinit(&dev->mt76); mt76_free_device(&dev->mt76); } static int mt7663s_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct mt7615_dev *mdev = sdio_get_drvdata(func); int err; if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && mt7615_firmware_offload(mdev)) { int err; - err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true); + err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, true, true); if (err < 0) return err; } sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); err = mt7615_mcu_set_fw_ctrl(mdev); if (err) return err; mt76_worker_disable(&mdev->mt76.sdio.txrx_worker); mt76_worker_disable(&mdev->mt76.sdio.status_worker); mt76_worker_disable(&mdev->mt76.sdio.net_worker); + mt76_worker_disable(&mdev->mt76.sdio.stat_worker); - cancel_work_sync(&mdev->mt76.sdio.stat_work); clear_bit(MT76_READING_STATS, &mdev->mphy.state); mt76_tx_status_check(&mdev->mt76, true); return 0; } static int mt7663s_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct mt7615_dev *mdev = sdio_get_drvdata(func); int err; mt76_worker_enable(&mdev->mt76.sdio.txrx_worker); mt76_worker_enable(&mdev->mt76.sdio.status_worker); mt76_worker_enable(&mdev->mt76.sdio.net_worker); err = mt7615_mcu_set_drv_ctrl(mdev); if (err) return err; if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && mt7615_firmware_offload(mdev)) - err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false); + err = mt76_connac_mcu_set_hif_suspend(&mdev->mt76, false, true); return err; } MODULE_DEVICE_TABLE(sdio, mt7663s_table); MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); MODULE_FIRMWARE(MT7663_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_ROM_PATCH); static DEFINE_SIMPLE_DEV_PM_OPS(mt7663s_pm_ops, mt7663s_suspend, mt7663s_resume); static struct sdio_driver mt7663s_driver = { .name = KBUILD_MODNAME, .probe = mt7663s_probe, .remove = mt7663s_remove, .id_table = mt7663s_table, .drv.pm = pm_sleep_ptr(&mt7663s_pm_ops), }; module_sdio_driver(mt7663s_driver); MODULE_AUTHOR("Sean Wang "); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT7663S (SDIO) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/sdio_mcu.c b/sys/contrib/dev/mediatek/mt76/mt7615/sdio_mcu.c new file mode 100644 index 000000000000..a7b8acb2da83 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7615/sdio_mcu.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ +#include +#include +#include +#include + +#include "../sdio.h" +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + u32 txdwcnt; + + sdio->sched.pse_data_quota = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, + MT_HIF0_MIN_QUOTA); + sdio->sched.pse_mcu_quota = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, + 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; + + return 0; +} + +static int +mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *seq) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + int ret; + + mt7615_mcu_fill_msg(dev, skb, cmd, seq); + ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0); + if (ret) + return ret; + + mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]); + + return ret; +} + +static int __mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_connac_pm *pm = &dev->pm; + u32 status; + int ret; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL); + + 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"); + } else { + 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; + } + sdio_release_host(func); + + return ret; +} + +static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + int ret = 0; + + mutex_lock(&dev->pm.mutex); + + if (test_bit(MT76_STATE_PM, &mphy->state)) + ret = __mt7663s_mcu_drv_pmctrl(dev); + + mutex_unlock(&dev->pm.mutex); + + return ret; +} + +static int mt7663s_mcu_fw_pmctrl(struct mt7615_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 ret = 0; + u32 status; + + mutex_lock(&pm->mutex); + + if (mt76_connac_skip_fw_pmctrl(mphy, pm)) + goto out; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL); + + 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"); + clear_bit(MT76_STATE_PM, &mphy->state); + } else { + pm->stats.last_doze_event = jiffies; + pm->stats.awake_time += pm->stats.last_doze_event - + pm->stats.last_wake_event; + } + + sdio_release_host(func); +out: + mutex_unlock(&pm->mutex); + + return ret; +} + +int mt7663s_mcu_init(struct mt7615_dev *dev) +{ + static const struct mt76_mcu_ops mt7663s_mcu_ops = { + .headroom = sizeof(struct mt7615_mcu_txd), + .tailroom = MT_USB_TAIL_SIZE, + .mcu_skb_send_msg = mt7663s_mcu_send_message, + .mcu_parse_response = mt7615_mcu_parse_response, + .mcu_rr = mt76_connac_mcu_reg_rr, + .mcu_wr = mt76_connac_mcu_reg_wr, + }; + struct mt7615_mcu_ops *mcu_ops; + int ret; + + ret = __mt7663s_mcu_drv_pmctrl(dev); + if (ret) + return ret; + + dev->mt76.mcu_ops = &mt7663s_mcu_ops; + + ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); + if (ret) { + mt7615_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_N9_RDY, 0, 500)) + return -EIO; + } + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops), + GFP_KERNEL); + if (!mcu_ops) + return -ENOMEM; + + mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl; + mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl; + dev->mcu_ops = mcu_ops; + + ret = mt7663s_mcu_init_sched(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/soc.c b/sys/contrib/dev/mediatek/mt76/mt7615/soc.c index f13d1b418742..06a0f2a141e8 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/soc.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/soc.c @@ -1,72 +1,70 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Ryder Lee * Felix Fietkau */ #include #include #include #include #include #include #include "mt7615.h" int mt7622_wmac_init(struct mt7615_dev *dev) { struct device_node *np = dev->mt76.dev->of_node; if (!is_mt7622(&dev->mt76)) return 0; dev->infracfg = syscon_regmap_lookup_by_phandle(np, "mediatek,infracfg"); if (IS_ERR(dev->infracfg)) { dev_err(dev->mt76.dev, "Cannot find infracfg controller\n"); return PTR_ERR(dev->infracfg); } return 0; } static int mt7622_wmac_probe(struct platform_device *pdev) { void __iomem *mem_base; int irq; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; mem_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(mem_base)) return PTR_ERR(mem_base); return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); } -static int mt7622_wmac_remove(struct platform_device *pdev) +static void mt7622_wmac_remove(struct platform_device *pdev) { struct mt7615_dev *dev = platform_get_drvdata(pdev); mt7615_unregister_device(dev); - - return 0; } static const struct of_device_id mt7622_wmac_of_match[] = { { .compatible = "mediatek,mt7622-wmac" }, {}, }; struct platform_driver mt7622_wmac_driver = { .driver = { .name = "mt7622-wmac", .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, .remove = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); MODULE_FIRMWARE(MT7622_ROM_PATCH); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/testmode.c b/sys/contrib/dev/mediatek/mt76/mt7615/testmode.c index a3d1cfa729ed..03f5af84424b 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/testmode.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/testmode.c @@ -1,376 +1,376 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 Felix Fietkau */ #include "mt7615.h" #include "eeprom.h" #include "mcu.h" enum { TM_CHANGED_TXPOWER_CTRL, TM_CHANGED_TXPOWER, TM_CHANGED_FREQ_OFFSET, /* must be last */ NUM_TM_CHANGED }; static const u8 tm_change_map[] = { [TM_CHANGED_TXPOWER_CTRL] = MT76_TM_ATTR_TX_POWER_CONTROL, [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, }; static const u32 reg_backup_list[] = { MT_WF_PHY_RFINTF3_0(0), MT_WF_PHY_RFINTF3_0(1), MT_WF_PHY_RFINTF3_0(2), MT_WF_PHY_RFINTF3_0(3), MT_ANT_SWITCH_CON(2), MT_ANT_SWITCH_CON(3), MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON(6), MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON(8), }; static const struct { u16 wf; u16 reg; } rf_backup_list[] = { { 0, 0x48 }, { 1, 0x48 }, { 2, 0x48 }, { 3, 0x48 }, }; static int mt7615_tm_set_tx_power(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; int i, ret, n_chains = hweight8(mphy->antenna_mask); struct cfg80211_chan_def *chandef = &mphy->chandef; int freq = chandef->center_freq1, len, target_chains; u8 *data, *eep = (u8 *)dev->mt76.eeprom.data; enum nl80211_band band = chandef->chan->band; struct sk_buff *skb; struct { u8 center_chan; u8 dbdc_idx; u8 band; u8 rsv; } __packed req_hdr = { .center_chan = ieee80211_frequency_to_channel(freq), .band = band, .dbdc_idx = phy != &dev->phy, }; u8 *tx_power = NULL; if (mphy->test.state != MT76_TM_STATE_OFF) tx_power = mphy->test.tx_power; len = MT7615_EE_MAX - MT_EE_NIC_CONF_0; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len); if (!skb) return -ENOMEM; skb_put_data(skb, &req_hdr, sizeof(req_hdr)); data = skb_put_data(skb, eep + MT_EE_NIC_CONF_0, len); target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; for (i = 0; i < target_chains; i++) { ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i); if (ret < 0) { dev_kfree_skb(skb); return -EINVAL; } if (tx_power && tx_power[i]) data[ret - MT_EE_NIC_CONF_0] = tx_power[i]; } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(SET_TX_POWER_CTRL), false); } static void mt7615_tm_reg_backup_restore(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; u32 *b = phy->test.reg_backup; int n_regs = ARRAY_SIZE(reg_backup_list); int n_rf_regs = ARRAY_SIZE(rf_backup_list); int i; if (phy->mt76->test.state == MT76_TM_STATE_OFF) { for (i = 0; i < n_regs; i++) mt76_wr(dev, reg_backup_list[i], b[i]); for (i = 0; i < n_rf_regs; i++) mt7615_rf_wr(dev, rf_backup_list[i].wf, rf_backup_list[i].reg, b[n_regs + i]); return; } if (b) return; b = devm_kzalloc(dev->mt76.dev, 4 * (n_regs + n_rf_regs), GFP_KERNEL); if (!b) return; phy->test.reg_backup = b; for (i = 0; i < n_regs; i++) b[i] = mt76_rr(dev, reg_backup_list[i]); for (i = 0; i < n_rf_regs; i++) b[n_regs + i] = mt7615_rf_rr(dev, rf_backup_list[i].wf, rf_backup_list[i].reg); } static void mt7615_tm_init(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; unsigned int total_flags = ~0; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; mt7615_mcu_set_sku_en(phy, phy->mt76->test.state == MT76_TM_STATE_OFF); mutex_unlock(&dev->mt76.mutex); - mt7615_set_channel(phy); + mt76_update_channel(phy->mt76); mt7615_ops.configure_filter(phy->mt76->hw, 0, &total_flags, 0); mutex_lock(&dev->mt76.mutex); mt7615_tm_reg_backup_restore(phy); } static void mt7615_tm_set_rx_enable(struct mt7615_dev *dev, bool en) { u32 rqcr_mask = (MT_ARB_RQCR_RX_START | MT_ARB_RQCR_RXV_START | MT_ARB_RQCR_RXV_R_EN | MT_ARB_RQCR_RXV_T_EN) * (BIT(0) | BIT(MT_ARB_RQCR_BAND_SHIFT)); if (en) { mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); mt76_set(dev, MT_ARB_RQCR, rqcr_mask); } else { mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); mt76_clear(dev, MT_ARB_RQCR, rqcr_mask); } } static void mt7615_tm_set_tx_antenna(struct mt7615_phy *phy, bool en) { struct mt7615_dev *dev = phy->dev; struct mt76_testmode_data *td = &phy->mt76->test; u8 mask = td->tx_antenna_mask; int i; if (!mask) return; if (!en) mask = phy->mt76->chainmask; for (i = 0; i < 4; i++) { mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i), MT_WF_PHY_RFINTF3_0_ANT, (mask & BIT(i)) ? 0 : 0xa); } /* 2.4 GHz band */ mt76_rmw_field(dev, MT_ANT_SWITCH_CON(3), MT_ANT_SWITCH_CON_MODE(0), (mask & BIT(0)) ? 0x8 : 0x1b); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(2), (mask & BIT(1)) ? 0xe : 0x1b); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(6), MT_ANT_SWITCH_CON_MODE1(0), (mask & BIT(2)) ? 0x0 : 0xf); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(2), (mask & BIT(3)) ? 0x6 : 0xf); /* 5 GHz band */ mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(1), (mask & BIT(0)) ? 0xd : 0x1b); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(2), MT_ANT_SWITCH_CON_MODE(3), (mask & BIT(1)) ? 0x13 : 0x1b); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(1), (mask & BIT(2)) ? 0x5 : 0xf); mt76_rmw_field(dev, MT_ANT_SWITCH_CON(8), MT_ANT_SWITCH_CON_MODE1(3), (mask & BIT(3)) ? 0xb : 0xf); for (i = 0; i < 4; i++) { u32 val; val = mt7615_rf_rr(dev, i, 0x48); val &= ~(0x3ff << 20); if (mask & BIT(i)) val |= 3 << 20; else val |= (2 << 28) | (2 << 26) | (8 << 20); mt7615_rf_wr(dev, i, 0x48, val); } } static void mt7615_tm_set_tx_frames(struct mt7615_phy *phy, bool en) { struct mt7615_dev *dev = phy->dev; struct ieee80211_tx_info *info; struct sk_buff *skb = phy->mt76->test.tx_skb; mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); mt7615_tm_set_tx_antenna(phy, en); mt7615_tm_set_rx_enable(dev, !en); if (!en || !skb) return; info = IEEE80211_SKB_CB(skb); info->control.vif = phy->monitor_vif; } static void mt7615_tm_update_params(struct mt7615_phy *phy, u32 changed) { struct mt7615_dev *dev = phy->dev; struct mt76_testmode_data *td = &phy->mt76->test; bool en = phy->mt76->test.state != MT76_TM_STATE_OFF; if (changed & BIT(TM_CHANGED_TXPOWER_CTRL)) mt7615_mcu_set_test_param(dev, MCU_ATE_SET_TX_POWER_CONTROL, en, en && td->tx_power_control); if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) mt7615_mcu_set_test_param(dev, MCU_ATE_SET_FREQ_OFFSET, en, en ? td->freq_offset : 0); if (changed & BIT(TM_CHANGED_TXPOWER)) mt7615_tm_set_tx_power(phy); } static int mt7615_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state) { struct mt7615_phy *phy = mphy->priv; struct mt76_testmode_data *td = &mphy->test; enum mt76_testmode_state prev_state = td->state; mphy->test.state = state; if (prev_state == MT76_TM_STATE_TX_FRAMES) mt7615_tm_set_tx_frames(phy, false); else if (state == MT76_TM_STATE_TX_FRAMES) mt7615_tm_set_tx_frames(phy, true); if (state <= MT76_TM_STATE_IDLE) mt7615_tm_init(phy); if ((state == MT76_TM_STATE_IDLE && prev_state == MT76_TM_STATE_OFF) || (state == MT76_TM_STATE_OFF && prev_state == MT76_TM_STATE_IDLE)) { u32 changed = 0; int i; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { u16 cur = tm_change_map[i]; if (td->param_set[cur / 32] & BIT(cur % 32)) changed |= BIT(i); } mt7615_tm_update_params(phy, changed); } return 0; } static int mt7615_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, enum mt76_testmode_state new_state) { struct mt76_testmode_data *td = &mphy->test; struct mt7615_phy *phy = mphy->priv; u32 changed = 0; int i; BUILD_BUG_ON(NUM_TM_CHANGED >= 32); if (new_state == MT76_TM_STATE_OFF || td->state == MT76_TM_STATE_OFF) return 0; if (td->tx_antenna_mask & ~mphy->chainmask) return -EINVAL; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { if (tb[tm_change_map[i]]) changed |= BIT(i); } mt7615_tm_update_params(phy, changed); return 0; } static int mt7615_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { struct mt7615_phy *phy = mphy->priv; void *rx, *rssi; int i; rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); if (!rx) return -ENOMEM; if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset)) return -ENOMEM; rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) if (nla_put_u8(msg, i, phy->test.last_rcpi[i])) return -ENOMEM; nla_nest_end(msg, rssi); rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++) if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++) if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); nla_nest_end(msg, rx); return 0; } const struct mt76_testmode_ops mt7615_testmode_ops = { .set_state = mt7615_tm_set_state, .set_params = mt7615_tm_set_params, .dump_stats = mt7615_tm_dump_stats, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/usb.c b/sys/contrib/dev/mediatek/mt76/mt7615/usb.c index 04963b9f7498..4aa9fa1c4a23 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/usb.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/usb.c @@ -1,284 +1,286 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2019 MediaTek Inc. * * Author: Felix Fietkau * Lorenzo Bianconi * Sean Wang */ #include #include #include #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "regs.h" static const struct usb_device_id mt7615_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7663, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(0x043e, 0x310c, 0xff, 0xff, 0xff) }, { }, }; static u32 mt7663u_rr(struct mt76_dev *dev, u32 addr) { u32 ret; mutex_lock(&dev->usb.usb_ctrl_mtx); ret = ___mt76u_rr(dev, MT_VEND_READ_EXT, USB_DIR_IN | USB_TYPE_VENDOR, addr); mutex_unlock(&dev->usb.usb_ctrl_mtx); return ret; } static void mt7663u_wr(struct mt76_dev *dev, u32 addr, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); ___mt76u_wr(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | USB_TYPE_VENDOR, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } static u32 mt7663u_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); val |= ___mt76u_rr(dev, MT_VEND_READ_EXT, USB_DIR_IN | USB_TYPE_VENDOR, addr) & ~mask; ___mt76u_wr(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | USB_TYPE_VENDOR, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); return val; } static void mt7663u_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { struct mt76_usb *usb = &dev->usb; int ret, i = 0, batch_len; const u8 *val = data; len = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); while (i < len) { batch_len = min_t(int, usb->data_len, len - i); memcpy(usb->data, val + i, batch_len); ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | USB_TYPE_VENDOR, (offset + i) >> 16, offset + i, usb->data, batch_len); if (ret < 0) break; i += batch_len; } mutex_unlock(&usb->usb_ctrl_mtx); } -static void mt7663u_stop(struct ieee80211_hw *hw) +static void mt7663u_stop(struct ieee80211_hw *hw, bool suspend) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); cancel_delayed_work_sync(&phy->scan_work); cancel_delayed_work_sync(&phy->mt76->mac_work); mt76u_stop_tx(&dev->mt76); } static void mt7663u_cleanup(struct mt7615_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); mt76u_queues_deinit(&dev->mt76); } static void mt7663u_init_work(struct work_struct *work) { struct mt7615_dev *dev; dev = container_of(work, struct mt7615_dev, mcu_work); if (mt7663u_mcu_init(dev)) return; mt7615_init_work(dev); } static int mt7663u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_USB_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, .tx_status_data = mt7663_usb_sdio_tx_status_data, .rx_skb = mt7615_queue_rx_skb, .rx_check = mt7615_rx_check, .sta_add = mt7615_mac_sta_add, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, + .set_channel = mt7615_set_channel, }; static struct mt76_bus_ops bus_ops = { .rr = mt7663u_rr, .wr = mt7663u_wr, .rmw = mt7663u_rmw, .read_copy = mt76u_read_copy, .write_copy = mt7663u_copy, .type = MT76_BUS_USB, }; struct usb_device *udev = interface_to_usbdev(usb_intf); struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; int ret; ops = devm_kmemdup(&usb_intf->dev, &mt7615_ops, sizeof(mt7615_ops), GFP_KERNEL); if (!ops) return -ENOMEM; ops->stop = mt7663u_stop; mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt7615_dev, mt76); udev = usb_get_dev(udev); usb_reset_device(udev); usb_set_intfdata(usb_intf, dev); INIT_WORK(&dev->mcu_work, mt7663u_init_work); dev->reg_map = mt7663_usb_sdio_reg_map; dev->ops = ops; ret = __mt76u_init(mdev, usb_intf, &bus_ops); if (ret < 0) 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); if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON, FW_STATE_PWR_ON << 1, 500)) { ret = mt7663u_mcu_power_on(dev); if (ret) goto error; } else { set_bit(MT76_STATE_POWER_OFF, &dev->mphy.state); } ret = mt76u_alloc_mcu_queue(&dev->mt76); if (ret) goto error; ret = mt76u_alloc_queues(&dev->mt76); if (ret) goto error; ret = mt7663_usb_sdio_register_device(dev); if (ret) goto error; return 0; error: mt76u_queues_deinit(&dev->mt76); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); mt76_free_device(&dev->mt76); return ret; } static void mt7663u_disconnect(struct usb_interface *usb_intf) { struct mt7615_dev *dev = usb_get_intfdata(usb_intf); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return; ieee80211_unregister_hw(dev->mt76.hw); mt7663u_cleanup(dev); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); mt76_free_device(&dev->mt76); } #ifdef CONFIG_PM static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state) { struct mt7615_dev *dev = usb_get_intfdata(intf); if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) { int err; - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true); if (err < 0) return err; } mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); return 0; } static int mt7663u_resume(struct usb_interface *intf) { struct mt7615_dev *dev = usb_get_intfdata(intf); int err; err = mt76u_vendor_request(&dev->mt76, MT_VEND_FEATURE_SET, USB_DIR_OUT | USB_TYPE_VENDOR, 0x5, 0x0, NULL, 0); if (err) return err; err = mt76u_resume_rx(&dev->mt76); if (err < 0) return err; if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev)) - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true); return err; } #endif /* CONFIG_PM */ MODULE_DEVICE_TABLE(usb, mt7615_device_table); MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); MODULE_FIRMWARE(MT7663_FIRMWARE_N9); MODULE_FIRMWARE(MT7663_ROM_PATCH); static struct usb_driver mt7663u_driver = { .name = KBUILD_MODNAME, .id_table = mt7615_device_table, .probe = mt7663u_probe, .disconnect = mt7663u_disconnect, #ifdef CONFIG_PM .suspend = mt7663u_suspend, .resume = mt7663u_resume, .reset_resume = mt7663u_resume, #endif /* CONFIG_PM */ .soft_unbind = 1, .disable_hub_initiated_lpm = 1, }; module_usb_driver(mt7663u_driver); MODULE_AUTHOR("Sean Wang "); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT7663U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/usb_mcu.c b/sys/contrib/dev/mediatek/mt76/mt7615/usb_mcu.c new file mode 100644 index 000000000000..33c01f8ce8e2 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7615/usb_mcu.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2019 MediaTek Inc. + * + * Author: Felix Fietkau + * Lorenzo Bianconi + * Sean Wang + */ +#include +#include + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +static int +mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *seq) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + int ret, ep, len, pad; + + mt7615_mcu_fill_msg(dev, skb, cmd, seq); + if (cmd != MCU_CMD(FW_SCATTER)) + ep = MT_EP_OUT_INBAND_CMD; + else + ep = MT_EP_OUT_AC_BE; + + len = skb->len; + put_unaligned_le32(len, skb_push(skb, sizeof(len))); + pad = round_up(skb->len, 4) + 4 - skb->len; + ret = mt76_skb_adjust_pad(skb, pad); + if (ret < 0) + goto out; + + ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, + 1000, ep); + +out: + dev_kfree_skb(skb); + + return ret; +} + +int mt7663u_mcu_power_on(struct mt7615_dev *dev) +{ + int ret; + + ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON, + USB_DIR_OUT | USB_TYPE_VENDOR, + 0x0, 0x1, NULL, 0); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_PWR_ON, + FW_STATE_PWR_ON << 1, 500)) { + dev_err(dev->mt76.dev, "Timeout for power on\n"); + ret = -EIO; + } + + return 0; +} + +int mt7663u_mcu_init(struct mt7615_dev *dev) +{ + static const struct mt76_mcu_ops mt7663u_mcu_ops = { + .headroom = MT_USB_HDR_SIZE + sizeof(struct mt7615_mcu_txd), + .tailroom = MT_USB_TAIL_SIZE, + .mcu_skb_send_msg = mt7663u_mcu_send_message, + .mcu_parse_response = mt7615_mcu_parse_response, + }; + int ret; + + dev->mt76.mcu_ops = &mt7663u_mcu_ops; + + mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); + if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { + ret = mt7615_mcu_restart(&dev->mt76); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_PWR_ON, 0, 500)) + return -EIO; + + ret = mt7663u_mcu_power_on(dev); + if (ret) + return ret; + } + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7615/usb_sdio.c b/sys/contrib/dev/mediatek/mt76/mt7615/usb_sdio.c index 0052d103e276..722418e9863c 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7615/usb_sdio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7615/usb_sdio.c @@ -1,352 +1,357 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * Author: Lorenzo Bianconi * Sean Wang */ #include #include #include #include "mt7615.h" #include "mac.h" #include "mcu.h" #include "regs.h" const u32 mt7663_usb_sdio_reg_map[] = { [MT_TOP_CFG_BASE] = 0x80020000, [MT_HW_BASE] = 0x80000000, [MT_DMA_SHDL_BASE] = 0x5000a000, [MT_HIF_BASE] = 0x50000000, [MT_CSR_BASE] = 0x40000000, [MT_EFUSE_ADDR_BASE] = 0x78011000, [MT_TOP_MISC_BASE] = 0x81020000, [MT_PLE_BASE] = 0x82060000, [MT_PSE_BASE] = 0x82068000, [MT_PP_BASE] = 0x8206c000, [MT_WTBL_BASE_ADDR] = 0x820e0000, [MT_CFG_BASE] = 0x820f0000, [MT_AGG_BASE] = 0x820f2000, [MT_ARB_BASE] = 0x820f3000, [MT_TMAC_BASE] = 0x820f4000, [MT_RMAC_BASE] = 0x820f5000, [MT_DMA_BASE] = 0x820f7000, [MT_PF_BASE] = 0x820f8000, [MT_WTBL_BASE_ON] = 0x820f9000, [MT_WTBL_BASE_OFF] = 0x820f9800, [MT_LPON_BASE] = 0x820fb000, [MT_MIB_BASE] = 0x820fd000, }; EXPORT_SYMBOL_GPL(mt7663_usb_sdio_reg_map); static void mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, enum mt76_txq_id qid, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, int pid, struct sk_buff *skb) { __le32 *txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); memset(txwi, 0, MT_USB_TXD_SIZE); mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, qid, false); skb_push(skb, MT_USB_TXD_SIZE); } static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, struct mt7615_wtbl_rate_desc *wrd) { struct mt7615_rate_desc *rate = &wrd->rate; struct mt7615_sta *sta = wrd->sta; u32 w5, w27, addr, val; u16 idx; lockdep_assert_held(&dev->mt76.mutex); if (!sta) return -EINVAL; if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) return -ETIMEDOUT; addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); w27 = mt76_rr(dev, addr + 27 * 4); w27 &= ~MT_WTBL_W27_CC_BW_SEL; w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); w5 = mt76_rr(dev, addr + 5 * 4); w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | MT_WTBL_W5_MPDU_OK_COUNT | MT_WTBL_W5_MPDU_FAIL_COUNT | MT_WTBL_W5_RATE_IDX); w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, rate->bw_idx ? rate->bw_idx - 1 : 7); mt76_wr(dev, MT_WTBL_RIUCR0, w5); mt76_wr(dev, MT_WTBL_RIUCR1, FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); mt76_wr(dev, MT_WTBL_RIUCR2, FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); mt76_wr(dev, MT_WTBL_RIUCR3, FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); mt76_wr(dev, MT_WTBL_UPDATE, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | MT_WTBL_UPDATE_RATE_UPDATE | MT_WTBL_UPDATE_TX_COUNT_CLEAR); mt76_wr(dev, addr + 27 * 4, w27); sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; idx = sta->vif->mt76.omac_idx; idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx; addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx); mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */ val = mt76_rr(dev, MT_LPON_UTTR0); sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; return 0; } static void mt7663_usb_sdio_rate_work(struct work_struct *work) { struct mt7615_wtbl_rate_desc *wrd, *wrd_next; struct list_head wrd_list; struct mt7615_dev *dev; dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, rate_work); INIT_LIST_HEAD(&wrd_list); spin_lock_bh(&dev->mt76.lock); list_splice_init(&dev->wrd_head, &wrd_list); spin_unlock_bh(&dev->mt76.lock); list_for_each_entry_safe(wrd, wrd_next, &wrd_list, node) { list_del(&wrd->node); mt7615_mutex_acquire(dev); mt7663_usb_sdio_set_rates(dev, wrd); mt7615_mutex_release(dev); kfree(wrd); } } bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); mt7615_mutex_acquire(dev); mt7615_mac_sta_poll(dev); mt7615_mutex_release(dev); return false; } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data); void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { unsigned int headroom = MT_USB_TXD_SIZE; if (mt76_is_usb(mdev)) headroom += MT_USB_HDR_SIZE; skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb); int mt7663_usb_sdio_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 mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct sk_buff *skb = tx_info->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_key_conf *key = info->control.hw_key; struct mt7615_sta *msta; int pad, err, pktid; msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; if (!wcid) wcid = &dev->mt76.global_wcid; if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && msta && !msta->rate_probe) { /* request to configure sampling rate */ spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], msta->rates); spin_unlock_bh(&dev->mt76.lock); } pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb); if (mt76_is_usb(mdev)) { u32 len = skb->len; put_unaligned_le32(len, skb_push(skb, sizeof(len))); pad = round_up(skb->len, 4) + 4 - skb->len; } else { pad = round_up(skb->len, 4) - skb->len; } err = mt76_skb_adjust_pad(skb, pad); if (err) /* Release pktid in case of error. */ idr_remove(&wcid->pktid, pktid); return err; } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb); static int mt7663u_dma_sched_init(struct mt7615_dev *dev) { int i; mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); /* disable refill group 5 - group 15 and raise group 2 * and 3 as high priority. */ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); for (i = 0; i < 5; i++) mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); /* group pririority from high to low: * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. */ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); mt76_wr(dev, MT_UDMA_WLCFG_1, FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); /* setup UDMA Rx Flush */ mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); /* hif reset */ mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | MT_WL_TX_TMOUT_FUNC_EN); mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | FIELD_PREP(MT_WL_RX_AGG_TO, 100)); return 0; } static int mt7663_usb_sdio_init_hardware(struct mt7615_dev *dev) { int ret, idx; ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); if (ret < 0) return ret; if (mt76_is_usb(&dev->mt76)) { ret = mt7663u_dma_sched_init(dev); if (ret) return ret; } set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); if (idx) return -ENOSPC; dev->mt76.global_wcid.idx = idx; dev->mt76.global_wcid.hw_key_idx = -1; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); return 0; } int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); int err; INIT_WORK(&dev->rate_work, mt7663_usb_sdio_rate_work); INIT_LIST_HEAD(&dev->wrd_head); mt7615_init_device(dev); err = mt7663_usb_sdio_init_hardware(dev); if (err) return err; hw->extra_tx_headroom += MT_USB_TXD_SIZE; if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += MT_USB_HDR_SIZE; /* check hw sg support in order to enable AMSDU */ if (dev->mt76.usb.sg_en) hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM; else hw->max_tx_fragments = 1; } err = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (err < 0) return err; if (!dev->mt76.usb.sg_en) { struct ieee80211_sta_vht_cap *vht_cap; /* decrease max A-MSDU size if SG is not supported */ vht_cap = &dev->mphy.sband_5g.sband.vht_cap; vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; } ieee80211_queue_work(hw, &dev->mcu_work); mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); +#if defined(CONFIG_MT7615_DEBUGFS) return mt7615_init_debugfs(dev); +#else + return 0; +#endif } EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_AUTHOR("Sean Wang "); +MODULE_DESCRIPTION("MediaTek MT7663 SDIO/USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac.h b/sys/contrib/dev/mediatek/mt76/mt76_connac.h index 22878f088804..455979476d11 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac.h +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac.h @@ -1,431 +1,456 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT76_CONNAC_H #define __MT76_CONNAC_H #include "mt76.h" enum rx_pkt_type { PKT_TYPE_TXS, PKT_TYPE_TXRXV, PKT_TYPE_NORMAL, PKT_TYPE_RX_DUP_RFB, PKT_TYPE_RX_TMR, PKT_TYPE_RETRIEVE, PKT_TYPE_TXRX_NOTIFY, PKT_TYPE_RX_EVENT, PKT_TYPE_NORMAL_MCU, PKT_TYPE_RX_FW_MONITOR = 0x0c, PKT_TYPE_TXRX_NOTIFY_V0 = 0x18, }; #define MT76_CONNAC_SCAN_IE_LEN 600 #define MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL 10 #define MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL U16_MAX #define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10 #define MT76_CONNAC_MAX_SCAN_MATCH 16 #define MT76_CONNAC_MAX_WMM_SETS 4 #define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20) #define MT76_CONNAC_COREDUMP_SZ (1300 * 1024) #define MT_TXD_SIZE (8 * 4) #define MT_USB_TXD_SIZE (MT_TXD_SIZE + 8 * 4) #define MT_USB_HDR_SIZE 4 #define MT_USB_TAIL_SIZE 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_MSDU_ID_VALID BIT(15) #define MT_TXD_LEN_LAST BIT(15) #define MT_TXD_LEN_MASK GENMASK(11, 0) #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80, CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160, CMD_CBW_10MHZ, CMD_CBW_5MHZ, CMD_CBW_8080MHZ, CMD_CBW_320MHZ, CMD_HE_MCS_BW80 = 0, CMD_HE_MCS_BW160, CMD_HE_MCS_BW8080, CMD_HE_MCS_BW_NUM }; enum { HW_BSSID_0 = 0x0, HW_BSSID_1, HW_BSSID_2, HW_BSSID_3, HW_BSSID_MAX = HW_BSSID_3, EXT_BSSID_START = 0x10, EXT_BSSID_1, EXT_BSSID_15 = 0x1f, EXT_BSSID_MAX = EXT_BSSID_15, REPEATER_BSSID_START = 0x20, REPEATER_BSSID_MAX = 0x3f, }; struct mt76_connac_reg_map { u32 phys; u32 maps; u32 size; }; struct mt76_connac_pm { bool enable:1; bool enable_user:1; bool ds_enable:1; bool ds_enable_user:1; bool suspended:1; spinlock_t txq_lock; struct { struct mt76_wcid *wcid; struct sk_buff *skb; } tx_q[IEEE80211_NUM_ACS]; struct work_struct wake_work; wait_queue_head_t wait; struct { spinlock_t lock; u32 count; } wake; struct mutex mutex; struct delayed_work ps_work; unsigned long last_activity; unsigned long idle_timeout; struct { unsigned long last_wake_event; unsigned long awake_time; unsigned long last_doze_event; unsigned long doze_time; unsigned int lp_wake; } stats; }; struct mt76_connac_coredump { struct sk_buff_head msg_list; struct delayed_work work; unsigned long last_activity; }; struct mt76_connac_sta_key_conf { s8 keyidx; u8 key[16]; }; #define MT_TXP_MAX_BUF_NUM 6 struct mt76_connac_fw_txp { __le16 flags; __le16 token; u8 bss_idx; __le16 rept_wds_wcid; u8 nbuf; __le32 buf[MT_TXP_MAX_BUF_NUM]; __le16 len[MT_TXP_MAX_BUF_NUM]; } __packed __aligned(4); #define MT_HW_TXP_MAX_MSDU_NUM 4 #define MT_HW_TXP_MAX_BUF_NUM 4 struct mt76_connac_txp_ptr { __le32 buf0; __le16 len0; __le16 len1; __le32 buf1; } __packed __aligned(4); struct mt76_connac_hw_txp { __le16 msdu_id[MT_HW_TXP_MAX_MSDU_NUM]; struct mt76_connac_txp_ptr ptr[MT_HW_TXP_MAX_BUF_NUM / 2]; } __packed __aligned(4); struct mt76_connac_txp_common { union { struct mt76_connac_fw_txp fw; struct mt76_connac_hw_txp hw; }; }; struct mt76_connac_tx_free { __le16 rx_byte_cnt; __le16 ctrl; __le32 txd; } __packed __aligned(4); extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; +static inline bool is_mt7925(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7925; +} + +static inline bool is_mt7920(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7920; +} + 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 || is_mt7922(dev); + return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev); } static inline bool is_mt7663(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7663; } static inline bool is_mt7915(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7915; } static inline bool is_mt7916(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7906; } static inline bool is_mt7981(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7981; } static inline bool is_mt7986(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7986; } static inline bool is_mt798x(struct mt76_dev *dev) { return is_mt7981(dev) || is_mt7986(dev); } static inline bool is_mt7996(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7990; } +static inline bool is_mt7992(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7992; +} + +static inline bool is_mt799x(struct mt76_dev *dev) +{ + return is_mt7996(dev) || is_mt7992(dev); +} + static inline bool is_mt7622(struct mt76_dev *dev) { if (!IS_ENABLED(CONFIG_MT7622_WMAC)) return false; return mt76_chip(dev) == 0x7622; } static inline bool is_mt7615(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7615 || mt76_chip(dev) == 0x7611; } static inline bool is_mt7611(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7611; } static inline bool is_connac_v1(struct mt76_dev *dev) { return is_mt7615(dev) || is_mt7663(dev) || is_mt7622(dev); } static inline bool is_mt76_fw_txp(struct mt76_dev *dev) { switch (mt76_chip(dev)) { case 0x7961: + case 0x7920: case 0x7922: + case 0x7925: case 0x7663: case 0x7622: return false; default: return true; } } static inline u8 mt76_connac_chan_bw(struct cfg80211_chan_def *chandef) { static const u8 width_to_bw[] = { [NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ, [NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ, [NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ, [NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ, [NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ, [NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ, [NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ, [NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ, [NL80211_CHAN_WIDTH_320] = CMD_CBW_320MHZ, }; if (chandef->width >= ARRAY_SIZE(width_to_bw)) return 0; return width_to_bw[chandef->width]; } static inline u8 mt76_connac_lmac_mapping(u8 ac) { /* LMAC uses the reverse order of mac80211 AC indexes */ return 3 - ac; } static inline void * mt76_connac_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) { u8 *txwi; if (!t) return NULL; txwi = mt76_get_txwi_ptr(dev, t); return (void *)(txwi + MT_TXD_SIZE); } static inline u8 mt76_connac_spe_idx(u8 antenna_mask) { static const u8 ant_to_spe[] = {0, 0, 1, 0, 3, 2, 4, 0, 9, 8, 6, 10, 16, 12, 18, 0}; if (antenna_mask >= sizeof(ant_to_spe)) return 0; return ant_to_spe[antenna_mask]; } static inline void mt76_connac_irq_enable(struct mt76_dev *dev, u32 mask) { mt76_set_irq_mask(dev, 0, 0, mask); tasklet_schedule(&dev->irq_tasklet); } int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm); void mt76_connac_power_save_sched(struct mt76_phy *phy, struct mt76_connac_pm *pm); void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, struct mt76_wcid *wcid); static inline void mt76_connac_tx_cleanup(struct mt76_dev *dev) { dev->queue_ops->tx_cleanup(dev, dev->q_mcu[MT_MCUQ_WM], false); dev->queue_ops->tx_cleanup(dev, dev->q_mcu[MT_MCUQ_WA], false); } static inline bool mt76_connac_pm_ref(struct mt76_phy *phy, struct mt76_connac_pm *pm) { bool ret = false; spin_lock_bh(&pm->wake.lock); if (test_bit(MT76_STATE_PM, &phy->state)) goto out; pm->wake.count++; ret = true; out: spin_unlock_bh(&pm->wake.lock); return ret; } static inline void mt76_connac_pm_unref(struct mt76_phy *phy, struct mt76_connac_pm *pm) { spin_lock_bh(&pm->wake.lock); pm->last_activity = jiffies; if (--pm->wake.count == 0 && test_bit(MT76_STATE_MCU_RUNNING, &phy->state)) mt76_connac_power_save_sched(phy, pm); spin_unlock_bh(&pm->wake.lock); } static inline bool mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm) { struct mt76_dev *dev = phy->dev; bool ret; if (dev->token_count) return true; spin_lock_bh(&pm->wake.lock); ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state); spin_unlock_bh(&pm->wake.lock); return ret; } static inline void mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm) __acquires(&dev->mutex) { mutex_lock(&dev->mutex); mt76_connac_pm_wake(&dev->phy, pm); } static inline void mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) __releases(&dev->mutex) { mt76_connac_power_save_sched(&dev->phy, pm); mutex_unlock(&dev->mutex); } -void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss); +void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss, enum nl80211_band band); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); + void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); void mt76_connac_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, struct mt76_connac_pm *pm, struct mt76_wcid *wcid, struct sk_buff *skb); void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, struct mt76_connac_pm *pm); void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, bool beacon, bool mcast); bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid, __le32 *txs_data); bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data); void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, struct sk_buff *skb, __le32 *rxv, u32 mode); int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, struct sk_buff *skb, u16 hdr_offset); int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, struct mt76_rx_status *status, struct ieee80211_supported_band *sband, __le32 *rxv, u8 *mode); void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi); void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, struct list_head *free_list); void mt76_connac2_tx_token_put(struct mt76_dev *dev); /* connac3 */ void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode); +void mt76_connac3_mac_decode_eht_radiotap(struct sk_buff *skb, __le32 *rxv, + u8 mode); #endif /* __MT76_CONNAC_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac2_mac.h b/sys/contrib/dev/mediatek/mt76/mt76_connac2_mac.h index bd2a92467a97..eb4765365b8c 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac2_mac.h +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac2_mac.h @@ -1,353 +1,365 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2022 MediaTek Inc. */ #ifndef __MT76_CONNAC2_MAC_H #define __MT76_CONNAC2_MAC_H enum tx_header_format { MT_HDR_FORMAT_802_3, MT_HDR_FORMAT_CMD, MT_HDR_FORMAT_802_11, MT_HDR_FORMAT_802_11_EXT, }; enum tx_pkt_type { MT_TX_TYPE_CT, MT_TX_TYPE_SF, MT_TX_TYPE_CMD, MT_TX_TYPE_FW, }; enum { 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 { + MT_TXS_MPDU_FMT = 0, + MT_TXS_PPDU_FMT = 2, +}; + #define MT_TX_FREE_MSDU_CNT GENMASK(9, 0) #define MT_TX_FREE_WLAN_ID GENMASK(23, 14) #define MT_TX_FREE_COUNT GENMASK(12, 0) /* 0: success, others: dropped */ #define MT_TX_FREE_STATUS GENMASK(14, 13) #define MT_TX_FREE_MSDU_ID GENMASK(30, 16) #define MT_TX_FREE_PAIR BIT(31) /* will support this field in further revision */ #define MT_TX_FREE_RATE GENMASK(13, 0) #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) #define MT_TXD0_TX_BYTES GENMASK(15, 0) #define MT_TXD1_LONG_FORMAT BIT(31) #define MT_TXD1_TGID BIT(30) #define MT_TXD1_OWN_MAC GENMASK(29, 24) #define MT_TXD1_AMSDU BIT(23) #define MT_TXD1_TID GENMASK(22, 20) #define MT_TXD1_HDR_PAD GENMASK(19, 18) #define MT_TXD1_HDR_FORMAT GENMASK(17, 16) #define MT_TXD1_HDR_INFO GENMASK(15, 11) #define MT_TXD1_ETH_802_3 BIT(15) #define MT_TXD1_VTA BIT(10) #define MT_TXD1_WLAN_IDX GENMASK(9, 0) #define MT_TXD2_FIX_RATE BIT(31) #define MT_TXD2_FIXED_RATE BIT(30) #define MT_TXD2_POWER_OFFSET GENMASK(29, 24) #define MT_TXD2_MAX_TX_TIME GENMASK(23, 16) #define MT_TXD2_FRAG GENMASK(15, 14) #define MT_TXD2_HTC_VLD BIT(13) #define MT_TXD2_DURATION BIT(12) #define MT_TXD2_BIP BIT(11) #define MT_TXD2_MULTICAST BIT(10) #define MT_TXD2_RTS BIT(9) #define MT_TXD2_SOUNDING BIT(8) #define MT_TXD2_NDPA BIT(7) #define MT_TXD2_NDP BIT(6) #define MT_TXD2_FRAME_TYPE GENMASK(5, 4) #define MT_TXD2_SUB_TYPE GENMASK(3, 0) #define MT_TXD3_SN_VALID BIT(31) #define MT_TXD3_PN_VALID BIT(30) #define MT_TXD3_SW_POWER_MGMT BIT(29) #define MT_TXD3_BA_DISABLE BIT(28) #define MT_TXD3_SEQ GENMASK(27, 16) #define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) #define MT_TXD3_TX_COUNT GENMASK(10, 6) #define MT_TXD3_TIMING_MEASURE BIT(5) #define MT_TXD3_DAS BIT(4) #define MT_TXD3_EEOSP BIT(3) #define MT_TXD3_EMRD BIT(2) #define MT_TXD3_PROTECT_FRAME BIT(1) #define MT_TXD3_NO_ACK BIT(0) #define MT_TXD4_PN_LOW GENMASK(31, 0) #define MT_TXD5_PN_HIGH GENMASK(31, 16) #define MT_TXD5_MD BIT(15) #define MT_TXD5_ADD_BA BIT(14) #define MT_TXD5_TX_STATUS_HOST BIT(10) #define MT_TXD5_TX_STATUS_MCU BIT(9) #define MT_TXD5_TX_STATUS_FMT BIT(8) #define MT_TXD5_PID GENMASK(7, 0) #define MT_TXD6_TX_IBF BIT(31) #define MT_TXD6_TX_EBF BIT(30) #define MT_TXD6_TX_RATE GENMASK(29, 16) #define MT_TXD6_SGI GENMASK(15, 14) #define MT_TXD6_HELTF GENMASK(13, 12) #define MT_TXD6_LDPC BIT(11) #define MT_TXD6_SPE_ID_IDX BIT(10) #define MT_TXD6_ANT_ID GENMASK(7, 4) #define MT_TXD6_DYN_BW BIT(3) #define MT_TXD6_FIXED_BW BIT(2) #define MT_TXD6_BW GENMASK(1, 0) #define MT_TXD7_TXD_LEN GENMASK(31, 30) #define MT_TXD7_UDP_TCP_SUM BIT(29) #define MT_TXD7_IP_SUM BIT(28) #define MT_TXD7_TYPE GENMASK(21, 20) #define MT_TXD7_SUB_TYPE GENMASK(19, 16) #define MT_TXD7_PSE_FID GENMASK(27, 16) #define MT_TXD7_SPE_IDX GENMASK(15, 11) #define MT_TXD7_HW_AMSDU BIT(10) #define MT_TXD7_TX_TIME GENMASK(9, 0) #define MT_TXD8_L_TYPE GENMASK(5, 4) #define MT_TXD8_L_SUB_TYPE GENMASK(3, 0) #define MT_TX_RATE_STBC BIT(13) #define MT_TX_RATE_NSS GENMASK(12, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) #define MT_TX_RATE_SU_EXT_TONE BIT(5) #define MT_TX_RATE_DCM BIT(4) /* VHT/HE only use bits 0-3 */ #define MT_TX_RATE_IDX GENMASK(5, 0) #define MT_TXS0_FIXED_RATE BIT(31) #define MT_TXS0_BW GENMASK(30, 29) #define MT_TXS0_TID GENMASK(28, 26) #define MT_TXS0_AMPDU BIT(25) #define MT_TXS0_TXS_FORMAT GENMASK(24, 23) #define MT_TXS0_BA_ERROR BIT(22) #define MT_TXS0_PS_FLAG BIT(21) #define MT_TXS0_TXOP_TIMEOUT BIT(20) #define MT_TXS0_BIP_ERROR BIT(19) #define MT_TXS0_QUEUE_TIMEOUT BIT(18) #define MT_TXS0_RTS_TIMEOUT BIT(17) #define MT_TXS0_ACK_TIMEOUT BIT(16) #define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) #define MT_TXS0_TX_STATUS_HOST BIT(15) #define MT_TXS0_TX_STATUS_MCU BIT(14) #define MT_TXS0_TX_RATE GENMASK(13, 0) #define MT_TXS1_SEQNO GENMASK(31, 20) #define MT_TXS1_RESP_RATE GENMASK(19, 16) #define MT_TXS1_RXV_SEQNO GENMASK(15, 8) #define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) #define MT_TXS2_BF_STATUS GENMASK(31, 30) #define MT_TXS2_LAST_TX_RATE GENMASK(29, 27) #define MT_TXS2_SHARED_ANTENNA BIT(26) #define MT_TXS2_WCID GENMASK(25, 16) #define MT_TXS2_TX_DELAY GENMASK(15, 0) #define MT_TXS3_PID GENMASK(31, 24) #define MT_TXS3_ANT_ID GENMASK(23, 0) #define MT_TXS4_TIMESTAMP GENMASK(31, 0) /* PPDU based TXS */ #define MT_TXS5_MPDU_TX_BYTE GENMASK(22, 0) #define MT_TXS5_MPDU_TX_CNT GENMASK(31, 23) #define MT_TXS6_MPDU_FAIL_CNT GENMASK(31, 23) #define MT_TXS7_MPDU_RETRY_BYTE GENMASK(22, 0) #define MT_TXS7_MPDU_RETRY_CNT GENMASK(31, 23) /* RXD DW0 */ #define MT_RXD0_LENGTH GENMASK(15, 0) #define MT_RXD0_PKT_FLAG GENMASK(19, 16) #define MT_RXD0_PKT_TYPE GENMASK(31, 27) #define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) #define MT_RXD0_NORMAL_IP_SUM BIT(23) #define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) /* RXD DW1 */ #define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0) #define MT_RXD1_NORMAL_GROUP_1 BIT(11) #define MT_RXD1_NORMAL_GROUP_2 BIT(12) #define MT_RXD1_NORMAL_GROUP_3 BIT(13) #define MT_RXD1_NORMAL_GROUP_4 BIT(14) #define MT_RXD1_NORMAL_GROUP_5 BIT(15) #define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16) #define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) #define MT_RXD1_NORMAL_CM BIT(23) #define MT_RXD1_NORMAL_CLM BIT(24) #define MT_RXD1_NORMAL_ICV_ERR BIT(25) #define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) #define MT_RXD1_NORMAL_FCS_ERR BIT(27) #define MT_RXD1_NORMAL_BAND_IDX BIT(28) #define MT_RXD1_NORMAL_SPP_EN BIT(29) #define MT_RXD1_NORMAL_ADD_OM BIT(30) #define MT_RXD1_NORMAL_SEC_DONE BIT(31) /* RXD DW2 */ #define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) #define MT_RXD2_NORMAL_CO_ANT BIT(6) #define MT_RXD2_NORMAL_BF_CQI BIT(7) #define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) #define MT_RXD2_NORMAL_HDR_TRANS BIT(13) #define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14) #define MT_RXD2_NORMAL_TID GENMASK(19, 16) #define MT_RXD2_NORMAL_MU_BAR BIT(21) #define MT_RXD2_NORMAL_SW_BIT BIT(22) #define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) #define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) #define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) #define MT_RXD2_NORMAL_INT_FRAME BIT(26) #define MT_RXD2_NORMAL_FRAG BIT(27) #define MT_RXD2_NORMAL_NULL_FRAME BIT(28) #define MT_RXD2_NORMAL_NDATA BIT(29) #define MT_RXD2_NORMAL_NON_AMPDU BIT(30) #define MT_RXD2_NORMAL_BF_REPORT BIT(31) /* RXD DW4 */ #define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) #define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) #define MT_RXD4_MID_AMSDU_FRAME BIT(1) #define MT_RXD4_LAST_AMSDU_FRAME BIT(0) #define MT_RXD4_NORMAL_PATTERN_DROP BIT(9) #define MT_RXD4_NORMAL_CLS BIT(10) #define MT_RXD4_NORMAL_OFLD GENMASK(12, 11) #define MT_RXD4_NORMAL_MAGIC_PKT BIT(13) #define MT_RXD4_NORMAL_WOL GENMASK(18, 14) #define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19) #define MT_RXD3_NORMAL_PF_MODE BIT(29) #define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30) #define MT_RXV_HDR_BAND_IDX BIT(24) /* RXD DW3 */ #define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) #define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) #define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) #define MT_RXD3_NORMAL_U2M BIT(0) #define MT_RXD3_NORMAL_HTC_VLD BIT(0) #define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19) #define MT_RXD3_NORMAL_BEACON_MC BIT(20) #define MT_RXD3_NORMAL_BEACON_UC BIT(21) #define MT_RXD3_NORMAL_AMSDU BIT(22) #define MT_RXD3_NORMAL_MESH BIT(23) #define MT_RXD3_NORMAL_MHCP BIT(24) #define MT_RXD3_NORMAL_NO_INFO_WB BIT(25) #define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26) #define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27) #define MT_RXD3_NORMAL_MORE BIT(28) #define MT_RXD3_NORMAL_UNWANT BIT(29) #define MT_RXD3_NORMAL_RX_DROP BIT(30) #define MT_RXD3_NORMAL_VLAN2ETH BIT(31) /* RXD GROUP4 */ #define MT_RXD6_FRAME_CONTROL GENMASK(15, 0) #define MT_RXD6_TA_LO GENMASK(31, 16) #define MT_RXD7_TA_HI GENMASK(31, 0) #define MT_RXD8_SEQ_CTRL GENMASK(15, 0) #define MT_RXD8_QOS_CTL GENMASK(31, 16) #define MT_RXD9_HT_CONTROL GENMASK(31, 0) /* P-RXV DW0 */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #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_FRAME_MODE GENMASK(14, 12) #define MT_PRXV_HT_SGI GENMASK(16, 15) #define MT_PRXV_HT_STBC GENMASK(23, 22) #define MT_PRXV_TX_MODE GENMASK(27, 24) #define MT_PRXV_DCM BIT(17) #define MT_PRXV_NUM_RX BIT(20, 18) /* P-RXV DW1 */ #define MT_PRXV_RCPI3 GENMASK(31, 24) #define MT_PRXV_RCPI2 GENMASK(23, 16) #define MT_PRXV_RCPI1 GENMASK(15, 8) #define MT_PRXV_RCPI0 GENMASK(7, 0) #define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0) /* C-RXV */ #define MT_CRXV_HT_STBC GENMASK(1, 0) #define MT_CRXV_TX_MODE GENMASK(7, 4) #define MT_CRXV_FRAME_MODE GENMASK(10, 8) #define MT_CRXV_HT_SHORT_GI GENMASK(14, 13) #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) #define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) #define MT_CRXV_HE_BSS_COLOR GENMASK(5, 0) #define MT_CRXV_HE_TXOP_DUR GENMASK(12, 6) #define MT_CRXV_HE_BEAM_CHNG BIT(13) #define MT_CRXV_HE_DOPPLER BIT(16) #define MT_CRXV_SNR GENMASK(18, 13) #define MT_CRXV_FOE_LO GENMASK(31, 19) #define MT_CRXV_FOE_HI GENMASK(6, 0) #define MT_CRXV_FOE_SHIFT 13 #define MT_CT_PARSE_LEN 72 #define MT_CT_DMA_BUF_NUM 2 #define MT_CT_INFO_APPLY_TXD BIT(0) #define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) #define MT_CT_INFO_MGMT_FRAME BIT(2) #define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) #define MT_CT_INFO_HSR2_TX BIT(4) #define MT_CT_INFO_FROM_HOST BIT(7) enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_Q0 = 0x20, MT_TX_MCU_PORT_RX_Q1, MT_TX_MCU_PORT_RX_Q2, MT_TX_MCU_PORT_RX_Q3, MT_TX_MCU_PORT_RX_FWDL = 0x3e }; enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU }; +enum tx_frag_idx { + MT_TX_FRAG_NONE, + MT_TX_FRAG_FIRST, + MT_TX_FRAG_MID, + MT_TX_FRAG_LAST +}; + #endif /* __MT76_CONNAC2_MAC_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.c b/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.c index 73e9f283d0ae..2d300948308d 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.c @@ -1,182 +1,268 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. */ #include "mt76_connac.h" #include "mt76_connac3_mac.h" #include "dma.h" #define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) +#define EHT_BITS(f) cpu_to_le32(IEEE80211_RADIOTAP_EHT_##f) #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ IEEE80211_RADIOTAP_HE_##f) +#define EHT_PREP(f, m, v) le32_encode_bits(le32_get_bits(v, MT_CRXV_EHT_##m),\ + IEEE80211_RADIOTAP_EHT_##f) static void mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, struct ieee80211_radiotap_he *he, __le32 *rxv) { u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0; status->bw = RATE_INFO_BW_HE_RU; switch (ru) { case 0 ... 36: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; offs = ru; break; case 37 ... 52: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; offs = ru - 37; break; case 53 ... 60: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; offs = ru - 53; break; case 61 ... 64: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; offs = ru - 61; break; case 65 ... 66: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; offs = ru - 65; break; case 67: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; break; case 68: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; break; } he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | le16_encode_bits(offs, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); } #define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f) static void mt76_connac3_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 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; status->flag |= RX_FLAG_RADIOTAP_HE_MU; he_mu = skb_push(skb, sizeof(mu_known)); memcpy(he_mu, &mu_known, sizeof(mu_known)); 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[4], MT_CRXV_HE_NUM_USER)); he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff; 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[16], MT_CRXV_HE_RU1) & 0xff; } if (status->bw >= RATE_INFO_BW_80) { u32 ru_h, ru_l; he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff; ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L); ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7; he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4); } } void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; static const struct ieee80211_radiotap_he known = { .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | HE_BITS(DATA1_DATA_DCM_KNOWN) | HE_BITS(DATA1_STBC_KNOWN) | 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) | HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | HE_BITS(DATA2_TXOP_KNOWN), }; u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1; struct ieee80211_radiotap_he *he; status->flag |= RX_FLAG_RADIOTAP_HE; he = skb_push(skb, sizeof(known)); memcpy(he, &known, sizeof(known)); he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) | HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]); he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]); he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) | 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[9]) | HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]); switch (mode) { 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_BW_RU_ALLOC_KNOWN); he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) | HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]); break; case MT_PHY_TYPE_HE_EXT_SU: he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]); break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | HE_BITS(DATA1_UL_DL_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]); he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]); mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv); mt76_connac3_mac_decode_he_mu_radiotap(skb, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | 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[13]) | HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) | HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) | HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]); mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv); break; default: break; } } EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap); + +static void * +mt76_connac3_mac_radiotap_push_tlv(struct sk_buff *skb, u16 type, u16 len) +{ + struct ieee80211_radiotap_tlv *tlv; + + tlv = skb_push(skb, sizeof(*tlv) + len); + tlv->type = cpu_to_le16(type); + tlv->len = cpu_to_le16(len); + memset(tlv->data, 0, len); + + return tlv->data; +} + +void mt76_connac3_mac_decode_eht_radiotap(struct sk_buff *skb, __le32 *rxv, + u8 mode) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ieee80211_radiotap_eht_usig *usig; + struct ieee80211_radiotap_eht *eht; + u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1; + u8 bw = FIELD_GET(MT_PRXV_FRAME_MODE, le32_to_cpu(rxv[2])); + + if (WARN_ONCE(skb_mac_header(skb) != skb->data, + "Should push tlv at the top of mac hdr")) + return; + + eht = mt76_connac3_mac_radiotap_push_tlv(skb, IEEE80211_RADIOTAP_EHT, + sizeof(*eht) + sizeof(u32)); + usig = mt76_connac3_mac_radiotap_push_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, + sizeof(*usig)); + + status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END; + + eht->known |= EHT_BITS(KNOWN_SPATIAL_REUSE) | + EHT_BITS(KNOWN_GI) | + EHT_BITS(KNOWN_EHT_LTF) | + EHT_BITS(KNOWN_LDPC_EXTRA_SYM_OM) | + EHT_BITS(KNOWN_PE_DISAMBIGUITY_OM) | + EHT_BITS(KNOWN_NSS_S); + + eht->data[0] |= + EHT_PREP(DATA0_SPATIAL_REUSE, SR_MASK, rxv[13]) | + cpu_to_le32(FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_GI, status->eht.gi) | + FIELD_PREP(IEEE80211_RADIOTAP_EHT_DATA0_LTF, ltf_size)) | + EHT_PREP(DATA0_PE_DISAMBIGUITY_OM, PE_DISAMBIG, rxv[5]) | + EHT_PREP(DATA0_LDPC_EXTRA_SYM_OM, LDPC_EXT_SYM, rxv[4]); + + /* iwlwifi and wireshark expect radiotap to report zero-based NSS, so subtract 1. */ + eht->data[7] |= le32_encode_bits(status->nss - 1, IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); + + eht->user_info[0] |= + EHT_BITS(USER_INFO_MCS_KNOWN) | + EHT_BITS(USER_INFO_CODING_KNOWN) | + EHT_BITS(USER_INFO_NSS_KNOWN_O) | + EHT_BITS(USER_INFO_BEAMFORMING_KNOWN_O) | + EHT_BITS(USER_INFO_DATA_FOR_USER) | + le32_encode_bits(status->rate_idx, IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) | + le32_encode_bits(status->nss - 1, IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O); + + if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) + eht->user_info[0] |= EHT_BITS(USER_INFO_BEAMFORMING_O); + + if (le32_to_cpu(rxv[0]) & MT_PRXV_HT_AD_CODE) + eht->user_info[0] |= EHT_BITS(USER_INFO_CODING); + + if (mode == MT_PHY_TYPE_EHT_MU) + eht->user_info[0] |= EHT_BITS(USER_INFO_STA_ID_KNOWN) | + EHT_PREP(USER_INFO_STA_ID, MU_AID, rxv[8]); + + usig->common |= + EHT_BITS(USIG_COMMON_PHY_VER_KNOWN) | + EHT_BITS(USIG_COMMON_BW_KNOWN) | + EHT_BITS(USIG_COMMON_UL_DL_KNOWN) | + EHT_BITS(USIG_COMMON_BSS_COLOR_KNOWN) | + EHT_BITS(USIG_COMMON_TXOP_KNOWN) | + le32_encode_bits(0, IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER) | + le32_encode_bits(bw, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW) | + EHT_PREP(USIG_COMMON_UL_DL, UPLINK, rxv[5]) | + EHT_PREP(USIG_COMMON_BSS_COLOR, BSS_COLOR, rxv[9]) | + EHT_PREP(USIG_COMMON_TXOP, TXOP_DUR, rxv[9]); +} +EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_eht_radiotap); diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.h b/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.h index 68ca0844cbbf..db0c29e65185 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.h +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac3_mac.h @@ -1,339 +1,389 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT76_CONNAC3_MAC_H #define __MT76_CONNAC3_MAC_H enum { 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, }; #define MT_CT_PARSE_LEN 72 #define MT_CT_DMA_BUF_NUM 2 #define MT_RXD0_LENGTH GENMASK(15, 0) #define MT_RXD0_PKT_FLAG GENMASK(19, 16) #define MT_RXD0_PKT_TYPE GENMASK(31, 27) #define MT_RXD0_MESH BIT(18) #define MT_RXD0_MHCP BIT(19) #define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16) -#define MT_RXD0_NORMAL_IP_SUM BIT(23) -#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24) #define MT_RXD0_SW_PKT_TYPE_MASK GENMASK(31, 16) #define MT_RXD0_SW_PKT_TYPE_MAP 0x380F #define MT_RXD0_SW_PKT_TYPE_FRAME 0x3801 /* RXD DW1 */ #define MT_RXD1_NORMAL_WLAN_IDX GENMASK(11, 0) #define MT_RXD1_NORMAL_GROUP_1 BIT(16) #define MT_RXD1_NORMAL_GROUP_2 BIT(17) #define MT_RXD1_NORMAL_GROUP_3 BIT(18) #define MT_RXD1_NORMAL_GROUP_4 BIT(19) #define MT_RXD1_NORMAL_GROUP_5 BIT(20) #define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21) #define MT_RXD1_NORMAL_CM BIT(23) #define MT_RXD1_NORMAL_CLM BIT(24) #define MT_RXD1_NORMAL_ICV_ERR BIT(25) #define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26) #define MT_RXD1_NORMAL_BAND_IDX GENMASK(28, 27) #define MT_RXD1_NORMAL_SPP_EN BIT(29) #define MT_RXD1_NORMAL_ADD_OM BIT(30) #define MT_RXD1_NORMAL_SEC_DONE BIT(31) /* RXD DW2 */ #define MT_RXD2_NORMAL_BSSID GENMASK(5, 0) #define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8) #define MT_RXD2_NORMAL_HDR_TRANS BIT(7) #define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 13) #define MT_RXD2_NORMAL_SEC_MODE GENMASK(20, 16) #define MT_RXD2_NORMAL_MU_BAR BIT(21) #define MT_RXD2_NORMAL_SW_BIT BIT(22) #define MT_RXD2_NORMAL_AMSDU_ERR BIT(23) #define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24) #define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25) #define MT_RXD2_NORMAL_INT_FRAME BIT(26) #define MT_RXD2_NORMAL_FRAG BIT(27) #define MT_RXD2_NORMAL_NULL_FRAME BIT(28) #define MT_RXD2_NORMAL_NDATA BIT(29) #define MT_RXD2_NORMAL_NON_AMPDU BIT(30) #define MT_RXD2_NORMAL_BF_REPORT BIT(31) /* RXD DW3 */ #define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0) #define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8) #define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16) #define MT_RXD3_NORMAL_U2M BIT(0) #define MT_RXD3_NORMAL_HTC_VLD BIT(18) #define MT_RXD3_NORMAL_BEACON_MC BIT(20) #define MT_RXD3_NORMAL_BEACON_UC BIT(21) #define MT_RXD3_NORMAL_CO_ANT BIT(22) #define MT_RXD3_NORMAL_FCS_ERR BIT(24) +#define MT_RXD3_NORMAL_IP_SUM BIT(26) +#define MT_RXD3_NORMAL_UDP_TCP_SUM BIT(27) #define MT_RXD3_NORMAL_VLAN2ETH BIT(31) /* RXD DW4 */ #define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0) #define MT_RXD4_FIRST_AMSDU_FRAME GENMASK(1, 0) #define MT_RXD4_MID_AMSDU_FRAME BIT(1) #define MT_RXD4_LAST_AMSDU_FRAME BIT(0) #define MT_RXV_HDR_BAND_IDX BIT(24) /* RXD GROUP4 */ #define MT_RXD8_FRAME_CONTROL GENMASK(15, 0) #define MT_RXD10_SEQ_CTRL GENMASK(15, 0) #define MT_RXD10_QOS_CTL GENMASK(31, 16) #define MT_RXD11_HT_CONTROL GENMASK(31, 0) /* P-RXV */ #define MT_PRXV_TX_RATE GENMASK(6, 0) #define MT_PRXV_TX_DCM BIT(4) #define MT_PRXV_TX_ER_SU_106T BIT(5) #define MT_PRXV_NSTS GENMASK(10, 7) #define MT_PRXV_TXBF BIT(11) #define MT_PRXV_HT_AD_CODE BIT(12) #define MT_PRXV_HE_RU_ALLOC GENMASK(30, 22) #define MT_PRXV_RCPI3 GENMASK(31, 24) #define MT_PRXV_RCPI2 GENMASK(23, 16) #define MT_PRXV_RCPI1 GENMASK(15, 8) #define MT_PRXV_RCPI0 GENMASK(7, 0) #define MT_PRXV_HT_SHORT_GI GENMASK(4, 3) #define MT_PRXV_HT_STBC GENMASK(10, 9) #define MT_PRXV_TX_MODE GENMASK(14, 11) #define MT_PRXV_FRAME_MODE GENMASK(2, 0) #define MT_PRXV_DCM BIT(5) /* C-RXV */ #define MT_CRXV_HE_NUM_USER GENMASK(26, 20) #define MT_CRXV_HE_LTF_SIZE GENMASK(28, 27) #define MT_CRXV_HE_LDPC_EXT_SYM BIT(30) #define MT_CRXV_HE_PE_DISAMBIG BIT(1) #define MT_CRXV_HE_UPLINK BIT(2) #define MT_CRXV_HE_MU_AID GENMASK(27, 17) #define MT_CRXV_HE_BEAM_CHNG BIT(29) #define MT_CRXV_HE_DOPPLER BIT(0) #define MT_CRXV_HE_BSS_COLOR GENMASK(15, 10) #define MT_CRXV_HE_TXOP_DUR GENMASK(19, 17) #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) #define MT_CRXV_HE_SR3_MASK GENMASK(24, 21) #define MT_CRXV_HE_RU0 GENMASK(8, 0) #define MT_CRXV_HE_RU1 GENMASK(17, 9) #define MT_CRXV_HE_RU2 GENMASK(26, 18) #define MT_CRXV_HE_RU3_L GENMASK(31, 27) #define MT_CRXV_HE_RU3_H GENMASK(3, 0) +#define MT_CRXV_EHT_NUM_USER GENMASK(26, 20) +#define MT_CRXV_EHT_LTF_SIZE GENMASK(28, 27) +#define MT_CRXV_EHT_LDPC_EXT_SYM BIT(30) +#define MT_CRXV_EHT_PE_DISAMBIG BIT(1) +#define MT_CRXV_EHT_UPLINK BIT(2) +#define MT_CRXV_EHT_MU_AID GENMASK(27, 17) +#define MT_CRXV_EHT_BEAM_CHNG BIT(29) +#define MT_CRXV_EHT_DOPPLER BIT(0) +#define MT_CRXV_EHT_BSS_COLOR GENMASK(15, 10) +#define MT_CRXV_EHT_TXOP_DUR GENMASK(23, 17) +#define MT_CRXV_EHT_SR_MASK GENMASK(11, 8) +#define MT_CRXV_EHT_SR1_MASK GENMASK(15, 12) +#define MT_CRXV_EHT_SR2_MASK GENMASK(19, 16) +#define MT_CRXV_EHT_SR3_MASK GENMASK(23, 20) +#define MT_CRXV_EHT_RU0 GENMASK(8, 0) +#define MT_CRXV_EHT_RU1 GENMASK(17, 9) +#define MT_CRXV_EHT_RU2 GENMASK(26, 18) +#define MT_CRXV_EHT_RU3_L GENMASK(31, 27) +#define MT_CRXV_EHT_RU3_H GENMASK(3, 0) +#define MT_CRXV_EHT_SIG_MCS GENMASK(19, 18) +#define MT_CRXV_EHT_LTF_SYM GENMASK(22, 20) + enum tx_header_format { MT_HDR_FORMAT_802_3, MT_HDR_FORMAT_CMD, MT_HDR_FORMAT_802_11, MT_HDR_FORMAT_802_11_EXT, }; enum tx_pkt_type { MT_TX_TYPE_CT, MT_TX_TYPE_SF, MT_TX_TYPE_CMD, MT_TX_TYPE_FW, }; enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU }; enum tx_mcu_port_q_idx { MT_TX_MCU_PORT_RX_Q0 = 0x20, MT_TX_MCU_PORT_RX_Q1, MT_TX_MCU_PORT_RX_Q2, MT_TX_MCU_PORT_RX_Q3, MT_TX_MCU_PORT_RX_FWDL = 0x3e }; enum tx_mgnt_type { MT_TX_NORMAL, MT_TX_TIMING, MT_TX_ADDBA, }; +enum tx_frag_idx { + MT_TX_FRAG_NONE, + MT_TX_FRAG_FIRST, + MT_TX_FRAG_MID, + MT_TX_FRAG_LAST +}; + #define MT_CT_INFO_APPLY_TXD BIT(0) #define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1) #define MT_CT_INFO_MGMT_FRAME BIT(2) #define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3) #define MT_CT_INFO_HSR2_TX BIT(4) #define MT_CT_INFO_FROM_HOST BIT(7) #define MT_TXD_SIZE (8 * 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) #define MT_TXD0_TX_BYTES GENMASK(15, 0) #define MT_TXD1_FIXED_RATE BIT(31) #define MT_TXD1_OWN_MAC GENMASK(30, 25) #define MT_TXD1_TID GENMASK(24, 21) #define MT_TXD1_BIP BIT(24) #define MT_TXD1_ETH_802_3 BIT(20) #define MT_TXD1_HDR_INFO GENMASK(20, 16) #define MT_TXD1_HDR_FORMAT GENMASK(15, 14) #define MT_TXD1_TGID GENMASK(13, 12) #define MT_TXD1_WLAN_IDX GENMASK(11, 0) #define MT_TXD2_POWER_OFFSET GENMASK(31, 26) #define MT_TXD2_MAX_TX_TIME GENMASK(25, 16) #define MT_TXD2_FRAG GENMASK(15, 14) #define MT_TXD2_HTC_VLD BIT(13) #define MT_TXD2_DURATION BIT(12) #define MT_TXD2_HDR_PAD GENMASK(11, 10) #define MT_TXD2_RTS BIT(9) #define MT_TXD2_OWN_MAC_MAP BIT(8) #define MT_TXD2_BF_TYPE GENMASK(6, 7) #define MT_TXD2_FRAME_TYPE GENMASK(5, 4) #define MT_TXD2_SUB_TYPE GENMASK(3, 0) #define MT_TXD3_SN_VALID BIT(31) #define MT_TXD3_PN_VALID BIT(30) #define MT_TXD3_SW_POWER_MGMT BIT(29) #define MT_TXD3_BA_DISABLE BIT(28) #define MT_TXD3_SEQ GENMASK(27, 16) #define MT_TXD3_REM_TX_COUNT GENMASK(15, 11) #define MT_TXD3_TX_COUNT GENMASK(10, 6) #define MT_TXD3_HW_AMSDU BIT(5) #define MT_TXD3_BCM BIT(4) #define MT_TXD3_EEOSP BIT(3) #define MT_TXD3_EMRD BIT(2) #define MT_TXD3_PROTECT_FRAME BIT(1) #define MT_TXD3_NO_ACK BIT(0) #define MT_TXD4_PN_LOW GENMASK(31, 0) #define MT_TXD5_PN_HIGH GENMASK(31, 16) #define MT_TXD5_FL BIT(15) #define MT_TXD5_BYPASS_TBB BIT(14) #define MT_TXD5_BYPASS_RBB BIT(13) #define MT_TXD5_BSS_COLOR_ZERO BIT(12) #define MT_TXD5_TX_STATUS_HOST BIT(10) #define MT_TXD5_TX_STATUS_MCU BIT(9) #define MT_TXD5_TX_STATUS_FMT BIT(8) #define MT_TXD5_PID GENMASK(7, 0) #define MT_TXD6_TX_SRC GENMASK(31, 30) #define MT_TXD6_VTA BIT(28) -#define MT_TXD6_BW GENMASK(25, 22) +#define MT_TXD6_FIXED_BW BIT(25) +#define MT_TXD6_BW GENMASK(24, 22) #define MT_TXD6_TX_RATE GENMASK(21, 16) #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) +#define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) #define MT_TXD6_DAS BIT(2) #define MT_TXD6_AMSDU_CAP BIT(1) #define MT_TXD7_TXD_LEN GENMASK(31, 30) #define MT_TXD7_IP_SUM BIT(29) #define MT_TXD7_DROP_BY_SDO BIT(28) #define MT_TXD7_MAC_TXD BIT(27) #define MT_TXD7_CTXD BIT(26) #define MT_TXD7_CTXD_CNT GENMASK(25, 22) #define MT_TXD7_UDP_TCP_SUM BIT(15) #define MT_TXD7_TX_TIME GENMASK(9, 0) +#define MT_TXD9_WLAN_IDX GENMASK(23, 8) + +#define MT_TXP_BUF_LEN GENMASK(11, 0) +#define MT_TXP_DMA_ADDR_H GENMASK(15, 12) + #define MT_TX_RATE_STBC BIT(14) #define MT_TX_RATE_NSS GENMASK(13, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) #define MT_TX_RATE_SU_EXT_TONE BIT(5) #define MT_TX_RATE_DCM BIT(4) /* VHT/HE only use bits 0-3 */ #define MT_TX_RATE_IDX GENMASK(5, 0) #define MT_TXFREE0_PKT_TYPE GENMASK(31, 27) #define MT_TXFREE0_MSDU_CNT GENMASK(25, 16) #define MT_TXFREE0_RX_BYTE GENMASK(15, 0) -#define MT_TXFREE1_VER GENMASK(18, 16) +#define MT_TXFREE1_VER GENMASK(19, 16) #define MT_TXFREE_INFO_PAIR BIT(31) #define MT_TXFREE_INFO_HEADER BIT(30) #define MT_TXFREE_INFO_WLAN_ID GENMASK(23, 12) #define MT_TXFREE_INFO_MSDU_ID GENMASK(14, 0) #define MT_TXFREE_INFO_COUNT GENMASK(27, 24) #define MT_TXFREE_INFO_STAT GENMASK(29, 28) #define MT_TXS0_BW GENMASK(31, 29) #define MT_TXS0_TID GENMASK(28, 26) #define MT_TXS0_AMPDU BIT(25) #define MT_TXS0_TXS_FORMAT GENMASK(24, 23) #define MT_TXS0_BA_ERROR BIT(22) #define MT_TXS0_PS_FLAG BIT(21) #define MT_TXS0_TXOP_TIMEOUT BIT(20) #define MT_TXS0_BIP_ERROR BIT(19) #define MT_TXS0_QUEUE_TIMEOUT BIT(18) #define MT_TXS0_RTS_TIMEOUT BIT(17) #define MT_TXS0_ACK_TIMEOUT BIT(16) #define MT_TXS0_ACK_ERROR_MASK GENMASK(18, 16) #define MT_TXS0_TX_STATUS_HOST BIT(15) #define MT_TXS0_TX_STATUS_MCU BIT(14) #define MT_TXS0_TX_RATE GENMASK(13, 0) #define MT_TXS1_SEQNO GENMASK(31, 20) #define MT_TXS1_RESP_RATE GENMASK(19, 16) #define MT_TXS1_RXV_SEQNO GENMASK(15, 8) #define MT_TXS1_TX_POWER_DBM GENMASK(7, 0) #define MT_TXS2_BF_STATUS GENMASK(31, 30) #define MT_TXS2_BAND GENMASK(29, 28) #define MT_TXS2_WCID GENMASK(27, 16) #define MT_TXS2_TX_DELAY GENMASK(15, 0) #define MT_TXS3_PID GENMASK(31, 24) #define MT_TXS3_RATE_STBC BIT(7) #define MT_TXS3_FIXED_RATE BIT(6) #define MT_TXS3_SRC GENMASK(5, 4) #define MT_TXS3_SHARED_ANTENNA BIT(3) #define MT_TXS3_LAST_TX_RATE GENMASK(2, 0) #define MT_TXS4_TIMESTAMP GENMASK(31, 0) +/* MPDU based TXS */ #define MT_TXS5_F0_FINAL_MPDU BIT(31) #define MT_TXS5_F0_QOS BIT(30) #define MT_TXS5_F0_TX_COUNT GENMASK(29, 25) #define MT_TXS5_F0_FRONT_TIME GENMASK(24, 0) #define MT_TXS5_F1_MPDU_TX_COUNT GENMASK(31, 24) #define MT_TXS5_F1_MPDU_TX_BYTES GENMASK(23, 0) #define MT_TXS6_F0_NOISE_3 GENMASK(31, 24) #define MT_TXS6_F0_NOISE_2 GENMASK(23, 16) #define MT_TXS6_F0_NOISE_1 GENMASK(15, 8) #define MT_TXS6_F0_NOISE_0 GENMASK(7, 0) #define MT_TXS6_F1_MPDU_FAIL_COUNT GENMASK(31, 24) #define MT_TXS6_F1_MPDU_FAIL_BYTES GENMASK(23, 0) #define MT_TXS7_F0_RCPI_3 GENMASK(31, 24) #define MT_TXS7_F0_RCPI_2 GENMASK(23, 16) #define MT_TXS7_F0_RCPI_1 GENMASK(15, 8) #define MT_TXS7_F0_RCPI_0 GENMASK(7, 0) #define MT_TXS7_F1_MPDU_RETRY_COUNT GENMASK(31, 24) #define MT_TXS7_F1_MPDU_RETRY_BYTES GENMASK(23, 0) +/* PPDU based TXS */ +#define MT_TXS5_MPDU_TX_CNT GENMASK(30, 20) +#define MT_TXS5_MPDU_TX_BYTE_SCALE BIT(15) +#define MT_TXS5_MPDU_TX_BYTE GENMASK(14, 0) + +#define MT_TXS6_MPDU_FAIL_CNT GENMASK(30, 20) +#define MT_TXS6_MPDU_FAIL_BYTE_SCALE BIT(15) +#define MT_TXS6_MPDU_FAIL_BYTE GENMASK(14, 0) + +#define MT_TXS7_MPDU_RETRY_CNT GENMASK(30, 20) +#define MT_TXS7_MPDU_RETRY_BYTE_SCALE BIT(15) +#define MT_TXS7_MPDU_RETRY_BYTE GENMASK(14, 0) + #endif /* __MT76_CONNAC3_MAC_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c b/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c index ee5177fd6dde..e9ac8a7317a1 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c @@ -1,1196 +1,1207 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include "mt76_connac.h" #include "mt76_connac2_mac.h" #include "dma.h" #define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f) #define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\ IEEE80211_RADIOTAP_HE_##f) -void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss) +void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss, enum nl80211_band band) { static const u8 ppet16_ppet8_ru3_ru0[] = { 0x1c, 0xc7, 0x71 }; - u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */ + u8 i, ppet_bits, ppet_size, ru_bit_mask = 0xf; + + if (band == NL80211_BAND_2GHZ) + ru_bit_mask = 0x3; he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) | FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK, ru_bit_mask); ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE * nss * hweight8(ru_bit_mask) * 2; ppet_size = DIV_ROUND_UP(ppet_bits, 8); for (i = 0; i < ppet_size - 1; i++) he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3]; he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] & (0xff >> (8 - (ppet_bits - 1) % 8)); } EXPORT_SYMBOL_GPL(mt76_connac_gen_ppe_thresh); int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) { struct mt76_dev *dev = phy->dev; if (mt76_is_usb(dev)) return 0; cancel_delayed_work_sync(&pm->ps_work); if (!test_bit(MT76_STATE_PM, &phy->state)) return 0; if (pm->suspended) return 0; queue_work(dev->wq, &pm->wake_work); if (!wait_event_timeout(pm->wait, !test_bit(MT76_STATE_PM, &phy->state), 3 * HZ)) { ieee80211_wake_queues(phy->hw); return -ETIMEDOUT; } return 0; } EXPORT_SYMBOL_GPL(mt76_connac_pm_wake); void mt76_connac_power_save_sched(struct mt76_phy *phy, struct mt76_connac_pm *pm) { struct mt76_dev *dev = phy->dev; if (mt76_is_usb(dev)) return; if (!pm->enable) return; if (pm->suspended) return; pm->last_activity = jiffies; if (!test_bit(MT76_STATE_PM, &phy->state)) { cancel_delayed_work(&phy->mac_work); queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout); } } EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched); void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm, struct mt76_wcid *wcid) { int i; spin_lock_bh(&pm->txq_lock); for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (wcid && pm->tx_q[i].wcid != wcid) continue; dev_kfree_skb(pm->tx_q[i].skb); pm->tx_q[i].skb = NULL; } spin_unlock_bh(&pm->txq_lock); } EXPORT_SYMBOL_GPL(mt76_connac_free_pending_tx_skbs); void mt76_connac_pm_queue_skb(struct ieee80211_hw *hw, struct mt76_connac_pm *pm, struct mt76_wcid *wcid, struct sk_buff *skb) { int qid = skb_get_queue_mapping(skb); struct mt76_phy *phy = hw->priv; spin_lock_bh(&pm->txq_lock); if (!pm->tx_q[qid].skb) { ieee80211_stop_queues(hw); pm->tx_q[qid].wcid = wcid; pm->tx_q[qid].skb = skb; queue_work(phy->dev->wq, &pm->wake_work); } else { dev_kfree_skb(skb); } spin_unlock_bh(&pm->txq_lock); } EXPORT_SYMBOL_GPL(mt76_connac_pm_queue_skb); void mt76_connac_pm_dequeue_skbs(struct mt76_phy *phy, struct mt76_connac_pm *pm) { int i; spin_lock_bh(&pm->txq_lock); for (i = 0; i < IEEE80211_NUM_ACS; i++) { struct mt76_wcid *wcid = pm->tx_q[i].wcid; struct ieee80211_sta *sta = NULL; if (!pm->tx_q[i].skb) continue; if (wcid && wcid->sta) sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); mt76_tx(phy, sta, wcid, pm->tx_q[i].skb); pm->tx_q[i].skb = NULL; } spin_unlock_bh(&pm->txq_lock); mt76_worker_schedule(&phy->dev->tx_worker); } EXPORT_SYMBOL_GPL(mt76_connac_pm_dequeue_skbs); void mt76_connac_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_connac_txp_common *txp; - struct mt76_txwi_cache *t; - u16 token; - - txp = mt76_connac_txwi_to_txp(mdev, e->txwi); - if (is_mt76_fw_txp(mdev)) - token = le16_to_cpu(txp->fw.token); - else - 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); } EXPORT_SYMBOL_GPL(mt76_connac_tx_complete_skb); void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id) { struct mt76_connac_hw_txp *txp = txp_ptr; struct mt76_connac_txp_ptr *ptr = &txp->ptr[0]; int i, nbuf = tx_info->nbuf - 1; u32 last_mask; 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); - if (is_mt7663(dev) || is_mt7921(dev)) + if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) last_mask = MT_TXD_LEN_LAST; else last_mask = MT_TXD_LEN_AMSDU_LAST | MT_TXD_LEN_MSDU_LAST; 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 |= last_mask; 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); } } } EXPORT_SYMBOL_GPL(mt76_connac_write_hw_txp); static void mt76_connac_txp_skb_unmap_fw(struct mt76_dev *mdev, struct mt76_connac_fw_txp *txp) { struct device *dev = is_connac_v1(mdev) ? mdev->dev : mdev->dma_dev; int i; for (i = 0; i < txp->nbuf; i++) dma_unmap_single(dev, le32_to_cpu(txp->buf[i]), le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); } static void mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt76_connac_hw_txp *txp) { u32 last_mask; int i; - if (is_mt7663(dev) || is_mt7921(dev)) + if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) last_mask = MT_TXD_LEN_LAST; else last_mask = MT_TXD_LEN_MSDU_LAST; for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) { struct mt76_connac_txp_ptr *ptr = &txp->ptr[i]; bool last; u16 len; len = le16_to_cpu(ptr->len0); last = len & last_mask; 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 & last_mask; len &= MT_TXD_LEN_MASK; dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len, DMA_TO_DEVICE); if (last) break; } } void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { struct mt76_connac_txp_common *txp; txp = mt76_connac_txwi_to_txp(dev, t); if (is_mt76_fw_txp(dev)) mt76_connac_txp_skb_unmap_fw(dev, &txp->fw); else mt76_connac_txp_skb_unmap_hw(dev, &txp->hw); } EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { int i, err; - err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, + wed, flags); if (err < 0) return err; for (i = 1; i <= MT_TXQ_PSD; i++) phy->q_tx[i] = phy->q_tx[0]; return 0; } EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues); #define __bitrate_mask_check(_mcs, _mode) \ ({ \ u8 i = 0; \ for (nss = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \ if (!mask->control[band]._mcs[i]) \ continue; \ if (hweight16(mask->control[band]._mcs[i]) == 1) { \ mode = MT_PHY_TYPE_##_mode; \ rateidx = ffs(mask->control[band]._mcs[i]) - 1; \ if (mode == MT_PHY_TYPE_HT) \ rateidx += 8 * i; \ else \ nss = i + 1; \ goto out; \ } \ } \ }) u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, bool beacon, bool mcast) { - u8 nss = 0, mode = 0, band = mphy->chandef.chan->band; + struct mt76_vif_link *mvif = mt76_vif_conf_link(mphy->dev, conf->vif, conf); + struct cfg80211_chan_def *chandef = mvif->ctx ? + &mvif->ctx->def : &mphy->chandef; + u8 nss = 0, mode = 0, band = chandef->chan->band; int rateidx = 0, mcast_rate; + int offset = 0; - if (!vif) + if (!conf) goto legacy; if (is_mt7921(mphy->dev)) { - rateidx = ffs(vif->bss_conf.basic_rates) - 1; + rateidx = ffs(conf->basic_rates) - 1; goto legacy; } if (beacon) { struct cfg80211_bitrate_mask *mask; - mask = &vif->bss_conf.beacon_tx_rate; + mask = &conf->beacon_tx_rate; __bitrate_mask_check(he_mcs, HE_SU); __bitrate_mask_check(vht_mcs, VHT); __bitrate_mask_check(ht_mcs, HT); if (hweight32(mask->control[band].legacy) == 1) { rateidx = ffs(mask->control[band].legacy) - 1; goto legacy; } } - mcast_rate = vif->bss_conf.mcast_rate[band]; + mcast_rate = conf->mcast_rate[band]; if (mcast && mcast_rate > 0) rateidx = mcast_rate - 1; else - rateidx = ffs(vif->bss_conf.basic_rates) - 1; + rateidx = ffs(conf->basic_rates) - 1; legacy: - rateidx = mt76_calculate_default_rate(mphy, rateidx); + if (band != NL80211_BAND_2GHZ) + offset = 4; + + /* pick the lowest rate for hidden nodes */ + if (rateidx < 0) + rateidx = 0; + + rateidx += offset; + if (rateidx >= ARRAY_SIZE(mt76_rates)) + rateidx = offset; + + rateidx = mt76_rates[rateidx].hw_value; mode = rateidx >> 8; rateidx &= GENMASK(7, 0); out: return FIELD_PREP(MT_TX_RATE_NSS, nss) | FIELD_PREP(MT_TX_RATE_IDX, rateidx) | FIELD_PREP(MT_TX_RATE_MODE, mode); } EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val); static void mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid) { u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; u8 fc_type, fc_stype; u16 ethertype; bool wmm = false; u32 val; if (wcid->sta) { struct ieee80211_sta *sta; sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); wmm = sta->wme; } val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | FIELD_PREP(MT_TXD1_TID, tid); ethertype = get_unaligned_be16(&skb->data[12]); if (ethertype >= ETH_P_802_3_MIN) val |= MT_TXD1_ETH_802_3; txwi[1] |= cpu_to_le32(val); fc_type = IEEE80211_FTYPE_DATA >> 2; fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); txwi[2] |= cpu_to_le32(val); val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); txwi[7] |= cpu_to_le32(val); } static void mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct ieee80211_key_conf *key) { 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; + __le16 sc = hdr->seq_ctrl; u8 fc_type, fc_stype; u32 val; if (ieee80211_is_action(fc) && mgmt->u.action.category == WLAN_CATEGORY_BACK && mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA); tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK; } else if (ieee80211_is_back_req(hdr->frame_control)) { struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; u16 control = le16_to_cpu(bar->control); tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control); } val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, ieee80211_get_hdrlen_from_skb(skb) / 2) | FIELD_PREP(MT_TXD1_TID, tid); txwi[1] |= cpu_to_le32(val); fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | FIELD_PREP(MT_TXD2_MULTICAST, multicast); if (key && multicast && 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 || info->flags & IEEE80211_TX_CTL_USE_MINRATE) val |= MT_TXD2_FIX_RATE; + if (ieee80211_has_morefrags(fc) && ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_FIRST); + else if (ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_MID); + else if (!ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_LAST); + txwi[2] |= cpu_to_le32(val); if (ieee80211_is_beacon(fc)) { txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); } if (info->flags & IEEE80211_TX_CTL_INJECTED) { - u16 seqno = le16_to_cpu(hdr->seq_ctrl); + u16 seqno = le16_to_cpu(sc); if (ieee80211_is_back_req(hdr->frame_control)) { struct ieee80211_bar *bar; bar = (struct ieee80211_bar *)skb->data; seqno = le16_to_cpu(bar->start_seq_num); } val = MT_TXD3_SN_VALID | FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); txwi[3] |= cpu_to_le32(val); txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); } if (mt76_is_mmio(dev)) { val = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); txwi[7] |= cpu_to_le32(val); } else { val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); txwi[8] |= cpu_to_le32(val); } } void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; struct ieee80211_vif *vif = info->control.vif; struct mt76_phy *mphy = &dev->phy; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; bool beacon = !!(changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)); bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); bool amsdu_en = wcid->amsdu; if (vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; omac_idx = mvif->omac_idx; wmm_idx = mvif->wmm_idx; band_idx = mvif->band_idx; } if (phy_idx && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; if (inband_disc) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_ALTX0; } else if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; } else if (qid >= MT_TXQ_PSD) { p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = MT_LMAC_ALTX0; } else { p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); /* mt7915 WA only counts WED path */ if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed)) wcid->stats.tx_packets++; } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); if (!is_mt7921(dev)) val |= MT_TXD1_VTA; if (phy_idx || band_idx) val |= MT_TXD1_TGID; txwi[1] = cpu_to_le32(val); txwi[2] = 0; val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); if (!is_mt7921(dev)) val |= MT_TXD3_SW_POWER_MGMT; if (key) val |= MT_TXD3_PROTECT_FRAME; if (info->flags & IEEE80211_TX_CTL_NO_ACK) val |= MT_TXD3_NO_ACK; txwi[3] = cpu_to_le32(val); txwi[4] = 0; val = FIELD_PREP(MT_TXD5_PID, pid); if (pid >= MT_PACKET_ID_FIRST) { val |= MT_TXD5_TX_STATUS_HOST; - amsdu_en = amsdu_en && !is_mt7921(dev); + amsdu_en = 0; } txwi[5] = cpu_to_le32(val); txwi[6] = 0; txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0; if (is_8023) mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid); else mt76_connac2_mac_write_txwi_80211(dev, txwi, skb, key); if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) { /* Fixed rata is available just for 802.11 txd */ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; bool multicast = ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1); - u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, + u16 rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon, multicast); u32 val = MT_TXD6_FIXED_BW; /* hardware won't add HTC for mgmt/ctrl frame */ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); val |= FIELD_PREP(MT_TXD6_TX_RATE, rate); txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); if (!is_mt7921(dev)) { u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); if (!spe_idx) spe_idx = 24 + phy_idx; txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx)); } + + txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); } } EXPORT_SYMBOL_GPL(mt76_connac2_mac_write_txwi); bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid, __le32 *txs_data) { struct mt76_sta_stats *stats = &wcid->stats; struct ieee80211_supported_band *sband; struct mt76_phy *mphy; struct rate_info rate = {}; bool cck = false; u32 txrate, txs, mode, stbc; txs = le32_to_cpu(txs_data[0]); /* PPDU based reporting */ if (mtk_wed_device_active(&dev->mmio.wed) && FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) { stats->tx_bytes += le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) - le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE); stats->tx_failed += le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT); stats->tx_retries += le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_CNT); if (wcid->sta) { struct ieee80211_sta *sta; u8 tid; sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); tid = FIELD_GET(MT_TXS0_TID, txs); ieee80211_refresh_tx_agg_session_timer(sta, tid); } } 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; stbc = FIELD_GET(MT_TX_RATE_STBC, txrate); if (stbc && rate.nss > 1) rate.nss >>= 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->phy; if (wcid->phy_idx == MT_BAND1 && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.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: if (rate.mcs > 31) return false; 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) return false; 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) return false; 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: return false; } 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; return true; } EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_txs); bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) { struct sk_buff_head list; struct sk_buff *skb; + if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == MT_TXS_PPDU_FMT) + return false; + mt76_tx_status_lock(dev, &list); skb = mt76_tx_status_skb_get(dev, wcid, pid, &list); if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK)) info->flags |= IEEE80211_TX_STAT_ACK; info->status.ampdu_len = 1; info->status.ampdu_ack_len = !!(info->flags & IEEE80211_TX_STAT_ACK); info->status.rates[0].idx = -1; mt76_connac2_mac_fill_txs(dev, wcid, txs_data); mt76_tx_status_skb_done(dev, skb, &list); } mt76_tx_status_unlock(dev, &list); return !!skb; } EXPORT_SYMBOL_GPL(mt76_connac2_mac_add_txs_skb); static void mt76_connac2_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, struct ieee80211_radiotap_he *he, __le32 *rxv) { u32 ru_h, ru_l; u8 ru, offs = 0; ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L); ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H); ru = (u8)(ru_l | ru_h << 4); status->bw = RATE_INFO_BW_HE_RU; switch (ru) { case 0 ... 36: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26; offs = ru; break; case 37 ... 52: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52; offs = ru - 37; break; case 53 ... 60: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; offs = ru - 53; break; case 61 ... 64: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242; offs = ru - 61; break; case 65 ... 66: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484; offs = ru - 65; break; case 67: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996; break; case 68: status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; break; } he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) | le16_encode_bits(offs, IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET); } static void mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb, __le32 *rxv) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; static 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; if (is_mt7921(dev)) { mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN); } status->flag |= RX_FLAG_RADIOTAP_HE_MU; 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); } } void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev, struct sk_buff *skb, __le32 *rxv, u32 mode) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; static const struct ieee80211_radiotap_he known = { .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) | HE_BITS(DATA1_DATA_DCM_KNOWN) | HE_BITS(DATA1_STBC_KNOWN) | 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) | HE_BITS(DATA2_PE_DISAMBIG_KNOWN) | HE_BITS(DATA2_TXOP_KNOWN), }; u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; struct ieee80211_radiotap_he *he; status->flag |= RX_FLAG_RADIOTAP_HE; he = skb_push(skb, sizeof(known)); memcpy(he, &known, sizeof(known)); 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]); switch (mode) { 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_BW_RU_ALLOC_KNOWN); he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); break; case MT_PHY_TYPE_HE_EXT_SU: he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_BW_RU_ALLOC_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | HE_BITS(DATA1_UL_DL_KNOWN); he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]); mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv); mt76_connac2_mac_decode_he_mu_radiotap(dev, skb, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | 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_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); mt76_connac2_mac_decode_he_radiotap_ru(status, he, rxv); break; default: break; } } EXPORT_SYMBOL_GPL(mt76_connac2_mac_decode_he_radiotap); /* The HW does not translate the mac header to 802.3 for mesh point */ int mt76_connac2_reverse_frag0_hdr_trans(struct ieee80211_vif *vif, struct sk_buff *skb, u16 hdr_offset) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_offset); __le32 *rxd = (__le32 *)skb->data; struct ieee80211_sta *sta; struct ieee80211_hdr hdr; u16 frame_control; if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != MT_RXD3_NORMAL_U2M) return -EINVAL; if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) return -EINVAL; sta = container_of((void *)status->wcid, struct ieee80211_sta, drv_priv); /* store the info from RXD and ethhdr to avoid being overridden */ frame_control = le32_get_bits(rxd[6], MT_RXD6_FRAME_CONTROL); hdr.frame_control = cpu_to_le16(frame_control); hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_SEQ_CTRL)); hdr.duration_id = 0; ether_addr_copy(hdr.addr1, vif->addr); ether_addr_copy(hdr.addr2, sta->addr); switch (frame_control & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case 0: ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); break; case IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_source); break; case IEEE80211_FCTL_TODS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); break; case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); ether_addr_copy(hdr.addr4, eth_hdr->h_source); break; default: return -EINVAL; } skb_pull(skb, hdr_offset + sizeof(struct ethhdr) - 2); if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); else skb_pull(skb, 2); if (ieee80211_has_order(hdr.frame_control)) memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[9], IEEE80211_HT_CTL_LEN); if (ieee80211_is_data_qos(hdr.frame_control)) { __le16 qos_ctrl; qos_ctrl = cpu_to_le16(le32_get_bits(rxd[8], MT_RXD8_QOS_CTL)); memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, IEEE80211_QOS_CTL_LEN); } if (ieee80211_has_a4(hdr.frame_control)) memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); else memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); return 0; } EXPORT_SYMBOL_GPL(mt76_connac2_reverse_frag0_hdr_trans); int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, struct mt76_rx_status *status, struct ieee80211_supported_band *sband, __le32 *rxv, u8 *mode) { u32 v0, v2; u8 stbc, gi, bw, dcm, nss; int i, idx; bool cck = false; v0 = le32_to_cpu(rxv[0]); v2 = le32_to_cpu(rxv[2]); idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; if (!is_mt7915(dev)) { stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); gi = FIELD_GET(MT_PRXV_HT_SGI, v0); *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); if (is_mt7921(dev)) dcm = !!(idx & MT_PRXV_TX_DCM); else dcm = FIELD_GET(MT_PRXV_DCM, v0); bw = FIELD_GET(MT_PRXV_FRAME_MODE, v0); } else { stbc = FIELD_GET(MT_CRXV_HT_STBC, v2); gi = FIELD_GET(MT_CRXV_HT_SHORT_GI, v2); *mode = FIELD_GET(MT_CRXV_TX_MODE, v2); dcm = !!(idx & GENMASK(3, 0) & MT_PRXV_TX_DCM); bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2); } switch (*mode) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: i = mt76_get_rate(dev, sband, i, cck); break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: status->encoding = RX_ENC_HT; if (gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (i > 31) return -EINVAL; break; case MT_PHY_TYPE_VHT: status->nss = nss; status->encoding = RX_ENC_VHT; if (gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (i > 11) return -EINVAL; break; case MT_PHY_TYPE_HE_MU: case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: case MT_PHY_TYPE_HE_TB: status->nss = nss; status->encoding = RX_ENC_HE; i &= GENMASK(3, 0); if (gi <= NL80211_RATE_INFO_HE_GI_3_2) status->he_gi = gi; status->he_dcm = dcm; break; default: return -EINVAL; } status->rate_idx = i; switch (bw) { case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: if (*mode & MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; } else { status->bw = RATE_INFO_BW_40; } break; case IEEE80211_STA_RX_BW_80: status->bw = RATE_INFO_BW_80; break; case IEEE80211_STA_RX_BW_160: status->bw = RATE_INFO_BW_160; break; default: return -EINVAL; } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; if (*mode < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; return 0; } EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate); void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) { struct mt76_wcid *wcid; u16 fc, tid; u32 val; if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) return; tid = le32_get_bits(txwi[1], MT_TXD1_TID); if (tid >= 6) /* skip VO queue */ return; val = le32_to_cpu(txwi[2]); fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; wcid = (struct mt76_wcid *)sta->drv_priv; if (!test_and_set_bit(tid, &wcid->ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); } EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, struct list_head *free_list) { struct mt76_wcid *wcid; __le32 *txwi; u16 wcid_idx; mt76_connac_txp_skb_unmap(dev, t); if (!t->skb) goto out; txwi = (__le32 *)mt76_get_txwi_ptr(dev, t); if (sta) { wcid = (struct mt76_wcid *)sta->drv_priv; wcid_idx = wcid->idx; } else { wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); wcid = rcu_dereference(dev->wcid[wcid_idx]); if (wcid && wcid->sta) { sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); - spin_lock_bh(&dev->sta_poll_lock); - if (list_empty(&wcid->poll_list)) - list_add_tail(&wcid->poll_list, - &dev->sta_poll_list); - spin_unlock_bh(&dev->sta_poll_lock); + mt76_wcid_add_poll(dev, wcid); } } if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) mt76_connac2_tx_check_aggr(sta, txwi); __mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list); out: t->skb = NULL; mt76_put_txwi(dev, t); } EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free); void mt76_connac2_tx_token_put(struct mt76_dev *dev) { struct mt76_txwi_cache *txwi; int id; spin_lock_bh(&dev->token_lock); idr_for_each_entry(&dev->token, txwi, id) { mt76_connac2_txwi_free(dev, txwi, NULL, NULL); dev->token_count--; } spin_unlock_bh(&dev->token_lock); idr_destroy(&dev->token); } EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put); diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c b/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c index f51a4fd405df..85a8573f2822 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c @@ -1,3261 +1,3208 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include "mt76_connac2_mac.h" #include "mt76_connac_mcu.h" int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) { struct { __le32 option; __le32 addr; } req = { .option = cpu_to_le32(option), .addr = cpu_to_le32(addr), }; return mt76_mcu_send_msg(dev, MCU_CMD(FW_START_REQ), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_firmware); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get) { u32 op = get ? PATCH_SEM_GET : PATCH_SEM_RELEASE; struct { __le32 op; } req = { .op = cpu_to_le32(op), }; return mt76_mcu_send_msg(dev, MCU_CMD(PATCH_SEM_CONTROL), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_patch_sem_ctrl); int mt76_connac_mcu_start_patch(struct mt76_dev *dev) { struct { u8 check_crc; u8 reserved[3]; } req = { .check_crc = 0, }; return mt76_mcu_send_msg(dev, MCU_CMD(PATCH_FINISH_REQ), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_start_patch); #define MCU_PATCH_ADDRESS 0x200000 int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, u32 mode) { struct { __le32 addr; __le32 len; __le32 mode; } req = { .addr = cpu_to_le32(addr), .len = cpu_to_le32(len), .mode = cpu_to_le32(mode), }; int cmd; if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_mt7921(dev) && addr == 0x900000) || - (is_mt7996(dev) && addr == 0x900000)) + (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || + (is_mt7996(dev) && addr == 0x900000) || + (is_mt7992(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); else cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ); return mt76_mcu_send_msg(dev, cmd, &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download); int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) { 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 * BW_20M 1 * BW_20_40_80M 2 * BW_20_40_80_160M 3 * BW_20_40_80_8080M 4 */ u8 bw_5g; u8 bw_6g; u8 pad; u8 n_2ch; u8 n_5ch; u8 n_6ch; u8 pad2; } __packed hdr = { .bw_2g = 0, .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; 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_6g.sband.n_channels; len = sizeof(hdr) + n_max_channels * sizeof(channel); skb = mt76_mcu_msg_alloc(dev, NULL, len); if (!skb) return -ENOMEM; skb_reserve(skb, sizeof(hdr)); for (i = 0; i < phy->sband_2g.sband.n_channels; i++) { chan = &phy->sband_2g.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_2ch++; } for (i = 0; i < phy->sband_5g.sband.n_channels; i++) { chan = &phy->sband_5g.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_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)); return mt76_mcu_skb_send_msg(dev, skb, MCU_CE_CMD(SET_CHAN_DOMAIN), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_channel_domain); int mt76_connac_mcu_set_mac_enable(struct mt76_dev *dev, int band, bool enable, bool hdr_trans) { struct { u8 enable; u8 band; u8 rsv[2]; } __packed req_mac = { .enable = enable, .band = band, }; return mt76_mcu_send_msg(dev, MCU_EXT_CMD(MAC_INIT_CTRL), &req_mac, sizeof(req_mac), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_mac_enable); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { u8 bss_idx; u8 ps_state; /* 0: device awake * 1: static power save * 2: dynamic power saving */ } req = { .bss_idx = mvif->idx, .ps_state = vif->cfg.ps ? 2 : 0, }; if (vif->type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; return mt76_mcu_send_msg(dev, MCU_CE_CMD(SET_PS_PROFILE), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_vif_ps); int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band) { struct { u8 prot_idx; u8 band; u8 rsv[2]; __le32 len_thresh; __le32 pkt_thresh; } __packed req = { .prot_idx = 1, .band = band, .len_thresh = cpu_to_le32(val), .pkt_thresh = cpu_to_le32(0x2), }; return mt76_mcu_send_msg(dev, MCU_EXT_CMD(PROTECT_CTRL), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rts_thresh); void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt76_connac_beacon_loss_event *event = priv; if (mvif->idx != event->bss_idx) return; if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER)) return; ieee80211_beacon_loss(vif); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_beacon_loss_iter); struct tlv * mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, void *sta_ntlv, void *sta_wtbl) { struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv; struct tlv *sta_hdr = sta_wtbl; struct tlv *ptlv, tlv = { .tag = cpu_to_le16(tag), .len = cpu_to_le16(len), }; u16 ntlv; - ptlv = skb_put(skb, len); + ptlv = skb_put_zero(skb, len); memcpy(ptlv, &tlv, sizeof(tlv)); ntlv = le16_to_cpu(ntlv_hdr->tlv_num); ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1); if (sta_hdr) { len += le16_to_cpu(sta_hdr->len); sta_hdr->len = cpu_to_le16(len); } return ptlv; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_nested_tlv); struct sk_buff * -__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, +__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, struct mt76_wcid *wcid, int len) { struct sta_req_hdr hdr = { .bss_idx = mvif->idx, .muar_idx = wcid ? mvif->omac_idx : 0, .is_tlv_append = 1, }; struct sk_buff *skb; + if (wcid && !wcid->sta && !wcid->sta_disabled) + hdr.muar_idx = 0xe; + mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo, &hdr.wlan_idx_hi); skb = mt76_mcu_msg_alloc(dev, NULL, len); if (!skb) return ERR_PTR(-ENOMEM); skb_put_data(skb, &hdr, sizeof(hdr)); return skb; } EXPORT_SYMBOL_GPL(__mt76_connac_mcu_alloc_sta_req); struct wtbl_req_hdr * mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, struct mt76_wcid *wcid, int cmd, void *sta_wtbl, struct sk_buff **skb) { struct tlv *sta_hdr = sta_wtbl; struct wtbl_req_hdr hdr = { .operation = cmd, }; struct sk_buff *nskb = *skb; mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo, &hdr.wlan_idx_hi); if (!nskb) { nskb = mt76_mcu_msg_alloc(dev, NULL, MT76_CONNAC_WTBL_UPDATE_MAX_SIZE); if (!nskb) return ERR_PTR(-ENOMEM); *skb = nskb; } if (sta_hdr) le16_add_cpu(&sta_hdr->len, sizeof(hdr)); return skb_put_data(nskb, &hdr, sizeof(hdr)); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_alloc_wtbl_req); void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; u8 omac_idx = mvif->omac_idx; struct bss_info_omac *omac; struct tlv *tlv; u32 type = 0; switch (vif->type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: if (vif->p2p) type = CONNECTION_P2P_GO; else type = CONNECTION_INFRA_AP; break; case NL80211_IFTYPE_STATION: if (vif->p2p) type = CONNECTION_P2P_GC; else type = CONNECTION_INFRA_STA; break; case NL80211_IFTYPE_ADHOC: type = CONNECTION_IBSS_ADHOC; break; default: WARN_ON(1); break; } tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac)); omac = (struct bss_info_omac *)tlv; omac->conn_type = cpu_to_le32(type); omac->omac_idx = mvif->omac_idx; omac->band_idx = mvif->band_idx; omac->hw_bss_idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - bool enable, bool newly) + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + int conn_state, bool newly) { + struct ieee80211_vif *vif = link_conf->vif; struct sta_rec_basic *basic; struct tlv *tlv; int conn_type; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic)); basic = (struct sta_rec_basic *)tlv; basic->extra_info = cpu_to_le16(EXTRA_INFO_VER); - if (enable) { - 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; - } + if (newly && conn_state != CONN_STATE_DISCONNECT) + basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW); + basic->conn_state = conn_state; - if (!sta) { + if (!link_sta) { basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); - eth_broadcast_addr(basic->peer_addr); + + if (vif->type == NL80211_IFTYPE_STATION && + !is_zero_ether_addr(link_conf->bssid)) { + memcpy(basic->peer_addr, link_conf->bssid, ETH_ALEN); + basic->aid = cpu_to_le16(vif->cfg.aid); + } else { + eth_broadcast_addr(basic->peer_addr); + } return; } switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: if (vif->p2p && !is_mt7921(dev)) conn_type = CONNECTION_P2P_GC; else conn_type = CONNECTION_INFRA_STA; basic->conn_type = cpu_to_le32(conn_type); - basic->aid = cpu_to_le16(sta->aid); + basic->aid = cpu_to_le16(link_sta->sta->aid); break; case NL80211_IFTYPE_STATION: if (vif->p2p && !is_mt7921(dev)) conn_type = CONNECTION_P2P_GO; else conn_type = CONNECTION_INFRA_AP; basic->conn_type = cpu_to_le32(conn_type); basic->aid = cpu_to_le16(vif->cfg.aid); break; case NL80211_IFTYPE_ADHOC: basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); - basic->aid = cpu_to_le16(sta->aid); + basic->aid = cpu_to_le16(link_sta->sta->aid); break; default: WARN_ON(1); break; } - memcpy(basic->peer_addr, sta->addr, ETH_ALEN); - basic->qos = sta->wme; + memcpy(basic->peer_addr, link_sta->addr, ETH_ALEN); + basic->qos = link_sta->sta->wme; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv); void mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct sta_rec_uapsd *uapsd; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_AP || !sta->wme) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); uapsd = (struct sta_rec_uapsd *)tlv; if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { uapsd->dac_map |= BIT(3); uapsd->tac_map |= BIT(3); } if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { uapsd->dac_map |= BIT(2); uapsd->tac_map |= BIT(2); } if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { uapsd->dac_map |= BIT(1); uapsd->tac_map |= BIT(1); } if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { uapsd->dac_map |= BIT(0); uapsd->tac_map |= BIT(0); } uapsd->max_sp = sta->max_sp; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_uapsd); 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) { struct wtbl_hdr_trans *htr; struct tlv *tlv; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HDR_TRANS, sizeof(*htr), wtbl_tlv, sta_wtbl); htr = (struct wtbl_hdr_trans *)tlv; htr->no_rx_trans = true; if (vif->type == NL80211_IFTYPE_STATION) htr->to_ds = true; else htr->from_ds = true; if (!wcid) return; htr->no_rx_trans = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); 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 mt76_vif_link *mvif = (struct mt76_vif_link *)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); int mt76_connac_mcu_wtbl_update_hdr_trans(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct wtbl_req_hdr *wtbl_hdr; struct sk_buff *skb = NULL; wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, wcid, WTBL_SET, NULL, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, NULL, wtbl_hdr); return mt76_mcu_skb_send_msg(dev, skb, MCU_EXT_CMD(WTBL_UPDATE), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_update_hdr_trans); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct wtbl_generic *generic; struct wtbl_rx *rx; struct wtbl_spe *spe; struct tlv *tlv; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic), wtbl_tlv, sta_wtbl); generic = (struct wtbl_generic *)tlv; if (sta) { if (vif->type == NL80211_IFTYPE_STATION) generic->partial_aid = cpu_to_le16(vif->cfg.aid); else generic->partial_aid = cpu_to_le16(sta->aid); memcpy(generic->peer_addr, sta->addr, ETH_ALEN); generic->muar_idx = mvif->omac_idx; generic->qos = sta->wme; } else { if (!is_connac_v1(dev) && vif->type == NL80211_IFTYPE_STATION) memcpy(generic->peer_addr, vif->bss_conf.bssid, ETH_ALEN); else eth_broadcast_addr(generic->peer_addr); generic->muar_idx = 0xe; } tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx), wtbl_tlv, sta_wtbl); rx = (struct wtbl_rx *)tlv; rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1; rx->rca2 = 1; rx->rv = 1; if (!is_connac_v1(dev)) return; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SPE, sizeof(*spe), wtbl_tlv, sta_wtbl); spe = (struct wtbl_spe *)tlv; spe->spe_idx = 24; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_generic_tlv); static void mt76_connac_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct sta_rec_amsdu *amsdu; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_STATION) return; if (!sta->deflink.agg.max_amsdu_len) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); amsdu = (struct sta_rec_amsdu *)tlv; amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; amsdu->max_mpdu_size = sta->deflink.agg.max_amsdu_len >= IEEE80211_MAX_MPDU_LEN_VHT_7991; wcid->amsdu = true; } #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) static void mt76_connac_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; struct sta_rec_he *he; struct tlv *tlv; u32 cap = 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); he = (struct sta_rec_he *)tlv; if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) cap |= STA_REC_HE_CAP_HTC; if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) cap |= STA_REC_HE_CAP_BSR; if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) cap |= STA_REC_HE_CAP_OM; if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU) cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) cap |= STA_REC_HE_CAP_BQR; if (elem->phy_cap_info[0] & (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; if (elem->phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) cap |= STA_REC_HE_CAP_LDPC; if (elem->phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; if (elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; if (elem->phy_cap_info[8] & IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; if (elem->phy_cap_info[8] & IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK) cap |= STA_REC_HE_CAP_TRIG_CQI_FK; if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; he->he_cap = cpu_to_le32(cap); switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) he->max_nss_mcs[CMD_HE_MCS_BW8080] = he_cap->he_mcs_nss_supp.rx_mcs_80p80; he->max_nss_mcs[CMD_HE_MCS_BW160] = he_cap->he_mcs_nss_supp.rx_mcs_160; fallthrough; default: he->max_nss_mcs[CMD_HE_MCS_BW80] = he_cap->he_mcs_nss_supp.rx_mcs_80; break; } he->t_frame_dur = HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); he->max_ampdu_exp = HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); he->bw_set = HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); he->device_class = HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); he->punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); he->dcm_tx_mode = HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); he->dcm_tx_max_nss = HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); he->dcm_rx_mode = HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); he->pkt_ext = 2; } -static void +void mt76_connac_mcu_sta_he_tlv_v2(struct sk_buff *skb, struct ieee80211_sta *sta) { struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; struct sta_rec_he_v2 *he; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he)); he = (struct sta_rec_he_v2 *)tlv; memcpy(he->he_phy_cap, elem->phy_cap_info, sizeof(he->he_phy_cap)); memcpy(he->he_mac_cap, elem->mac_cap_info, sizeof(he->he_mac_cap)); switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) he->max_nss_mcs[CMD_HE_MCS_BW8080] = he_cap->he_mcs_nss_supp.rx_mcs_80p80; he->max_nss_mcs[CMD_HE_MCS_BW160] = he_cap->he_mcs_nss_supp.rx_mcs_160; fallthrough; default: he->max_nss_mcs[CMD_HE_MCS_BW80] = he_cap->he_mcs_nss_supp.rx_mcs_80; break; } he->pkt_ext = IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US; } +EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_he_tlv_v2); -static u8 +u8 mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta) + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) { struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; const struct ieee80211_sta_he_cap *he_cap; + const struct ieee80211_sta_eht_cap *eht_cap; u8 mode = 0; - if (sta) { - ht_cap = &sta->deflink.ht_cap; - vht_cap = &sta->deflink.vht_cap; - he_cap = &sta->deflink.he_cap; + if (link_sta) { + ht_cap = &link_sta->ht_cap; + vht_cap = &link_sta->vht_cap; + he_cap = &link_sta->he_cap; + eht_cap = &link_sta->eht_cap; } else { struct ieee80211_supported_band *sband; sband = mphy->hw->wiphy->bands[band]; ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); + eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); } if (band == NL80211_BAND_2GHZ) { mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP; if (ht_cap->ht_supported) mode |= PHY_TYPE_BIT_HT; if (he_cap && he_cap->has_he) mode |= PHY_TYPE_BIT_HE; + + if (eht_cap && eht_cap->has_eht) + mode |= PHY_TYPE_BIT_BE; } else if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) { mode |= PHY_TYPE_BIT_OFDM; if (ht_cap->ht_supported) mode |= PHY_TYPE_BIT_HT; if (vht_cap->vht_supported) mode |= PHY_TYPE_BIT_VHT; if (he_cap && he_cap->has_he) mode |= PHY_TYPE_BIT_HE; + + if (eht_cap && eht_cap->has_eht) + mode |= PHY_TYPE_BIT_BE; } return mode; } +EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode_v2); 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 sta_state) { - struct cfg80211_chan_def *chandef = &mphy->chandef; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct cfg80211_chan_def *chandef = mvif->ctx ? + &mvif->ctx->def : &mphy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_dev *dev = mphy->dev; struct sta_rec_ra_info *ra_info; struct sta_rec_state *state; struct sta_rec_phy *phy; struct tlv *tlv; u16 supp_rates; /* starec ht */ if (sta->deflink.ht_cap.ht_supported) { struct sta_rec_ht *ht; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); ht = (struct sta_rec_ht *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); } /* starec vht */ if (sta->deflink.vht_cap.vht_supported) { struct sta_rec_vht *vht; int len; len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); vht = (struct sta_rec_vht *)tlv; vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; } /* starec uapsd */ mt76_connac_mcu_sta_uapsd(skb, vif, sta); if (!is_mt7921(dev)) return; if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he) mt76_connac_mcu_sta_amsdu_tlv(skb, sta, vif); /* starec he */ if (sta->deflink.he_cap.has_he) { mt76_connac_mcu_sta_he_tlv(skb, sta); mt76_connac_mcu_sta_he_tlv_v2(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->deflink.he_6ghz_capa.capa; } } tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; - phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, sta); + phy->phy_type = mt76_connac_get_phy_mode_v2(mphy, vif, band, + &sta->deflink); phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates); phy->rcpi = rcpi; phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, sta->deflink.ht_cap.ampdu_factor) | FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, sta->deflink.ht_cap.ampdu_density); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; supp_rates = sta->deflink.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->deflink.ht_cap.ht_supported) memcpy(ra_info->rx_mcs_bitmask, sta->deflink.ht_cap.mcs.rx_mask, HT_MCS_MASK_NUM); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); state = (struct sta_rec_state *)tlv; state->state = sta_state; if (sta->deflink.vht_cap.vht_supported) { state->vht_opmode = sta->deflink.bandwidth; state->vht_opmode |= (sta->deflink.rx_nss - 1) << IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; } } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_tlv); void mt76_connac_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv) { struct wtbl_smps *smps; struct tlv *tlv; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps), wtbl_tlv, sta_wtbl); smps = (struct wtbl_smps *)tlv; smps->smps = (sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_smps_tlv); void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv, bool ht_ldpc, bool vht_ldpc) { struct wtbl_ht *ht = NULL; struct tlv *tlv; u32 flags = 0; if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_6ghz_capa.capa) { tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht), wtbl_tlv, sta_wtbl); ht = (struct wtbl_ht *)tlv; ht->ldpc = ht_ldpc && !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING); if (sta->deflink.ht_cap.ht_supported) { ht->af = sta->deflink.ht_cap.ampdu_factor; ht->mm = sta->deflink.ht_cap.ampdu_density; } else { ht->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); ht->mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); } ht->ht = true; } if (sta->deflink.vht_cap.vht_supported || sta->deflink.he_6ghz_capa.capa) { struct wtbl_vht *vht; u8 af; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht), wtbl_tlv, sta_wtbl); vht = (struct wtbl_vht *)tlv; vht->ldpc = vht_ldpc && !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); vht->vht = true; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->deflink.vht_cap.cap); if (ht) ht->af = max(ht->af, af); } mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv); if (is_connac_v1(dev) && sta->deflink.ht_cap.ht_supported) { /* sgi */ u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 | MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160; struct wtbl_raw *raw; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_RAW_DATA, sizeof(*raw), wtbl_tlv, sta_wtbl); if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) flags |= MT_WTBL_W5_SHORT_GI_20; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) flags |= MT_WTBL_W5_SHORT_GI_40; if (sta->deflink.vht_cap.vht_supported) { if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) flags |= MT_WTBL_W5_SHORT_GI_80; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) flags |= MT_WTBL_W5_SHORT_GI_160; } raw = (struct wtbl_raw *)tlv; raw->val = cpu_to_le32(flags); raw->msk = cpu_to_le32(~msk); raw->wtbl_idx = 1; raw->dw = 5; } } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ht_tlv); 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_vif_link *mvif = (struct mt76_vif_link *)info->vif->drv_priv; + struct ieee80211_link_sta *link_sta; struct mt76_dev *dev = phy->dev; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; + int conn_state; + + if (!info->link_conf) + info->link_conf = &info->vif->bss_conf; skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); + conn_state = info->enable ? CONN_STATE_PORT_SECURE : + CONN_STATE_DISCONNECT; + link_sta = info->sta ? &info->sta->deflink : NULL; if (info->sta || !info->offload_fw) - mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta, - info->enable, info->newly); + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, + link_sta, conn_state, + 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)); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(dev, info->wcid, WTBL_RESET_AND_SET, sta_wtbl, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); if (info->enable) { 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, true, true); } return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); } 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, bool enable, bool tx, void *sta_wtbl, void *wtbl_tlv) { struct wtbl_ba *ba; struct tlv *tlv; tlv = mt76_connac_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba), wtbl_tlv, sta_wtbl); ba = (struct wtbl_ba *)tlv; ba->tid = params->tid; if (tx) { ba->ba_type = MT_BA_TYPE_ORIGINATOR; ba->sn = enable ? cpu_to_le16(params->ssn) : 0; ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0; ba->ba_en = enable; } else { memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN); ba->ba_type = MT_BA_TYPE_RECIPIENT; ba->rst_ba_tid = params->tid; ba->rst_ba_sel = RST_BA_MAC_TID_MATCH; ba->rst_ba_sb = 1; } if (!is_connac_v1(dev)) { ba->ba_winsize = enable ? cpu_to_le16(params->buf_size) : 0; return; } if (enable && tx) { static const u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 }; int i; for (i = 7; i > 0; i--) { if (params->buf_size >= ba_range[i]) break; } ba->ba_winsize_idx = i; } } EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_ba_tlv); int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + struct mt76_vif_link *mvif, struct mt76_wcid *wcid, bool enable) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt76_dev *dev = phy->dev; struct { struct { u8 omac_idx; u8 band_idx; __le16 pad; } __packed hdr; struct req_tlv { __le16 tag; __le16 len; u8 active; - u8 pad; + u8 link_idx; /* not link_id */ u8 omac_addr[ETH_ALEN]; } __packed tlv; } dev_req = { .hdr = { .omac_idx = mvif->omac_idx, .band_idx = mvif->band_idx, }, .tlv = { .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, + .link_idx = mvif->idx, }, }; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_bss_basic_tlv basic; } basic_req = { .hdr = { .bss_idx = mvif->idx, }, .basic = { .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)), .omac_idx = mvif->omac_idx, .band_idx = mvif->band_idx, .wmm_idx = mvif->wmm_idx, .active = enable, .bmc_tx_wlan_idx = cpu_to_le16(wcid->idx), .sta_idx = cpu_to_le16(wcid->idx), .conn_state = 1, + .link_idx = mvif->idx, }, }; int err, idx, cmd, len; void *data; - switch (vif->type) { + switch (bss_conf->vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); break; case NL80211_IFTYPE_STATION: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); break; + case NL80211_IFTYPE_P2P_DEVICE: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_P2P_GO); + break; case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); break; default: WARN_ON(1); break; } idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; basic_req.basic.hw_bss_idx = idx; - memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); + memcpy(dev_req.tlv.omac_addr, bss_conf->addr, ETH_ALEN); cmd = enable ? MCU_UNI_CMD(DEV_INFO_UPDATE) : MCU_UNI_CMD(BSS_INFO_UPDATE); data = enable ? (void *)&dev_req : (void *)&basic_req; len = enable ? sizeof(dev_req) : sizeof(basic_req); err = mt76_mcu_send_msg(dev, cmd, data, len, true); if (err < 0) return err; cmd = enable ? MCU_UNI_CMD(BSS_INFO_UPDATE) : MCU_UNI_CMD(DEV_INFO_UPDATE); data = enable ? (void *)&basic_req : (void *)&dev_req; len = enable ? sizeof(basic_req) : sizeof(dev_req); return mt76_mcu_send_msg(dev, cmd, data, len, true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_dev); void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb, struct ieee80211_ampdu_params *params, bool enable, bool tx) { struct sta_rec_ba *ba; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); ba = (struct sta_rec_ba *)tlv; ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT; ba->winsize = cpu_to_le16(params->buf_size); ba->ssn = cpu_to_le16(params->ssn); ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba_tlv); int mt76_connac_mcu_sta_wed_update(struct mt76_dev *dev, struct sk_buff *skb) { if (!mt76_is_mmio(dev)) return 0; if (!mtk_wed_device_active(&dev->mmio.wed)) return 0; return mtk_wed_device_update_msg(&dev->mmio.wed, WED_WO_STA_REC, skb->data, skb->len); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_wed_update); -int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, struct ieee80211_ampdu_params *params, int cmd, bool enable, bool tx) { struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; int ret; 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_ba_tlv(dev, skb, params, enable, tx, sta_wtbl, wtbl_hdr); ret = mt76_connac_mcu_sta_wed_update(dev, skb); if (ret) return ret; ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); if (ret) return ret; skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); if (IS_ERR(skb)) return PTR_ERR(skb); mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); ret = mt76_connac_mcu_sta_wed_update(dev, skb); if (ret) return ret; return mt76_mcu_skb_send_msg(dev, skb, cmd, true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba); u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta) + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) { struct mt76_dev *dev = phy->dev; const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_sta_vht_cap *vht_cap; struct ieee80211_sta_ht_cap *ht_cap; u8 mode = 0; if (is_connac_v1(dev)) return 0x38; - if (sta) { - ht_cap = &sta->deflink.ht_cap; - vht_cap = &sta->deflink.vht_cap; - he_cap = &sta->deflink.he_cap; + if (link_sta) { + ht_cap = &link_sta->ht_cap; + vht_cap = &link_sta->vht_cap; + he_cap = &link_sta->he_cap; } else { struct ieee80211_supported_band *sband; sband = phy->hw->wiphy->bands[band]; ht_cap = &sband->ht_cap; vht_cap = &sband->vht_cap; he_cap = ieee80211_get_he_iftype_cap(sband, vif->type); } if (band == NL80211_BAND_2GHZ) { mode |= PHY_MODE_B | PHY_MODE_G; if (ht_cap->ht_supported) mode |= PHY_MODE_GN; if (he_cap && he_cap->has_he) mode |= PHY_MODE_AX_24G; } else if (band == NL80211_BAND_5GHZ) { mode |= PHY_MODE_A; if (ht_cap->ht_supported) mode |= PHY_MODE_AN; if (vht_cap->vht_supported) mode |= PHY_MODE_AC; if (he_cap && he_cap->has_he) mode |= PHY_MODE_AX_5G; } else if (band == NL80211_BAND_6GHZ) { mode |= PHY_MODE_A | PHY_MODE_AN | PHY_MODE_AC | PHY_MODE_AX_5G; } return mode; } EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode); -u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, +u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf, enum nl80211_band band) { const struct ieee80211_sta_eht_cap *eht_cap; struct ieee80211_supported_band *sband; u8 mode = 0; if (band == NL80211_BAND_6GHZ) mode |= PHY_MODE_AX_6G; sband = phy->hw->wiphy->bands[band]; - eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); + eht_cap = ieee80211_get_eht_iftype_cap(sband, conf->vif->type); - if (!eht_cap || !eht_cap->has_eht) + if (!eht_cap || !eht_cap->has_eht || !conf->eht_support) return mode; switch (band) { case NL80211_BAND_6GHZ: mode |= PHY_MODE_BE_6G; break; case NL80211_BAND_5GHZ: mode |= PHY_MODE_BE_5G; break; case NL80211_BAND_2GHZ: mode |= PHY_MODE_BE_24G; break; default: break; } return mode; } EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode_ext); const struct ieee80211_sta_he_cap * mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif) { - enum nl80211_band band = phy->chandef.chan->band; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct cfg80211_chan_def *chandef = mvif->ctx ? + &mvif->ctx->def : &phy->chandef; + enum nl80211_band band = chandef->chan->band; struct ieee80211_supported_band *sband; sband = phy->hw->wiphy->bands[band]; return ieee80211_get_he_iftype_cap(sband, vif->type); } EXPORT_SYMBOL_GPL(mt76_connac_get_he_phy_cap); const struct ieee80211_sta_eht_cap * mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif) { enum nl80211_band band = phy->chandef.chan->band; struct ieee80211_supported_band *sband; sband = phy->hw->wiphy->bands[band]; return ieee80211_get_eht_iftype_cap(sband, vif->type); } EXPORT_SYMBOL_GPL(mt76_connac_get_eht_phy_cap); #define DEFAULT_HE_PE_DURATION 4 #define DEFAULT_HE_DURATION_RTS_THRES 1023 static void mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif, struct tlv *tlv) { const struct ieee80211_sta_he_cap *cap; struct bss_info_uni_he *he; cap = mt76_connac_get_he_phy_cap(phy, vif); he = (struct bss_info_uni_he *)tlv; he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; if (!he->he_pe_duration) he->he_pe_duration = DEFAULT_HE_PE_DURATION; he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); if (!he->he_rts_thres) he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; } -int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy, struct mt76_vif *mvif, +int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, struct ieee80211_chanctx_conf *ctx) { struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; enum nl80211_band band = chandef->chan->band; struct mt76_dev *mdev = phy->dev; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct rlm_tlv { __le16 tag; __le16 len; u8 control_channel; u8 center_chan; u8 center_chan2; u8 bw; u8 tx_streams; u8 rx_streams; u8 short_st; u8 ht_op_info; u8 sco; u8 band; u8 pad[2]; } __packed rlm; } __packed rlm_req = { .hdr = { .bss_idx = mvif->idx, }, .rlm = { .tag = cpu_to_le16(UNI_BSS_INFO_RLM), .len = cpu_to_le16(sizeof(struct rlm_tlv)), .control_channel = chandef->chan->hw_value, .center_chan = ieee80211_frequency_to_channel(freq1), .center_chan2 = ieee80211_frequency_to_channel(freq2), .tx_streams = hweight8(phy->antenna_mask), .ht_op_info = 4, /* set HT 40M allowed */ .rx_streams = phy->chainmask, .short_st = true, .band = band, }, }; switch (chandef->width) { case NL80211_CHAN_WIDTH_40: rlm_req.rlm.bw = CMD_CBW_40MHZ; break; case NL80211_CHAN_WIDTH_80: rlm_req.rlm.bw = CMD_CBW_80MHZ; break; case NL80211_CHAN_WIDTH_80P80: rlm_req.rlm.bw = CMD_CBW_8080MHZ; break; case NL80211_CHAN_WIDTH_160: rlm_req.rlm.bw = CMD_CBW_160MHZ; break; case NL80211_CHAN_WIDTH_5: rlm_req.rlm.bw = CMD_CBW_5MHZ; break; case NL80211_CHAN_WIDTH_10: rlm_req.rlm.bw = CMD_CBW_10MHZ; break; case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20: default: rlm_req.rlm.bw = CMD_CBW_20MHZ; rlm_req.rlm.ht_op_info = 0; break; } if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan) rlm_req.rlm.sco = 1; /* SCA */ else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan) rlm_req.rlm.sco = 3; /* SCB */ return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &rlm_req, sizeof(rlm_req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_set_chctx); int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_wcid *wcid, bool enable, struct ieee80211_chanctx_conf *ctx) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &phy->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_dev *mdev = phy->dev; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_bss_basic_tlv basic; struct mt76_connac_bss_qos_tlv qos; } basic_req = { .hdr = { .bss_idx = mvif->idx, }, .basic = { .tag = cpu_to_le16(UNI_BSS_INFO_BASIC), .len = cpu_to_le16(sizeof(struct mt76_connac_bss_basic_tlv)), .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), .dtim_period = vif->bss_conf.dtim_period, .omac_idx = mvif->omac_idx, .band_idx = mvif->band_idx, .wmm_idx = mvif->wmm_idx, .active = true, /* keep bss deactivated */ .phymode = mt76_connac_get_phy_mode(phy, vif, band, NULL), }, .qos = { .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), .len = cpu_to_le16(sizeof(struct mt76_connac_bss_qos_tlv)), .qos = vif->bss_conf.qos, }, }; int err, conn_type; 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 = PHY_MODE_AX_6G; 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: case NL80211_IFTYPE_AP: if (vif->p2p) conn_type = CONNECTION_P2P_GO; else conn_type = CONNECTION_INFRA_AP; basic_req.basic.conn_type = cpu_to_le32(conn_type); /* Fully active/deactivate BSS network in AP mode only */ basic_req.basic.active = enable; break; case NL80211_IFTYPE_STATION: if (vif->p2p) conn_type = CONNECTION_P2P_GC; else conn_type = CONNECTION_INFRA_STA; basic_req.basic.conn_type = cpu_to_le32(conn_type); break; case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); break; default: WARN_ON(1); break; } memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN); basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(wcid->idx); basic_req.basic.sta_idx = cpu_to_le16(wcid->idx); basic_req.basic.conn_state = !enable; err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), &basic_req, sizeof(basic_req), true); if (err < 0) return err; if (vif->bss_conf.he_support) { struct { struct { u8 bss_idx; 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, }, .he = { .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), &he_req, sizeof(he_req), true); if (err < 0) return err; } return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss); #define MT76_CONNAC_SCAN_CHANNEL_TIME 60 int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct cfg80211_scan_request *sreq = &scan_req->req; int n_ssids = 0, err, i, duration; int ext_channels_num = max_t(int, sreq->n_channels - 32, 0); struct ieee80211_channel **scan_list = sreq->channels; struct mt76_dev *mdev = phy->dev; struct mt76_connac_mcu_scan_channel *chan; struct mt76_connac_hw_scan_req *req; struct sk_buff *skb; if (test_bit(MT76_HW_SCANNING, &phy->state)) return -EBUSY; skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req)); if (!skb) return -ENOMEM; set_bit(MT76_HW_SCANNING, &phy->state); mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; - req = (struct mt76_connac_hw_scan_req *)skb_put(skb, sizeof(*req)); + req = (struct mt76_connac_hw_scan_req *)skb_put_zero(skb, sizeof(*req)); req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7; req->bss_idx = mvif->idx; req->scan_type = sreq->n_ssids ? 1 : 0; req->probe_req_num = sreq->n_ssids ? 2 : 0; req->version = 1; for (i = 0; i < sreq->n_ssids; i++) { if (!sreq->ssids[i].ssid_len) continue; req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid, sreq->ssids[i].ssid_len); n_ssids++; } req->ssid_type = n_ssids ? BIT(2) : BIT(0); req->ssid_type_ext = n_ssids ? BIT(0) : 0; req->ssids_num = n_ssids; duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME; /* increase channel time for passive scan */ if (!sreq->n_ssids) duration *= 2; req->timeout_value = cpu_to_le16(sreq->n_channels * duration); req->channel_min_dwell_time = cpu_to_le16(duration); req->channel_dwell_time = cpu_to_le16(duration); if (sreq->n_channels == 0 || sreq->n_channels > 64) { req->channel_type = 0; req->channels_num = 0; req->ext_channels_num = 0; } else { req->channel_type = 4; req->channels_num = min_t(u8, sreq->n_channels, 32); req->ext_channels_num = min_t(u8, ext_channels_num, 32); } for (i = 0; i < req->channels_num + req->ext_channels_num; i++) { if (i >= 32) chan = &req->ext_channels[i - 32]; else chan = &req->channels[i]; 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; } if (sreq->ie_len > 0) { memcpy(req->ies, sreq->ie, sreq->ie_len); req->ies_len = cpu_to_le16(sreq->ie_len); } if (is_mt7921(phy->dev)) req->scan_func |= SCAN_FUNC_SPLIT_SCAN; memcpy(req->bssid, sreq->bssid, ETH_ALEN); if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { get_random_mask_addr(req->random_mac, sreq->mac_addr, sreq->mac_addr_mask); req->scan_func |= SCAN_FUNC_RANDOM_MAC; } err = mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(START_HW_SCAN), false); if (err < 0) clear_bit(MT76_HW_SCANNING, &phy->state); return err; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_hw_scan); int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { u8 seq_num; u8 is_ext_channel; u8 rsv[2]; } __packed req = { .seq_num = mvif->scan_seq_num, }; if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) { struct cfg80211_scan_info info = { .aborted = true, }; ieee80211_scan_completed(phy->hw, &info); } return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(CANCEL_HW_SCAN), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_cancel_hw_scan); int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *sreq) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct ieee80211_channel **scan_list = sreq->channels; struct mt76_connac_mcu_scan_channel *chan; struct mt76_connac_sched_scan_req *req; struct mt76_dev *mdev = phy->dev; struct cfg80211_match_set *match; struct cfg80211_ssid *ssid; struct sk_buff *skb; int i; skb = mt76_mcu_msg_alloc(mdev, NULL, sizeof(*req) + sreq->ie_len); if (!skb) return -ENOMEM; mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; - req = (struct mt76_connac_sched_scan_req *)skb_put(skb, sizeof(*req)); + req = (struct mt76_connac_sched_scan_req *)skb_put_zero(skb, sizeof(*req)); req->version = 1; req->seq_num = mvif->scan_seq_num | mvif->band_idx << 7; 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; get_random_mask_addr(addr, sreq->mac_addr, sreq->mac_addr_mask); } 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++) { ssid = &sreq->ssids[i]; memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len); req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len); } req->match_num = sreq->n_match_sets; for (i = 0; i < req->match_num; i++) { match = &sreq->match_sets[i]; memcpy(req->match[i].ssid, match->ssid.ssid, match->ssid.ssid_len); req->match[i].rssi_th = cpu_to_le32(match->rssi_thold); req->match[i].ssid_len = match->ssid.ssid_len; } req->channel_type = sreq->n_channels ? 4 : 0; req->channels_num = min_t(u8, sreq->n_channels, 64); for (i = 0; i < req->channels_num; i++) { chan = &req->channels[i]; 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->intervals_num = sreq->n_scan_plans; for (i = 0; i < req->intervals_num; i++) req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); if (sreq->ie_len > 0) { req->ie_len = cpu_to_le16(sreq->ie_len); memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len); } return mt76_mcu_skb_send_msg(mdev, skb, MCU_CE_CMD(SCHED_SCAN_REQ), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_req); int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, struct ieee80211_vif *vif, bool enable) { struct { u8 active; /* 0: enabled 1: disabled */ u8 rsv[3]; } __packed req = { .active = !enable, }; if (enable) set_bit(MT76_HW_SCHED_SCANNING, &phy->state); else clear_bit(MT76_HW_SCHED_SCANNING, &phy->state); return mt76_mcu_send_msg(phy->dev, MCU_CE_CMD(SCHED_SCAN_ENABLE), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable); int mt76_connac_mcu_chip_config(struct mt76_dev *dev) { struct mt76_connac_config req = { .resp_type = 0, }; memcpy(req.data, "assert", 7); return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config); int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable) { struct mt76_connac_config req = { .resp_type = 0, }; snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable); return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG), &req, sizeof(req), false); } 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) { spin_lock_bh(&dev->lock); __skb_queue_tail(&coredump->msg_list, skb); spin_unlock_bh(&dev->lock); coredump->last_activity = jiffies; queue_delayed_work(dev->wq, &coredump->work, MT76_CONNAC_COREDUMP_TIMEOUT); } 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 { - __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_CE_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; - 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; - } - 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, enum nl80211_band band) { int max_power = is_mt7921(dev) ? 127 : 63; int i, offset = sizeof(limits->cck); memset(sku, max_power, MT_SKU_POWER_LIMIT); if (band == NL80211_BAND_2GHZ) { /* cck */ memcpy(sku, limits->cck, sizeof(limits->cck)); } /* ofdm */ memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm)); offset += sizeof(limits->ofdm); /* ht */ for (i = 0; i < 2; i++) { memcpy(&sku[offset], limits->mcs[i], 8); offset += 8; } sku[offset++] = limits->mcs[0][0]; /* vht */ for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) { memcpy(&sku[offset], limits->mcs[i], ARRAY_SIZE(limits->mcs[i])); offset += 12; } if (!is_mt7921(dev)) return; /* he */ for (i = 0; i < ARRAY_SIZE(limits->ru); i++) { memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i])); offset += ARRAY_SIZE(limits->ru[i]); } } -static s8 mt76_connac_get_ch_power(struct mt76_phy *phy, - struct ieee80211_channel *chan, - s8 target_power) +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; } +EXPORT_SYMBOL_GPL(mt76_connac_get_ch_power); static int mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, enum nl80211_band band) { struct mt76_dev *dev = phy->dev; int sku_len, batch_len = is_mt7921(dev) ? 8 : 16; static const u8 chan_list_2ghz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; static const u8 chan_list_5ghz[] = { 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, 155, 157, - 159, 161, 165 + 159, 161, 165, 169, 173, 177 }; 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; + int i, n_chan, batch_size, idx = 0, tx_power, last_ch, err = 0; struct mt76_connac_sku_tlv sku_tlbv; - struct mt76_power_limits limits; + struct mt76_power_limits *limits; const u8 *ch_list; + limits = devm_kmalloc(dev->dev, sizeof(*limits), GFP_KERNEL); + if (!limits) + return -ENOMEM; + 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); 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; } batch_size = DIV_ROUND_UP(n_chan, batch_len); if (phy->cap.has_6ghz) last_ch = chan_list_6ghz[ARRAY_SIZE(chan_list_6ghz) - 1]; else if (phy->cap.has_5ghz) last_ch = chan_list_5ghz[ARRAY_SIZE(chan_list_5ghz) - 1]; else last_ch = chan_list_2ghz[ARRAY_SIZE(chan_list_2ghz) - 1]; for (i = 0; i < batch_size; i++) { struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {}; - int j, err, msg_len, num_ch; + int j, msg_len, num_ch; struct sk_buff *skb; - num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; + num_ch = i == batch_size - 1 ? n_chan - i * 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; + if (!skb) { + err = -ENOMEM; + goto out; + } 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; 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_get_sar_power(phy, &chan, reg_power); - mt76_get_rate_power_limits(phy, &chan, &limits, + mt76_get_rate_power_limits(phy, &chan, limits, sar_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); + 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_CE_CMD(SET_RATE_TX_POWER), false); if (err < 0) - return err; + goto out; } - return 0; +out: + devm_kfree(dev->dev, limits); + return err; } int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy) { int 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; } if (phy->cap.has_6ghz) { err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_6GHZ); if (err < 0) return err; } return 0; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower); int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif, + struct mt76_vif_link *vif, struct ieee80211_bss_conf *info) { struct ieee80211_vif *mvif = container_of(info, struct ieee80211_vif, bss_conf); struct sk_buff *skb; int i, len = min_t(int, mvif->cfg.arp_addr_cnt, IEEE80211_BSS_ARP_ADDR_LIST_LEN); struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_arpns_tlv arp; } req_hdr = { .hdr = { .bss_idx = vif->idx, }, .arp = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), .ips_num = len, .mode = 2, /* update */ .option = 1, }, }; skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(req_hdr) + len * sizeof(__be32)); if (!skb) return -ENOMEM; skb_put_data(skb, &req_hdr, sizeof(req_hdr)); for (i = 0; i < len; i++) skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true); } 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; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)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_CE_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 = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | WIPHY_WOWLAN_NET_DETECT, .n_patterns = 1, .pattern_min_len = 1, .pattern_max_len = MT76_CONNAC_WOW_PATTEN_MAX_LEN, .max_nd_match_sets = 10, }; EXPORT_SYMBOL_GPL(mt76_connac_wowlan_support); static void mt76_connac_mcu_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, void *data) { struct mt76_connac_gtk_rekey_tlv *gtk_tlv = data; u32 cipher; if (key->cipher != WLAN_CIPHER_SUITE_AES_CMAC && key->cipher != WLAN_CIPHER_SUITE_CCMP && key->cipher != WLAN_CIPHER_SUITE_TKIP) return; if (key->cipher == WLAN_CIPHER_SUITE_TKIP) cipher = BIT(3); 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->keyid = key->keyidx; } else { gtk_tlv->group_cipher = cpu_to_le32(cipher); } } int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *key) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt76_connac_gtk_rekey_tlv *gtk_tlv; struct mt76_phy *phy = hw->priv; struct sk_buff *skb; struct { u8 bss_idx; u8 pad[3]; } __packed hdr = { .bss_idx = mvif->idx, }; skb = mt76_mcu_msg_alloc(phy->dev, NULL, sizeof(hdr) + sizeof(*gtk_tlv)); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); - gtk_tlv = (struct mt76_connac_gtk_rekey_tlv *)skb_put(skb, + gtk_tlv = (struct mt76_connac_gtk_rekey_tlv *)skb_put_zero(skb, sizeof(*gtk_tlv)); gtk_tlv->tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY); gtk_tlv->len = cpu_to_le16(sizeof(*gtk_tlv)); gtk_tlv->rekey_mode = 2; gtk_tlv->option = 1; rcu_read_lock(); ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv); rcu_read_unlock(); memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN); return mt76_mcu_skb_send_msg(phy->dev, skb, MCU_UNI_CMD(OFFLOAD), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_gtk_rekey); static int mt76_connac_mcu_set_arp_filter(struct mt76_dev *dev, struct ieee80211_vif *vif, bool suspend) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_arpns_tlv arpns; } req = { .hdr = { .bss_idx = mvif->idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), .mode = suspend, }, }; return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req, sizeof(req), true); } -static int +int mt76_connac_mcu_set_gtk_rekey(struct mt76_dev *dev, struct ieee80211_vif *vif, bool suspend) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_gtk_rekey_tlv gtk_tlv; } __packed req = { .hdr = { .bss_idx = mvif->idx, }, .gtk_tlv = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_GTK_REKEY), .len = cpu_to_le16(sizeof(struct mt76_connac_gtk_rekey_tlv)), .rekey_mode = !suspend, }, }; return mt76_mcu_send_msg(dev, MCU_UNI_CMD(OFFLOAD), &req, sizeof(req), true); } +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_gtk_rekey); -static int +int mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev, struct ieee80211_vif *vif, bool enable, u8 mdtim, bool wow_suspend) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_suspend_tlv suspend_tlv; } req = { .hdr = { .bss_idx = mvif->idx, }, .suspend_tlv = { .tag = cpu_to_le16(UNI_SUSPEND_MODE_SETTING), .len = cpu_to_le16(sizeof(struct mt76_connac_suspend_tlv)), .enable = enable, .mdtim = mdtim, .wow_suspend = wow_suspend, }, }; return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req, sizeof(req), true); } +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_mode); static int mt76_connac_mcu_set_wow_pattern(struct mt76_dev *dev, struct ieee80211_vif *vif, u8 index, bool enable, struct cfg80211_pkt_pattern *pattern) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt76_connac_wow_pattern_tlv *ptlv; struct sk_buff *skb; struct req_hdr { u8 bss_idx; u8 pad[3]; } __packed hdr = { .bss_idx = mvif->idx, }; skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*ptlv)); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); - ptlv = (struct mt76_connac_wow_pattern_tlv *)skb_put(skb, sizeof(*ptlv)); + ptlv = (struct mt76_connac_wow_pattern_tlv *)skb_put_zero(skb, sizeof(*ptlv)); ptlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); ptlv->len = cpu_to_le16(sizeof(*ptlv)); ptlv->data_len = pattern->pattern_len; ptlv->enable = enable; ptlv->index = index; memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len); 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); } -static int +int mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, bool suspend, struct cfg80211_wowlan *wowlan) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt76_dev *dev = phy->dev; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv; struct mt76_connac_wow_gpio_param_tlv gpio_tlv; } req = { .hdr = { .bss_idx = mvif->idx, }, .wow_ctrl_tlv = { .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), .len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)), .cmd = suspend ? 1 : 2, }, .gpio_tlv = { .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM), .len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)), .gpio_pin = 0xff, /* follow fw about GPIO pin */ }, }; if (wowlan->magic_pkt) req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC; if (wowlan->disconnect) 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 |= 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; else if (mt76_is_usb(dev)) req.wow_ctrl_tlv.wakeup_hif = WOW_USB; else if (mt76_is_sdio(dev)) req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO; return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req, sizeof(req), true); } +EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_wow_ctrl); -int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend) +int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp) { struct { struct { u8 hif_type; /* 0x0: HIF_SDIO * 0x1: HIF_USB * 0x2: HIF_PCIE */ u8 pad[3]; } __packed hdr; struct hif_suspend_tlv { __le16 tag; __le16 len; u8 suspend; + u8 pad[7]; } __packed hif_suspend; } req = { .hif_suspend = { .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), .suspend = suspend, }, }; if (mt76_is_mmio(dev)) req.hdr.hif_type = 2; else if (mt76_is_usb(dev)) req.hdr.hif_type = 1; else if (mt76_is_sdio(dev)) req.hdr.hif_type = 0; return mt76_mcu_send_msg(dev, MCU_UNI_CMD(HIF_CTRL), &req, - sizeof(req), true); + sizeof(req), wait_resp); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_hif_suspend); void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt76_phy *phy = priv; bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state); struct ieee80211_hw *hw = phy->hw; struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; int i; mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend); mt76_connac_mcu_set_arp_filter(phy->dev, vif, suspend); mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); for (i = 0; i < wowlan->n_patterns; i++) mt76_connac_mcu_set_wow_pattern(phy->dev, vif, i, suspend, &wowlan->patterns[i]); mt76_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_suspend_iter); #endif /* CONFIG_PM */ 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_CE_QUERY(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_CE_CMD(REG_WRITE), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_reg_wr); static int mt76_connac_mcu_sta_key_tlv(struct mt76_connac_sta_key_conf *sta_key_conf, struct sk_buff *skb, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { struct sta_rec_sec *sec; u32 len = sizeof(*sec); struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); sec = (struct sta_rec_sec *)tlv; sec->add = cmd; if (cmd == SET_KEY) { struct sec_key *sec_key; u8 cipher; cipher = mt76_connac_mcu_get_cipher(key->cipher); if (cipher == MCU_CIPHER_NONE) return -EOPNOTSUPP; sec_key = &sec->key[0]; sec_key->cipher_len = sizeof(*sec_key); if (cipher == MCU_CIPHER_BIP_CMAC_128) { sec_key->cipher_id = MCU_CIPHER_AES_CCMP; sec_key->key_id = sta_key_conf->keyidx; sec_key->key_len = 16; memcpy(sec_key->key, sta_key_conf->key, 16); sec_key = &sec->key[1]; sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; sec_key->cipher_len = sizeof(*sec_key); sec_key->key_len = 16; memcpy(sec_key->key, key->key, 16); sec->n_cipher = 2; } else { sec_key->cipher_id = cipher; sec_key->key_id = key->keyidx; sec_key->key_len = key->keylen; memcpy(sec_key->key, key->key, key->keylen); if (cipher == MCU_CIPHER_TKIP) { /* Rx/Tx MIC keys are swapped */ memcpy(sec_key->key + 16, key->key + 24, 8); memcpy(sec_key->key + 24, key->key + 16, 8); } /* store key_conf for BIP batch update */ if (cipher == MCU_CIPHER_AES_CCMP) { memcpy(sta_key_conf->key, key->key, key->keylen); sta_key_conf->keyidx = key->keyidx; } len -= sizeof(*sec_key); sec->n_cipher = 1; } } else { len -= sizeof(sec->key); sec->n_cipher = 0; } sec->len = cpu_to_le16(len); return 0; } int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct sk_buff *skb; int ret; skb = mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid); if (IS_ERR(skb)) return PTR_ERR(skb); ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd); if (ret) return ret; ret = mt76_connac_mcu_sta_wed_update(dev, skb); if (ret) return ret; return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_add_key); /* SIFS 20us + 512 byte beacon transmitted by 1Mbps (3906us) */ #define BCN_TX_ESTIMATE_TIME (4096 + 20) -void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif *mvif) +void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif_link *mvif) { struct bss_info_ext_bss *ext; int ext_bss_idx, tsf_offset; struct tlv *tlv; ext_bss_idx = mvif->omac_idx - EXT_BSSID_START; if (ext_bss_idx < 0) return; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext)); ext = (struct bss_info_ext_bss *)tlv; tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME; ext->mbss_tsf_offset = cpu_to_le32(tsf_offset); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_ext_tlv); int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct mt76_phy *phy, u16 wlan_idx, bool enable) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; u32 type = vif->p2p ? NETWORK_P2P : NETWORK_INFRA; struct bss_info_basic *bss; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss)); bss = (struct bss_info_basic *)tlv; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_AP: if (ieee80211_hw_check(phy->hw, SUPPORTS_MULTI_BSSID)) { u8 bssid_id = vif->bss_conf.bssid_indicator; struct wiphy *wiphy = phy->hw->wiphy; if (bssid_id > ilog2(wiphy->mbssid_max_interfaces)) return -EINVAL; bss->non_tx_bssid = vif->bss_conf.bssid_index; bss->max_bssid = bssid_id; } break; case NL80211_IFTYPE_STATION: if (enable) { rcu_read_lock(); if (!sta) sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ if (sta) { struct mt76_wcid *wcid; wcid = (struct mt76_wcid *)sta->drv_priv; wlan_idx = wcid->idx; } rcu_read_unlock(); } break; case NL80211_IFTYPE_ADHOC: type = NETWORK_IBSS; break; default: WARN_ON(1); break; } bss->network_type = cpu_to_le32(type); bss->bmc_wcid_lo = to_wcid_lo(wlan_idx); bss->bmc_wcid_hi = to_wcid_hi(wlan_idx); bss->wmm_idx = mvif->wmm_idx; bss->active = enable; bss->cipher = mvif->cipher; if (vif->type != NL80211_IFTYPE_MONITOR) { struct cfg80211_chan_def *chandef = &phy->chandef; 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; bss->phy_mode = mt76_connac_get_phy_mode(phy, vif, chandef->chan->band, NULL); } else { memcpy(bss->bssid, phy->macaddr, ETH_ALEN); } return 0; } EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_basic_tlv); #define ENTER_PM_STATE 1 #define EXIT_PM_STATE 2 int mt76_connac_mcu_set_pm(struct mt76_dev *dev, int band, int enter) { struct { u8 pm_number; u8 pm_state; u8 bssid[ETH_ALEN]; u8 dtim_period; u8 wlan_idx_lo; __le16 bcn_interval; __le32 aid; __le32 rx_filter; u8 band_idx; u8 wlan_idx_hi; u8 rsv[2]; __le32 feature; u8 omac_idx; u8 wmm_idx; u8 bcn_loss_cnt; u8 bcn_sp_duration; } __packed req = { .pm_number = 5, .pm_state = enter ? ENTER_PM_STATE : EXIT_PM_STATE, .band_idx = band, }; return mt76_mcu_send_msg(dev, MCU_EXT_CMD(PM_STATE_CTRL), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_pm); int mt76_connac_mcu_restart(struct mt76_dev *dev) { struct { u8 power_mode; u8 rsv[3]; } req = { .power_mode = 1, }; return mt76_mcu_send_msg(dev, MCU_CMD(NIC_POWER_CTRL), &req, sizeof(req), false); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_restart); +int mt76_connac_mcu_del_wtbl_all(struct mt76_dev *dev) +{ + struct wtbl_req_hdr req = { + .operation = WTBL_RESET_ALL, + }; + + return mt76_mcu_send_msg(dev, MCU_EXT_CMD(WTBL_UPDATE), + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_del_wtbl_all); + int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val) { struct { u8 ctrl; u8 rdd_idx; u8 rdd_rx_sel; u8 val; u8 rsv[4]; } __packed req = { .ctrl = cmd, .rdd_idx = index, .rdd_rx_sel = rx_sel, .val = val, }; return mt76_mcu_send_msg(dev, MCU_EXT_CMD(SET_RDD_CTRL), &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_rdd_cmd); static int mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev, const struct mt76_connac2_fw_trailer *hdr, const u8 *data, bool is_wa) { int i, offset = 0, max_len = mt76_is_sdio(dev) ? 2048 : 4096; u32 override = 0, option = 0; for (i = 0; i < hdr->n_region; i++) { const struct mt76_connac2_fw_region *region; u32 len, addr, mode; int err; region = (const void *)((const u8 *)hdr - (hdr->n_region - i) * sizeof(*region)); mode = mt76_connac_mcu_gen_dl_mode(dev, region->feature_set, is_wa); len = le32_to_cpu(region->len); addr = le32_to_cpu(region->addr); if (region->feature_set & FW_FEATURE_NON_DL) goto next; if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) override = addr; err = mt76_connac_mcu_init_download(dev, addr, len, mode); if (err) { dev_err(dev->dev, "Download request failed\n"); return err; } err = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), data + offset, len, max_len); if (err) { dev_err(dev->dev, "Failed to send firmware.\n"); return err; } next: offset += len; } if (override) option |= FW_START_OVERRIDE; if (is_wa) option |= FW_START_WORKING_PDA_CR4; return mt76_connac_mcu_start_firmware(dev, override, option); } int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa) { const struct mt76_connac2_fw_trailer *hdr; const struct firmware *fw; int ret; ret = request_firmware(&fw, fw_wm, dev->dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false); if (ret) { dev_err(dev->dev, "Failed to start WM firmware\n"); goto out; } snprintf(dev->hw->wiphy->fw_version, sizeof(dev->hw->wiphy->fw_version), "%.10s-%.15s", hdr->fw_ver, hdr->build_date); release_firmware(fw); if (!fw_wa) return 0; ret = request_firmware(&fw, fw_wa, dev->dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true); if (ret) { dev_err(dev->dev, "Failed to start WA firmware\n"); goto out; } snprintf(dev->hw->wiphy->fw_version, sizeof(dev->hw->wiphy->fw_version), "%.10s-%.15s", hdr->fw_ver, hdr->build_date); out: release_firmware(fw); return ret; } EXPORT_SYMBOL_GPL(mt76_connac2_load_ram); static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) { u32 mode = DL_MODE_NEED_RSP; - if (!is_mt7921(dev) || info == PATCH_SEC_NOT_SUPPORT) + if ((!is_mt7921(dev) && !is_mt7925(dev)) || 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->dev, "Encryption type not support!\n"); } return mode; } int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) { int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; const struct mt76_connac2_patch_hdr *hdr; const struct firmware *fw = NULL; sem = mt76_connac_mcu_patch_sem_ctrl(dev, true); switch (sem) { case PATCH_IS_DL: return 0; case PATCH_NOT_DL_SEM_SUCCESS: break; default: dev_err(dev->dev, "Failed to get patch semaphore\n"); return -EAGAIN; } ret = request_firmware(&fw, fw_name, dev->dev); if (ret) goto out; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)fw->data; dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { #if defined(__linux__) struct mt76_connac2_patch_sec *sec; #elif defined(__FreeBSD__) const struct mt76_connac2_patch_sec *sec; #endif u32 len, addr, mode; const u8 *dl; u32 sec_info; #if defined(__linux__) sec = (void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); #elif defined(__FreeBSD__) sec = (const void *)(fw->data + sizeof(*hdr) + i * sizeof(*sec)); #endif if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != PATCH_SEC_TYPE_INFO) { ret = -EINVAL; goto out; } 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 = mt76_connac2_get_data_mode(dev, sec_info); ret = mt76_connac_mcu_init_download(dev, addr, len, mode); if (ret) { dev_err(dev->dev, "Download request failed\n"); goto out; } ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), dl, len, max_len); if (ret) { dev_err(dev->dev, "Failed to send patch\n"); goto out; } } ret = mt76_connac_mcu_start_patch(dev); if (ret) dev_err(dev->dev, "Failed to start patch\n"); out: sem = mt76_connac_mcu_patch_sem_ctrl(dev, false); switch (sem) { case PATCH_REL_SEM_SUCCESS: break; default: ret = -EAGAIN; dev_err(dev->dev, "Failed to release patch semaphore\n"); break; } release_firmware(fw); return ret; } EXPORT_SYMBOL_GPL(mt76_connac2_load_patch); int mt76_connac2_mcu_fill_message(struct mt76_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq) { int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); struct mt76_connac2_mcu_uni_txd *uni_txd; struct mt76_connac2_mcu_txd *mcu_txd; __le32 *txd; u32 val; u8 seq; /* TODO: make dynamic based on msg type */ dev->mcu.timeout = 20 * HZ; seq = ++dev->mcu.msg_seq & 0xf; if (!seq) seq = ++dev->mcu.msg_seq & 0xf; if (cmd == MCU_CMD(FW_SCATTER)) goto exit; txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); txd = (__le32 *)skb_push(skb, txd_len); val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); txd[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); txd[1] = cpu_to_le32(val); if (cmd & __MCU_CMD_FIELD_UNI) { uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); uni_txd->option = MCU_CMD_UNI_EXT_ACK; uni_txd->cid = cpu_to_le16(mcu_cmd); uni_txd->s2d_index = MCU_S2D_H2N; uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; goto exit; } mcu_txd = (struct mt76_connac2_mcu_txd *)txd; mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, MT_TX_MCU_PORT_RX_Q0)); mcu_txd->pkt_type = MCU_PKT_ID; mcu_txd->seq = seq; mcu_txd->cid = mcu_cmd; mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { if (cmd & __MCU_CMD_FIELD_QUERY) mcu_txd->set_query = MCU_Q_QUERY; else mcu_txd->set_query = MCU_Q_SET; mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; } else { mcu_txd->set_query = MCU_Q_NA; } if (cmd & __MCU_CMD_FIELD_WA) mcu_txd->s2d_index = MCU_S2D_H2C; else mcu_txd->s2d_index = MCU_S2D_H2N; exit: if (wait_seq) *wait_seq = seq; return 0; } EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.h b/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.h index deb78c3d6670..18db7bb31730 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.h +++ b/sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.h @@ -1,1929 +1,2058 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT76_CONNAC_MCU_H #define __MT76_CONNAC_MCU_H #include "mt76_connac.h" #define FW_FEATURE_SET_ENCRYPT BIT(0) #define FW_FEATURE_SET_KEY_IDX GENMASK(2, 1) #define FW_FEATURE_ENCRY_MODE BIT(4) #define FW_FEATURE_OVERRIDE_ADDR BIT(5) #define FW_FEATURE_NON_DL BIT(6) #define DL_MODE_ENCRYPT BIT(0) #define DL_MODE_KEY_IDX GENMASK(2, 1) #define DL_MODE_RESET_SEC_IV BIT(3) #define DL_MODE_WORKING_PDA_CR4 BIT(4) #define DL_MODE_VALID_RAM_ENTRY BIT(5) #define DL_CONFIG_ENCRY_MODE_SEL BIT(6) #define DL_MODE_NEED_RSP BIT(31) #define FW_START_OVERRIDE BIT(0) #define FW_START_WORKING_PDA_CR4 BIT(2) #define FW_START_WORKING_PDA_DSP BIT(3) #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) enum { FW_TYPE_DEFAULT = 0, FW_TYPE_CLC = 2, FW_TYPE_MAX_NUM = 255 }; #define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) #define MCU_PKT_ID 0xa0 struct mt76_connac2_mcu_txd { __le32 txd[8]; __le16 len; __le16 pq_id; u8 cid; u8 pkt_type; u8 set_query; /* FW don't care */ u8 seq; u8 uc_d2b0_rev; u8 ext_cid; u8 s2d_index; u8 ext_cid_ack; u32 rsv[5]; } __packed __aligned(4); /** * struct mt76_connac2_mcu_uni_txd - mcu command descriptor for connac2 and connac3 * @txd: hardware descriptor * @len: total length not including txd * @cid: command identifier * @pkt_type: must be 0xa0 (cmd packet by long format) * @frag_n: fragment number * @seq: sequence number * @checksum: 0 mean there is no checksum * @s2d_index: index for command source and destination * Definition | value | note * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM * * @option: command option * BIT[0]: UNI_CMD_OPT_BIT_ACK * set to 1 to request a fw reply * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY * is set, mcu firmware will send response event EID = 0x01 * (UNI_EVENT_ID_CMD_RESULT) to the host. * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD * 0: original command * 1: unified command * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY * 0: QUERY command * 1: SET command */ struct mt76_connac2_mcu_uni_txd { __le32 txd[8]; /* DW1 */ __le16 len; __le16 cid; /* DW2 */ u8 rsv; u8 pkt_type; u8 frag_n; u8 seq; /* DW3 */ __le16 checksum; u8 s2d_index; u8 option; /* DW4 */ u8 rsv1[4]; } __packed __aligned(4); struct mt76_connac2_mcu_rxd { - __le32 rxd[6]; + /* New members MUST be added within the struct_group() macro below. */ + struct_group_tagged(mt76_connac2_mcu_rxd_hdr, hdr, + __le32 rxd[6]; - __le16 len; - __le16 pkt_type_id; + __le16 len; + __le16 pkt_type_id; - u8 eid; - u8 seq; - u8 option; - u8 rsv; - u8 ext_eid; - u8 rsv1[2]; - u8 s2d_index; + u8 eid; + u8 seq; + u8 option; + u8 rsv; + u8 ext_eid; + u8 rsv1[2]; + u8 s2d_index; + ); #if defined(__linux__) u8 tlv[]; #elif defined(__FreeBSD__) u8 tlv[0]; #endif }; +static_assert(offsetof(struct mt76_connac2_mcu_rxd, tlv) == sizeof(struct mt76_connac2_mcu_rxd_hdr), + "struct member likely outside of struct_group_tagged()"); struct mt76_connac2_patch_hdr { char build_date[16]; char platform[4]; __be32 hw_sw_ver; __be32 patch_ver; __be16 checksum; u16 rsv; struct { __be32 patch_ver; __be32 subsys; __be32 feature; __be32 n_region; __be32 crc; u32 rsv[11]; } desc; } __packed; struct mt76_connac2_patch_sec { __be32 type; __be32 offs; __be32 size; union { __be32 spec[13]; struct { __be32 addr; __be32 len; __be32 sec_key_idx; __be32 align_len; u32 rsv[9]; } info; }; } __packed; struct mt76_connac2_fw_trailer { u8 chip_id; u8 eco_code; u8 n_region; u8 format_ver; u8 format_flag; u8 rsv[2]; char fw_ver[10]; char build_date[15]; __le32 crc; } __packed; struct mt76_connac2_fw_region { __le32 decomp_crc; __le32 decomp_len; __le32 decomp_blk_sz; u8 rsv[4]; __le32 addr; __le32 len; u8 feature_set; u8 type; u8 rsv1[14]; } __packed; struct tlv { __le16 tag; __le16 len; + u8 data[]; } __packed; struct bss_info_omac { __le16 tag; __le16 len; u8 hw_bss_idx; u8 omac_idx; u8 band_idx; u8 rsv0; __le32 conn_type; u32 rsv1; } __packed; struct bss_info_basic { __le16 tag; __le16 len; __le32 network_type; u8 active; u8 rsv0; __le16 bcn_interval; u8 bssid[ETH_ALEN]; u8 wmm_idx; u8 dtim_period; u8 bmc_wcid_lo; u8 cipher; u8 phy_mode; u8 max_bssid; /* max BSSID. range: 1 ~ 8, 0: MBSSID disabled */ u8 non_tx_bssid;/* non-transmitted BSSID, 0: transmitted BSSID */ u8 bmc_wcid_hi; /* high Byte and version */ u8 rsv[2]; } __packed; struct bss_info_rf_ch { __le16 tag; __le16 len; u8 pri_ch; u8 center_ch0; u8 center_ch1; u8 bw; u8 he_ru26_block; /* 1: don't send HETB in RU26, 0: allow */ u8 he_all_disable; /* 1: disallow all HETB, 0: allow */ u8 rsv[2]; } __packed; struct bss_info_ext_bss { __le16 tag; __le16 len; __le32 mbss_tsf_offset; /* in unit of us */ u8 rsv[8]; } __packed; enum { BSS_INFO_OMAC, BSS_INFO_BASIC, BSS_INFO_RF_CH, /* optional, for BT/LTE coex */ BSS_INFO_PM, /* sta only */ BSS_INFO_UAPSD, /* sta only */ BSS_INFO_ROAM_DETECT, /* obsoleted */ BSS_INFO_LQ_RM, /* obsoleted */ BSS_INFO_EXT_BSS, BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */ BSS_INFO_SYNC_MODE, /* obsoleted */ BSS_INFO_RA, BSS_INFO_HW_AMSDU, BSS_INFO_BSS_COLOR, BSS_INFO_HE_BASIC, BSS_INFO_PROTECT_INFO, BSS_INFO_OFFLOAD, BSS_INFO_11V_MBSSID, BSS_INFO_MAX_NUM }; /* sta_rec */ struct sta_ntlv_hdr { u8 rsv[2]; __le16 tlv_num; } __packed; struct sta_req_hdr { u8 bss_idx; u8 wlan_idx_lo; __le16 tlv_num; u8 is_tlv_append; u8 muar_idx; u8 wlan_idx_hi; u8 rsv; } __packed; struct sta_rec_basic { __le16 tag; __le16 len; __le32 conn_type; u8 conn_state; u8 qos; __le16 aid; u8 peer_addr[ETH_ALEN]; #define EXTRA_INFO_VER BIT(0) #define EXTRA_INFO_NEW BIT(1) __le16 extra_info; } __packed; struct sta_rec_ht { __le16 tag; __le16 len; __le16 ht_cap; u16 rsv; } __packed; struct sta_rec_vht { __le16 tag; __le16 len; __le32 vht_cap; __le16 vht_rx_mcs_map; __le16 vht_tx_mcs_map; /* mt7915 - mt7921 */ u8 rts_bw_sig; u8 rsv[3]; } __packed; struct sta_rec_uapsd { __le16 tag; __le16 len; u8 dac_map; u8 tac_map; u8 max_sp; u8 rsv0; __le16 listen_interval; u8 rsv1[2]; } __packed; struct sta_rec_ba { __le16 tag; __le16 len; u8 tid; u8 ba_type; u8 amsdu; u8 ba_en; __le16 ssn; __le16 winsize; } __packed; struct sta_rec_he { __le16 tag; __le16 len; __le32 he_cap; u8 t_frame_dur; u8 max_ampdu_exp; u8 bw_set; u8 device_class; u8 dcm_tx_mode; u8 dcm_tx_max_nss; u8 dcm_rx_mode; u8 dcm_rx_max_nss; u8 dcm_max_ru; u8 punc_pream_rx; u8 pkt_ext; u8 rsv1; __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; u8 rsv2[2]; } __packed; struct sta_rec_he_v2 { __le16 tag; __le16 len; u8 he_mac_cap[6]; u8 he_phy_cap[11]; u8 pkt_ext; /* 0: BW80, 1: BW160, 2: BW8080 */ __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; } __packed; struct sta_rec_amsdu { __le16 tag; __le16 len; u8 max_amsdu_num; u8 max_mpdu_size; u8 amsdu_en; u8 rsv; } __packed; struct sta_rec_state { __le16 tag; __le16 len; __le32 flags; u8 state; u8 vht_opmode; u8 action; 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; __le16 len; __le16 legacy; u8 rx_mcs_bitmask[HT_MCS_MASK_NUM]; } __packed; struct sta_rec_phy { __le16 tag; __le16 len; __le16 basic_rate; u8 phy_type; u8 ampdu; u8 rts_policy; u8 rcpi; u8 max_ampdu_len; /* connac3 */ u8 rsv[1]; } __packed; struct sta_rec_he_6g_capa { __le16 tag; __le16 len; __le16 capa; u8 rsv[2]; } __packed; +struct sta_rec_pn_info { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 tsc_type; + u8 rsv; +} __packed; + struct sec_key { u8 cipher_id; u8 cipher_len; u8 key_id; u8 key_len; u8 key[32]; } __packed; struct sta_rec_sec { __le16 tag; __le16 len; u8 add; u8 n_cipher; u8 rsv[2]; struct sec_key key[2]; } __packed; struct sta_rec_bf { __le16 tag; __le16 len; __le16 pfmu; /* 0xffff: no access right for PFMU */ bool su_mu; /* 0: SU, 1: MU */ u8 bf_cap; /* 0: iBF, 1: eBF */ u8 sounding_phy; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ u8 ndpa_rate; u8 ndp_rate; u8 rept_poll_rate; u8 tx_mode; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT ... */ u8 ncol; u8 nrow; u8 bw; /* 0: 20M, 1: 40M, 2: 80M, 3: 160M */ u8 mem_total; u8 mem_20m; struct { u8 row; u8 col: 6, row_msb: 2; } mem[4]; __le16 smart_ant; u8 se_idx; u8 auto_sounding; /* b7: low traffic indicator * b6: Stop sounding for this entry * b5 ~ b0: postpone sounding */ u8 ibf_timeout; u8 ibf_dbw; u8 ibf_ncol; u8 ibf_nrow; u8 nrow_gt_bw80; u8 ncol_gt_bw80; u8 ru_start_idx; u8 ru_end_idx; bool trigger_su; bool trigger_mu; bool ng16_su; bool ng16_mu; bool codebook42_su; bool codebook75_mu; u8 he_ltf; u8 rsv[3]; } __packed; struct sta_rec_bfee { __le16 tag; __le16 len; bool fb_identity_matrix; /* 1: feedback identity matrix */ bool ignore_feedback; /* 1: ignore */ u8 rsv[2]; } __packed; struct sta_rec_muru { __le16 tag; __le16 len; struct { bool ofdma_dl_en; bool ofdma_ul_en; bool mimo_dl_en; bool mimo_ul_en; u8 rsv[4]; } cfg; struct { u8 punc_pream_rx; bool he_20m_in_40m_2g; bool he_20m_in_160m; bool he_80m_in_160m; bool lt16_sigb; bool rx_su_comp_sigb; bool rx_su_non_comp_sigb; u8 rsv; } ofdma_dl; struct { u8 t_frame_dur; u8 mu_cascading; u8 uo_ra; u8 he_2x996_tone; u8 rx_t_frame_11ac; u8 rx_ctrl_frame_to_mbss; u8 rsv[2]; } ofdma_ul; struct { bool vht_mu_bfee; bool partial_bw_dl_mimo; u8 rsv[2]; } mimo_dl; struct { bool full_ul_mimo; bool partial_ul_mimo; u8 rsv[2]; } mimo_ul; } __packed; +struct sta_rec_remove { + __le16 tag; + __le16 len; + u8 action; + u8 pad[3]; +} __packed; + struct sta_phy { u8 type; u8 flag; u8 stbc; u8 sgi; u8 bw; u8 ldpc; u8 mcs; u8 nss; u8 he_ltf; }; struct sta_rec_ra { __le16 tag; __le16 len; u8 valid; u8 auto_rate; u8 phy_mode; u8 channel; u8 bw; u8 disable_cck; u8 ht_mcs32; u8 ht_gf; u8 ht_mcs[4]; u8 mmps_mode; u8 gband_256; u8 af; u8 auth_wapi_mode; u8 rate_len; u8 supp_mode; u8 supp_cck_rate; u8 supp_ofdm_rate; __le32 supp_ht_mcs; __le16 supp_vht_mcs[4]; u8 op_mode; u8 op_vht_chan_width; u8 op_vht_rx_nss; u8 op_vht_rx_nss_type; __le32 sta_cap; struct sta_phy phy; } __packed; struct sta_rec_ra_fixed { __le16 tag; __le16 len; __le32 field; u8 op_mode; u8 op_vht_chan_width; u8 op_vht_rx_nss; u8 op_vht_rx_nss_type; struct sta_phy phy; u8 spe_idx; u8 short_preamble; u8 is_5g; u8 mmps_mode; } __packed; +struct sta_rec_tx_proc { + __le16 tag; + __le16 len; + __le32 flag; +} __packed; + /* wtbl_rec */ struct wtbl_req_hdr { u8 wlan_idx_lo; u8 operation; __le16 tlv_num; u8 wlan_idx_hi; u8 rsv[3]; } __packed; struct wtbl_generic { __le16 tag; __le16 len; u8 peer_addr[ETH_ALEN]; u8 muar_idx; u8 skip_tx; u8 cf_ack; u8 qos; u8 mesh; u8 adm; __le16 partial_aid; u8 baf_en; u8 aad_om; } __packed; struct wtbl_rx { __le16 tag; __le16 len; u8 rcid; u8 rca1; u8 rca2; u8 rv; u8 rsv[4]; } __packed; struct wtbl_ht { __le16 tag; __le16 len; u8 ht; u8 ldpc; u8 af; u8 mm; u8 rsv[4]; } __packed; struct wtbl_vht { __le16 tag; __le16 len; u8 ldpc; u8 dyn_bw; u8 vht; u8 txop_ps; u8 rsv[4]; } __packed; struct wtbl_tx_ps { __le16 tag; __le16 len; u8 txps; u8 rsv[3]; } __packed; struct wtbl_hdr_trans { __le16 tag; __le16 len; u8 to_ds; u8 from_ds; u8 no_rx_trans; u8 rsv; } __packed; struct wtbl_ba { __le16 tag; __le16 len; /* common */ u8 tid; u8 ba_type; u8 rsv0[2]; /* originator only */ __le16 sn; u8 ba_en; u8 ba_winsize_idx; /* originator & recipient */ __le16 ba_winsize; /* recipient only */ u8 peer_addr[ETH_ALEN]; u8 rst_ba_tid; u8 rst_ba_sel; u8 rst_ba_sb; u8 band_idx; u8 rsv1[4]; } __packed; struct wtbl_smps { __le16 tag; __le16 len; u8 smps; u8 rsv[3]; } __packed; /* mt7615 only */ struct wtbl_bf { __le16 tag; __le16 len; u8 ibf; u8 ebf; u8 ibf_vht; u8 ebf_vht; u8 gid; u8 pfmu_idx; u8 rsv[2]; } __packed; struct wtbl_pn { __le16 tag; __le16 len; u8 pn[6]; u8 rsv[2]; } __packed; struct wtbl_spe { __le16 tag; __le16 len; u8 spe_idx; u8 rsv[3]; } __packed; struct wtbl_raw { __le16 tag; __le16 len; u8 wtbl_idx; u8 dw; u8 rsv[2]; __le32 msk; __le32 val; } __packed; #define MT76_CONNAC_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \ sizeof(struct wtbl_generic) + \ sizeof(struct wtbl_rx) + \ sizeof(struct wtbl_ht) + \ sizeof(struct wtbl_vht) + \ sizeof(struct wtbl_tx_ps) + \ sizeof(struct wtbl_hdr_trans) +\ sizeof(struct wtbl_ba) + \ sizeof(struct wtbl_bf) + \ sizeof(struct wtbl_smps) + \ sizeof(struct wtbl_pn) + \ sizeof(struct wtbl_spe)) #define MT76_CONNAC_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 sta_rec_ra) + \ sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra_fixed) + \ sizeof(struct sta_rec_he_6g_capa) + \ + sizeof(struct sta_rec_pn_info) + \ + sizeof(struct sta_rec_tx_proc) + \ sizeof(struct tlv) + \ MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) enum { STA_REC_BASIC, STA_REC_RA, STA_REC_RA_CMM_INFO, STA_REC_RA_UPDATE, STA_REC_BF, STA_REC_AMSDU, STA_REC_BA, STA_REC_STATE, STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */ STA_REC_HT, STA_REC_VHT, STA_REC_APPS, STA_REC_KEY, STA_REC_WTBL, STA_REC_HE, STA_REC_HW_AMSDU, STA_REC_WTBL_AADOM, STA_REC_KEY_V2, STA_REC_MURU, STA_REC_MUEDCA, STA_REC_BFEE, STA_REC_PHY = 0x15, STA_REC_HE_6G = 0x17, STA_REC_HE_V2 = 0x19, + STA_REC_MLD = 0x20, + STA_REC_EHT_MLD = 0x21, STA_REC_EHT = 0x22, + STA_REC_MLD_OFF = 0x23, + STA_REC_REMOVE = 0x25, + STA_REC_PN_INFO = 0x26, + STA_REC_KEY_V3 = 0x27, STA_REC_HDRT = 0x28, STA_REC_HDR_TRANS = 0x2B, STA_REC_MAX_NUM }; enum { WTBL_GENERIC, WTBL_RX, WTBL_HT, WTBL_VHT, WTBL_PEER_PS, /* not used */ WTBL_TX_PS, WTBL_HDR_TRANS, WTBL_SEC_KEY, WTBL_BA, WTBL_RDG, /* obsoleted */ WTBL_PROTECT, /* not used */ WTBL_CLEAR, /* not used */ WTBL_BF, WTBL_SMPS, WTBL_RAW_DATA, /* debug only */ WTBL_PN, WTBL_SPE, WTBL_MAX_NUM }; #define STA_TYPE_STA BIT(0) #define STA_TYPE_AP BIT(1) #define STA_TYPE_ADHOC BIT(2) #define STA_TYPE_WDS BIT(4) #define STA_TYPE_BC BIT(5) #define NETWORK_INFRA BIT(16) #define NETWORK_P2P BIT(17) #define NETWORK_IBSS BIT(18) #define NETWORK_WDS BIT(21) #define SCAN_FUNC_RANDOM_MAC BIT(0) #define SCAN_FUNC_SPLIT_SCAN BIT(5) #define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) #define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) #define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) #define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) #define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) #define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) #define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) #define CONN_STATE_DISCONNECT 0 #define CONN_STATE_CONNECT 1 #define CONN_STATE_PORT_SECURE 2 /* HE MAC */ #define STA_REC_HE_CAP_HTC BIT(0) #define STA_REC_HE_CAP_BQR BIT(1) #define STA_REC_HE_CAP_BSR BIT(2) #define STA_REC_HE_CAP_OM BIT(3) #define STA_REC_HE_CAP_AMSDU_IN_AMPDU BIT(4) /* HE PHY */ #define STA_REC_HE_CAP_DUAL_BAND BIT(5) #define STA_REC_HE_CAP_LDPC BIT(6) #define STA_REC_HE_CAP_TRIG_CQI_FK BIT(7) #define STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE BIT(8) /* STBC */ #define STA_REC_HE_CAP_LE_EQ_80M_TX_STBC BIT(9) #define STA_REC_HE_CAP_LE_EQ_80M_RX_STBC BIT(10) #define STA_REC_HE_CAP_GT_80M_TX_STBC BIT(11) #define STA_REC_HE_CAP_GT_80M_RX_STBC BIT(12) /* GI */ #define STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI BIT(13) #define STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI BIT(14) #define STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI BIT(15) #define STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI BIT(16) #define STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI BIT(17) /* 242 TONE */ #define STA_REC_HE_CAP_BW20_RU242_SUPPORT BIT(18) #define STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242 BIT(19) #define STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242 BIT(20) #define PHY_MODE_A BIT(0) #define PHY_MODE_B BIT(1) #define PHY_MODE_G BIT(2) #define PHY_MODE_GN BIT(3) #define PHY_MODE_AN BIT(4) #define PHY_MODE_AC BIT(5) #define PHY_MODE_AX_24G BIT(6) #define PHY_MODE_AX_5G BIT(7) #define PHY_MODE_AX_6G BIT(0) /* phymode_ext */ #define PHY_MODE_BE_24G BIT(1) #define PHY_MODE_BE_5G BIT(2) #define PHY_MODE_BE_6G BIT(3) #define MODE_CCK BIT(0) #define MODE_OFDM BIT(1) #define MODE_HT BIT(2) #define MODE_VHT BIT(3) #define MODE_HE BIT(4) #define MODE_EHT BIT(5) #define STA_CAP_WMM BIT(0) #define STA_CAP_SGI_20 BIT(4) #define STA_CAP_SGI_40 BIT(5) #define STA_CAP_TX_STBC BIT(6) #define STA_CAP_RX_STBC BIT(7) #define STA_CAP_VHT_SGI_80 BIT(16) #define STA_CAP_VHT_SGI_160 BIT(17) #define STA_CAP_VHT_TX_STBC BIT(18) #define STA_CAP_VHT_RX_STBC BIT(19) #define STA_CAP_VHT_LDPC BIT(23) #define STA_CAP_LDPC BIT(24) #define STA_CAP_HT BIT(26) #define STA_CAP_VHT BIT(27) #define STA_CAP_HE BIT(28) enum { PHY_TYPE_HR_DSSS_INDEX = 0, PHY_TYPE_ERP_INDEX, PHY_TYPE_ERP_P2P_INDEX, PHY_TYPE_OFDM_INDEX, PHY_TYPE_HT_INDEX, PHY_TYPE_VHT_INDEX, PHY_TYPE_HE_INDEX, + PHY_TYPE_BE_INDEX, PHY_TYPE_INDEX_NUM }; +#define HR_DSSS_ERP_BASIC_RATE GENMASK(3, 0) +#define OFDM_BASIC_RATE (BIT(6) | BIT(8) | BIT(10)) + #define PHY_TYPE_BIT_HR_DSSS BIT(PHY_TYPE_HR_DSSS_INDEX) #define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) #define PHY_TYPE_BIT_OFDM BIT(PHY_TYPE_OFDM_INDEX) #define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) #define PHY_TYPE_BIT_VHT BIT(PHY_TYPE_VHT_INDEX) #define PHY_TYPE_BIT_HE BIT(PHY_TYPE_HE_INDEX) +#define PHY_TYPE_BIT_BE BIT(PHY_TYPE_BE_INDEX) #define MT_WTBL_RATE_TX_MODE GENMASK(9, 6) #define MT_WTBL_RATE_MCS GENMASK(5, 0) #define MT_WTBL_RATE_NSS GENMASK(12, 10) #define MT_WTBL_RATE_HE_GI GENMASK(7, 4) #define MT_WTBL_RATE_GI GENMASK(3, 0) #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) #define MT_WTBL_W5_SHORT_GI_20 BIT(8) #define MT_WTBL_W5_SHORT_GI_40 BIT(9) #define MT_WTBL_W5_SHORT_GI_80 BIT(10) #define MT_WTBL_W5_SHORT_GI_160 BIT(11) #define MT_WTBL_W5_BW_CAP GENMASK(13, 12) #define MT_WTBL_W5_MPDU_FAIL_COUNT GENMASK(25, 23) #define MT_WTBL_W5_MPDU_OK_COUNT GENMASK(28, 26) #define MT_WTBL_W5_RATE_IDX GENMASK(31, 29) enum { WTBL_RESET_AND_SET = 1, WTBL_SET, WTBL_QUERY, WTBL_RESET_ALL }; enum { MT_BA_TYPE_INVALID, MT_BA_TYPE_ORIGINATOR, MT_BA_TYPE_RECIPIENT }; enum { RST_BA_MAC_TID_MATCH, RST_BA_MAC_MATCH, RST_BA_NO_MATCH }; enum { DEV_INFO_ACTIVE, DEV_INFO_MAX_NUM }; /* event table */ enum { MCU_EVENT_TARGET_ADDRESS_LEN = 0x01, MCU_EVENT_FW_START = 0x01, MCU_EVENT_GENERIC = 0x01, MCU_EVENT_ACCESS_REG = 0x02, MCU_EVENT_MT_PATCH_SEM = 0x04, MCU_EVENT_REG_ACCESS = 0x05, MCU_EVENT_LP_INFO = 0x07, MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_TX_DONE = 0x0f, MCU_EVENT_ROC = 0x10, MCU_EVENT_BSS_ABSENCE = 0x11, MCU_EVENT_BSS_BEACON_LOSS = 0x13, MCU_EVENT_CH_PRIVILEGE = 0x18, MCU_EVENT_SCHED_SCAN_DONE = 0x23, MCU_EVENT_DBG_MSG = 0x27, + MCU_EVENT_RSSI_NOTIFY = 0x96, MCU_EVENT_TXPWR = 0xd0, MCU_EVENT_EXT = 0xed, MCU_EVENT_RESTART_DL = 0xef, MCU_EVENT_COREDUMP = 0xf0, }; /* ext event table */ enum { MCU_EXT_EVENT_PS_SYNC = 0x5, MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, MCU_EXT_EVENT_ASSERT_DUMP = 0x23, MCU_EXT_EVENT_RDD_REPORT = 0x3a, MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, MCU_EXT_EVENT_WA_TX_STAT = 0x74, MCU_EXT_EVENT_BCC_NOTIFY = 0x75, + MCU_EXT_EVENT_WF_RF_PIN_CTRL = 0x9a, MCU_EXT_EVENT_MURU_CTRL = 0x9f, }; /* unified event table */ enum { MCU_UNI_EVENT_RESULT = 0x01, + MCU_UNI_EVENT_HIF_CTRL = 0x03, MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04, + MCU_UNI_EVENT_ACCESS_REG = 0x6, MCU_UNI_EVENT_IE_COUNTDOWN = 0x09, + MCU_UNI_EVENT_COREDUMP = 0x0a, + MCU_UNI_EVENT_BSS_BEACON_LOSS = 0x0c, + MCU_UNI_EVENT_SCAN_DONE = 0x0e, MCU_UNI_EVENT_RDD_REPORT = 0x11, + MCU_UNI_EVENT_ROC = 0x27, + MCU_UNI_EVENT_TX_DONE = 0x2d, + MCU_UNI_EVENT_THERMAL = 0x35, + MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_WED_RRO = 0x57, + MCU_UNI_EVENT_PER_STA_INFO = 0x6d, + MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, }; #define MCU_UNI_CMD_EVENT BIT(1) #define MCU_UNI_CMD_UNSOLICITED_EVENT BIT(2) enum { MCU_Q_QUERY, MCU_Q_SET, MCU_Q_RESERVED, MCU_Q_NA }; enum { MCU_S2D_H2N, MCU_S2D_C2N, MCU_S2D_H2C, MCU_S2D_H2CN }; enum { PATCH_NOT_DL_SEM_FAIL, PATCH_IS_DL, PATCH_NOT_DL_SEM_SUCCESS, PATCH_REL_SEM_SUCCESS }; enum { FW_STATE_INITIAL, FW_STATE_FW_DOWNLOAD, FW_STATE_NORMAL_OPERATION, FW_STATE_NORMAL_TRX, FW_STATE_RDY = 7 }; enum { CH_SWITCH_NORMAL = 0, CH_SWITCH_SCAN = 3, CH_SWITCH_MCC = 4, CH_SWITCH_DFS = 5, CH_SWITCH_BACKGROUND_SCAN_START = 6, CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7, CH_SWITCH_BACKGROUND_SCAN_STOP = 8, CH_SWITCH_SCAN_BYPASS_DPD = 9 }; enum { THERMAL_SENSOR_TEMP_QUERY, THERMAL_SENSOR_MANUAL_CTRL, THERMAL_SENSOR_INFO_QUERY, THERMAL_SENSOR_TASK_CTRL, }; enum mcu_cipher_type { MCU_CIPHER_NONE = 0, MCU_CIPHER_WEP40, MCU_CIPHER_WEP104, MCU_CIPHER_WEP128, MCU_CIPHER_TKIP, MCU_CIPHER_AES_CCMP, MCU_CIPHER_CCMP_256, MCU_CIPHER_GCMP, MCU_CIPHER_GCMP_256, MCU_CIPHER_WAPI, MCU_CIPHER_BIP_CMAC_128, + MCU_CIPHER_BIP_CMAC_256, + MCU_CIPHER_BCN_PROT_CMAC_128, + MCU_CIPHER_BCN_PROT_CMAC_256, + MCU_CIPHER_BCN_PROT_GMAC_128, + MCU_CIPHER_BCN_PROT_GMAC_256, + MCU_CIPHER_BIP_GMAC_128, + MCU_CIPHER_BIP_GMAC_256, }; enum { EE_MODE_EFUSE, EE_MODE_BUFFER, }; enum { EE_FORMAT_BIN, EE_FORMAT_WHOLE, EE_FORMAT_MULTIPLE, }; enum { MCU_PHY_STATE_TX_RATE, MCU_PHY_STATE_RX_RATE, MCU_PHY_STATE_RSSI, MCU_PHY_STATE_CONTENTION_RX_RATE, MCU_PHY_STATE_OFDMLQ_CNINFO, }; #define MCU_CMD_ACK BIT(0) #define MCU_CMD_UNI BIT(1) #define MCU_CMD_SET BIT(2) #define MCU_CMD_UNI_EXT_ACK (MCU_CMD_ACK | MCU_CMD_UNI | \ MCU_CMD_SET) #define MCU_CMD_UNI_QUERY_ACK (MCU_CMD_ACK | MCU_CMD_UNI) #define __MCU_CMD_FIELD_ID GENMASK(7, 0) #define __MCU_CMD_FIELD_EXT_ID GENMASK(15, 8) #define __MCU_CMD_FIELD_QUERY BIT(16) #define __MCU_CMD_FIELD_UNI BIT(17) #define __MCU_CMD_FIELD_CE BIT(18) #define __MCU_CMD_FIELD_WA BIT(19) #define __MCU_CMD_FIELD_WM BIT(20) #define MCU_CMD(_t) FIELD_PREP(__MCU_CMD_FIELD_ID, \ MCU_CMD_##_t) #define MCU_EXT_CMD(_t) (MCU_CMD(EXT_CID) | \ FIELD_PREP(__MCU_CMD_FIELD_EXT_ID, \ MCU_EXT_CMD_##_t)) #define MCU_EXT_QUERY(_t) (MCU_EXT_CMD(_t) | __MCU_CMD_FIELD_QUERY) #define MCU_UNI_CMD(_t) (__MCU_CMD_FIELD_UNI | \ FIELD_PREP(__MCU_CMD_FIELD_ID, \ MCU_UNI_CMD_##_t)) #define MCU_CE_CMD(_t) (__MCU_CMD_FIELD_CE | \ FIELD_PREP(__MCU_CMD_FIELD_ID, \ MCU_CE_CMD_##_t)) #define MCU_CE_QUERY(_t) (MCU_CE_CMD(_t) | __MCU_CMD_FIELD_QUERY) #define MCU_WA_CMD(_t) (MCU_CMD(_t) | __MCU_CMD_FIELD_WA) #define MCU_WA_EXT_CMD(_t) (MCU_EXT_CMD(_t) | __MCU_CMD_FIELD_WA) #define MCU_WA_PARAM_CMD(_t) (MCU_WA_CMD(WA_PARAM) | \ FIELD_PREP(__MCU_CMD_FIELD_EXT_ID, \ MCU_WA_PARAM_CMD_##_t)) #define MCU_WM_UNI_CMD(_t) (MCU_UNI_CMD(_t) | \ __MCU_CMD_FIELD_WM) #define MCU_WM_UNI_CMD_QUERY(_t) (MCU_UNI_CMD(_t) | \ __MCU_CMD_FIELD_QUERY | \ __MCU_CMD_FIELD_WM) #define MCU_WA_UNI_CMD(_t) (MCU_UNI_CMD(_t) | \ __MCU_CMD_FIELD_WA) #define MCU_WMWA_UNI_CMD(_t) (MCU_WM_UNI_CMD(_t) | \ __MCU_CMD_FIELD_WA) enum { MCU_EXT_CMD_EFUSE_ACCESS = 0x01, MCU_EXT_CMD_RF_REG_ACCESS = 0x02, MCU_EXT_CMD_RF_TEST = 0x04, + MCU_EXT_CMD_ID_RADIO_ON_OFF_CTRL = 0x05, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, MCU_EXT_CMD_FW_LOG_2_HOST = 0x13, MCU_EXT_CMD_TXBF_ACTION = 0x1e, MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21, MCU_EXT_CMD_THERMAL_PROT = 0x23, MCU_EXT_CMD_STA_REC_UPDATE = 0x25, MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, MCU_EXT_CMD_EDCA_UPDATE = 0x27, MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, MCU_EXT_CMD_THERMAL_CTRL = 0x2c, MCU_EXT_CMD_WTBL_UPDATE = 0x32, MCU_EXT_CMD_SET_DRR_CTRL = 0x36, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, MCU_EXT_CMD_ATE_CTRL = 0x3d, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_DBDC_CTRL = 0x45, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, MCU_EXT_CMD_RX_HDR_TRANS = 0x47, MCU_EXT_CMD_MUAR_UPDATE = 0x48, MCU_EXT_CMD_BCN_OFFLOAD = 0x49, MCU_EXT_CMD_RX_AIRTIME_CTRL = 0x4a, MCU_EXT_CMD_SET_RX_PATH = 0x4e, MCU_EXT_CMD_EFUSE_FREE_BLOCK = 0x4f, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58, MCU_EXT_CMD_RXDCOC_CAL = 0x59, MCU_EXT_CMD_GET_MIB_INFO = 0x5a, MCU_EXT_CMD_TXDPD_CAL = 0x60, MCU_EXT_CMD_CAL_CACHE = 0x67, MCU_EXT_CMD_RED_ENABLE = 0x68, + MCU_EXT_CMD_CP_SUPPORT = 0x75, MCU_EXT_CMD_SET_RADAR_TH = 0x7c, MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, MCU_EXT_CMD_MWDS_SUPPORT = 0x80, MCU_EXT_CMD_SET_SER_TRIGGER = 0x81, MCU_EXT_CMD_TWT_AGRT_UPDATE = 0x94, MCU_EXT_CMD_FW_DBG_CTRL = 0x95, MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a, 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, + MCU_EXT_CMD_WF_RF_PIN_CTRL = 0xbd, }; enum { MCU_UNI_CMD_DEV_INFO_UPDATE = 0x01, MCU_UNI_CMD_BSS_INFO_UPDATE = 0x02, MCU_UNI_CMD_STA_REC_UPDATE = 0x03, MCU_UNI_CMD_EDCA_UPDATE = 0x04, MCU_UNI_CMD_SUSPEND = 0x05, MCU_UNI_CMD_OFFLOAD = 0x06, MCU_UNI_CMD_HIF_CTRL = 0x07, MCU_UNI_CMD_BAND_CONFIG = 0x08, MCU_UNI_CMD_REPT_MUAR = 0x09, MCU_UNI_CMD_WSYS_CONFIG = 0x0b, MCU_UNI_CMD_REG_ACCESS = 0x0d, MCU_UNI_CMD_CHIP_CONFIG = 0x0e, MCU_UNI_CMD_POWER_CTRL = 0x0f, MCU_UNI_CMD_RX_HDR_TRANS = 0x12, MCU_UNI_CMD_SER = 0x13, MCU_UNI_CMD_TWT = 0x14, + MCU_UNI_CMD_SET_DOMAIN_INFO = 0x15, + MCU_UNI_CMD_SCAN_REQ = 0x16, MCU_UNI_CMD_RDD_CTRL = 0x19, MCU_UNI_CMD_GET_MIB_INFO = 0x22, + MCU_UNI_CMD_GET_STAT_INFO = 0x23, MCU_UNI_CMD_SNIFFER = 0x24, MCU_UNI_CMD_SR = 0x25, MCU_UNI_CMD_ROC = 0x27, + MCU_UNI_CMD_SET_DBDC_PARMS = 0x28, MCU_UNI_CMD_TXPOWER = 0x2b, + MCU_UNI_CMD_SET_POWER_LIMIT = 0x2c, MCU_UNI_CMD_EFUSE_CTRL = 0x2d, MCU_UNI_CMD_RA = 0x2f, MCU_UNI_CMD_MURU = 0x31, MCU_UNI_CMD_BF = 0x33, MCU_UNI_CMD_CHANNEL_SWITCH = 0x34, MCU_UNI_CMD_THERMAL = 0x35, MCU_UNI_CMD_VOW = 0x37, + MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, + MCU_UNI_CMD_PER_STA_INFO = 0x6d, + MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, }; enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01, MCU_CMD_FW_START_REQ = 0x02, MCU_CMD_INIT_ACCESS_REG = 0x3, MCU_CMD_NIC_POWER_CTRL = 0x4, MCU_CMD_PATCH_START_REQ = 0x05, MCU_CMD_PATCH_FINISH_REQ = 0x07, MCU_CMD_PATCH_SEM_CONTROL = 0x10, MCU_CMD_WA_PARAM = 0xc4, MCU_CMD_EXT_CID = 0xed, MCU_CMD_FW_SCATTER = 0xee, MCU_CMD_RESTART_DL_REQ = 0xef, }; /* offload mcu commands */ enum { MCU_CE_CMD_TEST_CTRL = 0x01, MCU_CE_CMD_START_HW_SCAN = 0x03, MCU_CE_CMD_SET_PS_PROFILE = 0x05, MCU_CE_CMD_SET_RX_FILTER = 0x0a, MCU_CE_CMD_SET_CHAN_DOMAIN = 0x0f, MCU_CE_CMD_SET_BSS_CONNECTED = 0x16, MCU_CE_CMD_SET_BSS_ABORT = 0x17, MCU_CE_CMD_CANCEL_HW_SCAN = 0x1b, MCU_CE_CMD_SET_ROC = 0x1c, MCU_CE_CMD_SET_EDCA_PARMS = 0x1d, MCU_CE_CMD_SET_P2P_OPPPS = 0x33, MCU_CE_CMD_SET_CLC = 0x5c, MCU_CE_CMD_SET_RATE_TX_POWER = 0x5d, MCU_CE_CMD_SCHED_SCAN_ENABLE = 0x61, MCU_CE_CMD_SCHED_SCAN_REQ = 0x62, MCU_CE_CMD_GET_NIC_CAPAB = 0x8a, + MCU_CE_CMD_RSSI_MONITOR = 0xa1, MCU_CE_CMD_SET_MU_EDCA_PARMS = 0xb0, MCU_CE_CMD_REG_WRITE = 0xc0, MCU_CE_CMD_REG_READ = 0xc0, MCU_CE_CMD_CHIP_CONFIG = 0xca, MCU_CE_CMD_FWLOG_2_HOST = 0xc5, MCU_CE_CMD_GET_WTBL = 0xcd, MCU_CE_CMD_GET_TXPWR = 0xd0, }; enum { PATCH_SEM_RELEASE, PATCH_SEM_GET }; enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RA = 1, UNI_BSS_INFO_RLM = 2, UNI_BSS_INFO_BSS_COLOR = 4, UNI_BSS_INFO_HE_BASIC = 5, + UNI_BSS_INFO_11V_MBSSID = 6, UNI_BSS_INFO_BCN_CONTENT = 7, UNI_BSS_INFO_BCN_CSA = 8, UNI_BSS_INFO_BCN_BCC = 9, UNI_BSS_INFO_BCN_MBSSID = 10, UNI_BSS_INFO_RATE = 11, UNI_BSS_INFO_QBSS = 15, UNI_BSS_INFO_SEC = 16, + UNI_BSS_INFO_BCN_PROT = 17, UNI_BSS_INFO_TXCMD = 18, UNI_BSS_INFO_UAPSD = 19, UNI_BSS_INFO_PS = 21, UNI_BSS_INFO_BCNFT = 22, UNI_BSS_INFO_IFS_TIME = 23, UNI_BSS_INFO_OFFLOAD = 25, UNI_BSS_INFO_MLD = 26, + UNI_BSS_INFO_PM_DISABLE = 27, }; enum { UNI_OFFLOAD_OFFLOAD_ARP, UNI_OFFLOAD_OFFLOAD_ND, UNI_OFFLOAD_OFFLOAD_GTK_REKEY, UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, }; +enum UNI_ALL_STA_INFO_TAG { + UNI_ALL_STA_TXRX_RATE, + UNI_ALL_STA_TX_STAT, + UNI_ALL_STA_TXRX_ADM_STAT, + UNI_ALL_STA_TXRX_AIR_TIME, + UNI_ALL_STA_DATA_TX_RETRY_COUNT, + UNI_ALL_STA_GI_MODE, + UNI_ALL_STA_TXRX_MSDU_COUNT, + UNI_ALL_STA_MAX_NUM +}; + enum { MT_NIC_CAP_TX_RESOURCE, MT_NIC_CAP_TX_EFUSE_ADDR, MT_NIC_CAP_COEX, MT_NIC_CAP_SINGLE_SKU, MT_NIC_CAP_CSUM_OFFLOAD, MT_NIC_CAP_HW_VER, MT_NIC_CAP_SW_VER, MT_NIC_CAP_MAC_ADDR, MT_NIC_CAP_PHY, MT_NIC_CAP_MAC, MT_NIC_CAP_FRAME_BUF, MT_NIC_CAP_BEAM_FORM, MT_NIC_CAP_LOCATION, MT_NIC_CAP_MUMIMO, MT_NIC_CAP_BUFFER_MODE_INFO, MT_NIC_CAP_HW_ADIE_VERSION = 0x14, MT_NIC_CAP_ANTSWP = 0x16, MT_NIC_CAP_WFDMA_REALLOC, MT_NIC_CAP_6G, + MT_NIC_CAP_CHIP_CAP = 0x20, + MT_NIC_CAP_EML_CAP = 0x22, }; #define UNI_WOW_DETECT_TYPE_MAGIC BIT(0) #define UNI_WOW_DETECT_TYPE_ANY BIT(1) #define UNI_WOW_DETECT_TYPE_DISCONNECT BIT(2) #define UNI_WOW_DETECT_TYPE_GTK_REKEY_FAIL BIT(3) #define UNI_WOW_DETECT_TYPE_BCN_LOST BIT(4) #define UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT BIT(5) #define UNI_WOW_DETECT_TYPE_BITMAP BIT(6) enum { UNI_SUSPEND_MODE_SETTING, UNI_SUSPEND_WOW_CTRL, UNI_SUSPEND_WOW_GPIO_PARAM, UNI_SUSPEND_WOW_WAKEUP_PORT, UNI_SUSPEND_WOW_PATTERN, }; enum { WOW_USB = 1, WOW_PCIE = 2, WOW_GPIO = 3, }; struct mt76_connac_bss_basic_tlv { __le16 tag; __le16 len; u8 active; u8 omac_idx; u8 hw_bss_idx; u8 band_idx; __le32 conn_type; u8 conn_state; u8 wmm_idx; u8 bssid[ETH_ALEN]; __le16 bmc_tx_wlan_idx; __le16 bcn_interval; u8 dtim_period; u8 phymode; /* bit(0): A * bit(1): B * bit(2): G * bit(3): GN * bit(4): AN * bit(5): AC * bit(6): AX2 * bit(7): AX5 * bit(8): AX6 */ __le16 sta_idx; __le16 nonht_basic_phy; u8 phymode_ext; /* bit(0) AX_6G */ - u8 pad[1]; + u8 link_idx; } __packed; struct mt76_connac_bss_qos_tlv { __le16 tag; __le16 len; u8 qos; u8 pad[3]; } __packed; struct mt76_connac_beacon_loss_event { u8 bss_idx; u8 reason; u8 pad[2]; } __packed; +struct mt76_connac_rssi_notify_event { + __le32 rssi[4]; +} __packed; + struct mt76_connac_mcu_bss_event { u8 bss_idx; u8 is_absent; u8 free_quota; u8 pad; } __packed; struct mt76_connac_mcu_scan_ssid { __le32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; } __packed; struct mt76_connac_mcu_scan_channel { u8 band; /* 1: 2.4GHz * 2: 5.0GHz * Others: Reserved */ u8 channel_num; } __packed; struct mt76_connac_mcu_scan_match { __le32 rssi_th; u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ssid_len; u8 rsv[3]; } __packed; struct mt76_connac_hw_scan_req { u8 seq_num; u8 bss_idx; u8 scan_type; /* 0: PASSIVE SCAN * 1: ACTIVE SCAN */ u8 ssid_type; /* BIT(0) wildcard SSID * BIT(1) P2P wildcard SSID * BIT(2) specified SSID + wildcard SSID * BIT(2) + ssid_type_ext BIT(0) specified SSID only */ u8 ssids_num; u8 probe_req_num; /* Number of probe request for each SSID */ u8 scan_func; /* BIT(0) Enable random MAC scan * BIT(1) Disable DBDC scan type 1~3. * BIT(2) Use DBDC scan type 3 (dedicated one RF to scan). */ u8 version; /* 0: Not support fields after ies. * 1: Support fields after ies. */ struct mt76_connac_mcu_scan_ssid ssids[4]; __le16 probe_delay_time; __le16 channel_dwell_time; /* channel Dwell interval */ __le16 timeout_value; u8 channel_type; /* 0: Full channels * 1: Only 2.4GHz channels * 2: Only 5GHz channels * 3: P2P social channel only (channel #1, #6 and #11) * 4: Specified channels * Others: Reserved */ u8 channels_num; /* valid when channel_type is 4 */ /* valid when channels_num is set */ struct mt76_connac_mcu_scan_channel channels[32]; __le16 ies_len; u8 ies[MT76_CONNAC_SCAN_IE_LEN]; /* following fields are valid if version > 0 */ u8 ext_channels_num; u8 ext_ssids_num; __le16 channel_min_dwell_time; struct mt76_connac_mcu_scan_channel ext_channels[32]; struct mt76_connac_mcu_scan_ssid ext_ssids[6]; u8 bssid[ETH_ALEN]; u8 random_mac[ETH_ALEN]; /* valid when BIT(1) in scan_func is set. */ u8 pad[63]; u8 ssid_type_ext; } __packed; #define MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM 64 struct mt76_connac_hw_scan_done { u8 seq_num; u8 sparse_channel_num; struct mt76_connac_mcu_scan_channel sparse_channel; u8 complete_channel_num; u8 current_state; u8 version; u8 pad; __le32 beacon_scan_num; u8 pno_enabled; u8 pad2[3]; u8 sparse_channel_valid_num; u8 pad3[3]; u8 channel_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; /* idle format for channel_idle_time * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) * 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) * 2: dwell time (16us) */ __le16 channel_idle_time[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; /* beacon and probe response count */ u8 beacon_probe_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; u8 mdrdy_count[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; __le32 beacon_2g_num; __le32 beacon_5g_num; } __packed; struct mt76_connac_sched_scan_req { u8 version; u8 seq_num; u8 stop_on_match; u8 ssids_num; u8 match_num; u8 pad; __le16 ie_len; struct mt76_connac_mcu_scan_ssid ssids[MT76_CONNAC_MAX_SCHED_SCAN_SSID]; struct mt76_connac_mcu_scan_match match[MT76_CONNAC_MAX_SCAN_MATCH]; u8 channel_type; u8 channels_num; u8 intervals_num; u8 scan_func; /* MT7663: BIT(0) eable random mac address */ struct mt76_connac_mcu_scan_channel channels[64]; __le16 intervals[MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL]; union { struct { u8 random_mac[ETH_ALEN]; u8 pad2[58]; } mt7663; struct { u8 bss_idx; u8 pad1[3]; __le32 delay; u8 pad2[12]; u8 random_mac[ETH_ALEN]; u8 pad3[38]; } mt7921; }; } __packed; struct mt76_connac_sched_scan_done { u8 seq_num; u8 status; /* 0: ssid found */ __le16 pad; } __packed; struct bss_info_uni_bss_color { __le16 tag; __le16 len; u8 enable; u8 bss_color; u8 rsv[2]; } __packed; struct bss_info_uni_he { __le16 tag; __le16 len; __le16 he_rts_thres; u8 he_pe_duration; u8 su_disable; __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; u8 rsv[2]; } __packed; +struct bss_info_uni_mbssid { + __le16 tag; + __le16 len; + u8 max_indicator; + u8 mbss_idx; + u8 tx_bss_omac_idx; + u8 rsv; +} __packed; + struct mt76_connac_gtk_rekey_tlv { __le16 tag; __le16 len; u8 kek[NL80211_KEK_LEN]; u8 kck[NL80211_KCK_LEN]; u8 replay_ctr[NL80211_REPLAY_CTR_LEN]; u8 rekey_mode; /* 0: rekey offload enable * 1: rekey offload disable * 2: rekey update */ u8 keyid; 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 reserverd[4]; } __packed; #define MT76_CONNAC_WOW_MASK_MAX_LEN 16 #define MT76_CONNAC_WOW_PATTEN_MAX_LEN 128 struct mt76_connac_wow_pattern_tlv { __le16 tag; __le16 len; u8 index; /* pattern index */ u8 enable; /* 0: disable * 1: enable */ u8 data_len; /* pattern length */ u8 pad; u8 mask[MT76_CONNAC_WOW_MASK_MAX_LEN]; u8 pattern[MT76_CONNAC_WOW_PATTEN_MAX_LEN]; u8 rsv[4]; } __packed; struct mt76_connac_wow_ctrl_tlv { __le16 tag; __le16 len; u8 cmd; /* 0x1: PM_WOWLAN_REQ_START * 0x2: PM_WOWLAN_REQ_STOP * 0x3: PM_WOWLAN_PARAM_CLEAR */ u8 trigger; /* 0: NONE * BIT(0): NL80211_WOWLAN_TRIG_MAGIC_PKT * BIT(1): NL80211_WOWLAN_TRIG_ANY * BIT(2): NL80211_WOWLAN_TRIG_DISCONNECT * BIT(3): NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE * BIT(4): BEACON_LOST * BIT(5): NL80211_WOWLAN_TRIG_NET_DETECT */ u8 wakeup_hif; /* 0x0: HIF_SDIO * 0x1: HIF_USB * 0x2: HIF_PCIE * 0x3: HIF_GPIO */ u8 pad; u8 rsv[4]; } __packed; struct mt76_connac_wow_gpio_param_tlv { __le16 tag; __le16 len; u8 gpio_pin; u8 trigger_lvl; u8 pad[2]; __le32 gpio_interval; u8 rsv[4]; } __packed; struct mt76_connac_arpns_tlv { __le16 tag; __le16 len; u8 mode; u8 ips_num; u8 option; u8 pad[1]; } __packed; struct mt76_connac_suspend_tlv { __le16 tag; __le16 len; u8 enable; /* 0: suspend mode disabled * 1: suspend mode enabled */ u8 mdtim; /* LP parameter */ u8 wow_suspend; /* 0: update by origin policy * 1: update by wow dtim */ u8 pad[5]; } __packed; enum mt76_sta_info_state { MT76_STA_INFO_STATE_NONE, MT76_STA_INFO_STATE_AUTH, MT76_STA_INFO_STATE_ASSOC }; struct mt76_sta_cmd_info { - struct ieee80211_sta *sta; + union { + struct ieee80211_sta *sta; + struct ieee80211_link_sta *link_sta; + }; struct mt76_wcid *wcid; struct ieee80211_vif *vif; + struct ieee80211_bss_conf *link_conf; bool offload_fw; bool enable; bool newly; int cmd; u8 rcpi; u8 state; }; #define MT_SKU_POWER_LIMIT 161 struct mt76_connac_sku_tlv { u8 channel; s8 pwr_limit[MT_SKU_POWER_LIMIT]; } __packed; struct mt76_connac_tx_power_limit_tlv { /* DW0 - common info*/ u8 ver; u8 pad0; __le16 len; /* DW1 - cmd hint */ u8 n_chan; /* # channel */ u8 band; /* 2.4GHz - 5GHz - 6GHz */ u8 last_msg; u8 pad1; /* DW3 */ u8 alpha2[4]; /* regulatory_request.alpha2 */ u8 pad2[32]; } __packed; struct mt76_connac_config { __le16 id; u8 type; u8 resp_type; __le16 data_size; __le16 resv; u8 data[320]; } __packed; struct mt76_connac_mcu_uni_event { u8 cid; u8 pad[3]; __le32 status; /* 0: success, others: fail */ } __packed; struct mt76_connac_mcu_reg_event { __le32 reg; __le32 val; } __packed; static inline enum mcu_cipher_type mt76_connac_mcu_get_cipher(int cipher) { switch (cipher) { case WLAN_CIPHER_SUITE_WEP40: return MCU_CIPHER_WEP40; case WLAN_CIPHER_SUITE_WEP104: return MCU_CIPHER_WEP104; case WLAN_CIPHER_SUITE_TKIP: return MCU_CIPHER_TKIP; case WLAN_CIPHER_SUITE_AES_CMAC: return MCU_CIPHER_BIP_CMAC_128; case WLAN_CIPHER_SUITE_CCMP: return MCU_CIPHER_AES_CCMP; case WLAN_CIPHER_SUITE_CCMP_256: return MCU_CIPHER_CCMP_256; case WLAN_CIPHER_SUITE_GCMP: return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: return MCU_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + return MCU_CIPHER_BIP_GMAC_128; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + return MCU_CIPHER_BIP_GMAC_256; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + return MCU_CIPHER_BIP_CMAC_256; case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: return MCU_CIPHER_NONE; } } static inline u32 mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa) { u32 ret = 0; ret |= feature_set & FW_FEATURE_SET_ENCRYPT ? DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0; - if (is_mt7921(dev)) + if (is_mt7921(dev) || is_mt7925(dev)) ret |= feature_set & FW_FEATURE_ENCRY_MODE ? DL_CONFIG_ENCRY_MODE_SEL : 0; ret |= FIELD_PREP(DL_MODE_KEY_IDX, FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set)); ret |= DL_MODE_NEED_RSP; ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0; return ret; } #define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id) #define to_wcid_hi(id) FIELD_GET(GENMASK(10, 8), (u16)id) static inline void mt76_connac_mcu_get_wlan_idx(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 *wlan_idx_lo, u8 *wlan_idx_hi) { *wlan_idx_hi = 0; if (!is_connac_v1(dev)) { *wlan_idx_lo = wcid ? to_wcid_lo(wcid->idx) : 0; *wlan_idx_hi = wcid ? to_wcid_hi(wcid->idx) : 0; } else { *wlan_idx_lo = wcid ? wcid->idx : 0; } } struct sk_buff * -__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, +__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, struct mt76_wcid *wcid, int len); static inline struct sk_buff * -mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif, +mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, struct mt76_wcid *wcid) { return __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, MT76_CONNAC_STA_UPDATE_MAX_SIZE); } struct wtbl_req_hdr * mt76_connac_mcu_alloc_wtbl_req(struct mt76_dev *dev, struct mt76_wcid *wcid, int cmd, void *sta_wtbl, struct sk_buff **skb); struct tlv *mt76_connac_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len, void *sta_ntlv, void *sta_wtbl); static inline struct tlv * mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len) { return mt76_connac_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL); } int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy); int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif); void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable, - bool newly); + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + int state, bool newly); void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); 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); int mt76_connac_mcu_sta_update_hdr_trans(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_wcid *wcid, int cmd); +void mt76_connac_mcu_sta_he_tlv_v2(struct sk_buff *skb, struct ieee80211_sta *sta); +u8 mt76_connac_get_phy_mode_v2(struct mt76_phy *mphy, struct ieee80211_vif *vif, + enum nl80211_band band, + struct ieee80211_link_sta *link_sta); int mt76_connac_mcu_wtbl_update_hdr_trans(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); 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 state); void mt76_connac_mcu_wtbl_ht_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv, bool ht_ldpc, bool vht_ldpc); void mt76_connac_mcu_wtbl_ba_tlv(struct mt76_dev *dev, struct sk_buff *skb, struct ieee80211_ampdu_params *params, bool enable, bool tx, void *sta_wtbl, void *wtbl_tlv); void mt76_connac_mcu_sta_ba_tlv(struct sk_buff *skb, struct ieee80211_ampdu_params *params, bool enable, bool tx); int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, - struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + struct mt76_vif_link *mvif, struct mt76_wcid *wcid, bool enable); -int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, struct ieee80211_ampdu_params *params, int cmd, bool enable, bool tx); int mt76_connac_mcu_uni_set_chctx(struct mt76_phy *phy, - struct mt76_vif *vif, + struct mt76_vif_link *vif, struct ieee80211_chanctx_conf *ctx); int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_wcid *wcid, bool enable, struct ieee80211_chanctx_conf *ctx); int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy, struct mt76_sta_cmd_info *info); void mt76_connac_mcu_beacon_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt76_connac_mcu_set_rts_thresh(struct mt76_dev *dev, u32 val, u8 band); int mt76_connac_mcu_set_mac_enable(struct mt76_dev *dev, int band, bool enable, bool hdr_trans); int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, u32 mode); int mt76_connac_mcu_start_patch(struct mt76_dev *dev); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); -int mt76_connac_mcu_get_nic_capability(struct mt76_phy *phy); int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif); int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *sreq); int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, struct ieee80211_vif *vif, bool enable); int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev, - struct mt76_vif *vif, + struct mt76_vif_link *vif, struct ieee80211_bss_conf *info); +int mt76_connac_mcu_set_gtk_rekey(struct mt76_dev *dev, struct ieee80211_vif *vif, + bool suspend); +int mt76_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, + bool suspend, struct cfg80211_wowlan *wowlan); int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *key); -int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend); +int mt76_connac_mcu_set_suspend_mode(struct mt76_dev *dev, + struct ieee80211_vif *vif, + bool enable, u8 mdtim, + bool wow_suspend); +int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend, bool wait_resp); void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt76_connac_sta_state_dp(struct mt76_dev *dev, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state); int mt76_connac_mcu_chip_config(struct mt76_dev *dev); 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); +s8 mt76_connac_get_ch_power(struct mt76_phy *phy, + struct ieee80211_channel *chan, + s8 target_power); 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); const struct ieee80211_sta_he_cap * mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif); const struct ieee80211_sta_eht_cap * mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif); u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif, - enum nl80211_band band, struct ieee80211_sta *sta); -u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, + enum nl80211_band band, + struct ieee80211_link_sta *sta); +u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf, enum nl80211_band band); int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd); -void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif *mvif); +void mt76_connac_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt76_vif_link *mvif); void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif); int mt76_connac_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct mt76_phy *phy, u16 wlan_idx, bool enable); void mt76_connac_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt76_connac_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, void *sta_wtbl, void *wtbl_tlv); int mt76_connac_mcu_set_pm(struct mt76_dev *dev, int band, int enter); int mt76_connac_mcu_restart(struct mt76_dev *dev); +int mt76_connac_mcu_del_wtbl_all(struct mt76_dev *dev); int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt76_connac_mcu_sta_wed_update(struct mt76_dev *dev, struct sk_buff *skb); int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa); int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name); int mt76_connac2_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt76x0/pci.c b/sys/contrib/dev/mediatek/mt76/mt76x0/pci.c index 9277ff38b7a2..b456ccd00d58 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x0/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x0/pci.c @@ -1,318 +1,326 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #include #include #include "mt76x0.h" #include "mcu.h" static int mt76x0e_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; mt76x02_mac_start(dev); mt76x0_phy_calibrate(dev, true); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); return 0; } static void mt76x0e_stop_hw(struct mt76x02_dev *dev) { cancel_delayed_work_sync(&dev->cal_work); cancel_delayed_work_sync(&dev->mphy.mac_work); clear_bit(MT76_RESTART, &dev->mphy.state); if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY, 0, 1000)) dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN); mt76x0_mac_stop(dev); if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000)) dev_warn(dev->mt76.dev, "TX DMA did not stop\n"); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_RX_DMA_EN); } -static void mt76x0e_stop(struct ieee80211_hw *hw) +static void mt76x0e_stop(struct ieee80211_hw *hw, bool suspend) { struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); mt76x0e_stop_hw(dev); } static void mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { } static const struct ieee80211_ops mt76x0e_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x0e_start, .stop = mt76x0e_stop, .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .config = mt76x0_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .ampdu_action = mt76x02_ampdu_action, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .wake_tx_queue = mt76_wake_tx_queue, .get_survey = mt76_get_survey, .get_txpower = mt76_get_txpower, .flush = mt76x0e_flush, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x02_set_coverage_class, .set_rts_threshold = mt76x02_set_rts_threshold, .get_antenna = mt76_get_antenna, .reconfig_complete = mt76x02_reconfig_complete, .set_sar_specs = mt76x0_set_sar_specs, }; static int mt76x0e_init_hardware(struct mt76x02_dev *dev, bool resume) { int err; mt76x0_chip_onoff(dev, true, false); if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; mt76x02_dma_disable(dev); err = mt76x0e_mcu_init(dev); if (err < 0) return err; if (!resume) { err = mt76x02_dma_init(dev); if (err < 0) return err; } err = mt76x0_init_hardware(dev); if (err < 0) return err; mt76x02e_init_beacon_config(dev); if (mt76_chip(&dev->mt76) == 0x7610) { u16 val; mt76_clear(dev, MT_COEXCFG0, BIT(0)); val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); if (!(val & MT_EE_NIC_CONF_0_PA_IO_CURRENT)) mt76_set(dev, MT_XO_CTRL7, 0xc03); } mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); return 0; } static int mt76x0e_register_device(struct mt76x02_dev *dev) { int err; err = mt76x0e_init_hardware(dev, false); if (err < 0) return err; err = mt76x0_register_device(dev); if (err < 0) return err; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); return 0; } static int mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, + .set_channel = mt76x0_set_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, }; struct mt76x02_dev *dev; struct mt76_dev *mdev; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_set_master(pdev); ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; mt76_pci_disable_aspm(pdev); mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x0e_ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt76x02_dev, mt76); mutex_init(&dev->phy_mutex); mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); mt76_wr(dev, MT_INT_MASK_CSR, 0); ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; ret = mt76x0e_register_device(dev); if (ret < 0) goto error; return 0; error: mt76_free_device(&dev->mt76); return ret; } static void mt76x0e_cleanup(struct mt76x02_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); mt76x0_chip_onoff(dev, false, false); mt76x0e_stop_hw(dev); mt76_dma_cleanup(&dev->mt76); mt76x02_mcu_cleanup(dev); } static void mt76x0e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_unregister_device(mdev); mt76x0e_cleanup(dev); mt76_free_device(mdev); } #ifdef CONFIG_PM static int mt76x0e_suspend(struct pci_dev *pdev, pm_message_t state) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); int i; mt76_worker_disable(&mdev->tx_worker); for (i = 0; i < ARRAY_SIZE(mdev->phy.q_tx); i++) mt76_queue_tx_cleanup(dev, mdev->phy.q_tx[i], true); for (i = 0; i < ARRAY_SIZE(mdev->q_mcu); i++) mt76_queue_tx_cleanup(dev, mdev->q_mcu[i], true); napi_disable(&mdev->tx_napi); mt76_for_each_q_rx(mdev, i) napi_disable(&mdev->napi[i]); mt76x02_dma_disable(dev); mt76x02_mcu_cleanup(dev); mt76x0_chip_onoff(dev, false, false); pci_enable_wake(pdev, pci_choose_state(pdev, state), true); pci_save_state(pdev); return pci_set_power_state(pdev, pci_choose_state(pdev, state)); } static int mt76x0e_resume(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); int err, i; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; pci_restore_state(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]); - napi_schedule(&mdev->napi[i]); } - napi_enable(&mdev->tx_napi); + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + napi_schedule(&mdev->napi[i]); + } napi_schedule(&mdev->tx_napi); local_bh_enable(); return mt76x0e_init_hardware(dev, true); } #endif /* CONFIG_PM */ static const struct pci_device_id mt76x0e_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7610) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7630) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7650) }, { }, }; MODULE_DEVICE_TABLE(pci, mt76x0e_device_table); MODULE_FIRMWARE(MT7610E_FIRMWARE); MODULE_FIRMWARE(MT7650E_FIRMWARE); +MODULE_DESCRIPTION("MediaTek MT76x0E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76x0e_driver = { .name = KBUILD_MODNAME, .id_table = mt76x0e_device_table, .probe = mt76x0e_probe, .remove = mt76x0e_remove, #ifdef CONFIG_PM .suspend = mt76x0e_suspend, .resume = mt76x0e_resume, #endif /* CONFIG_PM */ }; module_pci_driver(mt76x0e_driver); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_beacon.c b/sys/contrib/dev/mediatek/mt76/mt76x02_beacon.c index ad4dc8e17b58..d570b99bccb9 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_beacon.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_beacon.c @@ -1,217 +1,215 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau * Copyright (C) 2018 Lorenzo Bianconi * Copyright (C) 2018 Stanislaw Gruszka */ #include "mt76x02.h" static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev) { u32 regs[4] = {}; u16 val; int i; for (i = 0; i < dev->beacon_ops->nslots; i++) { val = i * dev->beacon_ops->slot_size; regs[i / 4] |= (val / 64) << (8 * (i % 4)); } for (i = 0; i < 4; i++) mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]); } static int mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) { int beacon_len = dev->beacon_ops->slot_size; if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) return -ENOSPC; /* USB devices already reserve enough skb headroom for txwi's. This * helps to save slow copies over USB. */ if (mt76_is_usb(&dev->mt76)) { struct mt76x02_txwi *txwi; txwi = (struct mt76x02_txwi *)(skb->data - sizeof(*txwi)); mt76x02_mac_write_txwi(dev, txwi, skb, NULL, NULL, skb->len); skb_push(skb, sizeof(*txwi)); } else { struct mt76x02_txwi txwi; mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); offset += sizeof(txwi); } mt76_wr_copy(dev, offset, skb->data, skb->len); return 0; } void mt76x02_mac_set_beacon(struct mt76x02_dev *dev, struct sk_buff *skb) { int bcn_len = dev->beacon_ops->slot_size; int bcn_addr = MT_BEACON_BASE + (bcn_len * dev->beacon_data_count); if (!mt76x02_write_beacon(dev, bcn_addr, skb)) { if (!dev->beacon_data_count) dev->beacon_hang_check++; dev->beacon_data_count++; } dev_kfree_skb(skb); } EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon); void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; u8 old_mask = dev->mt76.beacon_mask; mt76x02_pre_tbtt_enable(dev, false); if (!dev->mt76.beacon_mask) dev->tbtt_count = 0; dev->beacon_hang_check = 0; if (enable) { dev->mt76.beacon_mask |= BIT(mvif->idx); } else { dev->mt76.beacon_mask &= ~BIT(mvif->idx); } if (!!old_mask == !!dev->mt76.beacon_mask) goto out; if (dev->mt76.beacon_mask) mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_BEACON_TX | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_TIMER_EN); else mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_BEACON_TX | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_TIMER_EN); mt76x02_beacon_enable(dev, !!dev->mt76.beacon_mask); out: mt76x02_pre_tbtt_enable(dev, true); } void mt76x02_resync_beacon_timer(struct mt76x02_dev *dev) { u32 timer_val = dev->mt76.beacon_int << 4; dev->tbtt_count++; /* * Beacon timer drifts by 1us every tick, the timer is configured * in 1/16 TU (64us) units. */ if (dev->tbtt_count < 63) return; /* * The updated beacon interval takes effect after two TBTT, because * at this point the original interval has already been loaded into * the next TBTT_TIMER value */ if (dev->tbtt_count == 63) timer_val -= 1; mt76_rmw_field(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_INTVAL, timer_val); if (dev->tbtt_count >= 64) dev->tbtt_count = 0; } EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer); void mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct mt76x02_dev *dev = (struct mt76x02_dev *)priv; + struct beacon_bc_data *data = priv; + struct mt76x02_dev *dev = data->dev; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct sk_buff *skb = NULL; if (!(dev->mt76.beacon_mask & BIT(mvif->idx))) return; skb = ieee80211_beacon_get(mt76_hw(dev), vif, 0); if (!skb) return; - mt76x02_mac_set_beacon(dev, skb); + __skb_queue_tail(&data->q, skb); } EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter); static void mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct beacon_bc_data *data = priv; struct mt76x02_dev *dev = data->dev; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct ieee80211_tx_info *info; struct sk_buff *skb; if (!(dev->mt76.beacon_mask & BIT(mvif->idx))) return; skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif); if (!skb) return; info = IEEE80211_SKB_CB(skb); info->control.vif = vif; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; mt76_skb_set_moredata(skb, true); __skb_queue_tail(&data->q, skb); data->tail[mvif->idx] = skb; } void mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev, struct beacon_bc_data *data, int max_nframes) { int i, nframes; - data->dev = dev; - __skb_queue_head_init(&data->q); - do { nframes = skb_queue_len(&data->q); ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt76x02_add_buffered_bc, data); } while (nframes != skb_queue_len(&data->q) && skb_queue_len(&data->q) < max_nframes); if (!skb_queue_len(&data->q)) return; for (i = 0; i < ARRAY_SIZE(data->tail); i++) { if (!data->tail[i]) continue; mt76_skb_set_moredata(data->tail[i], false); } } EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc); void mt76x02_init_beacon_config(struct mt76x02_dev *dev) { mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX)); mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff); mt76x02_set_beacon_offsets(dev); } EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_dfs.c b/sys/contrib/dev/mediatek/mt76/mt76x02_dfs.c index 024a5c0a5a57..7a07636d09c6 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_dfs.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_dfs.c @@ -1,892 +1,892 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Lorenzo Bianconi */ #include "mt76x02.h" #define RADAR_SPEC(m, len, el, eh, wl, wh, \ w_tolerance, tl, th, t_tolerance, \ bl, bh, event_exp, power_jmp) \ { \ .mode = m, \ .avg_len = len, \ .e_low = el, \ .e_high = eh, \ .w_low = wl, \ .w_high = wh, \ .w_margin = w_tolerance, \ .t_low = tl, \ .t_high = th, \ .t_margin = t_tolerance, \ .b_low = bl, \ .b_high = bh, \ .event_expiration = event_exp, \ .pwr_jmp = power_jmp \ } static const struct mt76x02_radar_specs etsi_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 0x7fffffff, 0x155cc0, 0x19dd), RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 0x7fffffff, 0x2191c0, 0x15cc), /* 40MHz */ RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 0x7fffffff, 0x155cc0, 0x19dd), RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 0x7fffffff, 0x2191c0, 0x15cc), /* 80MHz */ RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0, 0x7fffffff, 0x155cc0, 0x19cc), RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0, 0x7fffffff, 0x155cc0, 0x19dd), RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0, 0x7fffffff, 0x2191c0, 0x15cc) }; static const struct mt76x02_radar_specs fcc_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0xfe808, 0x13dc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0xfe808, 0x19dd), RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0xfe808, 0x12cc), RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0x57bcf00, 0x1289), /* 40MHz */ RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0xfe808, 0x13dc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0xfe808, 0x19dd), RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0xfe808, 0x12cc), RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0x57bcf00, 0x1289), /* 80MHz */ RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0, 0x7fffffff, 0xfe808, 0x16cc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0xfe808, 0x19dd), RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0xfe808, 0x12cc), RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0x57bcf00, 0x1289) }; static const struct mt76x02_radar_specs jp_w56_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0x14c080, 0x13dc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0x14c080, 0x19dd), RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0x14c080, 0x12cc), RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0X57bcf00, 0x1289), /* 40MHz */ RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0, 0x7fffffff, 0x14c080, 0x13dc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0x14c080, 0x19dd), RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0x14c080, 0x12cc), RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0X57bcf00, 0x1289), /* 80MHz */ RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0, 0x7fffffff, 0x14c080, 0x16cc), RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0, 0x7fffffff, 0x14c080, 0x19dd), RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0, 0x7fffffff, 0x14c080, 0x12cc), RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0, 0x3938700, 0X57bcf00, 0x1289) }; static const struct mt76x02_radar_specs jp_w53_radar_specs[] = { /* 20MHz */ RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 }, RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 }, /* 40MHz */ RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 }, RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 }, /* 80MHz */ RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 }, RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0, 0x7fffffff, 0x14c080, 0x16cc), { 0 } }; static void mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable) { u32 data; data = (1 << 1) | enable; mt76_wr(dev, MT_BBP(DFS, 36), data); } static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev, struct mt76x02_dfs_sequence *seq) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; list_add(&seq->head, &dfs_pd->seq_pool); dfs_pd->seq_stats.seq_pool_len++; dfs_pd->seq_stats.seq_len--; } static struct mt76x02_dfs_sequence * mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_sequence *seq; if (list_empty(&dfs_pd->seq_pool)) { seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC); } else { seq = list_first_entry(&dfs_pd->seq_pool, struct mt76x02_dfs_sequence, head); list_del(&seq->head); dfs_pd->seq_stats.seq_pool_len--; } if (seq) dfs_pd->seq_stats.seq_len++; return seq; } static int mt76x02_dfs_get_multiple(int val, int frac, int margin) { int remainder, factor; if (!frac) return 0; if (abs(val - frac) <= margin) return 1; factor = val / frac; remainder = val % frac; if (remainder > margin) { if ((frac - remainder) <= margin) factor++; else factor = 0; } return factor; } static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_sequence *seq, *tmp_seq; int i; /* reset hw detector */ mt76_wr(dev, MT_BBP(DFS, 1), 0xf); /* reset sw detector */ for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { dfs_pd->event_rb[i].h_rb = 0; dfs_pd->event_rb[i].t_rb = 0; } list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { list_del_init(&seq->head); mt76x02_dfs_seq_pool_put(dev, seq); } } static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev) { bool ret = false; u32 current_ts, delta_ts; struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER); delta_ts = current_ts - dfs_pd->chirp_pulse_ts; dfs_pd->chirp_pulse_ts = current_ts; /* 12 sec */ if (delta_ts <= (12 * (1 << 20))) { if (++dfs_pd->chirp_pulse_cnt > 8) ret = true; } else { dfs_pd->chirp_pulse_cnt = 1; } return ret; } static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev, struct mt76x02_dfs_hw_pulse *pulse) { u32 data; /* select channel */ data = (MT_DFS_CH_EN << 16) | pulse->engine; mt76_wr(dev, MT_BBP(DFS, 0), data); /* reported period */ pulse->period = mt76_rr(dev, MT_BBP(DFS, 19)); /* reported width */ pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20)); pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23)); /* reported burst number */ pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22)); } static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev, struct mt76x02_dfs_hw_pulse *pulse) { bool ret = false; if (!pulse->period || !pulse->w1) return false; switch (dev->mt76.region) { case NL80211_DFS_FCC: if (pulse->engine > 3) break; if (pulse->engine == 3) { ret = mt76x02_dfs_check_chirp(dev); break; } /* check short pulse*/ if (pulse->w1 < 120) ret = (pulse->period >= 2900 && (pulse->period <= 4700 || pulse->period >= 6400) && (pulse->period <= 6800 || pulse->period >= 10200) && pulse->period <= 61600); else if (pulse->w1 < 130) /* 120 - 130 */ ret = (pulse->period >= 2900 && pulse->period <= 61600); else ret = (pulse->period >= 3500 && pulse->period <= 10100); break; case NL80211_DFS_ETSI: if (pulse->engine >= 3) break; ret = (pulse->period >= 4900 && (pulse->period <= 10200 || pulse->period >= 12400) && pulse->period <= 100100); break; case NL80211_DFS_JP: if (dev->mphy.chandef.chan->center_freq >= 5250 && dev->mphy.chandef.chan->center_freq <= 5350) { /* JPW53 */ if (pulse->w1 <= 130) ret = (pulse->period >= 28360 && (pulse->period <= 28700 || pulse->period >= 76900) && pulse->period <= 76940); break; } if (pulse->engine > 3) break; if (pulse->engine == 3) { ret = mt76x02_dfs_check_chirp(dev); break; } /* check short pulse*/ if (pulse->w1 < 120) ret = (pulse->period >= 2900 && (pulse->period <= 4700 || pulse->period >= 6400) && (pulse->period <= 6800 || pulse->period >= 27560) && (pulse->period <= 27960 || pulse->period >= 28360) && (pulse->period <= 28700 || pulse->period >= 79900) && pulse->period <= 80100); else if (pulse->w1 < 130) /* 120 - 130 */ ret = (pulse->period >= 2900 && (pulse->period <= 10100 || pulse->period >= 27560) && (pulse->period <= 27960 || pulse->period >= 28360) && (pulse->period <= 28700 || pulse->period >= 79900) && pulse->period <= 80100); else ret = (pulse->period >= 3900 && pulse->period <= 10100); break; case NL80211_DFS_UNSET: default: return false; } return ret; } static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev, struct mt76x02_dfs_event *event) { u32 data; /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2) * 2nd: DFS_R37[21:0]: pulse time * 3rd: DFS_R37[11:0]: pulse width * 3rd: DFS_R37[25:16]: phase * 4th: DFS_R37[12:0]: current pwr * 4th: DFS_R37[21:16]: pwr stable counter * * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected */ data = mt76_rr(dev, MT_BBP(DFS, 37)); if (!MT_DFS_CHECK_EVENT(data)) return false; event->engine = MT_DFS_EVENT_ENGINE(data); data = mt76_rr(dev, MT_BBP(DFS, 37)); event->ts = MT_DFS_EVENT_TIMESTAMP(data); data = mt76_rr(dev, MT_BBP(DFS, 37)); event->width = MT_DFS_EVENT_WIDTH(data); return true; } static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev, struct mt76x02_dfs_event *event) { if (event->engine == 2) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1]; u16 last_event_idx; u32 delta_ts; last_event_idx = mt76_decr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); delta_ts = event->ts - event_buff->data[last_event_idx].ts; if (delta_ts < MT_DFS_EVENT_TIME_MARGIN && event_buff->data[last_event_idx].width >= 200) return false; } return true; } static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev, struct mt76x02_dfs_event *event) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_event_rb *event_buff; /* add radar event to ring buffer */ event_buff = event->engine == 2 ? &dfs_pd->event_rb[1] : &dfs_pd->event_rb[0]; event_buff->data[event_buff->t_rb] = *event; event_buff->data[event_buff->t_rb].fetch_ts = jiffies; event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN); if (event_buff->t_rb == event_buff->h_rb) event_buff->h_rb = mt76_incr(event_buff->h_rb, MT_DFS_EVENT_BUFLEN); } static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev, struct mt76x02_dfs_event *event, u16 cur_len) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_sw_detector_params *sw_params; u32 width_delta, with_sum; struct mt76x02_dfs_sequence seq, *seq_p; struct mt76x02_dfs_event_rb *event_rb; struct mt76x02_dfs_event *cur_event; int i, j, end, pri, factor, cur_pri; event_rb = event->engine == 2 ? &dfs_pd->event_rb[1] : &dfs_pd->event_rb[0]; i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN); end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN); while (i != end) { cur_event = &event_rb->data[i]; with_sum = event->width + cur_event->width; sw_params = &dfs_pd->sw_dpd_params; switch (dev->mt76.region) { case NL80211_DFS_FCC: case NL80211_DFS_JP: if (with_sum < 600) width_delta = 8; else width_delta = with_sum >> 3; break; case NL80211_DFS_ETSI: if (event->engine == 2) width_delta = with_sum >> 6; else if (with_sum < 620) width_delta = 24; else width_delta = 8; break; case NL80211_DFS_UNSET: default: return -EINVAL; } pri = event->ts - cur_event->ts; if (abs(event->width - cur_event->width) > width_delta || pri < sw_params->min_pri) goto next; if (pri > sw_params->max_pri) break; seq.pri = event->ts - cur_event->ts; seq.first_ts = cur_event->ts; seq.last_ts = event->ts; seq.engine = event->engine; seq.count = 2; j = mt76_decr(i, MT_DFS_EVENT_BUFLEN); while (j != end) { cur_event = &event_rb->data[j]; cur_pri = event->ts - cur_event->ts; factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri, sw_params->pri_margin); if (factor > 0) { seq.first_ts = cur_event->ts; seq.count++; } j = mt76_decr(j, MT_DFS_EVENT_BUFLEN); } if (seq.count <= cur_len) goto next; seq_p = mt76x02_dfs_seq_pool_get(dev); if (!seq_p) return -ENOMEM; *seq_p = seq; INIT_LIST_HEAD(&seq_p->head); list_add(&seq_p->head, &dfs_pd->sequences); next: i = mt76_decr(i, MT_DFS_EVENT_BUFLEN); } return 0; } static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev, struct mt76x02_dfs_event *event) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_sw_detector_params *sw_params; struct mt76x02_dfs_sequence *seq, *tmp_seq; u16 max_seq_len = 0; int factor, pri; sw_params = &dfs_pd->sw_dpd_params; list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) { if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) { list_del_init(&seq->head); mt76x02_dfs_seq_pool_put(dev, seq); continue; } if (event->engine != seq->engine) continue; pri = event->ts - seq->last_ts; factor = mt76x02_dfs_get_multiple(pri, seq->pri, sw_params->pri_margin); if (factor > 0) { seq->last_ts = event->ts; seq->count++; max_seq_len = max_t(u16, max_seq_len, seq->count); } } return max_seq_len; } static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_sequence *seq; if (list_empty(&dfs_pd->sequences)) return false; list_for_each_entry(seq, &dfs_pd->sequences, head) { if (seq->count > MT_DFS_SEQUENCE_TH) { dfs_pd->stats[seq->engine].sw_pattern++; return true; } } return false; } static void mt76x02_dfs_add_events(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_event event; int i, seq_len; /* disable debug mode */ mt76x02_dfs_set_capture_mode_ctrl(dev, false); for (i = 0; i < MT_DFS_EVENT_LOOP; i++) { if (!mt76x02_dfs_fetch_event(dev, &event)) break; if (dfs_pd->last_event_ts > event.ts) mt76x02_dfs_detector_reset(dev); dfs_pd->last_event_ts = event.ts; if (!mt76x02_dfs_check_event(dev, &event)) continue; seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event); mt76x02_dfs_create_sequence(dev, &event, seq_len); mt76x02_dfs_queue_event(dev, &event); } mt76x02_dfs_set_capture_mode_ctrl(dev, true); } static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; struct mt76x02_dfs_event_rb *event_buff; struct mt76x02_dfs_event *event; int i; for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) { event_buff = &dfs_pd->event_rb[i]; while (event_buff->h_rb != event_buff->t_rb) { event = &event_buff->data[event_buff->h_rb]; /* sorted list */ if (time_is_after_jiffies(event->fetch_ts + MT_DFS_EVENT_WINDOW)) break; event_buff->h_rb = mt76_incr(event_buff->h_rb, MT_DFS_EVENT_BUFLEN); } } } static void mt76x02_dfs_tasklet(struct tasklet_struct *t) { struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t, dfs_tasklet); struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd); u32 engine_mask; int i; if (test_bit(MT76_SCANNING, &dev->mphy.state)) goto out; if (time_is_before_jiffies(dfs_pd->last_sw_check + MT_DFS_SW_TIMEOUT)) { bool radar_detected; dfs_pd->last_sw_check = jiffies; mt76x02_dfs_add_events(dev); radar_detected = mt76x02_dfs_check_detection(dev); if (radar_detected) { /* sw detector rx radar pattern */ - ieee80211_radar_detected(dev->mt76.hw); + ieee80211_radar_detected(dev->mt76.hw, NULL); mt76x02_dfs_detector_reset(dev); return; } mt76x02_dfs_check_event_window(dev); } engine_mask = mt76_rr(dev, MT_BBP(DFS, 1)); if (!(engine_mask & 0xf)) goto out; for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { struct mt76x02_dfs_hw_pulse pulse; if (!(engine_mask & (1 << i))) continue; pulse.engine = i; mt76x02_dfs_get_hw_pulse(dev, &pulse); if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) { dfs_pd->stats[i].hw_pulse_discarded++; continue; } /* hw detector rx radar pattern */ dfs_pd->stats[i].hw_pattern++; - ieee80211_radar_detected(dev->mt76.hw); + ieee80211_radar_detected(dev->mt76.hw, NULL); mt76x02_dfs_detector_reset(dev); return; } /* reset hw detector */ mt76_wr(dev, MT_BBP(DFS, 1), 0xf); out: mt76x02_irq_enable(dev, MT_INT_GPTIMER); } static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; switch (dev->mt76.region) { case NL80211_DFS_FCC: dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI; dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI; dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; break; case NL80211_DFS_ETSI: dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI; dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI; dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2; break; case NL80211_DFS_JP: dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI; dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI; dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN; break; case NL80211_DFS_UNSET: default: break; } } static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev) { const struct mt76x02_radar_specs *radar_specs; u8 i, shift; u32 data; switch (dev->mphy.chandef.width) { case NL80211_CHAN_WIDTH_40: shift = MT_DFS_NUM_ENGINES; break; case NL80211_CHAN_WIDTH_80: shift = 2 * MT_DFS_NUM_ENGINES; break; default: shift = 0; break; } switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs[shift]; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs[shift]; break; case NL80211_DFS_JP: if (dev->mphy.chandef.chan->center_freq >= 5250 && dev->mphy.chandef.chan->center_freq <= 5350) radar_specs = &jp_w53_radar_specs[shift]; else radar_specs = &jp_w56_radar_specs[shift]; break; case NL80211_DFS_UNSET: default: return; } data = (MT_DFS_VGA_MASK << 16) | (MT_DFS_PWR_GAIN_OFFSET << 12) | (MT_DFS_PWR_DOWN_TIME << 8) | (MT_DFS_SYM_ROUND << 4) | (MT_DFS_DELTA_DELAY & 0xf); mt76_wr(dev, MT_BBP(DFS, 2), data); data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK; mt76_wr(dev, MT_BBP(DFS, 3), data); for (i = 0; i < MT_DFS_NUM_ENGINES; i++) { /* configure engine */ mt76_wr(dev, MT_BBP(DFS, 0), i); /* detection mode + avg_len */ data = ((radar_specs[i].avg_len & 0x1ff) << 16) | (radar_specs[i].mode & 0xf); mt76_wr(dev, MT_BBP(DFS, 4), data); /* dfs energy */ data = ((radar_specs[i].e_high & 0x0fff) << 16) | (radar_specs[i].e_low & 0x0fff); mt76_wr(dev, MT_BBP(DFS, 5), data); /* dfs period */ mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low); mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high); /* dfs burst */ mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low); mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high); /* dfs width */ data = ((radar_specs[i].w_high & 0x0fff) << 16) | (radar_specs[i].w_low & 0x0fff); mt76_wr(dev, MT_BBP(DFS, 14), data); /* dfs margins */ data = (radar_specs[i].w_margin << 16) | radar_specs[i].t_margin; mt76_wr(dev, MT_BBP(DFS, 15), data); /* dfs event expiration */ mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration); /* dfs pwr adj */ mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp); } /* reset status */ mt76_wr(dev, MT_BBP(DFS, 1), 0xf); mt76_wr(dev, MT_BBP(DFS, 36), 0x3); /* enable detection*/ mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); mt76_wr(dev, MT_BBP(IBI, 11), 0x0c350001); } void mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev *dev) { u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31; agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8)); agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4)); val_r8 = (agc_r8 & 0x00007e00) >> 9; val_r4 = agc_r4 & ~0x1f000000; val_r4 += (((val_r8 + 1) >> 1) << 24); mt76_wr(dev, MT_BBP(AGC, 4), val_r4); dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4); dfs_r31 += val_r8; dfs_r31 -= (agc_r8 & 0x00000038) >> 3; dfs_r31 = (dfs_r31 << 16) | 0x00000307; mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31); if (is_mt76x2(dev)) { mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071); } else { /* disable hw detector */ mt76_wr(dev, MT_BBP(DFS, 0), 0); /* enable hw detector */ mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16); } } EXPORT_SYMBOL_GPL(mt76x02_phy_dfs_adjust_agc); void mt76x02_dfs_init_params(struct mt76x02_dev *dev) { if (mt76_phy_dfs_state(&dev->mphy) > MT_DFS_STATE_DISABLED) { mt76x02_dfs_init_sw_detector(dev); mt76x02_dfs_set_bbp_params(dev); /* enable debug mode */ mt76x02_dfs_set_capture_mode_ctrl(dev, true); mt76x02_irq_enable(dev, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 1); } else { /* disable hw detector */ mt76_wr(dev, MT_BBP(DFS, 0), 0); /* clear detector status */ mt76_wr(dev, MT_BBP(DFS, 1), 0xf); if (mt76_chip(&dev->mt76) == 0x7610 || mt76_chip(&dev->mt76) == 0x7630) mt76_wr(dev, MT_BBP(IBI, 11), 0xfde8081); else mt76_wr(dev, MT_BBP(IBI, 11), 0); mt76x02_irq_disable(dev, MT_INT_GPTIMER); mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_GP_TIMER_EN, 0); } } EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params); void mt76x02_dfs_init_detector(struct mt76x02_dev *dev) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; INIT_LIST_HEAD(&dfs_pd->sequences); INIT_LIST_HEAD(&dfs_pd->seq_pool); dev->mt76.region = NL80211_DFS_UNSET; dfs_pd->last_sw_check = jiffies; tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet); } static void mt76x02_dfs_set_domain(struct mt76x02_dev *dev, enum nl80211_dfs_regions region) { struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd; mutex_lock(&dev->mt76.mutex); if (dev->mt76.region != region) { tasklet_disable(&dfs_pd->dfs_tasklet); dev->ed_monitor = dev->ed_monitor_enabled && region == NL80211_DFS_ETSI; mt76x02_edcca_init(dev); dev->mt76.region = region; mt76x02_dfs_init_params(dev); tasklet_enable(&dfs_pd->dfs_tasklet); } mutex_unlock(&dev->mt76.mutex); } void mt76x02_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt76x02_dev *dev = hw->priv; mt76x02_dfs_set_domain(dev, request->dfs_region); } diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.c b/sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.c index 0acabba2d1a5..a5e3392c0b48 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.c @@ -1,154 +1,147 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau * Copyright (C) 2018 Lorenzo Bianconi */ -#include +#include #include "mt76x02_eeprom.h" static int mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data, enum mt76x02_eeprom_modes mode) { u32 val; int i; val = mt76_rr(dev, MT_EFUSE_CTRL); val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE); val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); val |= MT_EFUSE_CTRL_KICK; mt76_wr(dev, MT_EFUSE_CTRL, val); if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) return -ETIMEDOUT; udelay(2); val = mt76_rr(dev, MT_EFUSE_CTRL); if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { memset(data, 0xff, 16); return 0; } for (i = 0; i < 4; i++) { val = mt76_rr(dev, MT_EFUSE_DATA(i)); put_unaligned_le32(val, data + 4 * i); } return 0; } int mt76x02_eeprom_copy(struct mt76x02_dev *dev, enum mt76x02_eeprom_field field, void *dest, int len) { if (field + len > dev->mt76.eeprom.size) return -1; memcpy(dest, dev->mt76.eeprom.data + field, len); return 0; } EXPORT_SYMBOL_GPL(mt76x02_eeprom_copy); int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, int len, enum mt76x02_eeprom_modes mode) { int ret, i; for (i = 0; i + 16 <= len; i += 16) { ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); if (ret) return ret; } return 0; } EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) { u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { case BOARD_TYPE_5GHZ: dev->mphy.cap.has_5ghz = true; break; case BOARD_TYPE_2GHZ: dev->mphy.cap.has_2ghz = true; break; default: dev->mphy.cap.has_2ghz = true; dev->mphy.cap.has_5ghz = true; break; } } EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) { u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); if (band == NL80211_BAND_5GHZ) return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); else return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); } EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) { u16 val; val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); *lna_2g = val & 0xff; lna_5g[0] = val >> 8; val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); lna_5g[1] = val >> 8; val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); lna_5g[2] = val >> 8; if (!mt76x02_field_valid(lna_5g[1])) lna_5g[1] = lna_5g[0]; if (!mt76x02_field_valid(lna_5g[2])) lna_5g[2] = lna_5g[0]; if (band == NL80211_BAND_2GHZ) *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); else *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); } EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, s8 *lna_2g, s8 *lna_5g, struct ieee80211_channel *chan) { - u16 val; u8 lna; - val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); - if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) - *lna_2g = 0; - if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) - memset(lna_5g, 0, sizeof(s8) * 3); - if (chan->band == NL80211_BAND_2GHZ) lna = *lna_2g; else if (chan->hw_value <= 64) lna = lna_5g[0]; else if (chan->hw_value <= 128) lna = lna_5g[1]; else lna = lna_5g[2]; return lna != 0xff ? lna : 0; } EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_mmio.c b/sys/contrib/dev/mediatek/mt76/mt76x02_mmio.c index e9c5e85ec07c..a82c75ba26e6 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_mmio.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_mmio.c @@ -1,556 +1,566 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau * Copyright (C) 2018 Lorenzo Bianconi */ #include #include #include "mt76x02.h" #include "mt76x02_mcu.h" #include "trace.h" static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t) { struct mt76x02_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet); struct mt76_dev *mdev = &dev->mt76; struct mt76_queue *q = dev->mphy.q_tx[MT_TXQ_PSD]; - struct beacon_bc_data data = {}; + struct beacon_bc_data data = { + .dev = dev, + }; struct sk_buff *skb; int i; - if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) + if (dev->mphy.offchannel) return; + __skb_queue_head_init(&data.q); + mt76x02_resync_beacon_timer(dev); /* Prevent corrupt transmissions during update */ mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); dev->beacon_data_count = 0; ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, - mt76x02_update_beacon_iter, dev); + mt76x02_update_beacon_iter, &data); + + while ((skb = __skb_dequeue(&data.q)) != NULL) + mt76x02_mac_set_beacon(dev, skb); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~(0xff00 >> dev->beacon_data_count)); mt76_csa_check(mdev); if (mdev->csa_complete) return; mt76x02_enqueue_buffered_bc(dev, &data, 8); if (!skb_queue_len(&data.q)) return; for (i = 0; i < ARRAY_SIZE(data.tail); i++) { if (!data.tail[i]) continue; mt76_skb_set_moredata(data.tail[i], false); } 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; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; mt76_tx_queue_skb(dev, q, MT_TXQ_PSD, skb, &mvif->group_wcid, NULL); } spin_unlock(&q->lock); } static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en) { if (en) tasklet_enable(&dev->mt76.pre_tbtt_tasklet); else tasklet_disable(&dev->mt76.pre_tbtt_tasklet); } static void mt76x02e_beacon_enable(struct mt76x02_dev *dev, bool en) { mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); if (en) mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); else mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); } void mt76x02e_init_beacon_config(struct mt76x02_dev *dev) { static const struct mt76x02_beacon_ops beacon_ops = { .nslots = 8, .slot_size = 1024, .pre_tbtt_enable = mt76x02e_pre_tbtt_enable, .beacon_enable = mt76x02e_beacon_enable, }; dev->beacon_ops = &beacon_ops; /* Fire a pre-TBTT interrupt 8 ms before TBTT */ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, MT_DFS_GP_INTERVAL); mt76_wr(dev, MT_INT_TIMER_EN, 0); mt76x02_init_beacon_config(dev); } EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config); static int mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q, int idx, int n_desc, int bufsize) { int err; err = mt76_queue_alloc(dev, q, idx, n_desc, bufsize, MT_RX_RING_BASE); if (err < 0) return err; mt76x02_irq_enable(dev, MT_INT_RX_DONE(idx)); return 0; } static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev) { struct mt76x02_tx_status stat; u8 update = 1; while (kfifo_get(&dev->txstatus_fifo, &stat)) mt76x02_send_tx_status(dev, &stat, &update); } static void mt76x02_tx_worker(struct mt76_worker *w) { struct mt76x02_dev *dev; dev = container_of(w, struct mt76x02_dev, mt76.tx_worker); mt76x02_mac_poll_tx_status(dev, false); mt76x02_process_tx_status_fifo(dev); mt76_txq_schedule_all(&dev->mphy); } static int mt76x02_poll_tx(struct napi_struct *napi, int budget) { struct mt76x02_dev *dev = container_of(napi, struct mt76x02_dev, mt76.tx_napi); int i; mt76x02_mac_poll_tx_status(dev, false); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); for (i = MT_TXQ_PSD; i >= 0; i--) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); if (napi_complete_done(napi, 0)) mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false); for (i = MT_TXQ_PSD; i >= 0; i--) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false); mt76_worker_schedule(&dev->mt76.tx_worker); return 0; } int mt76x02_dma_init(struct mt76x02_dev *dev) { struct mt76_txwi_cache __maybe_unused *t; int i, ret, fifo_size; struct mt76_queue *q; void *status_fifo; BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM); fifo_size = roundup_pow_of_two(32 * sizeof(struct mt76x02_tx_status)); status_fifo = devm_kzalloc(dev->mt76.dev, fifo_size, GFP_KERNEL); if (!status_fifo) return -ENOMEM; dev->mt76.tx_worker.fn = mt76x02_tx_worker; tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet); spin_lock_init(&dev->txstatus_fifo_lock); kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size); mt76_dma_attach(&dev->mt76); mt76_wr(dev, MT_WPDMA_RST_IDX, ~0); for (i = 0; i < IEEE80211_NUM_ACS; i++) { ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), MT76x02_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; mt76x02_irq_enable(dev, MT_INT_TX_DONE(IEEE80211_AC_VO) | MT_INT_TX_DONE(IEEE80211_AC_VI) | MT_INT_TX_DONE(IEEE80211_AC_BE) | MT_INT_TX_DONE(IEEE80211_AC_BK) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) | MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU)); ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1, MT_MCU_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; q = &dev->mt76.q_rx[MT_RXQ_MAIN]; q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi); ret = mt76x02_init_rx_queue(dev, q, 0, MT76X02_RX_RING_SIZE, MT_RX_BUF_SIZE); if (ret) return ret; ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt76x02_poll_tx); napi_enable(&dev->mt76.tx_napi); return 0; } EXPORT_SYMBOL_GPL(mt76x02_dma_init); void mt76x02_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { struct mt76x02_dev *dev; dev = container_of(mdev, struct mt76x02_dev, mt76); mt76x02_irq_enable(dev, MT_INT_RX_DONE(q)); } EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete); irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance) { struct mt76x02_dev *dev = dev_instance; u32 intr, mask; intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask = intr & (MT_INT_RX_DONE_ALL | MT_INT_GPTIMER); if (intr & (MT_INT_TX_DONE_ALL | MT_INT_TX_STAT)) mask |= MT_INT_TX_DONE_ALL; mt76x02_irq_disable(dev, mask); if (intr & MT_INT_RX_DONE(0)) napi_schedule(&dev->mt76.napi[0]); if (intr & MT_INT_RX_DONE(1)) napi_schedule(&dev->mt76.napi[1]); if (intr & MT_INT_PRE_TBTT) tasklet_schedule(&dev->mt76.pre_tbtt_tasklet); /* send buffered multicast frames now */ if (intr & MT_INT_TBTT) { if (dev->mt76.csa_complete) mt76_csa_finish(&dev->mt76); else mt76_queue_kick(dev, dev->mphy.q_tx[MT_TXQ_PSD]); } if (intr & MT_INT_TX_STAT) mt76x02_mac_poll_tx_status(dev, true); if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) napi_schedule(&dev->mt76.tx_napi); if (intr & MT_INT_GPTIMER) tasklet_schedule(&dev->dfs_pd.dfs_tasklet); return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(mt76x02_irq_handler); static void mt76x02_dma_enable(struct mt76x02_dev *dev) { u32 val; mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); mt76x02_wait_for_wpdma(&dev->mt76, 1000); usleep_range(50, 100); val = FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) | MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN; mt76_set(dev, MT_WPDMA_GLO_CFG, val); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE); } void mt76x02_dma_disable(struct mt76x02_dev *dev) { u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG); val &= MT_WPDMA_GLO_CFG_DMA_BURST_SIZE | MT_WPDMA_GLO_CFG_BIG_ENDIAN | MT_WPDMA_GLO_CFG_HDR_SEG_LEN; val |= MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE; mt76_wr(dev, MT_WPDMA_GLO_CFG, val); } EXPORT_SYMBOL_GPL(mt76x02_dma_disable); void mt76x02_mac_start(struct mt76x02_dev *dev) { mt76x02_mac_reset_counters(dev); mt76x02_dma_enable(dev); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); mt76x02_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | MT_INT_TX_STAT); } EXPORT_SYMBOL_GPL(mt76x02_mac_start); static bool mt76x02_tx_hang(struct mt76x02_dev *dev) { u32 dma_idx, prev_dma_idx; struct mt76_queue *q; int i; for (i = 0; i < 4; i++) { q = dev->mphy.q_tx[i]; prev_dma_idx = dev->mt76.tx_dma_idx[i]; dma_idx = readl(&q->regs->dma_idx); dev->mt76.tx_dma_idx[i] = dma_idx; if (!q->queued || prev_dma_idx != dma_idx) { dev->tx_hang_check[i] = 0; continue; } if (++dev->tx_hang_check[i] >= MT_TX_HANG_TH) return true; } return false; } static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, void *data) { struct mt76x02_dev *dev = hw->priv; struct mt76_wcid *wcid; if (!sta) return; wcid = (struct mt76_wcid *)sta->drv_priv; if (wcid->hw_key_idx != key->keyidx || wcid->sw_iv) return; mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key); } static void mt76x02_reset_state(struct mt76x02_dev *dev) { int i; lockdep_assert_held(&dev->mt76.mutex); clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); rcu_read_lock(); ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL); rcu_read_unlock(); for (i = 0; i < MT76x02_N_WCIDS; i++) { struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct mt76x02_sta *msta; struct mt76_wcid *wcid; void *priv; wcid = rcu_dereference_protected(dev->mt76.wcid[i], lockdep_is_held(&dev->mt76.mutex)); if (!wcid) continue; rcu_assign_pointer(dev->mt76.wcid[i], NULL); priv = msta = container_of(wcid, struct mt76x02_sta, wcid); sta = container_of(priv, struct ieee80211_sta, drv_priv); priv = msta->vif; vif = container_of(priv, struct ieee80211_vif, drv_priv); - __mt76_sta_remove(&dev->mt76, vif, sta); + __mt76_sta_remove(&dev->mphy, vif, sta); memset(msta, 0, sizeof(*msta)); } dev->mt76.vif_mask = 0; dev->mt76.beacon_mask = 0; } static void mt76x02_watchdog_reset(struct mt76x02_dev *dev) { u32 mask = dev->mt76.mmio.irqmask; bool restart = dev->mt76.mcu_ops->mcu_restart; int i; ieee80211_stop_queues(dev->mt76.hw); set_bit(MT76_RESET, &dev->mphy.state); tasklet_disable(&dev->mt76.pre_tbtt_tasklet); mt76_worker_disable(&dev->mt76.tx_worker); napi_disable(&dev->mt76.tx_napi); mt76_for_each_q_rx(&dev->mt76, i) { napi_disable(&dev->mt76.napi[i]); } mutex_lock(&dev->mt76.mutex); dev->mcu_timeout = 0; if (restart) mt76x02_reset_state(dev); if (dev->mt76.beacon_mask) mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_BEACON_TX | MT_BEACON_TIME_CFG_TBTT_EN); mt76x02_irq_disable(dev, mask); /* perform device reset */ mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); mt76_wr(dev, MT_MAC_SYS_CTRL, 0); mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN); usleep_range(5000, 10000); mt76_wr(dev, MT_INT_SOURCE_CSR, 0xffffffff); /* let fw reset DMA */ mt76_set(dev, 0x734, 0x3); if (restart) mt76_mcu_restart(dev); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true); for (i = 0; i < __MT_TXQ_MAX; i++) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); mt76_for_each_q_rx(&dev->mt76, i) { mt76_queue_rx_reset(dev, i); } mt76_tx_status_check(&dev->mt76, true); mt76x02_mac_start(dev); if (dev->ed_monitor) mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); if (dev->mt76.beacon_mask && !restart) mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_BEACON_TX | MT_BEACON_TIME_CFG_TBTT_EN); mt76x02_irq_enable(dev, mask); mutex_unlock(&dev->mt76.mutex); 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); - mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + + local_bh_disable(); + napi_schedule(&dev->mt76.tx_napi); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } local_bh_enable(); if (restart) { set_bit(MT76_RESTART, &dev->mphy.state); mt76x02_mcu_function_select(dev, Q_SELECT, 1); ieee80211_restart_hw(dev->mt76.hw); } else { ieee80211_wake_queues(dev->mt76.hw); mt76_txq_schedule_all(&dev->mphy); } } void mt76x02_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) { struct mt76x02_dev *dev = hw->priv; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; clear_bit(MT76_RESTART, &dev->mphy.state); } EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); static void mt76x02_check_tx_hang(struct mt76x02_dev *dev) { if (test_bit(MT76_RESTART, &dev->mphy.state)) return; if (!mt76x02_tx_hang(dev) && !dev->mcu_timeout) return; mt76x02_watchdog_reset(dev); dev->tx_hang_reset++; memset(dev->tx_hang_check, 0, sizeof(dev->tx_hang_check)); memset(dev->mt76.tx_dma_idx, 0xff, sizeof(dev->mt76.tx_dma_idx)); } void mt76x02_wdt_work(struct work_struct *work) { struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, wdt_work.work); mt76x02_check_tx_hang(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, MT_WATCHDOG_TIME); } diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_usb_core.c b/sys/contrib/dev/mediatek/mt76/mt76x02_usb_core.c index 2c6c03809b20..0e1ede9314d8 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_usb_core.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_usb_core.c @@ -1,282 +1,286 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi */ #include "mt76x02_usb.h" static void mt76x02u_remove_dma_hdr(struct sk_buff *skb) { int hdr_len; skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN); hdr_len = ieee80211_get_hdrlen_from_skb(skb); if (hdr_len % 4) mt76x02_remove_hdr_pad(skb, 2); } void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e) { mt76x02u_remove_dma_hdr(e->skb); mt76_tx_complete_skb(mdev, e->wcid, e->skb); } EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb); int mt76x02u_mac_start(struct mt76x02_dev *dev) { mt76x02_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) return -ETIMEDOUT; mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); if (!mt76x02_wait_for_wpdma(&dev->mt76, 50)) return -ETIMEDOUT; return 0; } EXPORT_SYMBOL_GPL(mt76x02u_mac_start); int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { u32 info, pad; /* Buffer layout: * | 4B | xfer len | pad | 4B | * | TXINFO | pkt/cmd | zero pad to 4B | zero | * * length field of TXINFO should be set to 'xfer len'. */ info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; put_unaligned_le32(info, skb_push(skb, sizeof(info))); pad = round_up(skb->len, 4) + 4 - skb->len; return mt76_skb_adjust_pad(skb, pad); } int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); - int pid, len = tx_info->skb->len, ep = q2ep(dev->mphy.q_tx[qid]->hw_idx); + int pid, len = tx_info->skb->len, ep = dev->mphy.q_tx[qid]->ep; struct mt76x02_txwi *txwi; bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU; enum mt76_qsel qsel; u32 flags; int err; mt76_insert_hdr_pad(tx_info->skb); txwi = (struct mt76x02_txwi *)(tx_info->skb->data - sizeof(*txwi)); mt76x02_mac_write_txwi(dev, txwi, tx_info->skb, wcid, sta, len); skb_push(tx_info->skb, sizeof(*txwi)); pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); /* encode packet rate for no-skb packet id to fix up status reporting */ if (pid == MT_PACKET_ID_NO_SKB) pid = MT_PACKET_ID_HAS_RATE | (le16_to_cpu(txwi->rate) & MT_PKTID_RATE) | FIELD_PREP(MT_PKTID_AC, skb_get_queue_mapping(tx_info->skb)); txwi->pktid = pid; if ((mt76_is_skb_pktid(pid) && ampdu) || ep == MT_EP_OUT_HCCA) qsel = MT_QSEL_MGMT; else qsel = MT_QSEL_EDCA; flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) | MT_TXD_INFO_80211; if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) flags |= MT_TXD_INFO_WIV; if (sta) { struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); } err = mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags); if (err && wcid) /* Release pktid in case of error. */ idr_remove(&wcid->pktid, pid); return err; } EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb); /* Trigger pre-TBTT event 8 ms before TBTT */ #define PRE_TBTT_USEC 8000 /* Beacon SRAM memory is limited to 8kB. We need to send PS buffered frames * (which can be 1500 bytes big) via beacon memory. That make limit of number * of slots to 5. TODO: dynamically calculate offsets in beacon SRAM. */ #define N_BCN_SLOTS 5 static void mt76x02u_start_pre_tbtt_timer(struct mt76x02_dev *dev) { u64 time; u32 tbtt; /* Get remaining TBTT in usec */ tbtt = mt76_get_field(dev, MT_TBTT_TIMER, MT_TBTT_TIMER_VAL); tbtt *= 32; if (tbtt <= PRE_TBTT_USEC) { queue_work(system_highpri_wq, &dev->pre_tbtt_work); return; } time = (tbtt - PRE_TBTT_USEC) * 1000ull; hrtimer_start(&dev->pre_tbtt_timer, time, HRTIMER_MODE_REL); } static void mt76x02u_restart_pre_tbtt_timer(struct mt76x02_dev *dev) { u32 tbtt, dw0, dw1; u64 tsf, time; /* Get remaining TBTT in usec */ tbtt = mt76_get_field(dev, MT_TBTT_TIMER, MT_TBTT_TIMER_VAL); tbtt *= 32; dw0 = mt76_rr(dev, MT_TSF_TIMER_DW0); dw1 = mt76_rr(dev, MT_TSF_TIMER_DW1); tsf = (u64)dw0 << 32 | dw1; dev_dbg(dev->mt76.dev, "TSF: %llu us TBTT %u us\n", tsf, tbtt); /* Convert beacon interval in TU (1024 usec) to nsec */ time = ((1000000000ull * dev->mt76.beacon_int) >> 10); /* Adjust time to trigger hrtimer 8ms before TBTT */ if (tbtt < PRE_TBTT_USEC) time -= (PRE_TBTT_USEC - tbtt) * 1000ull; else time += (tbtt - PRE_TBTT_USEC) * 1000ull; hrtimer_start(&dev->pre_tbtt_timer, time, HRTIMER_MODE_REL); } static void mt76x02u_stop_pre_tbtt_timer(struct mt76x02_dev *dev) { do { hrtimer_cancel(&dev->pre_tbtt_timer); cancel_work_sync(&dev->pre_tbtt_work); /* Timer can be rearmed by work. */ } while (hrtimer_active(&dev->pre_tbtt_timer)); } static void mt76x02u_pre_tbtt_work(struct work_struct *work) { struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, pre_tbtt_work); - struct beacon_bc_data data = {}; + struct beacon_bc_data data = { + .dev = dev, + }; struct sk_buff *skb; int nbeacons; - if (!dev->mt76.beacon_mask) + if (!dev->mt76.beacon_mask || dev->mphy.offchannel) return; - if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) - return; + __skb_queue_head_init(&data.q); mt76x02_resync_beacon_timer(dev); /* Prevent corrupt transmissions during update */ mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); dev->beacon_data_count = 0; - ieee80211_iterate_active_interfaces(mt76_hw(dev), + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, - mt76x02_update_beacon_iter, dev); + mt76x02_update_beacon_iter, &data); + + while ((skb = __skb_dequeue(&data.q)) != NULL) + mt76x02_mac_set_beacon(dev, skb); mt76_csa_check(&dev->mt76); if (dev->mt76.csa_complete) { mt76_csa_finish(&dev->mt76); goto out; } nbeacons = hweight8(dev->mt76.beacon_mask); mt76x02_enqueue_buffered_bc(dev, &data, N_BCN_SLOTS - nbeacons); while ((skb = __skb_dequeue(&data.q)) != NULL) mt76x02_mac_set_beacon(dev, skb); out: mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~(0xff00 >> dev->beacon_data_count)); mt76x02u_restart_pre_tbtt_timer(dev); } static enum hrtimer_restart mt76x02u_pre_tbtt_interrupt(struct hrtimer *timer) { struct mt76x02_dev *dev = container_of(timer, struct mt76x02_dev, pre_tbtt_timer); queue_work(system_highpri_wq, &dev->pre_tbtt_work); return HRTIMER_NORESTART; } static void mt76x02u_pre_tbtt_enable(struct mt76x02_dev *dev, bool en) { if (en && dev->mt76.beacon_mask && !hrtimer_active(&dev->pre_tbtt_timer)) mt76x02u_start_pre_tbtt_timer(dev); if (!en) mt76x02u_stop_pre_tbtt_timer(dev); } static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en) { if (WARN_ON_ONCE(!dev->mt76.beacon_int)) return; if (en) mt76x02u_start_pre_tbtt_timer(dev); } void mt76x02u_init_beacon_config(struct mt76x02_dev *dev) { static const struct mt76x02_beacon_ops beacon_ops = { .nslots = N_BCN_SLOTS, .slot_size = (8192 / N_BCN_SLOTS) & ~63, .pre_tbtt_enable = mt76x02u_pre_tbtt_enable, .beacon_enable = mt76x02u_beacon_enable, }; dev->beacon_ops = &beacon_ops; hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt; INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work); mt76x02_init_beacon_config(dev); } EXPORT_SYMBOL_GPL(mt76x02u_init_beacon_config); void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev) { if (!test_bit(MT76_REMOVED, &dev->mphy.state)) mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | MT_BEACON_TIME_CFG_BEACON_TX); mt76x02u_stop_pre_tbtt_timer(dev); } EXPORT_SYMBOL_GPL(mt76x02u_exit_beacon_config); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_usb_mcu.c b/sys/contrib/dev/mediatek/mt76/mt76x02_usb_mcu.c index 02da543dfc5c..b2cc44914294 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_usb_mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_usb_mcu.c @@ -1,296 +1,297 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi */ #include #include #include "mt76x02.h" #include "mt76x02_mcu.h" #include "mt76x02_usb.h" #define MT_CMD_HDR_LEN 4 #define MT_FCE_DMA_ADDR 0x0230 #define MT_FCE_DMA_LEN 0x0234 #define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 static void mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len) { struct mt76_usb *usb = &dev->usb; int i; WARN_ON_ONCE(len / 8 != usb->mcu.rp_len); for (i = 0; i < usb->mcu.rp_len; i++) { u32 reg = get_unaligned_le32(data + 8 * i) - usb->mcu.base; u32 val = get_unaligned_le32(data + 8 * i + 4); WARN_ON_ONCE(usb->mcu.rp[i].reg != reg); usb->mcu.rp[i].value = val; } } static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq) { struct mt76_usb *usb = &dev->usb; u8 *data = usb->mcu.data; int i, len, ret; u32 rxfce; for (i = 0; i < 5; i++) { ret = mt76u_bulk_msg(dev, data, MCU_RESP_URB_SIZE, &len, 300, MT_EP_IN_CMD_RESP); if (ret == -ETIMEDOUT) continue; if (ret) goto out; if (usb->mcu.rp) mt76x02u_multiple_mcu_reads(dev, data + 4, len - 8); rxfce = get_unaligned_le32(data); if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) && FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE) return 0; dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n", FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce), seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce)); } out: dev_err(dev->dev, "error: %s failed with %d\n", __func__, ret); return ret; } static int __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp) { u8 seq = 0; u32 info; int ret; if (test_bit(MT76_REMOVED, &dev->phy.state)) { ret = 0; goto out; } if (wait_resp) { seq = ++dev->mcu.msg_seq & 0xf; if (!seq) seq = ++dev->mcu.msg_seq & 0xf; } info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) | FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) | MT_MCU_MSG_TYPE_CMD; ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info); if (ret) return ret; ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500, MT_EP_OUT_INBAND_CMD); if (ret) goto out; if (wait_resp) ret = mt76x02u_mcu_wait_resp(dev, seq); out: consume_skb(skb); return ret; } static int mt76x02u_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len, bool wait_resp) { struct sk_buff *skb; int err; skb = mt76_mcu_msg_alloc(dev, data, len); if (!skb) return -ENOMEM; mutex_lock(&dev->mcu.mutex); err = __mt76x02u_mcu_send_msg(dev, skb, cmd, wait_resp); mutex_unlock(&dev->mcu.mutex); return err; } static inline void skb_put_le32(struct sk_buff *skb, u32 val) { put_unaligned_le32(val, skb_put(skb, 4)); } static int mt76x02u_mcu_wr_rp(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *data, int n) { const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; const int CMD_RANDOM_WRITE = 12; struct sk_buff *skb; int cnt, i, ret; if (!n) return 0; cnt = min(max_vals_per_cmd, n); skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); if (!skb) return -ENOMEM; skb_reserve(skb, MT_DMA_HDR_LEN); for (i = 0; i < cnt; i++) { skb_put_le32(skb, base + data[i].reg); skb_put_le32(skb, data[i].value); } mutex_lock(&dev->mcu.mutex); ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n); mutex_unlock(&dev->mcu.mutex); if (ret) return ret; return mt76x02u_mcu_wr_rp(dev, base, data + cnt, n - cnt); } static int mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { const int CMD_RANDOM_READ = 10; const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8; struct mt76_usb *usb = &dev->usb; struct sk_buff *skb; int cnt, i, ret; if (!n) return 0; cnt = min(max_vals_per_cmd, n); if (cnt != n) return -EINVAL; skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); if (!skb) return -ENOMEM; skb_reserve(skb, MT_DMA_HDR_LEN); for (i = 0; i < cnt; i++) { skb_put_le32(skb, base + data[i].reg); skb_put_le32(skb, data[i].value); } mutex_lock(&dev->mcu.mutex); usb->mcu.rp = data; usb->mcu.rp_len = n; usb->mcu.base = base; ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true); usb->mcu.rp = NULL; mutex_unlock(&dev->mcu.mutex); return ret; } void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev) { mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE, USB_DIR_OUT | USB_TYPE_VENDOR, 0x1, 0, NULL, 0); } EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset); static int __mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, u8 *data, const void *fw_data, int len, u32 dst_addr) { __le32 info; u32 val; int err, data_len; info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) | FIELD_PREP(MT_MCU_MSG_LEN, len) | MT_MCU_MSG_TYPE_CMD); memcpy(data, &info, sizeof(info)); memcpy(data + sizeof(info), fw_data, len); memset(data + sizeof(info) + len, 0, 4); mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_ADDR, dst_addr); len = roundup(len, 4); mt76u_single_wr(&dev->mt76, MT_VEND_WRITE_FCE, MT_FCE_DMA_LEN, len << 16); data_len = MT_CMD_HDR_LEN + len + sizeof(info); err = mt76u_bulk_msg(&dev->mt76, data, data_len, NULL, 1000, MT_EP_OUT_INBAND_CMD); if (err) { dev_err(dev->mt76.dev, "firmware upload failed: %d\n", err); return err; } val = mt76_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); val++; mt76_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); return 0; } int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, int data_len, u32 max_payload, u32 offset) { int len, err = 0, pos = 0, max_len = max_payload - 8; u8 *buf; buf = kmalloc(max_payload, GFP_KERNEL); if (!buf) return -ENOMEM; while (data_len > 0) { len = min_t(int, data_len, max_len); err = __mt76x02u_mcu_fw_send_data(dev, buf, data + pos, len, offset + pos); if (err < 0) break; data_len -= len; pos += len; usleep_range(5000, 10000); } kfree(buf); return err; } EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data); void mt76x02u_init_mcu(struct mt76_dev *dev) { static const struct mt76_mcu_ops mt76x02u_mcu_ops = { .headroom = MT_CMD_HDR_LEN, .tailroom = 8, .mcu_send_msg = mt76x02u_mcu_send_msg, .mcu_parse_response = mt76x02_mcu_parse_response, .mcu_wr_rp = mt76x02u_mcu_wr_rp, .mcu_rd_rp = mt76x02u_mcu_rd_rp, }; dev->mcu_ops = &mt76x02u_mcu_ops; } EXPORT_SYMBOL_GPL(mt76x02u_init_mcu); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT76x02 MCU helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x02_util.c b/sys/contrib/dev/mediatek/mt76/mt76x02_util.c index dcbb5c605dfe..4fb30589fa7a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x02_util.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x02_util.c @@ -1,699 +1,699 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Stanislaw Gruszka * Copyright (C) 2016 Felix Fietkau */ #include #include "mt76x02.h" #define MT76x02_CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ } struct ieee80211_rate mt76x02_rates[] = { MT76x02_CCK_RATE(0, 10), MT76x02_CCK_RATE(1, 20), MT76x02_CCK_RATE(2, 55), MT76x02_CCK_RATE(3, 110), OFDM_RATE(0, 60), OFDM_RATE(1, 90), OFDM_RATE(2, 120), OFDM_RATE(3, 180), OFDM_RATE(4, 240), OFDM_RATE(5, 360), OFDM_RATE(6, 480), OFDM_RATE(7, 540), }; EXPORT_SYMBOL_GPL(mt76x02_rates); static const struct ieee80211_iface_limit mt76x02_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, { .max = 8, .types = BIT(NL80211_IFTYPE_STATION) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP) }, }; static const struct ieee80211_iface_combination mt76x02_if_comb[] = { { .limits = mt76x02_if_limits, .n_limits = ARRAY_SIZE(mt76x02_if_limits), .max_interfaces = 8, .num_different_channels = 1, .beacon_int_infra_match = true, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80), } }; static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { { .limits = mt76x02u_if_limits, .n_limits = ARRAY_SIZE(mt76x02u_if_limits), .max_interfaces = 2, .num_different_channels = 1, .beacon_int_infra_match = true, } }; static void mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) { struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76); u32 val; val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val); mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val); val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | MT_LED_CTRL_KICK(mphy->leds.pin); if (mphy->leds.al) val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); mt76_wr(dev, MT_LED_CTRL, val); } static int mt76x02_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); u8 delta_on, delta_off; delta_off = max_t(u8, *delay_off / 10, 1); delta_on = max_t(u8, *delay_on / 10, 1); mt76x02_led_set_config(mphy, delta_on, delta_off); return 0; } static void mt76x02_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); if (!brightness) mt76x02_led_set_config(mphy, 0, 0xff); else mt76x02_led_set_config(mphy, 0xff, 0); } int mt76x02_init_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work); hw->queues = 4; hw->max_rates = 1; hw->max_report_rates = 7; hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; wiphy->iface_combinations = mt76x02u_if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb); } else { INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); mt76x02_dfs_init_detector(dev); wiphy->reg_notifier = mt76x02_regd_notifier; wiphy->iface_combinations = mt76x02_if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { dev->mphy.leds.cdev.brightness_set = mt76x02_led_set_brightness; dev->mphy.leds.cdev.blink_set = mt76x02_led_set_blink; } } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); hw->sta_data_size = sizeof(struct mt76x02_sta); hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.hw_key_idx = -1; dev->slottime = 9; if (is_mt76x2(dev)) { dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.chainmask = 0x202; dev->mphy.antenna_mask = 3; } else { dev->mphy.chainmask = 0x101; dev->mphy.antenna_mask = 1; } return 0; } EXPORT_SYMBOL_GPL(mt76x02_init_device); void mt76x02_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mt76x02_dev *dev = hw->priv; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ dev->mt76.rxfilter &= ~(_hw); \ dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ } while (0) mutex_lock(&dev->mt76.mutex); dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | MT_RX_FILTR_CFG_CFEND | MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV); MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); *total_flags = flags; mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mutex_unlock(&dev->mt76.mutex); } EXPORT_SYMBOL_GPL(mt76x02_configure_filter); int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; int idx = 0; memset(msta, 0, sizeof(*msta)); idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT76x02_N_WCIDS); if (idx < 0) return -ENOSPC; msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.hw_key_idx = -1; mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); mt76x02_mac_wcid_set_drop(dev, idx, false); ewma_pktlen_init(&msta->pktlen); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); return 0; } EXPORT_SYMBOL_GPL(mt76x02_sta_add); void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; int idx = wcid->idx; mt76x02_mac_wcid_set_drop(dev, idx, true); mt76x02_mac_wcid_setup(dev, idx, 0, NULL); } EXPORT_SYMBOL_GPL(mt76x02_sta_remove); static void mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, unsigned int idx) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76_txq *mtxq; memset(mvif, 0, sizeof(*mvif)); 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); + mt76_wcid_init(&mvif->group_wcid, 0); mtxq = (struct mt76_txq *)vif->txq->drv_priv; rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid); mtxq->wcid = MT_VIF_WCID(idx); } int mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x02_dev *dev = hw->priv; unsigned int idx = 0; /* Allow to change address in HW if we create first interface. */ if (!dev->mt76.vif_mask && (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) || memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1))) mt76x02_mac_setaddr(dev, vif->addr); if (vif->addr[0] & BIT(1)) idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7); /* * Client mode typically only has one configurable BSSID register, * which is used for bssidx=0. This is linked to the MAC address. * Since mac80211 allows changing interface types, and we cannot * force the use of the primary MAC address for a station mode * interface, we need some other way of configuring a per-interface * remote BSSID. * The hardware provides an AP-Client feature, where bssidx 0-7 are * used for AP mode and bssidx 8-15 for client mode. * We shift the station interface bss index by 8 to force the * hardware to recognize the BSSID. * The resulting bssidx mismatch for unicast frames is ignored by hw. */ if (vif->type == NL80211_IFTYPE_STATION) idx += 8; /* vif is already set or idx is 8 for AP/Mesh/... */ if (dev->mt76.vif_mask & BIT_ULL(idx) || (vif->type != NL80211_IFTYPE_STATION && idx > 7)) return -EBUSY; dev->mt76.vif_mask |= BIT_ULL(idx); mt76x02_vif_init(dev, vif, idx); return 0; } EXPORT_SYMBOL_GPL(mt76x02_add_interface); void mt76x02_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x02_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx); rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL); - mt76_packet_id_flush(&dev->mt76, &mvif->group_wcid); + mt76_wcid_cleanup(&dev->mt76, &mvif->group_wcid); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct ieee80211_sta *sta = params->sta; struct mt76x02_dev *dev = hw->priv; struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mutex_unlock(&dev->mt76.mutex); return ret; } EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mt76x02_dev *dev = hw->priv; struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76x02_sta *msta; struct mt76_wcid *wcid; int idx = key->keyidx; int ret; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: break; default: return -EOPNOTSUPP; } /* * The hardware does not support per-STA RX GTK, fall back * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* * In USB AP mode, broadcast/multicast frames are setup in beacon * data registers and sent via HW beacons engine, they require to * be already encrypted. */ if (mt76_is_usb(&dev->mt76) && vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* MT76x0 GTK offloading does not work with more than one VIF */ if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; wcid = msta ? &msta->wcid : &mvif->group_wcid; if (cmd != SET_KEY) { if (idx == wcid->hw_key_idx) { wcid->hw_key_idx = -1; wcid->sw_iv = false; } return 0; } key->hw_key_idx = wcid->idx; wcid->hw_key_idx = idx; if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; wcid->sw_iv = true; } mt76_wcid_key_setup(&dev->mt76, wcid, key); if (!msta) { if (key || wcid->hw_key_idx == idx) { ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key); if (ret) return ret; } return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key); } return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key); } EXPORT_SYMBOL_GPL(mt76x02_set_key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt76x02_dev *dev = hw->priv; u8 cw_min = 5, cw_max = 10, qid; u32 val; qid = dev->mphy.q_tx[queue]->hw_idx; if (params->cw_min) cw_min = fls(params->cw_min); if (params->cw_max) cw_max = fls(params->cw_max); val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); val = mt76_rr(dev, MT_WMM_TXOP(qid)); val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); val |= params->txop << MT_WMM_TXOP_SHIFT(qid); mt76_wr(dev, MT_WMM_TXOP(qid), val); val = mt76_rr(dev, MT_WMM_AIFSN); val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); mt76_wr(dev, MT_WMM_AIFSN, val); val = mt76_rr(dev, MT_WMM_CWMIN); val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); mt76_wr(dev, MT_WMM_CWMIN, val); val = mt76_rr(dev, MT_WMM_CWMAX); val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); mt76_wr(dev, MT_WMM_CWMAX, val); return 0; } EXPORT_SYMBOL_GPL(mt76x02_conf_tx); void mt76x02_set_tx_ackto(struct mt76x02_dev *dev) { u8 ackto, sifs, slottime = dev->slottime; /* As defined by IEEE 802.11-2007 17.3.8.6 */ slottime += 3 * dev->coverage_class; mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS); ackto = slottime + sifs; mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, MT_TX_TIMEOUT_CFG_ACKTO, ackto); } EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); void mt76x02_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); dev->coverage_class = max_t(s16, coverage_class, 0); mt76x02_set_tx_ackto(dev); mutex_unlock(&dev->mt76.mutex); } EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt76x02_dev *dev = hw->priv; if (val != ~0 && val > 0xffff) return -EINVAL; mutex_lock(&dev->mt76.mutex); mt76x02_mac_set_rts_thresh(dev, val); mutex_unlock(&dev->mt76.mutex); return 0; } EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold); void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt76x02_dev *dev = hw->priv; struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); struct ieee80211_tx_rate rate = {}; if (!rates) return; rate.idx = rates->rate[0].idx; rate.flags = rates->rate[0].flags; mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate); } EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) { int hdrlen; if (!len) return; hdrlen = ieee80211_get_hdrlen_from_skb(skb); memmove(skb->data + len, skb->data, hdrlen); skb_pull(skb, len); } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_SCANNING, &dev->mphy.state); if (dev->cal.gain_init_done) { /* Restore AGC gain and resume calibration after scanning. */ dev->cal.low_gain = -1; ieee80211_queue_delayed_work(hw, &dev->cal_work, 0); } } EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete); void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mphy, sta, true); if (mt76_is_mmio(mdev)) mt76x02_mac_wcid_set_drop(dev, idx, ps); } EXPORT_SYMBOL_GPL(mt76x02_sta_ps); void mt76x02_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); if (changed & BSS_CHANGED_BSSID) mt76x02_mac_set_bssid(dev, mvif->idx, info->bssid); if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) mt76x02_mac_set_tx_protection(dev, info->use_cts_prot, info->ht_operation_mode); if (changed & BSS_CHANGED_BEACON_INT) { mt76_rmw_field(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_INTVAL, info->beacon_int << 4); dev->mt76.beacon_int = info->beacon_int; } if (changed & BSS_CHANGED_BEACON_ENABLED) mt76x02_mac_set_beacon_enable(dev, vif, info->enable_beacon); if (changed & BSS_CHANGED_ERP_PREAMBLE) mt76x02_mac_set_short_preamble(dev, info->use_short_preamble); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; dev->slottime = slottime; mt76x02_set_tx_ackto(dev); } mutex_unlock(&dev->mt76.mutex); } EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed); void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; int i; for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { u8 *addr = dev->macaddr_list[i].addr; memcpy(addr, dev->mphy.macaddr, ETH_ALEN); if (!i) continue; addr[0] |= BIT(1); addr[0] ^= ((i - 1) << 2); } wiphy->addresses = dev->macaddr_list; wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); } EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list); +MODULE_DESCRIPTION("MediaTek MT76x02 helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.c b/sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.c index d5809408d1d3..156b16c17b2b 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.c @@ -1,500 +1,510 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #include -#include +#include #include "mt76x2.h" #include "eeprom.h" #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 static int mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev) { void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; memcpy(dev->mphy.macaddr, src, ETH_ALEN); return 0; } static bool mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) { u16 *efuse_w = (u16 *)efuse; if (efuse_w[MT_EE_NIC_CONF_0] != 0) return false; if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) return false; if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) return false; if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) return false; if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) return false; if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) return false; return true; } static void mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) { #define GROUP_5G(_id) \ MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 static const u8 cal_free_bytes[] = { MT_EE_XTAL_TRIM_1, MT_EE_TX_POWER_EXT_PA_5G + 1, MT_EE_TX_POWER_0_START_2G, MT_EE_TX_POWER_0_START_2G + 1, MT_EE_TX_POWER_1_START_2G, MT_EE_TX_POWER_1_START_2G + 1, GROUP_5G(0), GROUP_5G(1), GROUP_5G(2), GROUP_5G(3), GROUP_5G(4), GROUP_5G(5), MT_EE_RF_2G_TSSI_OFF_TXPOWER, MT_EE_RF_2G_RX_HIGH_GAIN + 1, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, }; struct device_node *np = dev->mt76.dev->of_node; u8 *eeprom = dev->mt76.eeprom.data; u8 prev_grp0[4] = { eeprom[MT_EE_TX_POWER_0_START_5G], eeprom[MT_EE_TX_POWER_0_START_5G + 1], eeprom[MT_EE_TX_POWER_1_START_5G], eeprom[MT_EE_TX_POWER_1_START_5G + 1] }; u16 val; int i; if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) return; if (!mt76x2_has_cal_free_data(dev, efuse)) return; for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { int offset = cal_free_bytes[i]; eeprom[offset] = efuse[offset]; } if (!(efuse[MT_EE_TX_POWER_0_START_5G] | efuse[MT_EE_TX_POWER_0_START_5G + 1])) memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); if (!(efuse[MT_EE_TX_POWER_1_START_5G] | efuse[MT_EE_TX_POWER_1_START_5G + 1])) memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); if (val != 0xffff) eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); if (val != 0xffff) eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); if (val != 0xffff) eeprom[MT_EE_BT_PMUCFG] = val & 0xff; } static int mt76x2_check_eeprom(struct mt76x02_dev *dev) { u16 val = get_unaligned_le16(dev->mt76.eeprom.data); if (!val) val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); switch (val) { case 0x7662: case 0x7612: return 0; default: dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); return -EINVAL; } } static int mt76x2_eeprom_load(struct mt76x02_dev *dev) { void *efuse; bool found; int ret; ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); if (ret < 0) return ret; found = ret; if (found) found = !mt76x2_check_eeprom(dev); dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, GFP_KERNEL); dev->mt76.otp.size = MT7662_EEPROM_SIZE; if (!dev->mt76.otp.data) return -ENOMEM; efuse = dev->mt76.otp.data; if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE, MT_EE_READ)) goto out; if (found) { mt76x2_apply_cal_free_data(dev, efuse); } else { /* FIXME: check if efuse data is complete */ found = true; memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); } out: if (!found) return -ENOENT; return 0; } static void mt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val) { s8 *dest = dev->cal.rx.high_gain; if (!mt76x02_field_valid(val)) { dest[0] = 0; dest[1] = 0; return; } dest[0] = mt76x02_sign_extend(val, 4); dest[1] = mt76x02_sign_extend(val >> 4, 4); } static void mt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val) { s8 *dest = dev->cal.rx.rssi_offset; if (!mt76x02_field_valid(val)) { dest[chain] = 0; return; } dest[chain] = mt76x02_sign_extend_optional(val, 7); } static enum mt76x2_cal_channel_group mt76x2_get_cal_channel_group(int channel) { if (channel >= 184 && channel <= 196) return MT_CH_5G_JAPAN; if (channel <= 48) return MT_CH_5G_UNII_1; if (channel <= 64) return MT_CH_5G_UNII_2; if (channel <= 114) return MT_CH_5G_UNII_2E_1; if (channel <= 144) return MT_CH_5G_UNII_2E_2; return MT_CH_5G_UNII_3; } static u8 mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel) { enum mt76x2_cal_channel_group group; group = mt76x2_get_cal_channel_group(channel); switch (group) { case MT_CH_5G_JAPAN: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); case MT_CH_5G_UNII_1: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); case MT_CH_5G_UNII_2E_1: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; case MT_CH_5G_UNII_2E_2: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); default: return mt76x02_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; } } void mt76x2_read_rx_gain(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mphy.chandef.chan; int channel = chan->hw_value; s8 lna_5g[3], lna_2g; - u8 lna; + bool use_lna; + u8 lna = 0; u16 val; if (chan->band == NL80211_BAND_2GHZ) val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; else val = mt76x2_get_5g_rx_gain(dev, channel); mt76x2_set_rx_gain_group(dev, val); mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g); mt76x2_set_rssi_offset(dev, 0, val); mt76x2_set_rssi_offset(dev, 1, val >> 8); dev->cal.rx.mcu_gain = (lna_2g & 0xff); dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; - lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); + val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); + if (chan->band == NL80211_BAND_2GHZ) + use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_2G); + else + use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_5G); + + if (use_lna) + lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); + dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); } EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76x02_rate_power *t, struct ieee80211_channel *chan) { bool is_5ghz; u16 val; is_5ghz = chan->band == NL80211_BAND_5GHZ; memset(t, 0, sizeof(*t)); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK); t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); else val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); if (is_5ghz) val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); else val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); if (!is_5ghz) val >>= 8; t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val >> 8); } EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); static void mt76x2_get_power_info_2g(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan, int chain, int offset) { int channel = chan->hw_value; int delta_idx; u8 data[6]; u16 val; if (channel < 6) delta_idx = 3; else if (channel < 11) delta_idx = 4; else delta_idx = 5; mt76x02_eeprom_copy(dev, offset, data, sizeof(data)); t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); t->target_power = val >> 8; } static void mt76x2_get_power_info_5g(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan, int chain, int offset) { int channel = chan->hw_value; enum mt76x2_cal_channel_group group; int delta_idx; u16 val; u8 data[5]; group = mt76x2_get_cal_channel_group(channel); offset += group * MT_TX_POWER_GROUP_SIZE_5G; if (channel >= 192) delta_idx = 4; else if (channel >= 184) delta_idx = 3; else if (channel < 44) delta_idx = 3; else if (channel < 52) delta_idx = 4; else if (channel < 58) delta_idx = 3; else if (channel < 98) delta_idx = 4; else if (channel < 106) delta_idx = 3; else if (channel < 116) delta_idx = 4; else if (channel < 130) delta_idx = 3; else if (channel < 149) delta_idx = 4; else if (channel < 157) delta_idx = 3; else delta_idx = 4; mt76x02_eeprom_copy(dev, offset, data, sizeof(data)); t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); t->target_power = val & 0xff; } void mt76x2_get_power_info(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, struct ieee80211_channel *chan) { u16 bw40, bw80; memset(t, 0, sizeof(*t)); bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); if (chan->band == NL80211_BAND_5GHZ) { bw40 >>= 8; mt76x2_get_power_info_5g(dev, t, chan, 0, MT_EE_TX_POWER_0_START_5G); mt76x2_get_power_info_5g(dev, t, chan, 1, MT_EE_TX_POWER_1_START_5G); } else { mt76x2_get_power_info_2g(dev, t, chan, 0, MT_EE_TX_POWER_0_START_2G); mt76x2_get_power_info_2g(dev, t, chan, 1, MT_EE_TX_POWER_1_START_2G); } if (mt76x2_tssi_enabled(dev) || !mt76x02_field_valid(t->target_power)) t->target_power = t->chain[0].target_power; t->delta_bw40 = mt76x02_rate_power_val(bw40); t->delta_bw80 = mt76x02_rate_power_val(bw80); } EXPORT_SYMBOL_GPL(mt76x2_get_power_info); int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t) { enum nl80211_band band = dev->mphy.chandef.chan->band; u16 val, slope; u8 bounds; memset(t, 0, sizeof(*t)); if (!mt76x2_temp_tx_alc_enabled(dev)) return -EINVAL; if (!mt76x02_ext_pa_enabled(dev, band)) return -EINVAL; val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; t->temp_25_ref = val & 0x7f; if (band == NL80211_BAND_5GHZ) { slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); } else { slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; } t->high_slope = slope & 0xff; t->low_slope = slope >> 8; t->lower_bound = 0 - (bounds & 0xf); t->upper_bound = (bounds >> 4) & 0xf; return 0; } EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); int mt76x2_eeprom_init(struct mt76x02_dev *dev) { int ret; ret = mt76x2_eeprom_load(dev); if (ret) return ret; mt76x02_eeprom_parse_hw_cap(dev); mt76x2_eeprom_get_macaddr(dev); mt76_eeprom_override(&dev->mphy); dev->mphy.macaddr[0] &= ~BIT(1); return 0; } EXPORT_SYMBOL_GPL(mt76x2_eeprom_init); +MODULE_DESCRIPTION("MediaTek MT76x2 EEPROM helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2.h b/sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2.h index be1217329a77..f051721bb00e 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2.h +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2.h @@ -1,80 +1,82 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau */ #ifndef __MT76x2_H #define __MT76x2_H #include #include #include #include #include #include #include #include #include #define MT7662_FIRMWARE "mt7662.bin" #define MT7662_ROM_PATCH "mt7662_rom_patch.bin" #define MT7662_EEPROM_SIZE 512 #include "../mt76x02.h" #include "mac.h" static inline bool is_mt7612(struct mt76x02_dev *dev) { return mt76_chip(&dev->mt76) == 0x7612; } static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mphy.chandef.chan; return ((chan->flags & IEEE80211_CHAN_RADAR) && chan->dfs_state != NL80211_DFS_AVAILABLE); } extern const struct ieee80211_ops mt76x2_ops; int mt76x2_register_device(struct mt76x02_dev *dev); int mt76x2_resume_device(struct mt76x02_dev *dev); int mt76x2_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); void mt76x2_phy_power_on(struct mt76x02_dev *dev); void mt76x2_stop_hardware(struct mt76x02_dev *dev); int mt76x2_eeprom_init(struct mt76x02_dev *dev); int mt76x2_apply_calibration_data(struct mt76x02_dev *dev, int channel); +int mt76x2e_set_channel(struct mt76_phy *phy); +int mt76x2u_set_channel(struct mt76_phy *phy); void mt76x2_phy_set_antenna(struct mt76x02_dev *dev); int mt76x2_phy_start(struct mt76x02_dev *dev); int mt76x2_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x2_phy_calibrate(struct work_struct *work); void mt76x2_phy_set_txpower(struct mt76x02_dev *dev); int mt76x2_mcu_init(struct mt76x02_dev *dev); int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw, u8 bw_index, bool scan); int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level, u8 channel); void mt76x2_cleanup(struct mt76x02_dev *dev); int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard); void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable); void mt76x2_init_txpower(struct mt76x02_dev *dev, struct ieee80211_supported_band *sband); void mt76_write_mac_initvals(struct mt76x02_dev *dev); void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev); void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band); void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw); void mt76x2_apply_gain_adj(struct mt76x02_dev *dev); void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/pci.c b/sys/contrib/dev/mediatek/mt76/mt76x2/pci.c index df85ebc6e1df..727bfdd00b40 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/pci.c @@ -1,181 +1,186 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #include #include #include "mt76x2.h" static const struct pci_device_id mt76x2e_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7662) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7612) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7602) }, { }, }; static int mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, + .set_channel = mt76x2e_set_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, .rx_skb = mt76x02_queue_rx_skb, .rx_poll_complete = mt76x02_rx_poll_complete, .sta_ps = mt76x02_sta_ps, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, }; struct mt76x02_dev *dev; struct mt76_dev *mdev; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_set_master(pdev); ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x2_ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_mmio_init(mdev, pcim_iomap_table(pdev)[0]); mt76x2_reset_wlan(dev, false); mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); mt76_wr(dev, MT_INT_MASK_CSR, 0); ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto error; ret = mt76x2_register_device(dev); if (ret) goto error; /* Fix up ASPM configuration */ /* RG_SSUSB_G1_CDR_BIR_LTR = 0x9 */ mt76_rmw_field(dev, 0x15a10, 0x1f << 16, 0x9); /* RG_SSUSB_G1_CDR_BIC_LTR = 0xf */ mt76_rmw_field(dev, 0x15a0c, 0xfU << 28, 0xf); /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); mt76_pci_disable_aspm(pdev); return 0; error: mt76_free_device(&dev->mt76); return ret; } static void mt76x2e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); mt76_unregister_device(mdev); mt76x2_cleanup(dev); mt76_free_device(mdev); } static int __maybe_unused mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state) { struct mt76_dev *mdev = pci_get_drvdata(pdev); int i, err; napi_disable(&mdev->tx_napi); tasklet_kill(&mdev->pre_tbtt_tasklet); mt76_worker_disable(&mdev->tx_worker); mt76_for_each_q_rx(mdev, i) napi_disable(&mdev->napi[i]); pci_enable_wake(pdev, pci_choose_state(pdev, state), true); pci_save_state(pdev); err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); if (err) goto restore; return 0; restore: mt76_for_each_q_rx(mdev, i) napi_enable(&mdev->napi[i]); napi_enable(&mdev->tx_napi); return err; } static int __maybe_unused mt76x2e_resume(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); int i, err; err = pci_set_power_state(pdev, PCI_D0); if (err) return err; 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); + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + napi_schedule(&mdev->napi[i]); + } napi_schedule(&mdev->tx_napi); local_bh_enable(); return mt76x2_resume_device(dev); } MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); +MODULE_DESCRIPTION("MediaTek MT76x2E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76pci_driver = { .name = KBUILD_MODNAME, .id_table = mt76x2e_device_table, .probe = mt76x2e_probe, .remove = mt76x2e_remove, #ifdef CONFIG_PM .suspend = mt76x2e_suspend, .resume = mt76x2e_resume, #endif /* CONFIG_PM */ }; module_pci_driver(mt76pci_driver); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/pci_main.c b/sys/contrib/dev/mediatek/mt76/mt76x2/pci_main.c index b38bb7a2362b..eb70130d2711 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/pci_main.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/pci_main.c @@ -1,164 +1,157 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include "mt76x2.h" #include "../mt76x02_mac.h" static int mt76x2_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; mt76x02_mac_start(dev); mt76x2_phy_start(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->wdt_work, MT_WATCHDOG_TIME); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); return 0; } static void -mt76x2_stop(struct ieee80211_hw *hw) +mt76x2_stop(struct ieee80211_hw *hw, bool suspend) { struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); mt76x2_stop_hardware(dev); } -static void -mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) +int mt76x2e_set_channel(struct mt76_phy *phy) { - cancel_delayed_work_sync(&dev->cal_work); + struct mt76x02_dev *dev = container_of(phy->dev, struct mt76x02_dev, mt76); + tasklet_disable(&dev->mt76.pre_tbtt_tasklet); tasklet_disable(&dev->dfs_pd.dfs_tasklet); - mutex_lock(&dev->mt76.mutex); - set_bit(MT76_RESET, &dev->mphy.state); - - mt76_set_channel(&dev->mphy); - mt76x2_mac_stop(dev, true); - mt76x2_phy_set_channel(dev, chandef); + mt76x2_phy_set_channel(dev, &phy->chandef); mt76x02_mac_cc_reset(dev); mt76x02_dfs_init_params(dev); mt76x2_mac_resume(dev); - clear_bit(MT76_RESET, &dev->mphy.state); - mutex_unlock(&dev->mt76.mutex); - tasklet_enable(&dev->dfs_pd.dfs_tasklet); tasklet_enable(&dev->mt76.pre_tbtt_tasklet); - mt76_txq_schedule_all(&dev->mphy); + return 0; } static int mt76x2_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x02_dev *dev = hw->priv; mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; else dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); } if (changed & IEEE80211_CONF_CHANGE_POWER) { struct mt76_phy *mphy = &dev->mphy; dev->txpower_conf = hw->conf.power_level * 2; dev->txpower_conf = mt76_get_sar_power(mphy, mphy->chandef.chan, dev->txpower_conf); /* convert to per-chain power for 2x2 devices */ dev->txpower_conf -= 6; if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { mt76x2_phy_set_txpower(dev); mt76x02_tx_set_txpwr_auto(dev, dev->txpower_conf); } } mutex_unlock(&dev->mt76.mutex); - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - mt76x2_set_channel(dev, &hw->conf.chandef); - ieee80211_wake_queues(hw); - } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) + mt76_update_channel(&dev->mphy); return 0; } static void mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { } static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt76x02_dev *dev = hw->priv; if (!tx_ant || tx_ant > 3 || tx_ant != rx_ant) return -EINVAL; mutex_lock(&dev->mt76.mutex); dev->mphy.chainmask = (tx_ant == 3) ? 0x202 : 0x101; dev->mphy.antenna_mask = tx_ant; mt76_set_stream_caps(&dev->mphy, true); mt76x2_phy_set_antenna(dev); mutex_unlock(&dev->mt76.mutex); return 0; } const struct ieee80211_ops mt76x2_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x2_start, .stop = mt76x2_stop, .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .config = mt76x2_config, .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .flush = mt76x2_flush, .ampdu_action = mt76x02_ampdu_action, .get_txpower = mt76_get_txpower, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x02_set_coverage_class, .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .set_antenna = mt76x2_set_antenna, .get_antenna = mt76_get_antenna, .set_rts_threshold = mt76x02_set_rts_threshold, .reconfig_complete = mt76x02_reconfig_complete, .set_sar_specs = mt76x2_set_sar_specs, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/phy.c b/sys/contrib/dev/mediatek/mt76/mt76x2/phy.c index f84517d932dc..e2b4cf30dc44 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/phy.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/phy.c @@ -1,349 +1,349 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau * Copyright (C) 2018 Lorenzo Bianconi */ #include "mt76x2.h" #include "eeprom.h" #include "mcu.h" #include "../mt76x02_phy.h" static void mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset) { s8 gain; gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); gain -= offset / 2; mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); } static void mt76x2_adjust_agc_gain(struct mt76x02_dev *dev, int reg, s8 offset) { s8 gain; gain = FIELD_GET(MT_BBP_AGC_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); gain += offset; mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_GAIN, gain); } void mt76x2_apply_gain_adj(struct mt76x02_dev *dev) { s8 *gain_adj = dev->cal.rx.high_gain; mt76x2_adjust_high_lna_gain(dev, 4, gain_adj[0]); mt76x2_adjust_high_lna_gain(dev, 5, gain_adj[1]); mt76x2_adjust_agc_gain(dev, 8, gain_adj[0]); mt76x2_adjust_agc_gain(dev, 9, gain_adj[1]); } EXPORT_SYMBOL_GPL(mt76x2_apply_gain_adj); void mt76x2_phy_set_txpower_regs(struct mt76x02_dev *dev, enum nl80211_band band) { u32 pa_mode[2]; u32 pa_mode_adj; if (band == NL80211_BAND_2GHZ) { pa_mode[0] = 0x010055ff; pa_mode[1] = 0x00550055; mt76_wr(dev, MT_TX_ALC_CFG_2, 0x35160a00); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x35160a06); if (mt76x02_ext_pa_enabled(dev, band)) { mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0x0000ec00); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0x0000ec00); } else { mt76_wr(dev, MT_RF_PA_MODE_ADJ0, 0xf4000200); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, 0xfa000200); } } else { pa_mode[0] = 0x0000ffff; pa_mode[1] = 0x00ff00ff; if (mt76x02_ext_pa_enabled(dev, band)) { mt76_wr(dev, MT_TX_ALC_CFG_2, 0x2f0f0400); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x2f0f0476); } else { mt76_wr(dev, MT_TX_ALC_CFG_2, 0x1b0f0400); mt76_wr(dev, MT_TX_ALC_CFG_3, 0x1b0f0476); } if (mt76x02_ext_pa_enabled(dev, band)) pa_mode_adj = 0x04000000; else pa_mode_adj = 0; mt76_wr(dev, MT_RF_PA_MODE_ADJ0, pa_mode_adj); mt76_wr(dev, MT_RF_PA_MODE_ADJ1, pa_mode_adj); } mt76_wr(dev, MT_BB_PA_MODE_CFG0, pa_mode[0]); mt76_wr(dev, MT_BB_PA_MODE_CFG1, pa_mode[1]); mt76_wr(dev, MT_RF_PA_MODE_CFG0, pa_mode[0]); mt76_wr(dev, MT_RF_PA_MODE_CFG1, pa_mode[1]); if (mt76x02_ext_pa_enabled(dev, band)) { u32 val; if (band == NL80211_BAND_2GHZ) val = 0x3c3c023c; else val = 0x363c023c; mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00001818); } else { if (band == NL80211_BAND_2GHZ) { u32 val = 0x0f3c3c3c; mt76_wr(dev, MT_TX0_RF_GAIN_CORR, val); mt76_wr(dev, MT_TX1_RF_GAIN_CORR, val); mt76_wr(dev, MT_TX_ALC_CFG_4, 0x00000606); } else { mt76_wr(dev, MT_TX0_RF_GAIN_CORR, 0x383c023c); mt76_wr(dev, MT_TX1_RF_GAIN_CORR, 0x24282e28); mt76_wr(dev, MT_TX_ALC_CFG_4, 0); } } } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower_regs); static int mt76x2_get_min_rate_power(struct mt76x02_rate_power *r) { int i; s8 ret = 0; for (i = 0; i < sizeof(r->all); i++) { if (!r->all[i]) continue; if (ret) ret = min(ret, r->all[i]); else ret = r->all[i]; } return ret; } void mt76x2_phy_set_txpower(struct mt76x02_dev *dev) { enum nl80211_chan_width width = dev->mphy.chandef.width; struct ieee80211_channel *chan = dev->mphy.chandef.chan; struct mt76x2_tx_power_info txp; int txp_0, txp_1, delta = 0; struct mt76x02_rate_power t = {}; int base_power, gain; mt76x2_get_power_info(dev, &txp, chan); if (width == NL80211_CHAN_WIDTH_40) delta = txp.delta_bw40; else if (width == NL80211_CHAN_WIDTH_80) delta = txp.delta_bw80; mt76x2_get_rate_power(dev, &t, chan); mt76x02_add_rate_power_offset(&t, txp.target_power + delta); mt76x02_limit_rate_power(&t, dev->txpower_conf); dev->mphy.txpower_cur = mt76x02_get_max_rate_power(&t); base_power = mt76x2_get_min_rate_power(&t); delta = base_power - txp.target_power; txp_0 = txp.chain[0].target_power + txp.chain[0].delta + delta; txp_1 = txp.chain[1].target_power + txp.chain[1].delta + delta; gain = min(txp_0, txp_1); if (gain < 0) { base_power -= gain; txp_0 -= gain; txp_1 -= gain; } else if (gain > 0x2f) { base_power -= gain - 0x2f; txp_0 = 0x2f; txp_1 = 0x2f; } mt76x02_add_rate_power_offset(&t, -base_power); dev->target_power = txp.target_power; dev->target_power_delta[0] = txp_0 - txp.chain[0].target_power; dev->target_power_delta[1] = txp_1 - txp.chain[0].target_power; dev->rate_power = t; mt76x02_phy_set_txpower(dev, txp_0, txp_1); } EXPORT_SYMBOL_GPL(mt76x2_phy_set_txpower); void mt76x2_configure_tx_delay(struct mt76x02_dev *dev, enum nl80211_band band, u8 bw) { u32 cfg0, cfg1; if (mt76x02_ext_pa_enabled(dev, band)) { cfg0 = bw ? 0x000b0c01 : 0x00101101; cfg1 = 0x00011414; } else { cfg0 = bw ? 0x000b0b01 : 0x00101001; cfg1 = 0x00021414; } mt76_wr(dev, MT_TX_SW_CFG0, cfg0); mt76_wr(dev, MT_TX_SW_CFG1, cfg1); mt76_rmw_field(dev, MT_XIFS_TIME_CFG, MT_XIFS_TIME_CFG_OFDM_SIFS, 15); } EXPORT_SYMBOL_GPL(mt76x2_configure_tx_delay); void mt76x2_phy_tssi_compensate(struct mt76x02_dev *dev) { struct ieee80211_channel *chan = dev->mphy.chandef.chan; struct mt76x2_tx_power_info txp; struct mt76x2_tssi_comp t = {}; if (!dev->cal.tssi_cal_done) return; if (!dev->cal.tssi_comp_pending) { /* TSSI trigger */ t.cal_mode = BIT(0); mt76x2_mcu_tssi_comp(dev, &t); dev->cal.tssi_comp_pending = true; } else { if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4)) return; dev->cal.tssi_comp_pending = false; mt76x2_get_power_info(dev, &txp, chan); if (mt76x02_ext_pa_enabled(dev, chan->band)) t.pa_mode = 1; t.cal_mode = BIT(1); t.slope0 = txp.chain[0].tssi_slope; t.offset0 = txp.chain[0].tssi_offset; t.slope1 = txp.chain[1].tssi_slope; t.offset1 = txp.chain[1].tssi_offset; mt76x2_mcu_tssi_comp(dev, &t); if (t.pa_mode || dev->cal.dpd_cal_done || dev->ed_tx_blocked) return; usleep_range(10000, 20000); mt76x02_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value); dev->cal.dpd_cal_done = true; } } EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate); static void mt76x2_phy_set_gain_val(struct mt76x02_dev *dev) { u32 val; u8 gain_val[2]; gain_val[0] = dev->cal.agc_gain_cur[0] - dev->cal.agc_gain_adjust; gain_val[1] = dev->cal.agc_gain_cur[1] - dev->cal.agc_gain_adjust; val = 0x1836 << 16; if (!mt76x2_has_ext_lna(dev) && dev->mphy.chandef.width >= NL80211_CHAN_WIDTH_40) val = 0x1e42 << 16; if (mt76x2_has_ext_lna(dev) && dev->mphy.chandef.chan->band == NL80211_BAND_2GHZ && dev->mphy.chandef.width < NL80211_CHAN_WIDTH_40) val = 0x0f36 << 16; val |= 0xf8; mt76_wr(dev, MT_BBP(AGC, 8), val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[0])); mt76_wr(dev, MT_BBP(AGC, 9), val | FIELD_PREP(MT_BBP_AGC_GAIN, gain_val[1])); if (dev->mphy.chandef.chan->flags & IEEE80211_CHAN_RADAR) mt76x02_phy_dfs_adjust_agc(dev); } void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) { u8 *gain = dev->cal.agc_gain_init; u8 low_gain_delta, gain_delta; u32 agc_35, agc_37; bool gain_change; int low_gain; u32 val; - dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76, false); + dev->cal.avg_rssi_all = mt76_get_min_avg_rssi(&dev->mt76, 0); if (!dev->cal.avg_rssi_all) dev->cal.avg_rssi_all = -75; low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); gain_change = dev->cal.low_gain < 0 || (dev->cal.low_gain & 2) ^ (low_gain & 2); dev->cal.low_gain = low_gain; if (!gain_change) { if (mt76x02_phy_adjust_vga_gain(dev)) mt76x2_phy_set_gain_val(dev); return; } if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_80) { mt76_wr(dev, MT_BBP(RXO, 14), 0x00560211); val = mt76_rr(dev, MT_BBP(AGC, 26)) & ~0xf; if (low_gain == 2) val |= 0x3; else val |= 0x5; mt76_wr(dev, MT_BBP(AGC, 26), val); } else { mt76_wr(dev, MT_BBP(RXO, 14), 0x00560423); } if (mt76x2_has_ext_lna(dev)) low_gain_delta = 10; else low_gain_delta = 14; agc_37 = 0x2121262c; if (dev->mphy.chandef.chan->band == NL80211_BAND_2GHZ) agc_35 = 0x11111516; else if (low_gain == 2) agc_35 = agc_37 = 0x08080808; else if (dev->mphy.chandef.width == NL80211_CHAN_WIDTH_80) agc_35 = 0x10101014; else agc_35 = 0x11111116; if (low_gain == 2) { mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a990); mt76_wr(dev, MT_BBP(AGC, 35), 0x08080808); mt76_wr(dev, MT_BBP(AGC, 37), 0x08080808); gain_delta = low_gain_delta; dev->cal.agc_gain_adjust = 0; } else { mt76_wr(dev, MT_BBP(RXO, 18), 0xf000a991); gain_delta = 0; dev->cal.agc_gain_adjust = low_gain_delta; } mt76_wr(dev, MT_BBP(AGC, 35), agc_35); mt76_wr(dev, MT_BBP(AGC, 37), agc_37); dev->cal.agc_gain_cur[0] = gain[0] - gain_delta; dev->cal.agc_gain_cur[1] = gain[1] - gain_delta; mt76x2_phy_set_gain_val(dev); /* clear false CCA counters */ mt76_rr(dev, MT_RX_STAT_1); } EXPORT_SYMBOL_GPL(mt76x2_phy_update_channel_gain); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/usb.c b/sys/contrib/dev/mediatek/mt76/mt76x2/usb.c index 55068f3252ef..e832ad53e239 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/usb.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/usb.c @@ -1,150 +1,153 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi */ #include #include #include "../mt76x02_usb.h" #include "mt76x2u.h" static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ + { USB_DEVICE(0x0846, 0x9014) }, /* Netgear WNDA3100v3 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ { }, }; static int mt76x2u_probe(struct usb_interface *intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { .drv_flags = MT_DRV_SW_RX_AIRTIME, .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, + .set_channel = mt76x2u_set_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, .tx_status_data = mt76x02_tx_status_data, .rx_skb = mt76x02_queue_rx_skb, .sta_ps = mt76x02_sta_ps, .sta_add = mt76x02_sta_add, .sta_remove = mt76x02_sta_remove, }; struct usb_device *udev = interface_to_usbdev(intf); struct mt76x02_dev *dev; struct mt76_dev *mdev; int err; mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt76x02_dev, mt76); udev = usb_get_dev(udev); usb_reset_device(udev); usb_set_intfdata(intf, dev); mt76x02u_init_mcu(mdev); err = mt76u_init(mdev, intf); if (err < 0) goto err; mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); if (!is_mt76x2(dev)) { err = -ENODEV; goto err; } err = mt76x2u_register_device(dev); if (err < 0) goto err; return 0; err: mt76u_queues_deinit(&dev->mt76); mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); return err; } static void mt76x2u_disconnect(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); struct mt76x02_dev *dev = usb_get_intfdata(intf); struct ieee80211_hw *hw = mt76_hw(dev); set_bit(MT76_REMOVED, &dev->mphy.state); ieee80211_unregister_hw(hw); mt76x2u_cleanup(dev); mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); } static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, pm_message_t state) { struct mt76x02_dev *dev = usb_get_intfdata(intf); mt76u_stop_rx(&dev->mt76); return 0; } static int __maybe_unused mt76x2u_resume(struct usb_interface *intf) { struct mt76x02_dev *dev = usb_get_intfdata(intf); int err; err = mt76u_resume_rx(&dev->mt76); if (err < 0) goto err; err = mt76x2u_init_hardware(dev); if (err < 0) goto err; return 0; err: mt76x2u_cleanup(dev); return err; } MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); static struct usb_driver mt76x2u_driver = { .name = KBUILD_MODNAME, .id_table = mt76x2u_device_table, .probe = mt76x2u_probe, .disconnect = mt76x2u_disconnect, #ifdef CONFIG_PM .suspend = mt76x2u_suspend, .resume = mt76x2u_resume, .reset_resume = mt76x2u_resume, #endif /* CONFIG_PM */ .soft_unbind = 1, .disable_hub_initiated_lpm = 1, }; module_usb_driver(mt76x2u_driver); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT76x2U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt76x2/usb_main.c b/sys/contrib/dev/mediatek/mt76/mt76x2/usb_main.c index ac07ed1f63a3..83e7061b10e2 100644 --- a/sys/contrib/dev/mediatek/mt76/mt76x2/usb_main.c +++ b/sys/contrib/dev/mediatek/mt76/mt76x2/usb_main.c @@ -1,129 +1,118 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi */ #include "mt76x2u.h" #include "../mt76x02_usb.h" static int mt76x2u_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; int ret; ret = mt76x02u_mac_start(dev); if (ret) return ret; ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT_MAC_WORK_INTERVAL); set_bit(MT76_STATE_RUNNING, &dev->mphy.state); return 0; } -static void mt76x2u_stop(struct ieee80211_hw *hw) +static void mt76x2u_stop(struct ieee80211_hw *hw, bool suspend) { struct mt76x02_dev *dev = hw->priv; clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); mt76u_stop_tx(&dev->mt76); mt76x2u_stop_hw(dev); } -static int -mt76x2u_set_channel(struct mt76x02_dev *dev, - struct cfg80211_chan_def *chandef) +int mt76x2u_set_channel(struct mt76_phy *mphy) { + struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, mt76); int err; - cancel_delayed_work_sync(&dev->cal_work); mt76x02_pre_tbtt_enable(dev, false); - - mutex_lock(&dev->mt76.mutex); - set_bit(MT76_RESET, &dev->mphy.state); - - mt76_set_channel(&dev->mphy); - mt76x2_mac_stop(dev, false); - err = mt76x2u_phy_set_channel(dev, chandef); + err = mt76x2u_phy_set_channel(dev, &mphy->chandef); mt76x02_mac_cc_reset(dev); mt76x2_mac_resume(dev); - clear_bit(MT76_RESET, &dev->mphy.state); - mutex_unlock(&dev->mt76.mutex); - mt76x02_pre_tbtt_enable(dev, true); - mt76_txq_schedule_all(&dev->mphy); return err; } static int mt76x2u_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x02_dev *dev = hw->priv; int err = 0; mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) dev->mt76.rxfilter |= MT_RX_FILTR_CFG_PROMISC; else dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_PROMISC; mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); } if (changed & IEEE80211_CONF_CHANGE_POWER) { struct mt76_phy *mphy = &dev->mphy; dev->txpower_conf = hw->conf.power_level * 2; dev->txpower_conf = mt76_get_sar_power(mphy, mphy->chandef.chan, dev->txpower_conf); /* convert to per-chain power for 2x2 devices */ dev->txpower_conf -= 6; if (test_bit(MT76_STATE_RUNNING, &mphy->state)) mt76x2_phy_set_txpower(dev); } mutex_unlock(&dev->mt76.mutex); - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - err = mt76x2u_set_channel(dev, &hw->conf.chandef); - ieee80211_wake_queues(hw); - } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) + mt76_update_channel(&dev->mphy); return err; } const struct ieee80211_ops mt76x2u_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt76x02_tx, .start = mt76x2u_start, .stop = mt76x2u_stop, .add_interface = mt76x02_add_interface, .remove_interface = mt76x02_remove_interface, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt76x02_set_key, .ampdu_action = mt76x02_ampdu_action, .config = mt76x2u_config, .wake_tx_queue = mt76_wake_tx_queue, .bss_info_changed = mt76x02_bss_info_changed, .configure_filter = mt76x02_configure_filter, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .get_txpower = mt76_get_txpower, .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, .get_antenna = mt76_get_antenna, .set_sar_specs = mt76x2_set_sar_specs, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/Kconfig b/sys/contrib/dev/mediatek/mt76/mt7915/Kconfig index 896ec38c23d9..193112c49bd1 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/Kconfig +++ b/sys/contrib/dev/mediatek/mt76/mt7915/Kconfig @@ -1,25 +1,25 @@ # SPDX-License-Identifier: ISC config MT7915E tristate "MediaTek MT7915E (PCIe) support" select MT76_CONNAC_LIB select WANT_DEV_COREDUMP depends on MAC80211 depends on PCI select RELAY help - This adds support for MT7915-based wireless PCIe devices, + This adds support for MT7915-based PCIe wireless devices, which support concurrent dual-band operation at both 5GHz and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels, OFDMA, spatial reuse and dual carrier modulation. To compile this driver as a module, choose M here. config MT798X_WMAC bool "MT798x (SoC) WMAC support" depends on MT7915E depends on ARCH_MEDIATEK || COMPILE_TEST select REGMAP help This adds support for the built-in WMAC on MT7981 and MT7986 SoC device which has the same feature set as a MT7915, but enables 6E support. diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/debugfs.c b/sys/contrib/dev/mediatek/mt76/mt7915/debugfs.c index 6c3696c8c700..578013884e43 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/debugfs.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/debugfs.c @@ -1,1399 +1,1400 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include "mt7915.h" #include "eeprom.h" #include "mcu.h" #include "mac.h" #define FW_BIN_LOG_MAGIC 0x44e98caf /** 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) { struct mt7915_dev *dev = data; /* The existing connected stations shall reconnect to apply * new implicit txbf configuration. */ dev->ibf = !!val; return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static int mt7915_implicit_txbf_get(void *data, u64 *val) { struct mt7915_dev *dev = data; *val = dev->ibf; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get, mt7915_implicit_txbf_set, "%lld\n"); /* test knob of system error recovery */ static ssize_t mt7915_sys_recovery_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; bool band = phy->mt76->band_idx; char buf[16]; int ret = 0; u16 val; if (count >= sizeof(buf)) return -EINVAL; if (copy_from_user(buf, user_buf, count)) return -EFAULT; if (count && buf[count - 1] == '\n') buf[count - 1] = '\0'; else buf[count] = '\0'; if (kstrtou16(buf, 0, &val)) return -EINVAL; switch (val) { /* * 0: grab firmware current SER state. * 1: trigger & enable system error L1 recovery. * 2: trigger & enable system error L2 recovery. * 3: trigger & enable system error L3 rx abort. * 4: trigger & enable system error L3 tx abort * 5: trigger & enable system error L3 tx disable. * 6: trigger & enable system error L3 bf recovery. * 7: trigger & enable system error full recovery. * 8: trigger firmware crash. */ case SER_QUERY: ret = mt7915_mcu_set_ser(dev, 0, 0, band); break; case SER_SET_RECOVER_L1: case SER_SET_RECOVER_L2: case SER_SET_RECOVER_L3_RX_ABORT: case SER_SET_RECOVER_L3_TX_ABORT: case SER_SET_RECOVER_L3_TX_DISABLE: case SER_SET_RECOVER_L3_BF: ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), band); if (ret) return ret; ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, band); break; /* enable full chip reset */ case SER_SET_RECOVER_FULL: mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); ret = mt7915_mcu_set_ser(dev, 1, 3, band); if (ret) return ret; dev->recovery.state |= MT_MCU_CMD_WDT_MASK; mt7915_reset(dev); break; /* WARNING: trigger firmware crash */ case SER_SET_SYSTEM_ASSERT: mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18)); mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18)); break; default: break; } return ret ? ret : count; } static ssize_t mt7915_sys_recovery_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; char *buff; int desc = 0; ssize_t ret; static const size_t bufsz = 1024; buff = kmalloc(bufsz, GFP_KERNEL); if (!buff) return -ENOMEM; /* HELP */ desc += scnprintf(buff + desc, bufsz - desc, "Please echo the correct value ...\n"); desc += scnprintf(buff + desc, bufsz - desc, "0: grab firmware transient SER state\n"); desc += scnprintf(buff + desc, bufsz - desc, "1: trigger system error L1 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, "2: trigger system error L2 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, "3: trigger system error L3 rx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, "4: trigger system error L3 tx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, "5: trigger system error L3 tx disable\n"); desc += scnprintf(buff + desc, bufsz - desc, "6: trigger system error L3 bf recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, "7: trigger system error full recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, "8: trigger firmware crash\n"); /* SER statistics */ desc += scnprintf(buff + desc, bufsz - desc, "\nlet's dump firmware SER statistics...\n"); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_STATUS = 0x%08x\n", mt76_rr(dev, MT_SWDEF_SER_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR_1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PSE_ERR = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PSE_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PSE_ERR_1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PSE1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "\nSYS_RESET_COUNT: WM %d, WA %d\n", dev->recovery.wm_reset_count, dev->recovery.wa_reset_count); ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); return ret; } static const struct file_operations mt7915_sys_recovery_ops = { .write = mt7915_sys_recovery_set, .read = mt7915_sys_recovery_get, .open = simple_open, .llseek = default_llseek, }; static int mt7915_radar_trigger(void *data, u64 val) { struct mt7915_dev *dev = data; if (val > MT_RX_SEL2) return -EINVAL; return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE, val, 0, 0); } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, mt7915_radar_trigger, "%lld\n"); static int mt7915_muru_debug_set(void *data, u64 val) { struct mt7915_dev *dev = data; dev->muru_debug = val; mt7915_mcu_muru_debug_set(dev, dev->muru_debug); return 0; } static int mt7915_muru_debug_get(void *data, u64 *val) { struct mt7915_dev *dev = data; *val = dev->muru_debug; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_debug, mt7915_muru_debug_get, mt7915_muru_debug_set, "%lld\n"); static int mt7915_muru_stats_show(struct seq_file *file, void *data) { struct mt7915_phy *phy = file->private; struct mt7915_dev *dev = phy->dev; static const char * const dl_non_he_type[] = { "CCK", "OFDM", "HT MIX", "HT GF", "VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU" }; static const char * const dl_he_type[] = { "HE SU", "HE EXT", "HE 2MU", "HE 3MU", "HE 4MU", "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU" }; static const char * const ul_he_type[] = { "HE 2MU", "HE 3MU", "HE 4MU", "HE SU", "HE 2RU", "HE 3RU", "HE 4RU", "HE 5-8RU", "HE 9-16RU", "HE >16RU" }; int ret, i; u64 total_ppdu_cnt, sub_total_cnt; if (!dev->muru_debug) { seq_puts(file, "Please enable muru_debug first.\n"); return 0; } mutex_lock(&dev->mt76.mutex); ret = mt7915_mcu_muru_debug_get(phy); if (ret) goto exit; /* Non-HE Downlink*/ seq_puts(file, "[Non-HE]\nDownlink\nData Type: "); for (i = 0; i < 5; i++) seq_printf(file, "%8s | ", dl_non_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ", phy->mib.dl_cck_cnt, phy->mib.dl_ofdm_cnt, phy->mib.dl_htmix_cnt, phy->mib.dl_htgf_cnt, phy->mib.dl_vht_su_cnt); seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); for (i = 5; i < 8; i++) seq_printf(file, "%8s | ", dl_non_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | ", phy->mib.dl_vht_2mu_cnt, phy->mib.dl_vht_3mu_cnt, phy->mib.dl_vht_4mu_cnt); sub_total_cnt = phy->mib.dl_vht_2mu_cnt + phy->mib.dl_vht_3mu_cnt + phy->mib.dl_vht_4mu_cnt; seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld", sub_total_cnt); total_ppdu_cnt = sub_total_cnt + phy->mib.dl_cck_cnt + phy->mib.dl_ofdm_cnt + phy->mib.dl_htmix_cnt + phy->mib.dl_htgf_cnt + phy->mib.dl_vht_su_cnt; seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt); /* HE Downlink */ seq_puts(file, "\n\n[HE]\nDownlink\nData Type: "); for (i = 0; i < 2; i++) seq_printf(file, "%8s | ", dl_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | ", phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt); seq_puts(file, "\nDownlink MU-MIMO\nData Type: "); for (i = 2; i < 5; i++) seq_printf(file, "%8s | ", dl_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | ", phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt, phy->mib.dl_he_4mu_cnt); seq_puts(file, "\nDownlink OFDMA\nData Type: "); for (i = 5; i < 11; i++) seq_printf(file, "%8s | ", dl_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ", phy->mib.dl_he_2ru_cnt, phy->mib.dl_he_3ru_cnt, phy->mib.dl_he_4ru_cnt, phy->mib.dl_he_5to8ru_cnt, phy->mib.dl_he_9to16ru_cnt, phy->mib.dl_he_gtr16ru_cnt); sub_total_cnt = phy->mib.dl_he_2mu_cnt + phy->mib.dl_he_3mu_cnt + phy->mib.dl_he_4mu_cnt; total_ppdu_cnt = sub_total_cnt; seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld", sub_total_cnt); sub_total_cnt = phy->mib.dl_he_2ru_cnt + phy->mib.dl_he_3ru_cnt + phy->mib.dl_he_4ru_cnt + phy->mib.dl_he_5to8ru_cnt + phy->mib.dl_he_9to16ru_cnt + phy->mib.dl_he_gtr16ru_cnt; total_ppdu_cnt += sub_total_cnt; seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld", sub_total_cnt); total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt; seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt); /* HE Uplink */ seq_puts(file, "\n\nUplink"); seq_puts(file, "\nTrigger-based Uplink MU-MIMO\nData Type: "); for (i = 0; i < 3; i++) seq_printf(file, "%8s | ", ul_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | ", phy->mib.ul_hetrig_2mu_cnt, phy->mib.ul_hetrig_3mu_cnt, phy->mib.ul_hetrig_4mu_cnt); seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type: "); for (i = 3; i < 10; i++) seq_printf(file, "%8s | ", ul_he_type[i]); seq_puts(file, "\nTotal Count:"); seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u | %7u | ", phy->mib.ul_hetrig_su_cnt, phy->mib.ul_hetrig_2ru_cnt, phy->mib.ul_hetrig_3ru_cnt, phy->mib.ul_hetrig_4ru_cnt, phy->mib.ul_hetrig_5to8ru_cnt, phy->mib.ul_hetrig_9to16ru_cnt, phy->mib.ul_hetrig_gtr16ru_cnt); sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt + phy->mib.ul_hetrig_3mu_cnt + phy->mib.ul_hetrig_4mu_cnt; total_ppdu_cnt = sub_total_cnt; seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld", sub_total_cnt); sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt + phy->mib.ul_hetrig_3ru_cnt + phy->mib.ul_hetrig_4ru_cnt + phy->mib.ul_hetrig_5to8ru_cnt + phy->mib.ul_hetrig_9to16ru_cnt + phy->mib.ul_hetrig_gtr16ru_cnt; total_ppdu_cnt += sub_total_cnt; seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld", sub_total_cnt); total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt; seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt); exit: mutex_unlock(&dev->mt76.mutex); return ret; } DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats); static int mt7915_rdd_monitor(struct seq_file *s, void *data) { struct mt7915_dev *dev = dev_get_drvdata(s->private); struct cfg80211_chan_def *chandef = &dev->rdd2_chandef; const char *bw; int ret = 0; mutex_lock(&dev->mt76.mutex); if (!cfg80211_chandef_valid(chandef)) { ret = -EINVAL; goto out; } if (!dev->rdd2_phy) { seq_puts(s, "not running\n"); goto out; } switch (chandef->width) { case NL80211_CHAN_WIDTH_40: bw = "40"; break; case NL80211_CHAN_WIDTH_80: bw = "80"; break; case NL80211_CHAN_WIDTH_160: bw = "160"; break; case NL80211_CHAN_WIDTH_80P80: bw = "80P80"; break; default: bw = "20"; break; } seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n", chandef->chan->hw_value, chandef->chan->center_freq, bw, chandef->center_freq1); out: mutex_unlock(&dev->mt76.mutex); return ret; } static int mt7915_fw_debug_wm_set(void *data, u64 val) { struct mt7915_dev *dev = data; enum { DEBUG_TXCMD = 62, DEBUG_CMD_RPT_TX, DEBUG_CMD_RPT_TRIG, DEBUG_SPL, DEBUG_RPT_RX, } debug; bool tx, rx, en; int ret; dev->fw.debug_wm = val ? MCU_FW_LOG_TO_HOST : 0; if (dev->fw.debug_bin) val = 16; else val = dev->fw.debug_wm; tx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(1)); rx = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(2)); en = dev->fw.debug_wm || (dev->fw.debug_bin & BIT(0)); ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val); if (ret) goto out; for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) { if (debug == DEBUG_RPT_RX) val = en && rx; else val = en && tx; ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val); if (ret) goto out; } /* WM CPU info record control */ mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0)); - mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | !dev->fw.debug_wm); + mt76_wr(dev, MT_DIC_CMD_REG_CMD, BIT(2) | BIT(13) | + (dev->fw.debug_wm ? 0 : BIT(0))); mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5)); mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5)); out: if (ret) dev->fw.debug_wm = 0; return ret; } static int mt7915_fw_debug_wm_get(void *data, u64 *val) { struct mt7915_dev *dev = data; *val = dev->fw.debug_wm; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7915_fw_debug_wm_get, mt7915_fw_debug_wm_set, "%lld\n"); static int mt7915_fw_debug_wa_set(void *data, u64 val) { struct mt7915_dev *dev = data; int ret; dev->fw.debug_wa = val ? MCU_FW_LOG_TO_HOST : 0; ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw.debug_wa); if (ret) goto out; ret = mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_PDMA_RX, !!dev->fw.debug_wa, 0); out: if (ret) dev->fw.debug_wa = 0; return ret; } static int mt7915_fw_debug_wa_get(void *data, u64 *val) { struct mt7915_dev *dev = data; *val = dev->fw.debug_wa; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get, mt7915_fw_debug_wa_set, "%lld\n"); static struct dentry * create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode, struct rchan_buf *buf, int *is_global) { struct dentry *f; f = debugfs_create_file("fwlog_data", mode, parent, buf, &relay_file_operations); if (IS_ERR(f)) return NULL; *is_global = 1; return f; } static int remove_buf_file_cb(struct dentry *f) { debugfs_remove(f); return 0; } static int mt7915_fw_debug_bin_set(void *data, u64 val) { static struct rchan_callbacks relay_cb = { .create_buf_file = create_buf_file_cb, .remove_buf_file = remove_buf_file_cb, }; struct mt7915_dev *dev = data; if (!dev->relay_fwlog) dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir, 1500, 512, &relay_cb, NULL); if (!dev->relay_fwlog) return -ENOMEM; dev->fw.debug_bin = val; relay_reset(dev->relay_fwlog); return mt7915_fw_debug_wm_set(dev, dev->fw.debug_wm); } static int mt7915_fw_debug_bin_get(void *data, u64 *val) { struct mt7915_dev *dev = data; *val = dev->fw.debug_bin; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get, mt7915_fw_debug_bin_set, "%lld\n"); static int mt7915_fw_util_wm_show(struct seq_file *file, void *data) { struct mt7915_dev *dev = file->private; seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC)); if (dev->fw.debug_wm) { seq_printf(file, "Busy: %u%% Peak busy: %u%%\n", mt76_rr(dev, MT_CPU_UTIL_BUSY_PCT), mt76_rr(dev, MT_CPU_UTIL_PEAK_BUSY_PCT)); seq_printf(file, "Idle count: %u Peak idle count: %u\n", mt76_rr(dev, MT_CPU_UTIL_IDLE_CNT), mt76_rr(dev, MT_CPU_UTIL_PEAK_IDLE_CNT)); } return 0; } DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wm); static int mt7915_fw_util_wa_show(struct seq_file *file, void *data) { struct mt7915_dev *dev = file->private; seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WA_MCU_PC)); if (dev->fw.debug_wa) return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_CPU_UTIL, 0, 0); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7915_fw_util_wa); static void mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, struct seq_file *file) { struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; int bound[15], range[4], i; u8 band = phy->mt76->band_idx; /* Tx ampdu stat */ for (i = 0; i < ARRAY_SIZE(range); i++) range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i)); for (i = 0; i < ARRAY_SIZE(bound); i++) bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band); seq_printf(file, "Length: %8d | ", bound[0]); for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) seq_printf(file, "%3d -%3d | ", bound[i] + 1, bound[i + 1]); seq_puts(file, "\nCount: "); for (i = 0; i < ARRAY_SIZE(bound); i++) seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]); seq_puts(file, "\n"); seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); } static void mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) { struct mt76_mib_stats *mib = &phy->mib; static const char * const bw[] = { "BW20", "BW40", "BW80", "BW160" }; /* Tx Beamformer monitor */ seq_puts(s, "\nTx Beamformer applied PPDU counts: "); 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: "); 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 */ 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 */ 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"); } static int mt7915_tx_stats_show(struct seq_file *file, void *data) { struct mt7915_phy *phy = file->private; struct mt7915_dev *dev = phy->dev; struct mt76_mib_stats *mib = &phy->mib; int i; mutex_lock(&dev->mt76.mutex); 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; 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 void mt7915_hw_queue_read(struct seq_file *s, u32 size, const struct hw_queue_map *map) { struct mt7915_phy *phy = s->private; struct mt7915_dev *dev = phy->dev; u32 i, val; val = mt76_rr(dev, MT_FL_Q_EMPTY); for (i = 0; i < size; i++) { u32 ctrl, head, tail, queued; if (val & BIT(map[i].index)) continue; ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); head = mt76_get_field(dev, MT_FL_Q2_CTRL, GENMASK(11, 0)); tail = mt76_get_field(dev, MT_FL_Q2_CTRL, GENMASK(27, 16)); queued = mt76_get_field(dev, 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_FL_Q0_CTRL, ctrl | msta->wcid.idx); qlen = mt76_get_field(dev, 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->mt76.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, 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, ARRAY_SIZE(pse_queue_map), &pse_queue_map[0]); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7915_hw_queues); static int mt7915_xmit_queues_show(struct seq_file *file, void *data) { struct mt7915_phy *phy = file->private; struct mt7915_dev *dev = phy->dev; struct { struct mt76_queue *q; char *queue; } queue_map[] = { { 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(file, " %s | %9d | %9d | %9d |\n", queue_map[i].queue, q->queued, q->head, q->tail); } return 0; } DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); #define mt7915_txpower_puts(rate) \ ({ \ len += scnprintf(buf + len, sz - len, "%-16s:", #rate " (TMAC)"); \ for (i = 0; i < mt7915_sku_group_len[SKU_##rate]; i++, offs++) \ len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]); \ len += scnprintf(buf + len, sz - len, "\n"); \ }) #define mt7915_txpower_sets(rate, pwr, flag) \ ({ \ offs += len; \ len = mt7915_sku_group_len[rate]; \ if (mode == flag) { \ for (i = 0; i < len; i++) \ req.txpower_sku[offs + i] = pwr; \ } \ }) static ssize_t mt7915_rate_txpower_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; s8 txpwr[MT7915_SKU_RATE_NUM]; static const size_t sz = 2048; u8 band = phy->mt76->band_idx; int i, offs = 0, len = 0; ssize_t ret; char *buf; u32 reg; buf = kzalloc(sz, GFP_KERNEL); if (!buf) return -ENOMEM; ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr)); if (ret) goto out; /* Txpower propagation path: TMAC -> TXV -> BBP */ len += scnprintf(buf + len, sz - len, "\nPhy%d Tx power table (channel %d)\n", phy != &dev->phy, phy->mt76->chandef.chan->hw_value); len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s\n", " ", "1m", "2m", "5m", "11m"); mt7915_txpower_puts(CCK); len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m", "54m"); mt7915_txpower_puts(OFDM); len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7"); mt7915_txpower_puts(HT_BW20); len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7", "mcs32"); mt7915_txpower_puts(HT_BW40); len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11"); mt7915_txpower_puts(VHT_BW20); mt7915_txpower_puts(VHT_BW40); mt7915_txpower_puts(VHT_BW80); mt7915_txpower_puts(VHT_BW160); mt7915_txpower_puts(HE_RU26); mt7915_txpower_puts(HE_RU52); mt7915_txpower_puts(HE_RU106); mt7915_txpower_puts(HE_RU242); mt7915_txpower_puts(HE_RU484); mt7915_txpower_puts(HE_RU996); mt7915_txpower_puts(HE_RU2x996); reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) : MT_WF_PHY_TPC_CTRL_STAT_MT7916(band); len += scnprintf(buf + len, sz - len, "\nTx power (bbp) : %6ld\n", mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER)); ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); out: kfree(buf); return ret; } static ssize_t mt7915_rate_txpower_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { + int i, ret, pwr, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct mt7915_mcu_txpower_sku req = { .format_id = TX_POWER_LIMIT_TABLE, .band_idx = phy->mt76->band_idx, }; char buf[100]; - int i, ret, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; enum mac80211_rx_encoding mode; u32 offs = 0, len = 0; if (count >= sizeof(buf)) return -EINVAL; if (copy_from_user(buf, user_buf, count)) return -EFAULT; if (count && buf[count - 1] == '\n') buf[count - 1] = '\0'; else buf[count] = '\0'; if (sscanf(buf, "%u %u %u %u %u", &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) { dev_warn(dev->mt76.dev, "per bandwidth power limit: Mode BW160 BW80 BW40 BW20"); return -EINVAL; } if (mode > RX_ENC_HE) return -EINVAL; if (pwr160) pwr160 = mt7915_get_power_bound(phy, pwr160); if (pwr80) pwr80 = mt7915_get_power_bound(phy, pwr80); if (pwr40) pwr40 = mt7915_get_power_bound(phy, pwr40); if (pwr20) pwr20 = mt7915_get_power_bound(phy, pwr20); if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0) return -EINVAL; mutex_lock(&dev->mt76.mutex); ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku, sizeof(req.txpower_sku)); if (ret) goto out; mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY); mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY); if (mode == RX_ENC_LEGACY) goto skip; mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT); mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT); if (mode == RX_ENC_HT) goto skip; mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT); mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT); mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT); mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT); if (mode == RX_ENC_VHT) goto skip; mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1); mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1); mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1); mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE); mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE); mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE); mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE); skip: ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); if (ret) goto out; - mphy->txpower_cur = max(mphy->txpower_cur, - max(pwr160, max(pwr80, max(pwr40, pwr20)))); + pwr = max3(pwr80, pwr40, pwr20); + mphy->txpower_cur = max3(mphy->txpower_cur, pwr160, pwr); out: mutex_unlock(&dev->mt76.mutex); return ret ? ret : count; } static const struct file_operations mt7915_rate_txpower_fops = { .write = mt7915_rate_txpower_set, .read = mt7915_rate_txpower_get, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; 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; } /* The index of RF registers use the generic regidx, combined with two parts: * WF selection [31:24] and offset [23:0]. */ static int mt7915_rf_regval_get(void *data, u64 *val) { struct mt7915_dev *dev = data; u32 regval; int ret; ret = mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, ®val, false); if (ret) return ret; *val = regval; return 0; } static int mt7915_rf_regval_set(void *data, u64 val) { struct mt7915_dev *dev = data; u32 val32 = val; return mt7915_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true); } DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7915_rf_regval_get, mt7915_rf_regval_set, "0x%08llx\n"); 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_fops(phy->mt76, NULL); if (!dir) return -ENOMEM; debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug); debugfs_create_file("muru_stats", 0400, dir, phy, &mt7915_muru_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("sys_recovery", 0600, dir, phy, &mt7915_sys_recovery_ops); debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); debugfs_create_file("fw_util_wm", 0400, dir, dev, &mt7915_fw_util_wm_fops); debugfs_create_file("fw_util_wa", 0400, dir, dev, &mt7915_fw_util_wa_fops); debugfs_create_file("implicit_txbf", 0600, dir, dev, &fops_implicit_txbf); 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("rf_regval", 0600, dir, dev, &fops_rf_regval); if (!dev->dbdc_support || phy->mt76->band_idx) { debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); debugfs_create_file("radar_trigger", 0200, dir, dev, &fops_radar_trigger); debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, mt7915_rdd_monitor); } if (!ext_phy) dev->debugfs_dir = dir; return 0; } static void mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen, const void *data, int len) { static DEFINE_SPINLOCK(lock); unsigned long flags; void *dest; spin_lock_irqsave(&lock, flags); dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4); if (dest) { *(u32 *)dest = hdrlen + len; dest += 4; if (hdrlen) { memcpy(dest, hdr, hdrlen); dest += hdrlen; } memcpy(dest, data, len); relay_flush(dev->relay_fwlog); } spin_unlock_irqrestore(&lock, flags); } void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len) { struct { __le32 magic; __le32 timestamp; __le16 msg_type; __le16 len; } hdr = { .magic = cpu_to_le32(FW_BIN_LOG_MAGIC), .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR), }; if (!dev->relay_fwlog) return; hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0))); hdr.len = *(__le16 *)data; mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len); } bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len) { if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC) return false; if (dev->relay_fwlog) mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len); return true; } #ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ static ssize_t mt7915_sta_fixed_rate_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ieee80211_sta *sta = file->private_data; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = msta->vif->phy->dev; struct ieee80211_vif *vif; struct sta_phy phy = {}; char buf[100]; int ret; u32 field; u8 i, gi, he_ltf; if (count >= sizeof(buf)) return -EINVAL; if (copy_from_user(buf, user_buf, count)) return -EFAULT; if (count && buf[count - 1] == '\n') buf[count - 1] = '\0'; else buf[count] = '\0'; /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3 * nss - vht: 1~4, he: 1~4, others: ignore * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2 * ldpc - off: 0, on: 1 * stbc - off: 0, on: 1 * he_ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 */ if (sscanf(buf, "%hhu %hhu %hhu %hhu %hhu %hhu %hhu %hhu", &phy.type, &phy.bw, &phy.nss, &phy.mcs, &gi, &phy.ldpc, &phy.stbc, &he_ltf) != 8) { dev_warn(dev->mt76.dev, "format: Mode BW NSS MCS (HE)GI LDPC STBC HE_LTF\n"); field = RATE_PARAM_AUTO; goto out; } phy.ldpc = (phy.bw || phy.ldpc) * GENMASK(2, 0); for (i = 0; i <= phy.bw; i++) { phy.sgi |= gi << (i << sta->deflink.he_cap.has_he); phy.he_ltf |= he_ltf << (i << sta->deflink.he_cap.has_he); } field = RATE_PARAM_FIXED; out: vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, field); if (ret) return -EFAULT; return count; } static const struct file_operations fops_fixed_rate = { .write = mt7915_sta_fixed_rate_set, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static int mt7915_queues_show(struct seq_file *s, void *data) { struct ieee80211_sta *sta = s->private; mt7915_sta_hw_queue_read(s, sta); return 0; } 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("hw-queues", 0400, dir, sta, &mt7915_queues_fops); } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/dma.c b/sys/contrib/dev/mediatek/mt76/mt7915/dma.c index 59a44d79aaed..0c62272fe7d0 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/dma.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/dma.c @@ -1,671 +1,655 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include "mt7915.h" #include "../dma.h" #include "mac.h" static int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) { struct mt7915_dev *dev = phy->dev; + struct mtk_wed_device *wed = NULL; - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { if (is_mt798x(&dev->mt76)) ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; else ring_base = MT_WED_TX_RING_BASE; idx -= MT_TXQ_ID(0); + wed = &dev->mt76.mmio.wed; } return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, - MT_WED_Q_TX(idx)); + wed, MT_WED_Q_TX(idx)); } static int mt7915_poll_tx(struct napi_struct *napi, int budget) { struct mt7915_dev *dev; dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); mt76_connac_tx_cleanup(&dev->mt76); if (napi_complete_done(napi, 0)) mt7915_irq_enable(dev, MT_INT_TX_DONE_MCU); return 0; } static void mt7915_dma_config(struct mt7915_dev *dev) { #define Q_CONFIG(q, wfdma, int, id) do { \ if (wfdma) \ dev->wfdma_mask |= (1 << (q)); \ dev->q_int_mask[(q)] = int; \ dev->q_id[(q)] = id; \ } while (0) #define MCUQ_CONFIG(q, wfdma, int, id) Q_CONFIG(q, (wfdma), (int), (id)) #define RXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__RXQ(q), (wfdma), (int), (id)) #define TXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__TXQ(q), (wfdma), (int), (id)) if (is_mt7915(&dev->mt76)) { RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7915_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, MT7915_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, MT7915_RXQ_MCU_WA); RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7915_RXQ_BAND1); RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, MT7915_RXQ_MCU_WA_EXT); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, MT7915_RXQ_MCU_WA); TXQ_CONFIG(0, WFDMA1, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA1, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); MCUQ_CONFIG(MT_MCUQ_WM, WFDMA1, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); MCUQ_CONFIG(MT_MCUQ_WA, WFDMA1, MT_INT_TX_DONE_MCU_WA, MT7915_TXQ_MCU_WA); MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA1, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); } else { RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7916_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, MT7916_RXQ_MCU_WA_EXT); MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA_MT7916, MT7915_TXQ_MCU_WA); MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); if (is_mt7916(&dev->mt76) && mtk_wed_device_active(&dev->mt76.mmio.wed)) { RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_WED_RX_DONE_BAND0_MT7916, MT7916_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MT7916, MT7916_RXQ_MCU_WA); if (dev->hif2) RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); else RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_WED_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA0, MT_INT_WED_TX_DONE_BAND1, MT7915_TXQ_BAND1); } else { RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, MT7916_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7916_RXQ_MCU_WA); RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); } } } static void __mt7915_dma_prefetch(struct mt7915_dev *dev, u32 ofs) { #define PREFETCH(_base, _depth) ((_base) << 16 | (_depth)) u32 base = 0; /* prefetch SRAM wrapping boundary for tx/rx ring. */ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x4)); mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x40, 0x4)); mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x80, 0x4)); mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0xc0, 0x4)); mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x100, 0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x140, 0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x180, 0x4)); if (!is_mt7915(&dev->mt76)) { mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x1c0, 0x4)); base = 0x40; } mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1_WA) + ofs, PREFETCH(0x1c0 + base, 0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x200 + base, 0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1) + ofs, PREFETCH(0x240 + base, 0x4)); /* for mt7915, the ring which is next the last * used ring must be initialized. */ if (is_mt7915(&dev->mt76)) { ofs += 0x4; mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x140, 0x0)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1_WA) + ofs, PREFETCH(0x200 + base, 0x0)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND1) + ofs, PREFETCH(0x280 + base, 0x0)); } } void mt7915_dma_prefetch(struct mt7915_dev *dev) { __mt7915_dma_prefetch(dev, 0); if (dev->hif2) __mt7915_dma_prefetch(dev, MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0)); } static void mt7915_dma_disable(struct mt7915_dev *dev, bool rst) { struct mt76_dev *mdev = &dev->mt76; u32 hif1_ofs = 0; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); /* reset */ if (rst) { mt76_clear(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); if (is_mt7915(mdev)) { mt76_clear(dev, MT_WFDMA1_RST, MT_WFDMA1_RST_DMASHDL_ALL_RST | MT_WFDMA1_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA1_RST, MT_WFDMA1_RST_DMASHDL_ALL_RST | MT_WFDMA1_RST_LOGIC_RST); } if (dev->hif2) { mt76_clear(dev, MT_WFDMA0_RST + hif1_ofs, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST + hif1_ofs, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); if (is_mt7915(mdev)) { mt76_clear(dev, MT_WFDMA1_RST + hif1_ofs, MT_WFDMA1_RST_DMASHDL_ALL_RST | MT_WFDMA1_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA1_RST + hif1_ofs, MT_WFDMA1_RST_DMASHDL_ALL_RST | MT_WFDMA1_RST_LOGIC_RST); } } } /* disable */ mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (is_mt7915(mdev)) mt76_clear(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO_PFET2); if (dev->hif2) { mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (is_mt7915(mdev)) mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO_PFET2); } } int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset) { struct mt76_dev *mdev = &dev->mt76; u32 hif1_ofs = 0; u32 irq_mask; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); /* enable wpdma tx/rx */ if (!reset) { mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (is_mt7915(mdev)) mt76_set(dev, MT_WFDMA1_GLO_CFG, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); if (dev->hif2) { mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (is_mt7915(mdev)) mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN | MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_PDMA_BAND); } } /* enable interrupts for TX/RX rings */ irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU | MT_INT_MCU_CMD; if (!dev->phy.mt76->band_idx) irq_mask |= MT_INT_BAND0_RX_DONE; if (dev->dbdc_support || dev->phy.mt76->band_idx) irq_mask |= MT_INT_BAND1_RX_DONE; if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) { u32 wed_irq_mask = irq_mask; int ret; wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; if (!is_mt798x(&dev->mt76)) mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask); else mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); ret = mt7915_mcu_wed_enable_rx_stats(dev); if (ret) return ret; mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); } irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; mt7915_irq_enable(dev, irq_mask); mt7915_irq_disable(dev, 0); return 0; } static int mt7915_dma_enable(struct mt7915_dev *dev, bool reset) { struct mt76_dev *mdev = &dev->mt76; u32 hif1_ofs = 0; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); if (is_mt7915(mdev)) mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0); if (dev->hif2) { mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR + hif1_ofs, ~0); if (is_mt7915(mdev)) mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR + hif1_ofs, ~0); } /* configure delay interrupt off */ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); if (is_mt7915(mdev)) { mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0); } else { mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2, 0); } if (dev->hif2) { mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0 + hif1_ofs, 0); if (is_mt7915(mdev)) { mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0 + hif1_ofs, 0); } else { mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1 + hif1_ofs, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2 + hif1_ofs, 0); } } /* configure perfetch settings */ mt7915_dma_prefetch(dev); /* hif wait WFDMA idle */ mt76_set(dev, MT_WFDMA0_BUSY_ENA, MT_WFDMA0_BUSY_ENA_TX_FIFO0 | MT_WFDMA0_BUSY_ENA_TX_FIFO1 | MT_WFDMA0_BUSY_ENA_RX_FIFO); if (is_mt7915(mdev)) mt76_set(dev, MT_WFDMA1_BUSY_ENA, MT_WFDMA1_BUSY_ENA_TX_FIFO0 | MT_WFDMA1_BUSY_ENA_TX_FIFO1 | MT_WFDMA1_BUSY_ENA_RX_FIFO); if (dev->hif2) { mt76_set(dev, MT_WFDMA0_BUSY_ENA + hif1_ofs, MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 | MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 | MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO); if (is_mt7915(mdev)) mt76_set(dev, MT_WFDMA1_BUSY_ENA + hif1_ofs, MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 | MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 | MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO); } mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC, MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000); return mt7915_dma_start(dev, reset, true); } int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) { struct mt76_dev *mdev = &dev->mt76; u32 wa_rx_base, wa_rx_idx; u32 hif1_ofs = 0; int ret; mt7915_dma_config(dev); mt76_dma_attach(&dev->mt76); if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); mt7915_dma_disable(dev, true); if (mtk_wed_device_active(&mdev->mmio.wed)) { if (!is_mt798x(mdev)) { u8 wed_control_rx1 = is_mt7915(mdev) ? 1 : 2; mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED); mt76_wr(dev, MT_WFDMA_WED_RING_CONTROL, FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX0, 18) | FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX1, 19) | FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_RX1, wed_control_rx1)); if (is_mt7915(mdev)) mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP, MT_WFDMA0_EXT0_RXWB_KEEP); } } else { mt76_clear(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED); } /* init tx queue */ ret = mt7915_init_tx_queues(&dev->phy, MT_TXQ_ID(dev->phy.mt76->band_idx), MT7915_TX_RING_SIZE, MT_TXQ_RING_BASE(0)); if (ret) return ret; if (phy2) { ret = mt7915_init_tx_queues(phy2, MT_TXQ_ID(phy2->mt76->band_idx), MT7915_TX_RING_SIZE, MT_TXQ_RING_BASE(1)); if (ret) return ret; } /* command to WM */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_MCUQ_ID(MT_MCUQ_WM), MT7915_TX_MCU_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_WM)); if (ret) return ret; /* command to WA */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, MT_MCUQ_ID(MT_MCUQ_WA), MT7915_TX_MCU_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_WA)); if (ret) return ret; /* firmware download */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT_MCUQ_ID(MT_MCUQ_FWDL), MT7915_TX_FWDL_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_FWDL)); if (ret) return ret; /* event from WM */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT_RXQ_ID(MT_RXQ_MCU), MT7915_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MCU)); if (ret) return ret; /* event from WA */ if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; - dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed; } else { wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA); wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA); } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], wa_rx_idx, MT7915_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, wa_rx_base); if (ret) return ret; /* rx data queue for band0 */ if (!dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_MAIN].flags = + mdev->q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(MT7915_RXQ_BAND0); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed; } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7915_RX_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MAIN)); if (ret) return ret; } /* tx free notify event from WA for band0 */ if (!is_mt7915(mdev)) { wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA); wa_rx_idx = MT_RXQ_ID(MT_RXQ_MAIN_WA); if (mtk_wed_device_active(&mdev->mmio.wed)) { mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed; if (is_mt7916(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; } } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], wa_rx_idx, MT7915_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, wa_rx_base); if (ret) return ret; } if (dev->dbdc_support || dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_BAND1].flags = + mdev->q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(MT7915_RXQ_BAND1); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed; } /* rx data queue for band1 */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], MT_RXQ_ID(MT_RXQ_BAND1), MT7915_RX_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs); if (ret) return ret; /* tx free notify event from WA for band1 */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], MT_RXQ_ID(MT_RXQ_BAND1_WA), MT7915_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs); if (ret) return ret; } ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret < 0) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt7915_poll_tx); napi_enable(&dev->mt76.tx_napi); mt7915_dma_enable(dev, false); return 0; } -static void mt7915_dma_wed_reset(struct mt7915_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - - if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state)) - return; - - complete(&mdev->mmio.wed_reset); - - if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete, - 3 * HZ)) - dev_err(dev->mt76.dev, "wed reset complete timeout\n"); -} - -static void -mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q) -{ - mt76_queue_reset(dev, q); - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) - mt76_dma_wed_setup(&dev->mt76, q, true); -} - int mt7915_dma_reset(struct mt7915_dev *dev, bool force) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; struct mtk_wed_device *wed = &dev->mt76.mmio.wed; int i; /* clean up hw queues */ for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) { mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); if (mphy_ext) mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true); } for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++) mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); /* reset wfsys */ if (force) mt7915_wfsys_reset(dev); if (mtk_wed_device_active(wed)) mtk_wed_device_dma_reset(wed); mt7915_dma_disable(dev, force); - mt7915_dma_wed_reset(dev); + mt76_wed_dma_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (mphy_ext) - mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, mphy_ext->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { - if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE) + if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) continue; mt76_queue_reset(dev, &dev->mt76.q_rx[i]); } mt76_tx_status_check(&dev->mt76, true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); if (mtk_wed_device_active(wed) && is_mt7915(&dev->mt76)) mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP, MT_WFDMA0_EXT0_RXWB_KEEP); mt7915_dma_enable(dev, !force); return 0; } void mt7915_dma_cleanup(struct mt7915_dev *dev) { mt7915_dma_disable(dev, true); mt76_dma_cleanup(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.c b/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.c index 331ffb3030d8..c772d2e06e8c 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.c @@ -1,359 +1,384 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include +#include #include "mt7915.h" #include "eeprom.h" +static bool enable_6ghz; +module_param(enable_6ghz, bool, 0644); +MODULE_PARM_DESC(enable_6ghz, "Enable 6 GHz instead of 5 GHz on hardware that supports both"); + static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) { struct mt76_dev *mdev = &dev->mt76; u8 *eeprom = mdev->eeprom.data; - u32 val = eeprom[MT_EE_DO_PRE_CAL]; - u32 offs; + u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2; + u32 size, val = eeprom[offs]; + int ret; - if (!dev->flash_mode) + if (!dev->flash_mode || !val) return 0; - if (val != (MT_EE_WIFI_CAL_DPD | MT_EE_WIFI_CAL_GROUP)) - return 0; + size = mt7915_get_cal_group_size(dev) + mt7915_get_cal_dpd_size(dev); - val = MT_EE_CAL_GROUP_SIZE + MT_EE_CAL_DPD_SIZE; - dev->cal = devm_kzalloc(mdev->dev, val, GFP_KERNEL); + dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL); if (!dev->cal) return -ENOMEM; offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_eeprom(mdev, dev->cal, offs, val); + ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size); + if (!ret) + return ret; + + ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size); + if (!ret) + return ret; + + dev_warn(mdev->dev, "missing precal data, size=%d\n", size); + devm_kfree(mdev->dev, dev->cal); + dev->cal = NULL; + + return ret; } static int mt7915_check_eeprom(struct mt7915_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; u16 val = get_unaligned_le16(eeprom); #define CHECK_EEPROM_ERR(match) (match ? 0 : -EINVAL) switch (val) { case 0x7915: return CHECK_EEPROM_ERR(is_mt7915(&dev->mt76)); case 0x7916: return CHECK_EEPROM_ERR(is_mt7916(&dev->mt76)); case 0x7981: return CHECK_EEPROM_ERR(is_mt7981(&dev->mt76)); case 0x7986: return CHECK_EEPROM_ERR(is_mt7986(&dev->mt76)); default: return -EINVAL; } } static char *mt7915_eeprom_name(struct mt7915_dev *dev) { switch (mt76_chip(&dev->mt76)) { case 0x7915: return dev->dbdc_support ? MT7915_EEPROM_DEFAULT_DBDC : MT7915_EEPROM_DEFAULT; case 0x7981: /* mt7981 only supports mt7976 and only in DBDC mode */ return MT7981_EEPROM_MT7976_DEFAULT_DBDC; case 0x7986: switch (mt7915_check_adie(dev, true)) { case MT7976_ONE_ADIE_DBDC: return MT7986_EEPROM_MT7976_DEFAULT_DBDC; case MT7975_ONE_ADIE: return MT7986_EEPROM_MT7975_DEFAULT; case MT7976_ONE_ADIE: return MT7986_EEPROM_MT7976_DEFAULT; case MT7975_DUAL_ADIE: return MT7986_EEPROM_MT7975_DUAL_DEFAULT; case MT7976_DUAL_ADIE: return MT7986_EEPROM_MT7976_DUAL_DEFAULT; default: break; } return NULL; default: return MT7916_EEPROM_DEFAULT; } } static int mt7915_eeprom_load_default(struct mt7915_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; const struct firmware *fw = NULL; int ret; ret = request_firmware(&fw, mt7915_eeprom_name(dev), dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data) { dev_err(dev->mt76.dev, "Invalid default bin\n"); ret = -EINVAL; goto out; } memcpy(eeprom, fw->data, mt7915_eeprom_size(dev)); dev->flash_mode = true; out: release_firmware(fw); return ret; } static int mt7915_eeprom_load(struct mt7915_dev *dev) { int ret; u16 eeprom_size = mt7915_eeprom_size(dev); ret = mt76_eeprom_init(&dev->mt76, eeprom_size); if (ret < 0) return ret; if (ret) { dev->flash_mode = true; } else { u8 free_block_num; u32 block_num, i; u32 eeprom_blk_size = MT7915_EEPROM_BLOCK_SIZE; ret = mt7915_mcu_get_eeprom_free_block(dev, &free_block_num); if (ret < 0) return ret; /* efuse info isn't enough */ if (free_block_num >= 29) return -EINVAL; /* read eeprom data from efuse */ block_num = DIV_ROUND_UP(eeprom_size, eeprom_blk_size); for (i = 0; i < block_num; i++) { ret = mt7915_mcu_get_eeprom(dev, i * eeprom_blk_size); if (ret < 0) return ret; } } return mt7915_check_eeprom(dev); } static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; u8 *eeprom = dev->mt76.eeprom.data; u8 band = phy->mt76->band_idx; u32 val; val = eeprom[MT_EE_WIFI_CONF + band]; val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); if (!is_mt7915(&dev->mt76)) { switch (val) { case MT_EE_V2_BAND_SEL_5GHZ: phy->mt76->cap.has_5ghz = true; return; case MT_EE_V2_BAND_SEL_6GHZ: phy->mt76->cap.has_6ghz = true; return; case MT_EE_V2_BAND_SEL_5GHZ_6GHZ: - phy->mt76->cap.has_5ghz = true; - phy->mt76->cap.has_6ghz = true; + if (enable_6ghz) { + phy->mt76->cap.has_6ghz = true; + u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + band], + MT_EE_V2_BAND_SEL_6GHZ, + MT_EE_WIFI_CONF0_BAND_SEL); + } else { + phy->mt76->cap.has_5ghz = true; + u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + band], + MT_EE_V2_BAND_SEL_5GHZ, + MT_EE_WIFI_CONF0_BAND_SEL); + } + /* force to buffer mode */ + dev->flash_mode = true; + return; default: phy->mt76->cap.has_2ghz = true; return; } } else if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support) { val = band ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; } switch (val) { case MT_EE_BAND_SEL_5GHZ: phy->mt76->cap.has_5ghz = true; break; case MT_EE_BAND_SEL_2GHZ: phy->mt76->cap.has_2ghz = true; break; default: phy->mt76->cap.has_2ghz = true; phy->mt76->cap.has_5ghz = true; break; } } void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, struct mt7915_phy *phy) { u8 path, nss, nss_max = 4, *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; u8 band = phy->mt76->band_idx; mt7915_eeprom_parse_band_config(phy); /* read tx/rx path from eeprom */ if (is_mt7915(&dev->mt76)) { path = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, eeprom[MT_EE_WIFI_CONF]); } else { path = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, eeprom[MT_EE_WIFI_CONF + band]); } if (!path || path > 4) path = 4; /* read tx/rx stream */ nss = path; if (dev->dbdc_support) { if (is_mt7915(&dev->mt76)) { path = min_t(u8, path, 2); nss = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B0, eeprom[MT_EE_WIFI_CONF + 3]); if (band) nss = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B1, eeprom[MT_EE_WIFI_CONF + 3]); } else { nss = FIELD_GET(MT_EE_WIFI_CONF_STREAM_NUM, eeprom[MT_EE_WIFI_CONF + 2 + band]); } if (!is_mt798x(&dev->mt76)) nss_max = 2; } if (!nss) nss = nss_max; nss = min_t(u8, min_t(u8, nss_max, nss), path); mphy->chainmask = BIT(path) - 1; if (band) mphy->chainmask <<= dev->chainshift; mphy->antenna_mask = BIT(nss) - 1; dev->chainmask |= mphy->chainmask; dev->chainshift = hweight8(dev->mphy.chainmask); } int mt7915_eeprom_init(struct mt7915_dev *dev) { int ret; ret = mt7915_eeprom_load(dev); if (ret < 0) { if (ret != -EINVAL) return ret; dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); ret = mt7915_eeprom_load_default(dev); if (ret) return ret; } - ret = mt7915_eeprom_load_precal(dev); - if (ret) - return ret; - + mt7915_eeprom_load_precal(dev); mt7915_eeprom_parse_hw_cap(dev, &dev->phy); #if defined(__linux__) memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #elif defined(__FreeBSD__) memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #endif ETH_ALEN); mt76_eeprom_override(&dev->mphy); return 0; } int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx) { u8 *eeprom = dev->mt76.eeprom.data; int index, target_power; bool tssi_on, is_7976; if (chain_idx > 3) return -EINVAL; tssi_on = mt7915_tssi_enabled(dev, chan->band); is_7976 = mt7915_check_adie(dev, false) || is_mt7916(&dev->mt76); if (chan->band == NL80211_BAND_2GHZ) { if (is_7976) { index = MT_EE_TX0_POWER_2G_V2 + chain_idx; target_power = eeprom[index]; } else { index = MT_EE_TX0_POWER_2G + chain_idx * 3; target_power = eeprom[index]; if (!tssi_on) target_power += eeprom[index + 1]; } } else if (chan->band == NL80211_BAND_5GHZ) { int group = mt7915_get_channel_group_5g(chan->hw_value, is_7976); if (is_7976) { index = MT_EE_TX0_POWER_5G_V2 + chain_idx * 5; target_power = eeprom[index + group]; } else { index = MT_EE_TX0_POWER_5G + chain_idx * 12; target_power = eeprom[index + group]; if (!tssi_on) target_power += eeprom[index + 8]; } } else { int group = mt7915_get_channel_group_6g(chan->hw_value); index = MT_EE_TX0_POWER_6G_V2 + chain_idx * 8; target_power = is_7976 ? eeprom[index + group] : 0; } return target_power; } s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band) { u8 *eeprom = dev->mt76.eeprom.data; u32 val, offs; s8 delta; bool is_7976 = mt7915_check_adie(dev, false) || is_mt7916(&dev->mt76); if (band == NL80211_BAND_2GHZ) offs = is_7976 ? MT_EE_RATE_DELTA_2G_V2 : MT_EE_RATE_DELTA_2G; else if (band == NL80211_BAND_5GHZ) offs = is_7976 ? MT_EE_RATE_DELTA_5G_V2 : MT_EE_RATE_DELTA_5G; else offs = is_7976 ? MT_EE_RATE_DELTA_6G_V2 : 0; val = eeprom[offs]; if (!offs || !(val & MT_EE_RATE_DELTA_EN)) return 0; delta = FIELD_GET(MT_EE_RATE_DELTA_MASK, val); return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta; } const u8 mt7915_sku_group_len[] = { [SKU_CCK] = 4, [SKU_OFDM] = 8, [SKU_HT_BW20] = 8, [SKU_HT_BW40] = 9, [SKU_VHT_BW20] = 12, [SKU_VHT_BW40] = 12, [SKU_VHT_BW80] = 12, [SKU_VHT_BW160] = 12, [SKU_HE_RU26] = 12, [SKU_HE_RU52] = 12, [SKU_HE_RU106] = 12, [SKU_HE_RU242] = 12, [SKU_HE_RU484] = 12, [SKU_HE_RU996] = 12, [SKU_HE_RU2x996] = 12 }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.h b/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.h index f3e56817d36e..509fb43d8a68 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.h +++ b/sys/contrib/dev/mediatek/mt76/mt7915/eeprom.h @@ -1,160 +1,202 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_EEPROM_H #define __MT7915_EEPROM_H #include "mt7915.h" struct cal_data { u8 count; u16 offset[60]; }; enum mt7915_eeprom_field { MT_EE_CHIP_ID = 0x000, MT_EE_VERSION = 0x002, MT_EE_MAC_ADDR = 0x004, MT_EE_MAC_ADDR2 = 0x00a, MT_EE_DDIE_FT_VERSION = 0x050, MT_EE_DO_PRE_CAL = 0x062, MT_EE_WIFI_CONF = 0x190, + MT_EE_DO_PRE_CAL_V2 = 0x19a, MT_EE_RATE_DELTA_2G = 0x252, MT_EE_RATE_DELTA_5G = 0x29d, MT_EE_TX0_POWER_2G = 0x2fc, MT_EE_TX0_POWER_5G = 0x34b, MT_EE_RATE_DELTA_2G_V2 = 0x7d3, MT_EE_RATE_DELTA_5G_V2 = 0x81e, MT_EE_RATE_DELTA_6G_V2 = 0x884, /* 6g fields only appear in eeprom v2 */ MT_EE_TX0_POWER_2G_V2 = 0x441, MT_EE_TX0_POWER_5G_V2 = 0x445, MT_EE_TX0_POWER_6G_V2 = 0x465, MT_EE_ADIE_FT_VERSION = 0x9a0, __MT_EE_MAX = 0xe00, __MT_EE_MAX_V2 = 0x1000, /* 0xe10 ~ 0x5780 used to save group cal data */ MT_EE_PRECAL = 0xe10, MT_EE_PRECAL_V2 = 0x1010 }; #define MT_EE_WIFI_CAL_GROUP BIT(0) -#define MT_EE_WIFI_CAL_DPD GENMASK(2, 1) +#define MT_EE_WIFI_CAL_DPD_2G BIT(2) +#define MT_EE_WIFI_CAL_DPD_5G BIT(1) +#define MT_EE_WIFI_CAL_DPD_6G BIT(3) +#define MT_EE_WIFI_CAL_DPD GENMASK(3, 1) #define MT_EE_CAL_UNIT 1024 -#define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16) -#define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT) +#define MT_EE_CAL_GROUP_SIZE_7915 (49 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_GROUP_SIZE_7916 (54 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_GROUP_SIZE_7975 (54 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_GROUP_SIZE_7976 (94 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_GROUP_SIZE_7916_6G (94 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_DPD_SIZE_V1 (54 * MT_EE_CAL_UNIT) +#define MT_EE_CAL_DPD_SIZE_V2 (300 * MT_EE_CAL_UNIT) +#define MT_EE_CAL_DPD_SIZE_V2_7981 (102 * MT_EE_CAL_UNIT) /* no 6g dpd data */ #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) #define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6) #define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6) #define MT_EE_WIFI_CONF_STREAM_NUM GENMASK(7, 5) #define MT_EE_WIFI_CONF3_TX_PATH_B0 GENMASK(1, 0) #define MT_EE_WIFI_CONF3_TX_PATH_B1 GENMASK(5, 4) #define MT_EE_WIFI_CONF7_TSSI0_2G BIT(0) #define MT_EE_WIFI_CONF7_TSSI0_5G BIT(2) #define MT_EE_WIFI_CONF7_TSSI1_5G BIT(4) #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0) #define MT_EE_RATE_DELTA_SIGN BIT(6) #define MT_EE_RATE_DELTA_EN BIT(7) enum mt7915_adie_sku { MT7976_ONE_ADIE_DBDC = 0x7, MT7975_ONE_ADIE = 0x8, MT7976_ONE_ADIE = 0xa, MT7975_DUAL_ADIE = 0xd, MT7976_DUAL_ADIE = 0xf, }; enum mt7915_eeprom_band { MT_EE_BAND_SEL_DEFAULT, MT_EE_BAND_SEL_5GHZ, MT_EE_BAND_SEL_2GHZ, MT_EE_BAND_SEL_DUAL, }; enum { MT_EE_V2_BAND_SEL_2GHZ, MT_EE_V2_BAND_SEL_5GHZ, MT_EE_V2_BAND_SEL_6GHZ, MT_EE_V2_BAND_SEL_5GHZ_6GHZ, }; enum mt7915_sku_rate_group { SKU_CCK, SKU_OFDM, SKU_HT_BW20, SKU_HT_BW40, SKU_VHT_BW20, SKU_VHT_BW40, SKU_VHT_BW80, SKU_VHT_BW160, SKU_HE_RU26, SKU_HE_RU52, SKU_HE_RU106, SKU_HE_RU242, SKU_HE_RU484, SKU_HE_RU996, SKU_HE_RU2x996, MAX_SKU_RATE_GROUP_NUM, }; static inline int mt7915_get_channel_group_5g(int channel, bool is_7976) { if (is_7976) { if (channel <= 64) return 0; if (channel <= 96) return 1; if (channel <= 128) return 2; if (channel <= 144) return 3; return 4; } if (channel >= 184 && channel <= 196) return 0; if (channel <= 48) return 1; if (channel <= 64) return 2; if (channel <= 96) return 3; if (channel <= 112) return 4; if (channel <= 128) return 5; if (channel <= 144) return 6; return 7; } static inline int mt7915_get_channel_group_6g(int channel) { if (channel <= 29) return 0; return DIV_ROUND_UP(channel - 29, 32); } static inline bool mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) { u8 *eep = dev->mt76.eeprom.data; - u8 val = eep[MT_EE_WIFI_CONF + 7]; + u8 offs = is_mt7981(&dev->mt76) ? 8 : 7; + u8 val = eep[MT_EE_WIFI_CONF + offs]; if (band == NL80211_BAND_2GHZ) return val & MT_EE_WIFI_CONF7_TSSI0_2G; if (dev->dbdc_support) return val & MT_EE_WIFI_CONF7_TSSI1_5G; else return val & MT_EE_WIFI_CONF7_TSSI0_5G; } +static inline u32 +mt7915_get_cal_group_size(struct mt7915_dev *dev) +{ + u8 *eep = dev->mt76.eeprom.data; + u32 val; + + if (is_mt7915(&dev->mt76)) { + return MT_EE_CAL_GROUP_SIZE_7915; + } else if (is_mt7916(&dev->mt76)) { + val = eep[MT_EE_WIFI_CONF + 1]; + val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); + return (val == MT_EE_V2_BAND_SEL_6GHZ) ? MT_EE_CAL_GROUP_SIZE_7916_6G : + MT_EE_CAL_GROUP_SIZE_7916; + } else if (mt7915_check_adie(dev, false)) { + return MT_EE_CAL_GROUP_SIZE_7976; + } else { + return MT_EE_CAL_GROUP_SIZE_7975; + } +} + +static inline u32 +mt7915_get_cal_dpd_size(struct mt7915_dev *dev) +{ + if (is_mt7915(&dev->mt76)) + return MT_EE_CAL_DPD_SIZE_V1; + else if (is_mt7981(&dev->mt76)) + return MT_EE_CAL_DPD_SIZE_V2_7981; + else + return MT_EE_CAL_DPD_SIZE_V2; +} + extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM]; #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/init.c b/sys/contrib/dev/mediatek/mt76/mt7915/init.c index 19e3234dfa7c..33928fe48165 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/init.c @@ -1,1296 +1,1330 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include #if defined(__FreeBSD__) #include #endif #include "mt7915.h" #include "mac.h" #include "mcu.h" #include "coredump.h" #include "eeprom.h" static const struct ieee80211_iface_limit if_limits[] = { { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, { .max = 16, .types = BIT(NL80211_IFTYPE_AP) #ifdef CONFIG_MAC80211_MESH | BIT(NL80211_IFTYPE_MESH_POINT) #endif }, { .max = MT7915_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_STATION) } }; static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = MT7915_MAX_INTERFACES, .num_different_channels = 1, .beacon_int_infra_match = true, .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80) | BIT(NL80211_CHAN_WIDTH_160), } }; #if defined(__linux__) 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; switch (i) { case 0: + mutex_lock(&phy->dev->mt76.mutex); temperature = mt7915_mcu_get_temperature(phy); + mutex_unlock(&phy->dev->mt76.mutex); if (temperature < 0) return temperature; /* display in millidegree celcius */ return sprintf(buf, "%u\n", temperature * 1000); case 1: case 2: return sprintf(buf, "%u\n", phy->throttle_temp[i - 1] * 1000); case 3: return sprintf(buf, "%hhu\n", phy->throttle_state); default: return -EINVAL; } } 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); + val = DIV_ROUND_CLOSEST(clamp_val(val, 60 * 1000, 130 * 1000), 1000); if ((i - 1 == MT7915_CRIT_TEMP_IDX && val > phy->throttle_temp[MT7915_MAX_TEMP_IDX]) || (i - 1 == MT7915_MAX_TEMP_IDX && val < phy->throttle_temp[MT7915_CRIT_TEMP_IDX])) { dev_err(phy->dev->mt76.dev, "temp1_max shall be greater than temp1_crit."); mutex_unlock(&phy->dev->mt76.mutex); return -EINVAL; } phy->throttle_temp[i - 1] = val; - mutex_unlock(&phy->dev->mt76.mutex); - ret = mt7915_mcu_set_thermal_protect(phy); + mutex_unlock(&phy->dev->mt76.mutex); if (ret) return ret; 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 SENSOR_DEVICE_ATTR_RO(throttle1, mt7915_thermal_temp, 3); 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, &sensor_dev_attr_throttle1.dev_attr.attr, NULL, }; ATTRIBUTE_GROUPS(mt7915_hwmon); static int mt7915_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, unsigned long *state) { *state = MT7915_CDEV_THROTTLE_MAX; return 0; } static int mt7915_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct mt7915_phy *phy = cdev->devdata; *state = phy->cdev_state; return 0; } static int mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, unsigned long state) { struct mt7915_phy *phy = cdev->devdata; u8 throttling = MT7915_THERMAL_THROTTLE_MAX - state; int ret; if (state > MT7915_CDEV_THROTTLE_MAX) { dev_err(phy->dev->mt76.dev, "please specify a valid throttling state\n"); return -EINVAL; } if (state == phy->cdev_state) return 0; /* * cooling_device convention: 0 = no cooling, more = more cooling * mcu convention: 1 = max cooling, more = less cooling */ + mutex_lock(&phy->dev->mt76.mutex); ret = mt7915_mcu_set_thermal_throttling(phy, throttling); + mutex_unlock(&phy->dev->mt76.mutex); if (ret) return ret; phy->cdev_state = state; return 0; } static const struct thermal_cooling_device_ops mt7915_thermal_ops = { .get_max_state = mt7915_thermal_get_max_throttle_state, .get_cur_state = mt7915_thermal_get_cur_throttle_state, .set_cur_state = mt7915_thermal_set_cur_throttle_state, }; static void mt7915_unregister_thermal(struct mt7915_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; if (!phy->cdev) return; sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); thermal_cooling_device_unregister(phy->cdev); } #endif static int mt7915_thermal_init(struct mt7915_phy *phy) { #if defined(__linux__) struct wiphy *wiphy = phy->mt76->hw->wiphy; struct thermal_cooling_device *cdev; struct device *hwmon; const char *name; name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7915_%s", wiphy_name(wiphy)); + if (!name) + return -ENOMEM; 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) thermal_cooling_device_unregister(cdev); else phy->cdev = cdev; } /* initialize critical/maximum high temperature */ phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP; phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP; if (!IS_REACHABLE(CONFIG_HWMON)) return 0; hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, mt7915_hwmon_groups); - if (IS_ERR(hwmon)) - return PTR_ERR(hwmon); -#endif - + return PTR_ERR_OR_ZERO(hwmon); +#elif defined(__FreeBSD__) return 0; +#endif } #if defined(CONFIG_MT76_LEDS) static void mt7915_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { struct mt7915_dev *dev; struct mt76_phy *mphy; u32 val; mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); dev = container_of(mphy->dev, struct mt7915_dev, mt76); /* set PWM mode */ val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); mt76_wr(dev, MT_LED_STATUS_0(mphy->band_idx), val); mt76_wr(dev, MT_LED_STATUS_1(mphy->band_idx), val); /* enable LED */ mt76_wr(dev, MT_LED_EN(mphy->band_idx), 1); /* control LED */ val = MT_LED_CTRL_KICK; if (dev->mphy.leds.al) val |= MT_LED_CTRL_POLARITY; if (mphy->band_idx) val |= MT_LED_CTRL_BAND; mt76_wr(dev, MT_LED_CTRL(mphy->band_idx), val); mt76_clear(dev, MT_LED_CTRL(mphy->band_idx), MT_LED_CTRL_KICK); } #endif static int mt7915_led_set_blink(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { #if defined(CONFIG_MT76_LEDS) 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); #endif return 0; } static void mt7915_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { #if defined(CONFIG_MT76_LEDS) if (!brightness) mt7915_led_set_config(led_cdev, 0, 0xff); else mt7915_led_set_config(led_cdev, 0xff, 0); #endif } -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7915_init_txpower(struct mt7915_phy *phy, + struct ieee80211_supported_band *sband) { - int i, n_chains = hweight8(dev->mphy.antenna_mask); + struct mt7915_dev *dev = phy->dev; + int i, n_chains = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(n_chains); int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; for (i = 0; i < sband->n_channels; i++) { struct ieee80211_channel *chan = &sband->channels[i]; u32 target_power = 0; int j; for (j = 0; j < n_chains; j++) { u32 val; val = mt7915_eeprom_get_target_power(dev, chan, j); target_power = max(target_power, val); } target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; target_power = DIV_ROUND_UP(target_power, 2); chan->max_power = min_t(int, chan->max_reg_power, target_power); chan->orig_mpwr = target_power; } } +void mt7915_init_txpower(struct mt7915_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7915_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct mt7915_phy *phy = mphy->priv; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; if (dev->mt76.region == NL80211_DFS_UNSET) mt7915_mcu_rdd_background_enable(phy, NULL); - mt7915_init_txpower(dev, &mphy->sband_2g.sband); - mt7915_init_txpower(dev, &mphy->sband_5g.sband); - mt7915_init_txpower(dev, &mphy->sband_6g.sband); + mt7915_init_txpower(phy); mphy->dfs_state = MT_DFS_STATE_UNKNOWN; mt7915_dfs_init_radar_detector(phy); } static void mt7915_init_wiphy(struct mt7915_phy *phy) { struct mt76_phy *mphy = phy->mt76; struct ieee80211_hw *hw = mphy->hw; -#if defined(CONFIG_OF) struct mt76_dev *mdev = &phy->dev->mt76; -#endif struct wiphy *wiphy = hw->wiphy; struct mt7915_dev *dev = phy->dev; hw->queues = 4; hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; hw->netdev_features = NETIF_F_RXCSUM; + if (mtk_wed_device_active(&mdev->mmio.wed)) + hw->netdev_features |= NETIF_F_HW_TC; + hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; hw->sta_data_size = sizeof(struct mt7915_sta); hw->vif_data_size = sizeof(struct mt7915_vif); wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->reg_notifier = mt7915_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->mbssid_max_interfaces = 16; 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); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); if (!is_mt7915(&dev->mt76)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); #if defined(CONFIG_OF) if (!mdev->dev->of_node || !of_property_read_bool(mdev->dev->of_node, "mediatek,disable-radar-background")) #endif wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RADAR_BACKGROUND); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); hw->max_tx_fragments = 4; if (phy->mt76->cap.has_2ghz) { phy->mt76->sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; - phy->mt76->sband_2g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_4; + if (is_mt7915(&dev->mt76)) + phy->mt76->sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_4; + else + phy->mt76->sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_2; } if (phy->mt76->cap.has_5ghz) { struct ieee80211_sta_vht_cap *vht_cap; vht_cap = &phy->mt76->sband_5g.sband.vht_cap; phy->mt76->sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; - phy->mt76->sband_5g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_4; if (is_mt7915(&dev->mt76)) { + phy->mt76->sband_5g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_4; + vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; if (!dev->dbdc_support) vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_160 | FIELD_PREP(IEEE80211_VHT_CAP_EXT_NSS_BW_MASK, 1); } else { + phy->mt76->sband_5g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_2; + vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; /* mt7916 dbdc with 2g 2x2 bw40 and 5g 2x2 bw160c */ vht_cap->cap |= IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; } if (!is_mt7915(&dev->mt76) || !dev->dbdc_support) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); } mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); + mt7915_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { mphy->leds.cdev.brightness_set = mt7915_led_set_brightness; mphy->leds.cdev.blink_set = mt7915_led_set_blink; } } static void mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) { u32 mask, set; mt76_rmw_field(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); mt76_set(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); mask = MT_MDP_RCFR0_MCU_RX_MGMT | MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR | MT_MDP_RCFR0_MCU_RX_CTL_BAR; set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) | FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) | FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF); mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set); mask = MT_MDP_RCFR1_MCU_RX_BYPASS | MT_MDP_RCFR1_RX_DROPPED_UCAST | MT_MDP_RCFR1_RX_DROPPED_MCAST; set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) | FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) | FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF); mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set); mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 0x680); /* mt7915: disable rx rate report by default due to hw issues */ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); /* clear estimated value of EIFS for Rx duration & OBSS time */ mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR); /* clear backoff time for Rx duration */ mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band), MT_WF_RMAC_MIB_NONQOSD_BACKOFF); mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band), MT_WF_RMAC_MIB_QOS01_BACKOFF); mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band), MT_WF_RMAC_MIB_QOS23_BACKOFF); + /* clear backoff time for Tx duration */ + mt76_clear(dev, MT_WTBLOFF_TOP_ACR(band), + MT_WTBLOFF_TOP_ADM_BACKOFFTIME); + + /* exclude estimated backoff time for Tx duration on MT7915 */ + if (is_mt7915(&dev->mt76)) + mt76_set(dev, MT_AGG_ATCR0(band), + MT_AGG_ATCR_MAC_BFF_TIME_EN); + /* clear backoff time and set software compensation for OBSS time */ mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET; set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) | FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4); mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set); /* filter out non-resp frames and get instanstaeous signal reporting */ mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM; set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. */ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H); } static void mt7915_init_led_mux(struct mt7915_dev *dev) { if (!IS_ENABLED(CONFIG_MT76_LEDS)) return; if (dev->dbdc_support) { switch (mt76_chip(&dev->mt76)) { case 0x7915: mt76_rmw_field(dev, MT_LED_GPIO_MUX2, GENMASK(11, 8), 4); mt76_rmw_field(dev, MT_LED_GPIO_MUX3, GENMASK(11, 8), 4); break; case 0x7986: mt76_rmw_field(dev, MT_LED_GPIO_MUX0, GENMASK(7, 4), 1); mt76_rmw_field(dev, MT_LED_GPIO_MUX0, GENMASK(11, 8), 1); break; case 0x7916: mt76_rmw_field(dev, MT_LED_GPIO_MUX1, GENMASK(27, 24), 3); mt76_rmw_field(dev, MT_LED_GPIO_MUX1, GENMASK(31, 28), 3); break; default: break; } } else if (dev->mphy.leds.pin) { switch (mt76_chip(&dev->mt76)) { case 0x7915: mt76_rmw_field(dev, MT_LED_GPIO_MUX3, GENMASK(11, 8), 4); break; case 0x7986: mt76_rmw_field(dev, MT_LED_GPIO_MUX0, GENMASK(11, 8), 1); break; case 0x7916: mt76_rmw_field(dev, MT_LED_GPIO_MUX1, GENMASK(31, 28), 3); break; default: break; } } else { switch (mt76_chip(&dev->mt76)) { case 0x7915: mt76_rmw_field(dev, MT_LED_GPIO_MUX2, GENMASK(11, 8), 4); break; case 0x7986: mt76_rmw_field(dev, MT_LED_GPIO_MUX0, GENMASK(7, 4), 1); break; case 0x7916: mt76_rmw_field(dev, MT_LED_GPIO_MUX1, GENMASK(27, 24), 3); break; default: break; } } } void mt7915_mac_init(struct mt7915_dev *dev) { int i; u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; /* config pse qid6 wfdma port selection */ if (!is_mt7915(&dev->mt76) && dev->hif2) mt76_rmw(dev, MT_WF_PP_TOP_RXQ_WFDMA_CF_5, 0, MT_WF_PP_TOP_RXQ_QID6_WFDMA_HIF_SEL_MASK); mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, rx_len); if (!is_mt7915(&dev->mt76)) mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); else mt76_clear(dev, MT_PLE_HOST_RPT0, MT_PLE_HOST_RPT0_TX_LATENCY); /* enable hardware de-agg */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); for (i = 0; i < mt7915_wtbl_size(dev); i++) mt7915_mac_wtbl_update(dev, i, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); for (i = 0; i < 2; i++) mt7915_mac_init_band(dev, i); mt7915_init_led_mux(dev); } int mt7915_txbf_init(struct mt7915_dev *dev) { int ret; if (dev->dbdc_support) { ret = mt7915_mcu_set_txbf(dev, MT_BF_MODULE_UPDATE); if (ret) return ret; } /* trigger sounding packets */ ret = mt7915_mcu_set_txbf(dev, MT_BF_SOUNDING_ON); if (ret) return ret; /* enable eBF */ return mt7915_mcu_set_txbf(dev, MT_BF_TYPE_UPDATE); } static struct mt7915_phy * mt7915_alloc_ext_phy(struct mt7915_dev *dev) { struct mt7915_phy *phy; struct mt76_phy *mphy; if (!dev->dbdc_support) return NULL; mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops, MT_BAND1); if (!mphy) return ERR_PTR(-ENOMEM); phy = mphy->priv; phy->dev = dev; phy->mt76 = mphy; /* Bind main phy to band0 and ext_phy to band1 for dbdc case */ phy->mt76->band_idx = 1; return phy; } static int mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy) { struct mt76_phy *mphy = phy->mt76; int ret; INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work); mt7915_eeprom_parse_hw_cap(dev, phy); #if defined(__linux__) memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2, #elif defined(__FreeBSD__) memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR2, #endif ETH_ALEN); /* Make the secondary PHY MAC address local without overlapping with * the usual MAC address allocation scheme on multiple virtual interfaces */ if (!is_valid_ether_addr(mphy->macaddr)) { #if defined(__linux__) memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #elif defined(__FreeBSD__) memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #endif ETH_ALEN); mphy->macaddr[0] |= 2; mphy->macaddr[0] ^= BIT(7); } mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ mt7915_init_wiphy(phy); ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) return ret; ret = mt7915_thermal_init(phy); if (ret) goto unreg; #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) mt7915_init_debugfs(phy); #endif return 0; unreg: mt76_unregister_phy(mphy); return ret; } static void mt7915_init_work(struct work_struct *work) { struct mt7915_dev *dev = container_of(work, struct mt7915_dev, init_work); mt7915_mcu_set_eeprom(dev); mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7915_txbf_init(dev); } void mt7915_wfsys_reset(struct mt7915_dev *dev) { #define MT_MCU_DUMMY_RANDOM GENMASK(15, 0) #define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16) if (is_mt7915(&dev->mt76)) { u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON; mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM); /* change to software control */ val |= MT_TOP_PWR_SW_RST; mt76_wr(dev, MT_TOP_PWR_CTRL, val); /* reset wfsys */ val &= ~MT_TOP_PWR_SW_RST; mt76_wr(dev, MT_TOP_PWR_CTRL, val); /* release wfsys then mcu re-executes romcode */ val |= MT_TOP_PWR_SW_RST; mt76_wr(dev, MT_TOP_PWR_CTRL, val); /* switch to hw control */ val &= ~MT_TOP_PWR_SW_RST; val |= MT_TOP_PWR_HW_CTRL; mt76_wr(dev, MT_TOP_PWR_CTRL, val); /* check whether mcu resets to default */ if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_DEFAULT, MT_MCU_DUMMY_DEFAULT, 1000)) { dev_err(dev->mt76.dev, "wifi subsystem reset failure\n"); return; } /* wfsys reset won't clear host registers */ mt76_clear(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE); msleep(100); } else if (is_mt798x(&dev->mt76)) { mt7986_wmac_disable(dev); msleep(20); mt7986_wmac_enable(dev); msleep(20); } else { mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); msleep(20); mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); msleep(20); } } static bool mt7915_band_config(struct mt7915_dev *dev) { bool ret = true; dev->phy.mt76->band_idx = 0; if (is_mt798x(&dev->mt76)) { u32 sku = mt7915_check_adie(dev, true); /* * for mt7986, dbdc support is determined by the number * of adie chips and the main phy is bound to band1 when * dbdc is disabled. */ if (sku == MT7975_ONE_ADIE || sku == MT7976_ONE_ADIE) { dev->phy.mt76->band_idx = 1; ret = false; } } else { ret = is_mt7915(&dev->mt76) ? !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5)) : true; } return ret; } static int mt7915_init_hardware(struct mt7915_dev *dev, struct mt7915_phy *phy2) { int ret, idx; mt76_wr(dev, MT_INT_MASK_CSR, 0); mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); INIT_WORK(&dev->init_work, mt7915_init_work); ret = mt7915_dma_init(dev, phy2); if (ret) return ret; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); ret = mt7915_mcu_init(dev); if (ret) return ret; ret = mt7915_eeprom_init(dev); if (ret < 0) return ret; - if (dev->flash_mode) { + if (dev->cal) { ret = mt7915_mcu_apply_group_cal(dev); if (ret) return ret; } /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); if (idx) return -ENOSPC; dev->mt76.global_wcid.idx = idx; dev->mt76.global_wcid.hw_key_idx = -1; dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); return 0; } void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy) { int sts; u32 *cap; if (!phy->mt76->cap.has_5ghz) return; sts = hweight8(phy->mt76->chainmask); cap = &phy->mt76->sband_5g.sband.vht_cap.cap; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1); *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); if (sts < 2) return; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, sts - 1); } static void mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy, struct ieee80211_sta_he_cap *he_cap, int vif) { struct mt7915_dev *dev = phy->dev; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; int sts = hweight8(phy->mt76->chainmask); u8 c, sts_160 = sts; /* Can do 1/2 of STS in 160Mhz mode for mt7915 */ if (is_mt7915(&dev->mt76)) { if (!dev->dbdc_support) sts_160 /= 2; else sts_160 = 0; } #ifdef CONFIG_MAC80211_MESH if (vif == NL80211_IFTYPE_MESH_POINT) return; #endif elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; if (sts_160) c |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; elem->phy_cap_info[5] &= ~c; c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] &= ~c; elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US; if (!is_mt7915(&dev->mt76)) c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; elem->phy_cap_info[2] |= c; c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; if (sts_160) c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; elem->phy_cap_info[4] |= c; /* do not support NG16 due to spec D4.0 changes subcarrier idx */ c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU; if (vif == NL80211_IFTYPE_STATION) c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; elem->phy_cap_info[6] |= c; if (sts < 2) return; /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; - if (vif != NL80211_IFTYPE_AP) + if (vif != NL80211_IFTYPE_AP && vif != NL80211_IFTYPE_STATION) return; elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; - elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, sts - 1); if (sts_160) c |= FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, sts_160 - 1); elem->phy_cap_info[5] |= c; + if (vif != NL80211_IFTYPE_AP) + return; + + elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] |= c; if (!is_mt7915(&dev->mt76)) { c = IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; elem->phy_cap_info[7] |= c; } } static int mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data) { struct mt7915_dev *dev = phy->dev; int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask); u16 mcs_map = 0; u16 mcs_map_160 = 0; u8 nss_160; if (!is_mt7915(&dev->mt76)) nss_160 = nss; else if (!dev->dbdc_support) /* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */ nss_160 = nss / 2; else /* Can't do 160MHz with mt7915 dbdc */ nss_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)); if (i < nss_160) 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++) { struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp; switch (i) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: #endif break; default: continue; } data[idx].types_mask = BIT(i); he_cap->has_he = true; he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; else if (nss_160) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; else he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; 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] |= IEEE80211_HE_MAC_CAP4_BQR; he_cap_elem->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; he_cap_elem->phy_cap_info[3] |= 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] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; else he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; he_cap_elem->phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; he_cap_elem->phy_cap_info[3] |= 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_TRIG_CQI_FB | IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; he_cap_elem->phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; if (nss_160) he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; break; } memset(he_mcs, 0, sizeof(*he_mcs)); 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_160); he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160); mt7915_set_stream_he_txbf_caps(phy, he_cap, i); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { - mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss); + mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss, band); } else { he_cap_elem->phy_cap_info[9] |= u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); } if (band == NL80211_BAND_6GHZ) { u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); data[idx].he_6ghz_capa.capa = cpu_to_le16(cap); } idx++; } return idx; } void mt7915_set_stream_he_caps(struct mt7915_phy *phy) { struct ieee80211_sband_iftype_data *data; struct ieee80211_supported_band *band; int n; if (phy->mt76->cap.has_2ghz) { data = phy->iftype[NL80211_BAND_2GHZ]; n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data); band = &phy->mt76->sband_2g.sband; - band->iftype_data = data; - band->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(band, data, n); } if (phy->mt76->cap.has_5ghz) { data = phy->iftype[NL80211_BAND_5GHZ]; n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data); band = &phy->mt76->sband_5g.sband; - band->iftype_data = data; - band->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(band, data, n); } if (phy->mt76->cap.has_6ghz) { data = phy->iftype[NL80211_BAND_6GHZ]; n = mt7915_init_he_caps(phy, NL80211_BAND_6GHZ, data); band = &phy->mt76->sband_6g.sband; - band->iftype_data = data; - band->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(band, data, n); } } static void mt7915_unregister_ext_phy(struct mt7915_dev *dev) { struct mt7915_phy *phy = mt7915_ext_phy(dev); struct mt76_phy *mphy = dev->mt76.phys[MT_BAND1]; if (!phy) return; #if defined(__linux__) mt7915_unregister_thermal(phy); #endif mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); } static void mt7915_stop_hardware(struct mt7915_dev *dev) { mt7915_mcu_exit(dev); mt76_connac2_tx_token_put(&dev->mt76); mt7915_dma_cleanup(dev); tasklet_disable(&dev->mt76.irq_tasklet); if (is_mt798x(&dev->mt76)) mt7986_wmac_disable(dev); } int mt7915_register_device(struct mt7915_dev *dev) { struct mt7915_phy *phy2; int ret; dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; 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->twt_list); init_waitqueue_head(&dev->reset_wait); INIT_WORK(&dev->reset_work, mt7915_mac_reset_work); INIT_WORK(&dev->dump_work, mt7915_mac_dump_work); mutex_init(&dev->dump_mutex); dev->dbdc_support = mt7915_band_config(dev); phy2 = mt7915_alloc_ext_phy(dev); if (IS_ERR(phy2)) return PTR_ERR(phy2); ret = mt7915_init_hardware(dev, phy2); if (ret) goto free_phy2; mt7915_init_wiphy(&dev->phy); #ifdef CONFIG_NL80211_TESTMODE dev->mt76.test_ops = &mt7915_testmode_ops; #endif ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) goto stop_hw; ret = mt7915_thermal_init(&dev->phy); if (ret) goto unreg_dev; - ieee80211_queue_work(mt76_hw(dev), &dev->init_work); - if (phy2) { ret = mt7915_register_ext_phy(dev, phy2); if (ret) goto unreg_thermal; } + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + dev->recovery.hw_init_done = true; #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) ret = mt7915_init_debugfs(&dev->phy); if (ret) goto unreg_thermal; #endif ret = mt7915_coredump_register(dev); if (ret) goto unreg_thermal; return 0; unreg_thermal: #if defined(__linux__) mt7915_unregister_thermal(&dev->phy); #endif unreg_dev: mt76_unregister_device(&dev->mt76); stop_hw: mt7915_stop_hardware(dev); free_phy2: if (phy2) ieee80211_free_hw(phy2->mt76->hw); return ret; } void mt7915_unregister_device(struct mt7915_dev *dev) { mt7915_unregister_ext_phy(dev); mt7915_coredump_unregister(dev); #if defined(__linux__) mt7915_unregister_thermal(&dev->phy); #endif mt76_unregister_device(&dev->mt76); mt7915_stop_hardware(dev); mt76_free_device(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/mac.c b/sys/contrib/dev/mediatek/mt76/mt7915/mac.c index 7e9706d8bb08..53b241bd2338 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/mac.c @@ -1,2448 +1,2464 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #if defined(__FreeBSD__) #include #include #endif #include "coredump.h" #include "mt7915.h" #include "../dma.h" #include "mac.h" #include "mcu.h" #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) static const struct mt7915_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, }, }; static const struct mt7915_dfs_radar_spec fcc_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, }, }; static const struct mt7915_dfs_radar_spec jp_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, }, }; static struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev, u16 idx, bool unicast) { struct mt7915_sta *sta; struct mt76_wcid *wcid; if (idx >= ARRAY_SIZE(dev->mt76.wcid)) return NULL; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (unicast || !wcid) return wcid; if (!wcid->sta) return NULL; sta = container_of(wcid, struct mt7915_sta, wcid); if (!sta->vif) return NULL; return &sta->vif->sta.wcid; } bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); } 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, dw); } static void mt7915_mac_sta_poll(struct mt7915_dev *dev) { static const u8 ac_to_tid[] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; struct ieee80211_sta *sta; struct mt7915_sta *msta; struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; #if defined(__linux__) LIST_HEAD(sta_poll_list); #elif defined(__FreeBSD__) LINUX_LIST_HEAD(sta_poll_list); #endif int i; spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); rcu_read_lock(); while (true) { bool clear = false; u32 addr, val; u16 idx; s8 rssi[4]; u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { spin_unlock_bh(&dev->mt76.sta_poll_lock); break; } msta = list_first_entry(&sta_poll_list, struct mt7915_sta, wcid.poll_list); list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); idx = msta->wcid.idx; /* refresh peer's airtime reporting */ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u32 tx_last = msta->airtime_ac[i]; u32 rx_last = msta->airtime_ac[i + 4]; msta->airtime_ac[i] = mt76_rr(dev, addr); msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); - tx_time[i] = msta->airtime_ac[i] - tx_last; - rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + if (msta->airtime_ac[i] <= tx_last) + tx_time[i] = 0; + else + tx_time[i] = msta->airtime_ac[i] - tx_last; + + if (msta->airtime_ac[i + 4] <= rx_last) + rx_time[i] = 0; + else + rx_time[i] = msta->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; addr += 8; } if (clear) { mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); } if (!msta->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u8 queue = mt76_connac_lmac_mapping(i); u32 tx_cur = tx_time[queue]; u32 rx_cur = rx_time[queue]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) continue; 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; } /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 30); val = mt76_rr(dev, addr); rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); rssi[3] = to_rssi(GENMASK(31, 14), val); msta->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); } rcu_read_unlock(); } void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; u32 addr; addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); if (enable) mt76_set(dev, addr, BIT(5)); else mt76_clear(dev, addr, BIT(5)); } static void mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, struct mt7915_sta *msta, struct sk_buff *skb, u32 info) { struct ieee80211_vif *vif; struct wireless_dev *wdev; if (!msta || !msta->vif) return; if (!mt76_queue_is_wed_rx(q)) return; if (!(info & MT_DMA_INFO_PPE_VLD)) return; vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); wdev = ieee80211_vif_to_wdev(vif); skb->dev = wdev->netdev; mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, FIELD_GET(MT_DMA_PPE_CPU_REASON, info), FIELD_GET(MT_DMA_PPE_ENTRY, info)); } static int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb, enum mt76_rxq_id q, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; __le32 *rxd = (__le32 *)skb->data; __le32 *rxv = NULL; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; bool unicast, insert_ccmp_hdr = false; u8 remove_pad, amsdu_info; u8 mode = 0, qos_ctl = 0; struct mt7915_sta *msta = NULL; u32 csum_status = *(u32 *)skb->cb; bool hdr_trans; u16 hdr_gap; u16 seq_ctrl = 0; __le16 fc = 0; int idx; memset(status, 0, sizeof(*status)); if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->mt76->band_idx) { mphy = dev->mt76.phys[MT_BAND1]; if (!mphy) return -EINVAL; phy = mphy->priv; status->phy_idx = 1; } if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) return -EINVAL; hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) return -EINVAL; /* ICV error or CCMP/BIP/WPI MIC error */ if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) status->flag |= RX_FLAG_ONLY_MONITOR; unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); status->wcid = mt7915_rx_get_wcid(dev, idx, unicast); if (status->wcid) { msta = container_of(status->wcid, struct mt7915_sta, wcid); - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); } status->freq = mphy->chandef.chan->center_freq; status->band = mphy->chandef.chan->band; if (status->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (status->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.sband; else sband = &mphy->sband_2g.sband; if (!sband->channels) return -EINVAL; if ((rxd0 & csum_mask) == csum_mask && !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) status->flag |= RX_FLAG_MMIC_ERROR; if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED; status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) return -EINVAL; rxd += 6; if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { u32 v0 = le32_to_cpu(rxd[0]); u32 v2 = le32_to_cpu(rxd[2]); fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { case MT_CIPHER_AES_CCMP: case MT_CIPHER_CCMP_CCX: case MT_CIPHER_CCMP_256: insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); fallthrough; case MT_CIPHER_TKIP: case MT_CIPHER_TKIP_NO_MIC: case MT_CIPHER_GCMP: case MT_CIPHER_GCMP_256: status->iv[0] = data[5]; status->iv[1] = data[4]; status->iv[2] = data[3]; status->iv[3] = data[2]; status->iv[4] = data[1]; status->iv[5] = data[0]; break; default: break; } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { status->timestamp = le32_to_cpu(rxd[0]); status->flag |= RX_FLAG_MACTIME_START; if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { status->flag |= RX_FLAG_AMPDU_DETAILS; /* all subframes of an A-MPDU have the same timestamp */ if (phy->rx_ampdu_ts != status->timestamp) { if (!++phy->ampdu_ref) phy->ampdu_ref++; } phy->rx_ampdu_ts = status->timestamp; status->ampdu_ref = phy->ampdu_ref; } rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } /* RXD Group 3 - P-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { u32 v0, v1; int ret; rxv = rxd; rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; v0 = le32_to_cpu(rxv[0]); v1 = le32_to_cpu(rxv[1]); if (v0 & MT_PRXV_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; status->chains = mphy->antenna_mask; status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); /* RXD Group 5 - C-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { rxd += 18; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (!is_mt7915(&dev->mt76) || (rxd1 & MT_RXD1_NORMAL_GROUP_5)) { ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, sband, rxv, &mode); if (ret < 0) return ret; } } amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); status->amsdu = !!amsdu_info; if (status->amsdu) { status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; } hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { struct ieee80211_vif *vif; int err; if (!msta || !msta->vif) return -EINVAL; vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap); if (err) return err; hdr_trans = false; } else { int pad_start = 0; skb_pull(skb, hdr_gap); if (!hdr_trans && status->amsdu) { pad_start = ieee80211_get_hdrlen_from_skb(skb); } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { /* * When header translation failure is indicated, * the hardware will insert an extra 2-byte field * containing the data length after the protocol * type field. This happens either when the LLC-SNAP * pattern did not match, or if a VLAN header was * detected. */ pad_start = 12; if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) pad_start += 4; else pad_start = 0; } if (pad_start) { memmove(skb->data + 2, skb->data, pad_start); skb_pull(skb, 2); } } if (!hdr_trans) { struct ieee80211_hdr *hdr; if (insert_ccmp_hdr) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); mt76_insert_ccmp_hdr(skb, key_id); } hdr = mt76_skb_get_hdr(skb); fc = hdr->frame_control; if (ieee80211_is_data_qos(fc)) { seq_ctrl = le16_to_cpu(hdr->seq_ctrl); qos_ctl = *ieee80211_get_qos_ctl(hdr); } } else { status->flag |= RX_FLAG_8023; mt7915_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, *info); } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode); if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); status->qos_ctl = qos_ctl; status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); return 0; } static void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) { #ifdef CONFIG_NL80211_TESTMODE struct mt7915_phy *phy = &dev->phy; __le32 *rxd = (__le32 *)skb->data; __le32 *rxv_hdr = rxd + 2; __le32 *rxv = rxd + 4; u32 rcpi, ib_rssi, wb_rssi, v20, v21; u8 band_idx; s32 foe; u8 snr; int i; band_idx = le32_get_bits(rxv_hdr[1], MT_RXV_HDR_BAND_IDX); if (band_idx && !phy->mt76->band_idx) { phy = mt7915_ext_phy(dev); if (!phy) goto out; } rcpi = le32_to_cpu(rxv[6]); ib_rssi = le32_to_cpu(rxv[7]); wb_rssi = le32_to_cpu(rxv[8]) >> 5; for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) { if (i == 3) wb_rssi = le32_to_cpu(rxv[9]); phy->test.last_rcpi[i] = rcpi & 0xff; phy->test.last_ib_rssi[i] = ib_rssi & 0xff; phy->test.last_wb_rssi[i] = wb_rssi & 0xff; } v20 = le32_to_cpu(rxv[20]); v21 = le32_to_cpu(rxv[21]); foe = FIELD_GET(MT_CRXV_FOE_LO, v20) | (FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT); snr = FIELD_GET(MT_CRXV_SNR, v20) - 16; phy->test.last_freq_offset = foe; phy->test.last_snr = snr; out: #endif dev_kfree_skb(skb); } static void mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, struct sk_buff *skb) { #ifdef CONFIG_NL80211_TESTMODE struct mt76_testmode_data *td = &phy->mt76->test; const struct ieee80211_rate *r; u8 bw, mode, nss = td->tx_rate_nss; u8 rate_idx = td->tx_rate_idx; u16 rateval = 0; u32 val; bool cck = false; int band; if (skb != phy->mt76->test.tx_skb) return; switch (td->tx_rate_mode) { case MT76_TM_TX_MODE_HT: nss = 1 + (rate_idx >> 3); mode = MT_PHY_TYPE_HT; break; case MT76_TM_TX_MODE_VHT: mode = MT_PHY_TYPE_VHT; break; case MT76_TM_TX_MODE_HE_SU: mode = MT_PHY_TYPE_HE_SU; break; case MT76_TM_TX_MODE_HE_EXT_SU: mode = MT_PHY_TYPE_HE_EXT_SU; break; case MT76_TM_TX_MODE_HE_TB: mode = MT_PHY_TYPE_HE_TB; break; case MT76_TM_TX_MODE_HE_MU: mode = MT_PHY_TYPE_HE_MU; break; case MT76_TM_TX_MODE_CCK: cck = true; fallthrough; case MT76_TM_TX_MODE_OFDM: band = phy->mt76->chandef.chan->band; if (band == NL80211_BAND_2GHZ && !cck) rate_idx += 4; r = &phy->mt76->hw->wiphy->bands[band]->bitrates[rate_idx]; val = cck ? r->hw_value_short : r->hw_value; mode = val >> 8; rate_idx = val & 0xff; break; default: mode = MT_PHY_TYPE_OFDM; break; } switch (phy->mt76->chandef.width) { case NL80211_CHAN_WIDTH_40: bw = 1; break; case NL80211_CHAN_WIDTH_80: bw = 2; break; case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: bw = 3; break; default: bw = 0; break; } if (td->tx_rate_stbc && nss == 1) { nss++; rateval |= MT_TX_RATE_STBC; } rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | FIELD_PREP(MT_TX_RATE_MODE, mode) | FIELD_PREP(MT_TX_RATE_NSS, nss - 1); txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE); le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT); if (td->tx_rate_mode < MT76_TM_TX_MODE_HT) txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); val = MT_TXD6_FIXED_BW | FIELD_PREP(MT_TXD6_BW, bw) | FIELD_PREP(MT_TXD6_TX_RATE, rateval) | FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi); /* for HE_SU/HE_EXT_SU PPDU * - 1x, 2x, 4x LTF + 0.8us GI * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI * for HE_MU PPDU * - 2x, 4x LTF + 0.8us GI * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI * for HE_TB PPDU * - 1x, 2x LTF + 1.6us GI * - 4x LTF + 3.2us GI */ if (mode >= MT_PHY_TYPE_HE_SU) val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf); if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU)) val |= MT_TXD6_LDPC; txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID); txwi[6] |= cpu_to_le32(val); txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, phy->test.spe_idx)); #endif } void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, enum mt76_txq_id qid, u32 changed) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; struct mt76_phy *mphy = &dev->phy; if (phy_idx && dev->phys[MT_BAND1]) mphy = dev->phys[MT_BAND1]; mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed); if (mt76_testmode_enabled(mphy)) mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb); } 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, struct mt76_tx_info *tx_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; struct mt76_connac_fw_txp *txp; struct mt76_txwi_cache *t; int id, i, nbuf = tx_info->nbuf - 1; u8 *txwi = (u8 *)txwi_ptr; int pid; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; 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; } } 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; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key, qid, 0); txp = (struct mt76_connac_fw_txp *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len); } txp->nbuf = nbuf; txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST); if (!key) txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && ieee80211_is_mgmt(hdr->frame_control)) txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); if (vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; txp->bss_idx = mvif->mt76.idx; } txp->token = cpu_to_le16(id); if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) txp->rept_wds_wcid = cpu_to_le16(wcid->idx); else txp->rept_wds_wcid = cpu_to_le16(0x3ff); - tx_info->skb = DMA_DUMMY_DATA; + tx_info->skb = NULL; /* pass partial skb header to fw */ tx_info->buf[1].len = MT_CT_PARSE_LEN; tx_info->buf[1].skip_unmap = true; tx_info->nbuf = MT_CT_DMA_BUF_NUM; return 0; } u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) { #if defined(__linux__) struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; #elif defined(__FreeBSD__) struct mt76_connac_fw_txp *txp = (void *)((u8 *)ptr + MT_TXD_SIZE); #endif __le32 *txwi = ptr; u32 val; memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); txwi[0] = cpu_to_le32(val); val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); txwi[1] = cpu_to_le32(val); txp->token = cpu_to_le16(token_id); txp->nbuf = 1; txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); return MT_TXD_SIZE + sizeof(*txp); } static void mt7915_mac_tx_free_prepare(struct mt7915_dev *dev) { struct mt76_dev *mdev = &dev->mt76; struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1]; /* 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); if (mphy_ext) { mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false); mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false); } } static void mt7915_mac_tx_free_done(struct mt7915_dev *dev, struct list_head *free_list, bool wake) { struct sk_buff *skb, *tmp; mt7915_mac_sta_poll(dev); if (wake) mt76_set_tx_blocked(&dev->mt76, false); mt76_worker_schedule(&dev->mt76.tx_worker); list_for_each_entry_safe(skb, tmp, free_list, list) { skb_list_del_init(skb); napi_consume_skb(skb, 1); } } static void mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) { struct mt76_connac_tx_free *free = data; #if defined(__linux__) __le32 *tx_info = (__le32 *)(data + sizeof(*free)); #elif defined(__FreeBSD__) __le32 *tx_info = (__le32 *)((u8 *)data + sizeof(*free)); #endif struct mt76_dev *mdev = &dev->mt76; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; struct mt76_wcid *wcid = NULL; #if defined(__linux__) LIST_HEAD(free_list); void *end = data + len; #elif defined(__FreeBSD__) LINUX_LIST_HEAD(free_list); void *end = (u8 *)data + len; #endif bool v3, wake = false; u16 total, count = 0; u32 txd = le32_to_cpu(free->txd); __le32 *cur_info; mt7915_mac_tx_free_prepare(dev); total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4); for (cur_info = tx_info; count < total; cur_info++) { u32 msdu, info; u8 i; if (WARN_ON_ONCE((void *)cur_info >= end)) return; /* * 1'b1: new wcid pair. * 1'b0: msdu_id with the same 'wcid pair' as above. */ info = le32_to_cpu(*cur_info); if (info & MT_TX_FREE_PAIR) { struct mt7915_sta *msta; u16 idx; 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 mt7915_sta, wcid); - spin_lock_bh(&mdev->sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &mdev->sta_poll_list); - spin_unlock_bh(&mdev->sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); continue; } if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) { u32 tx_retries = 0, tx_failed = 0; if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) { tx_retries = FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1; tx_failed = tx_retries + !!FIELD_GET(MT_TX_FREE_STAT_V3, info); } else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) { tx_retries = FIELD_GET(MT_TX_FREE_COUNT, info) - 1; tx_failed = tx_retries + !!FIELD_GET(MT_TX_FREE_STAT, info); } wcid->stats.tx_retries += tx_retries; wcid->stats.tx_failed += tx_failed; } if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) continue; for (i = 0; i < 1 + v3; i++) { if (v3) { msdu = (info >> (15 * i)) & MT_TX_FREE_MSDU_ID_V3; if (msdu == MT_TX_FREE_MSDU_ID_V3) continue; } else { msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); } count++; txwi = mt76_token_release(mdev, msdu, &wake); if (!txwi) continue; mt76_connac2_txwi_free(mdev, txwi, sta, &free_list); } } mt7915_mac_tx_free_done(dev, &free_list, wake); } static void mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len) { struct mt76_connac_tx_free *free = data; #if defined(__linux__) __le16 *info = (__le16 *)(data + sizeof(*free)); #elif defined(__FreeBSD__) __le16 *info = (__le16 *)((u8 *)data + sizeof(*free)); #endif struct mt76_dev *mdev = &dev->mt76; #if defined(__linux__) void *end = data + len; LIST_HEAD(free_list); #elif defined(__FreeBSD__) void *end = (u8 *)data + len; LINUX_LIST_HEAD(free_list); #endif bool wake = false; u8 i, count; mt7915_mac_tx_free_prepare(dev); count = FIELD_GET(MT_TX_FREE_MSDU_CNT_V0, le16_to_cpu(free->ctrl)); if (WARN_ON_ONCE((void *)&info[count] > end)) return; for (i = 0; i < count; i++) { struct mt76_txwi_cache *txwi; u16 msdu = le16_to_cpu(info[i]); txwi = mt76_token_release(mdev, msdu, &wake); if (!txwi) continue; mt76_connac2_txwi_free(mdev, txwi, NULL, &free_list); } mt7915_mac_tx_free_done(dev, &free_list, wake); } static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data) { struct mt7915_sta *msta = NULL; struct mt76_wcid *wcid; __le32 *txs_data = data; u16 wcidx; u8 pid; wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); pid = le32_get_bits(txs_data[3], MT_TXS3_PID); if (pid < MT_PACKET_ID_WED) return; if (wcidx >= mt7915_wtbl_size(dev)) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wcidx]); if (!wcid) goto out; msta = container_of(wcid, struct mt7915_sta, wcid); if (pid == MT_PACKET_ID_WED) mt76_connac2_mac_fill_txs(&dev->mt76, wcid, txs_data); else mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data); if (!wcid->sta) goto out; - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); out: rcu_read_unlock(); } bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); __le32 *rxd = (__le32 *)data; __le32 *end = (__le32 *)&rxd[len / 4]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); switch (type) { case PKT_TYPE_TXRX_NOTIFY: mt7915_mac_tx_free(dev, data, len); return false; case PKT_TYPE_TXRX_NOTIFY_V0: mt7915_mac_tx_free_v0(dev, data, len); return false; case PKT_TYPE_TXS: for (rxd += 2; rxd + 8 <= end; rxd += 8) mt7915_mac_add_txs(dev, rxd); return false; case PKT_TYPE_RX_FW_MONITOR: #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) mt7915_debugfs_rx_fw_monitor(dev, data, len); #endif return false; default: return true; } } void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); __le32 *rxd = (__le32 *)skb->data; __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); switch (type) { case PKT_TYPE_TXRX_NOTIFY: mt7915_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; case PKT_TYPE_TXRX_NOTIFY_V0: mt7915_mac_tx_free_v0(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; case PKT_TYPE_RX_EVENT: mt7915_mcu_rx_event(dev, skb); break; case PKT_TYPE_TXRXV: mt7915_mac_fill_rx_vector(dev, skb); break; case PKT_TYPE_TXS: for (rxd += 2; rxd + 8 <= end; rxd += 8) mt7915_mac_add_txs(dev, rxd); dev_kfree_skb(skb); break; case PKT_TYPE_RX_FW_MONITOR: #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len); #endif dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: if (!mt7915_mac_fill_rx(dev, skb, q, info)) { mt76_rx(&dev->mt76, q, skb); return; } fallthrough; default: dev_kfree_skb(skb); break; } } void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; u32 reg = MT_WF_PHY_RX_CTRL1(phy->mt76->band_idx); mt76_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN); mt76_set(dev, reg, BIT(11) | BIT(9)); } void mt7915_mac_reset_counters(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; int i; for (i = 0; i < 4; i++) { mt76_rr(dev, MT_TX_AGG_CNT(phy->mt76->band_idx, i)); mt76_rr(dev, MT_TX_AGG_CNT2(phy->mt76->band_idx, i)); } phy->mt76->survey_time = ktime_get_boottime(); memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); /* reset airtime counters */ mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->mt76->band_idx), MT_WF_RMAC_MIB_RXTIME_CLR); mt7915_mcu_get_chan_mib_info(phy, true); } void mt7915_mac_set_timing(struct mt7915_phy *phy) { s16 coverage_class = phy->coverage_class; struct mt7915_dev *dev = phy->dev; struct mt7915_phy *ext_phy = mt7915_ext_phy(dev); u32 val, reg_offset; u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); u8 band = phy->mt76->band_idx; - int eifs_ofdm = 360, sifs = 10, offset; + int eifs_ofdm = 84, sifs = 10, offset; bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ); if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; if (ext_phy) coverage_class = max_t(s16, dev->phy.coverage_class, ext_phy->coverage_class); mt76_set(dev, MT_ARB_SCR(band), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); udelay(1); offset = 3 * coverage_class; reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); if (!is_mt7915(&dev->mt76)) { if (!a_band) { mt76_wr(dev, MT_TMAC_ICR1(band), FIELD_PREP(MT_IFS_EIFS_CCK, 314)); eifs_ofdm = 78; } else { eifs_ofdm = 84; } } else if (a_band) { sifs = 16; } mt76_wr(dev, MT_TMAC_CDTR(band), cck + reg_offset); mt76_wr(dev, MT_TMAC_ODTR(band), ofdm + reg_offset); mt76_wr(dev, MT_TMAC_ICR0(band), FIELD_PREP(MT_IFS_EIFS_OFDM, eifs_ofdm) | FIELD_PREP(MT_IFS_RIFS, 2) | FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); if (phy->slottime < 20 || a_band) val = MT7915_CFEND_RATE_DEFAULT; else val = MT7915_CFEND_RATE_11B; mt76_rmw_field(dev, MT_AGG_ACR0(band), MT_AGG_ACR_CFEND_RATE, val); mt76_clear(dev, MT_ARB_SCR(band), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); } void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool band) { u32 reg; reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(band) : MT_WF_PHY_RXTD12_MT7916(band); mt76_set(dev, reg, MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY | MT_WF_PHY_RXTD12_IRPI_SW_CLR); reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(band) : MT_WF_PHY_RX_CTRL1_MT7916(band); mt76_set(dev, reg, FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5)); } static u8 mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) { static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; struct mt7915_dev *dev = phy->dev; u32 val, sum = 0, n = 0; int nss, i; for (nss = 0; nss < hweight8(phy->mt76->chainmask); nss++) { u32 reg = is_mt7915(&dev->mt76) ? MT_WF_IRPI_NSS(0, nss + (idx << dev->dbdc_support)) : MT_WF_IRPI_NSS_MT7916(idx, nss); for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { val = mt76_rr(dev, reg); sum += val * nf_power[i]; n += val; } } if (!n) return 0; return sum / n; } void mt7915_update_channel(struct mt76_phy *mphy) { - struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; + struct mt7915_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; mt7915_mcu_get_chan_mib_info(phy, false); nf = mt7915_phy_get_nf(phy, phy->mt76->band_idx); if (!phy->noise) phy->noise = nf << 4; else if (nf) phy->noise += nf - (phy->noise >> 4); state->noise = -(phy->noise >> 4); } static bool mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) { bool ret; ret = wait_event_timeout(dev->reset_wait, (READ_ONCE(dev->recovery.state) & state), MT7915_RESET_TIMEOUT); WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); return ret; } static void mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = priv; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon, BSS_CHANGED_BEACON_ENABLED); break; default: break; } } static void mt7915_update_beacons(struct mt7915_dev *dev) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7915_update_vif_beacon, dev->mt76.hw); if (!mphy_ext) return; ieee80211_iterate_active_interfaces(mphy_ext->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7915_update_vif_beacon, mphy_ext->hw); } static int mt7915_mac_restart(struct mt7915_dev *dev) { struct mt7915_phy *phy2; struct mt76_phy *ext_phy; struct mt76_dev *mdev = &dev->mt76; int i, ret; ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; if (dev->hif2) { mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); } if (dev_is_pci(mdev->dev)) { mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); if (dev->hif2) { if (is_mt7915(mdev)) mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); else mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0x0); } } set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); - if (ext_phy) { + if (ext_phy) set_bit(MT76_RESET, &ext_phy->state); - set_bit(MT76_MCU_RESET, &ext_phy->state); - } /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); if (ext_phy) mt76_txq_schedule_all(ext_phy); /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(mdev, i) { if (mdev->q_rx[i].ndesc) napi_disable(&dev->mt76.napi[i]); } napi_disable(&dev->mt76.tx_napi); /* token reinit */ mt76_connac2_tx_token_put(&dev->mt76); idr_init(&dev->mt76.token); mt7915_dma_reset(dev, true); - local_bh_disable(); mt76_for_each_q_rx(mdev, i) { if (mdev->q_rx[i].ndesc) { napi_enable(&dev->mt76.napi[i]); + } + } + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + if (mdev->q_rx[i].ndesc) { napi_schedule(&dev->mt76.napi[i]); } } local_bh_enable(); clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); if (dev->hif2) { mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); } if (dev_is_pci(mdev->dev)) { mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); if (dev->hif2) { + mt76_wr(dev, MT_PCIE_RECOG_ID, + dev->hif2->index | MT_PCIE_RECOG_ID_SEM); if (is_mt7915(mdev)) mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); else mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff); } } /* load firmware */ ret = mt7915_mcu_init_firmware(dev); if (ret) goto out; /* set the necessary init items */ ret = mt7915_mcu_set_eeprom(dev); if (ret) goto out; mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); + mt7915_init_txpower(&dev->phy); + mt7915_init_txpower(phy2); ret = mt7915_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { ret = mt7915_run(dev->mphy.hw); if (ret) goto out; } if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) { ret = mt7915_run(ext_phy->hw); if (ret) goto out; } out: /* reset done */ clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); - local_bh_disable(); napi_enable(&dev->mt76.tx_napi); + + local_bh_disable(); napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); mt76_worker_enable(&dev->mt76.tx_worker); return ret; } static void mt7915_mac_full_reset(struct mt7915_dev *dev) { struct mt76_phy *ext_phy; + struct mt7915_phy *phy2; int i; ext_phy = dev->mt76.phys[MT_BAND1]; + phy2 = ext_phy ? ext_phy->priv : NULL; dev->recovery.hw_full_reset = true; + set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); ieee80211_stop_queues(mt76_hw(dev)); if (ext_phy) ieee80211_stop_queues(ext_phy->hw); cancel_delayed_work_sync(&dev->mphy.mac_work); if (ext_phy) cancel_delayed_work_sync(&ext_phy->mac_work); mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { if (!mt7915_mac_restart(dev)) break; } - mutex_unlock(&dev->mt76.mutex); if (i == 10) dev_err(dev->mt76.dev, "chip full reset failed\n"); - ieee80211_restart_hw(mt76_hw(dev)); - if (ext_phy) - ieee80211_restart_hw(ext_phy->hw); + spin_lock_bh(&dev->mt76.sta_poll_lock); + while (!list_empty(&dev->mt76.sta_poll_list)) + list_del_init(dev->mt76.sta_poll_list.next); + spin_unlock_bh(&dev->mt76.sta_poll_lock); - ieee80211_wake_queues(mt76_hw(dev)); - if (ext_phy) - ieee80211_wake_queues(ext_phy->hw); + memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask)); + dev->mt76.vif_mask = 0; + dev->phy.omac_mask = 0; + if (phy2) + phy2->omac_mask = 0; + i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); + dev->mt76.global_wcid.idx = i; dev->recovery.hw_full_reset = false; - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, - MT7915_WATCHDOG_TIME); + + mutex_unlock(&dev->mt76.mutex); + + ieee80211_restart_hw(mt76_hw(dev)); if (ext_phy) - ieee80211_queue_delayed_work(ext_phy->hw, - &ext_phy->mac_work, - MT7915_WATCHDOG_TIME); + ieee80211_restart_hw(ext_phy->hw); } /* system error recovery */ void mt7915_mac_reset_work(struct work_struct *work) { struct mt7915_phy *phy2; struct mt76_phy *ext_phy; struct mt7915_dev *dev; int i; dev = container_of(work, struct mt7915_dev, reset_work); ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; /* chip full reset */ if (dev->recovery.restart) { /* disable WA/WM WDT */ mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT) dev->recovery.wa_reset_count++; else dev->recovery.wm_reset_count++; mt7915_mac_full_reset(dev); /* enable mcu irq */ mt7915_irq_enable(dev, MT_INT_MCU_CMD); mt7915_irq_disable(dev, 0); /* enable WA/WM WDT */ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; dev->recovery.restart = false; return; } /* chip partial reset */ if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) return; - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { - mtk_wed_device_stop(&dev->mt76.mmio.wed); - if (!is_mt798x(&dev->mt76)) - mt76_wr(dev, MT_INT_WED_MASK_CSR, 0); - } - ieee80211_stop_queues(mt76_hw(dev)); if (ext_phy) ieee80211_stop_queues(ext_phy->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); cancel_delayed_work_sync(&phy2->mt76->mac_work); } + + mutex_lock(&dev->mt76.mutex); + mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(&dev->mt76, i) napi_disable(&dev->mt76.napi[i]); napi_disable(&dev->mt76.tx_napi); - mutex_lock(&dev->mt76.mutex); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { mt7915_dma_reset(dev, false); mt76_connac2_tx_token_put(&dev->mt76); idr_init(&dev->mt76.token); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); } mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); /* enable DMA Tx/Rx and interrupt */ mt7915_dma_start(dev, false, false); clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); - local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + + local_bh_disable(); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } local_bh_enable(); tasklet_schedule(&dev->mt76.irq_tasklet); mt76_worker_enable(&dev->mt76.tx_worker); - local_bh_disable(); napi_enable(&dev->mt76.tx_napi); + local_bh_disable(); napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); if (ext_phy) ieee80211_wake_queues(ext_phy->hw); mutex_unlock(&dev->mt76.mutex); mt7915_update_beacons(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT7915_WATCHDOG_TIME); if (phy2) ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mt76->mac_work, MT7915_WATCHDOG_TIME); } /* firmware coredump */ void mt7915_mac_dump_work(struct work_struct *work) { const struct mt7915_mem_region *mem_region; struct mt7915_crash_data *crash_data; struct mt7915_dev *dev; struct mt7915_mem_hdr *hdr; size_t buf_len; int i; u32 num; u8 *buf; dev = container_of(work, struct mt7915_dev, dump_work); mutex_lock(&dev->dump_mutex); crash_data = mt7915_coredump_new(dev); if (!crash_data) { mutex_unlock(&dev->dump_mutex); goto skip_coredump; } mem_region = mt7915_coredump_get_mem_layout(dev, &num); if (!mem_region || !crash_data->memdump_buf_len) { mutex_unlock(&dev->dump_mutex); goto skip_memdump; } buf = crash_data->memdump_buf; buf_len = crash_data->memdump_buf_len; /* dumping memory content... */ memset(buf, 0, buf_len); for (i = 0; i < num; i++) { if (mem_region->len > buf_len) { dev_warn(dev->mt76.dev, "%s len %lu is too large\n", mem_region->name, (unsigned long)mem_region->len); break; } /* reserve space for the header */ hdr = (void *)buf; buf += sizeof(*hdr); buf_len -= sizeof(*hdr); mt7915_memcpy_fromio(dev, buf, mem_region->start, mem_region->len); hdr->start = mem_region->start; hdr->len = mem_region->len; if (!mem_region->len) /* note: the header remains, just with zero length */ break; buf += mem_region->len; buf_len -= mem_region->len; mem_region++; } mutex_unlock(&dev->dump_mutex); skip_memdump: mt7915_coredump_submit(dev); skip_coredump: queue_work(dev->mt76.wq, &dev->reset_work); } void mt7915_reset(struct mt7915_dev *dev) { if (!dev->recovery.hw_init_done) return; if (dev->recovery.hw_full_reset) return; /* wm/wa exception: do full recovery */ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { dev->recovery.restart = true; dev_info(dev->mt76.dev, "%s indicated firmware crash, attempting recovery\n", wiphy_name(dev->mt76.hw->wiphy)); mt7915_irq_disable(dev, MT_INT_MCU_CMD); queue_work(dev->mt76.wq, &dev->dump_work); return; } + if ((READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) { + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + } + queue_work(dev->mt76.wq, &dev->reset_work); wake_up(&dev->reset_wait); } void mt7915_mac_update_stats(struct mt7915_phy *phy) { struct mt76_mib_stats *mib = &phy->mib; struct mt7915_dev *dev = phy->dev; int i, aggr0 = 0, aggr1, cnt; u8 band = phy->mt76->band_idx; u32 val; cnt = mt76_rr(dev, MT_MIB_SDR3(band)); mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR4(band)); mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR5(band)); mib->rx_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR6(band)); mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR7(band)); mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR8(band)); mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR10(band)); mib->rx_mrdy_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR11(band)); mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR12(band)); mib->tx_ampdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR13(band)); 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(band)); mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR15(band)); mib->tx_mpdu_success_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR16(band)); mib->primary_cca_busy_time += FIELD_GET(MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR17(band)); mib->secondary_cca_busy_time += FIELD_GET(MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR18(band)); mib->primary_energy_detect_time += FIELD_GET(MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR19(band)); mib->cck_mdrdy_time += FIELD_GET(MT_MIB_SDR19_CCK_MDRDY_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR20(band)); mib->ofdm_mdrdy_time += FIELD_GET(MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR21(band)); mib->green_mdrdy_time += FIELD_GET(MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR22(band)); mib->rx_ampdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR23(band)); mib->rx_ampdu_bytes_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR24(band)); mib->rx_ampdu_valid_subframe_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR25(band)); mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR27(band)); mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR28(band)); mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_SDR29(band)); mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDRVEC(band)); mib->rx_vec_queue_overflow_drop_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916, cnt); cnt = mt76_rr(dev, MT_MIB_SDR31(band)); mib->rx_ba_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDRMUBF(band)); mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); cnt = mt76_rr(dev, MT_MIB_DR8(band)); mib->tx_mu_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_DR9(band)); mib->tx_mu_acked_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_DR11(band)); mib->tx_su_acked_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(band)); mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_PAR_RPT0_FB_BW, cnt); mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NC, cnt); mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NR, 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; } if (is_mt7915(&dev->mt76)) { for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) { val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 4))); mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 4))); mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); phy->mt76->aggr_stats[aggr0++] += val & 0xffff; phy->mt76->aggr_stats[aggr0++] += val >> 16; val = mt76_rr(dev, MT_TX_AGG_CNT2(band, i)); phy->mt76->aggr_stats[aggr1++] += val & 0xffff; phy->mt76->aggr_stats[aggr1++] += val >> 16; } cnt = mt76_rr(dev, MT_MIB_SDR32(band)); mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); cnt = mt76_rr(dev, MT_MIB_SDR33(band)); mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT, cnt); cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(band)); 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_TX_NDP_BFRP(band)); 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); cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(band)); 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); } else { for (i = 0; i < 2; i++) { /* rts count */ val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 2))); mib->rts_cnt += FIELD_GET(GENMASK(15, 0), val); mib->rts_cnt += FIELD_GET(GENMASK(31, 16), val); /* rts retry count */ val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 2))); mib->rts_retries_cnt += FIELD_GET(GENMASK(15, 0), val); mib->rts_retries_cnt += FIELD_GET(GENMASK(31, 16), val); /* ba miss count */ val = mt76_rr(dev, MT_MIB_MB_SDR2(band, (i << 2))); mib->ba_miss_cnt += FIELD_GET(GENMASK(15, 0), val); mib->ba_miss_cnt += FIELD_GET(GENMASK(31, 16), val); /* ack fail count */ val = mt76_rr(dev, MT_MIB_MB_BFTF(band, (i << 2))); mib->ack_fail_cnt += FIELD_GET(GENMASK(15, 0), val); mib->ack_fail_cnt += FIELD_GET(GENMASK(31, 16), val); } for (i = 0; i < 8; i++) { val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val); phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val); } cnt = mt76_rr(dev, MT_MIB_SDR32(band)); mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); cnt = mt76_rr(dev, MT_MIB_BFCR7(band)); mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_MIB_BFCR7_BFEE_TX_FB_CPL, cnt); cnt = mt76_rr(dev, MT_MIB_BFCR2(band)); mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_MIB_BFCR2_BFEE_TX_FB_TRIG, cnt); cnt = mt76_rr(dev, MT_MIB_BFCR0(band)); mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); cnt = mt76_rr(dev, MT_MIB_BFCR1(band)); mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); } } static void mt7915_mac_severe_check(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; u32 trb; if (!phy->omac_mask) return; /* In rare cases, TRB pointers might be out of sync leads to RMAC * stopping Rx, so check status periodically to see if TRB hardware * requires minimal recovery. */ trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->mt76->band_idx)); if ((FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, trb) != FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, trb)) && (FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, phy->trb_ts) != FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, phy->trb_ts)) && trb == phy->trb_ts) mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L3_RX_ABORT, phy->mt76->band_idx); phy->trb_ts = trb; } void mt7915_mac_sta_rc_work(struct work_struct *work) { struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work); struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct mt7915_sta *msta; u32 changed; #if defined(__linux__) LIST_HEAD(list); #elif defined(__FreeBSD__) LINUX_LIST_HEAD(list); #endif spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->sta_rc_list, &list); while (!list_empty(&list)) { msta = list_first_entry(&list, struct mt7915_sta, rc_list); list_del_init(&msta->rc_list); changed = msta->changed; msta->changed = 0; spin_unlock_bh(&dev->mt76.sta_poll_lock); sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | IEEE80211_RC_NSS_CHANGED | IEEE80211_RC_BW_CHANGED)) mt7915_mcu_add_rate_ctrl(dev, vif, sta, true); if (changed & IEEE80211_RC_SMPS_CHANGED) mt7915_mcu_add_smps(dev, vif, sta); spin_lock_bh(&dev->mt76.sta_poll_lock); } spin_unlock_bh(&dev->mt76.sta_poll_lock); } void mt7915_mac_work(struct work_struct *work) { struct mt7915_phy *phy; struct mt76_phy *mphy; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); phy = mphy->priv; mutex_lock(&mphy->dev->mutex); mt76_update_survey(mphy); if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; mt7915_mac_update_stats(phy); mt7915_mac_severe_check(phy); if (phy->dev->muru_debug) mt7915_mcu_muru_debug_get(phy); } mutex_unlock(&mphy->dev->mutex); mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7915_WATCHDOG_TIME); } static void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; if (phy->rdd_state & BIT(0)) mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0, MT_RX_SEL0, 0); if (phy->rdd_state & BIT(1)) mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1, MT_RX_SEL0, 0); } static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) { int err, region; switch (dev->mt76.region) { case NL80211_DFS_ETSI: region = 0; break; case NL80211_DFS_JP: region = 2; break; case NL80211_DFS_FCC: default: region = 1; break; } err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain, MT_RX_SEL0, region); if (err < 0) return err; if (is_mt7915(&dev->mt76)) { err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, chain, 0, dev->dbdc_support ? 2 : 0); if (err < 0) return err; } return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain, MT_RX_SEL0, 1); } static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) { struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7915_dev *dev = phy->dev; int err; /* start CAC */ err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) return err; err = mt7915_dfs_start_rdd(dev, phy->mt76->band_idx); if (err < 0) return err; phy->rdd_state |= BIT(phy->mt76->band_idx); if (!is_mt7915(&dev->mt76)) return 0; if (chandef->width == NL80211_CHAN_WIDTH_160 || chandef->width == NL80211_CHAN_WIDTH_80P80) { err = mt7915_dfs_start_rdd(dev, 1); if (err < 0) return err; phy->rdd_state |= BIT(1); } return 0; } static int mt7915_dfs_init_radar_specs(struct mt7915_phy *phy) { const struct mt7915_dfs_radar_spec *radar_specs; struct mt7915_dev *dev = phy->dev; int err, i; switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs; err = mt7915_mcu_set_fcc5_lpn(dev, 8); if (err < 0) return err; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs; break; case NL80211_DFS_JP: radar_specs = &jp_radar_specs; break; default: return -EINVAL; } for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { err = mt7915_mcu_set_radar_th(dev, i, &radar_specs->radar_pattern[i]); if (err < 0) return err; } return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th); } int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; enum mt76_dfs_state dfs_state, prev_state; int err; prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); if (prev_state == dfs_state) return 0; if (prev_state == MT_DFS_STATE_UNKNOWN) mt7915_dfs_stop_radar_detector(phy); if (dfs_state == MT_DFS_STATE_DISABLED) goto stop; if (prev_state <= MT_DFS_STATE_DISABLED) { err = mt7915_dfs_init_radar_specs(phy); if (err < 0) return err; err = mt7915_dfs_start_radar_detector(phy); if (err < 0) return err; phy->mt76->dfs_state = MT_DFS_STATE_CAC; } if (dfs_state == MT_DFS_STATE_CAC) return 0; err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; } phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE; return 0; stop: err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) return err; if (is_mt7915(&dev->mt76)) { err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, phy->mt76->band_idx, 0, dev->dbdc_support ? 2 : 0); if (err < 0) return err; } mt7915_dfs_stop_radar_detector(phy); phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; 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; } static bool mt7915_mac_twt_param_equal(struct mt7915_sta *msta, struct ieee80211_twt_params *twt_agrt) { u16 type = le16_to_cpu(twt_agrt->req_type); u8 exp; int i; exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); for (i = 0; i < MT7915_MAX_STA_TWT_AGRT; i++) { struct mt7915_twt_flow *f; if (!(msta->twt.flowid_mask & BIT(i))) continue; f = &msta->twt.flow[i]; if (f->duration == twt_agrt->min_twt_dur && f->mantissa == twt_agrt->mantissa && f->exp == exp && f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) return true; } return false; } 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; if (twt_agrt->min_twt_dur < MT7915_MIN_TWT_DUR) { setup_cmd = TWT_SETUP_CMD_DICTATE; twt_agrt->min_twt_dur = MT7915_MIN_TWT_DUR; goto unlock; } flowid = ffs(~msta->twt.flowid_mask) - 1; twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); twt_agrt->req_type |= le16_encode_bits(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); if (mt7915_mac_twt_param_equal(msta, twt_agrt)) goto unlock; 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: twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); twt_agrt->req_type |= le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) | (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED); } void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, struct mt7915_sta *msta, u8 flowid) { struct mt7915_twt_flow *flow; lockdep_assert_held(&dev->mt76.mutex); if (flowid >= ARRAY_SIZE(msta->twt.flow)) return; if (!(msta->twt.flowid_mask & BIT(flowid))) return; flow = &msta->twt.flow[flowid]; if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_DELETE)) return; list_del_init(&flow->list); msta->twt.flowid_mask &= ~BIT(flowid); dev->twt.table_mask &= ~BIT(flow->table_id); dev->twt.n_agrt--; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/main.c b/sys/contrib/dev/mediatek/mt76/mt7915/main.c index 8ebbf186fab2..3aa31c5cefa6 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/main.c @@ -1,1697 +1,1815 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include "mt7915.h" #include "mcu.h" static bool mt7915_dev_running(struct mt7915_dev *dev) { struct mt7915_phy *phy; if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) return true; phy = mt7915_ext_phy(dev); return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); } int mt7915_run(struct ieee80211_hw *hw) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool running; int ret; running = mt7915_dev_running(dev); if (!running) { ret = mt76_connac_mcu_set_pm(&dev->mt76, dev->phy.mt76->band_idx, 0); if (ret) goto out; ret = mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, true, true); if (ret) goto out; mt7915_mac_enable_nf(dev, dev->phy.mt76->band_idx); } if (phy != &dev->phy) { ret = mt76_connac_mcu_set_pm(&dev->mt76, phy->mt76->band_idx, 0); if (ret) goto out; ret = mt7915_mcu_set_mac(dev, phy->mt76->band_idx, true, true); if (ret) goto out; mt7915_mac_enable_nf(dev, phy->mt76->band_idx); } ret = mt7915_mcu_set_thermal_throttling(phy, MT7915_THERMAL_THROTTLE_MAX); if (ret) goto out; ret = mt7915_mcu_set_thermal_protect(phy); if (ret) goto out; ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, phy->mt76->band_idx); if (ret) goto out; ret = mt7915_mcu_set_sku_en(phy, true); if (ret) goto out; ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); if (ret) goto out; set_bit(MT76_STATE_RUNNING, &phy->mt76->state); if (!mt76_testmode_enabled(phy->mt76)) ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7915_WATCHDOG_TIME); if (!running) mt7915_mac_reset_counters(phy); out: return ret; } static int mt7915_start(struct ieee80211_hw *hw) { struct mt7915_dev *dev = mt7915_hw_dev(hw); int ret; flush_work(&dev->init_work); mutex_lock(&dev->mt76.mutex); ret = mt7915_run(hw); mutex_unlock(&dev->mt76.mutex); return ret; } -static void mt7915_stop(struct ieee80211_hw *hw) +static void mt7915_stop(struct ieee80211_hw *hw, bool suspend) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(phy->mt76, true); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); if (phy != &dev->phy) { mt76_connac_mcu_set_pm(&dev->mt76, phy->mt76->band_idx, 1); mt7915_mcu_set_mac(dev, phy->mt76->band_idx, false, false); } if (!mt7915_dev_running(dev)) { mt76_connac_mcu_set_pm(&dev->mt76, dev->phy.mt76->band_idx, 1); mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, false, false); } mutex_unlock(&dev->mt76.mutex); } static inline int get_free_idx(u32 mask, u8 start, u8 end) { return ffs(~mask & GENMASK(end, start)); } static int get_omac_idx(enum nl80211_iftype type, u64 mask) { int i; switch (type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: /* prefer hw bssid slot 1-3 */ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); if (i) return i - 1; if (type != NL80211_IFTYPE_STATION) break; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; break; case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP: /* ap uses hw bssid 0 and ext bssid */ if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; break; default: WARN_ON(1); break; } return -1; } static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; int i; for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; mvif->bitrate_mask.control[i].he_gi = 0xff; mvif->bitrate_mask.control[i].he_ltf = 0xff; mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, sizeof(mvif->bitrate_mask.control[i].ht_mcs)); memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, sizeof(mvif->bitrate_mask.control[i].vht_mcs)); memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, sizeof(mvif->bitrate_mask.control[i].he_mcs)); } } static int mt7915_add_interface(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); struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt76_txq *mtxq; bool ext_phy = phy != &dev->phy; int idx, ret = 0; mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(phy->mt76, true); if (vif->type == NL80211_IFTYPE_MONITOR && is_zero_ether_addr(vif->addr)) phy->monitor_vif = vif; mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); if (mvif->mt76.idx >= (MT7915_MAX_INTERFACES << dev->dbdc_support)) { ret = -ENOSPC; goto out; } idx = get_omac_idx(vif->type, phy->omac_mask); if (idx < 0) { ret = -ENOSPC; goto out; } mvif->mt76.omac_idx = idx; mvif->phy = phy; mvif->mt76.band_idx = phy->mt76->band_idx; + mvif->mt76.wcid = &mvif->sta.wcid; mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; if (ext_phy) mvif->mt76.wmm_idx += 2; ret = mt7915_mcu_add_dev_info(phy, vif, true); if (ret) goto out; dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); - idx = MT7915_WTBL_RESERVED - mvif->mt76.idx; + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, mt7915_wtbl_size(dev)); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } INIT_LIST_HEAD(&mvif->sta.rc_list); - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = ext_phy; - mvif->sta.wcid.hw_key_idx = -1; mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; - mt76_packet_id_init(&mvif->sta.wcid); + mt76_wcid_init(&mvif->sta.wcid, phy->mt76->band_idx); mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; } if (vif->type != NL80211_IFTYPE_AP && (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) vif->offload_flags = 0; vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; mt7915_init_bitrate_mask(vif); memset(&mvif->cap, -1, sizeof(mvif->cap)); mt7915_mcu_add_bss_info(phy, vif, true); - mt7915_mcu_add_sta(dev, vif, NULL, true); + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); out: mutex_unlock(&dev->mt76.mutex); return ret; } static void mt7915_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = &mvif->sta; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int idx = msta->wcid.idx; mt7915_mcu_add_bss_info(phy, vif, false); - mt7915_mcu_add_sta(dev, vif, NULL, false); + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, mvif->sta.wcid.idx); mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(phy->mt76, true); mutex_unlock(&dev->mt76.mutex); if (vif == phy->monitor_vif) phy->monitor_vif = NULL; mt7915_mcu_add_dev_info(phy, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mutex_lock(&dev->mt76.mutex); dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); mutex_unlock(&dev->mt76.mutex); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - mt76_packet_id_flush(&dev->mt76, &msta->wcid); + mt76_wcid_cleanup(&dev->mt76, &msta->wcid); } -int mt7915_set_channel(struct mt7915_phy *phy) +int mt7915_set_channel(struct mt76_phy *mphy) { + struct mt7915_phy *phy = mphy->priv; struct mt7915_dev *dev = phy->dev; int ret; - cancel_delayed_work_sync(&phy->mt76->mac_work); - - mutex_lock(&dev->mt76.mutex); - set_bit(MT76_RESET, &phy->mt76->state); - - mt76_set_channel(phy->mt76); - - if (dev->flash_mode) { + if (dev->cal) { ret = mt7915_mcu_apply_tx_dpd(phy); if (ret) goto out; } ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH)); if (ret) goto out; mt7915_mac_set_timing(phy); ret = mt7915_dfs_init_radar_detector(phy); mt7915_mac_cca_stats_reset(phy); mt7915_mac_reset_counters(phy); phy->noise = 0; out: - clear_bit(MT76_RESET, &phy->mt76->state); - mutex_unlock(&dev->mt76.mutex); - - mt76_txq_schedule_all(phy->mt76); - if (!mt76_testmode_enabled(phy->mt76)) ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work, MT7915_WATCHDOG_TIME); return ret; } static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { 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 mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->wcid; u8 *wcid_keyidx = &wcid->hw_key_idx; int idx = key->keyidx; int err = 0; + if (sta && !wcid->sta) { + if (cmd != SET_KEY) + return 0; + + return -EOPNOTSUPP; + } + /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_AES_CMAC: wcid_keyidx = &wcid->hw_key_idx2; key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; break; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: default: return -EOPNOTSUPP; } mutex_lock(&dev->mt76.mutex); if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); mt7915_mcu_add_bss_info(phy, vif, true); } if (cmd == SET_KEY) { *wcid_keyidx = idx; } else { if (idx == *wcid_keyidx) *wcid_keyidx = -1; goto out; } mt76_wcid_key_setup(&dev->mt76, wcid, key); err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, key, MCU_EXT_CMD(STA_REC_UPDATE), &msta->wcid, cmd); out: mutex_unlock(&dev->mt76.mutex); return err; } static int mt7915_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); int err = -EINVAL; mutex_lock(&dev->mt76.mutex); if (!cfg80211_chandef_valid(&phy->mt76->chandef)) goto out; err = mt76_init_sar_power(hw, sar); if (err) goto out; err = mt7915_mcu_set_txpower_sku(phy); out: mutex_unlock(&dev->mt76.mutex); return err; } static int mt7915_config(struct ieee80211_hw *hw, u32 changed) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int ret; if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { #ifdef CONFIG_NL80211_TESTMODE if (phy->mt76->test.state != MT76_TM_STATE_OFF) { mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(phy->mt76, false); mutex_unlock(&dev->mt76.mutex); } #endif - ieee80211_stop_queues(hw); - ret = mt7915_set_channel(phy); + ret = mt76_update_channel(phy->mt76); if (ret) return ret; - ieee80211_wake_queues(hw); } if (changed & (IEEE80211_CONF_CHANGE_POWER | IEEE80211_CONF_CHANGE_CHANNEL)) { ret = mt7915_mcu_set_txpower_sku(phy); if (ret) return ret; } mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); bool band = phy->mt76->band_idx; + u32 rxfilter = phy->rxfilter; - if (!enabled) - phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; - else - phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + if (!enabled) { + rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + dev->monitor_mask &= ~BIT(band); + } else { + rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + dev->monitor_mask |= BIT(band); + } mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN, enabled); + mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_MDP_DCR0_RX_HDR_TRANS_EN, + !dev->monitor_mask); mt76_testmode_reset(phy->mt76, true); - mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + mt76_wr(dev, MT_WF_RFCR(band), rxfilter); } mutex_unlock(&dev->mt76.mutex); return 0; } static int mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; /* no need to update right away, we'll get BSS_CHANGED_QOS */ queue = mt76_connac_lmac_mapping(queue); mvif->queue_params[queue] = *params; return 0; } static void mt7915_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool band = phy->mt76->band_idx; u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | MT_WF_RFCR1_DROP_BF_POLL | MT_WF_RFCR1_DROP_BA | MT_WF_RFCR1_DROP_CFEND | MT_WF_RFCR1_DROP_CFACK; + u32 rxfilter; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ phy->rxfilter &= ~(_hw); \ phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ } while (0) mutex_lock(&dev->mt76.mutex); phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | MT_WF_RFCR_DROP_OTHER_BEACON | MT_WF_RFCR_DROP_FRAME_REPORT | MT_WF_RFCR_DROP_PROBEREQ | MT_WF_RFCR_DROP_MCAST_FILTERED | MT_WF_RFCR_DROP_MCAST | MT_WF_RFCR_DROP_BCAST | MT_WF_RFCR_DROP_DUPLICATE | MT_WF_RFCR_DROP_A2_BSSID | MT_WF_RFCR_DROP_UNWANTED_CTL | MT_WF_RFCR_DROP_STBC_MULTI); MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | MT_WF_RFCR_DROP_A3_MAC | MT_WF_RFCR_DROP_A3_BSSID); MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | MT_WF_RFCR_DROP_RTS | - MT_WF_RFCR_DROP_CTL_RSV | - MT_WF_RFCR_DROP_NDPA); + MT_WF_RFCR_DROP_CTL_RSV); *total_flags = flags; - mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); + rxfilter = phy->rxfilter; + if (hw->conf.flags & IEEE80211_CONF_MONITOR) + rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + else + rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + mt76_wr(dev, MT_WF_RFCR(band), rxfilter); if (*total_flags & FIF_CONTROL) mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); 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->mt76.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, u64 changed) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); int set_bss_info = -1, set_sta = -1; mutex_lock(&dev->mt76.mutex); /* * station mode uses BSSID to map the wlan entry to a peer, * and then peer references bss_info_rfch to set bandwidth cap. */ if (changed & BSS_CHANGED_BSSID && vif->type == NL80211_IFTYPE_STATION) set_bss_info = set_sta = !is_zero_ether_addr(info->bssid); if (changed & BSS_CHANGED_ASSOC) set_bss_info = vif->cfg.assoc; if (changed & BSS_CHANGED_BEACON_ENABLED && + info->enable_beacon && vif->type != NL80211_IFTYPE_AP) - set_bss_info = set_sta = info->enable_beacon; + set_bss_info = set_sta = 1; if (set_bss_info == 1) mt7915_mcu_add_bss_info(phy, vif, true); if (set_sta == 1) - mt7915_mcu_add_sta(dev, vif, NULL, true); + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); if (changed & BSS_CHANGED_ERP_CTS_PROT) mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); if (changed & BSS_CHANGED_ERP_SLOT) { - int slottime = info->use_short_slot ? 9 : 20; + int slottime = 9; + + if (phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ && + !info->use_short_slot) + slottime = 20; if (slottime != phy->slottime) { phy->slottime = slottime; mt7915_mac_set_timing(phy); } } /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) mt7915_mcu_set_tx(dev, vif); if (changed & BSS_CHANGED_HE_OBSS_PD) mt7915_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 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 | - BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | - BSS_CHANGED_FILS_DISCOVERY)) + BSS_CHANGED_BEACON_ENABLED)) mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed); + if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | + BSS_CHANGED_FILS_DISCOVERY)) + mt7915_mcu_add_inband_discov(dev, vif, changed); + if (set_bss_info == 0) mt7915_mcu_add_bss_info(phy, vif, false); if (set_sta == 0) - mt7915_mcu_add_sta(dev, vif, NULL, false); + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false); mutex_unlock(&dev->mt76.mutex); } static void mt7915_vif_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_vif_cap *vc = &mvif->cap; vc->ht_ldpc = vif->bss_conf.ht_ldpc; vc->vht_ldpc = vif->bss_conf.vht_ldpc; vc->vht_su_ebfer = vif->bss_conf.vht_su_beamformer; vc->vht_su_ebfee = vif->bss_conf.vht_su_beamformee; vc->vht_mu_ebfer = vif->bss_conf.vht_mu_beamformer; vc->vht_mu_ebfee = vif->bss_conf.vht_mu_beamformee; vc->he_ldpc = vif->bss_conf.he_ldpc; vc->he_su_ebfer = vif->bss_conf.he_su_beamformer; vc->he_su_ebfee = vif->bss_conf.he_su_beamformee; vc->he_mu_ebfer = vif->bss_conf.he_mu_beamformer; } static int mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); int err; mutex_lock(&dev->mt76.mutex); mt7915_vif_check_caps(phy, vif); err = mt7915_mcu_add_bss_info(phy, vif, true); if (err) goto out; - err = mt7915_mcu_add_sta(dev, vif, NULL, true); + err = mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); out: mutex_unlock(&dev->mt76.mutex); return err; } static void mt7915_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct mt7915_dev *dev = mt7915_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mt7915_mcu_add_sta(dev, vif, NULL, false); + mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false); mutex_unlock(&dev->mt76.mutex); } static void mt7915_channel_switch_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_chan_def *chandef) { struct mt7915_dev *dev = mt7915_hw_dev(hw); mutex_lock(&dev->mt76.mutex); mt7915_mcu_add_beacon(hw, vif, true, BSS_CHANGED_BEACON); mutex_unlock(&dev->mt76.mutex); } int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; bool ext_phy = mvif->phy != &dev->phy; - int ret, idx; + int idx; 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->wcid.poll_list); msta->vif = mvif; - msta->wcid.sta = 1; + msta->wcid.sta_disabled = 1; msta->wcid.idx = idx; msta->wcid.phy_idx = ext_phy; - msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->jiffies = jiffies; ewma_avg_signal_init(&msta->avg_ack_signal); mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, true); - ret = mt7915_mcu_add_sta(dev, vif, sta, true); - if (ret) - return ret; + return 0; +} + +struct drop_sta_iter { + struct mt7915_dev *dev; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif; + u8 sta_addr[ETH_ALEN]; +}; + +static void +__mt7915_drop_sta(void *ptr, u8 *mac, struct ieee80211_vif *vif) +{ + struct drop_sta_iter *data = ptr; + struct ieee80211_sta *sta; + struct mt7915_sta *msta; + + if (vif == data->vif || vif->type != NL80211_IFTYPE_AP) + return; + + sta = ieee80211_find_sta_by_ifaddr(data->hw, data->sta_addr, mac); + if (!sta) + return; + + msta = (struct mt7915_sta *)sta->drv_priv; + mt7915_mcu_add_sta(data->dev, vif, sta, CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; + msta->wcid.sta = 0; +} + +static void +mt7915_drop_other_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76_phy *ext_phy = dev->mt76.phys[MT_BAND1]; + struct drop_sta_iter data = { + .dev = dev, + .hw = dev->mphy.hw, + .vif = vif, + }; + + if (vif->type != NL80211_IFTYPE_AP) + return; + + memcpy(data.sta_addr, sta->addr, ETH_ALEN); + ieee80211_iterate_active_interfaces(data.hw, 0, __mt7915_drop_sta, &data); + + if (!ext_phy) + return; + + data.hw = ext_phy->hw; + ieee80211_iterate_active_interfaces(data.hw, 0, __mt7915_drop_sta, &data); +} + +int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) +{ + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + int i, ret; + u32 addr; + + switch (ev) { + case MT76_STA_EVENT_ASSOC: + ret = mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_CONNECT, true); + if (ret) + return ret; + + addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 30); + mt76_rmw_field(dev, addr, GENMASK(7, 0), 0xa0); + + ret = mt7915_mcu_add_rate_ctrl(dev, vif, sta, false); + if (ret) + return ret; + + msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->wcid.sta = 1; + msta->wcid.sta_disabled = 0; + + return 0; - return mt7915_mcu_add_rate_ctrl(dev, vif, sta, false); + case MT76_STA_EVENT_AUTHORIZE: + mt7915_drop_other_sta(dev, vif, sta); + return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); + + case MT76_STA_EVENT_DISASSOC: + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7915_mac_twt_teardown_flow(dev, msta, i); + + mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; + msta->wcid.sta = 0; + return 0; + } + + return 0; } void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { 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(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(&mdev->sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); if (!list_empty(&msta->rc_list)) list_del_init(&msta->rc_list); spin_unlock_bh(&mdev->sta_poll_lock); } static void mt7915_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; if (control->sta) { struct mt7915_sta *sta; sta = (struct mt7915_sta *)control->sta->drv_priv; wcid = &sta->wcid; } if (vif && !control->sta) { struct mt7915_vif *mvif; mvif = (struct mt7915_vif *)vif->drv_priv; wcid = &mvif->sta.wcid; } mt76_tx(mphy, control->sta, wcid, skb); } static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int ret; mutex_lock(&dev->mt76.mutex); ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, phy->mt76->band_idx); mutex_unlock(&dev->mt76.mutex); return ret; } static int mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct ieee80211_sta *sta = params->sta; struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); ret = mt7915_mcu_add_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); ret = mt7915_mcu_add_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; ret = mt7915_mcu_add_tx_ba(dev, params, true); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; clear_bit(tid, &msta->wcid.ampdu_state); ret = mt7915_mcu_add_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: set_bit(tid, &msta->wcid.ampdu_state); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; clear_bit(tid, &msta->wcid.ampdu_state); ret = mt7915_mcu_add_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mutex_unlock(&dev->mt76.mutex); return ret; } -static int -mt7915_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, - IEEE80211_STA_NONE); -} - -static int -mt7915_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, - IEEE80211_STA_NOTEXIST); -} - static int mt7915_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt76_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; mutex_unlock(&dev->mt76.mutex); return 0; } u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); bool band = phy->mt76->band_idx; union { u64 t64; u32 t32[2]; } tsf; u16 n; lockdep_assert_held(&dev->mt76.mutex); n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; /* TSF software read */ if (is_mt7915(&dev->mt76)) mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_READ); else mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_READ); 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 ret; } static void mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 timestamp) { 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->mt76->band_idx; union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; mutex_lock(&dev->mt76.mutex); n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); /* TSF software overwrite */ if (is_mt7915(&dev->mt76)) mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_WRITE); else mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_WRITE); mutex_unlock(&dev->mt76.mutex); } static void mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, s64 timestamp) { 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->mt76->band_idx; union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; mutex_lock(&dev->mt76.mutex); n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); /* TSF software adjust*/ if (is_mt7915(&dev->mt76)) mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_ADJUST); else mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_ADJUST); mutex_unlock(&dev->mt76.mutex); } static void mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; mutex_lock(&dev->mt76.mutex); phy->coverage_class = max_t(s16, coverage_class, 0); mt7915_mac_set_timing(phy); mutex_unlock(&dev->mt76.mutex); } static int mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int max_nss = hweight8(hw->wiphy->available_antennas_tx); u8 chainshift = dev->chainshift; u8 band = phy->mt76->band_idx; if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) return -EINVAL; mutex_lock(&dev->mt76.mutex); phy->mt76->antenna_mask = tx_ant; - /* handle a variant of mt7916 which has 3T3R but nss2 on 5 GHz band */ - if (is_mt7916(&dev->mt76) && band && hweight8(tx_ant) == max_nss) + /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ + if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) && + band && hweight8(tx_ant) == max_nss) phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; else phy->mt76->chainmask = tx_ant << (chainshift * band); mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); mutex_unlock(&dev->mt76.mutex); return 0; } static void mt7915_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct rate_info *txrate = &msta->wcid.rate; struct rate_info rxrate = {}; - if (is_mt7915(&phy->dev->mt76) && - !mt7915_mcu_get_rx_rate(phy, vif, sta, &rxrate)) { + if (!mt7915_mcu_get_rx_rate(phy, vif, sta, &rxrate)) { sinfo->rxrate = rxrate; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); } if (txrate->legacy || txrate->flags) { if (txrate->legacy) { sinfo->txrate.legacy = txrate->legacy; } else { 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 = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } /* offloading flows bypass networking stack, so driver counts and * reports sta statistics via NL80211_STA_INFO when WED is active. */ if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { sinfo->tx_bytes = msta->wcid.stats.tx_bytes; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); if (!mt7915_mcu_wed_wa_tx_stats(phy->dev, msta->wcid.idx)) { sinfo->tx_packets = msta->wcid.stats.tx_packets; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); } if (mtk_wed_get_rx_capa(&phy->dev->mt76.mmio.wed)) { sinfo->rx_bytes = msta->wcid.stats.rx_bytes; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); sinfo->rx_packets = msta->wcid.stats.rx_packets; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); } } sinfo->tx_failed = msta->wcid.stats.tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); sinfo->tx_retries = msta->wcid.stats.tx_retries; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); sinfo->ack_signal = (s8)msta->ack_signal; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); } static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = msta->vif->phy->dev; u32 *changed = data; spin_lock_bh(&dev->mt76.sta_poll_lock); msta->changed |= *changed; if (list_empty(&msta->rc_list)) list_add_tail(&msta->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); } static void mt7915_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + + if (!msta->wcid.sta) + return; mt7915_sta_rc_work(&changed, sta); ieee80211_queue_work(hw, &dev->rc_work); } static int mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; mvif->bitrate_mask = *mask; /* if multiple rates across different preambles are given we can * reconfigure this info with all peers using sta_rec command with * the below exception cases. * - single rate : if a rate is passed along with different preambles, * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT * then multiple MCS setting (MCS 4,5,6) is not supported. */ ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed); ieee80211_queue_work(hw, &dev->rc_work); return 0; } static void mt7915_sta_set_4addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; if (enabled) set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); + if (!msta->wcid.sta) + return; + mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; if (enabled) set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + if (!msta->wcid.sta) + return; + mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw); s16 txpower = sta->deflink.txpwr.power; int ret; if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) txpower = 0; mutex_lock(&dev->mt76.mutex); /* NOTE: temporarily use 0 as minimum limit, which is a * global setting and will be applied to all stations. */ ret = mt7915_mcu_set_txpower_frame_min(phy, 0); if (ret) goto out; /* This only applies to data frames while pushing traffic, * whereas the management frames or other packets that are * using fixed rate can be configured via TxD. */ ret = mt7915_mcu_set_txpower_frame(phy, vif, sta, txpower); out: mutex_unlock(&dev->mt76.mutex); return ret; } 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", "primary_cca_busy_time", "secondary_cca_busy_time", "primary_energy_detect_time", "cck_mdrdy_time", "ofdm_mdrdy_time", "green_mdrdy_time", "rx_vector_mismatch_cnt", "rx_delimiter_fail_cnt", "rx_mrdy_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", /* muru mu-mimo and ofdma related stats */ "dl_cck_cnt", "dl_ofdm_cnt", "dl_htmix_cnt", "dl_htgf_cnt", "dl_vht_su_cnt", "dl_vht_2mu_cnt", "dl_vht_3mu_cnt", "dl_vht_4mu_cnt", "dl_he_su_cnt", "dl_he_ext_su_cnt", "dl_he_2ru_cnt", "dl_he_2mu_cnt", "dl_he_3ru_cnt", "dl_he_3mu_cnt", "dl_he_4ru_cnt", "dl_he_4mu_cnt", "dl_he_5to8ru_cnt", "dl_he_9to16ru_cnt", "dl_he_gtr16ru_cnt", "ul_hetrig_su_cnt", "ul_hetrig_2ru_cnt", "ul_hetrig_3ru_cnt", "ul_hetrig_4ru_cnt", "ul_hetrig_5to8ru_cnt", "ul_hetrig_9to16ru_cnt", "ul_hetrig_gtr16ru_cnt", "ul_hetrig_2mu_cnt", "ul_hetrig_3mu_cnt", "ul_hetrig_4mu_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", "v_tx_nss_1", "v_tx_nss_2", "v_tx_nss_3", "v_tx_nss_4", }; #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) return; - memcpy(data, *mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats)); + memcpy(data, mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats)); data += sizeof(mt7915_gstrings_stats); page_pool_ethtool_stats_get_strings(data); } static int mt7915_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int sset) { if (sset != ETH_SS_STATS) return 0; return MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count(); } 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->mt76.idx != wi->idx) return; mt76_ethtool_worker(wi, &msta->wcid.stats, false); } 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_mib_stats *mib = &phy->mib; struct mt76_ethtool_worker_info wi = { .data = data, .idx = mvif->mt76.idx, }; /* See mt7915_ampdu_stat_read_phy, etc */ int i, ei = 0, stats_size; 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 */ for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) data[ei++] = phy->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; 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->primary_cca_busy_time; data[ei++] = mib->secondary_cca_busy_time; data[ei++] = mib->primary_energy_detect_time; data[ei++] = mib->cck_mdrdy_time; data[ei++] = mib->ofdm_mdrdy_time; data[ei++] = mib->green_mdrdy_time; data[ei++] = mib->rx_vector_mismatch_cnt; data[ei++] = mib->rx_delimiter_fail_cnt; data[ei++] = mib->rx_mrdy_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; data[ei++] = mib->dl_cck_cnt; data[ei++] = mib->dl_ofdm_cnt; data[ei++] = mib->dl_htmix_cnt; data[ei++] = mib->dl_htgf_cnt; data[ei++] = mib->dl_vht_su_cnt; data[ei++] = mib->dl_vht_2mu_cnt; data[ei++] = mib->dl_vht_3mu_cnt; data[ei++] = mib->dl_vht_4mu_cnt; data[ei++] = mib->dl_he_su_cnt; data[ei++] = mib->dl_he_ext_su_cnt; data[ei++] = mib->dl_he_2ru_cnt; data[ei++] = mib->dl_he_2mu_cnt; data[ei++] = mib->dl_he_3ru_cnt; data[ei++] = mib->dl_he_3mu_cnt; data[ei++] = mib->dl_he_4ru_cnt; data[ei++] = mib->dl_he_4mu_cnt; data[ei++] = mib->dl_he_5to8ru_cnt; data[ei++] = mib->dl_he_9to16ru_cnt; data[ei++] = mib->dl_he_gtr16ru_cnt; data[ei++] = mib->ul_hetrig_su_cnt; data[ei++] = mib->ul_hetrig_2ru_cnt; data[ei++] = mib->ul_hetrig_3ru_cnt; data[ei++] = mib->ul_hetrig_4ru_cnt; data[ei++] = mib->ul_hetrig_5to8ru_cnt; data[ei++] = mib->ul_hetrig_9to16ru_cnt; data[ei++] = mib->ul_hetrig_gtr16ru_cnt; data[ei++] = mib->ul_hetrig_2mu_cnt; data[ei++] = mib->ul_hetrig_3mu_cnt; data[ei++] = mib->ul_hetrig_4mu_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; mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei); stats_size = MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count(); if (ei != stats_size) dev_err(dev->mt76.dev, "ei: %d size: %d", ei, stats_size); } 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); } +static int +mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val) +{ + return 0; +} + static int mt7915_set_radar_background(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; int ret = -EINVAL; bool running; mutex_lock(&dev->mt76.mutex); if (dev->mt76.region == NL80211_DFS_UNSET) goto out; if (dev->rdd2_phy && dev->rdd2_phy != phy) { /* rdd2 is already locked */ ret = -EBUSY; goto out; } /* rdd2 already configured on a radar channel */ running = dev->rdd2_phy && cfg80211_chandef_valid(&dev->rdd2_chandef) && !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); if (!chandef || running || !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { ret = mt7915_mcu_rdd_background_enable(phy, NULL); if (ret) goto out; if (!running) goto update_phy; } ret = mt7915_mcu_rdd_background_enable(phy, chandef); if (ret) goto out; update_phy: dev->rdd2_phy = chandef ? phy : NULL; if (chandef) dev->rdd2_chandef = *chandef; out: mutex_unlock(&dev->mt76.mutex); return ret; } #ifdef CONFIG_NET_MEDIATEK_SOC_WED static int mt7915_net_fill_forward_path(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct net_device_path_ctx *ctx, struct net_device_path *path) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mtk_wed_device *wed = &dev->mt76.mmio.wed; if (!mtk_wed_device_active(wed)) return -ENODEV; if (msta->wcid.idx > 0xff) return -EIO; path->type = DEV_PATH_MTK_WDMA; path->dev = ctx->dev; path->mtk_wdma.wdma_idx = wed->wdma_idx; path->mtk_wdma.bss = mvif->mt76.idx; path->mtk_wdma.wcid = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff; path->mtk_wdma.queue = phy != &dev->phy; ctx->dev = NULL; return 0; } #endif +static void +mt7915_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + + ieee80211_wake_queues(hw); + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT7915_WATCHDOG_TIME); +} + const struct ieee80211_ops mt7915_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mt7915_tx, .start = mt7915_start, .stop = mt7915_stop, .add_interface = mt7915_add_interface, .remove_interface = mt7915_remove_interface, .config = mt7915_config, .conf_tx = mt7915_conf_tx, .configure_filter = mt7915_configure_filter, .bss_info_changed = mt7915_bss_info_changed, .start_ap = mt7915_start_ap, .stop_ap = mt7915_stop_ap, - .sta_add = mt7915_sta_add, - .sta_remove = mt7915_sta_remove, + .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7915_sta_rc_update, + .link_sta_rc_update = mt7915_sta_rc_update, .set_key = mt7915_set_key, .ampdu_action = mt7915_ampdu_action, .set_rts_threshold = mt7915_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76_sw_scan_complete, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .set_sar_specs = mt7915_set_sar_specs, .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, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7915_set_antenna, .set_bitrate_mask = mt7915_set_bitrate_mask, .set_coverage_class = mt7915_set_coverage_class, .sta_statistics = mt7915_sta_statistics, .sta_set_txpwr = mt7915_sta_set_txpwr, .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, + .set_frag_threshold = mt7915_set_frag_threshold, CFG80211_TESTMODE_CMD(mt76_testmode_cmd) CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = mt7915_sta_add_debugfs, #endif .set_radar_background = mt7915_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7915_net_fill_forward_path, + .net_setup_tc = mt76_wed_net_setup_tc, #endif + .reconfig_complete = mt7915_reconfig_complete, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7915/mcu.c index cc13f1725a8b..03dfe2ed4682 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/mcu.c @@ -1,3874 +1,4017 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include "mt7915.h" #include "mcu.h" #include "mac.h" #include "eeprom.h" #define fw_name(_dev, name, ...) ({ \ char *_fw; \ switch (mt76_chip(&(_dev)->mt76)) { \ case 0x7915: \ _fw = MT7915_##name; \ break; \ case 0x7981: \ _fw = MT7981_##name; \ break; \ case 0x7986: \ _fw = MT7986_##name##__VA_ARGS__; \ break; \ default: \ _fw = MT7916_##name; \ break; \ } \ _fw; \ }) #define fw_name_var(_dev, name) (mt7915_check_adie(dev, false) ? \ fw_name(_dev, name) : \ fw_name(_dev, name, _MT7975)) #define MCU_PATCH_ADDRESS 0x200000 #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) static bool sr_scene_detect = true; module_param(sr_scene_detect, bool, 0644); MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm"); static u8 mt7915_mcu_get_sta_nss(u16 mcs_map) { u8 nss; for (nss = 8; nss > 0; nss--) { u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3; if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) break; } return nss - 1; } static void mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, u16 mcs_map) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = msta->vif->phy->dev; enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs; int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; for (nss = 0; nss < max_nss; nss++) { int mcs; switch ((mcs_map >> (2 * nss)) & 0x3) { case IEEE80211_HE_MCS_SUPPORT_0_11: mcs = GENMASK(11, 0); break; case IEEE80211_HE_MCS_SUPPORT_0_9: mcs = GENMASK(9, 0); break; case IEEE80211_HE_MCS_SUPPORT_0_7: mcs = GENMASK(7, 0); break; default: mcs = 0; } mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1; switch (mcs) { case 0 ... 7: mcs = IEEE80211_HE_MCS_SUPPORT_0_7; break; case 8 ... 9: mcs = IEEE80211_HE_MCS_SUPPORT_0_9; break; case 10 ... 11: mcs = IEEE80211_HE_MCS_SUPPORT_0_11; break; default: mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; break; } mcs_map &= ~(0x3 << (nss * 2)); mcs_map |= mcs << (nss * 2); /* only support 2ss on 160MHz for mt7915 */ if (is_mt7915(&dev->mt76) && nss > 1 && sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) break; } *he_mcs = cpu_to_le16(mcs_map); } static void mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, const u16 *mask) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = msta->vif->phy->dev; u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; u16 mcs; for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) { switch (mcs_map & 0x3) { case IEEE80211_VHT_MCS_SUPPORT_0_9: mcs = GENMASK(9, 0); break; case IEEE80211_VHT_MCS_SUPPORT_0_8: mcs = GENMASK(8, 0); break; case IEEE80211_VHT_MCS_SUPPORT_0_7: mcs = GENMASK(7, 0); break; default: mcs = 0; } vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]); /* only support 2ss on 160MHz for mt7915 */ if (is_mt7915(&dev->mt76) && nss > 1 && sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) break; } } static void mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, const u8 *mask) { int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; for (nss = 0; nss < max_nss; nss++) ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss]; } static int mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt76_connac2_mcu_rxd *rxd; int ret = 0; if (!skb) { dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); + + if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { + dev->recovery.restart = true; + wake_up(&dev->mt76.mcu.wait); + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } + return -ETIMEDOUT; } rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (seq != rxd->seq && !(rxd->eid == MCU_CMD_EXT_CID && rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT)) return -EAGAIN; if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { skb_pull(skb, sizeof(*rxd) + 4); ret = le32_to_cpu(*(__le32 *)skb->data); } else { skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); } return ret; } +static void +mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd) +{ + if ((cmd & __MCU_CMD_FIELD_ID) != MCU_CMD_EXT_CID) + return; + + switch (FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd)) { + case MCU_EXT_CMD_THERMAL_CTRL: + case MCU_EXT_CMD_GET_MIB_INFO: + case MCU_EXT_CMD_PHY_STAT_INFO: + case MCU_EXT_CMD_STA_REC_UPDATE: + case MCU_EXT_CMD_BSS_INFO_UPDATE: + mdev->mcu.timeout = 2 * HZ; + return; + default: + break; + } +} + static int mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); enum mt76_mcuq_id qid; - int ret; - - ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq); - if (ret) - return ret; if (cmd == MCU_CMD(FW_SCATTER)) qid = MT_MCUQ_FWDL; else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WA; else qid = MT_MCUQ_WM; + mt7915_mcu_set_timeout(mdev, cmd); + return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0); } int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) { struct { __le32 args[3]; } req = { .args = { cpu_to_le32(a1), cpu_to_le32(a2), cpu_to_le32(a3), }, }; return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false); } static void mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->bss_conf.csa_active) - ieee80211_csa_finish(vif); + if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) + return; + + ieee80211_csa_finish(vif, 0); } static void mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_mcu_csa_notify *c; c = (struct mt7915_mcu_csa_notify *)skb->data; if (c->band_idx > MT_BAND1) return; if ((c->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7915_mcu_csa_finish, mphy->hw); } static void mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_mcu_thermal_notify *t; struct mt7915_phy *phy; t = (struct mt7915_mcu_thermal_notify *)skb->data; if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) return; if (t->ctrl.band_idx > MT_BAND1) return; if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; - phy = (struct mt7915_phy *)mphy->priv; + phy = mphy->priv; phy->throttle_state = t->ctrl.duty.duty_cycle; } static void mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_mcu_rdd_report *r; r = (struct mt7915_mcu_rdd_report *)skb->data; if (r->band_idx > MT_RX_SEL2) return; if ((r->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (r->band_idx == MT_RX_SEL2) cfg80211_background_radar_event(mphy->hw->wiphy, &dev->rdd2_chandef, GFP_ATOMIC); else - ieee80211_radar_detected(mphy->hw); + ieee80211_radar_detected(mphy->hw, NULL); dev->hw_pattern++; } static void mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; int len = skb->len - sizeof(*rxd); const char *data, *type; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; data = (char *)&rxd[1]; switch (rxd->s2d_index) { case 0: #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS) if (mt7915_debugfs_rx_log(dev, data, len)) return; #endif type = "WM"; break; case 2: type = "WA"; break; default: type = "unknown"; break; } wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); } static void mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (!vif->bss_conf.color_change_active) + if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) return; - ieee80211_color_change_finish(vif); + ieee80211_color_change_finish(vif, 0); } static void mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_mcu_bcc_notify *b; b = (struct mt7915_mcu_bcc_notify *)skb->data; if (b->band_idx > MT_BAND1) return; if ((b->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7915_mcu_cca_finish, mphy->hw); } static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->ext_eid) { case MCU_EXT_EVENT_THERMAL_PROTECT: mt7915_mcu_rx_thermal_notify(dev, skb); break; case MCU_EXT_EVENT_RDD_REPORT: mt7915_mcu_rx_radar_detected(dev, skb); break; case MCU_EXT_EVENT_CSA_NOTIFY: mt7915_mcu_rx_csa_notify(dev, skb); break; case MCU_EXT_EVENT_FW_LOG_2_HOST: mt7915_mcu_rx_log_message(dev, skb); break; case MCU_EXT_EVENT_BCC_NOTIFY: mt7915_mcu_rx_bcc_notify(dev, skb); break; default: break; } } static void mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_EXT: mt7915_mcu_rx_ext_event(dev, skb); break; default: break; } dev_kfree_skb(skb); } void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY || !rxd->seq) && !(rxd->eid == MCU_CMD_EXT_CID && rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT)) mt7915_mcu_rx_unsolicited_event(dev, skb); else mt76_mcu_rx_event(&dev->mt76, skb); } static struct tlv * mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len, __le16 *sub_ntlv, __le16 *len) { struct tlv *ptlv, tlv = { .tag = cpu_to_le16(sub_tag), .len = cpu_to_le16(sub_len), }; - ptlv = skb_put(skb, sub_len); + ptlv = skb_put_zero(skb, sub_len); memcpy(ptlv, &tlv, sizeof(tlv)); le16_add_cpu(sub_ntlv, 1); le16_add_cpu(len, sub_len); return ptlv; } /** bss info **/ struct mt7915_he_obss_narrow_bw_ru_data { bool tolerated; }; static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, struct cfg80211_bss *bss, void *_data) { struct mt7915_he_obss_narrow_bw_ru_data *data = _data; const struct element *elem; rcu_read_lock(); elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY); if (!elem || elem->datalen <= 10 || !(elem->data[10] & WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) data->tolerated = false; rcu_read_unlock(); } static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7915_he_obss_narrow_bw_ru_data iter_data = { .tolerated = true, }; - if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) + if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) return false; - cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef, + cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper, mt7915_check_he_obss_narrow_bw_ru_iter, &iter_data); /* * If there is at least one AP on radar channel that cannot * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU. */ return !iter_data.tolerated; } static void mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct bss_info_rf_ch *ch; struct tlv *tlv; int freq1 = chandef->center_freq1; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch)); ch = (struct bss_info_rf_ch *)tlv; ch->pri_ch = chandef->chan->hw_value; ch->center_ch0 = ieee80211_frequency_to_channel(freq1); ch->bw = mt76_connac_chan_bw(chandef); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; ch->center_ch1 = ieee80211_frequency_to_channel(freq2); } if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) { struct mt76_phy *mphy = phy->mt76; ch->he_ru26_block = mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif); ch->he_all_disable = false; } else { ch->he_all_disable = true; } } static void mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { int max_nss = hweight8(phy->mt76->antenna_mask); struct bss_info_ra *ra; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra)); ra = (struct bss_info_ra *)tlv; ra->op_mode = vif->type == NL80211_IFTYPE_AP; ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC; ra->short_preamble = true; ra->tx_streams = max_nss; ra->rx_streams = max_nss; ra->algo = 4; ra->train_up_rule = 2; ra->train_up_high_thres = 110; ra->train_up_rule_rssi = -70; ra->low_traffic_thres = 2; ra->phy_cap = cpu_to_le32(0xfdf); ra->interval = cpu_to_le32(500); ra->fast_interval = cpu_to_le32(100); } static void mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { #define DEFAULT_HE_PE_DURATION 4 #define DEFAULT_HE_DURATION_RTS_THRES 1023 const struct ieee80211_sta_he_cap *cap; struct bss_info_he *he; struct tlv *tlv; cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he)); he = (struct bss_info_he *)tlv; he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; if (!he->he_pe_duration) he->he_pe_duration = DEFAULT_HE_PE_DURATION; he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); if (!he->he_rts_thres) he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; } static void mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb) { #define TXD_CMP_MAP1 GENMASK(15, 0) #define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23)) struct bss_info_hw_amsdu *amsdu; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu)); amsdu = (struct bss_info_hw_amsdu *)tlv; amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1); amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2); amsdu->trig_thres = cpu_to_le16(2); amsdu->enable = true; } static void mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy) { struct bss_info_bmc_rate *bmc; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; enum nl80211_band band = chandef->chan->band; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc)); bmc = (struct bss_info_bmc_rate *)tlv; if (band == NL80211_BAND_2GHZ) { bmc->short_preamble = true; } else { bmc->bc_trans = cpu_to_le16(0x2000); bmc->mc_trans = cpu_to_le16(0x2080); } } static int mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bssid, bool enable) { struct mt7915_dev *dev = phy->dev; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START; u32 mask = phy->omac_mask >> 32 & ~BIT(idx); const u8 *addr = vif->addr; struct { u8 mode; u8 force_clear; u8 clear_bitmap[8]; u8 entry_count; u8 write; u8 band; u8 index; u8 bssid; u8 addr[ETH_ALEN]; } __packed req = { .mode = !!mask || enable, .entry_count = 1, .write = 1, .band = phy->mt76->band_idx, .index = idx * 2 + bssid, }; if (bssid) addr = vif->bss_conf.bssid; if (enable) ether_addr_copy(req.addr, addr); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req, sizeof(req), true); } int mt7915_mcu_add_bss_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, int enable) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = phy->dev; struct sk_buff *skb; if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) { mt7915_mcu_muar_config(phy, vif, false, enable); mt7915_mcu_muar_config(phy, vif, true, enable); } skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL, MT7915_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* bss_omac must be first */ if (enable) mt76_connac_mcu_bss_omac_tlv(skb, vif); mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76, mvif->sta.wcid.idx, enable); if (vif->type == NL80211_IFTYPE_MONITOR) goto out; if (enable) { mt7915_mcu_bss_rfch_tlv(skb, vif, phy); mt7915_mcu_bss_bmc_tlv(skb, phy); mt7915_mcu_bss_ra_tlv(skb, vif, phy); mt7915_mcu_bss_hw_amsdu_tlv(skb); if (vif->bss_conf.he_support) mt7915_mcu_bss_he_tlv(skb, vif, phy); if (mvif->mt76.omac_idx >= EXT_BSSID_START && mvif->mt76.omac_idx < REPEATER_BSSID_START) mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76); } out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(BSS_INFO_UPDATE), true); } /** starec & wtbl **/ int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; struct mt7915_vif *mvif = msta->vif; + int ret; + mt76_worker_disable(&dev->mt76.tx_worker); if (enable && !params->amsdu) msta->wcid.amsdu = false; + ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, + MCU_EXT_CMD(STA_REC_UPDATE), + enable, true); + mt76_worker_enable(&dev->mt76.tx_worker); - return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - MCU_EXT_CMD(STA_REC_UPDATE), - enable, true); + return ret; } int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv; struct mt7915_vif *mvif = msta->vif; return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, MCU_EXT_CMD(STA_REC_UPDATE), enable, false); } static void mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; struct ieee80211_he_mcs_nss_supp mcs_map; struct sta_rec_he *he; struct tlv *tlv; u32 cap = 0; if (!sta->deflink.he_cap.has_he) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he)); he = (struct sta_rec_he *)tlv; if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE) cap |= STA_REC_HE_CAP_HTC; if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR) cap |= STA_REC_HE_CAP_BSR; if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) cap |= STA_REC_HE_CAP_OM; if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU) cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) cap |= STA_REC_HE_CAP_BQR; if (elem->phy_cap_info[0] & (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G)) cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT; if (mvif->cap.he_ldpc && (elem->phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) cap |= STA_REC_HE_CAP_LDPC; if (elem->phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US) cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US) cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ) cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC; if (elem->phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC; if (elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB) cap |= STA_REC_HE_CAP_TRIG_CQI_FK; if (elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE) cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ) cap |= STA_REC_HE_CAP_GT_80M_TX_STBC; if (elem->phy_cap_info[7] & IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ) cap |= STA_REC_HE_CAP_GT_80M_RX_STBC; if (elem->phy_cap_info[8] & IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI; if (elem->phy_cap_info[8] & IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI) cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI; if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU) cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242; if (elem->phy_cap_info[9] & IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU) cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242; he->he_cap = cpu_to_le32(cap); mcs_map = sta->deflink.he_cap.he_mcs_nss_supp; switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW8080], le16_to_cpu(mcs_map.rx_mcs_80p80)); mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW160], le16_to_cpu(mcs_map.rx_mcs_160)); fallthrough; default: mt7915_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW80], le16_to_cpu(mcs_map.rx_mcs_80)); break; } he->t_frame_dur = HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); he->max_ampdu_exp = HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]); he->bw_set = HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]); he->device_class = HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]); he->punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); he->dcm_tx_mode = HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]); he->dcm_tx_max_nss = HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]); he->dcm_rx_mode = HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); he->pkt_ext = 2; } static void mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; struct sta_rec_muru *muru; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); muru = (struct sta_rec_muru *)tlv; muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer || mvif->cap.vht_mu_ebfer || mvif->cap.vht_mu_ebfee; if (!is_mt7915(&dev->mt76)) muru->cfg.mimo_ul_en = true; muru->cfg.ofdma_dl_en = true; if (sta->deflink.vht_cap.vht_supported) muru->mimo_dl.vht_mu_bfee = !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); if (!sta->deflink.he_cap.has_he) return; muru->mimo_dl.partial_bw_dl_mimo = HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); muru->mimo_ul.full_ul_mimo = HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); muru->mimo_ul.partial_ul_mimo = HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); muru->ofdma_dl.punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); muru->ofdma_dl.he_20m_in_40m_2g = HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); muru->ofdma_dl.he_20m_in_160m = HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); muru->ofdma_dl.he_80m_in_160m = HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); muru->ofdma_ul.t_frame_dur = HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); muru->ofdma_ul.mu_cascading = HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); muru->ofdma_ul.uo_ra = HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); + muru->ofdma_ul.rx_ctrl_frame_to_mbss = + HE_MAC(CAP3_RX_CTRL_FRAME_TO_MULTIBSS, elem->mac_cap_info[3]); } static void mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct sta_rec_ht *ht; struct tlv *tlv; if (!sta->deflink.ht_cap.ht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); ht = (struct sta_rec_ht *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); } static void mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct sta_rec_vht *vht; struct tlv *tlv; if (!sta->deflink.vht_cap.vht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); vht = (struct sta_rec_vht *)tlv; vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; } static void mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct sta_rec_amsdu *amsdu; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return; if (!sta->deflink.agg.max_amsdu_len) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); amsdu = (struct sta_rec_amsdu *)tlv; amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; msta->wcid.amsdu = true; switch (sta->deflink.agg.max_amsdu_len) { case IEEE80211_MAX_MPDU_LEN_VHT_11454: if (!is_mt7915(&dev->mt76)) { amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; return; } fallthrough; case IEEE80211_MAX_MPDU_LEN_HT_7935: case IEEE80211_MAX_MPDU_LEN_VHT_7991: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; return; default: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; return; } } static int mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta; struct wtbl_req_hdr *wtbl_hdr; struct mt76_wcid *wcid; struct tlv *tlv; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; wcid = sta ? &msta->wcid : NULL; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid, WTBL_RESET_AND_SET, tlv, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv, wtbl_hdr); mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr); if (sta) mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv, wtbl_hdr, mvif->cap.ht_ldpc, mvif->cap.vht_ldpc); return 0; } static inline bool mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool bfee) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - int tx_ant = hweight8(phy->mt76->chainmask) - 1; + int sts = hweight16(phy->mt76->chainmask); if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return false; - if (!bfee && tx_ant < 2) + if (!bfee && sts < 2) return false; if (sta->deflink.he_cap.has_he) { struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; if (bfee) return mvif->cap.he_su_ebfee && HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); else return mvif->cap.he_su_ebfer && HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); } if (sta->deflink.vht_cap.vht_supported) { u32 cap = sta->deflink.vht_cap.cap; if (bfee) return mvif->cap.vht_su_ebfee && (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); else return mvif->cap.vht_su_ebfer && (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); } return false; } static void mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf) { bf->sounding_phy = MT_PHY_TYPE_OFDM; bf->ndp_rate = 0; /* mcs0 */ bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT; /* ofdm 24m */ } static void mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy, struct sta_rec_bf *bf) { struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs; u8 n = 0; bf->tx_mode = MT_PHY_TYPE_HT; if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) && (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, mcs->tx_params); else if (mcs->rx_mask[3]) n = 3; else if (mcs->rx_mask[2]) n = 2; else if (mcs->rx_mask[1]) n = 1; bf->nrow = hweight8(phy->mt76->chainmask) - 1; bf->ncol = min_t(u8, bf->nrow, n); bf->ibf_ncol = n; } static void mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy, struct sta_rec_bf *bf, bool explicit) { struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); u8 tx_ant = hweight8(phy->mt76->chainmask) - 1; bf->tx_mode = MT_PHY_TYPE_VHT; if (explicit) { u8 sts, snd_dim; mt7915_mcu_sta_sounding_rate(bf); sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, pc->cap); snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, vc->cap); bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant); bf->ncol = min_t(u8, nss_mcs, bf->nrow); bf->ibf_ncol = bf->ncol; if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) bf->nrow = 1; } else { bf->nrow = tx_ant; bf->ncol = min_t(u8, nss_mcs, bf->nrow); bf->ibf_ncol = nss_mcs; if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) bf->ibf_nrow = 1; } } static void mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, struct mt7915_phy *phy, struct sta_rec_bf *bf) { struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap; struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; const struct ieee80211_sta_he_cap *vc = mt76_connac_get_he_phy_cap(phy->mt76, vif); const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); u8 snd_dim, sts; bf->tx_mode = MT_PHY_TYPE_HE_SU; mt7915_mcu_sta_sounding_rate(bf); bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB, pe->phy_cap_info[6]); bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB, pe->phy_cap_info[6]); snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, ve->phy_cap_info[5]); sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, pe->phy_cap_info[4]); bf->nrow = min_t(u8, snd_dim, sts); bf->ncol = min_t(u8, nss_mcs, bf->nrow); bf->ibf_ncol = bf->ncol; if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160) return; /* go over for 160MHz and 80p80 */ if (pe->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); bf->ncol_gt_bw80 = nss_mcs; } if (pe->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); if (bf->ncol_gt_bw80) bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs); else bf->ncol_gt_bw80 = nss_mcs; } snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, ve->phy_cap_info[5]); sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, pe->phy_cap_info[4]); bf->nrow_gt_bw80 = min_t(int, snd_dim, sts); } static void mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_phy *phy = mvif->phy; int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bf *bf; struct tlv *tlv; - const u8 matrix[4][4] = { + static const u8 matrix[4][4] = { {0, 0, 0, 0}, {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ }; bool ebf; if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) return; ebf = mt7915_is_ebf_supported(phy, vif, sta, false); if (!ebf && !dev->ibf) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); bf = (struct sta_rec_bf *)tlv; /* he: eBF only, in accordance with spec * vht: support eBF and iBF * ht: iBF only, since mac80211 lacks of eBF support */ if (sta->deflink.he_cap.has_he && ebf) mt7915_mcu_sta_bfer_he(sta, vif, phy, bf); else if (sta->deflink.vht_cap.vht_supported) mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf); else if (sta->deflink.ht_cap.ht_supported) mt7915_mcu_sta_bfer_ht(sta, phy, bf); else return; bf->bf_cap = ebf ? ebf : dev->ibf << 1; bf->bw = sta->deflink.bandwidth; bf->ibf_dbw = sta->deflink.bandwidth; bf->ibf_nrow = tx_ant; if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) bf->ibf_timeout = 0x48; else bf->ibf_timeout = 0x18; if (ebf && bf->nrow != tx_ant) bf->mem_20m = matrix[tx_ant][bf->ncol]; else bf->mem_20m = matrix[bf->nrow][bf->ncol]; switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: case IEEE80211_STA_RX_BW_80: bf->mem_total = bf->mem_20m * 2; break; case IEEE80211_STA_RX_BW_40: bf->mem_total = bf->mem_20m; break; case IEEE80211_STA_RX_BW_20: default: break; } } static void mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_phy *phy = mvif->phy; int tx_ant = hweight8(phy->mt76->chainmask) - 1; struct sta_rec_bfee *bfee; struct tlv *tlv; u8 nrow = 0; if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he)) return; if (!mt7915_is_ebf_supported(phy, vif, sta, true)) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); bfee = (struct sta_rec_bfee *)tlv; if (sta->deflink.he_cap.has_he) { struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, pe->phy_cap_info[5]); } else if (sta->deflink.vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, pc->cap); } /* reply with identity matrix to avoid 2x2 BF negative gain */ bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } static enum mcu_mmps_mode mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps) { switch (smps) { case IEEE80211_SMPS_OFF: return MCU_MMPS_DISABLE; case IEEE80211_SMPS_STATIC: return MCU_MMPS_STATIC; case IEEE80211_SMPS_DYNAMIC: return MCU_MMPS_DYNAMIC; default: return MCU_MMPS_DISABLE; } } int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *data, u32 field) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct sta_phy *phy = data; struct sta_rec_ra_fixed *ra; struct sk_buff *skb; struct tlv *tlv; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); ra = (struct sta_rec_ra_fixed *)tlv; switch (field) { case RATE_PARAM_AUTO: break; case RATE_PARAM_FIXED: case RATE_PARAM_FIXED_MCS: case RATE_PARAM_FIXED_GI: case RATE_PARAM_FIXED_HE_LTF: if (phy) ra->phy = *phy; break; case RATE_PARAM_MMPS_UPDATE: ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); break; case RATE_PARAM_SPE_UPDATE: ra->spe_idx = *(u8 *)data; break; default: break; } ra->field = cpu_to_le32(field); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; int ret; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->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->mt76, &msta->wcid, WTBL_SET, sta_wtbl, &skb); if (IS_ERR(wtbl_hdr)) return PTR_ERR(wtbl_hdr); mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); if (ret) return ret; return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL, RATE_PARAM_MMPS_UPDATE); } static int mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt76_phy *mphy = mvif->phy->mt76; u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx, RATE_PARAM_SPE_UPDATE); } static int mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; struct sta_phy phy = {}; int ret, nrates = 0; #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ do { \ u8 i, gi = mask->control[band]._gi; \ gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \ for (i = 0; i <= sta->deflink.bandwidth; i++) { \ phy.sgi |= gi << (i << (_he)); \ phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\ } \ for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \ if (!mask->control[band]._mcs[i]) \ continue; \ nrates += hweight16(mask->control[band]._mcs[i]); \ phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \ if (_ht) \ phy.mcs += 8 * i; \ } \ } while (0) if (sta->deflink.he_cap.has_he) { __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1); } else if (sta->deflink.vht_cap.vht_supported) { __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0); } else if (sta->deflink.ht_cap.ht_supported) { __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0); } else { nrates = hweight32(mask->control[band].legacy); phy.mcs = ffs(mask->control[band].legacy) - 1; } #undef __sta_phy_bitrate_mask_check /* fall back to auto rate control */ if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI && mask->control[band].he_gi == GENMASK(7, 0) && mask->control[band].he_ltf == GENMASK(7, 0) && nrates != 1) return 0; /* fixed single rate */ if (nrates == 1) { ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, RATE_PARAM_FIXED_MCS); if (ret) return ret; } /* fixed GI */ if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI || mask->control[band].he_gi != GENMASK(7, 0)) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; u32 addr; /* firmware updates only TXCMD but doesn't take WTBL into * account, so driver should update here to reflect the * actual txrate hardware sends out. */ addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7); if (sta->deflink.he_cap.has_he) mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi); else mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi); ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, RATE_PARAM_FIXED_GI); if (ret) return ret; } /* fixed HE_LTF */ if (mask->control[band].he_ltf != GENMASK(7, 0)) { ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy, RATE_PARAM_FIXED_HE_LTF); if (ret) return ret; } return mt7915_mcu_set_spe_idx(dev, vif, sta); } static void mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt76_phy *mphy = mvif->phy->mt76; struct cfg80211_chan_def *chandef = &mphy->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; struct sta_rec_ra *ra; struct tlv *tlv; u32 supp_rate = sta->deflink.supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); ra = (struct sta_rec_ra *)tlv; ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta); + ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink); ra->channel = chandef->chan->hw_value; ra->bw = sta->deflink.bandwidth; ra->phy.bw = sta->deflink.bandwidth; ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); if (supp_rate) { supp_rate &= mask->control[band].legacy; ra->rate_len = hweight32(supp_rate); if (band == NL80211_BAND_2GHZ) { ra->supp_mode = MODE_CCK; ra->supp_cck_rate = supp_rate & GENMASK(3, 0); if (ra->rate_len > 4) { ra->supp_mode |= MODE_OFDM; ra->supp_ofdm_rate = supp_rate >> 4; } } else { ra->supp_mode = MODE_OFDM; ra->supp_ofdm_rate = supp_rate; } } if (sta->deflink.ht_cap.ht_supported) { ra->supp_mode |= MODE_HT; ra->af = sta->deflink.ht_cap.ampdu_factor; ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); cap |= STA_CAP_HT; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) cap |= STA_CAP_SGI_20; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) cap |= STA_CAP_SGI_40; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) cap |= STA_CAP_TX_STBC; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) cap |= STA_CAP_RX_STBC; if (mvif->cap.ht_ldpc && (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) cap |= STA_CAP_LDPC; mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mask->control[band].ht_mcs); ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; } if (sta->deflink.vht_cap.vht_supported) { u8 af; ra->supp_mode |= MODE_VHT; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->deflink.vht_cap.cap); ra->af = max_t(u8, ra->af, af); cap |= STA_CAP_VHT; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) cap |= STA_CAP_VHT_SGI_80; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) cap |= STA_CAP_VHT_SGI_160; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) cap |= STA_CAP_VHT_TX_STBC; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) cap |= STA_CAP_VHT_RX_STBC; if (mvif->cap.vht_ldpc && (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) cap |= STA_CAP_VHT_LDPC; mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mask->control[band].vht_mcs); } if (sta->deflink.he_cap.has_he) { ra->supp_mode |= MODE_HE; cap |= STA_CAP_HE; if (sta->deflink.he_6ghz_capa.capa) ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); } ra->sta_cap = cpu_to_le32(cap); } int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct sk_buff *skb; int ret; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); /* firmware rc algorithm refers to sta_rec_he for HE control. * once dev->rc_work changes the settings driver should also * update sta_rec_he here. */ if (changed) mt7915_mcu_sta_he_tlv(skb, sta, vif); /* sta_rec_ra accommodates BW, NSS and only MCS range format * i.e 0-{7,8,9} for VHT. */ mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); if (ret) return ret; /* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE, * and updates as peer fixed rate parameters, which overrides * sta_rec_ra and firmware rate control algorithm. */ return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta); } static int mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { #define MT_STA_BSS_GROUP 1 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta; struct { __le32 action; u8 wlan_idx_lo; u8 status; u8 wlan_idx_hi; u8 rsv0[5]; __le32 val; u8 rsv1[8]; } __packed req = { .action = cpu_to_le32(MT_STA_BSS_GROUP), .val = cpu_to_le32(mvif->mt76.idx % 16), }; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx); req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req, sizeof(req), true); } int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) + struct ieee80211_sta *sta, int conn_state, bool newly) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; struct mt7915_sta *msta; struct sk_buff *skb; int ret; msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta; + link_sta = sta ? &sta->deflink : NULL; skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &msta->wcid); if (IS_ERR(skb)) return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable, - !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx])); - if (!enable) - goto out; - + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta, + conn_state, newly); /* tag order is in accordance with firmware dependency. */ - if (sta) { + if (sta && conn_state != CONN_STATE_DISCONNECT) { /* starec bfer */ mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta); /* starec ht */ mt7915_mcu_sta_ht_tlv(skb, sta); /* starec vht */ mt7915_mcu_sta_vht_tlv(skb, sta); /* starec uapsd */ mt76_connac_mcu_sta_uapsd(skb, vif, sta); } - ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta); - if (ret) { - dev_kfree_skb(skb); - return ret; + if (newly || conn_state != CONN_STATE_DISCONNECT) { + ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta); + if (ret) { + dev_kfree_skb(skb); + return ret; + } } + if (conn_state == CONN_STATE_DISCONNECT) + goto out; + if (sta) { /* starec amsdu */ mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta); /* starec he */ mt7915_mcu_sta_he_tlv(skb, sta, vif); /* starec muru */ mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif); /* starec bfee */ mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta); } ret = mt7915_mcu_add_group(dev, vif, sta); if (ret) { dev_kfree_skb(skb); return ret; } out: ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); if (ret) return ret; return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED struct mtk_wed_device *wed = &dev->mt76.mmio.wed; struct { __le32 args[2]; } req = { .args[0] = cpu_to_le32(1), .args[1] = cpu_to_le32(6), }; return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL, &req, sizeof(req)); #else return 0; #endif } int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool enable) { struct mt7915_dev *dev = phy->dev; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct { struct req_hdr { u8 omac_idx; u8 band_idx; __le16 tlv_num; u8 is_tlv_append; u8 rsv[3]; } __packed hdr; struct req_tlv { __le16 tag; __le16 len; u8 active; u8 band_idx; u8 omac_addr[ETH_ALEN]; } __packed tlv; } data = { .hdr = { .omac_idx = mvif->mt76.omac_idx, .band_idx = mvif->mt76.band_idx, .tlv_num = cpu_to_le16(1), .is_tlv_append = 1, }, .tlv = { .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, .band_idx = mvif->mt76.band_idx, }, }; if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) return mt7915_mcu_muar_config(phy, vif, false, enable); memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); } static void mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, struct sk_buff *skb, struct bss_info_bcn *bcn, struct ieee80211_mutable_offsets *offs) { struct bss_info_bcn_cntdwn *info; struct tlv *tlv; int sub_tag; if (!offs->cntdwn_counter_offs[0]) return; sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC; tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info), &bcn->sub_ntlv, &bcn->len); info = (struct bss_info_bcn_cntdwn *)tlv; info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; } static void mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, struct ieee80211_vif *vif, struct bss_info_bcn *bcn, struct ieee80211_mutable_offsets *offs) { struct bss_info_bcn_mbss *mbss; const struct element *elem; struct tlv *tlv; if (!vif->bss_conf.bssid_indicator) return; tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID, sizeof(*mbss), &bcn->sub_ntlv, &bcn->len); mbss = (struct bss_info_bcn_mbss *)tlv; mbss->offset[0] = cpu_to_le16(offs->tim_offset); mbss->bitmap = cpu_to_le32(1); for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, &skb->data[offs->mbssid_off], skb->len - offs->mbssid_off) { const struct element *sub_elem; if (elem->datalen < 2) continue; for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) { const struct ieee80211_bssid_index *idx; const u8 *idx_ie; if (sub_elem->id || sub_elem->datalen < 4) continue; /* not a valid BSS profile */ /* Find WLAN_EID_MULTI_BSSID_IDX * in the merged nontransmitted profile */ idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, sub_elem->data, sub_elem->datalen); if (!idx_ie || idx_ie[1] < sizeof(*idx)) continue; #if defined(__linux__) idx = (void *)(idx_ie + 2); #elif defined(__FreeBSD__) idx = (const void *)(idx_ie + 2); #endif if (!idx->bssid_index || idx->bssid_index > 31) continue; mbss->offset[idx->bssid_index] = cpu_to_le16(idx_ie - skb->data); mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index)); } } } static void mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct sk_buff *rskb, struct sk_buff *skb, struct bss_info_bcn *bcn, struct ieee80211_mutable_offsets *offs) { struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct bss_info_bcn_cont *cont; struct tlv *tlv; u8 *buf; int len = sizeof(*cont) + MT_TXD_SIZE + skb->len; len = (len & 0x3) ? ((len | 0x3) + 1) : len; tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT, len, &bcn->sub_ntlv, &bcn->len); cont = (struct bss_info_bcn_cont *)tlv; cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); cont->tim_ofs = cpu_to_le16(offs->tim_offset); if (offs->cntdwn_counter_offs[0]) { u16 offset = offs->cntdwn_counter_offs[0]; if (vif->bss_conf.csa_active) cont->csa_ofs = cpu_to_le16(offset - 4); if (vif->bss_conf.color_change_active) cont->bcc_ofs = cpu_to_le16(offset - 3); } buf = (u8 *)tlv + sizeof(*cont); mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, 0, BSS_CHANGED_BEACON); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } -static void -mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif, - struct sk_buff *rskb, struct bss_info_bcn *bcn, - u32 changed) +int +mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif, + u32 changed) { #define OFFLOAD_TX_MODE_SU BIT(0) #define OFFLOAD_TX_MODE_MU BIT(1) struct ieee80211_hw *hw = mt76_hw(dev); struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; enum nl80211_band band = chandef->chan->band; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct bss_info_bcn *bcn; struct bss_info_inband_discovery *discov; struct ieee80211_tx_info *info; - struct sk_buff *skb = NULL; - struct tlv *tlv; + struct sk_buff *rskb, *skb = NULL; + struct tlv *tlv, *sub_tlv; bool ext_phy = phy != &dev->phy; u8 *buf, interval; int len; - if (changed & BSS_CHANGED_FILS_DISCOVERY && - vif->bss_conf.fils_discovery.max_interval) { + if (vif->bss_conf.nontransmitted) + return 0; + + rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL, + MT7915_MAX_BSS_OFFLOAD_SIZE); + if (IS_ERR(rskb)) + return PTR_ERR(rskb); + + tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); + bcn = (struct bss_info_bcn *)tlv; + bcn->enable = true; + + if (changed & BSS_CHANGED_FILS_DISCOVERY) { interval = vif->bss_conf.fils_discovery.max_interval; skb = ieee80211_get_fils_discovery_tmpl(hw, vif); } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP && vif->bss_conf.unsol_bcast_probe_resp_interval) { interval = vif->bss_conf.unsol_bcast_probe_resp_interval; skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif); } - if (!skb) - return; + if (!skb) { + dev_kfree_skb(rskb); + return -EINVAL; + } info = IEEE80211_SKB_CB(skb); info->control.vif = vif; info->band = band; - info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); len = sizeof(*discov) + MT_TXD_SIZE + skb->len; len = (len & 0x3) ? ((len | 0x3) + 1) : len; - if (len > (MT7915_MAX_BSS_OFFLOAD_SIZE - rskb->len)) { + if (skb->len > MT7915_MAX_BEACON_SIZE) { dev_err(dev->mt76.dev, "inband discovery size limit exceed\n"); + dev_kfree_skb(rskb); dev_kfree_skb(skb); - return; + return -EINVAL; } - tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV, - len, &bcn->sub_ntlv, &bcn->len); - discov = (struct bss_info_inband_discovery *)tlv; + sub_tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV, + len, &bcn->sub_ntlv, &bcn->len); + discov = (struct bss_info_inband_discovery *)sub_tlv; discov->tx_mode = OFFLOAD_TX_MODE_SU; /* 0: UNSOL PROBE RESP, 1: FILS DISCOV */ discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY); discov->tx_interval = interval; discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len); - discov->enable = true; + discov->enable = !!interval; - buf = (u8 *)tlv + sizeof(*discov); + buf = (u8 *)sub_tlv + sizeof(*discov); mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL, 0, changed); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); dev_kfree_skb(skb); + + return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, + MCU_EXT_CMD(BSS_INFO_UPDATE), true); } int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int en, u32 changed) { 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 ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct sk_buff *skb, *rskb; struct tlv *tlv; struct bss_info_bcn *bcn; int len = MT7915_MAX_BSS_OFFLOAD_SIZE; bool ext_phy = phy != &dev->phy; if (vif->bss_conf.nontransmitted) return 0; rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL, len); if (IS_ERR(rskb)) return PTR_ERR(rskb); tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn)); bcn = (struct bss_info_bcn *)tlv; bcn->enable = en; if (!en) goto out; skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); - if (!skb) + if (!skb) { + dev_kfree_skb(rskb); return -EINVAL; + } - if (skb->len > MT7915_MAX_BEACON_SIZE - MT_TXD_SIZE) { + if (skb->len > MT7915_MAX_BEACON_SIZE) { dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); + dev_kfree_skb(rskb); dev_kfree_skb(skb); return -EINVAL; } info = IEEE80211_SKB_CB(skb); info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy); mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs); mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs); mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); dev_kfree_skb(skb); - if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || - changed & BSS_CHANGED_FILS_DISCOVERY) - mt7915_mcu_beacon_inband_discov(dev, vif, rskb, - bcn, changed); - out: return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, MCU_EXT_CMD(BSS_INFO_UPDATE), true); } static int mt7915_driver_own(struct mt7915_dev *dev, u8 band) { mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN); if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) { dev_err(dev->mt76.dev, "Timeout for driver own\n"); return -EIO; } /* clear irq when the driver own success */ mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band), MT_TOP_LPCR_HOST_BAND_STAT); return 0; } static int mt7915_firmware_state(struct mt7915_dev *dev, bool wa) { u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD); if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE, state, 1000)) { dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } return 0; } static int mt7915_load_firmware(struct mt7915_dev *dev) { int ret; /* make sure fw is download state */ if (mt7915_firmware_state(dev, false)) { /* restart firmware once */ mt76_connac_mcu_restart(&dev->mt76); ret = mt7915_firmware_state(dev, false); if (ret) { dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); return ret; } } ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH)); if (ret) return ret; ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM), fw_name(dev, FIRMWARE_WA)); if (ret) return ret; ret = mt7915_firmware_state(dev, true); if (ret) return ret; mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; } int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl) { struct { u8 ctrl_val; u8 pad[3]; } data = { .ctrl_val = ctrl }; if (type == MCU_FW_LOG_WA) return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST), &data, sizeof(data), true); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data, sizeof(data), true); } int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level) { struct { u8 ver; u8 pad; __le16 len; u8 level; u8 rsv[3]; __le32 module_idx; } data = { .module_idx = cpu_to_le32(module), .level = level, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data, sizeof(data), false); } int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled) { struct { __le32 cmd; u8 enable; } data = { .cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN), .enable = enabled, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data, sizeof(data), false); } int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct sk_buff *skb; struct mt7915_mcu_muru_stats *mu_stats; int ret; struct { __le32 cmd; u8 band_idx; } req = { .cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS), .band_idx = phy->mt76->band_idx, }; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, sizeof(req), true, &skb); if (ret) return ret; mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data); /* accumulate stats, these are clear-on-read */ #define __dl_u32(s) phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s) #define __ul_u32(s) phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s) __dl_u32(cck_cnt); __dl_u32(ofdm_cnt); __dl_u32(htmix_cnt); __dl_u32(htgf_cnt); __dl_u32(vht_su_cnt); __dl_u32(vht_2mu_cnt); __dl_u32(vht_3mu_cnt); __dl_u32(vht_4mu_cnt); __dl_u32(he_su_cnt); __dl_u32(he_2ru_cnt); __dl_u32(he_2mu_cnt); __dl_u32(he_3ru_cnt); __dl_u32(he_3mu_cnt); __dl_u32(he_4ru_cnt); __dl_u32(he_4mu_cnt); __dl_u32(he_5to8ru_cnt); __dl_u32(he_9to16ru_cnt); __dl_u32(he_gtr16ru_cnt); __ul_u32(hetrig_su_cnt); __ul_u32(hetrig_2ru_cnt); __ul_u32(hetrig_3ru_cnt); __ul_u32(hetrig_4ru_cnt); __ul_u32(hetrig_5to8ru_cnt); __ul_u32(hetrig_9to16ru_cnt); __ul_u32(hetrig_gtr16ru_cnt); __ul_u32(hetrig_2mu_cnt); __ul_u32(hetrig_3mu_cnt); __ul_u32(hetrig_4mu_cnt); #undef __dl_u32 #undef __ul_u32 dev_kfree_skb(skb); return 0; } static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled) { struct { u8 enable; u8 _rsv[3]; } __packed req = { .enable = enabled }; return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req, sizeof(req), false); } int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val) { struct { __le32 cmd; u8 val[4]; } __packed req = { .cmd = cpu_to_le32(cmd), }; put_unaligned_le32(val, req.val); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req, sizeof(req), false); } static int mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) { #define RX_AIRTIME_FEATURE_CTRL 1 #define RX_AIRTIME_BITWISE_CTRL 2 #define RX_AIRTIME_CLEAR_EN 1 struct { __le16 field; __le16 sub_field; __le32 set_status; __le32 get_status; u8 _rsv[12]; bool airtime_en; bool mibtime_en; bool earlyend_en; u8 _rsv1[9]; bool airtime_clear; bool mibtime_clear; u8 _rsv2[98]; } __packed req = { .field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL), .sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN), .airtime_clear = true, }; int ret; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, sizeof(req), true); if (ret) return ret; req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL); req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN); req.airtime_en = true; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req, sizeof(req), true); } static int mt7915_red_set_watermark(struct mt7915_dev *dev) { #define RED_GLOBAL_TOKEN_WATERMARK 2 struct { __le32 args[3]; u8 cmd; u8 version; u8 __rsv1[4]; __le16 len; __le16 high_mark; __le16 low_mark; u8 __rsv2[12]; } __packed req = { .args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING), .cmd = RED_GLOBAL_TOKEN_WATERMARK, .len = cpu_to_le16(sizeof(req) - sizeof(req.args)), .high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256), .low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536), }; return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req, sizeof(req), false); } static int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled) { #define RED_DISABLE 0 #define RED_BY_WA_ENABLE 2 int ret; u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE; __le32 req = cpu_to_le32(red_type); if (enabled) { ret = mt7915_red_set_watermark(dev); if (ret < 0) return ret; } ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req, sizeof(req), false); if (ret < 0) return ret; return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, enabled, 0); } int mt7915_mcu_init_firmware(struct mt7915_dev *dev) { 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 = mt7915_driver_own(dev, 0); if (ret) return ret; /* set driver own for band1 when two hif exist */ if (dev->hif2) { ret = mt7915_driver_own(dev, 1); if (ret) return ret; } ret = mt7915_load_firmware(dev); if (ret) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0); if (ret) return ret; ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); if (ret) return ret; + mt76_connac_mcu_del_wtbl_all(&dev->mt76); + if ((mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76)) || !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0); ret = mt7915_mcu_set_mwds(dev, 1); if (ret) return ret; ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE, MURU_PLATFORM_TYPE_PERF_LEVEL_2); if (ret) return ret; ret = mt7915_mcu_init_rx_airtime(dev); if (ret) return ret; return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed)); } int mt7915_mcu_init(struct mt7915_dev *dev) { static const struct mt76_mcu_ops mt7915_mcu_ops = { + .max_retry = 1, .headroom = sizeof(struct mt76_connac2_mcu_txd), + .mcu_skb_prepare_msg = mt76_connac2_mcu_fill_message, .mcu_skb_send_msg = mt7915_mcu_send_message, .mcu_parse_response = mt7915_mcu_parse_response, }; dev->mt76.mcu_ops = &mt7915_mcu_ops; return mt7915_mcu_init_firmware(dev); } void mt7915_mcu_exit(struct mt7915_dev *dev) { mt76_connac_mcu_restart(&dev->mt76); if (mt7915_firmware_state(dev, false)) { dev_err(dev->mt76.dev, "Failed to exit mcu\n"); goto out; } mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN); if (dev->hif2) mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1), MT_TOP_LPCR_HOST_FW_OWN); out: skb_queue_purge(&dev->mt76.mcu.res_q); } static int mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band) { struct { u8 operation; u8 count; u8 _rsv[2]; u8 index; u8 enable; __le16 etype; } req = { .operation = 1, .count = 1, .enable = 1, .etype = cpu_to_le16(ETH_P_PAE), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), &req, sizeof(req), false); } int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, bool hdr_trans) { struct { u8 operation; u8 enable; u8 check_bssid; u8 insert_vlan; u8 remove_vlan; u8 tid; u8 mode; u8 rsv; } __packed req_trans = { .enable = hdr_trans, }; struct { u8 enable; u8 band; u8 rsv[2]; } __packed req_mac = { .enable = enable, .band = band, }; int ret; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS), &req_trans, sizeof(req_trans), false); if (ret) return ret; if (hdr_trans) mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL), &req_mac, sizeof(req_mac), true); } int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param) { struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param; u8 num = req->total; size_t len = sizeof(*req) - (IEEE80211_NUM_ACS - num) * sizeof(struct edca); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req, len, true); } int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) { #define TX_CMD_MODE 1 struct mt7915_mcu_tx req = { .valid = true, .mode = TX_CMD_MODE, .total = IEEE80211_NUM_ACS, }; struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; int ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; struct edca *e = &req.edca[ac]; e->set = WMM_PARAM_SET; e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; e->aifs = q->aifs; e->txop = cpu_to_le16(q->txop); if (q->cw_min) e->cw_min = fls(q->cw_min); else e->cw_min = 5; if (q->cw_max) e->cw_max = cpu_to_le16(fls(q->cw_max)); else e->cw_max = cpu_to_le16(10); } return mt7915_mcu_update_edca(dev, &req); } int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val) { struct { __le32 tag; __le16 min_lpn; u8 rsv[2]; } __packed req = { .tag = cpu_to_le32(0x1), .min_lpn = cpu_to_le16(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, const struct mt7915_dfs_pulse *pulse) { struct { __le32 tag; __le32 max_width; /* us */ __le32 max_pwr; /* dbm */ __le32 min_pwr; /* dbm */ __le32 min_stgr_pri; /* us */ __le32 max_stgr_pri; /* us */ __le32 min_cr_pri; /* us */ __le32 max_cr_pri; /* us */ } __packed req = { .tag = cpu_to_le32(0x3), #define __req_field(field) .field = cpu_to_le32(pulse->field) __req_field(max_width), __req_field(max_pwr), __req_field(min_pwr), __req_field(min_stgr_pri), __req_field(max_stgr_pri), __req_field(min_cr_pri), __req_field(max_cr_pri), #undef __req_field }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index, const struct mt7915_dfs_pattern *pattern) { struct { __le32 tag; __le16 radar_type; u8 enb; u8 stgr; u8 min_crpn; u8 max_crpn; u8 min_crpr; u8 min_pw; __le32 min_pri; __le32 max_pri; u8 max_pw; u8 min_crbn; u8 max_crbn; u8 min_stgpn; u8 max_stgpn; u8 min_stgpr; u8 rsv[2]; __le32 min_stgpr_diff; } __packed req = { .tag = cpu_to_le32(0x2), .radar_type = cpu_to_le16(index), #define __req_field_u8(field) .field = pattern->field #define __req_field_u32(field) .field = cpu_to_le32(pattern->field) __req_field_u8(enb), __req_field_u8(stgr), __req_field_u8(min_crpn), __req_field_u8(max_crpn), __req_field_u8(min_crpr), __req_field_u8(min_pw), __req_field_u32(min_pri), __req_field_u32(max_pri), __req_field_u8(max_pw), __req_field_u8(min_crbn), __req_field_u8(max_crbn), __req_field_u8(min_stgpn), __req_field_u8(max_stgpn), __req_field_u8(min_stgpr), __req_field_u32(min_stgpr_diff), #undef __req_field_u8 #undef __req_field_u32 }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req, sizeof(req), true); } static int mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, struct cfg80211_chan_def *chandef, int cmd) { struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_channel *chan = mphy->chandef.chan; int freq = mphy->chandef.center_freq1; struct mt7915_mcu_background_chain_ctrl req = { .monitor_scan_type = 2, /* simple rx */ }; if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP) return -EINVAL; if (!cfg80211_chandef_valid(&mphy->chandef)) return -EINVAL; switch (cmd) { case CH_SWITCH_BACKGROUND_SCAN_START: { req.chan = chan->hw_value; req.central_chan = ieee80211_frequency_to_channel(freq); req.bw = mt76_connac_chan_bw(&mphy->chandef); req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.monitor_bw = mt76_connac_chan_bw(chandef); req.band_idx = phy->mt76->band_idx; req.scan_mode = 1; break; } case CH_SWITCH_BACKGROUND_SCAN_RUNNING: req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.band_idx = phy->mt76->band_idx; req.scan_mode = 2; break; case CH_SWITCH_BACKGROUND_SCAN_STOP: req.chan = chan->hw_value; req.central_chan = ieee80211_frequency_to_channel(freq); req.bw = mt76_connac_chan_bw(&mphy->chandef); req.tx_stream = hweight8(mphy->antenna_mask); req.rx_stream = mphy->antenna_mask; break; default: return -EINVAL; } req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL), &req, sizeof(req), false); } int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy, struct cfg80211_chan_def *chandef) { struct mt7915_dev *dev = phy->dev; int err, region; if (!chandef) { /* disable offchain */ err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2, 0, 0); if (err) return err; return mt7915_mcu_background_chain_ctrl(phy, NULL, CH_SWITCH_BACKGROUND_SCAN_STOP); } err = mt7915_mcu_background_chain_ctrl(phy, chandef, CH_SWITCH_BACKGROUND_SCAN_START); if (err) return err; switch (dev->mt76.region) { case NL80211_DFS_ETSI: region = 0; break; case NL80211_DFS_JP: region = 2; break; case NL80211_DFS_FCC: default: region = 1; break; } return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2, 0, region); } int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) { static const u8 ch_band[] = { [NL80211_BAND_2GHZ] = 0, [NL80211_BAND_5GHZ] = 1, [NL80211_BAND_6GHZ] = 2, }; struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; u8 band = phy->mt76->band_idx; struct { u8 control_ch; u8 center_ch; u8 bw; u8 tx_path_num; u8 rx_path; /* mask or num */ u8 switch_reason; u8 band_idx; u8 center_ch2; /* for 80+80 only */ __le16 cac_case; u8 channel_band; u8 rsv0; __le32 outband_freq; u8 txpower_drop; u8 ap_bw; u8 ap_center_ch; u8 rsv1[57]; } __packed req = { .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), .band_idx = band, .channel_band = ch_band[chandef->chan->band], }; #ifdef CONFIG_NL80211_TESTMODE if (phy->mt76->test.tx_antenna_mask && mt76_testmode_enabled(phy->mt76)) { req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask); req.rx_path = phy->mt76->test.tx_antenna_mask; } #endif if (mt76_connac_spe_idx(phy->mt76->antenna_mask)) req.tx_path_num = fls(phy->mt76->antenna_mask); - if (cmd == MCU_EXT_CMD(SET_RX_PATH) || - dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) + if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; - else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + else if (phy->mt76->offchannel || + phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, NL80211_IFTYPE_AP)) req.switch_reason = CH_SWITCH_DFS; else req.switch_reason = CH_SWITCH_NORMAL; if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) req.rx_path = hweight8(req.rx_path); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; req.center_ch2 = ieee80211_frequency_to_channel(freq2); } return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) { #define MAX_PAGE_IDX_MASK GENMASK(7, 5) #define PAGE_IDX_MASK GENMASK(4, 2) #define PER_PAGE_SIZE 0x400 struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER }; u16 eeprom_size = mt7915_eeprom_size(dev); u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); u8 *eep = (u8 *)dev->mt76.eeprom.data; int eep_len; int i; for (i = 0; i < total; i++, eep += eep_len) { struct sk_buff *skb; int ret; if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) eep_len = eeprom_size % PER_PAGE_SIZE; else eep_len = PER_PAGE_SIZE; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + eep_len); if (!skb) return -ENOMEM; req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) | FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE; req.len = cpu_to_le16(eep_len); skb_put_data(skb, &req, sizeof(req)); skb_put_data(skb, eep, eep_len); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(EFUSE_BUFFER_MODE), true); if (ret) return ret; } return 0; } int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) { struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_EFUSE, .format = EE_FORMAT_WHOLE, }; if (dev->flash_mode) return mt7915_mcu_set_eeprom_flash(dev); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), &req, sizeof(req), true); } int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) { struct mt7915_mcu_eeprom_info req = { .addr = cpu_to_le32(round_down(offset, MT7915_EEPROM_BLOCK_SIZE)), }; struct mt7915_mcu_eeprom_info *res; struct sk_buff *skb; int ret; u8 *buf; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), &req, sizeof(req), true, &skb); if (ret) return ret; res = (struct mt7915_mcu_eeprom_info *)skb->data; #if defined(__linux__) buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); #elif defined(__FreeBSD__) buf = (u8 *)dev->mt76.eeprom.data + le32_to_cpu(res->addr); #endif memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); dev_kfree_skb(skb); return 0; } int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num) { struct { u8 _rsv; u8 version; u8 die_idx; u8 _rsv2; } __packed req = { .version = 1, }; struct sk_buff *skb; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_FREE_BLOCK), &req, sizeof(req), true, &skb); if (ret) return ret; *block_num = *(u8 *)skb->data; dev_kfree_skb(skb); return 0; } static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx, u8 *data, u32 len, int cmd) { struct { u8 dir; u8 valid; __le16 bitmap; s8 precal; u8 action; u8 band; u8 idx; u8 rsv[4]; __le32 len; } req = {}; struct sk_buff *skb; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len); if (!skb) return -ENOMEM; req.idx = idx; req.len = cpu_to_le32(len); skb_put_data(skb, &req, sizeof(req)); skb_put_data(skb, data, len); return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false); } int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev) { u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data; - u32 total = MT_EE_CAL_GROUP_SIZE; + u32 total = mt7915_get_cal_group_size(dev); + u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2; - if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP)) + if (!(eep[offs] & MT_EE_WIFI_CAL_GROUP)) return 0; /* * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC */ while (total > 0) { int ret, len; len = min_t(u32, total, MT_EE_CAL_UNIT); ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len, MCU_EXT_CMD(GROUP_PRE_CAL_INFO)); if (ret) return ret; total -= len; cal += len; idx++; } return 0; } static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur) { int i; for (i = 0; i < n_freqs; i++) if (cur == freqs[i]) return i; return -1; } -static int mt7915_dpd_freq_idx(u16 freq, u8 bw) +static int mt7915_dpd_freq_idx(struct mt7915_dev *dev, u16 freq, u8 bw) { - static const u16 freq_list[] = { + static const u16 freq_list_v1[] = { 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805, 5825 }; - int offset_2g = ARRAY_SIZE(freq_list); + static const u16 freq_list_v2[] = { + /* 6G BW20*/ + 5955, 5975, 5995, 6015, + 6035, 6055, 6075, 6095, + 6115, 6135, 6155, 6175, + 6195, 6215, 6235, 6255, + 6275, 6295, 6315, 6335, + 6355, 6375, 6395, 6415, + 6435, 6455, 6475, 6495, + 6515, 6535, 6555, 6575, + 6595, 6615, 6635, 6655, + 6675, 6695, 6715, 6735, + 6755, 6775, 6795, 6815, + 6835, 6855, 6875, 6895, + 6915, 6935, 6955, 6975, + 6995, 7015, 7035, 7055, + 7075, 7095, 7115, + /* 6G BW160 */ + 6025, 6185, 6345, 6505, + 6665, 6825, 6985, + /* 5G BW20 */ + 5180, 5200, 5220, 5240, + 5260, 5280, 5300, 5320, + 5500, 5520, 5540, 5560, + 5580, 5600, 5620, 5640, + 5660, 5680, 5700, 5720, + 5745, 5765, 5785, 5805, + 5825, 5845, 5865, 5885, + /* 5G BW160 */ + 5250, 5570, 5815 + }; + static const u16 freq_list_v2_7981[] = { + /* 5G BW20 */ + 5180, 5200, 5220, 5240, + 5260, 5280, 5300, 5320, + 5500, 5520, 5540, 5560, + 5580, 5600, 5620, 5640, + 5660, 5680, 5700, 5720, + 5745, 5765, 5785, 5805, + 5825, 5845, 5865, 5885, + /* 5G BW160 */ + 5250, 5570, 5815 + }; + const u16 *freq_list = freq_list_v1; + int n_freqs = ARRAY_SIZE(freq_list_v1); int idx; + if (!is_mt7915(&dev->mt76)) { + if (is_mt7981(&dev->mt76)) { + freq_list = freq_list_v2_7981; + n_freqs = ARRAY_SIZE(freq_list_v2_7981); + } else { + freq_list = freq_list_v2; + n_freqs = ARRAY_SIZE(freq_list_v2); + } + } + if (freq < 4000) { if (freq < 2432) - return offset_2g; + return n_freqs; if (freq < 2457) - return offset_2g + 1; + return n_freqs + 1; - return offset_2g + 2; + return n_freqs + 2; } - if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160) + if (bw == NL80211_CHAN_WIDTH_80P80) return -1; if (bw != NL80211_CHAN_WIDTH_20) { - idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), - freq + 10); + idx = mt7915_find_freq_idx(freq_list, n_freqs, freq + 10); if (idx >= 0) return idx; - idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), - freq - 10); + idx = mt7915_find_freq_idx(freq_list, n_freqs, freq - 10); if (idx >= 0) return idx; } - return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq); + return mt7915_find_freq_idx(freq_list, n_freqs, freq); } int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; - u16 total = 2, center_freq = chandef->center_freq1; + enum nl80211_band band = chandef->chan->band; + u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2; + u16 center_freq = chandef->center_freq1; u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data; + u8 dpd_mask, cal_num = is_mt7915(&dev->mt76) ? 2 : 3; int idx; - if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD)) + switch (band) { + case NL80211_BAND_2GHZ: + dpd_mask = MT_EE_WIFI_CAL_DPD_2G; + break; + case NL80211_BAND_5GHZ: + dpd_mask = MT_EE_WIFI_CAL_DPD_5G; + break; + case NL80211_BAND_6GHZ: + dpd_mask = MT_EE_WIFI_CAL_DPD_6G; + break; + default: + dpd_mask = 0; + break; + } + + if (!(eep[offs] & dpd_mask)) return 0; - idx = mt7915_dpd_freq_idx(center_freq, chandef->width); + idx = mt7915_dpd_freq_idx(dev, center_freq, chandef->width); if (idx < 0) return -EINVAL; /* Items: Tx DPD, Tx Flatness */ - idx = idx * 2; - cal += MT_EE_CAL_GROUP_SIZE; + idx = idx * cal_num; + cal += mt7915_get_cal_group_size(dev) + (idx * MT_EE_CAL_UNIT); - while (total--) { + while (cal_num--) { int ret; - cal += (idx * MT_EE_CAL_UNIT); ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT, MCU_EXT_CMD(DPD_PRE_CAL_INFO)); if (ret) return ret; idx++; + cal += MT_EE_CAL_UNIT; } return 0; } int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) { struct mt76_channel_state *state = phy->mt76->chan_state; struct mt76_channel_state *state_ts = &phy->state_ts; struct mt7915_dev *dev = phy->dev; struct mt7915_mcu_mib *res, req[5]; struct sk_buff *skb; static const u32 *offs; int i, ret, len, offs_cc; u64 cc_tx; /* strict order */ if (is_mt7915(&dev->mt76)) { static const u32 chip_offs[] = { MIB_NON_WIFI_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME, MIB_TXOP_INIT_COUNT, }; len = ARRAY_SIZE(chip_offs); offs = chip_offs; offs_cc = 20; } else { static const u32 chip_offs[] = { MIB_NON_WIFI_TIME_V2, MIB_TX_TIME_V2, MIB_RX_TIME_V2, MIB_OBSS_AIRTIME_V2 }; len = ARRAY_SIZE(chip_offs); offs = chip_offs; offs_cc = 0; } for (i = 0; i < len; i++) { req[i].band = cpu_to_le32(phy->mt76->band_idx); req[i].offs = cpu_to_le32(offs[i]); } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), req, len * sizeof(req[0]), true, &skb); if (ret) return ret; res = (struct mt7915_mcu_mib *)(skb->data + offs_cc); #define __res_u64(s) le64_to_cpu(res[s].data) - /* subtract Tx backoff time from Tx duration */ - cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1); + /* subtract Tx backoff time from Tx duration for MT7915 */ + if (is_mt7915(&dev->mt76)) { + u64 backoff = (__res_u64(4) & 0xffff) * 79; /* 16us + 9us * 7 */ + cc_tx = __res_u64(1) - backoff; + } else { + cc_tx = __res_u64(1); + } if (chan_switch) goto out; state->cc_tx += cc_tx - state_ts->cc_tx; state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) - state_ts->cc_busy; out: state_ts->cc_tx = cc_tx; state_ts->cc_bss_rx = __res_u64(2); state_ts->cc_rx = __res_u64(2) + __res_u64(3); state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3); #undef __res_u64 dev_kfree_skb(skb); return 0; } int mt7915_mcu_get_temperature(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct { u8 ctrl_id; u8 action; u8 band_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, .band_idx = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, sizeof(req), true); } int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) { struct mt7915_dev *dev = phy->dev; struct mt7915_mcu_thermal_ctrl req = { .band_idx = phy->mt76->band_idx, .ctrl_id = THERMAL_PROTECT_DUTY_CONFIG, }; int level, ret; /* set duty cycle and level */ for (level = 0; level < 4; level++) { req.duty.duty_level = level; req.duty.duty_cycle = state; state /= 2; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), &req, sizeof(req), false); if (ret) return ret; } return 0; } int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct { struct mt7915_mcu_thermal_ctrl ctrl; __le32 trigger_temp; __le32 restore_temp; __le16 sustain_time; u8 rsv[2]; } __packed req = { .ctrl = { .band_idx = phy->mt76->band_idx, .type.protect_type = 1, .type.trigger_type = 1, }, }; int ret; req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), &req, sizeof(req.ctrl), false); if (ret) return ret; /* set high-temperature trigger threshold */ req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE; /* add a safety margin ~10 */ req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10); req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); req.sustain_time = cpu_to_le16(10); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT), &req, sizeof(req), false); } int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower) { struct mt7915_dev *dev = phy->dev; struct { u8 format_id; u8 rsv; u8 band_idx; s8 txpower_min; } __packed req = { .format_id = TX_POWER_LIMIT_FRAME_MIN, .band_idx = phy->mt76->band_idx, .txpower_min = txpower * 2, /* 0.5db */ }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, s8 txpower) { struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct { u8 format_id; u8 rsv[3]; u8 band_idx; s8 txpower_max; __le16 wcid; s8 txpower_offs[48]; } __packed req = { .format_id = TX_POWER_LIMIT_FRAME, .band_idx = phy->mt76->band_idx, .txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2), .wcid = cpu_to_le16(msta->wcid.idx), }; int ret; s8 txpower_sku[MT7915_SKU_RATE_NUM]; ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku)); if (ret) return ret; txpower = mt7915_get_power_bound(phy, txpower); if (txpower > mphy->txpower_cur || txpower < 0) return -EINVAL; if (txpower) { u32 offs, len, i; if (sta->deflink.ht_cap.ht_supported) { const u8 *sku_len = mt7915_sku_group_len; offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM]; len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40]; if (sta->deflink.vht_cap.vht_supported) { offs += len; len = sku_len[SKU_VHT_BW20] * 4; if (sta->deflink.he_cap.has_he) { offs += len + sku_len[SKU_HE_RU26] * 3; len = sku_len[SKU_HE_RU242] * 4; } } } else { return -EINVAL; } for (i = 0; i < len; i++, offs++) req.txpower_offs[i] = DIV_ROUND_UP(txpower - txpower_sku[offs], 2); } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_hw *hw = mphy->hw; struct mt7915_mcu_txpower_sku req = { .format_id = TX_POWER_LIMIT_TABLE, .band_idx = phy->mt76->band_idx, }; struct mt76_power_limits limits_array; s8 *la = (s8 *)&limits_array; int i, idx; int tx_power; tx_power = mt7915_get_power_bound(phy, hw->conf.power_level); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits_array, tx_power); mphy->txpower_cur = tx_power; for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { u8 mcs_num, len = mt7915_sku_group_len[i]; int j; if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) { mcs_num = 10; if (i == SKU_HT_BW20 || i == SKU_VHT_BW20) la = (s8 *)&limits_array + 12; } else { mcs_num = len; } for (j = 0; j < min_t(u8, mcs_num, len); j++) req.txpower_sku[idx + j] = la[j]; la += mcs_num; idx += len; } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) { #define RATE_POWER_INFO 2 struct mt7915_dev *dev = phy->dev; struct { u8 format_id; u8 category; u8 band_idx; u8 _rsv; } __packed req = { .format_id = TX_POWER_LIMIT_INFO, .category = RATE_POWER_INFO, .band_idx = phy->mt76->band_idx, }; s8 txpower_sku[MT7915_SKU_RATE_NUM][2]; struct sk_buff *skb; int ret, i; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true, &skb); if (ret) return ret; memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku)); for (i = 0; i < len; i++) txpower[i] = txpower_sku[i][req.band_idx]; dev_kfree_skb(skb); return 0; } int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, u8 en) { struct { u8 test_mode_en; u8 param_idx; u8 _rsv[2]; u8 enable; u8 _rsv2[3]; u8 pad[8]; } __packed req = { .test_mode_en = test_mode, .param_idx = param, .enable = en, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) { struct mt7915_dev *dev = phy->dev; struct mt7915_sku { u8 format_id; u8 sku_enable; u8 band_idx; u8 rsv; } __packed req = { .format_id = TX_POWER_LIMIT_ENABLE, .band_idx = phy->mt76->band_idx, .sku_enable = enable, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), true); } int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band) { struct { u8 action; u8 set; u8 band; u8 rsv; } req = { .action = action, .set = set, .band = band, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER), &req, sizeof(req), false); } int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) { struct { u8 action; union { struct { u8 snd_mode; u8 sta_num; u8 rsv; u8 wlan_idx[4]; __le32 snd_period; /* ms */ } __packed snd; struct { bool ebf; bool ibf; u8 rsv; } __packed type; struct { u8 bf_num; u8 bf_bitmap; u8 bf_sel[8]; u8 rsv[5]; } __packed mod; }; } __packed req = { .action = action, }; #define MT_BF_PROCESSING 4 switch (action) { case MT_BF_SOUNDING_ON: req.snd.snd_mode = MT_BF_PROCESSING; break; case MT_BF_TYPE_UPDATE: req.type.ebf = true; req.type.ibf = dev->ibf; break; case MT_BF_MODULE_UPDATE: req.mod.bf_num = 2; req.mod.bf_bitmap = GENMASK(1, 0); break; default: return -EINVAL; } return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req, sizeof(req), true); } static int mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val) { struct mt7915_dev *dev = phy->dev; struct mt7915_mcu_sr_ctrl req = { .action = action, .argnum = 1, .band_idx = phy->mt76->band_idx, .val = cpu_to_le32(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } static int mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7915_dev *dev = phy->dev; struct { struct mt7915_mcu_sr_ctrl ctrl; struct { u8 pd_th_non_srg; u8 pd_th_srg; u8 period_offs; u8 rcpi_src; __le16 obss_pd_min; __le16 obss_pd_min_srg; u8 resp_txpwr_mode; u8 txpwr_restrict_mode; u8 txpwr_ref; u8 rsv[3]; } __packed param; } __packed req = { .ctrl = { .action = SPR_SET_PARAM, .argnum = 9, .band_idx = phy->mt76->band_idx, }, }; int ret; u8 max_th = 82, non_srg_max_th = 62; /* disable firmware dynamical PD asjustment */ ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false); if (ret) return ret; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED) req.param.pd_th_non_srg = max_th; else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) req.param.pd_th_non_srg = max_th - he_obss_pd->non_srg_max_offset; else req.param.pd_th_non_srg = non_srg_max_th; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) req.param.pd_th_srg = max_th - he_obss_pd->max_offset; req.param.obss_pd_min = cpu_to_le16(82); req.param.obss_pd_min_srg = cpu_to_le16(82); req.param.txpwr_restrict_mode = 2; req.param.txpwr_ref = 21; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } static int mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = phy->dev; u8 omac = mvif->mt76.omac_idx; struct { struct mt7915_mcu_sr_ctrl ctrl; struct { u8 omac; u8 rsv[3]; u8 flag[20]; } __packed siga; } __packed req = { .ctrl = { .action = SPR_SET_SIGA, .argnum = 1, .band_idx = phy->mt76->band_idx, }, .siga = { .omac = omac > HW_BSSID_MAX ? omac - 12 : omac, }, }; int ret; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED) req.siga.flag[req.siga.omac] = 0xf; else return 0; /* switch to normal AP mode */ ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0); if (ret) return ret; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } static int mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7915_dev *dev = phy->dev; struct { struct mt7915_mcu_sr_ctrl ctrl; struct { __le32 color_l[2]; __le32 color_h[2]; __le32 bssid_l[2]; __le32 bssid_h[2]; } __packed bitmap; } __packed req = { .ctrl = { .action = SPR_SET_SRG_BITMAP, .argnum = 4, .band_idx = phy->mt76->band_idx, }, }; u32 bitmap; memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap)); req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap)); req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap)); req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap)); req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd) { int ret; /* enable firmware scene detection algorithms */ ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect); if (ret) return ret; /* firmware dynamically adjusts PD threshold so skip manual control */ if (sr_scene_detect && !he_obss_pd->enable) return 0; /* enable spatial reuse */ ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable); if (ret) return ret; if (sr_scene_detect || !he_obss_pd->enable) return 0; ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true); if (ret) return ret; /* set SRG/non-SRG OBSS PD threshold */ ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd); if (ret) return ret; /* Set SR prohibit */ ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd); if (ret) return ret; /* set SRG BSS color/BSSID bitmap */ return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd); } int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate) { struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct { u8 category; u8 band; __le16 wcid; } __packed req = { .category = MCU_PHY_STATE_CONTENTION_RX_RATE, .band = mvif->mt76.band_idx, .wcid = cpu_to_le16(msta->wcid.idx), }; struct ieee80211_supported_band *sband; struct mt7915_mcu_phy_rx_info *res; struct sk_buff *skb; int ret; bool cck = false; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO), &req, sizeof(req), true, &skb); if (ret) return ret; res = (struct mt7915_mcu_phy_rx_info *)skb->data; rate->mcs = res->rate; rate->nss = res->nsts + 1; switch (res->mode) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.sband; else sband = &mphy->sband_2g.sband; rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck); rate->legacy = sband->bitrates[rate->mcs].bitrate; break; case MT_PHY_TYPE_HT: case MT_PHY_TYPE_HT_GF: if (rate->mcs > 31) { ret = -EINVAL; goto out; } rate->flags = RATE_INFO_FLAGS_MCS; if (res->gi) rate->flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_VHT: if (rate->mcs > 9) { ret = -EINVAL; goto out; } rate->flags = RATE_INFO_FLAGS_VHT_MCS; if (res->gi) rate->flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: case MT_PHY_TYPE_HE_TB: case MT_PHY_TYPE_HE_MU: if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) { ret = -EINVAL; goto out; } rate->he_gi = res->gi; rate->flags = RATE_INFO_FLAGS_HE_MCS; break; default: ret = -EINVAL; goto out; } switch (res->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; } out: dev_kfree_skb(skb); return ret; } int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct cfg80211_he_bss_color *he_bss_color) { int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct bss_info_color *bss_color; struct sk_buff *skb; struct tlv *tlv; skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL, len); if (IS_ERR(skb)) return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR, sizeof(*bss_color)); bss_color = (struct bss_info_color *)tlv; bss_color->disable = !he_bss_color->enabled; bss_color->color = he_bss_color->color; return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(BSS_INFO_UPDATE), true); } #define TWT_AGRT_TRIGGER BIT(0) #define TWT_AGRT_ANNOUNCE BIT(1) #define TWT_AGRT_PROTECT BIT(2) int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, struct mt7915_vif *mvif, struct mt7915_twt_flow *flow, int cmd) { struct { u8 tbl_idx; u8 cmd; u8 own_mac_idx; u8 flowid; /* 0xff for group id */ __le16 peer_id; /* specify the peer_id (msb=0) * or group_id (msb=1) */ u8 duration; /* 256 us */ u8 bss_idx; __le64 start_tsf; __le16 mantissa; u8 exponent; u8 is_ap; u8 agrt_params; u8 rsv[23]; } __packed req = { .tbl_idx = flow->table_id, .cmd = cmd, .own_mac_idx = mvif->mt76.omac_idx, .flowid = flow->id, .peer_id = cpu_to_le16(flow->wcid), .duration = flow->duration, .bss_idx = mvif->mt76.idx, .start_tsf = cpu_to_le64(flow->tsf), .mantissa = flow->mantissa, .exponent = flow->exp, .is_ap = true, }; if (flow->protection) req.agrt_params |= TWT_AGRT_PROTECT; if (!flow->flowtype) req.agrt_params |= TWT_AGRT_ANNOUNCE; if (flow->trigger) req.agrt_params |= TWT_AGRT_TRIGGER; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE), &req, sizeof(req), true); } int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx) { struct { __le32 cmd; - __le32 num; - __le32 __rsv; - __le16 wlan_idx; - } req = { + __le32 arg0; + __le32 arg1; + __le16 arg2; + } __packed req = { .cmd = cpu_to_le32(0x15), - .num = cpu_to_le32(1), - .wlan_idx = cpu_to_le16(wlan_idx), }; struct mt7915_mcu_wa_tx_stat { - __le16 wlan_idx; - u8 __rsv[2]; + __le16 wcid; + u8 __rsv2[2]; /* tx_bytes is deprecated since WA byte counter uses u32, * which easily leads to overflow. */ __le32 tx_bytes; __le32 tx_packets; - } *res; + } __packed *res; struct mt76_wcid *wcid; struct sk_buff *skb; - int ret; + int ret, len; + u16 ret_wcid; + + if (is_mt7915(&dev->mt76)) { + req.arg0 = cpu_to_le32(wlan_idx); + len = sizeof(req) - sizeof(req.arg2); + } else { + req.arg0 = cpu_to_le32(1); + req.arg2 = cpu_to_le16(wlan_idx); + len = sizeof(req); + } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY), - &req, sizeof(req), true, &skb); + &req, len, true, &skb); if (ret) return ret; if (!is_mt7915(&dev->mt76)) skb_pull(skb, 4); res = (struct mt7915_mcu_wa_tx_stat *)skb->data; - if (le16_to_cpu(res->wlan_idx) != wlan_idx) { + ret_wcid = le16_to_cpu(res->wcid); + if (is_mt7915(&dev->mt76)) + ret_wcid &= 0xff; + + if (ret_wcid != wlan_idx) { ret = -EINVAL; goto out; } rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); if (wcid) wcid->stats.tx_packets += le32_to_cpu(res->tx_packets); else ret = -EINVAL; rcu_read_unlock(); out: dev_kfree_skb(skb); return ret; } int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set) { struct { __le32 idx; __le32 ofs; __le32 data; } __packed req = { .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))), .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))), .data = set ? cpu_to_le32(*val) : 0, }; struct sk_buff *skb; int ret; if (set) return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS), &req, sizeof(req), false); ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS), &req, sizeof(req), true, &skb); if (ret) return ret; *val = le32_to_cpu(*(__le32 *)(skb->data + 8)); dev_kfree_skb(skb); return 0; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/mcu.h b/sys/contrib/dev/mediatek/mt76/mt7915/mcu.h index b9ea297f382c..49476a4182fd 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/mcu.h +++ b/sys/contrib/dev/mediatek/mt76/mt7915/mcu.h @@ -1,532 +1,530 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_MCU_H #define __MT7915_MCU_H #include "../mt76_connac_mcu.h" enum { MCU_ATE_SET_TRX = 0x1, MCU_ATE_SET_FREQ_OFFSET = 0xa, MCU_ATE_SET_SLOT_TIME = 0x13, MCU_ATE_CLEAN_TXQUEUE = 0x1c, }; struct mt7915_mcu_thermal_ctrl { u8 ctrl_id; u8 band_idx; union { struct { u8 protect_type; /* 1: duty admit, 2: radio off */ u8 trigger_type; /* 0: low, 1: high */ } __packed type; struct { u8 duty_level; /* level 0~3 */ u8 duty_cycle; } __packed duty; }; } __packed; struct mt7915_mcu_thermal_notify { - struct mt76_connac2_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd_hdr rxd; struct mt7915_mcu_thermal_ctrl ctrl; __le32 temperature; u8 rsv[8]; } __packed; struct mt7915_mcu_csa_notify { - struct mt76_connac2_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd_hdr rxd; u8 omac_idx; u8 csa_count; u8 band_idx; u8 rsv; } __packed; struct mt7915_mcu_bcc_notify { - struct mt76_connac2_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd_hdr rxd; u8 band_idx; u8 omac_idx; u8 cca_count; u8 rsv; } __packed; struct mt7915_mcu_rdd_report { - struct mt76_connac2_mcu_rxd rxd; + struct mt76_connac2_mcu_rxd_hdr rxd; u8 band_idx; u8 long_detected; u8 constant_prf_detected; u8 staggered_prf_detected; u8 radar_type_idx; u8 periodic_pulse_num; u8 long_pulse_num; u8 hw_pulse_num; u8 out_lpn; u8 out_spn; u8 out_crpn; u8 out_crpw; u8 out_crbn; u8 out_stgpn; u8 out_stgpw; u8 rsv; __le32 out_pri_const; __le32 out_pri_stg[3]; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 mdrdy_flag; u8 rsv[3]; } long_pulse[32]; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 mdrdy_flag; u8 rsv[3]; } periodic_pulse[32]; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 sc_pass; u8 sw_reset; u8 mdrdy_flag; u8 tx_active; } hw_pulse[32]; } __packed; struct mt7915_mcu_background_chain_ctrl { u8 chan; /* primary channel */ u8 central_chan; /* central channel */ u8 bw; u8 tx_stream; u8 rx_stream; u8 monitor_chan; /* monitor channel */ u8 monitor_central_chan;/* monitor central channel */ u8 monitor_bw; u8 monitor_tx_stream; u8 monitor_rx_stream; u8 scan_mode; /* 0: ScanStop * 1: ScanStart * 2: ScanRunning */ u8 band_idx; /* DBDC */ u8 monitor_scan_type; u8 band; /* 0: 2.4GHz, 1: 5GHz */ u8 rsv[2]; } __packed; struct mt7915_mcu_sr_ctrl { u8 action; u8 argnum; u8 band_idx; u8 status; u8 drop_ta_idx; u8 sta_idx; /* 256 sta */ u8 rsv[2]; __le32 val; } __packed; struct mt7915_mcu_eeprom { u8 buffer_mode; u8 format; __le16 len; } __packed; struct mt7915_mcu_eeprom_info { __le32 addr; __le32 valid; u8 data[16]; } __packed; struct mt7915_mcu_phy_rx_info { u8 category; u8 rate; u8 mode; u8 nsts; u8 gi; u8 coding; u8 stbc; u8 bw; }; struct mt7915_mcu_mib { __le32 band; __le32 offs; __le64 data; } __packed; enum mt7915_chan_mib_offs { /* mt7915 */ MIB_TX_TIME = 81, MIB_RX_TIME, MIB_OBSS_AIRTIME = 86, MIB_NON_WIFI_TIME, MIB_TXOP_INIT_COUNT, /* mt7916 */ MIB_TX_TIME_V2 = 6, MIB_RX_TIME_V2 = 8, MIB_OBSS_AIRTIME_V2 = 490, MIB_NON_WIFI_TIME_V2 }; struct mt7915_mcu_txpower_sku { u8 format_id; u8 limit_type; u8 band_idx; s8 txpower_sku[MT7915_SKU_RATE_NUM]; } __packed; struct edca { u8 queue; u8 set; u8 aifs; u8 cw_min; __le16 cw_max; __le16 txop; }; struct mt7915_mcu_tx { u8 total; u8 action; u8 valid; u8 mode; struct edca edca[IEEE80211_NUM_ACS]; } __packed; struct mt7915_mcu_muru_stats { __le32 event_id; struct { __le32 cck_cnt; __le32 ofdm_cnt; __le32 htmix_cnt; __le32 htgf_cnt; __le32 vht_su_cnt; __le32 vht_2mu_cnt; __le32 vht_3mu_cnt; __le32 vht_4mu_cnt; __le32 he_su_cnt; __le32 he_ext_su_cnt; __le32 he_2ru_cnt; __le32 he_2mu_cnt; __le32 he_3ru_cnt; __le32 he_3mu_cnt; __le32 he_4ru_cnt; __le32 he_4mu_cnt; __le32 he_5to8ru_cnt; __le32 he_9to16ru_cnt; __le32 he_gtr16ru_cnt; } dl; struct { __le32 hetrig_su_cnt; __le32 hetrig_2ru_cnt; __le32 hetrig_3ru_cnt; __le32 hetrig_4ru_cnt; __le32 hetrig_5to8ru_cnt; __le32 hetrig_9to16ru_cnt; __le32 hetrig_gtr16ru_cnt; __le32 hetrig_2mu_cnt; __le32 hetrig_3mu_cnt; __le32 hetrig_4mu_cnt; } ul; }; #define WMM_AIFS_SET BIT(0) #define WMM_CW_MIN_SET BIT(1) #define WMM_CW_MAX_SET BIT(2) #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET GENMASK(3, 0) enum { MCU_FW_LOG_WM, MCU_FW_LOG_WA, MCU_FW_LOG_TO_HOST, }; enum { MCU_TWT_AGRT_ADD, MCU_TWT_AGRT_MODIFY, MCU_TWT_AGRT_DELETE, MCU_TWT_AGRT_TEARDOWN, MCU_TWT_AGRT_GET_TSF, }; enum { MCU_WA_PARAM_CMD_QUERY, MCU_WA_PARAM_CMD_SET, MCU_WA_PARAM_CMD_CAPABILITY, MCU_WA_PARAM_CMD_DEBUG, }; enum { MCU_WA_PARAM_PDMA_RX = 0x04, MCU_WA_PARAM_CPU_UTIL = 0x0b, MCU_WA_PARAM_RED = 0x0e, MCU_WA_PARAM_RED_SETTING = 0x40, }; enum mcu_mmps_mode { MCU_MMPS_STATIC, MCU_MMPS_DYNAMIC, MCU_MMPS_RSV, MCU_MMPS_DISABLE, }; struct bss_info_bmc_rate { __le16 tag; __le16 len; __le16 bc_trans; __le16 mc_trans; u8 short_preamble; u8 rsv[7]; } __packed; struct bss_info_ra { __le16 tag; __le16 len; u8 op_mode; u8 adhoc_en; u8 short_preamble; u8 tx_streams; u8 rx_streams; u8 algo; u8 force_sgi; u8 force_gf; u8 ht_mode; u8 has_20_sta; /* Check if any sta support GF. */ u8 bss_width_trigger_events; u8 vht_nss_cap; u8 vht_bw_signal; /* not use */ u8 vht_force_sgi; /* not use */ u8 se_off; u8 antenna_idx; u8 train_up_rule; u8 rsv[3]; unsigned short train_up_high_thres; short train_up_rule_rssi; unsigned short low_traffic_thres; __le16 max_phyrate; __le32 phy_cap; __le32 interval; __le32 fast_interval; } __packed; struct bss_info_hw_amsdu { __le16 tag; __le16 len; __le32 cmp_bitmap_0; __le32 cmp_bitmap_1; __le16 trig_thres; u8 enable; 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; u8 he_pe_duration; u8 vht_op_info_present; __le16 he_rts_thres; __le16 max_nss_mcs[CMD_HE_MCS_BW_NUM]; u8 rsv[6]; } __packed; struct bss_info_bcn { __le16 tag; __le16 len; u8 ver; u8 enable; __le16 sub_ntlv; } __packed __aligned(4); struct bss_info_bcn_cntdwn { __le16 tag; __le16 len; u8 cnt; u8 rsv[3]; } __packed __aligned(4); struct bss_info_bcn_mbss { #define MAX_BEACON_NUM 32 __le16 tag; __le16 len; __le32 bitmap; __le16 offset[MAX_BEACON_NUM]; u8 rsv[8]; } __packed __aligned(4); struct bss_info_bcn_cont { __le16 tag; __le16 len; __le16 tim_ofs; __le16 csa_ofs; __le16 bcc_ofs; __le16 pkt_len; } __packed __aligned(4); struct bss_info_inband_discovery { __le16 tag; __le16 len; u8 tx_type; u8 tx_mode; u8 tx_interval; u8 enable; __le16 rsv; __le16 prob_rsp_len; } __packed __aligned(4); enum { BSS_INFO_BCN_CSA, BSS_INFO_BCN_BCC, BSS_INFO_BCN_MBSSID, BSS_INFO_BCN_CONTENT, BSS_INFO_BCN_DISCOV, BSS_INFO_BCN_MAX }; enum { RATE_PARAM_FIXED = 3, RATE_PARAM_MMPS_UPDATE = 5, RATE_PARAM_FIXED_HE_LTF = 7, RATE_PARAM_FIXED_MCS, RATE_PARAM_FIXED_GI = 11, RATE_PARAM_AUTO = 20, RATE_PARAM_SPE_UPDATE = 22, }; #define RATE_CFG_MCS GENMASK(3, 0) #define RATE_CFG_NSS GENMASK(7, 4) #define RATE_CFG_GI GENMASK(11, 8) #define RATE_CFG_BW GENMASK(15, 12) #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) enum { TX_POWER_LIMIT_ENABLE, TX_POWER_LIMIT_TABLE = 0x4, TX_POWER_LIMIT_INFO = 0x7, TX_POWER_LIMIT_FRAME = 0x11, TX_POWER_LIMIT_FRAME_MIN = 0x12, }; enum { SPR_ENABLE = 0x1, SPR_ENABLE_SD = 0x3, SPR_ENABLE_MODE = 0x5, SPR_ENABLE_DPD = 0x23, SPR_ENABLE_TX = 0x25, SPR_SET_SRG_BITMAP = 0x80, SPR_SET_PARAM = 0xc2, SPR_SET_SIGA = 0xdc, }; enum { THERMAL_PROTECT_PARAMETER_CTRL, THERMAL_PROTECT_BASIC_INFO, THERMAL_PROTECT_ENABLE, THERMAL_PROTECT_DISABLE, THERMAL_PROTECT_DUTY_CONFIG, THERMAL_PROTECT_MECH_INFO, THERMAL_PROTECT_DUTY_INFO, THERMAL_PROTECT_STATE_ACT, }; 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, }; /* tx cmd tx statistics */ enum { MURU_SET_TXC_TX_STATS_EN = 150, MURU_GET_TXC_TX_STATS = 151, }; enum { SER_QUERY, /* recovery */ SER_SET_RECOVER_L1, SER_SET_RECOVER_L2, SER_SET_RECOVER_L3_RX_ABORT, SER_SET_RECOVER_L3_TX_ABORT, SER_SET_RECOVER_L3_TX_DISABLE, SER_SET_RECOVER_L3_BF, SER_SET_RECOVER_FULL, SER_SET_SYSTEM_ASSERT, /* action */ SER_ENABLE = 2, SER_RECOVER }; -#define MT7915_MAX_BEACON_SIZE 512 -#define MT7915_MAX_INBAND_FRAME_SIZE 256 -#define MT7915_MAX_BSS_OFFLOAD_SIZE (MT7915_MAX_BEACON_SIZE + \ - MT7915_MAX_INBAND_FRAME_SIZE + \ +#define MT7915_MAX_BEACON_SIZE 1308 +#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ + sizeof(struct bss_info_bcn) + \ + sizeof(struct bss_info_bcn_cntdwn) + \ + sizeof(struct bss_info_bcn_mbss) + \ + MT_TXD_SIZE + \ + sizeof(struct bss_info_bcn_cont)) +#define MT7915_MAX_BSS_OFFLOAD_SIZE (MT7915_MAX_BEACON_SIZE + \ MT7915_BEACON_UPDATE_SIZE) #define MT7915_BSS_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct bss_info_omac) + \ sizeof(struct bss_info_basic) +\ sizeof(struct bss_info_rf_ch) +\ sizeof(struct bss_info_ra) + \ sizeof(struct bss_info_hw_amsdu) +\ sizeof(struct bss_info_he) + \ sizeof(struct bss_info_bmc_rate) +\ sizeof(struct bss_info_ext_bss)) -#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \ - sizeof(struct bss_info_bcn_cntdwn) + \ - sizeof(struct bss_info_bcn_mbss) + \ - sizeof(struct bss_info_bcn_cont) + \ - sizeof(struct bss_info_inband_discovery)) - static inline s8 mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower) { struct mt76_phy *mphy = phy->mt76; - int n_chains = hweight8(mphy->antenna_mask); + int n_chains = hweight16(mphy->chainmask); txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); txpower -= mt76_tx_power_nss_delta(n_chains); return txpower; } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/mmio.c b/sys/contrib/dev/mediatek/mt76/mt7915/mmio.c index 8736c5651c23..8530043d3232 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/mmio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/mmio.c @@ -1,1071 +1,1009 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include #include "mt7915.h" #include "mac.h" #include "mcu.h" #include "../trace.h" #include "../dma.h" static bool wed_enable; module_param(wed_enable, bool, 0644); MODULE_PARM_DESC(wed_enable, "Enable Wireless Ethernet Dispatch support"); static const u32 mt7915_reg[] = { [INT_SOURCE_CSR] = 0xd7010, [INT_MASK_CSR] = 0xd7014, [INT1_SOURCE_CSR] = 0xd7088, [INT1_MASK_CSR] = 0xd708c, [INT_MCU_CMD_SOURCE] = 0xd51f0, [INT_MCU_CMD_EVENT] = 0x3108, [WFDMA0_ADDR] = 0xd4000, [WFDMA0_PCIE1_ADDR] = 0xd8000, [WFDMA_EXT_CSR_ADDR] = 0xd7000, [CBTOP1_PHY_END] = 0x77ffffff, [INFRA_MCU_ADDR_END] = 0x7c3fffff, [FW_ASSERT_STAT_ADDR] = 0x219848, [FW_EXCEPT_TYPE_ADDR] = 0x21987c, [FW_EXCEPT_COUNT_ADDR] = 0x219848, [FW_CIRQ_COUNT_ADDR] = 0x216f94, [FW_CIRQ_IDX_ADDR] = 0x216ef8, [FW_CIRQ_LISR_ADDR] = 0x2170ac, [FW_TASK_ID_ADDR] = 0x216f90, [FW_TASK_IDX_ADDR] = 0x216f9c, [FW_TASK_QID1_ADDR] = 0x219680, [FW_TASK_QID2_ADDR] = 0x219760, [FW_TASK_START_ADDR] = 0x219558, [FW_TASK_END_ADDR] = 0x219554, [FW_TASK_SIZE_ADDR] = 0x219560, [FW_LAST_MSG_ID_ADDR] = 0x216f70, [FW_EINT_INFO_ADDR] = 0x219818, [FW_SCHED_INFO_ADDR] = 0x219828, [SWDEF_BASE_ADDR] = 0x41f200, [TXQ_WED_RING_BASE] = 0xd7300, [RXQ_WED_RING_BASE] = 0xd7410, [RXQ_WED_DATA_RING_BASE] = 0xd4500, }; static const u32 mt7916_reg[] = { [INT_SOURCE_CSR] = 0xd4200, [INT_MASK_CSR] = 0xd4204, [INT1_SOURCE_CSR] = 0xd8200, [INT1_MASK_CSR] = 0xd8204, [INT_MCU_CMD_SOURCE] = 0xd41f0, [INT_MCU_CMD_EVENT] = 0x2108, [WFDMA0_ADDR] = 0xd4000, [WFDMA0_PCIE1_ADDR] = 0xd8000, [WFDMA_EXT_CSR_ADDR] = 0xd7000, [CBTOP1_PHY_END] = 0x7fffffff, [INFRA_MCU_ADDR_END] = 0x7c085fff, [FW_ASSERT_STAT_ADDR] = 0x02204c14, [FW_EXCEPT_TYPE_ADDR] = 0x022051a4, [FW_EXCEPT_COUNT_ADDR] = 0x022050bc, [FW_CIRQ_COUNT_ADDR] = 0x022001ac, [FW_CIRQ_IDX_ADDR] = 0x02204f84, [FW_CIRQ_LISR_ADDR] = 0x022050d0, [FW_TASK_ID_ADDR] = 0x0220406c, [FW_TASK_IDX_ADDR] = 0x0220500c, [FW_TASK_QID1_ADDR] = 0x022028c8, [FW_TASK_QID2_ADDR] = 0x02202a38, [FW_TASK_START_ADDR] = 0x0220286c, [FW_TASK_END_ADDR] = 0x02202870, [FW_TASK_SIZE_ADDR] = 0x02202878, [FW_LAST_MSG_ID_ADDR] = 0x02204fe8, [FW_EINT_INFO_ADDR] = 0x0220525c, [FW_SCHED_INFO_ADDR] = 0x0220516c, [SWDEF_BASE_ADDR] = 0x411400, [TXQ_WED_RING_BASE] = 0xd7300, [RXQ_WED_RING_BASE] = 0xd7410, [RXQ_WED_DATA_RING_BASE] = 0xd4540, }; static const u32 mt7986_reg[] = { [INT_SOURCE_CSR] = 0x24200, [INT_MASK_CSR] = 0x24204, [INT1_SOURCE_CSR] = 0x28200, [INT1_MASK_CSR] = 0x28204, [INT_MCU_CMD_SOURCE] = 0x241f0, [INT_MCU_CMD_EVENT] = 0x54000108, [WFDMA0_ADDR] = 0x24000, [WFDMA0_PCIE1_ADDR] = 0x28000, [WFDMA_EXT_CSR_ADDR] = 0x27000, [CBTOP1_PHY_END] = 0x7fffffff, [INFRA_MCU_ADDR_END] = 0x7c085fff, [FW_ASSERT_STAT_ADDR] = 0x02204b54, [FW_EXCEPT_TYPE_ADDR] = 0x022050dc, [FW_EXCEPT_COUNT_ADDR] = 0x02204ffc, [FW_CIRQ_COUNT_ADDR] = 0x022001ac, [FW_CIRQ_IDX_ADDR] = 0x02204ec4, [FW_CIRQ_LISR_ADDR] = 0x02205010, [FW_TASK_ID_ADDR] = 0x02204fac, [FW_TASK_IDX_ADDR] = 0x02204f4c, [FW_TASK_QID1_ADDR] = 0x02202814, [FW_TASK_QID2_ADDR] = 0x02202984, [FW_TASK_START_ADDR] = 0x022027b8, [FW_TASK_END_ADDR] = 0x022027bc, [FW_TASK_SIZE_ADDR] = 0x022027c4, [FW_LAST_MSG_ID_ADDR] = 0x02204f28, [FW_EINT_INFO_ADDR] = 0x02205194, [FW_SCHED_INFO_ADDR] = 0x022051a4, [SWDEF_BASE_ADDR] = 0x411400, [TXQ_WED_RING_BASE] = 0x24420, [RXQ_WED_RING_BASE] = 0x24520, [RXQ_WED_DATA_RING_BASE] = 0x24540, }; static const u32 mt7915_offs[] = { [TMAC_CDTR] = 0x090, [TMAC_ODTR] = 0x094, [TMAC_ATCR] = 0x098, [TMAC_TRCR0] = 0x09c, [TMAC_ICR0] = 0x0a4, [TMAC_ICR1] = 0x0b4, [TMAC_CTCR0] = 0x0f4, [TMAC_TFCR0] = 0x1e0, [MDP_BNRCFR0] = 0x070, [MDP_BNRCFR1] = 0x074, [ARB_DRNGR0] = 0x194, [ARB_SCR] = 0x080, [RMAC_MIB_AIRTIME14] = 0x3b8, [AGG_AWSCR0] = 0x05c, [AGG_PCR0] = 0x06c, [AGG_ACR0] = 0x084, [AGG_ACR4] = 0x08c, [AGG_MRCR] = 0x098, + [AGG_ATCR0] = 0x0ec, [AGG_ATCR1] = 0x0f0, [AGG_ATCR3] = 0x0f4, [LPON_UTTR0] = 0x080, [LPON_UTTR1] = 0x084, [LPON_FRCR] = 0x314, [MIB_SDR3] = 0x014, [MIB_SDR4] = 0x018, [MIB_SDR5] = 0x01c, [MIB_SDR7] = 0x024, [MIB_SDR8] = 0x028, [MIB_SDR9] = 0x02c, [MIB_SDR10] = 0x030, [MIB_SDR11] = 0x034, [MIB_SDR12] = 0x038, [MIB_SDR13] = 0x03c, [MIB_SDR14] = 0x040, [MIB_SDR15] = 0x044, [MIB_SDR16] = 0x048, [MIB_SDR17] = 0x04c, [MIB_SDR18] = 0x050, [MIB_SDR19] = 0x054, [MIB_SDR20] = 0x058, [MIB_SDR21] = 0x05c, [MIB_SDR22] = 0x060, [MIB_SDR23] = 0x064, [MIB_SDR24] = 0x068, [MIB_SDR25] = 0x06c, [MIB_SDR27] = 0x074, [MIB_SDR28] = 0x078, [MIB_SDR29] = 0x07c, [MIB_SDRVEC] = 0x080, [MIB_SDR31] = 0x084, [MIB_SDR32] = 0x088, [MIB_SDRMUBF] = 0x090, [MIB_DR8] = 0x0c0, [MIB_DR9] = 0x0c4, [MIB_DR11] = 0x0cc, [MIB_MB_SDR0] = 0x100, [MIB_MB_SDR1] = 0x104, [TX_AGG_CNT] = 0x0a8, [TX_AGG_CNT2] = 0x164, [MIB_ARNG] = 0x4b8, [WTBLON_TOP_WDUCR] = 0x0, [WTBL_UPDATE] = 0x030, [PLE_FL_Q_EMPTY] = 0x0b0, [PLE_FL_Q_CTRL] = 0x1b0, [PLE_AC_QEMPTY] = 0x500, [PLE_FREEPG_CNT] = 0x100, [PLE_FREEPG_HEAD_TAIL] = 0x104, [PLE_PG_HIF_GROUP] = 0x110, [PLE_HIF_PG_INFO] = 0x114, [AC_OFFSET] = 0x040, [ETBF_PAR_RPT0] = 0x068, }; static const u32 mt7916_offs[] = { [TMAC_CDTR] = 0x0c8, [TMAC_ODTR] = 0x0cc, [TMAC_ATCR] = 0x00c, [TMAC_TRCR0] = 0x010, [TMAC_ICR0] = 0x014, [TMAC_ICR1] = 0x018, [TMAC_CTCR0] = 0x114, [TMAC_TFCR0] = 0x0e4, [MDP_BNRCFR0] = 0x090, [MDP_BNRCFR1] = 0x094, [ARB_DRNGR0] = 0x1e0, [ARB_SCR] = 0x000, [RMAC_MIB_AIRTIME14] = 0x0398, [AGG_AWSCR0] = 0x030, [AGG_PCR0] = 0x040, [AGG_ACR0] = 0x054, [AGG_ACR4] = 0x05c, [AGG_MRCR] = 0x068, + [AGG_ATCR0] = 0x1a4, [AGG_ATCR1] = 0x1a8, [AGG_ATCR3] = 0x080, [LPON_UTTR0] = 0x360, [LPON_UTTR1] = 0x364, [LPON_FRCR] = 0x37c, [MIB_SDR3] = 0x698, [MIB_SDR4] = 0x788, [MIB_SDR5] = 0x780, [MIB_SDR7] = 0x5a8, [MIB_SDR8] = 0x78c, [MIB_SDR9] = 0x024, [MIB_SDR10] = 0x76c, [MIB_SDR11] = 0x790, [MIB_SDR12] = 0x558, [MIB_SDR13] = 0x560, [MIB_SDR14] = 0x564, [MIB_SDR15] = 0x568, [MIB_SDR16] = 0x7fc, [MIB_SDR17] = 0x800, [MIB_SDR18] = 0x030, [MIB_SDR19] = 0x5ac, [MIB_SDR20] = 0x5b0, [MIB_SDR21] = 0x5b4, [MIB_SDR22] = 0x770, [MIB_SDR23] = 0x774, [MIB_SDR24] = 0x778, [MIB_SDR25] = 0x77c, [MIB_SDR27] = 0x080, [MIB_SDR28] = 0x084, [MIB_SDR29] = 0x650, [MIB_SDRVEC] = 0x5a8, [MIB_SDR31] = 0x55c, [MIB_SDR32] = 0x7a8, [MIB_SDRMUBF] = 0x7ac, [MIB_DR8] = 0x56c, [MIB_DR9] = 0x570, [MIB_DR11] = 0x574, [MIB_MB_SDR0] = 0x688, [MIB_MB_SDR1] = 0x690, [TX_AGG_CNT] = 0x7dc, [TX_AGG_CNT2] = 0x7ec, [MIB_ARNG] = 0x0b0, [WTBLON_TOP_WDUCR] = 0x200, [WTBL_UPDATE] = 0x230, [PLE_FL_Q_EMPTY] = 0x360, [PLE_FL_Q_CTRL] = 0x3e0, [PLE_AC_QEMPTY] = 0x600, [PLE_FREEPG_CNT] = 0x380, [PLE_FREEPG_HEAD_TAIL] = 0x384, [PLE_PG_HIF_GROUP] = 0x00c, [PLE_HIF_PG_INFO] = 0x388, [AC_OFFSET] = 0x080, [ETBF_PAR_RPT0] = 0x100, }; static const struct mt76_connac_reg_map mt7915_reg_map[] = { { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure regs) */ { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ { 0x54000000, 0x02000, 0x01000 }, /* WFDMA PCIE0 MCU DMA0 */ { 0x55000000, 0x03000, 0x01000 }, /* WFDMA PCIE0 MCU DMA1 */ { 0x58000000, 0x06000, 0x01000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ { 0x59000000, 0x07000, 0x01000 }, /* WFDMA PCIE1 MCU DMA1 */ { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ { 0x820c0000, 0x08000, 0x04000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ { 0x820cc000, 0x0e000, 0x02000 }, /* WF_UMAC_TOP (PP) */ { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ { 0x820e5000, 0x21400, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ { 0x820ed000, 0x24800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ { 0x820fd000, 0xa4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ { 0x0, 0x0, 0x0 }, /* imply end of search */ }; static const struct mt76_connac_reg_map mt7916_reg_map[] = { { 0x54000000, 0x02000, 0x01000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x03000, 0x01000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ { 0x56000000, 0x04000, 0x01000 }, /* WFDMA_2 (Reserved) */ { 0x57000000, 0x05000, 0x01000 }, /* WFDMA_3 (MCU wrap CR) */ { 0x58000000, 0x06000, 0x01000 }, /* WFDMA_4 (PCIE1 MCU DMA0) */ { 0x59000000, 0x07000, 0x01000 }, /* WFDMA_5 (PCIE1 MCU DMA1) */ { 0x820c0000, 0x08000, 0x04000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ { 0x820cc000, 0x0e000, 0x02000 }, /* WF_UMAC_TOP (PP) */ { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ { 0x820e5000, 0x21400, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ { 0x820ed000, 0x24800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ { 0x820ca000, 0x26000, 0x02000 }, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure cr) */ { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ { 0x820fd000, 0xa4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ { 0x820c4000, 0xa8000, 0x01000 }, /* WF_LMAC_TOP (WF_UWTBL ) */ { 0x820b0000, 0xae000, 0x01000 }, /* [APB2] WFSYS_ON */ { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ { 0x0, 0x0, 0x0 }, /* imply end of search */ }; static const struct mt76_connac_reg_map mt7986_reg_map[] = { { 0x54000000, 0x402000, 0x01000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x403000, 0x01000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ { 0x56000000, 0x404000, 0x01000 }, /* WFDMA_2 (Reserved) */ { 0x57000000, 0x405000, 0x01000 }, /* WFDMA_3 (MCU wrap CR) */ { 0x58000000, 0x406000, 0x01000 }, /* WFDMA_4 (PCIE1 MCU DMA0) */ { 0x59000000, 0x407000, 0x01000 }, /* WFDMA_5 (PCIE1 MCU DMA1) */ { 0x820c0000, 0x408000, 0x04000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x40c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ { 0x820cc000, 0x40e000, 0x02000 }, /* WF_UMAC_TOP (PP) */ { 0x820e0000, 0x420000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ { 0x820e1000, 0x420400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ { 0x820e2000, 0x420800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ { 0x820e3000, 0x420c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ { 0x820e4000, 0x421000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ { 0x820e5000, 0x421400, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ { 0x820ce000, 0x421c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820e7000, 0x421e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820cf000, 0x422000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ { 0x820e9000, 0x423400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ { 0x820ea000, 0x424000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ { 0x820eb000, 0x424200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ { 0x820ec000, 0x424600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ { 0x820ed000, 0x424800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ { 0x820ca000, 0x426000, 0x02000 }, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ { 0x820d0000, 0x430000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x00400000, 0x480000, 0x10000 }, /* WF_MCU_SYSRAM */ { 0x00410000, 0x490000, 0x10000 }, /* WF_MCU_SYSRAM */ { 0x820f0000, 0x4a0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ { 0x820f1000, 0x4a0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ { 0x820f2000, 0x4a0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ { 0x820f3000, 0x4a0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ { 0x820f4000, 0x4a1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ { 0x820f5000, 0x4a1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ { 0x820f7000, 0x4a1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ { 0x820f9000, 0x4a3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ { 0x820fa000, 0x4a4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ { 0x820fb000, 0x4a4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ { 0x820fc000, 0x4a4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ { 0x820fd000, 0x4a4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ { 0x820c4000, 0x4a8000, 0x01000 }, /* WF_LMAC_TOP (WF_UWTBL ) */ { 0x820b0000, 0x4ae000, 0x01000 }, /* [APB2] WFSYS_ON */ { 0x80020000, 0x4b0000, 0x10000 }, /* WF_TOP_MISC_OFF */ { 0x81020000, 0x4c0000, 0x10000 }, /* WF_TOP_MISC_ON */ { 0x89000000, 0x4d0000, 0x01000 }, /* WF_MCU_CFG_ON */ { 0x89010000, 0x4d1000, 0x01000 }, /* WF_MCU_CIRQ */ { 0x89020000, 0x4d2000, 0x01000 }, /* WF_MCU_GPT */ { 0x89030000, 0x4d3000, 0x01000 }, /* WF_MCU_WDT */ { 0x80010000, 0x4d4000, 0x01000 }, /* WF_AXIDMA */ { 0x0, 0x0, 0x0 }, /* imply end of search */ }; static u32 mt7915_reg_map_l1(struct mt7915_dev *dev, u32 addr) { u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); u32 l1_remap; if (is_mt798x(&dev->mt76)) return MT_CONN_INFRA_OFFSET(addr); l1_remap = is_mt7915(&dev->mt76) ? MT_HIF_REMAP_L1 : MT_HIF_REMAP_L1_MT7916; dev->bus_ops->rmw(&dev->mt76, l1_remap, MT_HIF_REMAP_L1_MASK, FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, l1_remap); return MT_HIF_REMAP_BASE_L1 + offset; } static u32 mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr) { u32 offset, base; if (is_mt7915(&dev->mt76)) { offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); } else { u32 ofs = is_mt798x(&dev->mt76) ? 0x400000 : 0; offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET_MT7916, addr); base = FIELD_GET(MT_HIF_REMAP_L2_BASE_MT7916, addr); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2_MT7916 + ofs, MT_HIF_REMAP_L2_MASK_MT7916, FIELD_PREP(MT_HIF_REMAP_L2_MASK_MT7916, base)); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2_MT7916 + ofs); offset += (MT_HIF_REMAP_BASE_L2_MT7916 + ofs); } return offset; } static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) { int i; if (addr < 0x100000) return addr; if (!dev->reg.map) { dev_err(dev->mt76.dev, "err: reg_map is null\n"); return addr; } for (i = 0; i < dev->reg.map_size; i++) { u32 ofs; if (addr < dev->reg.map[i].phys) continue; ofs = addr - dev->reg.map[i].phys; - if (ofs > dev->reg.map[i].size) + if (ofs >= dev->reg.map[i].size) continue; return dev->reg.map[i].maps + ofs; } + return 0; +} + +static u32 __mt7915_reg_remap_addr(struct mt7915_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) return mt7915_reg_map_l1(dev, addr); if (dev_is_pci(dev->mt76.dev) && ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || addr >= MT_CBTOP2_PHY_START)) return mt7915_reg_map_l1(dev, addr); /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ if (addr >= MT_INFRA_MCU_START && addr <= MT_INFRA_MCU_END) { addr = addr - MT_INFRA_MCU_START + MT_INFRA_BASE; return mt7915_reg_map_l1(dev, addr); } return mt7915_reg_map_l2(dev, addr); } void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, size_t len) { u32 addr = __mt7915_reg_addr(dev, offset); + if (addr) { #if defined(__linux__) - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); #elif defined(__FreeBSD__) - memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + addr, len); + memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + addr, len); #endif + return; + } + + spin_lock_bh(&dev->reg_lock); +#if defined(__linux__) + memcpy_fromio(buf, dev->mt76.mmio.regs + +#elif defined(__FreeBSD__) + memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + +#endif + __mt7915_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - u32 addr = __mt7915_reg_addr(dev, offset); + u32 addr = __mt7915_reg_addr(dev, offset), val; - return dev->bus_ops->rr(mdev, addr); -} + if (addr) + return dev->bus_ops->rr(mdev, addr); -static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) -{ - struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); - u32 addr = __mt7915_reg_addr(dev, offset); + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7915_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); - dev->bus_ops->wr(mdev, addr, val); + return val; } -static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); u32 addr = __mt7915_reg_addr(dev, offset); - return dev->bus_ops->rmw(mdev, addr, mask, val); -} - -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->mt76.token_lock); - - return !wait_event_timeout(dev->mt76.tx_wait, - !dev->mt76.wed_token_count, HZ); -} - -static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = MT7915_TOKEN_SIZE; - spin_unlock_bh(&dev->mt76.token_lock); -} - -static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - int i; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - for (i = 0; i < dev->mt76.rx_token_size; i++) { - struct mt76_txwi_cache *t; - - t = mt76_rx_token_release(&dev->mt76, i); - if (!t || !t->ptr) - continue; - - mt76_put_page_pool_buf(t->ptr, false); - t->ptr = NULL; - - mt76_put_rxwi(&dev->mt76, t); + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; } - mt76_free_pending_rxwi(&dev->mt76); + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7915_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } -static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { - struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc; - struct mt76_txwi_cache *t = NULL; - struct mt7915_dev *dev; - struct mt76_queue *q; - int i, len; + struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); + u32 addr = __mt7915_reg_addr(dev, offset); - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - len = SKB_WITH_OVERHEAD(q->buf_size); - - for (i = 0; i < size; i++) { - enum dma_data_direction dir; - dma_addr_t addr; - u32 offset; - int token; - void *buf; - - t = mt76_get_rxwi(&dev->mt76); - if (!t) - goto unmap; - - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); - if (!buf) - goto unmap; - - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir); - - desc->buf0 = cpu_to_le32(addr); - token = mt76_rx_token_consume(&dev->mt76, buf, t, addr); - if (token < 0) { - mt76_put_page_pool_buf(buf, false); - goto unmap; - } + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, - token)); - desc++; - } + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7915_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); - return 0; - -unmap: - if (t) - mt76_put_rxwi(&dev->mt76, t); - mt7915_mmio_wed_release_rx_buf(wed); - return -ENOMEM; + return val; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { int idx = le16_to_cpu(stats->wlan_idx); struct mt7915_dev *dev; struct mt76_wcid *wcid; dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); if (idx >= mt7915_wtbl_size(dev)) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[idx]); if (wcid) { wcid->stats.rx_bytes += le32_to_cpu(stats->rx_byte_cnt); wcid->stats.rx_packets += le32_to_cpu(stats->rx_pkt_cnt); wcid->stats.rx_errors += le32_to_cpu(stats->rx_err_cnt); wcid->stats.rx_drops += le32_to_cpu(stats->rx_drop_cnt); } rcu_read_unlock(); } static int mt7915_mmio_wed_reset(struct mtk_wed_device *wed) { struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed); struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); struct mt76_phy *mphy = &dev->mphy; int ret; ASSERT_RTNL(); if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state)) return -EBUSY; ret = mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L1, mphy->band_idx); if (ret) goto out; rtnl_unlock(); if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) { dev_err(mdev->dev, "wed reset timeout\n"); ret = -ETIMEDOUT; } rtnl_lock(); out: clear_bit(MT76_STATE_WED_RESET, &mphy->state); return ret; } - -static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - complete(&dev->mmio.wed_reset_complete); -} #endif int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, bool pci, int *irq) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED struct mtk_wed_device *wed = &dev->mt76.mmio.wed; int ret; if (!wed_enable) return 0; if (pci) { struct pci_dev *pci_dev = pdev_ptr; wed->wlan.pci_dev = pci_dev; wed->wlan.bus_type = MTK_WED_BUS_PCIE; wed->wlan.base = devm_ioremap(dev->mt76.dev, pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); wed->wlan.phy_base = pci_resource_start(pci_dev, 0); wed->wlan.wpdma_int = pci_resource_start(pci_dev, 0) + MT_INT_WED_SOURCE_CSR; wed->wlan.wpdma_mask = pci_resource_start(pci_dev, 0) + MT_INT_WED_MASK_CSR; wed->wlan.wpdma_phys = pci_resource_start(pci_dev, 0) + MT_WFDMA_EXT_CSR_BASE; wed->wlan.wpdma_tx = pci_resource_start(pci_dev, 0) + MT_TXQ_WED_RING_BASE; wed->wlan.wpdma_txfree = pci_resource_start(pci_dev, 0) + MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = pci_resource_start(pci_dev, 0) + MT_WPDMA_GLO_CFG; wed->wlan.wpdma_rx = pci_resource_start(pci_dev, 0) + MT_RXQ_WED_DATA_RING_BASE; } else { struct platform_device *plat_dev = pdev_ptr; struct resource *res; res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); if (!res) - return -ENOMEM; + return 0; wed->wlan.platform_dev = plat_dev; wed->wlan.bus_type = MTK_WED_BUS_AXI; wed->wlan.base = devm_ioremap(dev->mt76.dev, res->start, resource_size(res)); wed->wlan.phy_base = res->start; wed->wlan.wpdma_int = res->start + MT_INT_SOURCE_CSR; wed->wlan.wpdma_mask = res->start + MT_INT_MASK_CSR; wed->wlan.wpdma_tx = res->start + MT_TXQ_WED_RING_BASE; wed->wlan.wpdma_txfree = res->start + MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = res->start + MT_WPDMA_GLO_CFG; wed->wlan.wpdma_rx = res->start + MT_RXQ_WED_DATA_RING_BASE; } wed->wlan.nbuf = MT7915_HW_TOKEN_SIZE; wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30; wed->wlan.tx_tbit[1] = is_mt7915(&dev->mt76) ? 5 : 31; wed->wlan.txfree_tbit = is_mt798x(&dev->mt76) ? 2 : 1; wed->wlan.token_start = MT7915_TOKEN_SIZE - wed->wlan.nbuf; wed->wlan.wcid_512 = !is_mt7915(&dev->mt76); wed->wlan.rx_nbuf = 65536; wed->wlan.rx_npkt = MT7915_WED_RX_TOKEN_SIZE; wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); if (is_mt7915(&dev->mt76)) { wed->wlan.rx_tbit[0] = 16; wed->wlan.rx_tbit[1] = 17; } else if (is_mt798x(&dev->mt76)) { wed->wlan.rx_tbit[0] = 22; wed->wlan.rx_tbit[1] = 23; } else { wed->wlan.rx_tbit[0] = 18; wed->wlan.rx_tbit[1] = 19; } wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; - wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_wed_offload_enable; + wed->wlan.offload_disable = mt76_wed_offload_disable; + wed->wlan.init_rx_buf = mt76_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; - wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_wed_reset_complete; dev->mt76.rx_token_size = wed->wlan.rx_npkt; if (mtk_wed_device_attach(wed)) return 0; *irq = wed->irq; dev->mt76.dma_dev = wed->dev; ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); if (ret) return ret; return 1; #else return 0; #endif } static int mt7915_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, u32 device_id) { struct mt76_bus_ops *bus_ops; struct mt7915_dev *dev; dev = container_of(mdev, struct mt7915_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7915: dev->reg.reg_rev = mt7915_reg; dev->reg.offs_rev = mt7915_offs; dev->reg.map = mt7915_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7915_reg_map); break; case 0x7906: dev->reg.reg_rev = mt7916_reg; dev->reg.offs_rev = mt7916_offs; dev->reg.map = mt7916_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7916_reg_map); break; case 0x7981: case 0x7986: dev->reg.reg_rev = mt7986_reg; dev->reg.offs_rev = mt7916_offs; dev->reg.map = mt7986_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7986_reg_map); break; default: return -EINVAL; } dev->bus_ops = dev->mt76.bus; bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), GFP_KERNEL); if (!bus_ops) return -ENOMEM; bus_ops->rr = mt7915_rr; bus_ops->wr = mt7915_wr; bus_ops->rmw = mt7915_rmw; dev->mt76.bus = bus_ops; mdev->rev = (device_id << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); return 0; } void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, u32 clear, u32 set) { struct mt76_dev *mdev = &dev->mt76; unsigned long flags; spin_lock_irqsave(&mdev->mmio.irq_lock, flags); mdev->mmio.irqmask &= ~clear; mdev->mmio.irqmask |= set; if (write_reg) { if (mtk_wed_device_active(&mdev->mmio.wed)) mtk_wed_device_irq_set_mask(&mdev->mmio.wed, mdev->mmio.irqmask); else mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); } spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); } static void mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); mt7915_irq_enable(dev, MT_INT_RX(q)); } /* TODO: support 2/4/6/8 MSI-X vectors */ static void mt7915_irq_tasklet(struct tasklet_struct *t) { struct mt7915_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); struct mtk_wed_device *wed = &dev->mt76.mmio.wed; u32 intr, intr1, mask; if (mtk_wed_device_active(wed)) { mtk_wed_device_irq_set_mask(wed, 0); if (dev->hif2) mt76_wr(dev, MT_INT1_MASK_CSR, 0); intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); } else { mt76_wr(dev, MT_INT_MASK_CSR, 0); if (dev->hif2) mt76_wr(dev, MT_INT1_MASK_CSR, 0); intr = mt76_rr(dev, MT_INT_SOURCE_CSR); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT_SOURCE_CSR, intr); } if (dev->hif2) { intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); intr1 &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); intr |= intr1; } trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask = intr & MT_INT_RX_DONE_ALL; if (intr & MT_INT_TX_DONE_MCU) mask |= MT_INT_TX_DONE_MCU; mt7915_irq_disable(dev, mask); if (intr & MT_INT_TX_DONE_MCU) napi_schedule(&dev->mt76.tx_napi); if (intr & MT_INT_RX(MT_RXQ_MAIN)) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]); if (intr & MT_INT_RX(MT_RXQ_BAND1)) napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1]); if (intr & MT_INT_RX(MT_RXQ_MCU)) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]); if (intr & MT_INT_RX(MT_RXQ_MCU_WA)) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]); if (!is_mt7915(&dev->mt76) && (intr & MT_INT_RX(MT_RXQ_MAIN_WA))) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN_WA]); if (intr & MT_INT_RX(MT_RXQ_BAND1_WA)) napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1_WA]); if (intr & MT_INT_MCU_CMD) { u32 val = mt76_rr(dev, MT_MCU_CMD); mt76_wr(dev, MT_MCU_CMD, val); if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { dev->recovery.state = val; mt7915_reset(dev); } } } irqreturn_t mt7915_irq_handler(int irq, void *dev_instance) { struct mt7915_dev *dev = dev_instance; struct mtk_wed_device *wed = &dev->mt76.mmio.wed; if (mtk_wed_device_active(wed)) mtk_wed_device_irq_set_mask(wed, 0); else mt76_wr(dev, MT_INT_MASK_CSR, 0); if (dev->hif2) mt76_wr(dev, MT_INT1_MASK_CSR, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; tasklet_schedule(&dev->mt76.irq_tasklet); return IRQ_HANDLED; } struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, void __iomem *mem_base, u32 device_id) { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .token_size = MT7915_TOKEN_SIZE, .tx_prepare_skb = mt7915_tx_prepare_skb, .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_skb = mt7915_queue_rx_skb, .rx_check = mt7915_rx_check, .rx_poll_complete = mt7915_rx_poll_complete, .sta_add = mt7915_mac_sta_add, + .sta_event = mt7915_mac_sta_event, .sta_remove = mt7915_mac_sta_remove, .update_survey = mt7915_update_channel, + .set_channel = mt7915_set_channel, }; struct mt7915_dev *dev; struct mt76_dev *mdev; int ret; mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7915_ops, &drv_ops); if (!mdev) return ERR_PTR(-ENOMEM); dev = container_of(mdev, struct mt7915_dev, mt76); ret = mt7915_mmio_init(mdev, mem_base, device_id); if (ret) goto error; tasklet_setup(&mdev->irq_tasklet, mt7915_irq_tasklet); return dev; error: mt76_free_device(&dev->mt76); return ERR_PTR(ret); } static int __init mt7915_init(void) { int ret; ret = pci_register_driver(&mt7915_hif_driver); if (ret) return ret; ret = pci_register_driver(&mt7915_pci_driver); if (ret) goto error_pci; if (IS_ENABLED(CONFIG_MT798X_WMAC)) { ret = platform_driver_register(&mt798x_wmac_driver); if (ret) goto error_wmac; } return 0; error_wmac: pci_unregister_driver(&mt7915_pci_driver); error_pci: pci_unregister_driver(&mt7915_hif_driver); return ret; } static void __exit mt7915_exit(void) { if (IS_ENABLED(CONFIG_MT798X_WMAC)) platform_driver_unregister(&mt798x_wmac_driver); pci_unregister_driver(&mt7915_pci_driver); pci_unregister_driver(&mt7915_hif_driver); } module_init(mt7915_init); module_exit(mt7915_exit); +MODULE_DESCRIPTION("MediaTek MT7915E MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/mt7915.h b/sys/contrib/dev/mediatek/mt76/mt7915/mt7915.h index f25d0c107d43..afec39e8703b 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/mt7915.h +++ b/sys/contrib/dev/mediatek/mt76/mt7915/mt7915.h @@ -1,597 +1,608 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_H #define __MT7915_H #include #include #if defined(__FreeBSD__) #include #endif #include "../mt76_connac.h" #include "regs.h" #define MT7915_MAX_INTERFACES 19 #define MT7915_WTBL_SIZE 288 #define MT7916_WTBL_SIZE 544 #define MT7915_WTBL_RESERVED (mt7915_wtbl_size(dev) - 1) #define MT7915_WTBL_STA (MT7915_WTBL_RESERVED - \ MT7915_MAX_INTERFACES) #define MT7915_WATCHDOG_TIME (HZ / 10) #define MT7915_RESET_TIMEOUT (30 * HZ) #define MT7915_TX_RING_SIZE 2048 #define MT7915_TX_MCU_RING_SIZE 256 #define MT7915_TX_FWDL_RING_SIZE 128 #define MT7915_RX_RING_SIZE 1536 #define MT7915_RX_MCU_RING_SIZE 512 #define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin" #define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin" #define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" #define MT7916_FIRMWARE_WA "mediatek/mt7916_wa.bin" #define MT7916_FIRMWARE_WM "mediatek/mt7916_wm.bin" #define MT7916_ROM_PATCH "mediatek/mt7916_rom_patch.bin" #define MT7981_FIRMWARE_WA "mediatek/mt7981_wa.bin" #define MT7981_FIRMWARE_WM "mediatek/mt7981_wm.bin" #define MT7981_ROM_PATCH "mediatek/mt7981_rom_patch.bin" #define MT7986_FIRMWARE_WA "mediatek/mt7986_wa.bin" #define MT7986_FIRMWARE_WM "mediatek/mt7986_wm.bin" #define MT7986_FIRMWARE_WM_MT7975 "mediatek/mt7986_wm_mt7975.bin" #define MT7986_ROM_PATCH "mediatek/mt7986_rom_patch.bin" #define MT7986_ROM_PATCH_MT7975 "mediatek/mt7986_rom_patch_mt7975.bin" #define MT7915_EEPROM_DEFAULT "mediatek/mt7915_eeprom.bin" #define MT7915_EEPROM_DEFAULT_DBDC "mediatek/mt7915_eeprom_dbdc.bin" #define MT7916_EEPROM_DEFAULT "mediatek/mt7916_eeprom.bin" #define MT7981_EEPROM_MT7976_DEFAULT_DBDC "mediatek/mt7981_eeprom_mt7976_dbdc.bin" #define MT7986_EEPROM_MT7975_DEFAULT "mediatek/mt7986_eeprom_mt7975.bin" #define MT7986_EEPROM_MT7975_DUAL_DEFAULT "mediatek/mt7986_eeprom_mt7975_dual.bin" #define MT7986_EEPROM_MT7976_DEFAULT "mediatek/mt7986_eeprom_mt7976.bin" #define MT7986_EEPROM_MT7976_DEFAULT_DBDC "mediatek/mt7986_eeprom_mt7976_dbdc.bin" #define MT7986_EEPROM_MT7976_DUAL_DEFAULT "mediatek/mt7986_eeprom_mt7976_dual.bin" #define MT7915_EEPROM_SIZE 3584 #define MT7916_EEPROM_SIZE 4096 #define MT7915_EEPROM_BLOCK_SIZE 16 #define MT7915_HW_TOKEN_SIZE 4096 #define MT7915_TOKEN_SIZE 8192 #define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT7915_THERMAL_THROTTLE_MAX 100 #define MT7915_CDEV_THROTTLE_MAX 99 #define MT7915_SKU_RATE_NUM 161 #define MT7915_MAX_TWT_AGRT 16 #define MT7915_MAX_STA_TWT_AGRT 8 #define MT7915_MIN_TWT_DUR 64 #define MT7915_MAX_QUEUE (MT_RXQ_BAND2 + __MT_MCUQ_MAX + 2) #define MT7915_WED_RX_TOKEN_SIZE 12288 #define MT7915_CRIT_TEMP_IDX 0 #define MT7915_MAX_TEMP_IDX 1 #define MT7915_CRIT_TEMP 110 #define MT7915_MAX_TEMP 120 struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; struct mt7915_dfs_pattern; enum mt7915_txq_id { MT7915_TXQ_FWDL = 16, MT7915_TXQ_MCU_WM, MT7915_TXQ_BAND0, MT7915_TXQ_BAND1, MT7915_TXQ_MCU_WA, }; enum mt7915_rxq_id { MT7915_RXQ_BAND0 = 0, MT7915_RXQ_BAND1, MT7915_RXQ_MCU_WM = 0, MT7915_RXQ_MCU_WA, MT7915_RXQ_MCU_WA_EXT, }; enum mt7916_rxq_id { MT7916_RXQ_MCU_WM = 0, MT7916_RXQ_MCU_WA, MT7916_RXQ_MCU_WA_MAIN, MT7916_RXQ_MCU_WA_EXT, MT7916_RXQ_BAND0, MT7916_RXQ_BAND1, }; 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; }; DECLARE_EWMA(avg_signal, 10, 8) struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ struct mt7915_vif *vif; struct list_head rc_list; u32 airtime_ac[8]; int ack_signal; struct ewma_avg_signal avg_ack_signal; unsigned long changed; unsigned long jiffies; struct mt76_connac_sta_key_conf bip; struct { u8 flowid_mask; struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT]; } twt; }; struct mt7915_vif_cap { bool ht_ldpc:1; bool vht_ldpc:1; bool he_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 { - struct mt76_vif mt76; /* must be first */ + struct mt76_vif_link mt76; /* must be first */ struct mt7915_vif_cap cap; struct mt7915_sta sta; struct mt7915_phy *phy; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; struct cfg80211_bitrate_mask bitrate_mask; }; /* crash-dump */ struct mt7915_crash_data { guid_t guid; struct timespec64 timestamp; u8 *memdump_buf; size_t memdump_buf_len; }; struct mt7915_hif { struct list_head list; struct device *dev; void __iomem *regs; int irq; + u32 index; }; struct mt7915_phy { struct mt76_phy *mt76; struct mt7915_dev *dev; struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; struct ieee80211_vif *monitor_vif; struct thermal_cooling_device *cdev; u8 cdev_state; u8 throttle_state; u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ u32 rxfilter; u64 omac_mask; u16 noise; s16 coverage_class; u8 slottime; u8 rdd_state; u32 trb_ts; u32 rx_ampdu_ts; u32 ampdu_ref; struct mt76_mib_stats mib; struct mt76_channel_state state_ts; #ifdef CONFIG_NL80211_TESTMODE struct { u32 *reg_backup; s32 last_freq_offset; u8 last_rcpi[4]; s8 last_ib_rssi[4]; s8 last_wb_rssi[4]; u8 last_snr; u8 spe_idx; } test; #endif }; struct mt7915_dev { union { /* must be first */ struct mt76_dev mt76; struct mt76_phy mphy; }; struct mt7915_hif *hif2; struct mt7915_reg_desc reg; u8 q_id[MT7915_MAX_QUEUE]; u32 q_int_mask[MT7915_MAX_QUEUE]; u32 wfdma_mask; const struct mt76_bus_ops *bus_ops; struct mt7915_phy phy; /* monitor rx chain configured channel */ struct cfg80211_chan_def rdd2_chandef; struct mt7915_phy *rdd2_phy; u16 chainmask; u16 chainshift; u32 hif_idx; struct work_struct init_work; struct work_struct rc_work; struct work_struct dump_work; struct work_struct reset_work; wait_queue_head_t reset_wait; struct { u32 state; u32 wa_reset_count; u32 wm_reset_count; bool hw_full_reset:1; bool hw_init_done:1; bool restart:1; } recovery; /* protects coredump data */ struct mutex dump_mutex; #ifdef CONFIG_DEV_COREDUMP struct { struct mt7915_crash_data *crash_data; } coredump; #endif struct list_head sta_rc_list; struct list_head twt_list; + spinlock_t reg_lock; u32 hw_pattern; bool dbdc_support; bool flash_mode; bool muru_debug; bool ibf; + u8 monitor_mask; + struct dentry *debugfs_dir; struct rchan *relay_fwlog; void *cal; + u32 cur_prek_offset; + u8 dpd_chan_num_2g; + u8 dpd_chan_num_5g; + u8 dpd_chan_num_6g; struct { u8 debug_wm; u8 debug_wa; u8 debug_bin; } fw; struct { u16 table_mask; u8 n_agrt; } twt; struct reset_control *rstc; void __iomem *dcm; void __iomem *sku; }; enum { WFDMA0 = 0x0, WFDMA1, WFDMA_EXT, __MT_WFDMA_MAX, }; enum { MT_RX_SEL0, MT_RX_SEL1, MT_RX_SEL2, /* monitor chain */ }; enum mt7915_rdd_cmd { RDD_STOP, RDD_START, RDD_DET_MODE, RDD_RADAR_EMULATE, RDD_START_TXQ = 20, RDD_SET_WF_ANT = 30, RDD_CAC_START = 50, RDD_CAC_END, RDD_NORMAL_START, RDD_DISABLE_DFS_CAL, RDD_PULSE_DBG, RDD_READ_PULSE, RDD_RESUME_BF, RDD_IRQ_OFF, }; static inline struct mt7915_phy * mt7915_hw_phy(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return phy->priv; } static inline struct mt7915_dev * mt7915_hw_dev(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return container_of(phy->dev, struct mt7915_dev, mt76); } static inline struct mt7915_phy * mt7915_ext_phy(struct mt7915_dev *dev) { struct mt76_phy *phy = dev->mt76.phys[MT_BAND1]; if (!phy) return NULL; return phy->priv; } static inline u32 mt7915_check_adie(struct mt7915_dev *dev, bool sku) { u32 mask = sku ? MT_CONNINFRA_SKU_MASK : MT_ADIE_TYPE_MASK; if (!is_mt798x(&dev->mt76)) return 0; return mt76_rr(dev, MT_CONNINFRA_SKU_DEC_ADDR) & mask; } extern const struct ieee80211_ops mt7915_ops; extern const struct mt76_testmode_ops mt7915_testmode_ops; extern struct pci_driver mt7915_pci_driver; extern struct pci_driver mt7915_hif_driver; extern struct platform_driver mt798x_wmac_driver; #ifdef CONFIG_MT798X_WMAC int mt7986_wmac_enable(struct mt7915_dev *dev); void mt7986_wmac_disable(struct mt7915_dev *dev); #else static inline int mt7986_wmac_enable(struct mt7915_dev *dev) { return 0; } static inline void mt7986_wmac_disable(struct mt7915_dev *dev) { } #endif struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, void __iomem *mem_base, u32 device_id); void mt7915_wfsys_reset(struct mt7915_dev *dev); irqreturn_t mt7915_irq_handler(int irq, void *dev_instance); u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif); u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); int mt7915_register_device(struct mt7915_dev *dev); void mt7915_unregister_device(struct mt7915_dev *dev); int mt7915_eeprom_init(struct mt7915_dev *dev); void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, struct mt7915_phy *phy); int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band); int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset); int mt7915_txbf_init(struct mt7915_dev *dev); -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband); +void mt7915_init_txpower(struct mt7915_phy *phy); void mt7915_reset(struct mt7915_dev *dev); int mt7915_run(struct ieee80211_hw *hw); int mt7915_mcu_init(struct mt7915_dev *dev); int mt7915_mcu_init_firmware(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); + struct ieee80211_sta *sta, int conn_state, bool newly); int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev, struct ieee80211_ampdu_params *params, bool add); int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev, struct ieee80211_ampdu_params *params, bool add); 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_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif, + u32 changed); int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable, u32 changed); int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed); int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int mt7915_set_channel(struct mt7915_phy *phy); +int mt7915_set_channel(struct mt76_phy *mphy); int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd); int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif); int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *req); int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, void *data, u32 field); int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num); int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, bool hdr_trans); int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode, u8 en); int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len); int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower); int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, s8 txpower); int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); 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_set_thermal_protect(struct mt7915_phy *phy); 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_background_enable(struct mt7915_phy *phy, struct cfg80211_chan_def *chandef); int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wcid); int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set); int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl); int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level); void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb); void mt7915_mcu_exit(struct mt7915_dev *dev); static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev) { return is_mt7915(&dev->mt76) ? MT7915_WTBL_SIZE : MT7916_WTBL_SIZE; } static inline u16 mt7915_eeprom_size(struct mt7915_dev *dev) { return is_mt7915(&dev->mt76) ? MT7915_EEPROM_SIZE : MT7916_EEPROM_SIZE; } void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, bool write_reg, u32 clear, u32 set); static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask) { if (dev->hif2) mt7915_dual_hif_set_irq_mask(dev, false, 0, mask); else mt76_set_irq_mask(&dev->mt76, 0, 0, mask); tasklet_schedule(&dev->mt76.irq_tasklet); } static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) { if (dev->hif2) mt7915_dual_hif_set_irq_mask(dev, true, mask, 0); else mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, size_t len); void mt7915_mac_init(struct mt7915_dev *dev); u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw); bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, struct ieee80211_vif *vif, bool enable); void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, enum mt76_txq_id qid, u32 changed); void mt7915_mac_set_timing(struct mt7915_phy *phy); int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7915_mac_work(struct work_struct *work); void mt7915_mac_reset_work(struct work_struct *work); void mt7915_mac_dump_work(struct work_struct *work); void mt7915_mac_sta_rc_work(struct work_struct *work); void mt7915_mac_update_stats(struct mt7915_phy *phy); 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, struct mt76_tx_info *tx_info); void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7915_stats_work(struct work_struct *work); int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force); 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_mcu_muru_debug_set(struct mt7915_dev *dev, bool enable); int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy); int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev); int mt7915_init_debugfs(struct mt7915_phy *phy); void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len); bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len); #ifdef CONFIG_MAC80211_DEBUGFS void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, bool pci, int *irq); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/pci.c b/sys/contrib/dev/mediatek/mt76/mt7915/pci.c index 9fdfd5204a71..26acac3e59fd 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/pci.c @@ -1,271 +1,272 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * Author: Ryder Lee */ #if defined(__FreeBSD__) #define LINUXKPI_PARAM_PREFIX mt7915_pci_ #endif #include #include #include #include "mt7915.h" #include "mac.h" #include "../trace.h" #if defined(__linux__) static LIST_HEAD(hif_list); #elif defined(__FreeBSD__) static LINUX_LIST_HEAD(hif_list); #endif static DEFINE_SPINLOCK(hif_lock); static u32 hif_idx; static const struct pci_device_id mt7915_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7915) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7906) }, { }, }; static const struct pci_device_id mt7915_hif_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7916) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x790a) }, { }, }; static struct mt7915_hif *mt7915_pci_get_hif2(u32 idx) { struct mt7915_hif *hif; u32 val; spin_lock_bh(&hif_lock); list_for_each_entry(hif, &hif_list, list) { #if defined(__linux__) val = readl(hif->regs + MT_PCIE_RECOG_ID); #elif defined(__FreeBSD__) val = readl((u8 *)hif->regs + MT_PCIE_RECOG_ID); #endif val &= MT_PCIE_RECOG_ID_MASK; if (val != idx) continue; get_device(hif->dev); + hif->index = idx; goto out; } hif = NULL; out: spin_unlock_bh(&hif_lock); return hif; } static void mt7915_put_hif2(struct mt7915_hif *hif) { if (!hif) return; put_device(hif->dev); } static struct mt7915_hif *mt7915_pci_init_hif2(struct pci_dev *pdev) { struct pci_dev *tmp_pdev; hif_idx++; #if defined(__linux__) tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); #elif defined(__FreeBSD__) tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); #endif if (!tmp_pdev) { #if defined(__linux__) tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); #elif defined(__FreeBSD__) tmp_pdev = linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); #endif if (!tmp_pdev) return NULL; } pci_dev_put(tmp_pdev); writel(hif_idx | MT_PCIE_RECOG_ID_SEM, #if defined(__linux__) pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); #elif defined(__FreeBSD__) (u8 *)(pcim_iomap_table(pdev)[0]) + MT_PCIE_RECOG_ID); #endif return mt7915_pci_get_hif2(hif_idx); } static int mt7915_pci_hif2_probe(struct pci_dev *pdev) { struct mt7915_hif *hif; hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); if (!hif) return -ENOMEM; hif->dev = &pdev->dev; hif->regs = pcim_iomap_table(pdev)[0]; hif->irq = pdev->irq; spin_lock_bh(&hif_lock); list_add(&hif->list, &hif_list); spin_unlock_bh(&hif_lock); pci_set_drvdata(pdev, hif); return 0; } static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct mt7915_hif *hif2 = NULL; struct mt7915_dev *dev; struct mt76_dev *mdev; int irq; int ret; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_set_master(pdev); ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; mt76_pci_disable_aspm(pdev); if (id->device == 0x7916 || id->device == 0x790a) return mt7915_pci_hif2_probe(pdev); dev = mt7915_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], id->device); if (IS_ERR(dev)) return PTR_ERR(dev); mdev = &dev->mt76; mt7915_wfsys_reset(dev); hif2 = mt7915_pci_init_hif2(pdev); ret = mt7915_mmio_wed_init(dev, pdev, true, &irq); if (ret < 0) goto free_wed_or_irq_vector; if (!ret) { hif2 = mt7915_pci_init_hif2(pdev); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) goto free_device; irq = pdev->irq; } ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto free_wed_or_irq_vector; /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); if (hif2) { dev->hif2 = hif2; mt76_wr(dev, MT_INT1_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ if (is_mt7915(mdev)) mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); else mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff); ret = devm_request_irq(mdev->dev, dev->hif2->irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME "-hif", dev); if (ret) goto free_hif2; } ret = mt7915_register_device(dev); if (ret) goto free_hif2_irq; return 0; free_hif2_irq: if (dev->hif2) devm_free_irq(mdev->dev, dev->hif2->irq, dev); free_hif2: if (dev->hif2) put_device(dev->hif2->dev); devm_free_irq(mdev->dev, irq, dev); free_wed_or_irq_vector: if (mtk_wed_device_active(&mdev->mmio.wed)) mtk_wed_device_detach(&mdev->mmio.wed); else pci_free_irq_vectors(pdev); free_device: mt76_free_device(&dev->mt76); return ret; } static void mt7915_hif_remove(struct pci_dev *pdev) { struct mt7915_hif *hif = pci_get_drvdata(pdev); list_del(&hif->list); } static void mt7915_pci_remove(struct pci_dev *pdev) { struct mt76_dev *mdev; struct mt7915_dev *dev; mdev = pci_get_drvdata(pdev); dev = container_of(mdev, struct mt7915_dev, mt76); mt7915_put_hif2(dev->hif2); mt7915_unregister_device(dev); } struct pci_driver mt7915_hif_driver = { .name = KBUILD_MODNAME "_hif", .id_table = mt7915_hif_device_table, .probe = mt7915_pci_probe, .remove = mt7915_hif_remove, }; struct pci_driver mt7915_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7915_pci_device_table, .probe = mt7915_pci_probe, .remove = mt7915_pci_remove, }; MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table); MODULE_DEVICE_TABLE(pci, mt7915_hif_device_table); MODULE_FIRMWARE(MT7915_FIRMWARE_WA); MODULE_FIRMWARE(MT7915_FIRMWARE_WM); MODULE_FIRMWARE(MT7915_ROM_PATCH); MODULE_FIRMWARE(MT7916_FIRMWARE_WA); MODULE_FIRMWARE(MT7916_FIRMWARE_WM); MODULE_FIRMWARE(MT7916_ROM_PATCH); #if defined(__FreeBSD__) MODULE_VERSION(mt7915_pci, 1); MODULE_DEPEND(mt7915_pci, linuxkpi, 1, 1, 1); MODULE_DEPEND(mt7915_pci, linuxkpi_wlan, 1, 1, 1); MODULE_DEPEND(mt7915_pci, mt76_core, 1, 1, 1); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/regs.h b/sys/contrib/dev/mediatek/mt76/mt7915/regs.h index 588cd87e24e9..c5ec63a25a42 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/regs.h +++ b/sys/contrib/dev/mediatek/mt76/mt7915/regs.h @@ -1,1221 +1,1229 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7915_REGS_H #define __MT7915_REGS_H /* used to differentiate between generations */ struct mt7915_reg_desc { const u32 *reg_rev; const u32 *offs_rev; const struct mt76_connac_reg_map *map; u32 map_size; }; enum reg_rev { INT_SOURCE_CSR, INT_MASK_CSR, INT1_SOURCE_CSR, INT1_MASK_CSR, INT_MCU_CMD_SOURCE, INT_MCU_CMD_EVENT, WFDMA0_ADDR, WFDMA0_PCIE1_ADDR, WFDMA_EXT_CSR_ADDR, CBTOP1_PHY_END, INFRA_MCU_ADDR_END, FW_ASSERT_STAT_ADDR, FW_EXCEPT_TYPE_ADDR, FW_EXCEPT_COUNT_ADDR, FW_CIRQ_COUNT_ADDR, FW_CIRQ_IDX_ADDR, FW_CIRQ_LISR_ADDR, FW_TASK_ID_ADDR, FW_TASK_IDX_ADDR, FW_TASK_QID1_ADDR, FW_TASK_QID2_ADDR, FW_TASK_START_ADDR, FW_TASK_END_ADDR, FW_TASK_SIZE_ADDR, FW_LAST_MSG_ID_ADDR, FW_EINT_INFO_ADDR, FW_SCHED_INFO_ADDR, SWDEF_BASE_ADDR, TXQ_WED_RING_BASE, RXQ_WED_RING_BASE, RXQ_WED_DATA_RING_BASE, __MT_REG_MAX, }; enum offs_rev { TMAC_CDTR, TMAC_ODTR, TMAC_ATCR, TMAC_TRCR0, TMAC_ICR0, TMAC_ICR1, TMAC_CTCR0, TMAC_TFCR0, MDP_BNRCFR0, MDP_BNRCFR1, ARB_DRNGR0, ARB_SCR, RMAC_MIB_AIRTIME14, AGG_AWSCR0, AGG_PCR0, AGG_ACR0, AGG_ACR4, AGG_MRCR, + AGG_ATCR0, AGG_ATCR1, AGG_ATCR3, LPON_UTTR0, LPON_UTTR1, LPON_FRCR, MIB_SDR3, MIB_SDR4, MIB_SDR5, MIB_SDR7, MIB_SDR8, MIB_SDR9, MIB_SDR10, MIB_SDR11, MIB_SDR12, MIB_SDR13, MIB_SDR14, MIB_SDR15, MIB_SDR16, MIB_SDR17, MIB_SDR18, MIB_SDR19, MIB_SDR20, MIB_SDR21, MIB_SDR22, MIB_SDR23, MIB_SDR24, MIB_SDR25, MIB_SDR27, MIB_SDR28, MIB_SDR29, MIB_SDRVEC, MIB_SDR31, MIB_SDR32, MIB_SDRMUBF, MIB_DR8, MIB_DR9, MIB_DR11, MIB_MB_SDR0, MIB_MB_SDR1, TX_AGG_CNT, TX_AGG_CNT2, MIB_ARNG, WTBLON_TOP_WDUCR, WTBL_UPDATE, PLE_FL_Q_EMPTY, PLE_FL_Q_CTRL, PLE_AC_QEMPTY, PLE_FREEPG_CNT, PLE_FREEPG_HEAD_TAIL, PLE_PG_HIF_GROUP, PLE_HIF_PG_INFO, AC_OFFSET, ETBF_PAR_RPT0, __MT_OFFS_MAX, }; #define __REG(id) (dev->reg.reg_rev[(id)]) #define __OFFS(id) (dev->reg.offs_rev[(id)]) /* MCU WFDMA0 */ #define MT_MCU_WFDMA0_BASE 0x2000 #define MT_MCU_WFDMA0(ofs) (MT_MCU_WFDMA0_BASE + (ofs)) #define MT_MCU_WFDMA0_DUMMY_CR MT_MCU_WFDMA0(0x120) /* MCU WFDMA1 */ #define MT_MCU_WFDMA1_BASE 0x3000 #define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs)) #define MT_MCU_INT_EVENT __REG(INT_MCU_CMD_EVENT) #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) #define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) #define MT_MCU_INT_EVENT_RESET_DONE BIT(3) /* PLE */ #define MT_PLE_BASE 0x820c0000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) #define MT_PLE_HOST_RPT0 MT_PLE(0x030) #define MT_PLE_HOST_RPT0_TX_LATENCY BIT(3) #define MT_FL_Q_EMPTY MT_PLE(__OFFS(PLE_FL_Q_EMPTY)) #define MT_FL_Q0_CTRL MT_PLE(__OFFS(PLE_FL_Q_CTRL)) #define MT_FL_Q2_CTRL MT_PLE(__OFFS(PLE_FL_Q_CTRL) + 0x8) #define MT_FL_Q3_CTRL MT_PLE(__OFFS(PLE_FL_Q_CTRL) + 0xc) #define MT_PLE_FREEPG_CNT MT_PLE(__OFFS(PLE_FREEPG_CNT)) #define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(__OFFS(PLE_FREEPG_HEAD_TAIL)) #define MT_PLE_PG_HIF_GROUP MT_PLE(__OFFS(PLE_PG_HIF_GROUP)) #define MT_PLE_HIF_PG_INFO MT_PLE(__OFFS(PLE_HIF_PG_INFO)) #define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(__OFFS(PLE_AC_QEMPTY) + \ __OFFS(AC_OFFSET) * \ (ac) + ((n) << 2)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) #define MT_PSE_BASE 0x820c8000 #define MT_PSE(ofs) (MT_PSE_BASE + (ofs)) /* WF MDP TOP */ #define MT_MDP_BASE 0x820cd000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) #define MT_MDP_DCR0 MT_MDP(0x000) #define MT_MDP_DCR0_DAMSDU_EN BIT(15) +#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) #define MT_MDP_DCR1 MT_MDP(0x004) #define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3) #define MT_MDP_DCR2 MT_MDP(0x0e8) #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) #define MT_MDP_BNRCFR0(_band) MT_MDP(__OFFS(MDP_BNRCFR0) + \ ((_band) << 8)) #define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4) #define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6) #define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8) #define MT_MDP_BNRCFR1(_band) MT_MDP(__OFFS(MDP_BNRCFR1) + \ ((_band) << 8)) #define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22) #define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27) #define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29) #define MT_MDP_TO_HIF 0 #define MT_MDP_TO_WM 1 /* TRB: band 0(0x820e1000), band 1(0x820f1000) */ #define MT_WF_TRB_BASE(_band) ((_band) ? 0x820f1000 : 0x820e1000) #define MT_WF_TRB(_band, ofs) (MT_WF_TRB_BASE(_band) + (ofs)) #define MT_TRB_RXPSR0(_band) MT_WF_TRB(_band, 0x03c) #define MT_TRB_RXPSR0_RX_WTBL_PTR GENMASK(25, 16) #define MT_TRB_RXPSR0_RX_RMAC_PTR GENMASK(9, 0) /* TMAC: band 0(0x820e4000), band 1(0x820f4000) */ #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) #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, __OFFS(TMAC_CDTR)) #define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, __OFFS(TMAC_ODTR)) #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) #define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) #define MT_TMAC_ATCR(_band) MT_WF_TMAC(_band, __OFFS(TMAC_ATCR)) #define MT_TMAC_ATCR_TXV_TOUT GENMASK(7, 0) #define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, __OFFS(TMAC_TRCR0)) #define MT_TMAC_TRCR0_TR2T_CHK GENMASK(8, 0) #define MT_TMAC_TRCR0_I2T_CHK GENMASK(24, 16) #define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, __OFFS(TMAC_ICR0)) #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, __OFFS(TMAC_ICR1)) #define MT_IFS_EIFS_CCK GENMASK(8, 0) #define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, __OFFS(TMAC_CTCR0)) #define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) #define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17) #define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, __OFFS(TMAC_TFCR0)) /* WF DMA TOP: band 0(0x820e7000),band 1(0x820f7000) */ #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) #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) /* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */ #define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000) #define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs)) #define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008) #define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30) #define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24) +#define MT_WTBLOFF_TOP_ACR(_band) MT_WTBLOFF_TOP(_band, 0x010) +#define MT_WTBLOFF_TOP_ADM_BACKOFFTIME BIT(29) + /* ETBF: band 0(0x820ea000), band 1(0x820fa000) */ #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_NDP_BFRP(_band) MT_WF_ETBF(_band, 0x040) #define MT_ETBF_TX_FB_CPL GENMASK(31, 16) #define MT_ETBF_TX_FB_TRI GENMASK(15, 0) #define MT_ETBF_PAR_RPT0(_band) MT_WF_ETBF(_band, __OFFS(ETBF_PAR_RPT0)) #define MT_ETBF_PAR_RPT0_FB_BW GENMASK(7, 6) #define MT_ETBF_PAR_RPT0_FB_NC GENMASK(5, 3) #define MT_ETBF_PAR_RPT0_FB_NR GENMASK(2, 0) #define MT_ETBF_TX_APP_CNT(_band) MT_WF_ETBF(_band, 0x0f0) #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, 0x0f8) #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) /* LPON: band 0(0x820eb000), band 1(0x820fb000) */ #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, __OFFS(LPON_UTTR0)) #define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, __OFFS(LPON_UTTR1)) #define MT_LPON_FRCR(_band) MT_WF_LPON(_band, __OFFS(LPON_FRCR)) #define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + \ (((n) * 4) << 1)) #define MT_LPON_TCR_MT7916(_band, n) MT_WF_LPON(_band, 0x0a8 + \ (((n) * 4) << 4)) #define MT_LPON_TCR_SW_MODE GENMASK(1, 0) #define MT_LPON_TCR_SW_WRITE BIT(0) #define MT_LPON_TCR_SW_ADJUST BIT(1) #define MT_LPON_TCR_SW_READ GENMASK(1, 0) /* MIB: band 0(0x820ed000), band 1(0x820fd000) */ /* 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) ? 0x820fd000 : 0x820ed000) #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, __OFFS(MIB_SDR3)) #define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0) #define MT_MIB_SDR3_FCS_ERR_MASK_MT7916 GENMASK(31, 16) #define MT_MIB_SDR4(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR4)) #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, __OFFS(MIB_SDR5)) #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, __OFFS(MIB_SDR7)) #define MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK GENMASK(15, 0) #define MT_MIB_SDR8(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR8)) #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, __OFFS(MIB_SDR9)) #define MT_MIB_SDR9_CCA_BUSY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR10(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR10)) #define MT_MIB_SDR10_MRDY_COUNT_MASK GENMASK(25, 0) #define MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916 GENMASK(31, 0) #define MT_MIB_SDR11(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR11)) #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, __OFFS(MIB_SDR12)) #define MT_MIB_SDR13(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR13)) #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, __OFFS(MIB_SDR14)) #define MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK GENMASK(23, 0) #define MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916 GENMASK(31, 0) /* counts all successfully tx'd mpdus in ampdu */ #define MT_MIB_SDR15(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR15)) #define MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK GENMASK(23, 0) #define MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916 GENMASK(31, 0) /* in units of 'us' */ #define MT_MIB_SDR16(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR16)) #define MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR17(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR17)) #define MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR18(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR18)) #define MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK GENMASK(23, 0) /* units are us */ #define MT_MIB_SDR19(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR19)) #define MT_MIB_SDR19_CCK_MDRDY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR20(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR20)) #define MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK GENMASK(23, 0) #define MT_MIB_SDR21(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR21)) #define MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK GENMASK(23, 0) /* rx ampdu count, 32-bit */ #define MT_MIB_SDR22(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR22)) /* rx ampdu bytes count, 32-bit */ #define MT_MIB_SDR23(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR23)) /* rx ampdu valid subframe count */ #define MT_MIB_SDR24(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR24)) #define MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK GENMASK(23, 0) #define MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916 GENMASK(31, 0) /* rx ampdu valid subframe bytes count, 32bits */ #define MT_MIB_SDR25(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR25)) /* remaining windows protected stats */ #define MT_MIB_SDR27(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR27)) #define MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK GENMASK(15, 0) #define MT_MIB_SDR28(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR28)) #define MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK GENMASK(15, 0) #define MT_MIB_SDR29(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR29)) #define MT_MIB_SDR29_RX_PFDROP_CNT_MASK GENMASK(7, 0) #define MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916 GENMASK(15, 0) #define MT_MIB_SDRVEC(_band) MT_WF_MIB(_band, __OFFS(MIB_SDRVEC)) #define MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK GENMASK(15, 0) #define MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916 GENMASK(31, 16) /* rx blockack count, 32 bits */ #define MT_MIB_SDR31(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR31)) #define MT_MIB_SDR32(_band) MT_WF_MIB(_band, __OFFS(MIB_SDR32)) #define MT_MIB_SDR32_TX_PKT_EBF_CNT GENMASK(15, 0) #define MT_MIB_SDR32_TX_PKT_IBF_CNT GENMASK(31, 16) #define MT_MIB_SDR33(_band) MT_WF_MIB(_band, 0x088) #define MT_MIB_SDR33_TX_PKT_IBF_CNT GENMASK(15, 0) #define MT_MIB_SDRMUBF(_band) MT_WF_MIB(_band, __OFFS(MIB_SDRMUBF)) #define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) /* 36, 37 both DNR */ #define MT_MIB_DR8(_band) MT_WF_MIB(_band, __OFFS(MIB_DR8)) #define MT_MIB_DR9(_band) MT_WF_MIB(_band, __OFFS(MIB_DR9)) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, __OFFS(MIB_DR11)) #define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, __OFFS(MIB_MB_SDR0) + (n)) #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, __OFFS(MIB_MB_SDR1) + (n)) #define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16) #define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x518 + (n)) #define MT_MIB_MB_BFTF(_band, n) MT_WF_MIB(_band, 0x510 + (n)) #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(TX_AGG_CNT) + \ ((n) << 2)) #define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, __OFFS(TX_AGG_CNT2) + \ ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, __OFFS(MIB_ARNG) + \ ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0)) #define MT_MIB_BFCR0(_band) MT_WF_MIB(_band, 0x7b0) #define MT_MIB_BFCR0_RX_FB_HT GENMASK(15, 0) #define MT_MIB_BFCR0_RX_FB_VHT GENMASK(31, 16) #define MT_MIB_BFCR1(_band) MT_WF_MIB(_band, 0x7b4) #define MT_MIB_BFCR1_RX_FB_HE GENMASK(15, 0) #define MT_MIB_BFCR2(_band) MT_WF_MIB(_band, 0x7b8) #define MT_MIB_BFCR2_BFEE_TX_FB_TRIG GENMASK(15, 0) #define MT_MIB_BFCR7(_band) MT_WF_MIB(_band, 0x7cc) #define MT_MIB_BFCR7_BFEE_TX_FB_CPL GENMASK(15, 0) /* WTBLON TOP */ #define MT_WTBLON_TOP_BASE 0x820d4000 #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) #define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(__OFFS(WTBLON_TOP_WDUCR)) #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0) #define MT_WTBL_UPDATE MT_WTBLON_TOP(__OFFS(WTBL_UPDATE)) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) #define MT_WTBL_UPDATE_BUSY BIT(31) /* WTBL */ #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 | \ FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) /* AGG: band 0(0x820e2000), band 1(0x820f2000) */ #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, (__OFFS(AGG_AWSCR0) + \ (_n) * 4)) #define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, (__OFFS(AGG_PCR0) + \ (_n) * 4)) #define MT_AGG_PCR0_MM_PROT BIT(0) #define MT_AGG_PCR0_GF_PROT BIT(1) #define MT_AGG_PCR0_BW20_PROT BIT(2) #define MT_AGG_PCR0_BW40_PROT BIT(4) #define MT_AGG_PCR0_BW80_PROT BIT(6) #define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8) #define MT_AGG_PCR0_VHT_PROT BIT(13) #define MT_AGG_PCR0_PTA_WIN_DIS BIT(15) #define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23) #define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0) #define MT_AGG_ACR0(_band) MT_WF_AGG(_band, __OFFS(AGG_ACR0)) #define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) #define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) #define MT_AGG_ACR4(_band) MT_WF_AGG(_band, __OFFS(AGG_ACR4)) #define MT_AGG_ACR_PPDU_TXS2H BIT(1) #define MT_AGG_MRCR(_band) MT_WF_AGG(_band, __OFFS(AGG_MRCR)) #define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12) #define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6) #define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7) #define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24) +#define MT_AGG_ATCR0(_band) MT_WF_AGG(_band, __OFFS(AGG_ATCR0)) +#define MT_AGG_ATCR_MAC_BFF_TIME_EN BIT(30) + #define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, __OFFS(AGG_ATCR1)) #define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, __OFFS(AGG_ATCR3)) /* ARB: band 0(0x820e3000), band 1(0x820f3000) */ #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, __OFFS(ARB_SCR)) #define MT_ARB_SCR_TX_DISABLE BIT(8) #define MT_ARB_SCR_RX_DISABLE BIT(9) #define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, (__OFFS(ARB_DRNGR0) + \ (_n) * 4)) /* RMAC: band 0(0x820e5000), band 1(0x820f5000) */ #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) #define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) #define MT_WF_RFCR_DROP_FCSFAIL BIT(1) #define MT_WF_RFCR_DROP_VERSION BIT(3) #define MT_WF_RFCR_DROP_PROBEREQ BIT(4) #define MT_WF_RFCR_DROP_MCAST BIT(5) #define MT_WF_RFCR_DROP_BCAST BIT(6) #define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) #define MT_WF_RFCR_DROP_A3_MAC BIT(8) #define MT_WF_RFCR_DROP_A3_BSSID BIT(9) #define MT_WF_RFCR_DROP_A2_BSSID BIT(10) #define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) #define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) #define MT_WF_RFCR_DROP_CTL_RSV BIT(13) #define MT_WF_RFCR_DROP_CTS BIT(14) #define MT_WF_RFCR_DROP_RTS BIT(15) #define MT_WF_RFCR_DROP_DUPLICATE BIT(16) #define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) #define MT_WF_RFCR_DROP_OTHER_UC BIT(18) #define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) #define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) #define MT_WF_RFCR1_DROP_ACK BIT(4) #define MT_WF_RFCR1_DROP_BF_POLL BIT(5) #define MT_WF_RFCR1_DROP_BA BIT(6) #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) #define MT_WF_RMAC_RSVD0(_band) MT_WF_RMAC(_band, 0x02e0) #define MT_WF_RMAC_RSVD0_EIFS_CLR BIT(21) #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_OBSS_BACKOFF GENMASK(15, 0) #define MT_WF_RMAC_MIB_ED_OFFSET GENMASK(20, 16) #define MT_WF_RMAC_MIB_AIRTIME1(_band) MT_WF_RMAC(_band, 0x0384) #define MT_WF_RMAC_MIB_NONQOSD_BACKOFF GENMASK(31, 16) #define MT_WF_RMAC_MIB_AIRTIME3(_band) MT_WF_RMAC(_band, 0x038c) #define MT_WF_RMAC_MIB_QOS01_BACKOFF GENMASK(31, 0) #define MT_WF_RMAC_MIB_AIRTIME4(_band) MT_WF_RMAC(_band, 0x0390) #define MT_WF_RMAC_MIB_QOS23_BACKOFF GENMASK(31, 0) /* WFDMA0 */ #define MT_WFDMA0_BASE __REG(WFDMA0_ADDR) #define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) #define MT_WFDMA0_RST MT_WFDMA0(0x100) #define MT_WFDMA0_RST_LOGIC_RST BIT(4) #define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) #define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) #define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) #define MT_WFDMA0_EXT0_CFG MT_WFDMA0(0x2b0) #define MT_WFDMA0_EXT0_RXWB_KEEP BIT(10) #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) #define MT_WFDMA0_PRI_DLY_INT_CFG1 MT_WFDMA0(0x2f4) #define MT_WFDMA0_PRI_DLY_INT_CFG2 MT_WFDMA0(0x2f8) #define MT_WPDMA_GLO_CFG MT_WFDMA0(0x208) /* WFDMA1 */ #define MT_WFDMA1_BASE 0xd5000 #define MT_WFDMA1(ofs) (MT_WFDMA1_BASE + (ofs)) #define MT_WFDMA1_RST MT_WFDMA1(0x100) #define MT_WFDMA1_RST_LOGIC_RST BIT(4) #define MT_WFDMA1_RST_DMASHDL_ALL_RST BIT(5) #define MT_WFDMA1_BUSY_ENA MT_WFDMA1(0x13c) #define MT_WFDMA1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA1_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA1_BUSY_ENA_RX_FIFO BIT(2) #define MT_WFDMA1_GLO_CFG MT_WFDMA1(0x208) #define MT_WFDMA1_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA1_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WFDMA1_GLO_CFG_OMIT_TX_INFO BIT(28) #define MT_WFDMA1_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA1_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) #define MT_WFDMA1_RST_DTX_PTR MT_WFDMA1(0x20c) #define MT_WFDMA1_PRI_DLY_INT_CFG0 MT_WFDMA1(0x2f0) /* WFDMA CSR */ #define MT_WFDMA_EXT_CSR_BASE __REG(WFDMA_EXT_CSR_ADDR) #define MT_WFDMA_EXT_CSR_PHYS_BASE 0x18027000 #define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) #define MT_WFDMA_EXT_CSR_PHYS(ofs) (MT_WFDMA_EXT_CSR_PHYS_BASE + (ofs)) #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR_PHYS(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) #define MT_WFDMA_HOST_CONFIG_WED BIT(1) #define MT_WFDMA_WED_RING_CONTROL MT_WFDMA_EXT_CSR_PHYS(0x34) #define MT_WFDMA_WED_RING_CONTROL_TX0 GENMASK(4, 0) #define MT_WFDMA_WED_RING_CONTROL_TX1 GENMASK(12, 8) #define MT_WFDMA_WED_RING_CONTROL_RX1 GENMASK(20, 16) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR_PHYS(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) #define MT_INT_WED_SOURCE_CSR MT_WFDMA_EXT_CSR(0x200) #define MT_INT_WED_MASK_CSR MT_WFDMA_EXT_CSR(0x204) #define MT_WED_TX_RING_BASE MT_WFDMA_EXT_CSR(0x300) #define MT_WED_RX_RING_BASE MT_WFDMA_EXT_CSR(0x400) /* WFDMA0 PCIE1 */ #define MT_WFDMA0_PCIE1_BASE __REG(WFDMA0_PCIE1_ADDR) #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO BIT(2) /* WFDMA1 PCIE1 */ #define MT_WFDMA1_PCIE1_BASE 0xd9000 #define MT_WFDMA1_PCIE1(ofs) (MT_WFDMA1_PCIE1_BASE + (ofs)) #define MT_WFDMA1_PCIE1_BUSY_ENA MT_WFDMA1_PCIE1(0x13c) #define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO BIT(2) /* WFDMA COMMON */ #define __RXQ(q) ((q) + __MT_MCUQ_MAX) #define __TXQ(q) (__RXQ(q) + MT_RXQ_BAND2) #define MT_Q_ID(q) (dev->q_id[(q)]) #define MT_Q_BASE(q) ((dev->wfdma_mask >> (q)) & 0x1 ? \ MT_WFDMA1_BASE : MT_WFDMA0_BASE) #define MT_MCUQ_ID(q) MT_Q_ID(q) #define MT_TXQ_ID(q) MT_Q_ID(__TXQ(q)) #define MT_RXQ_ID(q) MT_Q_ID(__RXQ(q)) #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q)* 0x4) #define MT_RXQ_BAND1_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ MT_RXQ_ID(q)* 0x4) #define MT_TXQ_EXT_CTRL(q) (MT_Q_BASE(__TXQ(q)) + 0x600 + \ MT_TXQ_ID(q)* 0x4) #define MT_TXQ_WED_RING_BASE __REG(TXQ_WED_RING_BASE) #define MT_RXQ_WED_RING_BASE __REG(RXQ_WED_RING_BASE) #define MT_RXQ_WED_DATA_RING_BASE __REG(RXQ_WED_DATA_RING_BASE) #define MT_INT_SOURCE_CSR __REG(INT_SOURCE_CSR) #define MT_INT_MASK_CSR __REG(INT_MASK_CSR) #define MT_INT1_SOURCE_CSR __REG(INT1_SOURCE_CSR) #define MT_INT1_MASK_CSR __REG(INT1_MASK_CSR) #define MT_INT_RX_DONE_BAND0 BIT(16) #define MT_INT_RX_DONE_BAND1 BIT(17) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) #define MT_INT_RX_DONE_WA_MAIN BIT(1) #define MT_INT_RX_DONE_WA_EXT BIT(2) #define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_DONE_BAND0_MT7916 BIT(22) #define MT_INT_RX_DONE_BAND1_MT7916 BIT(23) #define MT_INT_RX_DONE_WA_MAIN_MT7916 BIT(2) #define MT_INT_RX_DONE_WA_EXT_MT7916 BIT(3) #define MT_INT_WED_RX_DONE_BAND0_MT7916 BIT(18) #define MT_INT_WED_RX_DONE_BAND1_MT7916 BIT(19) #define MT_INT_WED_RX_DONE_WA_MAIN_MT7916 BIT(1) #define MT_INT_WED_RX_DONE_WA_MT7916 BIT(17) #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) #define MT_INT_RX_DONE_MCU (MT_INT_RX(MT_RXQ_MCU) | \ MT_INT_RX(MT_RXQ_MCU_WA)) #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ MT_INT_RX(MT_RXQ_MAIN_WA)) #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ MT_INT_RX(MT_RXQ_BAND1_WA) | \ MT_INT_RX(MT_RXQ_MAIN_WA)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ MT_INT_BAND0_RX_DONE | \ MT_INT_BAND1_RX_DONE) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) #define MT_INT_TX_DONE_MCU_WA BIT(15) #define MT_INT_TX_DONE_BAND0 BIT(30) #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_MCU_WA_MT7916 BIT(25) #define MT_INT_WED_TX_DONE_BAND0 BIT(4) #define MT_INT_WED_TX_DONE_BAND1 BIT(5) #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ MT_INT_TX_MCU(MT_MCUQ_FWDL)) #define MT_MCU_CMD __REG(INT_MCU_CMD_SOURCE) #define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1) #define MT_MCU_CMD_STOP_DMA BIT(2) #define MT_MCU_CMD_RESET_DONE BIT(3) #define MT_MCU_CMD_RECOVERY_DONE BIT(4) #define MT_MCU_CMD_NORMAL_STATE BIT(5) #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) #define MT_MCU_CMD_WA_WDT BIT(31) #define MT_MCU_CMD_WM_WDT BIT(30) #define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) /* TOP RGU */ #define MT_TOP_RGU_BASE 0x18000000 #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0)) #define MT_TOP_PWR_KEY (0x5746 << 16) #define MT_TOP_PWR_SW_RST BIT(0) #define MT_TOP_PWR_SW_PWR_ON GENMASK(3, 2) #define MT_TOP_PWR_HW_CTRL BIT(4) #define MT_TOP_PWR_PWR_ON BIT(7) #define MT_TOP_RGU_SYSRAM_PDN (MT_TOP_RGU_BASE + 0x050) #define MT_TOP_RGU_SYSRAM_SLP (MT_TOP_RGU_BASE + 0x054) #define MT_TOP_WFSYS_PWR (MT_TOP_RGU_BASE + 0x010) #define MT_TOP_PWR_EN_MASK BIT(7) #define MT_TOP_PWR_ACK_MASK BIT(6) #define MT_TOP_PWR_KEY_MASK GENMASK(31, 16) #define MT7986_TOP_WM_RESET (MT_TOP_RGU_BASE + 0x120) #define MT7986_TOP_WM_RESET_MASK BIT(0) /* l1/l2 remap */ #define MT_HIF_REMAP_L1 0xf11ac #define MT_HIF_REMAP_L1_MT7916 0xfe260 #define MT_HIF_REMAP_L1_MASK GENMASK(15, 0) #define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) #define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) #define MT_HIF_REMAP_BASE_L1 0xe0000 #define MT_HIF_REMAP_L2 0xf11b0 #define MT_HIF_REMAP_L2_MASK GENMASK(19, 0) #define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0) #define MT_HIF_REMAP_L2_BASE GENMASK(31, 12) #define MT_HIF_REMAP_L2_MT7916 0x1b8 #define MT_HIF_REMAP_L2_MASK_MT7916 GENMASK(31, 16) #define MT_HIF_REMAP_L2_OFFSET_MT7916 GENMASK(15, 0) #define MT_HIF_REMAP_L2_BASE_MT7916 GENMASK(31, 16) #define MT_HIF_REMAP_BASE_L2_MT7916 0x40000 #define MT_INFRA_BASE 0x18000000 #define MT_WFSYS0_PHY_START 0x18400000 #define MT_WFSYS1_PHY_START 0x18800000 #define MT_WFSYS1_PHY_END 0x18bfffff #define MT_CBTOP1_PHY_START 0x70000000 #define MT_CBTOP1_PHY_END __REG(CBTOP1_PHY_END) #define MT_CBTOP2_PHY_START 0xf0000000 #define MT_INFRA_MCU_START 0x7c000000 #define MT_INFRA_MCU_END __REG(INFRA_MCU_ADDR_END) #define MT_CONN_INFRA_OFFSET(p) ((p) - MT_INFRA_BASE) /* CONN INFRA CFG */ #define MT_CONN_INFRA_BASE 0x18001000 #define MT_CONN_INFRA(ofs) (MT_CONN_INFRA_BASE + (ofs)) #define MT_CONN_INFRA_EFUSE MT_CONN_INFRA(0x020) #define MT_CONN_INFRA_ADIE_RESET MT_CONN_INFRA(0x030) #define MT_CONN_INFRA_ADIE1_RESET_MASK BIT(0) #define MT_CONN_INFRA_ADIE2_RESET_MASK BIT(2) #define MT_CONN_INFRA_OSC_RC_EN MT_CONN_INFRA(0x380) #define MT_CONN_INFRA_OSC_CTRL MT_CONN_INFRA(0x300) #define MT_CONN_INFRA_OSC_RC_EN_MASK BIT(7) #define MT_CONN_INFRA_OSC_STB_TIME_MASK GENMASK(23, 0) #define MT_CONN_INFRA_HW_CTRL MT_CONN_INFRA(0x200) #define MT_CONN_INFRA_HW_CTRL_MASK BIT(0) #define MT_CONN_INFRA_WF_SLP_PROT MT_CONN_INFRA(0x540) #define MT_CONN_INFRA_WF_SLP_PROT_MASK BIT(0) #define MT_CONN_INFRA_WF_SLP_PROT_RDY MT_CONN_INFRA(0x544) #define MT_CONN_INFRA_CONN_WF_MASK (BIT(29) | BIT(31)) #define MT_CONN_INFRA_CONN (BIT(25) | BIT(29) | BIT(31)) #define MT_CONN_INFRA_EMI_REQ MT_CONN_INFRA(0x414) #define MT_CONN_INFRA_EMI_REQ_MASK BIT(0) #define MT_CONN_INFRA_INFRA_REQ_MASK BIT(5) /* AFE */ #define MT_AFE_CTRL_BASE(_band) (0x18003000 + ((_band) << 19)) #define MT_AFE_CTRL(_band, ofs) (MT_AFE_CTRL_BASE(_band) + (ofs)) #define MT_AFE_DIG_EN_01(_band) MT_AFE_CTRL(_band, 0x00) #define MT_AFE_DIG_EN_02(_band) MT_AFE_CTRL(_band, 0x04) #define MT_AFE_DIG_EN_03(_band) MT_AFE_CTRL(_band, 0x08) #define MT_AFE_DIG_TOP_01(_band) MT_AFE_CTRL(_band, 0x0c) #define MT_AFE_PLL_STB_TIME(_band) MT_AFE_CTRL(_band, 0xf4) #define MT_AFE_PLL_STB_TIME_MASK (GENMASK(30, 16) | GENMASK(14, 0)) #define MT_AFE_PLL_STB_TIME_VAL (FIELD_PREP(GENMASK(30, 16), 0x4bc) | \ FIELD_PREP(GENMASK(14, 0), 0x7e4)) #define MT_AFE_BPLL_CFG_MASK GENMASK(7, 6) #define MT_AFE_WPLL_CFG_MASK GENMASK(1, 0) #define MT_AFE_MCU_WPLL_CFG_MASK GENMASK(3, 2) #define MT_AFE_MCU_BPLL_CFG_MASK GENMASK(17, 16) #define MT_AFE_PLL_CFG_MASK (MT_AFE_BPLL_CFG_MASK | \ MT_AFE_WPLL_CFG_MASK | \ MT_AFE_MCU_WPLL_CFG_MASK | \ MT_AFE_MCU_BPLL_CFG_MASK) #define MT_AFE_PLL_CFG_VAL (FIELD_PREP(MT_AFE_BPLL_CFG_MASK, 0x1) | \ FIELD_PREP(MT_AFE_WPLL_CFG_MASK, 0x2) | \ FIELD_PREP(MT_AFE_MCU_WPLL_CFG_MASK, 0x1) | \ FIELD_PREP(MT_AFE_MCU_BPLL_CFG_MASK, 0x2)) #define MT_AFE_DIG_TOP_01_MASK GENMASK(18, 15) #define MT_AFE_DIG_TOP_01_VAL FIELD_PREP(MT_AFE_DIG_TOP_01_MASK, 0x9) #define MT_AFE_RG_WBG_EN_RCK_MASK BIT(0) #define MT_AFE_RG_WBG_EN_BPLL_UP_MASK BIT(21) #define MT_AFE_RG_WBG_EN_WPLL_UP_MASK BIT(20) #define MT_AFE_RG_WBG_EN_PLL_UP_MASK (MT_AFE_RG_WBG_EN_BPLL_UP_MASK | \ MT_AFE_RG_WBG_EN_WPLL_UP_MASK) #define MT_AFE_RG_WBG_EN_TXCAL_WF4 BIT(29) #define MT_AFE_RG_WBG_EN_TXCAL_BT BIT(21) #define MT_AFE_RG_WBG_EN_TXCAL_WF3 BIT(20) #define MT_AFE_RG_WBG_EN_TXCAL_WF2 BIT(19) #define MT_AFE_RG_WBG_EN_TXCAL_WF1 BIT(18) #define MT_AFE_RG_WBG_EN_TXCAL_WF0 BIT(17) #define MT_ADIE_SLP_CTRL_BASE(_band) (0x18005000 + ((_band) << 19)) #define MT_ADIE_SLP_CTRL(_band, ofs) (MT_ADIE_SLP_CTRL_BASE(_band) + (ofs)) #define MT_ADIE_SLP_CTRL_CK0(_band) MT_ADIE_SLP_CTRL(_band, 0x120) /* ADIE */ #define MT_ADIE_CHIP_ID 0x02c #define MT_ADIE_VERSION_MASK GENMASK(15, 0) #define MT_ADIE_CHIP_ID_MASK GENMASK(31, 16) #define MT_ADIE_IDX0 GENMASK(15, 0) #define MT_ADIE_IDX1 GENMASK(31, 16) #define MT_ADIE_RG_TOP_THADC_BG 0x034 #define MT_ADIE_VRPI_SEL_CR_MASK GENMASK(15, 12) #define MT_ADIE_VRPI_SEL_EFUSE_MASK GENMASK(6, 3) #define MT_ADIE_RG_TOP_THADC 0x038 #define MT_ADIE_PGA_GAIN_MASK GENMASK(25, 23) #define MT_ADIE_PGA_GAIN_EFUSE_MASK GENMASK(2, 0) #define MT_ADIE_LDO_CTRL_MASK GENMASK(27, 26) #define MT_ADIE_LDO_CTRL_EFUSE_MASK GENMASK(6, 5) #define MT_AFE_RG_ENCAL_WBTAC_IF_SW 0x070 #define MT_ADIE_EFUSE_RDATA0 0x130 #define MT_ADIE_EFUSE2_CTRL 0x148 #define MT_ADIE_EFUSE_CTRL_MASK BIT(1) #define MT_ADIE_EFUSE_CFG 0x144 #define MT_ADIE_EFUSE_MODE_MASK GENMASK(7, 6) #define MT_ADIE_EFUSE_ADDR_MASK GENMASK(25, 16) #define MT_ADIE_EFUSE_VALID_MASK BIT(29) #define MT_ADIE_EFUSE_KICK_MASK BIT(30) #define MT_ADIE_THADC_ANALOG 0x3a6 #define MT_ADIE_THADC_SLOP 0x3a7 #define MT_ADIE_ANA_EN_MASK BIT(7) #define MT_ADIE_7975_XTAL_CAL 0x3a1 #define MT_ADIE_TRIM_MASK GENMASK(6, 0) #define MT_ADIE_EFUSE_TRIM_MASK GENMASK(5, 0) #define MT_ADIE_XO_TRIM_EN_MASK BIT(7) #define MT_ADIE_XTAL_DECREASE_MASK BIT(6) #define MT_ADIE_7975_XO_TRIM2 0x3a2 #define MT_ADIE_7975_XO_TRIM3 0x3a3 #define MT_ADIE_7975_XO_TRIM4 0x3a4 #define MT_ADIE_7975_XTAL_EN 0x3a5 #define MT_ADIE_XO_TRIM_FLOW 0x3ac #define MT_ADIE_XTAL_AXM_80M_OSC 0x390 #define MT_ADIE_XTAL_AXM_40M_OSC 0x391 #define MT_ADIE_XTAL_TRIM1_80M_OSC 0x398 #define MT_ADIE_XTAL_TRIM1_40M_OSC 0x399 #define MT_ADIE_WRI_CK_SEL 0x4ac #define MT_ADIE_RG_STRAP_PIN_IN 0x4fc #define MT_ADIE_XTAL_C1 0x654 #define MT_ADIE_XTAL_C2 0x658 #define MT_ADIE_RG_XO_01 0x65c #define MT_ADIE_RG_XO_03 0x664 #define MT_ADIE_CLK_EN 0xa00 #define MT_ADIE_7975_XTAL 0xa18 #define MT_ADIE_7975_XTAL_EN_MASK BIT(29) #define MT_ADIE_7975_COCLK 0xa1c #define MT_ADIE_7975_XO_2 0xa84 #define MT_ADIE_7975_XO_2_FIX_EN BIT(31) #define MT_ADIE_7975_XO_CTRL2 0xa94 #define MT_ADIE_7975_XO_CTRL2_C1_MASK GENMASK(26, 20) #define MT_ADIE_7975_XO_CTRL2_C2_MASK GENMASK(18, 12) #define MT_ADIE_7975_XO_CTRL2_MASK (MT_ADIE_7975_XO_CTRL2_C1_MASK | \ MT_ADIE_7975_XO_CTRL2_C2_MASK) #define MT_ADIE_7975_XO_CTRL6 0xaa4 #define MT_ADIE_7975_XO_CTRL6_MASK BIT(16) /* TOP SPI */ #define MT_TOP_SPI_ADIE_BASE(_band) (0x18004000 + ((_band) << 19)) #define MT_TOP_SPI_ADIE(_band, ofs) (MT_TOP_SPI_ADIE_BASE(_band) + (ofs)) #define MT_TOP_SPI_BUSY_CR(_band) MT_TOP_SPI_ADIE(_band, 0) #define MT_TOP_SPI_POLLING_BIT BIT(5) #define MT_TOP_SPI_ADDR_CR(_band) MT_TOP_SPI_ADIE(_band, 0x50) #define MT_TOP_SPI_READ_ADDR_FORMAT (BIT(12) | BIT(13) | BIT(15)) #define MT_TOP_SPI_WRITE_ADDR_FORMAT (BIT(13) | BIT(15)) #define MT_TOP_SPI_WRITE_DATA_CR(_band) MT_TOP_SPI_ADIE(_band, 0x54) #define MT_TOP_SPI_READ_DATA_CR(_band) MT_TOP_SPI_ADIE(_band, 0x58) /* CONN INFRA CKGEN */ #define MT_INFRA_CKGEN_BASE 0x18009000 #define MT_INFRA_CKGEN(ofs) (MT_INFRA_CKGEN_BASE + (ofs)) #define MT_INFRA_CKGEN_BUS MT_INFRA_CKGEN(0xa00) #define MT_INFRA_CKGEN_BUS_CLK_SEL_MASK BIT(23) #define MT_INFRA_CKGEN_BUS_RDY_SEL_MASK BIT(29) #define MT_INFRA_CKGEN_BUS_WPLL_DIV_1 MT_INFRA_CKGEN(0x008) #define MT_INFRA_CKGEN_BUS_WPLL_DIV_2 MT_INFRA_CKGEN(0x00c) #define MT_INFRA_CKGEN_RFSPI_WPLL_DIV MT_INFRA_CKGEN(0x040) #define MT_INFRA_CKGEN_DIV_SEL_MASK GENMASK(7, 2) #define MT_INFRA_CKGEN_DIV_EN_MASK BIT(0) /* CONN INFRA BUS */ #define MT_INFRA_BUS_BASE 0x1800e000 #define MT_INFRA_BUS(ofs) (MT_INFRA_BUS_BASE + (ofs)) #define MT_INFRA_BUS_OFF_TIMEOUT MT_INFRA_BUS(0x300) #define MT_INFRA_BUS_TIMEOUT_LIMIT_MASK GENMASK(14, 7) #define MT_INFRA_BUS_TIMEOUT_EN_MASK GENMASK(3, 0) #define MT_INFRA_BUS_ON_TIMEOUT MT_INFRA_BUS(0x31c) #define MT_INFRA_BUS_EMI_START MT_INFRA_BUS(0x360) #define MT_INFRA_BUS_EMI_END MT_INFRA_BUS(0x364) /* CONN_INFRA_SKU */ #define MT_CONNINFRA_SKU_DEC_ADDR 0x18050000 #define MT_CONNINFRA_SKU_MASK GENMASK(15, 0) #define MT_ADIE_TYPE_MASK BIT(1) /* FW MODE SYNC */ #define MT_FW_ASSERT_STAT __REG(FW_ASSERT_STAT_ADDR) #define MT_FW_EXCEPT_TYPE __REG(FW_EXCEPT_TYPE_ADDR) #define MT_FW_EXCEPT_COUNT __REG(FW_EXCEPT_COUNT_ADDR) #define MT_FW_CIRQ_COUNT __REG(FW_CIRQ_COUNT_ADDR) #define MT_FW_CIRQ_IDX __REG(FW_CIRQ_IDX_ADDR) #define MT_FW_CIRQ_LISR __REG(FW_CIRQ_LISR_ADDR) #define MT_FW_TASK_ID __REG(FW_TASK_ID_ADDR) #define MT_FW_TASK_IDX __REG(FW_TASK_IDX_ADDR) #define MT_FW_TASK_QID1 __REG(FW_TASK_QID1_ADDR) #define MT_FW_TASK_QID2 __REG(FW_TASK_QID2_ADDR) #define MT_FW_TASK_START __REG(FW_TASK_START_ADDR) #define MT_FW_TASK_END __REG(FW_TASK_END_ADDR) #define MT_FW_TASK_SIZE __REG(FW_TASK_SIZE_ADDR) #define MT_FW_LAST_MSG_ID __REG(FW_LAST_MSG_ID_ADDR) #define MT_FW_EINT_INFO __REG(FW_EINT_INFO_ADDR) #define MT_FW_SCHED_INFO __REG(FW_SCHED_INFO_ADDR) #define MT_SWDEF_BASE __REG(SWDEF_BASE_ADDR) #define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs)) #define MT_SWDEF_MODE MT_SWDEF(0x3c) #define MT_SWDEF_NORMAL_MODE 0 #define MT_SWDEF_ICAP_MODE 1 #define MT_SWDEF_SPECTRUM_MODE 2 #define MT_SWDEF_SER_STATS MT_SWDEF(0x040) #define MT_SWDEF_PLE_STATS MT_SWDEF(0x044) #define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048) #define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04C) #define MT_SWDEF_PSE_STATS MT_SWDEF(0x050) #define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054) #define MT_SWDEF_LAMC_WISR6_BN0_STATS MT_SWDEF(0x058) #define MT_SWDEF_LAMC_WISR6_BN1_STATS MT_SWDEF(0x05C) #define MT_SWDEF_LAMC_WISR7_BN0_STATS MT_SWDEF(0x060) #define MT_SWDEF_LAMC_WISR7_BN1_STATS MT_SWDEF(0x064) #define MT_DIC_CMD_REG_BASE 0x41f000 #define MT_DIC_CMD_REG(ofs) (MT_DIC_CMD_REG_BASE + (ofs)) #define MT_DIC_CMD_REG_CMD MT_DIC_CMD_REG(0x10) #define MT_CPU_UTIL_BASE 0x41f030 #define MT_CPU_UTIL(ofs) (MT_CPU_UTIL_BASE + (ofs)) #define MT_CPU_UTIL_BUSY_PCT MT_CPU_UTIL(0x00) #define MT_CPU_UTIL_PEAK_BUSY_PCT MT_CPU_UTIL(0x04) #define MT_CPU_UTIL_IDLE_CNT MT_CPU_UTIL(0x08) #define MT_CPU_UTIL_PEAK_IDLE_CNT MT_CPU_UTIL(0x0c) #define MT_CPU_UTIL_CTRL MT_CPU_UTIL(0x1c) /* LED */ #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_BAND BIT(4) #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_STATUS_0(_n) MT_LED_PHYS(0x20 + ((_n) * 8)) #define MT_LED_STATUS_1(_n) MT_LED_PHYS(0x24 + ((_n) * 8)) #define MT_LED_STATUS_OFF GENMASK(31, 24) #define MT_LED_STATUS_ON GENMASK(23, 16) #define MT_LED_STATUS_DURATION GENMASK(15, 0) #define MT_LED_EN(_n) MT_LED_PHYS(0x40 + ((_n) * 4)) #define MT_LED_GPIO_MUX0 0x70005050 /* GPIO 1 and GPIO 2 */ #define MT_LED_GPIO_MUX1 0x70005054 /* GPIO 14 and 15 */ #define MT_LED_GPIO_MUX2 0x70005058 /* GPIO 18 */ #define MT_LED_GPIO_MUX3 0x7000505c /* GPIO 26 */ /* MT TOP */ #define MT_TOP_BASE 0x18060000 #define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) #define MT_TOP_LPCR_HOST_BAND(_band) MT_TOP(0x10 + ((_band) * 0x10)) #define MT_TOP_LPCR_HOST_FW_OWN BIT(0) #define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) #define MT_TOP_LPCR_HOST_FW_OWN_STAT BIT(2) #define MT_TOP_LPCR_HOST_BAND_IRQ_STAT(_band) MT_TOP(0x14 + ((_band) * 0x10)) #define MT_TOP_LPCR_HOST_BAND_STAT BIT(0) #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) #define MT_TOP_WFSYS_WAKEUP MT_TOP(0x1a4) #define MT_TOP_WFSYS_WAKEUP_MASK BIT(0) #define MT_TOP_MCU_EMI_BASE MT_TOP(0x1c4) #define MT_TOP_MCU_EMI_BASE_MASK GENMASK(19, 0) #define MT_TOP_WF_AP_PERI_BASE MT_TOP(0x1c8) #define MT_TOP_WF_AP_PERI_BASE_MASK GENMASK(19, 0) #define MT_TOP_EFUSE_BASE MT_TOP(0x1cc) #define MT_TOP_EFUSE_BASE_MASK GENMASK(19, 0) #define MT_TOP_CONN_INFRA_WAKEUP MT_TOP(0x1a0) #define MT_TOP_CONN_INFRA_WAKEUP_MASK BIT(0) #define MT_TOP_WFSYS_RESET_STATUS MT_TOP(0x2cc) #define MT_TOP_WFSYS_RESET_STATUS_MASK BIT(30) /* SEMA */ #define MT_SEMA_BASE 0x18070000 #define MT_SEMA(ofs) (MT_SEMA_BASE + (ofs)) #define MT_SEMA_RFSPI_STATUS (MT_SEMA(0x2000) + (11 * 4)) #define MT_SEMA_RFSPI_RELEASE (MT_SEMA(0x2200) + (11 * 4)) #define MT_SEMA_RFSPI_STATUS_MASK BIT(1) /* MCU BUS */ #define MT_MCU_BUS_BASE 0x18400000 #define MT_MCU_BUS(ofs) (MT_MCU_BUS_BASE + (ofs)) #define MT_MCU_BUS_TIMEOUT MT_MCU_BUS(0xf0440) #define MT_MCU_BUS_TIMEOUT_SET_MASK GENMASK(7, 0) #define MT_MCU_BUS_TIMEOUT_CG_EN_MASK BIT(28) #define MT_MCU_BUS_TIMEOUT_EN_MASK BIT(31) #define MT_MCU_BUS_REMAP MT_MCU_BUS(0x120) /* TOP CFG */ #define MT_TOP_CFG_BASE 0x184b0000 #define MT_TOP_CFG(ofs) (MT_TOP_CFG_BASE + (ofs)) #define MT_TOP_CFG_IP_VERSION_ADDR MT_TOP_CFG(0x010) /* TOP CFG ON */ #define MT_TOP_CFG_ON_BASE 0x184c1000 #define MT_TOP_CFG_ON(ofs) (MT_TOP_CFG_ON_BASE + (ofs)) #define MT_TOP_CFG_ON_ROM_IDX MT_TOP_CFG_ON(0x604) /* SLP CTRL */ #define MT_SLP_BASE 0x184c3000 #define MT_SLP(ofs) (MT_SLP_BASE + (ofs)) #define MT_SLP_STATUS MT_SLP(0x00c) #define MT_SLP_WFDMA2CONN_MASK (BIT(21) | BIT(23)) #define MT_SLP_CTRL_EN_MASK BIT(0) #define MT_SLP_CTRL_BSY_MASK BIT(1) /* MCU BUS DBG */ #define MT_MCU_BUS_DBG_BASE 0x18500000 #define MT_MCU_BUS_DBG(ofs) (MT_MCU_BUS_DBG_BASE + (ofs)) #define MT_MCU_BUS_DBG_TIMEOUT MT_MCU_BUS_DBG(0x0) #define MT_MCU_BUS_DBG_TIMEOUT_SET_MASK GENMASK(31, 16) #define MT_MCU_BUS_DBG_TIMEOUT_CK_EN_MASK BIT(3) #define MT_MCU_BUS_DBG_TIMEOUT_EN_MASK BIT(2) #define MT_HW_BOUND 0x70010020 #define MT_HW_REV 0x70010204 #define MT_WF_SUBSYS_RST 0x70002600 /* PCIE MAC */ #define MT_PCIE_MAC_BASE 0x74030000 #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) #define MT_PCIE1_MAC_INT_ENABLE 0x74020188 #define MT_PCIE1_MAC_INT_ENABLE_MT7916 0x74090188 #define MT_WM_MCU_PC 0x7c060204 #define MT_WA_MCU_PC 0x7c06020c /* PP TOP */ #define MT_WF_PP_TOP_BASE 0x820cc000 #define MT_WF_PP_TOP(ofs) (MT_WF_PP_TOP_BASE + (ofs)) #define MT_WF_PP_TOP_RXQ_WFDMA_CF_5 MT_WF_PP_TOP(0x0e8) #define MT_WF_PP_TOP_RXQ_QID6_WFDMA_HIF_SEL_MASK BIT(6) #define MT_WF_IRPI_BASE 0x83000000 #define MT_WF_IRPI(ofs) (MT_WF_IRPI_BASE + (ofs)) #define MT_WF_IRPI_NSS(phy, nss) MT_WF_IRPI(0x6000 + ((phy) << 20) + ((nss) << 16)) #define MT_WF_IRPI_NSS_MT7916(phy, nss) MT_WF_IRPI(0x1000 + ((phy) << 20) + ((nss) << 16)) /* PHY */ #define MT_WF_PHY_BASE 0x83080000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) #define MT_WF_PHY_RX_CTRL1(_phy) MT_WF_PHY(0x2004 + ((_phy) << 16)) #define MT_WF_PHY_RX_CTRL1_MT7916(_phy) MT_WF_PHY(0x2004 + ((_phy) << 20)) #define MT_WF_PHY_RX_CTRL1_IPI_EN GENMASK(2, 0) #define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9) #define MT_WF_PHY_RXTD12(_phy) MT_WF_PHY(0x8230 + ((_phy) << 16)) #define MT_WF_PHY_RXTD12_MT7916(_phy) MT_WF_PHY(0x8230 + ((_phy) << 20)) #define MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY BIT(18) #define MT_WF_PHY_RXTD12_IRPI_SW_CLR BIT(29) #define MT_WF_PHY_TPC_CTRL_STAT(_phy) MT_WF_PHY(0xe7a0 + ((_phy) << 16)) #define MT_WF_PHY_TPC_CTRL_STAT_MT7916(_phy) MT_WF_PHY(0xe7a0 + ((_phy) << 20)) #define MT_WF_PHY_TPC_POWER GENMASK(15, 8) #define MT_MCU_WM_CIRQ_BASE 0x89010000 #define MT_MCU_WM_CIRQ(ofs) (MT_MCU_WM_CIRQ_BASE + (ofs)) #define MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x80) #define MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR MT_MCU_WM_CIRQ(0xc0) #define MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x108) #define MT_MCU_WM_CIRQ_EINT_SOFT_ADDR MT_MCU_WM_CIRQ(0x118) #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/soc.c b/sys/contrib/dev/mediatek/mt76/mt7915/soc.c index 37348b208736..c823a7554a3a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/soc.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/soc.c @@ -1,1322 +1,1317 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2022 MediaTek Inc. */ #include #include #include #include #include #include -#include #include #include #include #include #include "mt7915.h" #define MT7981_CON_INFRA_VERSION 0x02090000 #define MT7986_CON_INFRA_VERSION 0x02070000 /* INFRACFG */ #define MT_INFRACFG_CONN2AP_SLPPROT 0x0d0 #define MT_INFRACFG_AP2CONN_SLPPROT 0x0d4 #define MT_INFRACFG_RX_EN_MASK BIT(16) #define MT_INFRACFG_TX_RDY_MASK BIT(4) #define MT_INFRACFG_TX_EN_MASK BIT(0) /* TOP POS */ #define MT_TOP_POS_FAST_CTRL 0x114 #define MT_TOP_POS_FAST_EN_MASK BIT(3) #define MT_TOP_POS_SKU 0x21c #define MT_TOP_POS_SKU_MASK GENMASK(31, 28) #define MT_TOP_POS_SKU_ADIE_DBDC_MASK BIT(2) enum { ADIE_SB, ADIE_DBDC }; static int mt76_wmac_spi_read(struct mt7915_dev *dev, u8 adie, u32 addr, u32 *val) { int ret; u32 cur; ret = read_poll_timeout(mt76_rr, cur, !(cur & MT_TOP_SPI_POLLING_BIT), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_SPI_BUSY_CR(adie)); if (ret) return ret; mt76_wr(dev, MT_TOP_SPI_ADDR_CR(adie), MT_TOP_SPI_READ_ADDR_FORMAT | addr); mt76_wr(dev, MT_TOP_SPI_WRITE_DATA_CR(adie), 0); ret = read_poll_timeout(mt76_rr, cur, !(cur & MT_TOP_SPI_POLLING_BIT), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_SPI_BUSY_CR(adie)); if (ret) return ret; *val = mt76_rr(dev, MT_TOP_SPI_READ_DATA_CR(adie)); return 0; } static int mt76_wmac_spi_write(struct mt7915_dev *dev, u8 adie, u32 addr, u32 val) { int ret; u32 cur; ret = read_poll_timeout(mt76_rr, cur, !(cur & MT_TOP_SPI_POLLING_BIT), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_SPI_BUSY_CR(adie)); if (ret) return ret; mt76_wr(dev, MT_TOP_SPI_ADDR_CR(adie), MT_TOP_SPI_WRITE_ADDR_FORMAT | addr); mt76_wr(dev, MT_TOP_SPI_WRITE_DATA_CR(adie), val); return read_poll_timeout(mt76_rr, cur, !(cur & MT_TOP_SPI_POLLING_BIT), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_SPI_BUSY_CR(adie)); } static int mt76_wmac_spi_rmw(struct mt7915_dev *dev, u8 adie, u32 addr, u32 mask, u32 val) { u32 cur, ret; ret = mt76_wmac_spi_read(dev, adie, addr, &cur); if (ret) return ret; cur &= ~mask; cur |= val; return mt76_wmac_spi_write(dev, adie, addr, cur); } static int mt7986_wmac_adie_efuse_read(struct mt7915_dev *dev, u8 adie, u32 addr, u32 *data) { int ret, temp; u32 val, mask; ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_EFUSE_CFG, MT_ADIE_EFUSE_CTRL_MASK); if (ret) return ret; ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_EFUSE2_CTRL, BIT(30), 0x0); if (ret) return ret; mask = (MT_ADIE_EFUSE_MODE_MASK | MT_ADIE_EFUSE_ADDR_MASK | MT_ADIE_EFUSE_KICK_MASK); val = FIELD_PREP(MT_ADIE_EFUSE_MODE_MASK, 0) | FIELD_PREP(MT_ADIE_EFUSE_ADDR_MASK, addr) | FIELD_PREP(MT_ADIE_EFUSE_KICK_MASK, 1); ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_EFUSE2_CTRL, mask, val); if (ret) return ret; ret = read_poll_timeout(mt76_wmac_spi_read, temp, !temp && !FIELD_GET(MT_ADIE_EFUSE_KICK_MASK, val), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, adie, MT_ADIE_EFUSE2_CTRL, &val); if (ret) return ret; ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_EFUSE2_CTRL, &val); if (ret) return ret; if (FIELD_GET(MT_ADIE_EFUSE_VALID_MASK, val) == 1) ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_EFUSE_RDATA0, data); return ret; } static inline void mt76_wmac_spi_lock(struct mt7915_dev *dev) { u32 cur; read_poll_timeout(mt76_rr, cur, FIELD_GET(MT_SEMA_RFSPI_STATUS_MASK, cur), 1000, 1000 * MSEC_PER_SEC, false, dev, MT_SEMA_RFSPI_STATUS); } static inline void mt76_wmac_spi_unlock(struct mt7915_dev *dev) { mt76_wr(dev, MT_SEMA_RFSPI_RELEASE, 1); } static u32 mt76_wmac_rmw(void __iomem *base, u32 offset, u32 mask, u32 val) { val |= readl(base + offset) & ~mask; writel(val, base + offset); return val; } static u8 mt798x_wmac_check_adie_type(struct mt7915_dev *dev) { u32 val; /* Only DBDC A-die is used with MT7981 */ if (is_mt7981(&dev->mt76)) return ADIE_DBDC; val = readl(dev->sku + MT_TOP_POS_SKU); return FIELD_GET(MT_TOP_POS_SKU_ADIE_DBDC_MASK, val); } static int mt7986_wmac_consys_reset(struct mt7915_dev *dev, bool enable) { if (!enable) return reset_control_assert(dev->rstc); mt76_wmac_rmw(dev->sku, MT_TOP_POS_FAST_CTRL, MT_TOP_POS_FAST_EN_MASK, FIELD_PREP(MT_TOP_POS_FAST_EN_MASK, 0x1)); return reset_control_deassert(dev->rstc); } static int mt7986_wmac_gpio_setup(struct mt7915_dev *dev) { struct pinctrl_state *state; struct pinctrl *pinctrl; int ret; u8 type; type = mt798x_wmac_check_adie_type(dev); pinctrl = devm_pinctrl_get(dev->mt76.dev); if (IS_ERR(pinctrl)) return PTR_ERR(pinctrl); switch (type) { case ADIE_SB: state = pinctrl_lookup_state(pinctrl, "default"); if (IS_ERR_OR_NULL(state)) return -EINVAL; break; case ADIE_DBDC: state = pinctrl_lookup_state(pinctrl, "dbdc"); if (IS_ERR_OR_NULL(state)) return -EINVAL; break; default: return -EINVAL; } ret = pinctrl_select_state(pinctrl, state); if (ret) return ret; usleep_range(500, 1000); return 0; } static int mt7986_wmac_consys_lockup(struct mt7915_dev *dev, bool enable) { int ret; u32 cur; mt76_wmac_rmw(dev->dcm, MT_INFRACFG_AP2CONN_SLPPROT, MT_INFRACFG_RX_EN_MASK, FIELD_PREP(MT_INFRACFG_RX_EN_MASK, enable)); ret = read_poll_timeout(readl, cur, !(cur & MT_INFRACFG_RX_EN_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev->dcm + MT_INFRACFG_AP2CONN_SLPPROT); if (ret) return ret; mt76_wmac_rmw(dev->dcm, MT_INFRACFG_AP2CONN_SLPPROT, MT_INFRACFG_TX_EN_MASK, FIELD_PREP(MT_INFRACFG_TX_EN_MASK, enable)); ret = read_poll_timeout(readl, cur, !(cur & MT_INFRACFG_TX_RDY_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev->dcm + MT_INFRACFG_AP2CONN_SLPPROT); if (ret) return ret; mt76_wmac_rmw(dev->dcm, MT_INFRACFG_CONN2AP_SLPPROT, MT_INFRACFG_RX_EN_MASK, FIELD_PREP(MT_INFRACFG_RX_EN_MASK, enable)); mt76_wmac_rmw(dev->dcm, MT_INFRACFG_CONN2AP_SLPPROT, MT_INFRACFG_TX_EN_MASK, FIELD_PREP(MT_INFRACFG_TX_EN_MASK, enable)); return 0; } static int mt798x_wmac_coninfra_check(struct mt7915_dev *dev) { u32 cur; u32 con_infra_version; if (is_mt7981(&dev->mt76)) { con_infra_version = MT7981_CON_INFRA_VERSION; } else if (is_mt7986(&dev->mt76)) { con_infra_version = MT7986_CON_INFRA_VERSION; } else { WARN_ON(1); return -EINVAL; } return read_poll_timeout(mt76_rr, cur, (cur == con_infra_version), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_CONN_INFRA_BASE); } static int mt798x_wmac_coninfra_setup(struct mt7915_dev *dev) { struct device *pdev = dev->mt76.dev; struct reserved_mem *rmem; struct device_node *np; u32 val; np = of_parse_phandle(pdev->of_node, "memory-region", 0); if (!np) return -EINVAL; rmem = of_reserved_mem_lookup(np); of_node_put(np); if (!rmem) return -EINVAL; val = (rmem->base >> 16) & MT_TOP_MCU_EMI_BASE_MASK; if (is_mt7986(&dev->mt76)) { /* Set conninfra subsys PLL check */ mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS, MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS, MT_INFRA_CKGEN_BUS_RDY_SEL_MASK, 0x1); } mt76_rmw_field(dev, MT_TOP_MCU_EMI_BASE, MT_TOP_MCU_EMI_BASE_MASK, val); if (is_mt7981(&dev->mt76)) { mt76_rmw_field(dev, MT_TOP_WF_AP_PERI_BASE, MT_TOP_WF_AP_PERI_BASE_MASK, 0x300d0000 >> 16); mt76_rmw_field(dev, MT_TOP_EFUSE_BASE, MT_TOP_EFUSE_BASE_MASK, 0x11f20000 >> 16); } mt76_wr(dev, MT_INFRA_BUS_EMI_START, rmem->base); mt76_wr(dev, MT_INFRA_BUS_EMI_END, rmem->size); mt76_rr(dev, MT_CONN_INFRA_EFUSE); /* Set conninfra sysram */ mt76_wr(dev, MT_TOP_RGU_SYSRAM_PDN, 0); mt76_wr(dev, MT_TOP_RGU_SYSRAM_SLP, 1); return 0; } static int mt798x_wmac_sku_setup(struct mt7915_dev *dev, u32 *adie_type) { int ret; u32 adie_main = 0, adie_ext = 0; mt76_rmw_field(dev, MT_CONN_INFRA_ADIE_RESET, MT_CONN_INFRA_ADIE1_RESET_MASK, 0x1); if (is_mt7986(&dev->mt76)) { mt76_rmw_field(dev, MT_CONN_INFRA_ADIE_RESET, MT_CONN_INFRA_ADIE2_RESET_MASK, 0x1); } mt76_wmac_spi_lock(dev); ret = mt76_wmac_spi_read(dev, 0, MT_ADIE_CHIP_ID, &adie_main); if (ret) goto out; if (is_mt7986(&dev->mt76)) { ret = mt76_wmac_spi_read(dev, 1, MT_ADIE_CHIP_ID, &adie_ext); if (ret) goto out; } *adie_type = FIELD_GET(MT_ADIE_CHIP_ID_MASK, adie_main) | (MT_ADIE_CHIP_ID_MASK & adie_ext); out: mt76_wmac_spi_unlock(dev); return 0; } static inline u16 mt7986_adie_idx(u8 adie, u32 adie_type) { if (adie == 0) return u32_get_bits(adie_type, MT_ADIE_IDX0); else return u32_get_bits(adie_type, MT_ADIE_IDX1); } static inline bool is_7975(struct mt7915_dev *dev, u8 adie, u32 adie_type) { return mt7986_adie_idx(adie, adie_type) == 0x7975; } static inline bool is_7976(struct mt7915_dev *dev, u8 adie, u32 adie_type) { return mt7986_adie_idx(adie, adie_type) == 0x7976; } static int mt7986_wmac_adie_thermal_cal(struct mt7915_dev *dev, u8 adie) { int ret; u32 data, val; ret = mt7986_wmac_adie_efuse_read(dev, adie, MT_ADIE_THADC_ANALOG, &data); if (ret || FIELD_GET(MT_ADIE_ANA_EN_MASK, data)) { val = FIELD_GET(MT_ADIE_VRPI_SEL_EFUSE_MASK, data); ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_RG_TOP_THADC_BG, MT_ADIE_VRPI_SEL_CR_MASK, FIELD_PREP(MT_ADIE_VRPI_SEL_CR_MASK, val)); if (ret) return ret; val = FIELD_GET(MT_ADIE_PGA_GAIN_EFUSE_MASK, data); ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_RG_TOP_THADC, MT_ADIE_PGA_GAIN_MASK, FIELD_PREP(MT_ADIE_PGA_GAIN_MASK, val)); if (ret) return ret; } ret = mt7986_wmac_adie_efuse_read(dev, adie, MT_ADIE_THADC_SLOP, &data); if (ret || FIELD_GET(MT_ADIE_ANA_EN_MASK, data)) { val = FIELD_GET(MT_ADIE_LDO_CTRL_EFUSE_MASK, data); return mt76_wmac_spi_rmw(dev, adie, MT_ADIE_RG_TOP_THADC, MT_ADIE_LDO_CTRL_MASK, FIELD_PREP(MT_ADIE_LDO_CTRL_MASK, val)); } return 0; } static int mt7986_read_efuse_xo_trim_7976(struct mt7915_dev *dev, u8 adie, bool is_40m, int *result) { int ret; u32 data, addr; addr = is_40m ? MT_ADIE_XTAL_AXM_40M_OSC : MT_ADIE_XTAL_AXM_80M_OSC; ret = mt7986_wmac_adie_efuse_read(dev, adie, addr, &data); if (ret) return ret; if (!FIELD_GET(MT_ADIE_XO_TRIM_EN_MASK, data)) { *result = 64; } else { *result = FIELD_GET(MT_ADIE_TRIM_MASK, data); addr = is_40m ? MT_ADIE_XTAL_TRIM1_40M_OSC : MT_ADIE_XTAL_TRIM1_80M_OSC; ret = mt7986_wmac_adie_efuse_read(dev, adie, addr, &data); if (ret) return ret; if (FIELD_GET(MT_ADIE_XO_TRIM_EN_MASK, data) && FIELD_GET(MT_ADIE_XTAL_DECREASE_MASK, data)) *result -= FIELD_GET(MT_ADIE_EFUSE_TRIM_MASK, data); else if (FIELD_GET(MT_ADIE_XO_TRIM_EN_MASK, data)) *result += FIELD_GET(MT_ADIE_EFUSE_TRIM_MASK, data); *result = max(0, min(127, *result)); } return 0; } static int mt7986_wmac_adie_xtal_trim_7976(struct mt7915_dev *dev, u8 adie) { int ret, trim_80m, trim_40m; u32 data, val, mode; ret = mt7986_wmac_adie_efuse_read(dev, adie, MT_ADIE_XO_TRIM_FLOW, &data); if (ret || !FIELD_GET(BIT(1), data)) return 0; ret = mt7986_read_efuse_xo_trim_7976(dev, adie, false, &trim_80m); if (ret) return ret; ret = mt7986_read_efuse_xo_trim_7976(dev, adie, true, &trim_40m); if (ret) return ret; ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_RG_STRAP_PIN_IN, &val); if (ret) return ret; mode = FIELD_PREP(GENMASK(6, 4), val); if (!mode || mode == 0x2) { ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_XTAL_C1, GENMASK(31, 24), FIELD_PREP(GENMASK(31, 24), trim_80m)); if (ret) return ret; ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_XTAL_C2, GENMASK(31, 24), FIELD_PREP(GENMASK(31, 24), trim_80m)); } else if (mode == 0x3 || mode == 0x4 || mode == 0x6) { ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_XTAL_C1, GENMASK(23, 16), FIELD_PREP(GENMASK(23, 16), trim_40m)); if (ret) return ret; ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_XTAL_C2, GENMASK(23, 16), FIELD_PREP(GENMASK(23, 16), trim_40m)); } return ret; } static int mt798x_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie) { u32 id, version, rg_xo_01, rg_xo_03; int ret; ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_CHIP_ID, &id); if (ret) return ret; version = FIELD_GET(MT_ADIE_VERSION_MASK, id); ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_TOP_THADC, 0x4a563b00); if (ret) return ret; - if (version == 0x8a00 || version == 0x8a10 || version == 0x8b00) { + if (version == 0x8a00 || version == 0x8a10 || + version == 0x8b00 || version == 0x8c10) { rg_xo_01 = 0x1d59080f; rg_xo_03 = 0x34c00fe0; } else { if (is_mt7981(&dev->mt76)) { rg_xo_01 = 0x1959c80f; } else if (is_mt7986(&dev->mt76)) { rg_xo_01 = 0x1959f80f; } else { WARN_ON(1); return -EINVAL; } rg_xo_03 = 0x34d00fe0; } ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_01, rg_xo_01); if (ret) return ret; return mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_03, rg_xo_03); } static int mt7986_read_efuse_xo_trim_7975(struct mt7915_dev *dev, u8 adie, u32 addr, u32 *result) { int ret; u32 data; ret = mt7986_wmac_adie_efuse_read(dev, adie, addr, &data); if (ret) return ret; if ((data & MT_ADIE_XO_TRIM_EN_MASK)) { if ((data & MT_ADIE_XTAL_DECREASE_MASK)) *result -= (data & MT_ADIE_EFUSE_TRIM_MASK); else *result += (data & MT_ADIE_EFUSE_TRIM_MASK); *result = (*result & MT_ADIE_TRIM_MASK); } return 0; } static int mt7986_wmac_adie_xtal_trim_7975(struct mt7915_dev *dev, u8 adie) { int ret; u32 data, result = 0, value; ret = mt7986_wmac_adie_efuse_read(dev, adie, MT_ADIE_7975_XTAL_EN, &data); if (ret || !(data & BIT(1))) return 0; ret = mt7986_wmac_adie_efuse_read(dev, adie, MT_ADIE_7975_XTAL_CAL, &data); if (ret) return ret; if (data & MT_ADIE_XO_TRIM_EN_MASK) result = (data & MT_ADIE_TRIM_MASK); ret = mt7986_read_efuse_xo_trim_7975(dev, adie, MT_ADIE_7975_XO_TRIM2, &result); if (ret) return ret; ret = mt7986_read_efuse_xo_trim_7975(dev, adie, MT_ADIE_7975_XO_TRIM3, &result); if (ret) return ret; ret = mt7986_read_efuse_xo_trim_7975(dev, adie, MT_ADIE_7975_XO_TRIM4, &result); if (ret) return ret; /* Update trim value to C1 and C2*/ value = FIELD_GET(MT_ADIE_7975_XO_CTRL2_C1_MASK, result) | FIELD_GET(MT_ADIE_7975_XO_CTRL2_C2_MASK, result); ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_7975_XO_CTRL2, MT_ADIE_7975_XO_CTRL2_MASK, value); if (ret) return ret; ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_7975_XTAL, &value); if (ret) return ret; if (value & MT_ADIE_7975_XTAL_EN_MASK) { ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_7975_XO_2, MT_ADIE_7975_XO_2_FIX_EN, 0x0); if (ret) return ret; } return mt76_wmac_spi_rmw(dev, adie, MT_ADIE_7975_XO_CTRL6, MT_ADIE_7975_XO_CTRL6_MASK, 0x1); } static int mt7986_wmac_adie_patch_7975(struct mt7915_dev *dev, u8 adie) { int ret; /* disable CAL LDO and fine tune RFDIG LDO */ ret = mt76_wmac_spi_write(dev, adie, 0x348, 0x00000002); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x378, 0x00000002); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x3a8, 0x00000002); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x3d8, 0x00000002); if (ret) return ret; /* set CKA driving and filter */ ret = mt76_wmac_spi_write(dev, adie, 0xa1c, 0x30000aaa); if (ret) return ret; /* set CKB LDO to 1.4V */ ret = mt76_wmac_spi_write(dev, adie, 0xa84, 0x8470008a); if (ret) return ret; /* turn on SX0 LTBUF */ if (is_mt7981(&dev->mt76)) { ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000007); } else if (is_mt7986(&dev->mt76)) { ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000002); } else { WARN_ON(1); return -EINVAL; } if (ret) return ret; /* CK_BUF_SW_EN = 1 (all buf in manual mode.) */ ret = mt76_wmac_spi_write(dev, adie, 0xaa4, 0x01001fc0); if (ret) return ret; /* BT mode/WF normal mode 00000005 */ ret = mt76_wmac_spi_write(dev, adie, 0x070, 0x00000005); if (ret) return ret; /* BG thermal sensor offset update */ ret = mt76_wmac_spi_write(dev, adie, 0x344, 0x00000088); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x374, 0x00000088); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x3a4, 0x00000088); if (ret) return ret; ret = mt76_wmac_spi_write(dev, adie, 0x3d4, 0x00000088); if (ret) return ret; /* set WCON VDD IPTAT to "0000" */ ret = mt76_wmac_spi_write(dev, adie, 0xa80, 0x44d07000); if (ret) return ret; /* change back LTBUF SX3 drving to default value */ ret = mt76_wmac_spi_write(dev, adie, 0xa88, 0x3900aaaa); if (ret) return ret; /* SM input cap off */ ret = mt76_wmac_spi_write(dev, adie, 0x2c4, 0x00000000); if (ret) return ret; /* set CKB driving and filter */ if (is_mt7986(&dev->mt76)) return mt76_wmac_spi_write(dev, adie, 0x2c8, 0x00000072); return ret; } static int mt7986_wmac_adie_cfg(struct mt7915_dev *dev, u8 adie, u32 adie_type) { int ret; mt76_wmac_spi_lock(dev); ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_CLK_EN, ~0); if (ret) goto out; if (is_7975(dev, adie, adie_type)) { ret = mt76_wmac_spi_rmw(dev, adie, MT_ADIE_7975_COCLK, BIT(1), 0x1); if (ret) goto out; ret = mt7986_wmac_adie_thermal_cal(dev, adie); if (ret) goto out; ret = mt7986_wmac_adie_xtal_trim_7975(dev, adie); if (ret) goto out; ret = mt7986_wmac_adie_patch_7975(dev, adie); } else if (is_7976(dev, adie, adie_type)) { if (mt798x_wmac_check_adie_type(dev) == ADIE_DBDC) { ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_WRI_CK_SEL, 0x1c); if (ret) goto out; } ret = mt7986_wmac_adie_thermal_cal(dev, adie); if (ret) goto out; ret = mt7986_wmac_adie_xtal_trim_7976(dev, adie); if (ret) goto out; ret = mt798x_wmac_adie_patch_7976(dev, adie); } out: mt76_wmac_spi_unlock(dev); return ret; } static int mt7986_wmac_afe_cal(struct mt7915_dev *dev, u8 adie, bool dbdc, u32 adie_type) { int ret; u8 idx; u32 txcal; mt76_wmac_spi_lock(dev); if (is_7975(dev, adie, adie_type)) ret = mt76_wmac_spi_write(dev, adie, MT_AFE_RG_ENCAL_WBTAC_IF_SW, 0x80000000); else ret = mt76_wmac_spi_write(dev, adie, MT_AFE_RG_ENCAL_WBTAC_IF_SW, 0x88888005); if (ret) goto out; idx = dbdc ? ADIE_DBDC : adie; mt76_rmw_field(dev, MT_AFE_DIG_EN_01(idx), MT_AFE_RG_WBG_EN_RCK_MASK, 0x1); usleep_range(60, 100); mt76_rmw(dev, MT_AFE_DIG_EN_01(idx), MT_AFE_RG_WBG_EN_RCK_MASK, 0x0); mt76_rmw_field(dev, MT_AFE_DIG_EN_03(idx), MT_AFE_RG_WBG_EN_BPLL_UP_MASK, 0x1); usleep_range(30, 100); mt76_rmw_field(dev, MT_AFE_DIG_EN_03(idx), MT_AFE_RG_WBG_EN_WPLL_UP_MASK, 0x1); usleep_range(60, 100); txcal = (MT_AFE_RG_WBG_EN_TXCAL_BT | MT_AFE_RG_WBG_EN_TXCAL_WF0 | MT_AFE_RG_WBG_EN_TXCAL_WF1 | MT_AFE_RG_WBG_EN_TXCAL_WF2 | MT_AFE_RG_WBG_EN_TXCAL_WF3); if (is_mt7981(&dev->mt76)) txcal |= MT_AFE_RG_WBG_EN_TXCAL_WF4; mt76_set(dev, MT_AFE_DIG_EN_01(idx), txcal); usleep_range(800, 1000); mt76_clear(dev, MT_AFE_DIG_EN_01(idx), txcal); mt76_rmw(dev, MT_AFE_DIG_EN_03(idx), MT_AFE_RG_WBG_EN_PLL_UP_MASK, 0x0); ret = mt76_wmac_spi_write(dev, adie, MT_AFE_RG_ENCAL_WBTAC_IF_SW, 0x5); out: mt76_wmac_spi_unlock(dev); return ret; } static void mt7986_wmac_subsys_pll_initial(struct mt7915_dev *dev, u8 band) { mt76_rmw(dev, MT_AFE_PLL_STB_TIME(band), MT_AFE_PLL_STB_TIME_MASK, MT_AFE_PLL_STB_TIME_VAL); mt76_rmw(dev, MT_AFE_DIG_EN_02(band), MT_AFE_PLL_CFG_MASK, MT_AFE_PLL_CFG_VAL); mt76_rmw(dev, MT_AFE_DIG_TOP_01(band), MT_AFE_DIG_TOP_01_MASK, MT_AFE_DIG_TOP_01_VAL); } static void mt7986_wmac_subsys_setting(struct mt7915_dev *dev) { /* Subsys pll init */ mt7986_wmac_subsys_pll_initial(dev, 0); mt7986_wmac_subsys_pll_initial(dev, 1); /* Set legacy OSC control stable time*/ mt76_rmw(dev, MT_CONN_INFRA_OSC_RC_EN, MT_CONN_INFRA_OSC_RC_EN_MASK, 0x0); mt76_rmw(dev, MT_CONN_INFRA_OSC_CTRL, MT_CONN_INFRA_OSC_STB_TIME_MASK, 0x80706); /* prevent subsys from power on/of in a short time interval */ mt76_rmw(dev, MT_TOP_WFSYS_PWR, MT_TOP_PWR_ACK_MASK | MT_TOP_PWR_KEY_MASK, MT_TOP_PWR_KEY); } static int mt7986_wmac_bus_timeout(struct mt7915_dev *dev) { mt76_rmw_field(dev, MT_INFRA_BUS_OFF_TIMEOUT, MT_INFRA_BUS_TIMEOUT_LIMIT_MASK, 0x2); mt76_rmw_field(dev, MT_INFRA_BUS_OFF_TIMEOUT, MT_INFRA_BUS_TIMEOUT_EN_MASK, 0xf); mt76_rmw_field(dev, MT_INFRA_BUS_ON_TIMEOUT, MT_INFRA_BUS_TIMEOUT_LIMIT_MASK, 0xc); mt76_rmw_field(dev, MT_INFRA_BUS_ON_TIMEOUT, MT_INFRA_BUS_TIMEOUT_EN_MASK, 0xf); return mt798x_wmac_coninfra_check(dev); } static void mt7986_wmac_clock_enable(struct mt7915_dev *dev, u32 adie_type) { u32 cur; mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS_WPLL_DIV_1, MT_INFRA_CKGEN_DIV_SEL_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS_WPLL_DIV_2, MT_INFRA_CKGEN_DIV_SEL_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS_WPLL_DIV_1, MT_INFRA_CKGEN_DIV_EN_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS_WPLL_DIV_2, MT_INFRA_CKGEN_DIV_EN_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_RFSPI_WPLL_DIV, MT_INFRA_CKGEN_DIV_SEL_MASK, 0x8); mt76_rmw_field(dev, MT_INFRA_CKGEN_RFSPI_WPLL_DIV, MT_INFRA_CKGEN_DIV_EN_MASK, 0x1); mt76_rmw_field(dev, MT_INFRA_CKGEN_BUS, MT_INFRA_CKGEN_BUS_CLK_SEL_MASK, 0x0); mt76_rmw_field(dev, MT_CONN_INFRA_HW_CTRL, MT_CONN_INFRA_HW_CTRL_MASK, 0x1); mt76_rmw(dev, MT_TOP_CONN_INFRA_WAKEUP, MT_TOP_CONN_INFRA_WAKEUP_MASK, 0x1); usleep_range(900, 1000); mt76_wmac_spi_lock(dev); if (is_7975(dev, 0, adie_type) || is_7976(dev, 0, adie_type)) { mt76_rmw_field(dev, MT_ADIE_SLP_CTRL_CK0(0), MT_SLP_CTRL_EN_MASK, 0x1); read_poll_timeout(mt76_rr, cur, !(cur & MT_SLP_CTRL_BSY_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_ADIE_SLP_CTRL_CK0(0)); } if (is_7975(dev, 1, adie_type) || is_7976(dev, 1, adie_type)) { mt76_rmw_field(dev, MT_ADIE_SLP_CTRL_CK0(1), MT_SLP_CTRL_EN_MASK, 0x1); read_poll_timeout(mt76_rr, cur, !(cur & MT_SLP_CTRL_BSY_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_ADIE_SLP_CTRL_CK0(0)); } mt76_wmac_spi_unlock(dev); mt76_rmw(dev, MT_TOP_CONN_INFRA_WAKEUP, MT_TOP_CONN_INFRA_WAKEUP_MASK, 0x0); usleep_range(900, 1000); } static int mt7986_wmac_top_wfsys_wakeup(struct mt7915_dev *dev, bool enable) { mt76_rmw_field(dev, MT_TOP_WFSYS_WAKEUP, MT_TOP_WFSYS_WAKEUP_MASK, enable); usleep_range(900, 1000); if (!enable) return 0; return mt798x_wmac_coninfra_check(dev); } static int mt7986_wmac_wm_enable(struct mt7915_dev *dev, bool enable) { u32 cur; if (is_mt7986(&dev->mt76)) mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, 0); mt76_rmw_field(dev, MT7986_TOP_WM_RESET, MT7986_TOP_WM_RESET_MASK, enable); if (!enable) return 0; return read_poll_timeout(mt76_rr, cur, (cur == 0x1d1e), USEC_PER_MSEC, 5000 * USEC_PER_MSEC, false, dev, MT_TOP_CFG_ON_ROM_IDX); } static int mt7986_wmac_wfsys_poweron(struct mt7915_dev *dev, bool enable) { u32 mask = MT_TOP_PWR_EN_MASK | MT_TOP_PWR_KEY_MASK; u32 cur; mt76_rmw(dev, MT_TOP_WFSYS_PWR, mask, MT_TOP_PWR_KEY | FIELD_PREP(MT_TOP_PWR_EN_MASK, enable)); return read_poll_timeout(mt76_rr, cur, (FIELD_GET(MT_TOP_WFSYS_RESET_STATUS_MASK, cur) == enable), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_WFSYS_RESET_STATUS); } static int mt7986_wmac_wfsys_setting(struct mt7915_dev *dev) { int ret; u32 cur; /* Turn off wfsys2conn bus sleep protect */ mt76_rmw(dev, MT_CONN_INFRA_WF_SLP_PROT, MT_CONN_INFRA_WF_SLP_PROT_MASK, 0x0); ret = mt7986_wmac_wfsys_poweron(dev, true); if (ret) return ret; /* Check bus sleep protect */ ret = read_poll_timeout(mt76_rr, cur, !(cur & MT_CONN_INFRA_CONN_WF_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_CONN_INFRA_WF_SLP_PROT_RDY); if (ret) return ret; ret = read_poll_timeout(mt76_rr, cur, !(cur & MT_SLP_WFDMA2CONN_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_SLP_STATUS); if (ret) return ret; return read_poll_timeout(mt76_rr, cur, (cur == 0x02060000), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_TOP_CFG_IP_VERSION_ADDR); } static void mt7986_wmac_wfsys_set_timeout(struct mt7915_dev *dev) { u32 mask = MT_MCU_BUS_TIMEOUT_SET_MASK | MT_MCU_BUS_TIMEOUT_CG_EN_MASK | MT_MCU_BUS_TIMEOUT_EN_MASK; u32 val = FIELD_PREP(MT_MCU_BUS_TIMEOUT_SET_MASK, 1) | FIELD_PREP(MT_MCU_BUS_TIMEOUT_CG_EN_MASK, 1) | FIELD_PREP(MT_MCU_BUS_TIMEOUT_EN_MASK, 1); mt76_rmw(dev, MT_MCU_BUS_TIMEOUT, mask, val); mt76_wr(dev, MT_MCU_BUS_REMAP, 0x810f0000); mask = MT_MCU_BUS_DBG_TIMEOUT_SET_MASK | MT_MCU_BUS_DBG_TIMEOUT_CK_EN_MASK | MT_MCU_BUS_DBG_TIMEOUT_EN_MASK; val = FIELD_PREP(MT_MCU_BUS_DBG_TIMEOUT_SET_MASK, 0x3aa) | FIELD_PREP(MT_MCU_BUS_DBG_TIMEOUT_CK_EN_MASK, 1) | FIELD_PREP(MT_MCU_BUS_DBG_TIMEOUT_EN_MASK, 1); mt76_rmw(dev, MT_MCU_BUS_DBG_TIMEOUT, mask, val); } static int mt7986_wmac_sku_update(struct mt7915_dev *dev, u32 adie_type) { u32 val; if (is_7976(dev, 0, adie_type) && is_7976(dev, 1, adie_type)) val = 0xf; else if (is_7975(dev, 0, adie_type) && is_7975(dev, 1, adie_type)) val = 0xd; else if (is_7976(dev, 0, adie_type)) val = 0x7; else if (is_7975(dev, 1, adie_type)) val = 0x8; else if (is_7976(dev, 1, adie_type)) val = 0xa; else return -EINVAL; mt76_wmac_rmw(dev->sku, MT_TOP_POS_SKU, MT_TOP_POS_SKU_MASK, FIELD_PREP(MT_TOP_POS_SKU_MASK, val)); mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, val); return 0; } static int mt7986_wmac_adie_setup(struct mt7915_dev *dev, u8 adie, u32 adie_type) { int ret; if (!(is_7975(dev, adie, adie_type) || is_7976(dev, adie, adie_type))) return 0; ret = mt7986_wmac_adie_cfg(dev, adie, adie_type); if (ret) return ret; ret = mt7986_wmac_afe_cal(dev, adie, false, adie_type); if (ret) return ret; if (!adie && (mt798x_wmac_check_adie_type(dev) == ADIE_DBDC)) ret = mt7986_wmac_afe_cal(dev, adie, true, adie_type); return ret; } static int mt7986_wmac_subsys_powerup(struct mt7915_dev *dev, u32 adie_type) { int ret; mt7986_wmac_subsys_setting(dev); ret = mt7986_wmac_bus_timeout(dev); if (ret) return ret; mt7986_wmac_clock_enable(dev, adie_type); return 0; } static int mt7986_wmac_wfsys_powerup(struct mt7915_dev *dev) { int ret; ret = mt7986_wmac_wm_enable(dev, false); if (ret) return ret; ret = mt7986_wmac_wfsys_setting(dev); if (ret) return ret; mt7986_wmac_wfsys_set_timeout(dev); return mt7986_wmac_wm_enable(dev, true); } int mt7986_wmac_enable(struct mt7915_dev *dev) { int ret; u32 adie_type; ret = mt7986_wmac_consys_reset(dev, true); if (ret) return ret; ret = mt7986_wmac_gpio_setup(dev); if (ret) return ret; ret = mt7986_wmac_consys_lockup(dev, false); if (ret) return ret; ret = mt798x_wmac_coninfra_check(dev); if (ret) return ret; ret = mt798x_wmac_coninfra_setup(dev); if (ret) return ret; ret = mt798x_wmac_sku_setup(dev, &adie_type); if (ret) return ret; ret = mt7986_wmac_adie_setup(dev, 0, adie_type); if (ret) return ret; /* mt7981 doesn't support a second a-die */ if (is_mt7986(&dev->mt76)) { ret = mt7986_wmac_adie_setup(dev, 1, adie_type); if (ret) return ret; } ret = mt7986_wmac_subsys_powerup(dev, adie_type); if (ret) return ret; ret = mt7986_wmac_top_wfsys_wakeup(dev, true); if (ret) return ret; ret = mt7986_wmac_wfsys_powerup(dev); if (ret) return ret; return mt7986_wmac_sku_update(dev, adie_type); } void mt7986_wmac_disable(struct mt7915_dev *dev) { u32 cur; mt7986_wmac_top_wfsys_wakeup(dev, true); /* Turn on wfsys2conn bus sleep protect */ mt76_rmw_field(dev, MT_CONN_INFRA_WF_SLP_PROT, MT_CONN_INFRA_WF_SLP_PROT_MASK, 0x1); /* Check wfsys2conn bus sleep protect */ read_poll_timeout(mt76_rr, cur, !(cur ^ MT_CONN_INFRA_CONN), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, dev, MT_CONN_INFRA_WF_SLP_PROT_RDY); mt7986_wmac_wfsys_poweron(dev, false); /* Turn back wpll setting */ mt76_rmw_field(dev, MT_AFE_DIG_EN_02(0), MT_AFE_MCU_BPLL_CFG_MASK, 0x2); mt76_rmw_field(dev, MT_AFE_DIG_EN_02(0), MT_AFE_WPLL_CFG_MASK, 0x2); /* Reset EMI */ mt76_rmw_field(dev, MT_CONN_INFRA_EMI_REQ, MT_CONN_INFRA_EMI_REQ_MASK, 0x1); mt76_rmw_field(dev, MT_CONN_INFRA_EMI_REQ, MT_CONN_INFRA_EMI_REQ_MASK, 0x0); mt76_rmw_field(dev, MT_CONN_INFRA_EMI_REQ, MT_CONN_INFRA_INFRA_REQ_MASK, 0x1); mt76_rmw_field(dev, MT_CONN_INFRA_EMI_REQ, MT_CONN_INFRA_INFRA_REQ_MASK, 0x0); mt7986_wmac_top_wfsys_wakeup(dev, false); mt7986_wmac_consys_lockup(dev, true); mt7986_wmac_consys_reset(dev, false); } static int mt798x_wmac_init(struct mt7915_dev *dev) { struct device *pdev = dev->mt76.dev; struct platform_device *pfdev = to_platform_device(pdev); struct clk *mcu_clk, *ap_conn_clk; mcu_clk = devm_clk_get(pdev, "mcu"); if (IS_ERR(mcu_clk)) dev_err(pdev, "mcu clock not found\n"); else if (clk_prepare_enable(mcu_clk)) dev_err(pdev, "mcu clock configuration failed\n"); ap_conn_clk = devm_clk_get(pdev, "ap2conn"); if (IS_ERR(ap_conn_clk)) dev_err(pdev, "ap2conn clock not found\n"); else if (clk_prepare_enable(ap_conn_clk)) dev_err(pdev, "ap2conn clock configuration failed\n"); dev->dcm = devm_platform_ioremap_resource(pfdev, 1); if (IS_ERR(dev->dcm)) return PTR_ERR(dev->dcm); dev->sku = devm_platform_ioremap_resource(pfdev, 2); if (IS_ERR(dev->sku)) return PTR_ERR(dev->sku); dev->rstc = devm_reset_control_get(pdev, "consys"); - if (IS_ERR(dev->rstc)) - return PTR_ERR(dev->rstc); - - return 0; + return PTR_ERR_OR_ZERO(dev->rstc); } static int mt798x_wmac_probe(struct platform_device *pdev) { void __iomem *mem_base; struct mt7915_dev *dev; struct mt76_dev *mdev; int irq, ret; u32 chip_id; chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev); mem_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem_base)) { dev_err(&pdev->dev, "Failed to get memory resource\n"); return PTR_ERR(mem_base); } dev = mt7915_mmio_probe(&pdev->dev, mem_base, chip_id); if (IS_ERR(dev)) return PTR_ERR(dev); mdev = &dev->mt76; ret = mt7915_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) goto free_device; if (!ret) { irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; goto free_device; } } ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) goto free_device; ret = mt798x_wmac_init(dev); if (ret) goto free_irq; mt7915_wfsys_reset(dev); ret = mt7915_register_device(dev); if (ret) goto free_irq; return 0; free_irq: devm_free_irq(mdev->dev, irq, dev); free_device: if (mtk_wed_device_active(&mdev->mmio.wed)) mtk_wed_device_detach(&mdev->mmio.wed); mt76_free_device(mdev); return ret; } -static int mt798x_wmac_remove(struct platform_device *pdev) +static void mt798x_wmac_remove(struct platform_device *pdev) { struct mt7915_dev *dev = platform_get_drvdata(pdev); mt7915_unregister_device(dev); - - return 0; } static const struct of_device_id mt798x_wmac_of_match[] = { { .compatible = "mediatek,mt7981-wmac", .data = (u32 *)0x7981 }, { .compatible = "mediatek,mt7986-wmac", .data = (u32 *)0x7986 }, {}, }; MODULE_DEVICE_TABLE(of, mt798x_wmac_of_match); struct platform_driver mt798x_wmac_driver = { .driver = { .name = "mt798x-wmac", .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, .remove = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); MODULE_FIRMWARE(MT7986_FIRMWARE_WM); MODULE_FIRMWARE(MT7986_FIRMWARE_WM_MT7975); MODULE_FIRMWARE(MT7986_ROM_PATCH); MODULE_FIRMWARE(MT7986_ROM_PATCH_MT7975); MODULE_FIRMWARE(MT7981_FIRMWARE_WA); MODULE_FIRMWARE(MT7981_FIRMWARE_WM); MODULE_FIRMWARE(MT7981_ROM_PATCH); diff --git a/sys/contrib/dev/mediatek/mt76/mt7915/testmode.c b/sys/contrib/dev/mediatek/mt76/mt7915/testmode.c index 0d76ae31b376..d534fff5c952 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7915/testmode.c +++ b/sys/contrib/dev/mediatek/mt76/mt7915/testmode.c @@ -1,788 +1,790 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include "mt7915.h" #include "mac.h" #include "mcu.h" #include "testmode.h" enum { TM_CHANGED_TXPOWER, TM_CHANGED_FREQ_OFFSET, /* must be last */ NUM_TM_CHANGED }; static const u8 tm_change_map[] = { [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, }; struct reg_band { u32 band[2]; }; #define REG_BAND(_list, _reg) \ { _list.band[0] = MT_##_reg(0); \ _list.band[1] = MT_##_reg(1); } #define REG_BAND_IDX(_list, _reg, _idx) \ { _list.band[0] = MT_##_reg(0, _idx); \ _list.band[1] = MT_##_reg(1, _idx); } #define TM_REG_MAX_ID 17 static struct reg_band reg_backup_list[TM_REG_MAX_ID]; static int mt7915_tm_set_tx_power(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct cfg80211_chan_def *chandef = &mphy->chandef; int freq = chandef->center_freq1; int ret; struct { u8 format_id; u8 band_idx; s8 tx_power; u8 ant_idx; /* Only 0 is valid */ u8 center_chan; u8 rsv[3]; } __packed req = { .format_id = 0xf, .band_idx = phy->mt76->band_idx, .center_chan = ieee80211_frequency_to_channel(freq), }; u8 *tx_power = NULL; if (phy->mt76->test.state != MT76_TM_STATE_OFF) tx_power = phy->mt76->test.tx_power; /* Tx power of the other antennas are the same as antenna 0 */ if (tx_power && tx_power[0]) req.tx_power = tx_power[0]; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), false); return ret; } static int mt7915_tm_set_freq_offset(struct mt7915_phy *phy, bool en, u32 val) { struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = en, .param_idx = MCU_ATE_SET_FREQ_OFFSET, .param.freq.band = phy->mt76->band_idx, .param.freq.freq_offset = cpu_to_le32(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } static int mt7915_tm_mode_ctrl(struct mt7915_dev *dev, bool enable) { struct { u8 format_id; bool enable; u8 rsv[2]; } __packed req = { .format_id = 0x6, .enable = enable, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, sizeof(req), false); } static int mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en) { struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = 1, .param_idx = MCU_ATE_SET_TRX, .param.trx.type = type, .param.trx.enable = en, .param.trx.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } static int mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid) { struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = 1, .param_idx = MCU_ATE_CLEAN_TXQUEUE, .param.clean.wcid = wcid, .param.clean.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, sizeof(req), false); } static int mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) { struct mt7915_dev *dev = phy->dev; struct mt7915_tm_cmd req = { .testmode_en = !(phy->mt76->test.state == MT76_TM_STATE_OFF), .param_idx = MCU_ATE_SET_SLOT_TIME, .param.slot.slot_time = slot_time, .param.slot.sifs = sifs, .param.slot.rifs = 2, .param.slot.eifs = cpu_to_le16(60), .param.slot.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 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_phy *phy, u8 qid, u8 aifs, u8 cw_min, u16 cw_max, u16 txop) { struct mt7915_vif *mvif = (struct mt7915_vif *)phy->monitor_vif->drv_priv; struct mt7915_mcu_tx req = { .total = 1 }; struct edca *e = &req.edca[0]; e->queue = qid + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; e->set = WMM_PARAM_SET; e->aifs = aifs; e->cw_min = cw_min; e->cw_max = cpu_to_le16(cw_max); e->txop = cpu_to_le16(txop); return mt7915_mcu_update_edca(phy->dev, &req); } static int mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode) { #define TM_DEFAULT_SIFS 10 #define TM_MAX_SIFS 127 #define TM_MAX_AIFSN 0xf #define TM_MIN_AIFSN 0x1 #define BBP_PROC_TIME 1500 struct mt7915_dev *dev = phy->dev; u8 sig_ext = (mode == MT76_TM_TX_MODE_CCK) ? 0 : 6; u8 slot_time = 9, sifs = TM_DEFAULT_SIFS; u8 aifsn = TM_MIN_AIFSN; u8 band = phy->mt76->band_idx; u32 i2t_time, tr2t_time, txv_time; u16 cw = 0; if (ipg < sig_ext + slot_time + sifs) ipg = 0; if (!ipg) goto done; ipg -= sig_ext; if (ipg <= (TM_MAX_SIFS + slot_time)) { sifs = ipg - slot_time; } else { u32 val = (ipg + slot_time) / slot_time; while (val >>= 1) cw++; if (cw > 16) cw = 16; ipg -= ((1 << cw) - 1) * slot_time; aifsn = ipg / slot_time; if (aifsn > TM_MAX_AIFSN) aifsn = TM_MAX_AIFSN; ipg -= aifsn * slot_time; if (ipg > TM_DEFAULT_SIFS) sifs = min_t(u32, ipg, TM_MAX_SIFS); } done: txv_time = mt76_get_field(dev, MT_TMAC_ATCR(band), MT_TMAC_ATCR_TXV_TOUT); txv_time *= 50; /* normal clock time */ i2t_time = (slot_time * 1000 - txv_time - BBP_PROC_TIME) / 50; tr2t_time = (sifs * 1000 - txv_time - BBP_PROC_TIME) / 50; mt76_set(dev, MT_TMAC_TRCR0(band), FIELD_PREP(MT_TMAC_TRCR0_TR2T_CHK, tr2t_time) | FIELD_PREP(MT_TMAC_TRCR0_I2T_CHK, i2t_time)); mt7915_tm_set_slot_time(phy, slot_time, sifs); return mt7915_tm_set_wmm_qid(phy, mt76_connac_lmac_mapping(IEEE80211_AC_BE), aifsn, cw, cw, 0); } static int mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time) { struct mt76_phy *mphy = phy->mt76; struct mt76_testmode_data *td = &mphy->test; struct ieee80211_supported_band *sband; struct rate_info rate = {}; u16 flags = 0, tx_len; u32 bitrate; int ret; if (!tx_time) return 0; rate.mcs = td->tx_rate_idx; rate.nss = td->tx_rate_nss; switch (td->tx_rate_mode) { case MT76_TM_TX_MODE_CCK: case MT76_TM_TX_MODE_OFDM: if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.sband; else sband = &mphy->sband_2g.sband; rate.legacy = sband->bitrates[rate.mcs].bitrate; break; case MT76_TM_TX_MODE_HT: rate.mcs += rate.nss * 8; flags |= RATE_INFO_FLAGS_MCS; if (td->tx_rate_sgi) flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT76_TM_TX_MODE_VHT: flags |= RATE_INFO_FLAGS_VHT_MCS; if (td->tx_rate_sgi) flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT76_TM_TX_MODE_HE_SU: case MT76_TM_TX_MODE_HE_EXT_SU: case MT76_TM_TX_MODE_HE_TB: case MT76_TM_TX_MODE_HE_MU: rate.he_gi = td->tx_rate_sgi; flags |= RATE_INFO_FLAGS_HE_MCS; break; default: break; } rate.flags = flags; switch (mphy->chandef.width) { case NL80211_CHAN_WIDTH_160: case NL80211_CHAN_WIDTH_80P80: rate.bw = RATE_INFO_BW_160; break; case NL80211_CHAN_WIDTH_80: rate.bw = RATE_INFO_BW_80; break; case NL80211_CHAN_WIDTH_40: rate.bw = RATE_INFO_BW_40; break; default: rate.bw = RATE_INFO_BW_20; break; } bitrate = cfg80211_calculate_bitrate(&rate); tx_len = bitrate * tx_time / 10 / 8; ret = mt76_testmode_alloc_skb(phy->mt76, tx_len); if (ret) return ret; return 0; } static void mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) { int n_regs = ARRAY_SIZE(reg_backup_list); struct mt7915_dev *dev = phy->dev; u32 *b = phy->test.reg_backup; u8 band = phy->mt76->band_idx; int i; REG_BAND_IDX(reg_backup_list[0], AGG_PCR0, 0); REG_BAND_IDX(reg_backup_list[1], AGG_PCR0, 1); REG_BAND_IDX(reg_backup_list[2], AGG_AWSCR0, 0); REG_BAND_IDX(reg_backup_list[3], AGG_AWSCR0, 1); REG_BAND_IDX(reg_backup_list[4], AGG_AWSCR0, 2); REG_BAND_IDX(reg_backup_list[5], AGG_AWSCR0, 3); REG_BAND(reg_backup_list[6], AGG_MRCR); REG_BAND(reg_backup_list[7], TMAC_TFCR0); REG_BAND(reg_backup_list[8], TMAC_TCR0); REG_BAND(reg_backup_list[9], AGG_ATCR1); REG_BAND(reg_backup_list[10], AGG_ATCR3); REG_BAND(reg_backup_list[11], TMAC_TRCR0); REG_BAND(reg_backup_list[12], TMAC_ICR0); REG_BAND_IDX(reg_backup_list[13], ARB_DRNGR0, 0); REG_BAND_IDX(reg_backup_list[14], ARB_DRNGR0, 1); REG_BAND(reg_backup_list[15], WF_RFCR); REG_BAND(reg_backup_list[16], WF_RFCR1); if (phy->mt76->test.state == MT76_TM_STATE_OFF) { for (i = 0; i < n_regs; i++) mt76_wr(dev, reg_backup_list[i].band[band], b[i]); return; } if (!b) { b = devm_kzalloc(dev->mt76.dev, 4 * n_regs, GFP_KERNEL); if (!b) return; phy->test.reg_backup = b; for (i = 0; i < n_regs; i++) b[i] = mt76_rr(dev, reg_backup_list[i].band[band]); } mt76_clear(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_MM_PROT | MT_AGG_PCR0_GF_PROT | MT_AGG_PCR0_ERP_PROT | MT_AGG_PCR0_VHT_PROT | MT_AGG_PCR0_BW20_PROT | MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT); mt76_set(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_PTA_WIN_DIS); mt76_wr(dev, MT_AGG_PCR0(band, 1), MT_AGG_PCR1_RTS0_NUM_THRES | MT_AGG_PCR1_RTS0_LEN_THRES); mt76_clear(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_BAR_CNT_LIMIT | MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT | MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT); mt76_rmw(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_RTS_FAIL_LIMIT | MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, FIELD_PREP(MT_AGG_MRCR_RTS_FAIL_LIMIT, 1) | FIELD_PREP(MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 1)); mt76_wr(dev, MT_TMAC_TFCR0(band), 0); mt76_clear(dev, MT_TMAC_TCR0(band), MT_TMAC_TCR0_TBTT_STOP_CTRL); /* config rx filter for testmode rx */ mt76_wr(dev, MT_WF_RFCR(band), 0xcf70a); mt76_wr(dev, MT_WF_RFCR1(band), 0); } static void mt7915_tm_init(struct mt7915_phy *phy, bool en) { struct mt7915_dev *dev = phy->dev; + int state; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; mt7915_mcu_set_sku_en(phy, !en); mt7915_tm_mode_ctrl(dev, en); mt7915_tm_reg_backup_restore(phy); 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); + state = en ? CONN_STATE_PORT_SECURE : CONN_STATE_DISCONNECT; + mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, state, true); if (!en) mt7915_tm_set_tam_arb(phy, en, 0); } static void mt7915_tm_update_channel(struct mt7915_phy *phy) { mutex_unlock(&phy->dev->mt76.mutex); - mt7915_set_channel(phy); + mt76_update_channel(phy->mt76); mutex_lock(&phy->dev->mt76.mutex); mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); } static void mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) { struct mt76_testmode_data *td = &phy->mt76->test; struct mt7915_dev *dev = phy->dev; struct ieee80211_tx_info *info; u8 duty_cycle = td->tx_duty_cycle; u32 tx_time = td->tx_time; u32 ipg = td->tx_ipg; mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); mt7915_tm_clean_hwq(phy, dev->mt76.global_wcid.idx); if (en) { mt7915_tm_update_channel(phy); if (td->tx_spe_idx) phy->test.spe_idx = td->tx_spe_idx; else phy->test.spe_idx = mt76_connac_spe_idx(td->tx_antenna_mask); } 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; } else if (duty_cycle && !tx_time && ipg) { if (duty_cycle < 100) tx_time = duty_cycle * ipg / (100 - duty_cycle); } mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode); mt7915_tm_set_tx_len(phy, tx_time); if (ipg) td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2; if (!en || !td->tx_skb) return; info = IEEE80211_SKB_CB(td->tx_skb); info->control.vif = phy->monitor_vif; mt7915_tm_set_trx(phy, TM_MAC_TX, en); } static void mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) { mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); if (en) { struct mt7915_dev *dev = phy->dev; mt7915_tm_update_channel(phy); /* read-clear */ mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); } } static int mt7915_tm_rf_switch_mode(struct mt7915_dev *dev, u32 oper) { struct mt7915_tm_rf_test req = { .op.op_mode = cpu_to_le32(oper), }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, sizeof(req), true); } static int mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) { #define TX_CONT_START 0x05 #define TX_CONT_STOP 0x06 struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = ieee80211_frequency_to_channel(chandef->center_freq1); struct mt76_testmode_data *td = &phy->mt76->test; u32 func_idx = en ? TX_CONT_START : TX_CONT_STOP; u8 rate_idx = td->tx_rate_idx, mode; u8 band = phy->mt76->band_idx; u16 rateval; struct mt7915_tm_rf_test req = { .action = 1, .icap_len = 120, .op.rf.func_idx = cpu_to_le32(func_idx), }; struct tm_tx_cont *tx_cont = &req.op.rf.param.tx_cont; tx_cont->control_ch = chandef->chan->hw_value; tx_cont->center_ch = freq1; tx_cont->tx_ant = td->tx_antenna_mask; tx_cont->band = band; switch (chandef->width) { case NL80211_CHAN_WIDTH_40: tx_cont->bw = CMD_CBW_40MHZ; break; case NL80211_CHAN_WIDTH_80: tx_cont->bw = CMD_CBW_80MHZ; break; case NL80211_CHAN_WIDTH_80P80: tx_cont->bw = CMD_CBW_8080MHZ; break; case NL80211_CHAN_WIDTH_160: tx_cont->bw = CMD_CBW_160MHZ; break; case NL80211_CHAN_WIDTH_5: tx_cont->bw = CMD_CBW_5MHZ; break; case NL80211_CHAN_WIDTH_10: tx_cont->bw = CMD_CBW_10MHZ; break; case NL80211_CHAN_WIDTH_20: tx_cont->bw = CMD_CBW_20MHZ; break; case NL80211_CHAN_WIDTH_20_NOHT: tx_cont->bw = CMD_CBW_20MHZ; break; default: return -EINVAL; } if (!en) { req.op.rf.param.func_data = cpu_to_le32(band); goto out; } if (td->tx_rate_mode <= MT76_TM_TX_MODE_OFDM) { struct ieee80211_supported_band *sband; u8 idx = rate_idx; if (chandef->chan->band == NL80211_BAND_5GHZ) sband = &phy->mt76->sband_5g.sband; else if (chandef->chan->band == NL80211_BAND_6GHZ) sband = &phy->mt76->sband_6g.sband; else sband = &phy->mt76->sband_2g.sband; if (td->tx_rate_mode == MT76_TM_TX_MODE_OFDM) idx += 4; rate_idx = sband->bitrates[idx].hw_value & 0xff; } switch (td->tx_rate_mode) { case MT76_TM_TX_MODE_CCK: mode = MT_PHY_TYPE_CCK; break; case MT76_TM_TX_MODE_OFDM: mode = MT_PHY_TYPE_OFDM; break; case MT76_TM_TX_MODE_HT: mode = MT_PHY_TYPE_HT; break; case MT76_TM_TX_MODE_VHT: mode = MT_PHY_TYPE_VHT; break; case MT76_TM_TX_MODE_HE_SU: mode = MT_PHY_TYPE_HE_SU; break; case MT76_TM_TX_MODE_HE_EXT_SU: mode = MT_PHY_TYPE_HE_EXT_SU; break; case MT76_TM_TX_MODE_HE_TB: mode = MT_PHY_TYPE_HE_TB; break; case MT76_TM_TX_MODE_HE_MU: mode = MT_PHY_TYPE_HE_MU; break; default: return -EINVAL; } rateval = mode << 6 | rate_idx; tx_cont->rateval = cpu_to_le16(rateval); out: if (!en) { int ret; ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, sizeof(req), true); if (ret) return ret; return mt7915_tm_rf_switch_mode(dev, RF_OPER_NORMAL); } mt7915_tm_rf_switch_mode(dev, RF_OPER_RF_TEST); mt7915_tm_update_channel(phy); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, sizeof(req), true); } static void mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed) { struct mt76_testmode_data *td = &phy->mt76->test; bool en = phy->mt76->test.state != MT76_TM_STATE_OFF; if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) mt7915_tm_set_freq_offset(phy, en, en ? td->freq_offset : 0); if (changed & BIT(TM_CHANGED_TXPOWER)) mt7915_tm_set_tx_power(phy); } static int mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state) { struct mt76_testmode_data *td = &mphy->test; struct mt7915_phy *phy = mphy->priv; enum mt76_testmode_state prev_state = td->state; mphy->test.state = state; if (prev_state == MT76_TM_STATE_TX_FRAMES || state == MT76_TM_STATE_TX_FRAMES) mt7915_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES); else if (prev_state == MT76_TM_STATE_RX_FRAMES || state == MT76_TM_STATE_RX_FRAMES) mt7915_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES); else if (prev_state == MT76_TM_STATE_TX_CONT || state == MT76_TM_STATE_TX_CONT) mt7915_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT); else if (prev_state == MT76_TM_STATE_OFF || state == MT76_TM_STATE_OFF) mt7915_tm_init(phy, !(state == MT76_TM_STATE_OFF)); if ((state == MT76_TM_STATE_IDLE && prev_state == MT76_TM_STATE_OFF) || (state == MT76_TM_STATE_OFF && prev_state == MT76_TM_STATE_IDLE)) { u32 changed = 0; int i; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { u16 cur = tm_change_map[i]; if (td->param_set[cur / 32] & BIT(cur % 32)) changed |= BIT(i); } mt7915_tm_update_params(phy, changed); } return 0; } static int mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, enum mt76_testmode_state new_state) { struct mt76_testmode_data *td = &mphy->test; struct mt7915_phy *phy = mphy->priv; struct mt7915_dev *dev = phy->dev; u32 chainmask = mphy->chainmask, changed = 0; bool ext_phy = phy != &dev->phy; int i; BUILD_BUG_ON(NUM_TM_CHANGED >= 32); if (new_state == MT76_TM_STATE_OFF || td->state == MT76_TM_STATE_OFF) return 0; chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask; if (td->tx_antenna_mask > chainmask) return -EINVAL; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { if (tb[tm_change_map[i]]) changed |= BIT(i); } mt7915_tm_update_params(phy, changed); return 0; } static int mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) { struct mt7915_phy *phy = mphy->priv; struct mt7915_dev *dev = phy->dev; enum mt76_rxq_id q; void *rx, *rssi; u16 fcs_err; int i; u32 cnt; rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); if (!rx) return -ENOMEM; if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset)) return -ENOMEM; rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) if (nla_put_u8(msg, i, phy->test.last_rcpi[i])) return -ENOMEM; nla_nest_end(msg, rssi); rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++) if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI); if (!rssi) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++) if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i])) return -ENOMEM; nla_nest_end(msg, rssi); if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr)) return -ENOMEM; nla_nest_end(msg, rx); cnt = mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); fcs_err = is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); q = phy->mt76->band_idx ? MT_RXQ_BAND1 : MT_RXQ_MAIN; mphy->test.rx_stats.packets[q] += fcs_err; mphy->test.rx_stats.fcs_error[q] += fcs_err; return 0; } const struct mt76_testmode_ops mt7915_testmode_ops = { .set_state = mt7915_tm_set_state, .set_params = mt7915_tm_set_params, .dump_stats = mt7915_tm_dump_stats, }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/init.c b/sys/contrib/dev/mediatek/mt76/mt7921/init.c index bb2e1eb8d684..2498f6d30f4f 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/init.c @@ -1,274 +1,362 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include #include "mt7921.h" #include "../mt76_connac2_mac.h" #include "mcu.h" #if defined(__linux__) static ssize_t mt7921_thermal_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { switch (to_sensor_dev_attr(attr)->index) { case 0: { struct mt792x_phy *phy = dev_get_drvdata(dev); struct mt792x_dev *mdev = phy->dev; int temperature; mt792x_mutex_acquire(mdev); temperature = mt7921_mcu_get_temperature(phy); mt792x_mutex_release(mdev); if (temperature < 0) return temperature; /* display in millidegree Celsius */ return sprintf(buf, "%u\n", temperature * 1000); } default: return -EINVAL; } } static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7921_thermal_temp, 0); static struct attribute *mt7921_hwmon_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, NULL, }; ATTRIBUTE_GROUPS(mt7921_hwmon); static int mt7921_thermal_init(struct mt792x_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; struct device *hwmon; const char *name; if (!IS_REACHABLE(CONFIG_HWMON)) return 0; name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7921_%s", wiphy_name(wiphy)); + if (!name) + return -ENOMEM; hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, mt7921_hwmon_groups); - if (IS_ERR(hwmon)) - return PTR_ERR(hwmon); - - return 0; + return PTR_ERR_OR_ZERO(hwmon); } #endif +static void +mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) +{ +#define IS_UNII_INVALID(idx, sfreq, efreq) \ + (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq)) + struct ieee80211_supported_band *sband; + struct mt76_dev *mdev = &dev->mt76; + struct device_node *np, *band_np; + struct ieee80211_channel *ch; + int i, cfreq; + + np = mt76_find_power_limits_node(mdev); + + sband = wiphy->bands[NL80211_BAND_5GHZ]; +#if defined(CONFIG_OF) + band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL; +#else + band_np = NULL; +#endif + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + cfreq = ch->center_freq; + + if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + ch->flags |= IEEE80211_CHAN_DISABLED; + continue; + } + + /* UNII-4 */ + if (IS_UNII_INVALID(0, 5845, 5925)) + ch->flags |= IEEE80211_CHAN_DISABLED; + } + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + +#if defined(CONFIG_OF) + band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL; +#else + band_np = NULL; +#endif + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + cfreq = ch->center_freq; + + if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + ch->flags |= IEEE80211_CHAN_DISABLED; + continue; + } + + /* UNII-5/6/7/8 */ + if (IS_UNII_INVALID(1, 5925, 6425) || + IS_UNII_INVALID(2, 6425, 6525) || + IS_UNII_INVALID(3, 6525, 6875) || + IS_UNII_INVALID(4, 6875, 7125)) + ch->flags |= IEEE80211_CHAN_DISABLED; + } +} + +void mt7921_regd_update(struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_hw *hw = mdev->hw; + struct wiphy *wiphy = hw->wiphy; + + mt7921_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env); + mt7921_regd_channel_update(wiphy, dev); + mt76_connac_mcu_set_channel_domain(hw->priv); + mt7921_set_tx_sar_pwr(hw, NULL); +} +EXPORT_SYMBOL_GPL(mt7921_regd_update); + static void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_connac_pm *pm = &dev->pm; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; dev->country_ie_env = request->country_ie_env; + if (request->initiator == NL80211_REGDOM_SET_BY_USER) { + if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0') + wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; + else + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + } + + if (pm->suspended) + return; + + dev->regd_in_progress = true; + mt792x_mutex_acquire(dev); - mt7921_mcu_set_clc(dev, request->alpha2, request->country_ie_env); - mt76_connac_mcu_set_channel_domain(hw->priv); - mt7921_set_tx_sar_pwr(hw, NULL); + mt7921_regd_update(dev); mt792x_mutex_release(dev); + + dev->regd_in_progress = false; + wake_up(&dev->wait); } int mt7921_mac_init(struct mt792x_dev *dev) { int i; mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); /* enable hardware de-agg */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); /* enable hardware rx header translation */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); for (i = 0; i < MT792x_WTBL_SIZE; i++) mt7921_mac_wtbl_update(dev, i, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); for (i = 0; i < 2; i++) mt792x_mac_init_band(dev, i); return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); } EXPORT_SYMBOL_GPL(mt7921_mac_init); static int __mt7921_init_hardware(struct mt792x_dev *dev) { 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 = mt792x_mcu_init(dev); if (ret) goto out; 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 mt792x_dev *dev) { int ret, i; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); for (i = 0; i < MT792x_MCU_INIT_RETRY_COUNT; i++) { ret = __mt7921_init_hardware(dev); if (!ret) break; mt792x_init_reset(dev); } if (i == MT792x_MCU_INIT_RETRY_COUNT) { dev_err(dev->mt76.dev, "hardware init failed\n"); return ret; } return 0; } static void mt7921_init_work(struct work_struct *work) { struct mt792x_dev *dev = container_of(work, struct mt792x_dev, init_work); int ret; ret = mt7921_init_hardware(dev); if (ret) return; mt76_set_stream_caps(&dev->mphy, true); mt7921_set_stream_he_caps(&dev->phy); + mt792x_config_mac_addr_list(dev); ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) { dev_err(dev->mt76.dev, "register device failed\n"); return; } #if !defined(__FreeBSD__) || defined(CONFIG_MT7921_DEBUGFS) ret = mt7921_init_debugfs(dev); if (ret) { dev_err(dev->mt76.dev, "register debugfs failed\n"); return; } #endif #if defined(__linux__) ret = mt7921_thermal_init(&dev->phy); if (ret) { dev_err(dev->mt76.dev, "thermal init failed\n"); return; } #endif /* we support chip reset now */ dev->hw_init_done = true; mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); } int mt7921_register_device(struct mt792x_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); int ret; dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; dev->mt76.tx_worker.fn = mt792x_tx_worker; INIT_DELAYED_WORK(&dev->pm.ps_work, mt792x_pm_power_save_work); INIT_WORK(&dev->pm.wake_work, mt792x_pm_wake_work); spin_lock_init(&dev->pm.wake.lock); mutex_init(&dev->pm.mutex); init_waitqueue_head(&dev->pm.wait); + init_waitqueue_head(&dev->wait); if (mt76_is_sdio(&dev->mt76)) init_waitqueue_head(&dev->mt76.sdio.wait); spin_lock_init(&dev->pm.txq_lock); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt792x_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work); #if IS_ENABLED(CONFIG_IPV6) INIT_WORK(&dev->ipv6_ns_work, mt7921_set_ipv6_ns_work); skb_queue_head_init(&dev->ipv6_ns_list); #endif skb_queue_head_init(&dev->phy.scan_event_list); skb_queue_head_init(&dev->coredump.msg_list); INIT_WORK(&dev->reset_work, mt7921_mac_reset_work); INIT_WORK(&dev->init_work, mt7921_init_work); INIT_WORK(&dev->phy.roc_work, mt7921_roc_work); timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0); init_waitqueue_head(&dev->phy.roc_wait); dev->pm.idle_timeout = MT792x_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; if (!mt76_is_usb(&dev->mt76)) { dev->pm.enable_user = true; dev->pm.enable = true; dev->pm.ds_enable_user = true; dev->pm.ds_enable = true; } if (!mt76_is_mmio(&dev->mt76)) hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; mt792x_init_acpi_sar(dev); ret = mt792x_init_wcid(dev); if (ret) return ret; ret = mt792x_init_wiphy(hw); if (ret) return ret; hw->wiphy->reg_notifier = mt7921_regd_notifier; dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); if (is_mt7922(&dev->mt76)) dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_SHORT_GI_160; dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; queue_work(system_wq, &dev->init_work); return 0; } EXPORT_SYMBOL_GPL(mt7921_register_device); diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/mac.c b/sys/contrib/dev/mediatek/mt76/mt7921/mac.c index b701a5f1fd1b..25010d2ea442 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/mac.c @@ -1,883 +1,881 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #if defined(__FreeBSD__) #include #endif #include "mt7921.h" #include "../dma.h" #include "../mt76_connac2_mac.h" #include "mcu.h" #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 bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); } static u32 mt7921_mac_wtbl_lmac_addr(int idx, u8 offset) { return MT_WTBL_LMAC_OFFS(idx, 0) + offset * 4; } static void mt7921_mac_sta_poll(struct mt792x_dev *dev) { static const u8 ac_to_tid[] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; struct ieee80211_sta *sta; struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; #if defined(__linux__) LIST_HEAD(sta_poll_list); #elif defined(__FreeBSD__) LINUX_LIST_HEAD(sta_poll_list); #endif struct rate_info *rate; s8 rssi[4]; int i; spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); while (true) { bool clear = false; u32 addr, val; u16 idx; u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { spin_unlock_bh(&dev->mt76.sta_poll_lock); break; } - msta = list_first_entry(&sta_poll_list, - struct mt792x_sta, wcid.poll_list); - list_del_init(&msta->wcid.poll_list); + mlink = list_first_entry(&sta_poll_list, + struct mt792x_link_sta, + wcid.poll_list); + msta = container_of(mlink, struct mt792x_sta, deflink); + list_del_init(&mlink->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - idx = msta->wcid.idx; + idx = mlink->wcid.idx; addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u32 tx_last = msta->airtime_ac[i]; - u32 rx_last = msta->airtime_ac[i + 4]; + u32 tx_last = mlink->airtime_ac[i]; + u32 rx_last = mlink->airtime_ac[i + 4]; - msta->airtime_ac[i] = mt76_rr(dev, addr); - msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + mlink->airtime_ac[i] = mt76_rr(dev, addr); + mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); - tx_time[i] = msta->airtime_ac[i] - tx_last; - rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + tx_time[i] = mlink->airtime_ac[i] - tx_last; + rx_time[i] = mlink->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; addr += 8; } if (clear) { mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); } - if (!msta->wcid.sta) + if (!mlink->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u8 q = mt76_connac_lmac_mapping(i); u32 tx_cur = tx_time[q]; u32 rx_cur = rx_time[q]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) continue; 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; + rate = &mlink->wcid.rate; addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_TXRX_CAP_RATE_OFFSET); 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 = MT_WTBL_TXRX_RATE_G2_HE + 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(MT_WTBL_TXRX_RATE_G2 + bw)) rate->flags |= RATE_INFO_FLAGS_SHORT_GI; else rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; } /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7921_mac_wtbl_lmac_addr(idx, 30); val = mt76_rr(dev, addr); rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); rssi[3] = to_rssi(GENMASK(31, 14), val); - msta->ack_signal = + mlink->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); - ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); + ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal); } } static int mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) { u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; bool hdr_trans, unicast, insert_ccmp_hdr = false; u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info; u16 hdr_gap; __le32 *rxv = NULL, *rxd = (__le32 *)skb->data; struct mt76_phy *mphy = &dev->mt76.phy; struct mt792x_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; u32 csum_status = *(u32 *)skb->cb; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink; u16 seq_ctrl = 0; __le16 fc = 0; u8 mode = 0; int i, idx; memset(status, 0, sizeof(*status)); if (rxd1 & MT_RXD1_NORMAL_BAND_IDX) return -EINVAL; if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) return -EINVAL; hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) return -EINVAL; /* ICV error or CCMP/BIP/WPI MIC error */ if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) status->flag |= RX_FLAG_ONLY_MONITOR; chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); status->wcid = mt792x_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - msta = container_of(status->wcid, struct mt792x_sta, wcid); - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mlink = container_of(status->wcid, struct mt792x_link_sta, wcid); + msta = container_of(mlink, struct mt792x_sta, deflink); + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); } mt792x_get_status_freq_info(status, chfreq); switch (status->band) { case NL80211_BAND_5GHZ: sband = &mphy->sband_5g.sband; break; case NL80211_BAND_6GHZ: sband = &mphy->sband_6g.sband; break; default: sband = &mphy->sband_2g.sband; break; } if (!sband->channels) return -EINVAL; if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask && !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; if (rxd1 & MT_RXD1_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) status->flag |= RX_FLAG_MMIC_ERROR; if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 && !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED; status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) return -EINVAL; rxd += 6; if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { u32 v0 = le32_to_cpu(rxd[0]); u32 v2 = le32_to_cpu(rxd[2]); fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0)); seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2); qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2); rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) { case MT_CIPHER_AES_CCMP: case MT_CIPHER_CCMP_CCX: case MT_CIPHER_CCMP_256: insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); fallthrough; case MT_CIPHER_TKIP: case MT_CIPHER_TKIP_NO_MIC: case MT_CIPHER_GCMP: case MT_CIPHER_GCMP_256: status->iv[0] = data[5]; status->iv[1] = data[4]; status->iv[2] = data[3]; status->iv[3] = data[2]; status->iv[4] = data[1]; status->iv[5] = data[0]; break; default: break; } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { status->timestamp = le32_to_cpu(rxd[0]); status->flag |= RX_FLAG_MACTIME_START; if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { status->flag |= RX_FLAG_AMPDU_DETAILS; /* all subframes of an A-MPDU have the same timestamp */ if (phy->rx_ampdu_ts != status->timestamp) { if (!++phy->ampdu_ref) phy->ampdu_ref++; } phy->rx_ampdu_ts = status->timestamp; status->ampdu_ref = phy->ampdu_ref; } rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } /* RXD Group 3 - P-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { u32 v0, v1; int ret; rxv = rxd; rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; v0 = le32_to_cpu(rxv[0]); v1 = le32_to_cpu(rxv[1]); if (v0 & MT_PRXV_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status, sband, rxv, &mode); if (ret < 0) return ret; if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; rxv = rxd; /* Monitor mode would use RCPI described in GROUP 5 * instead. */ v1 = le32_to_cpu(rxv[0]); rxd += 12; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } status->chains = mphy->antenna_mask; status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); status->signal = -128; for (i = 0; i < hweight8(mphy->antenna_mask); i++) { if (!(status->chains & BIT(i)) || status->chain_signal[i] >= 0) continue; status->signal = max(status->signal, status->chain_signal[i]); } } amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); status->amsdu = !!amsdu_info; if (status->amsdu) { status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; } hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { struct ieee80211_vif *vif; int err; if (!msta || !msta->vif) return -EINVAL; vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap); if (err) return err; hdr_trans = false; } else { skb_pull(skb, hdr_gap); if (!hdr_trans && status->amsdu) { memmove(skb->data + 2, skb->data, ieee80211_get_hdrlen_from_skb(skb)); skb_pull(skb, 2); } } if (!hdr_trans) { struct ieee80211_hdr *hdr; if (insert_ccmp_hdr) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); mt76_insert_ccmp_hdr(skb, key_id); } hdr = mt76_skb_get_hdr(skb); fc = hdr->frame_control; if (ieee80211_is_data_qos(fc)) { seq_ctrl = le16_to_cpu(hdr->seq_ctrl); qos_ctl = *ieee80211_get_qos_ctl(hdr); } } else { status->flag |= RX_FLAG_8023; } mt792x_mac_assoc_rssi(dev, skb); if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode); if (!status->wcid || !ieee80211_is_data_qos(fc)) return 0; status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); status->qos_ctl = qos_ctl; return 0; } void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data) { - struct mt792x_sta *msta = NULL; + struct mt792x_link_sta *mlink; struct mt76_wcid *wcid; __le32 *txs_data = data; u16 wcidx; u8 pid; if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1) return; wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); pid = le32_get_bits(txs_data[3], MT_TXS3_PID); if (pid < MT_PACKET_ID_FIRST) return; if (wcidx >= MT792x_WTBL_SIZE) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wcidx]); if (!wcid) goto out; - msta = container_of(wcid, struct mt792x_sta, wcid); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data); if (!wcid->sta) goto out; - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); out: rcu_read_unlock(); } static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len) { struct mt76_connac_tx_free *free = data; #if defined(__linux__) __le32 *tx_info = (__le32 *)(data + sizeof(*free)); #elif defined(__FreeBSD__) __le32 *tx_info = (__le32 *)((u8 *)data + sizeof(*free)); #endif struct mt76_dev *mdev = &dev->mt76; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; struct mt76_wcid *wcid = NULL; struct sk_buff *skb, *tmp; #if defined(__linux__) void *end = data + len; #elif defined(__FreeBSD__) void *end = (u8 *)data + len; #endif LIST_HEAD(free_list); 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); count = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); if (WARN_ON_ONCE((void *)&tx_info[count] > end)) return; for (i = 0; i < count; i++) { u32 msdu, info = le32_to_cpu(tx_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 mt792x_sta *msta; + struct mt792x_link_sta *mlink; 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 mt792x_sta, wcid); - spin_lock_bh(&mdev->sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &mdev->sta_poll_list); - spin_unlock_bh(&mdev->sta_poll_lock); + mlink = container_of(wcid, struct mt792x_link_sta, wcid); + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); continue; } msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info); stat = FIELD_GET(MT_TX_FREE_STATUS, info); if (wcid) { wcid->stats.tx_retries += FIELD_GET(MT_TX_FREE_COUNT, info) - 1; wcid->stats.tx_failed += !!stat; } txwi = mt76_token_release(mdev, msdu, &wake); if (!txwi) continue; mt76_connac2_txwi_free(mdev, txwi, sta, &free_list); } if (wake) mt76_set_tx_blocked(&dev->mt76, false); 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); } bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); __le32 *rxd = (__le32 *)data; __le32 *end = (__le32 *)&rxd[len / 4]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); switch (type) { case PKT_TYPE_TXRX_NOTIFY: /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ mt7921_mac_tx_free(dev, data, len); /* mmio */ return false; case PKT_TYPE_TXS: for (rxd += 2; rxd + 8 <= end; rxd += 8) mt7921_mac_add_txs(dev, rxd); return false; default: return true; } } EXPORT_SYMBOL_GPL(mt7921_rx_check); void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); __le32 *rxd = (__le32 *)skb->data; __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; u16 flag; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG); if (type == PKT_TYPE_RX_EVENT && flag == 0x1) type = PKT_TYPE_NORMAL_MCU; switch (type) { case PKT_TYPE_TXRX_NOTIFY: /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ mt7921_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; case PKT_TYPE_RX_EVENT: mt7921_mcu_rx_event(dev, skb); break; case PKT_TYPE_TXS: for (rxd += 2; rxd + 8 <= end; rxd += 8) mt7921_mac_add_txs(dev, rxd); dev_kfree_skb(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; } } EXPORT_SYMBOL_GPL(mt7921_queue_rx_skb); static void mt7921_vif_connect_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mvif->phy->dev; struct ieee80211_hw *hw = mt76_hw(dev); if (vif->type == NL80211_IFTYPE_STATION) ieee80211_disconnect(vif, true); - mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); + mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->bss_conf.mt76, + &mvif->sta.deflink.wcid, true); mt7921_mcu_set_tx(dev, vif); if (vif->type == NL80211_IFTYPE_AP) { - mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.wcid, + mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, true, NULL); mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_NONE); mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, true); } } /* system error recovery */ void mt7921_mac_reset_work(struct work_struct *work) { struct mt792x_dev *dev = container_of(work, struct mt792x_dev, reset_work); struct ieee80211_hw *hw = mt76_hw(dev); struct mt76_connac_pm *pm = &dev->pm; int i, ret; dev_dbg(dev->mt76.dev, "chip reset\n"); + set_bit(MT76_RESET, &dev->mphy.state); dev->hw_full_reset = true; ieee80211_stop_queues(hw); cancel_delayed_work_sync(&dev->mphy.mac_work); cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); for (i = 0; i < 10; i++) { mutex_lock(&dev->mt76.mutex); ret = mt792x_dev_reset(dev); mutex_unlock(&dev->mt76.mutex); if (!ret) break; } if (i == 10) dev_err(dev->mt76.dev, "chip reset failed\n"); if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) { struct cfg80211_scan_info info = { .aborted = true, }; ieee80211_scan_completed(dev->mphy.hw, &info); } dev->hw_full_reset = false; + clear_bit(MT76_RESET, &dev->mphy.state); pm->suspended = false; ieee80211_wake_queues(hw); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_vif_connect_iter, NULL); mt76_connac_power_save_sched(&dev->mt76.phy, pm); } void mt7921_coredump_work(struct work_struct *work) { struct mt792x_dev *dev; char *dump, *data; dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, coredump.work.work); if (time_is_after_jiffies(dev->coredump.last_activity + 4 * MT76_CONNAC_COREDUMP_TIMEOUT)) { queue_delayed_work(dev->mt76.wq, &dev->coredump.work, MT76_CONNAC_COREDUMP_TIMEOUT); return; } dump = vzalloc(MT76_CONNAC_COREDUMP_SZ); data = dump; while (true) { struct sk_buff *skb; spin_lock_bh(&dev->mt76.lock); skb = __skb_dequeue(&dev->coredump.msg_list); spin_unlock_bh(&dev->mt76.lock); if (!skb) break; skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { dev_kfree_skb(skb); continue; } memcpy(data, skb->data, skb->len); data += skb->len; dev_kfree_skb(skb); } if (dump) dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, GFP_KERNEL); mt792x_reset(&dev->mt76); } /* usb_sdio */ static void mt7921_usb_sdio_write_txwi(struct mt792x_dev *dev, struct mt76_wcid *wcid, enum mt76_txq_id qid, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, int pid, struct sk_buff *skb) { __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); memset(txwi, 0, MT_SDIO_TXD_SIZE); mt76_connac2_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0); skb_push(skb, MT_SDIO_TXD_SIZE); } int mt7921_usb_sdio_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 mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct sk_buff *skb = tx_info->skb; int err, pad, pktid, type; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; err = skb_cow_head(skb, MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE); if (err) return err; if (!wcid) wcid = &dev->mt76.global_wcid; if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); mt7921_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb); type = mt76_is_sdio(mdev) ? MT7921_SDIO_DATA : 0; - mt7921_skb_add_usb_sdio_hdr(dev, skb, type); + mt792x_skb_add_usb_sdio_hdr(dev, skb, type); pad = round_up(skb->len, 4) - skb->len; if (mt76_is_usb(mdev)) pad += 4; err = mt76_skb_adjust_pad(skb, pad); if (err) /* Release pktid in case of error. */ idr_remove(&wcid->pktid, pktid); return err; } EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_prepare_skb); void mt7921_usb_sdio_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 = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); wcid = rcu_dereference(mdev->wcid[idx]); sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) mt76_connac2_tx_check_aggr(sta, txwi); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); } EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_complete_skb); bool mt7921_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); mt792x_mutex_acquire(dev); mt7921_mac_sta_poll(dev); mt792x_mutex_release(dev); return false; } EXPORT_SYMBOL_GPL(mt7921_usb_sdio_tx_status_data); #if IS_ENABLED(CONFIG_IPV6) void mt7921_set_ipv6_ns_work(struct work_struct *work) { struct mt792x_dev *dev = container_of(work, struct mt792x_dev, ipv6_ns_work); struct sk_buff *skb; int ret = 0; do { skb = skb_dequeue(&dev->ipv6_ns_list); if (!skb) break; mt792x_mutex_acquire(dev); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(OFFLOAD), true); mt792x_mutex_release(dev); } while (!ret); if (ret) skb_queue_purge(&dev->ipv6_ns_list); } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/main.c b/sys/contrib/dev/mediatek/mt76/mt7921/main.c index 0844d28b3223..13e58c328aff 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/main.c @@ -1,1378 +1,1580 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include #include #include #include "mt7921.h" #include "mcu.h" static int mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data) { int i, idx = 0; int nss = hweight8(phy->mt76->chainmask); u16 mcs_map = 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)); } for (i = 0; i < NUM_NL80211_IFTYPES; i++) { struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp; switch (i) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: break; default: continue; } data[idx].types_mask = BIT(i); he_cap->has_he = true; he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; else he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; switch (i) { case NL80211_IFTYPE_AP: he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_BQR; he_cap_elem->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; he_cap_elem->phy_cap_info[3] |= 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] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; else he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; he_cap_elem->phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; he_cap_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; he_cap_elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; he_cap_elem->phy_cap_info[5] |= IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; he_cap_elem->phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; he_cap_elem->phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; if (is_mt7922(phy->mt76->dev)) { he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; } break; } he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map); if (is_mt7922(phy->mt76->dev)) { he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map); he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map); } memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { - mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss); + mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss, band); } else { he_cap_elem->phy_cap_info[9] |= u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); } 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[idx].he_6ghz_capa.capa = cpu_to_le16(cap); } idx++; } return idx; } void mt7921_set_stream_he_caps(struct mt792x_phy *phy) { struct ieee80211_sband_iftype_data *data; struct ieee80211_supported_band *band; int n; if (phy->mt76->cap.has_2ghz) { data = phy->iftype[NL80211_BAND_2GHZ]; n = mt7921_init_he_caps(phy, NL80211_BAND_2GHZ, data); band = &phy->mt76->sband_2g.sband; - band->iftype_data = data; - band->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(band, data, n); } if (phy->mt76->cap.has_5ghz) { data = phy->iftype[NL80211_BAND_5GHZ]; n = mt7921_init_he_caps(phy, NL80211_BAND_5GHZ, data); band = &phy->mt76->sband_5g.sband; - band->iftype_data = data; - band->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(band, 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; + _ieee80211_set_sband_iftype_data(band, data, n); } } } int __mt7921_start(struct mt792x_phy *phy) { struct mt76_phy *mphy = phy->mt76; int err; err = mt76_connac_mcu_set_mac_enable(mphy->dev, 0, true, false); if (err) return err; err = mt76_connac_mcu_set_channel_domain(mphy); if (err) return err; err = mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); if (err) return err; err = mt7921_set_tx_sar_pwr(mphy->hw, NULL); if (err) return err; mt792x_mac_reset_counters(phy); set_bit(MT76_STATE_RUNNING, &mphy->state); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT792x_WATCHDOG_TIME); + if (mt76_is_mmio(mphy->dev)) { + err = mt7921_mcu_radio_led_ctrl(phy->dev, EXT_CMD_RADIO_LED_CTRL_ENABLE); + if (err) + return err; + + err = mt7921_mcu_radio_led_ctrl(phy->dev, EXT_CMD_RADIO_ON_LED); + if (err) + return err; + } + + if (phy->chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) { + mt7921_mcu_wf_rf_pin_ctrl(phy, WF_RF_PIN_INIT); + wiphy_rfkill_start_polling(mphy->hw->wiphy); + } return 0; } EXPORT_SYMBOL_GPL(__mt7921_start); static int mt7921_start(struct ieee80211_hw *hw) { struct mt792x_phy *phy = mt792x_hw_phy(hw); int err; mt792x_mutex_acquire(phy->dev); err = __mt7921_start(phy); mt792x_mutex_release(phy->dev); return err; } -void mt7921_stop(struct ieee80211_hw *hw) +static void mt7921_stop(struct ieee80211_hw *hw, bool suspend) { struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt792x_phy *phy = mt792x_hw_phy(hw); - - cancel_delayed_work_sync(&phy->mt76->mac_work); + int err = 0; - cancel_delayed_work_sync(&dev->pm.ps_work); - cancel_work_sync(&dev->pm.wake_work); - cancel_work_sync(&dev->reset_work); - mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + if (mt76_is_mmio(&dev->mt76)) { + mt792x_mutex_acquire(dev); + err = mt7921_mcu_radio_led_ctrl(dev, EXT_CMD_RADIO_OFF_LED); + mt792x_mutex_release(dev); + if (err) + return; + } - mt792x_mutex_acquire(dev); - clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); - mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); - mt792x_mutex_release(dev); + mt792x_stop(hw, false); } -EXPORT_SYMBOL_GPL(mt7921_stop); static int mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt76_txq *mtxq; int idx, ret = 0; mt792x_mutex_acquire(dev); - mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mvif->mt76.idx >= MT792x_MAX_INTERFACES) { + mvif->bss_conf.mt76.idx = __ffs64(~dev->mt76.vif_mask); + if (mvif->bss_conf.mt76.idx >= MT792x_MAX_INTERFACES) { ret = -ENOSPC; goto out; } - mvif->mt76.omac_idx = mvif->mt76.idx; + mvif->bss_conf.mt76.omac_idx = mvif->bss_conf.mt76.idx; mvif->phy = phy; - mvif->mt76.band_idx = 0; - mvif->mt76.wmm_idx = mvif->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + mvif->bss_conf.vif = mvif; + mvif->bss_conf.mt76.band_idx = 0; + mvif->bss_conf.mt76.wmm_idx = mvif->bss_conf.mt76.idx % MT76_CONNAC_MAX_WMM_SETS; - ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, - true); + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, &vif->bss_conf, + &mvif->bss_conf.mt76, + &mvif->sta.deflink.wcid, true); if (ret) goto out; - dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); - phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + dev->mt76.vif_mask |= BIT_ULL(mvif->bss_conf.mt76.idx); + phy->omac_mask |= BIT_ULL(mvif->bss_conf.mt76.omac_idx); - idx = MT792x_WTBL_RESERVED - mvif->mt76.idx; + idx = MT792x_WTBL_RESERVED - mvif->bss_conf.mt76.idx; - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); - mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = 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); + INIT_LIST_HEAD(&mvif->sta.deflink.wcid.poll_list); + mvif->sta.deflink.wcid.idx = idx; + mvif->sta.deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&mvif->sta.deflink.wcid, mvif->bss_conf.mt76.band_idx); mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.deflink.wcid); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; } vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + INIT_WORK(&mvif->csa_work, mt7921_csa_work); + timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0); out: mt792x_mutex_release(dev); return ret; } static void mt7921_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = priv; mt7921_mcu_abort_roc(phy, mvif, phy->roc_token_id); } +void mt7921_roc_abort_sync(struct mt792x_dev *dev) +{ + struct mt792x_phy *phy = &dev->phy; + + del_timer_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + ieee80211_iterate_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_roc_iter, (void *)phy); +} +EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); + void mt7921_roc_work(struct work_struct *work) { struct mt792x_phy *phy; phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, roc_work); if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) return; mt792x_mutex_acquire(phy->dev); ieee80211_iterate_active_interfaces(phy->mt76->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_roc_iter, phy); mt792x_mutex_release(phy->dev); ieee80211_remain_on_channel_expired(phy->mt76->hw); } static int mt7921_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif) { int err = 0; del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); mt792x_mutex_acquire(phy->dev); if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id); mt792x_mutex_release(phy->dev); return err; } static int mt7921_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, struct ieee80211_channel *chan, int duration, enum mt7921_roc_req type) { int err; if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) return -EBUSY; phy->roc_grant = false; err = mt7921_mcu_set_roc(phy, vif, chan, duration, type, ++phy->roc_token_id); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); goto out; } if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) { mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id); clear_bit(MT76_STATE_ROC, &phy->mt76->state); err = -ETIMEDOUT; } out: return err; } static int mt7921_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration, enum ieee80211_roc_type type) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); int err; mt792x_mutex_acquire(phy->dev); err = mt7921_set_roc(phy, mvif, chan, duration, MT7921_ROC_REQ_ROC); mt792x_mutex_release(phy->dev); return err; } static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); return mt7921_abort_roc(phy, mvif); } -static int mt7921_set_channel(struct mt792x_phy *phy) +int mt7921_set_channel(struct mt76_phy *mphy) { + struct mt792x_phy *phy = mphy->priv; struct mt792x_dev *dev = phy->dev; int ret; - cancel_delayed_work_sync(&phy->mt76->mac_work); - - mt792x_mutex_acquire(dev); - set_bit(MT76_RESET, &phy->mt76->state); - - mt76_set_channel(phy->mt76); - + mt76_connac_pm_wake(mphy, &dev->pm); ret = mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH)); if (ret) goto out; mt792x_mac_set_timeing(phy); - mt792x_mac_reset_counters(phy); phy->noise = 0; out: - clear_bit(MT76_RESET, &phy->mt76->state); - mt792x_mutex_release(dev); + mt76_connac_power_save_sched(mphy, &dev->pm); - mt76_worker_schedule(&dev->mt76.tx_worker); - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work, + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT792x_WATCHDOG_TIME); return ret; } +EXPORT_SYMBOL_GPL(mt7921_set_channel); static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - struct mt76_wcid *wcid = &msta->wcid; + struct mt76_wcid *wcid = &msta->deflink.wcid; u8 *wcid_keyidx = &wcid->hw_key_idx; int idx = key->keyidx, err = 0; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { case WLAN_CIPHER_SUITE_AES_CMAC: key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; wcid_keyidx = &wcid->hw_key_idx2; break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: if (!mvif->wep_sta) return -EOPNOTSUPP; break; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; default: return -EOPNOTSUPP; } mt792x_mutex_acquire(dev); if (cmd == SET_KEY) { *wcid_keyidx = idx; } else { if (idx == *wcid_keyidx) *wcid_keyidx = -1; - goto out; + + /* For security issue we don't trigger the key deletion when + * reassociating. But we should trigger the deletion process + * to avoid using incorrect cipher after disconnection, + */ + if (vif->type != NL80211_IFTYPE_STATION || vif->cfg.assoc) + goto out; } mt76_wcid_key_setup(&dev->mt76, wcid, key); - err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, + err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->deflink.bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); + &msta->deflink.wcid, cmd); if (err) goto out; if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || key->cipher == WLAN_CIPHER_SUITE_WEP40) err = mt76_connac_mcu_add_key(&dev->mt76, vif, - &mvif->wep_sta->bip, + &mvif->wep_sta->deflink.bip, key, MCU_UNI_CMD(STA_REC_UPDATE), - &mvif->wep_sta->wcid, cmd); + &mvif->wep_sta->deflink.wcid, cmd); out: mt792x_mutex_release(dev); return err; } static void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt792x_dev *dev = priv; struct ieee80211_hw *hw = mt76_hw(dev); bool pm_enable = dev->pm.enable; int err; err = mt7921_mcu_set_beacon_filter(dev, vif, pm_enable); if (err < 0) return; if (pm_enable) { vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; ieee80211_hw_set(hw, CONNECTION_MONITOR); } else { vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); } } static void mt7921_sniffer_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct mt792x_dev *dev = priv; struct ieee80211_hw *hw = mt76_hw(dev); struct mt76_connac_pm *pm = &dev->pm; bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); mt7921_mcu_set_sniffer(dev, vif, monitor); pm->enable = pm->enable_user && !monitor; pm->ds_enable = pm->ds_enable_user && !monitor; mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); if (monitor) mt7921_mcu_set_beacon_filter(dev, vif, false); } void mt7921_set_runtime_pm(struct mt792x_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct mt76_connac_pm *pm = &dev->pm; bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); pm->enable = pm->enable_user && !monitor; ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_pm_interface_iter, dev); pm->ds_enable = pm->ds_enable_user && !monitor; mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); } static int mt7921_config(struct ieee80211_hw *hw, u32 changed) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); int ret = 0; if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - ret = mt7921_set_channel(phy); + ret = mt76_update_channel(phy->mt76); if (ret) return ret; - ieee80211_wake_queues(hw); } mt792x_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_POWER) { ret = mt7921_set_tx_sar_pwr(hw, NULL); if (ret) goto out; } if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_sniffer_interface_iter, dev); } out: mt792x_mutex_release(dev); return ret; } static void mt7921_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { #define MT7921_FILTER_FCSFAIL BIT(2) #define MT7921_FILTER_CONTROL BIT(5) #define MT7921_FILTER_OTHER_BSS BIT(6) #define MT7921_FILTER_ENABLE BIT(31) struct mt792x_dev *dev = mt792x_hw_dev(hw); u32 flags = MT7921_FILTER_ENABLE; #define MT7921_FILTER(_fif, _type) do { \ if (*total_flags & (_fif)) \ flags |= MT7921_FILTER_##_type; \ } while (0) MT7921_FILTER(FIF_FCSFAIL, FCSFAIL); MT7921_FILTER(FIF_CONTROL, CONTROL); MT7921_FILTER(FIF_OTHER_BSS, OTHER_BSS); mt792x_mutex_acquire(dev); mt7921_mcu_set_rxfilter(dev, flags, 0, 0); mt792x_mutex_release(dev); *total_flags &= (FIF_OTHER_BSS | FIF_FCSFAIL | FIF_CONTROL); } static void mt7921_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; if (slottime != phy->slottime) { phy->slottime = slottime; mt792x_mac_set_timeing(phy); } } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, info->enable_beacon); /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) mt7921_mcu_set_tx(dev, vif); if (changed & BSS_CHANGED_PS) mt7921_mcu_uni_bss_ps(dev, vif); + if (changed & BSS_CHANGED_CQM) + mt7921_mcu_set_rssimonitor(dev, vif); + if (changed & BSS_CHANGED_ASSOC) { mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); mt7921_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); } if (changed & BSS_CHANGED_ARP_FILTER) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76, + mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->bss_conf.mt76, info); } mt792x_mutex_release(dev); } +static void +mt7921_calc_vif_num(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + u32 *num = priv; + + if (!priv) + return; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + *num += 1; + break; + default: + break; + } +} + +static void +mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = mvif->phy; + struct mt792x_dev *dev = phy->dev; + u32 valid_vif_num = 0; + + ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_calc_vif_num, &valid_vif_num); + + if (valid_vif_num > 1) { + phy->power_type = MT_AP_DEFAULT; + goto out; + } + + if (!is_add) + vif->bss_conf.power_type = IEEE80211_REG_UNSET_AP; + + switch (vif->bss_conf.power_type) { + case IEEE80211_REG_SP_AP: + phy->power_type = MT_AP_SP; + break; + case IEEE80211_REG_VLP_AP: + phy->power_type = MT_AP_VLP; + break; + case IEEE80211_REG_LPI_AP: + phy->power_type = MT_AP_LPI; + break; + case IEEE80211_REG_UNSET_AP: + phy->power_type = MT_AP_UNSET; + break; + default: + phy->power_type = MT_AP_DEFAULT; + break; + } + +out: + mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); +} + int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; int ret, idx; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx < 0) return -ENOSPC; - INIT_LIST_HEAD(&msta->wcid.poll_list); + INIT_LIST_HEAD(&msta->deflink.wcid.poll_list); msta->vif = mvif; - msta->wcid.sta = 1; - msta->wcid.idx = idx; - msta->wcid.phy_idx = mvif->mt76.band_idx; - msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->last_txs = jiffies; + msta->deflink.wcid.sta = 1; + msta->deflink.wcid.idx = idx; + msta->deflink.wcid.phy_idx = mvif->bss_conf.mt76.band_idx; + msta->deflink.wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->deflink.last_txs = jiffies; ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) return ret; if (vif->type == NL80211_IFTYPE_STATION) mvif->wep_sta = msta; mt7921_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); ret = mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_NONE); if (ret) return ret; + mt7921_regd_set_6ghz_power_type(vif, true); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); 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) +int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + if (ev != MT76_STA_EVENT_ASSOC) + return 0; + mt792x_mutex_acquire(dev); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid, - true, mvif->ctx); + mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.deflink.wcid, + true, mvif->bss_conf.mt76.ctx); - ewma_avg_signal_init(&msta->avg_ack_signal); + ewma_avg_signal_init(&msta->deflink.avg_ack_signal); - mt7921_mac_wtbl_update(dev, msta->wcid.idx, + mt7921_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + memset(msta->deflink.airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); mt7921_mcu_sta_update(dev, sta, vif, true, MT76_STA_INFO_STATE_ASSOC); mt792x_mutex_release(dev); + + return 0; } -EXPORT_SYMBOL_GPL(mt7921_mac_sta_assoc); +EXPORT_SYMBOL_GPL(mt7921_mac_sta_event); void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid); + mt7921_roc_abort_sync(dev); + mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); mt7921_mcu_sta_update(dev, sta, vif, false, MT76_STA_INFO_STATE_NONE); - mt7921_mac_wtbl_update(dev, msta->wcid.idx, + mt7921_mac_wtbl_update(dev, msta->deflink.wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->type == NL80211_IFTYPE_STATION) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; - ewma_rssi_init(&mvif->rssi); + ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, - &mvif->sta.wcid, false, - mvif->ctx); + &mvif->sta.deflink.wcid, false, + mvif->bss_conf.mt76.ctx); } spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta->wcid.poll_list)) - list_del_init(&msta->wcid.poll_list); + if (!list_empty(&msta->deflink.wcid.poll_list)) + list_del_init(&msta->deflink.wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt7921_regd_set_6ghz_power_type(vif, false); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, 0); mt792x_mutex_release(dev); return 0; } static int mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct mt792x_dev *dev = mt792x_hw_dev(hw); struct ieee80211_sta *sta = params->sta; struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mt792x_mutex_acquire(dev); switch (action) { case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, params->buf_size); mt7921_mcu_uni_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); mt7921_mcu_uni_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; mt7921_mcu_uni_tx_ba(dev, params, true); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7921_mcu_uni_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: - set_bit(tid, &msta->wcid.ampdu_state); + set_bit(tid, &msta->deflink.wcid.ampdu_state); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; - clear_bit(tid, &msta->wcid.ampdu_state); + clear_bit(tid, &msta->deflink.wcid.ampdu_state); mt7921_mcu_uni_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mt792x_mutex_release(dev); return ret; } static int mt7921_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { struct mt792x_dev *dev = mt792x_hw_dev(hw); if (dev->pm.ds_enable) { mt792x_mutex_acquire(dev); mt76_connac_sta_state_dp(&dev->mt76, old_state, new_state); mt792x_mutex_release(dev); } return mt76_sta_state(hw, vif, sta, old_state, new_state); } void mt7921_scan_work(struct work_struct *work) { struct mt792x_phy *phy; phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, scan_work.work); while (true) { struct mt76_connac2_mcu_rxd *rxd; struct sk_buff *skb; spin_lock_bh(&phy->dev->mt76.lock); skb = __skb_dequeue(&phy->scan_event_list); spin_unlock_bh(&phy->dev->mt76.lock); if (!skb) break; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { ieee80211_sched_scan_results(phy->mt76->hw); } else if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { struct cfg80211_scan_info info = { .aborted = false, }; ieee80211_scan_completed(phy->mt76->hw, &info); } dev_kfree_skb(skb); } } static int mt7921_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; mt792x_mutex_acquire(dev); err = mt76_connac_mcu_hw_scan(mphy, vif, req); mt792x_mutex_release(dev); return err; } static void mt7921_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_phy *mphy = hw->priv; mt792x_mutex_acquire(dev); mt76_connac_mcu_cancel_hw_scan(mphy, vif); mt792x_mutex_release(dev); } static int mt7921_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; mt792x_mutex_acquire(dev); err = mt76_connac_mcu_sched_scan_req(mphy, vif, req); if (err < 0) goto out; err = mt76_connac_mcu_sched_scan_enable(mphy, vif, true); out: mt792x_mutex_release(dev); return err; } static int mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; mt792x_mutex_acquire(dev); err = mt76_connac_mcu_sched_scan_enable(mphy, vif, false); mt792x_mutex_release(dev); return err; } static int mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); int max_nss = hweight8(hw->wiphy->available_antennas_tx); if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) return -EINVAL; if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) return -EINVAL; mt792x_mutex_acquire(dev); phy->mt76->antenna_mask = tx_ant; phy->mt76->chainmask = tx_ant; mt76_set_stream_caps(phy->mt76, true); mt7921_set_stream_he_caps(phy); mt792x_mutex_release(dev); return 0; } #ifdef CONFIG_PM static int mt7921_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); cancel_delayed_work_sync(&phy->scan_work); cancel_delayed_work_sync(&phy->mt76->mac_work); cancel_delayed_work_sync(&dev->pm.ps_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt792x_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_mcu_set_suspend_iter, &dev->mphy); mt792x_mutex_release(dev); return 0; } static int mt7921_resume(struct ieee80211_hw *hw) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); mt792x_mutex_acquire(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt76_connac_mcu_set_suspend_iter, &dev->mphy); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT792x_WATCHDOG_TIME); mt792x_mutex_release(dev); return 0; } static void mt7921_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); mt76_connac_mcu_update_gtk_rekey(hw, vif, data); mt792x_mutex_release(dev); } #endif /* CONFIG_PM */ static void mt7921_sta_set_decap_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); if (enabled) - set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); else - clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->deflink.wcid.flags); - mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->wcid, + mt76_connac_mcu_sta_update_hdr_trans(&dev->mt76, vif, &msta->deflink.wcid, MCU_UNI_CMD(STA_REC_UPDATE)); mt792x_mutex_release(dev); } #if IS_ENABLED(CONFIG_IPV6) static void mt7921_ipv6_addr_change(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct inet6_dev *idev) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt792x_dev *dev = mvif->phy->dev; + struct mt792x_dev *dev = mt792x_hw_dev(hw); struct inet6_ifaddr *ifa; struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; struct sk_buff *skb; u8 i, idx = 0; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_arpns_tlv arpns; } req_hdr = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), .mode = 2, /* update */ .option = 1, /* update only */ }, }; read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa->flags & IFA_F_TENTATIVE) continue; ns_addrs[idx] = ifa->addr; if (++idx >= IEEE80211_BSS_ARP_ADDR_LIST_LEN) break; } read_unlock_bh(&idev->lock); if (!idx) return; req_hdr.arpns.ips_num = idx; req_hdr.arpns.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv) + idx * sizeof(struct in6_addr)); skb = __mt76_mcu_msg_alloc(&dev->mt76, &req_hdr, sizeof(req_hdr) + idx * sizeof(struct in6_addr), sizeof(req_hdr), GFP_ATOMIC); if (!skb) return; for (i = 0; i < idx; i++) skb_put_data(skb, &ns_addrs[i].in6_u, sizeof(struct in6_addr)); skb_queue_tail(&dev->ipv6_ns_list, skb); ieee80211_queue_work(dev->mt76.hw, &dev->ipv6_ns_work); } #endif int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt76_phy *mphy = hw->priv; if (sar) { int err = mt76_init_sar_power(hw, sar); if (err) return err; } mt792x_init_acpi_sar_power(mt792x_hw_phy(hw), !sar); return mt76_connac_mcu_set_rate_txpower(mphy); } static int mt7921_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar) { struct mt792x_dev *dev = mt792x_hw_dev(hw); int err; mt792x_mutex_acquire(dev); err = mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); if (err < 0) goto out; err = mt7921_set_tx_sar_pwr(hw, sar); out: mt792x_mutex_release(dev); return err; } static void mt7921_channel_switch_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_chan_def *chandef) { struct mt792x_dev *dev = mt792x_hw_dev(hw); mt792x_mutex_acquire(dev); mt7921_mcu_uni_add_beacon_offload(dev, hw, vif, true); mt792x_mutex_release(dev); } static int mt7921_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); int err; mt792x_mutex_acquire(dev); - err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, - true, mvif->ctx); + err = mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.deflink.wcid, + true, mvif->bss_conf.mt76.ctx); if (err) goto out; err = mt7921_mcu_set_bss_pm(dev, vif, true); if (err) goto out; err = mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_NONE); out: mt792x_mutex_release(dev); return err; } static void mt7921_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); int err; mt792x_mutex_acquire(dev); err = mt7921_mcu_set_bss_pm(dev, vif, false); if (err) goto out; - mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.wcid, false, - mvif->ctx); + mt76_connac_mcu_uni_add_bss(phy->mt76, vif, &mvif->sta.deflink.wcid, false, + mvif->bss_conf.mt76.ctx); out: mt792x_mutex_release(dev); } static int mt7921_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + dev->new_ctx = ctx; return 0; } static void mt7921_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { -} - -static void mt7921_ctx_iter(void *priv, u8 *mac, - struct ieee80211_vif *vif) -{ - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct ieee80211_chanctx_conf *ctx = priv; - - if (ctx != mvif->ctx) - return; + struct mt792x_dev *dev = mt792x_hw_dev(hw); - if (vif->type == NL80211_IFTYPE_MONITOR) - mt7921_mcu_config_sniffer(mvif, ctx); - else - mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx); + if (dev->new_ctx == ctx) + dev->new_ctx = NULL; } static void mt7921_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct ieee80211_vif *vif; + struct mt792x_vif *mvif; + + if (!mctx->bss_conf) + return; + + mvif = container_of(mctx->bss_conf, struct mt792x_vif, bss_conf); + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); mt792x_mutex_acquire(phy->dev); - ieee80211_iterate_active_interfaces(phy->mt76->hw, - IEEE80211_IFACE_ITER_ACTIVE, - mt7921_ctx_iter, ctx); + if (vif->type == NL80211_IFTYPE_MONITOR) + mt7921_mcu_config_sniffer(mvif, ctx); + else + mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); mt792x_mutex_release(phy->dev); } static void mt7921_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_prep_tx_info *info) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); u16 duration = info->duration ? info->duration : jiffies_to_msecs(HZ); mt792x_mutex_acquire(dev); - mt7921_set_roc(mvif->phy, mvif, mvif->ctx->def.chan, duration, + mt7921_set_roc(mvif->phy, mvif, mvif->bss_conf.mt76.ctx->def.chan, duration, MT7921_ROC_REQ_JOIN); mt792x_mutex_release(dev); } static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_prep_tx_info *info) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mt7921_abort_roc(mvif->phy, mvif); } +static int mt7921_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + return mt792x_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf, + vifs->new_ctx); +} + +void mt7921_csa_work(struct work_struct *work) +{ + struct mt792x_vif *mvif; + struct mt792x_dev *dev; + struct ieee80211_vif *vif; + int ret; + + mvif = (struct mt792x_vif *)container_of(work, struct mt792x_vif, + csa_work); + dev = mvif->phy->dev; + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + mt792x_mutex_acquire(dev); + ret = mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, + dev->new_ctx); + mt792x_mutex_release(dev); + + ieee80211_chswitch_done(vif, !ret, 0); +} + +static int mt7921_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) + return -EOPNOTSUPP; + + /* Avoid beacon loss due to the CAC(Channel Availability Check) time + * of the AP. + */ + if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef, + IEEE80211_CHAN_RADAR)) + return -EOPNOTSUPP; + + return 0; +} + +static void mt7921_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + u16 beacon_interval = vif->bss_conf.beacon_int; + + mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count); + add_timer(&mvif->csa_timer); +} + +static void mt7921_abort_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + del_timer_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); +} + +static void mt7921_channel_switch_rx_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + u16 beacon_interval = vif->bss_conf.beacon_int; + + if (cfg80211_chandef_identical(&chsw->chandef, + &dev->new_ctx->def) && + chsw->count) { + mod_timer(&mvif->csa_timer, + TU_TO_EXP_TIME(beacon_interval * chsw->count)); + } +} + +static void mt7921_rfkill_poll(struct ieee80211_hw *hw) +{ + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int ret = 0; + + mt792x_mutex_acquire(phy->dev); + ret = mt7921_mcu_wf_rf_pin_ctrl(phy, WF_RF_PIN_POLL); + mt792x_mutex_release(phy->dev); + + wiphy_rfkill_set_hw_state(hw->wiphy, ret ? false : true); +} + const struct ieee80211_ops mt7921_ops = { .tx = mt792x_tx, .start = mt7921_start, .stop = mt7921_stop, .add_interface = mt7921_add_interface, .remove_interface = mt792x_remove_interface, .config = mt7921_config, .conf_tx = mt792x_conf_tx, .configure_filter = mt7921_configure_filter, .bss_info_changed = mt7921_bss_info_changed, .start_ap = mt7921_start_ap, .stop_ap = mt7921_stop_ap, .sta_state = mt7921_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, .sta_set_decap_offload = mt7921_sta_set_decap_offload, #if IS_ENABLED(CONFIG_IPV6) .ipv6_addr_change = mt7921_ipv6_addr_change, #endif /* CONFIG_IPV6 */ .ampdu_action = mt7921_ampdu_action, .set_rts_threshold = mt7921_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .release_buffered_frames = mt76_release_buffered_frames, .channel_switch_beacon = mt7921_channel_switch_beacon, .get_txpower = mt76_get_txpower, .get_stats = mt792x_get_stats, .get_et_sset_count = mt792x_get_et_sset_count, .get_et_strings = mt792x_get_et_strings, .get_et_stats = mt792x_get_et_stats, .get_tsf = mt792x_get_tsf, .set_tsf = mt792x_set_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7921_set_antenna, .set_coverage_class = mt792x_set_coverage_class, .hw_scan = mt7921_hw_scan, .cancel_hw_scan = mt7921_cancel_hw_scan, .sta_statistics = mt792x_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, .set_wakeup = mt792x_set_wakeup, .set_rekey_data = mt7921_set_rekey_data, #endif /* CONFIG_PM */ .flush = mt792x_flush, .set_sar_specs = mt7921_set_sar_specs, + .rfkill_poll = mt7921_rfkill_poll, .remain_on_channel = mt7921_remain_on_channel, .cancel_remain_on_channel = mt7921_cancel_remain_on_channel, .add_chanctx = mt7921_add_chanctx, .remove_chanctx = mt7921_remove_chanctx, .change_chanctx = mt7921_change_chanctx, .assign_vif_chanctx = mt792x_assign_vif_chanctx, .unassign_vif_chanctx = mt792x_unassign_vif_chanctx, .mgd_prepare_tx = mt7921_mgd_prepare_tx, .mgd_complete_tx = mt7921_mgd_complete_tx, + .switch_vif_chanctx = mt7921_switch_vif_chanctx, + .pre_channel_switch = mt7921_pre_channel_switch, + .channel_switch = mt7921_channel_switch, + .abort_channel_switch = mt7921_abort_channel_switch, + .channel_switch_rx_beacon = mt7921_channel_switch_rx_beacon, }; EXPORT_SYMBOL_GPL(mt7921_ops); +MODULE_DESCRIPTION("MediaTek MT7921 core driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Sean Wang "); diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7921/mcu.c index a97f78d64258..4b95d7c0a225 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/mcu.c @@ -1,1251 +1,1501 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. */ #include #include #include "mt7921.h" #include "mcu.h" #include "../mt76_connac2_mac.h" #include "../mt792x_trace.h" #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) static bool mt7921_disable_clc; module_param_named(disable_clc, mt7921_disable_clc, bool, 0644); MODULE_PARM_DESC(disable_clc, "disable CLC support"); int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); struct mt76_connac2_mcu_rxd *rxd; int ret = 0; if (!skb) { dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); mt792x_reset(mdev); return -ETIMEDOUT; } rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; if (cmd == MCU_CMD(PATCH_SEM_CONTROL) || cmd == MCU_CMD(PATCH_FINISH_REQ)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { skb_pull(skb, sizeof(*rxd) + 4); ret = le32_to_cpu(*(__le32 *)skb->data); } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || cmd == MCU_UNI_CMD(STA_REC_UPDATE) || cmd == MCU_UNI_CMD(HIF_CTRL) || cmd == MCU_UNI_CMD(OFFLOAD) || cmd == MCU_UNI_CMD(SUSPEND)) { struct mt76_connac_mcu_uni_event *event; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); /* skip invalid event */ if (mcu_cmd != event->cid) ret = -EAGAIN; } else if (cmd == MCU_CE_QUERY(REG_READ)) { struct mt76_connac_mcu_reg_event *event; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_reg_event *)skb->data; ret = (int)le32_to_cpu(event->val); + } else if (cmd == MCU_EXT_CMD(WF_RF_PIN_CTRL)) { + struct mt7921_wf_rf_pin_ctrl_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7921_wf_rf_pin_ctrl_event *)skb->data; + ret = (int)event->result; } else { skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); } return ret; } EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response); static int mt7921_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val) { struct mt7921_mcu_eeprom_info *res, req = { .addr = cpu_to_le32(round_down(offset, MT7921_EEPROM_BLOCK_SIZE)), }; struct sk_buff *skb; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), &req, sizeof(req), true, &skb); if (ret) return ret; res = (struct mt7921_mcu_eeprom_info *)skb->data; *val = res->data[offset % MT7921_EEPROM_BLOCK_SIZE]; dev_kfree_skb(skb); return 0; } #ifdef CONFIG_PM static int mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev, struct ieee80211_vif *vif, bool suspend) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct mt76_connac_arpns_tlv arpns; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .arpns = { .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)), .mode = suspend, }, }; return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req), true); } void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (IS_ENABLED(CONFIG_IPV6)) { struct mt76_phy *phy = priv; mt7921_mcu_set_ipv6_ns_filter(phy->dev, vif, !test_bit(MT76_STATE_RUNNING, &phy->state)); } mt76_connac_mcu_set_suspend_iter(priv, mac, vif); } #endif /* CONFIG_PM */ static void mt7921_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt7921_roc_grant_tlv *grant; struct mt76_connac2_mcu_rxd *rxd; int duration; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4); /* should never happen */ WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT)); if (grant->reqtype == MT7921_ROC_REQ_ROC) ieee80211_ready_on_channel(dev->mt76.phy.hw); dev->phy.roc_grant = true; wake_up(&dev->phy.roc_wait); duration = le32_to_cpu(grant->max_interval); mod_timer(&dev->phy.roc_timer, jiffies + msecs_to_jiffies(duration)); } static void mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); spin_unlock_bh(&dev->mt76.lock); ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, MT792x_HW_SCAN_TIMEOUT); } static void mt7921_mcu_connection_loss_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt76_connac_beacon_loss_event *event = priv; if (mvif->idx != event->bss_idx) return; if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) || vif->type != NL80211_IFTYPE_STATION) return; ieee80211_connection_loss(vif); } static void mt7921_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_connac_beacon_loss_event *event; struct mt76_phy *mphy = &dev->mt76.phy; skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt76_connac_beacon_loss_event *)skb->data; ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_mcu_connection_loss_iter, event); } static void mt7921_mcu_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt7921_debug_msg { __le16 id; u8 type; u8 flag; __le32 value; __le16 len; u8 content[512]; } __packed * msg; skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); msg = (struct mt7921_debug_msg *)skb->data; if (msg->type == 3) { /* fw log */ u16 len = min_t(u16, le16_to_cpu(msg->len), 512); int i; for (i = 0 ; i < len; i++) { if (!msg->content[i]) msg->content[i] = ' '; } wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content); } } static void mt7921_mcu_low_power_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt7921_mcu_lp_event { u8 state; u8 reserved[3]; } __packed * event; skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt7921_mcu_lp_event *)skb->data; trace_lp_event(dev, event->state); } static void mt7921_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt7921_mcu_tx_done_event *event; skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); event = (struct mt7921_mcu_tx_done_event *)skb->data; mt7921_mac_add_txs(dev, event->txs); } +static void +mt7921_mcu_rssi_monitor_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt76_connac_rssi_notify_event *event = priv; + enum nl80211_cqm_rssi_threshold_event nl_event; + s32 rssi = le32_to_cpu(event->rssi[mvif->bss_conf.mt76.idx]); + + if (!rssi) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + return; + + if (rssi > vif->bss_conf.cqm_rssi_thold) + nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + else + nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + + ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL); +} + +static void +mt7921_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct mt76_connac_rssi_notify_event *event; + + skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd)); + event = (struct mt76_connac_rssi_notify_event *)skb->data; + + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_mcu_rssi_monitor_iter, event); +} + static void mt7921_mcu_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_BSS_BEACON_LOSS: mt7921_mcu_connection_loss_event(dev, skb); break; case MCU_EVENT_SCHED_SCAN_DONE: case MCU_EVENT_SCAN_DONE: mt7921_mcu_scan_event(dev, skb); return; case MCU_EVENT_DBG_MSG: 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; + case MCU_EVENT_RSSI_NOTIFY: + mt7921_mcu_rssi_monitor_event(dev, skb); + break; default: break; } dev_kfree_skb(skb); } static void mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_UNI_EVENT_ROC: mt7921_mcu_uni_roc_event(dev, skb); break; default: break; } dev_kfree_skb(skb); } void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; if (skb_linearize(skb)) return; rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) { mt7921_mcu_uni_rx_unsolicited_event(dev, skb); return; } if (rxd->eid == 0x6) { mt76_mcu_rx_event(&dev->mt76, skb); return; } if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT || rxd->eid == MCU_EVENT_BSS_BEACON_LOSS || rxd->eid == MCU_EVENT_SCHED_SCAN_DONE || + rxd->eid == MCU_EVENT_RSSI_NOTIFY || rxd->eid == MCU_EVENT_SCAN_DONE || rxd->eid == MCU_EVENT_TX_DONE || rxd->eid == MCU_EVENT_DBG_MSG || rxd->eid == MCU_EVENT_COREDUMP || rxd->eid == MCU_EVENT_LP_INFO || !rxd->seq) mt7921_mcu_rx_unsolicited_event(dev, skb); else mt76_mcu_rx_event(&dev->mt76, skb); } /** starec & wtbl **/ int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; if (enable && !params->amsdu) - msta->wcid.amsdu = false; + msta->deflink.wcid.amsdu = false; - return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), enable, true); } int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; - return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params, + return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->bss_conf.mt76, params, MCU_UNI_CMD(STA_REC_UPDATE), enable, false); } static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) { const struct mt76_connac2_fw_trailer *hdr; const struct mt76_connac2_fw_region *region; const struct mt7921_clc *clc; struct mt76_dev *mdev = &dev->mt76; struct mt792x_phy *phy = &dev->phy; const struct firmware *fw; int ret, i, len, offset = 0; #if defined(__linux__) u8 *clc_base = NULL, hw_encap = 0; #elif defined(__FreeBSD__) const u8 *clc_base = NULL; u8 hw_encap = 0; #endif + dev->phy.clc_chan_conf = 0xff; if (mt7921_disable_clc || mt76_is_usb(&dev->mt76)) return 0; if (mt76_is_mmio(&dev->mt76)) { ret = mt7921_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap); if (ret) return ret; hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP); } ret = request_firmware(&fw, fw_name, mdev->dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(mdev->dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); for (i = 0; i < hdr->n_region; i++) { region = (const void *)((const u8 *)hdr - (hdr->n_region - i) * sizeof(*region)); len = le32_to_cpu(region->len); /* check if we have valid buffer size */ if (offset + len > fw->size) { dev_err(mdev->dev, "Invalid firmware region\n"); ret = -EINVAL; goto out; } if ((region->feature_set & FW_FEATURE_NON_DL) && region->type == FW_TYPE_CLC) { #if defined(__linux__) clc_base = (u8 *)(fw->data + offset); #elif defined(__FreeBSD__) clc_base = (const u8 *)(fw->data + offset); #endif break; } offset += len; } if (!clc_base) goto out; for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { clc = (const struct mt7921_clc *)(clc_base + offset); /* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx]) continue; /* header content sanity */ if (clc->idx == MT7921_CLC_POWER && u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap) continue; phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc, le32_to_cpu(clc->len), GFP_KERNEL); if (!phy->clc[clc->idx]) { ret = -ENOMEM; goto out; } } ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR); out: release_firmware(fw); return ret; } +static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev, + struct sk_buff *skb) +{ + struct mt76_sdio *sdio = &dev->sdio; + struct mt7921_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 mt7921_tx_resource *)skb->data; + sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota); + sdio->pse_mcu_quota_max = le32_to_cpu(tx_res->pse_mcu_quota); + /* The mcu quota usage of this function itself must be taken into consideration */ + sdio->sched.pse_mcu_quota = + sdio->sched.pse_mcu_quota ? sdio->pse_mcu_quota_max : sdio->pse_mcu_quota_max - 1; + 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 mt7921_mcu_parse_phy_cap(struct mt76_dev *dev, + struct sk_buff *skb) +{ + struct mt7921_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 mt7921_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); +} + +static int mt7921_mcu_get_nic_capability(struct mt792x_phy *mphy) +{ + struct mt76_connac_cap_hdr { + __le16 n_element; + u8 rsv[2]; + } __packed * hdr; + struct sk_buff *skb; + struct mt76_phy *phy = mphy->mt76; + int ret, i; + + ret = mt76_mcu_send_and_get_msg(phy->dev, MCU_CE_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; + case MT_NIC_CAP_MAC_ADDR: + memcpy(phy->macaddr, (void *)skb->data, ETH_ALEN); + break; + case MT_NIC_CAP_PHY: + mt7921_mcu_parse_phy_cap(phy->dev, skb); + break; + case MT_NIC_CAP_TX_RESOURCE: + if (mt76_is_sdio(phy->dev)) + mt7921_mcu_parse_tx_resource(phy->dev, + skb); + break; + case MT_NIC_CAP_CHIP_CAP: + memcpy(&mphy->chip_cap, (void *)skb->data, sizeof(u64)); + break; + default: + break; + } + skb_pull(skb, len); + } +out: + dev_kfree_skb(skb); + + return ret; +} + int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl) { struct { u8 ctrl_val; u8 pad[3]; } data = { .ctrl_val = ctrl }; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST), &data, sizeof(data), false); } int mt7921_run_firmware(struct mt792x_dev *dev) { int err; err = mt792x_load_firmware(dev); if (err) return err; - err = mt76_connac_mcu_get_nic_capability(&dev->mphy); + err = mt7921_mcu_get_nic_capability(&dev->phy); if (err) return err; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); err = mt7921_load_clc(dev, mt792x_ram_name(dev)); if (err) return err; return mt7921_mcu_fw_log_2_host(dev, 1); } EXPORT_SYMBOL_GPL(mt7921_run_firmware); +int mt7921_mcu_radio_led_ctrl(struct mt792x_dev *dev, u8 value) +{ + struct { + u8 ctrlid; + u8 rsv[3]; + } __packed req = { + .ctrlid = value, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ID_RADIO_ON_OFF_CTRL), + &req, sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt7921_mcu_radio_led_ctrl); + int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct edca { __le16 cw_min; __le16 cw_max; __le16 txop; __le16 aifs; u8 guardtime; u8 acm; } __packed; struct mt7921_mcu_tx { struct edca edca[IEEE80211_NUM_ACS]; u8 bss_idx; u8 qos; u8 wmm_idx; u8 pad; } __packed req = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, .qos = vif->bss_conf.qos, - .wmm_idx = mvif->mt76.wmm_idx, + .wmm_idx = mvif->bss_conf.mt76.wmm_idx, }; 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, + .bss_idx = mvif->bss_conf.mt76.idx, .qos = vif->bss_conf.qos, - .wmm_idx = mvif->mt76.wmm_idx, + .wmm_idx = mvif->bss_conf.mt76.wmm_idx, }; static const int to_aci[] = { 1, 0, 2, 3 }; int ac, ret; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct ieee80211_tx_queue_params *q = &mvif->bss_conf.queue_params[ac]; struct edca *e = &req.edca[to_aci[ac]]; e->aifs = cpu_to_le16(q->aifs); e->txop = cpu_to_le16(q->txop); if (q->cw_min) e->cw_min = cpu_to_le16(q->cw_min); else e->cw_min = cpu_to_le16(5); if (q->cw_max) e->cw_max = cpu_to_le16(q->cw_max); else e->cw_max = cpu_to_le16(10); } ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req, sizeof(req), false); 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; - if (!mvif->queue_params[ac].mu_edca) + if (!mvif->bss_conf.queue_params[ac].mu_edca) break; - q = &mvif->queue_params[ac].mu_edca_param_rec; + q = &mvif->bss_conf.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_CE_CMD(SET_MU_EDCA_PARMS), &req_mu, sizeof(req_mu), false); } int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, struct ieee80211_channel *chan, int duration, enum mt7921_roc_req type, u8 token_id) { int center_ch = ieee80211_frequency_to_channel(chan->center_freq); struct mt792x_dev *dev = phy->dev; struct { struct { u8 rsv[4]; } __packed hdr; struct roc_acquire_tlv { __le16 tag; __le16 len; u8 bss_idx; u8 tokenid; u8 control_channel; u8 sco; u8 band; u8 bw; u8 center_chan; u8 center_chan2; u8 bw_from_ap; u8 center_chan_from_ap; u8 center_chan2_from_ap; u8 reqtype; __le32 maxinterval; u8 dbdcband; u8 rsv[3]; } __packed roc; } __packed req = { .roc = { .tag = cpu_to_le16(UNI_ROC_ACQUIRE), .len = cpu_to_le16(sizeof(struct roc_acquire_tlv)), .tokenid = token_id, .reqtype = type, .maxinterval = cpu_to_le32(duration), - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .control_channel = chan->hw_value, .bw = CMD_CBW_20MHZ, .bw_from_ap = CMD_CBW_20MHZ, .center_chan = center_ch, .center_chan_from_ap = center_ch, .dbdcband = 0xff, /* auto */ }, }; if (chan->hw_value < center_ch) req.roc.sco = 1; /* SCA */ else if (chan->hw_value > center_ch) req.roc.sco = 3; /* SCB */ switch (chan->band) { case NL80211_BAND_6GHZ: req.roc.band = 3; break; case NL80211_BAND_5GHZ: req.roc.band = 2; break; default: req.roc.band = 1; break; } return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), &req, sizeof(req), false); } int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, u8 token_id) { struct mt792x_dev *dev = phy->dev; struct { struct { u8 rsv[4]; } __packed hdr; struct roc_abort_tlv { __le16 tag; __le16 len; u8 bss_idx; u8 tokenid; u8 dbdcband; u8 rsv[5]; } __packed abort; } __packed req = { .abort = { .tag = cpu_to_le16(UNI_ROC_ABORT), .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), .tokenid = token_id, - .bss_idx = vif->mt76.idx, + .bss_idx = vif->bss_conf.mt76.idx, .dbdcband = 0xff, /* auto*/ }, }; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), &req, sizeof(req), false); } int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd) { struct mt792x_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; struct { u8 control_ch; u8 center_ch; u8 bw; u8 tx_streams_num; u8 rx_streams; /* mask or num */ u8 switch_reason; u8 band_idx; u8 center_ch2; /* for 80+80 only */ __le16 cac_case; u8 channel_band; u8 rsv0; __le32 outband_freq; u8 txpower_drop; u8 ap_bw; u8 ap_center_ch; u8 rsv1[57]; } __packed req = { .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_streams_num = hweight8(phy->mt76->antenna_mask), .rx_streams = phy->mt76->antenna_mask, .band_idx = phy != &dev->phy, }; if (chandef->chan->band == NL80211_BAND_6GHZ) req.channel_band = 2; else req.channel_band = chandef->chan->band; if (cmd == MCU_EXT_CMD(SET_RX_PATH) || dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; - else if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + else if (phy->mt76->offchannel) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if (!cfg80211_reg_can_beacon(dev->mt76.hw->wiphy, chandef, NL80211_IFTYPE_AP)) req.switch_reason = CH_SWITCH_DFS; else req.switch_reason = CH_SWITCH_NORMAL; if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) req.rx_streams = hweight8(req.rx_streams); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; req.center_ch2 = ieee80211_frequency_to_channel(freq2); } return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } int mt7921_mcu_set_eeprom(struct mt792x_dev *dev) { struct req_hdr { u8 buffer_mode; u8 format; __le16 len; } __packed req = { .buffer_mode = EE_MODE_EFUSE, .format = EE_FORMAT_WHOLE, }; 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_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct ps_tlv { __le16 tag; __le16 len; u8 ps_state; /* 0: device awake * 1: static power save * 2: dynamic power saving * 3: enter TWT power saving * 4: leave TWT power saving */ u8 pad[3]; } __packed ps; } __packed ps_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .ps = { .tag = cpu_to_le16(UNI_BSS_INFO_PS), .len = cpu_to_le16(sizeof(struct ps_tlv)), .ps_state = vif->cfg.ps ? 2 : 0, }, }; if (vif->type != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), &ps_req, sizeof(ps_req), true); } static int mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct { struct { u8 bss_idx; u8 pad[3]; } __packed hdr; struct bcnft_tlv { __le16 tag; __le16 len; __le16 bcn_interval; u8 dtim_period; u8 pad; } __packed bcnft; } __packed bcnft_req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .bcnft = { .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), .len = cpu_to_le16(sizeof(struct bcnft_tlv)), .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), .dtim_period = vif->bss_conf.dtim_period, }, }; if (vif->type != NL80211_IFTYPE_STATION) return 0; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), &bcnft_req, sizeof(bcnft_req), true); } int mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct { u8 bss_idx; u8 dtim_period; __le16 aid; __le16 bcn_interval; __le16 atim_window; u8 uapsd; u8 bmc_delivered_ac; u8 bmc_triggered_ac; u8 pad; } req = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, .aid = cpu_to_le16(vif->cfg.aid), .dtim_period = vif->bss_conf.dtim_period, .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int), }; struct { u8 bss_idx; u8 pad[3]; } req_hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }; int err; err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT), &req_hdr, sizeof(req_hdr), false); if (err < 0 || !enable) return err; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED), &req, sizeof(req), false); } int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - int rssi = -ewma_rssi_read(&mvif->rssi); + int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); struct mt76_sta_cmd_info info = { .sta = sta, .vif = vif, .enable = enable, .cmd = MCU_UNI_CMD(STA_REC_UPDATE), .state = state, .offload_fw = true, .rcpi = to_rcpi(rssi), }; struct mt792x_sta *msta; msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL; - info.wcid = msta ? &msta->wcid : &mvif->sta.wcid; + info.wcid = msta ? &msta->deflink.wcid : &mvif->sta.deflink.wcid; info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true; return mt76_connac_mcu_sta_cmd(&dev->mphy, &info); } int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable) { #define MT7921_FIF_BIT_CLR BIT(1) #define MT7921_FIF_BIT_SET BIT(0) int err; if (enable) { err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); if (err) return err; err = mt7921_mcu_set_rxfilter(dev, 0, MT7921_FIF_BIT_SET, MT_WF_RFCR_DROP_OTHER_BEACON); if (err) return err; return 0; } err = mt7921_mcu_set_bss_pm(dev, vif, false); if (err) return err; err = mt7921_mcu_set_rxfilter(dev, 0, MT7921_FIF_BIT_CLR, MT_WF_RFCR_DROP_OTHER_BEACON); if (err) return err; return 0; } int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr) { struct mt7921_txpwr_event *event; struct mt7921_txpwr_req req = { .dbdc_idx = 0, }; struct sk_buff *skb; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR), &req, sizeof(req), true, &skb); if (ret) return ret; event = (struct mt7921_txpwr_event *)skb->data; WARN_ON(skb->len != le16_to_cpu(event->len)); memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); dev_kfree_skb(skb); return 0; } int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct { struct { u8 band_idx; u8 pad[3]; } __packed hdr; struct sniffer_enable_tlv { __le16 tag; __le16 len; u8 enable; u8 pad[3]; } __packed enable; } req = { .hdr = { .band_idx = mvif->band_idx, }, .enable = { .tag = cpu_to_le16(0), .len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)), .enable = enable, }, }; return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); } int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, struct ieee80211_chanctx_conf *ctx) { struct cfg80211_chan_def *chandef = &ctx->def; int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; - const u8 ch_band[] = { + static const u8 ch_band[] = { [NL80211_BAND_2GHZ] = 1, [NL80211_BAND_5GHZ] = 2, [NL80211_BAND_6GHZ] = 3, }; - const u8 ch_width[] = { + static const u8 ch_width[] = { [NL80211_CHAN_WIDTH_20_NOHT] = 0, [NL80211_CHAN_WIDTH_20] = 0, [NL80211_CHAN_WIDTH_40] = 0, [NL80211_CHAN_WIDTH_80] = 1, [NL80211_CHAN_WIDTH_160] = 2, [NL80211_CHAN_WIDTH_80P80] = 3, [NL80211_CHAN_WIDTH_5] = 4, [NL80211_CHAN_WIDTH_10] = 5, [NL80211_CHAN_WIDTH_320] = 6, }; struct { struct { u8 band_idx; u8 pad[3]; } __packed hdr; struct config_tlv { __le16 tag; __le16 len; u16 aid; u8 ch_band; u8 bw; u8 control_ch; u8 sco; u8 center_ch; u8 center_ch2; u8 drop_err; u8 pad[3]; } __packed tlv; } __packed req = { .hdr = { - .band_idx = vif->mt76.band_idx, + .band_idx = vif->bss_conf.mt76.band_idx, }, .tlv = { .tag = cpu_to_le16(1), .len = cpu_to_le16(sizeof(req.tlv)), .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .drop_err = 1, }, }; if (chandef->chan->band < ARRAY_SIZE(ch_band)) req.tlv.ch_band = ch_band[chandef->chan->band]; if (chandef->width < ARRAY_SIZE(ch_width)) req.tlv.bw = ch_width[chandef->width]; if (freq2) req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2); if (req.tlv.control_ch < req.tlv.center_ch) req.tlv.sco = 1; /* SCA */ else if (req.tlv.control_ch > req.tlv.center_ch) req.tlv.sco = 3; /* SCB */ return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); } int mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct ieee80211_mutable_offsets offs; struct { struct req_hdr { u8 bss_idx; u8 pad[3]; } __packed hdr; struct bcn_content_tlv { __le16 tag; __le16 len; __le16 tim_ie_pos; __le16 csa_ie_pos; __le16 bcc_ie_pos; /* 0: disable beacon offload * 1: enable beacon offload * 2: update probe respond offload */ u8 enable; /* 0: legacy format (TXD + payload) * 1: only cap field IE */ u8 type; __le16 pkt_len; u8 pkt[512]; } __packed beacon_tlv; } req = { .hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = mvif->bss_conf.mt76.idx, }, .beacon_tlv = { .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), .len = cpu_to_le16(sizeof(struct bcn_content_tlv)), .enable = enable, }, }; struct sk_buff *skb; /* support enable/update process only * disable flow would be handled in bss stop handler automatically */ if (!enable) return -EOPNOTSUPP; skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); if (!skb) return -EINVAL; if (skb->len > 512 - MT_TXD_SIZE) { dev_err(dev->mt76.dev, "beacon size limit exceed\n"); dev_kfree_skb(skb); return -EINVAL; } mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt), skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON); memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len); req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); if (offs.cntdwn_counter_offs[0]) { u16 csa_offs; csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4; req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs); } dev_kfree_skb(skb); return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), &req, sizeof(req), true); } static int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap, struct mt7921_clc *clc, u8 idx) { - struct sk_buff *skb; +#define CLC_CAP_EVT_EN BIT(0) +#define CLC_CAP_DTS_EN BIT(1) + struct sk_buff *skb, *ret_skb = NULL; struct { u8 ver; u8 pad0; __le16 len; u8 idx; u8 env; u8 acpi_conf; - u8 pad1; + u8 cap; u8 alpha2[2]; u8 type[2]; - u8 rsvd[64]; + u8 env_6g; + u8 mtcl_conf; + u8 rsvd[62]; } __packed req = { + .ver = 1, .idx = idx, .env = env_cap, + .env_6g = dev->phy.power_type, .acpi_conf = mt792x_acpi_get_flags(&dev->phy), + .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; - u8 i, *pos; + u32 buf_len = 0; + u8 *pos; if (!clc) return 0; + if (dev->phy.chip_cap & MT792x_CHIP_CAP_CLC_EVT_EN) + req.cap |= CLC_CAP_EVT_EN; + if (mt76_find_power_limits_node(&dev->mt76)) + req.cap |= CLC_CAP_DTS_EN; + + buf_len = le32_to_cpu(clc->len) - sizeof(*clc); pos = clc->data; - for (i = 0; i < clc->nr_country; i++) { + while (buf_len > 16) { struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos; u16 len = le16_to_cpu(rule->len); + u16 offset = len + sizeof(*rule); - pos += len + sizeof(*rule); + pos += offset; + buf_len -= offset; if (rule->alpha2[0] != alpha2[0] || rule->alpha2[1] != alpha2[1]) continue; memcpy(req.alpha2, rule->alpha2, 2); memcpy(req.type, rule->type, 2); req.len = cpu_to_le16(sizeof(req) + len); skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, le16_to_cpu(req.len), sizeof(req), GFP_KERNEL); if (!skb) return -ENOMEM; skb_put_data(skb, rule->data, len); - ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_CE_CMD(SET_CLC), false); + ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb, + MCU_CE_CMD(SET_CLC), + !!(req.cap & CLC_CAP_EVT_EN), + &ret_skb); if (ret < 0) return ret; + + if (ret_skb) { + struct mt7921_clc_info_tlv *info; + + info = (struct mt7921_clc_info_tlv *)(ret_skb->data + 4); + dev->phy.clc_chan_conf = info->chan_conf; + dev_kfree_skb(ret_skb); + } + valid_cnt++; } if (!valid_cnt) return -ENOENT; return 0; } int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap) { struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy; int i, ret; /* submit all clc config */ for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap, phy->clc[i], i); /* If no country found, set "00" as default */ if (ret == -ENOENT) ret = __mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR, phy->clc[i], i); if (ret < 0) return ret; } return 0; } int mt7921_mcu_get_temperature(struct mt792x_phy *phy) { struct mt792x_dev *dev = phy->dev; struct { u8 ctrl_id; u8 action; u8 band_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, .band_idx = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, sizeof(req), true); } +int mt7921_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy, u8 action) +{ + struct mt792x_dev *dev = phy->dev; + struct { + u8 action; + u8 value; + } req = { + .action = action, + .value = 0, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(WF_RF_PIN_CTRL), &req, + sizeof(req), action ? true : false); +} + int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, u8 bit_op, u32 bit_map) { struct { u8 rsv[4]; u8 mode; u8 rsv2[3]; __le32 fif; __le32 bit_map; /* bit_* for bitmap update */ u8 bit_op; u8 pad[51]; } __packed data = { .mode = fif ? 1 : 2, .fif = cpu_to_le32(fif), .bit_map = cpu_to_le32(bit_map), .bit_op = bit_op, }; return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER), &data, sizeof(data), false); } + +int mt7921_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct { + u8 enable; + s8 cqm_rssi_high; + s8 cqm_rssi_low; + u8 bss_idx; + u16 duration; + u8 rsv2[2]; + } __packed data = { + .enable = vif->cfg.assoc, + .cqm_rssi_high = vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst, + .cqm_rssi_low = vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst, + .bss_idx = mvif->bss_conf.mt76.idx, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(RSSI_MONITOR), + &data, sizeof(data), false); +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/mcu.h b/sys/contrib/dev/mediatek/mt76/mt7921/mcu.h index 9b0aa3b70f0e..2834c6c53e58 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/mcu.h +++ b/sys/contrib/dev/mediatek/mt76/mt7921/mcu.h @@ -1,102 +1,120 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7921_MCU_H #define __MT7921_MCU_H #include "../mt76_connac_mcu.h" struct mt7921_mcu_tx_done_event { u8 pid; u8 status; __le16 seq; u8 wlan_idx; u8 tx_cnt; __le16 tx_rate; u8 flag; u8 tid; u8 rsp_rate; u8 mcs; u8 bw; u8 tx_pwr; u8 reason; u8 rsv0[1]; __le32 delay; __le32 timestamp; __le32 applied_flag; u8 txs[28]; u8 rsv1[32]; } __packed; /* ext event table */ enum { MCU_EXT_EVENT_RATE_REPORT = 0x87, }; struct mt7921_mcu_eeprom_info { __le32 addr; __le32 valid; u8 data[MT7921_EEPROM_BLOCK_SIZE]; } __packed; #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) enum { MT_EBF = BIT(0), /* explicit beamforming */ MT_IBF = BIT(1) /* implicit beamforming */ }; struct mt7921_mcu_ant_id_config { u8 ant_id[4]; } __packed; struct mt7921_txpwr_req { u8 ver; u8 action; __le16 len; u8 dbdc_idx; u8 rsv[3]; } __packed; struct mt7921_txpwr_event { u8 ver; u8 action; __le16 len; struct mt7921_txpwr txpwr; } __packed; +struct mt7921_wf_rf_pin_ctrl_event { + u8 result; + u8 value; +} __packed; + enum { TM_SWITCH_MODE, TM_SET_AT_CMD, TM_QUERY_AT_CMD, }; enum { MT7921_TM_NORMAL, MT7921_TM_TESTMODE, MT7921_TM_ICAP, MT7921_TM_ICAP_OVERLAP, MT7921_TM_WIFISPECTRUM, }; struct mt7921_rftest_cmd { u8 action; u8 rsv[3]; __le32 param0; __le32 param1; } __packed; struct mt7921_rftest_evt { __le32 param0; __le32 param1; } __packed; + +struct mt7921_clc_info_tlv { + __le16 tag; + __le16 len; + + u8 chan_conf; /* BIT(0) : Enable UNII-4 + * BIT(1) : Enable UNII-5 + * BIT(2) : Enable UNII-6 + * BIT(3) : Enable UNII-7 + * BIT(4) : Enable UNII-8 + */ + u8 rsv[63]; +} __packed; #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/mt7921.h b/sys/contrib/dev/mediatek/mt76/mt7921/mt7921.h index 87dd06855f68..c88793fcec64 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/mt7921.h +++ b/sys/contrib/dev/mediatek/mt76/mt7921/mt7921.h @@ -1,339 +1,338 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2020 MediaTek Inc. */ #ifndef __MT7921_H #define __MT7921_H #include "../mt792x.h" #include "regs.h" #define MT7921_TX_RING_SIZE 2048 #define MT7921_TX_MCU_RING_SIZE 256 #define MT7921_TX_FWDL_RING_SIZE 128 #define MT7921_RX_RING_SIZE 1536 -#define MT7921_RX_MCU_RING_SIZE 512 +#define MT7921_RX_MCU_RING_SIZE 8 +#define MT7921_RX_MCU_WA_RING_SIZE 512 #define MT7921_EEPROM_SIZE 3584 #define MT7921_TOKEN_SIZE 8192 #define MT7921_EEPROM_BLOCK_SIZE 16 #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) - #define MCU_UNI_EVENT_ROC 0x27 +#define MCU_UNI_EVENT_CLC 0x80 + +#define EXT_CMD_RADIO_LED_CTRL_ENABLE 0x1 +#define EXT_CMD_RADIO_ON_LED 0x2 +#define EXT_CMD_RADIO_OFF_LED 0x3 + +#define WF_RF_PIN_INIT 0x0 +#define WF_RF_PIN_POLL 0x1 enum { UNI_ROC_ACQUIRE, UNI_ROC_ABORT, UNI_ROC_NUM }; enum mt7921_roc_req { MT7921_ROC_REQ_JOIN, MT7921_ROC_REQ_ROC, MT7921_ROC_REQ_NUM }; enum { UNI_EVENT_ROC_GRANT = 0, UNI_EVENT_ROC_TAG_NUM }; struct mt7921_realease_info { __le16 len; u8 pad_len; u8 tag; } __packed; struct mt7921_fw_features { u8 segment; u8 data; u8 rsv[14]; } __packed; struct mt7921_roc_grant_tlv { __le16 tag; __le16 len; u8 bss_idx; u8 tokenid; u8 status; u8 primarychannel; u8 rfsco; u8 rfband; u8 channelwidth; u8 centerfreqseg1; u8 centerfreqseg2; u8 reqtype; u8 dbdcband; u8 rsv[1]; __le32 max_interval; } __packed; 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) enum mt7921_txq_id { MT7921_TXQ_BAND0, MT7921_TXQ_BAND1, MT7921_TXQ_FWDL = 16, MT7921_TXQ_MCU_WM, }; enum mt7921_rxq_id { MT7921_RXQ_BAND0 = 0, MT7921_RXQ_BAND1, MT7921_RXQ_MCU_WM = 0, }; enum { MT7921_CLC_POWER, MT7921_CLC_CHAN, MT7921_CLC_MAX_NUM, }; struct mt7921_clc_rule { u8 alpha2[2]; u8 type[2]; __le16 len; u8 data[]; } __packed; struct mt7921_clc { __le32 len; u8 idx; u8 ver; u8 nr_country; u8 type; u8 rsv[8]; u8 data[]; } __packed; enum mt7921_eeprom_field { MT_EE_CHIP_ID = 0x000, MT_EE_VERSION = 0x002, MT_EE_MAC_ADDR = 0x004, MT_EE_WIFI_CONF = 0x07c, MT_EE_HW_TYPE = 0x55b, __MT_EE_MAX = 0x9ff }; #define MT_EE_HW_TYPE_ENCAP BIT(0) enum { TXPWR_USER, TXPWR_EEPROM, TXPWR_MAC, TXPWR_MAX_NUM, }; struct mt7921_txpwr { u8 ch; u8 rsv[3]; struct { u8 ch; u8 cck[4]; u8 ofdm[8]; u8 ht20[8]; u8 ht40[9]; u8 vht20[12]; u8 vht40[12]; u8 vht80[12]; u8 vht160[12]; u8 he26[12]; u8 he52[12]; u8 he106[12]; u8 he242[12]; u8 he484[12]; u8 he996[12]; u8 he996x2[12]; } data[TXPWR_MAX_NUM]; }; extern const struct ieee80211_ops mt7921_ops; u32 mt7921_reg_map(struct mt792x_dev *dev, u32 addr); int __mt7921_start(struct mt792x_phy *phy); int mt7921_register_device(struct mt792x_dev *dev); void mt7921_unregister_device(struct mt792x_dev *dev); int mt7921_run_firmware(struct mt792x_dev *dev); +int mt7921_set_channel(struct mt76_phy *mphy); int mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta, struct ieee80211_vif *vif, bool enable, enum mt76_sta_info_state state); int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd); int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif); int mt7921_mcu_set_eeprom(struct mt792x_dev *dev); int mt7921_mcu_get_rx_rate(struct mt792x_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate); int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl); void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb); int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, u8 bit_op, u32 bit_map); +int mt7921_mcu_radio_led_ctrl(struct mt792x_dev *dev, u8 value); +int mt7921_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy, u8 action); static inline u32 mt7921_reg_map_l1(struct mt792x_dev *dev, u32 addr) { u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); mt76_rmw_field(dev, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, base); /* use read to push write */ mt76_rr(dev, MT_HIF_REMAP_L1); return MT_HIF_REMAP_BASE_L1 + offset; } static inline u32 mt7921_l1_rr(struct mt792x_dev *dev, u32 addr) { return mt76_rr(dev, mt7921_reg_map_l1(dev, addr)); } static inline void mt7921_l1_wr(struct mt792x_dev *dev, u32 addr, u32 val) { mt76_wr(dev, mt7921_reg_map_l1(dev, addr), val); } static inline u32 mt7921_l1_rmw(struct mt792x_dev *dev, u32 addr, u32 mask, u32 val) { val |= mt7921_l1_rr(dev, addr) & ~mask; mt7921_l1_wr(dev, addr, val); return val; } #define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val) #define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0) -static inline void -mt7921_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb, - int type) -{ - u32 hdr, len; - - len = mt76_is_usb(&dev->mt76) ? skb->len : skb->len + sizeof(hdr); - hdr = FIELD_PREP(MT7921_SDIO_HDR_TX_BYTES, len) | - FIELD_PREP(MT7921_SDIO_HDR_PKT_TYPE, type); - - put_unaligned_le32(hdr, skb_push(skb, sizeof(hdr))); -} - -void mt7921_stop(struct ieee80211_hw *hw); +void mt7921_regd_update(struct mt792x_dev *dev); int mt7921_mac_init(struct mt792x_dev *dev); bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask); 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, - struct ieee80211_sta *sta); +int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7921_mac_reset_work(struct work_struct *work); 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); bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); void mt7921_stats_work(struct work_struct *work); void mt7921_set_stream_he_caps(struct mt792x_phy *phy); int mt7921_init_debugfs(struct mt792x_dev *dev); int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev, struct ieee80211_ampdu_params *params, bool enable); int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev, struct ieee80211_ampdu_params *params, bool enable); void mt7921_scan_work(struct work_struct *work); void mt7921_roc_work(struct work_struct *work); +void mt7921_csa_work(struct work_struct *work); int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif); void mt7921_coredump_work(struct work_struct *work); int mt7921_get_txpwr_info(struct mt792x_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); int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq); int mt7921e_driver_own(struct mt792x_dev *dev); int mt7921e_mac_reset(struct mt792x_dev *dev); int mt7921e_mcu_init(struct mt792x_dev *dev); int mt7921s_wfsys_reset(struct mt792x_dev *dev); int mt7921s_mac_reset(struct mt792x_dev *dev); int mt7921s_init_reset(struct mt792x_dev *dev); int mt7921s_mcu_init(struct mt792x_dev *dev); int mt7921s_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt7921s_mcu_fw_pmctrl(struct mt792x_dev *dev); void mt7921_mac_add_txs(struct mt792x_dev *dev, void *data); void mt7921_set_runtime_pm(struct mt792x_dev *dev); void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); void mt7921_set_ipv6_ns_work(struct work_struct *work); int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, struct ieee80211_chanctx_conf *ctx); int mt7921_mcu_get_temperature(struct mt792x_phy *phy); int mt7921_usb_sdio_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_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e); bool mt7921_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update); /* usb */ int mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool enable); int mt7921_set_tx_sar_pwr(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap); int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, struct ieee80211_channel *chan, int duration, enum mt7921_roc_req type, u8 token_id); int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif, u8 token_id); +void mt7921_roc_abort_sync(struct mt792x_dev *dev); +int mt7921_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/pci.c b/sys/contrib/dev/mediatek/mt76/mt7921/pci.c index ff338d4dea20..bde91b0f0a59 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/pci.c @@ -1,554 +1,601 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * */ #if defined(__FreeBSD__) #define LINUXKPI_PARAM_PREFIX mt7921_pci_ #endif #include #include #include +#include #include "mt7921.h" #include "../mt76_connac2_mac.h" #include "../dma.h" #include "mcu.h" static const struct pci_device_id mt7921_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961), .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7922), .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_ITTIM, 0x7922), + .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0608), .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0616), .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920), + .driver_data = (kernel_ulong_t)MT7920_FIRMWARE_WM }, { }, }; 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 int mt7921e_init_reset(struct mt792x_dev *dev) { return mt792x_wpdma_reset(dev, true); } static void mt7921e_unregister_device(struct mt792x_dev *dev) { int i; struct mt76_connac_pm *pm = &dev->pm; + struct ieee80211_hw *hw = mt76_hw(dev); + + if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) + wiphy_rfkill_stop_polling(hw->wiphy); cancel_work_sync(&dev->init_work); 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); cancel_work_sync(&dev->reset_work); mt76_connac2_tx_token_put(&dev->mt76); __mt792x_mcu_drv_pmctrl(dev); mt792x_dma_cleanup(dev); mt792x_wfsys_reset(dev); skb_queue_purge(&dev->mt76.mcu.res_q); tasklet_disable(&dev->mt76.irq_tasklet); } static u32 __mt7921_reg_addr(struct mt792x_dev *dev, u32 addr) { static const struct mt76_connac_reg_map fixed_map[] = { { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x820ed000, 0x24800, 0x00800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ { 0x820e4000, 0x21000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ { 0x820e7000, 0x21e00, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820eb000, 0x24200, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ { 0x820e2000, 0x20800, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ { 0x820e3000, 0x20c00, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ { 0x820e5000, 0x21400, 0x00800 }, /* 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, 0x01000 }, /* WFDMA PCIE0 MCU DMA0 */ { 0x55000000, 0x03000, 0x01000 }, /* WFDMA PCIE0 MCU DMA1 */ { 0x58000000, 0x06000, 0x01000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ { 0x59000000, 0x07000, 0x01000 }, /* WFDMA PCIE1 MCU DMA1 */ { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */ { 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, 0x04000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x0c000, 0x02000 }, /* WF_UMAC_TOP (PSE) */ { 0x820cc000, 0x0e000, 0x01000 }, /* WF_UMAC_TOP (PP) */ { 0x820cd000, 0x0f000, 0x01000 }, /* WF_MDP_TOP */ { 0x74030000, 0x10000, 0x10000 }, /* PCIE_MAC_IREG */ { 0x820ce000, 0x21c00, 0x00200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820cf000, 0x22000, 0x01000 }, /* WF_LMAC_TOP (WF_PF) */ { 0x820e0000, 0x20000, 0x00400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ { 0x820e1000, 0x20400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ { 0x820e9000, 0x23400, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ { 0x820ea000, 0x24000, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ { 0x820ec000, 0x24600, 0x00200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ { 0x820f0000, 0xa0000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ { 0x820f1000, 0xa0600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ { 0x820f2000, 0xa0800, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ { 0x820f3000, 0xa0c00, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ { 0x820f4000, 0xa1000, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ { 0x820f5000, 0xa1400, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ { 0x820f7000, 0xa1e00, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ { 0x820f9000, 0xa3400, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ { 0x820fa000, 0xa4000, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ { 0x820fb000, 0xa4200, 0x00400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ { 0x820fc000, 0xa4600, 0x00200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ { 0x820fd000, 0xa4800, 0x00800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ }; int i; if (addr < 0x100000) return addr; for (i = 0; i < ARRAY_SIZE(fixed_map); i++) { u32 ofs; if (addr < fixed_map[i].phys) continue; ofs = addr - fixed_map[i].phys; if (ofs > fixed_map[i].size) continue; return fixed_map[i].maps + ofs; } if ((addr >= 0x18000000 && addr < 0x18c00000) || (addr >= 0x70000000 && addr < 0x78000000) || (addr >= 0x7c000000 && addr < 0x7c400000)) return mt7921_reg_map_l1(dev, addr); dev_err(dev->mt76.dev, "Access currently unsupported address %08x\n", addr); return 0; } static u32 mt7921_rr(struct mt76_dev *mdev, u32 offset) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); u32 addr = __mt7921_reg_addr(dev, offset); return dev->bus_ops->rr(mdev, addr); } static void mt7921_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); u32 addr = __mt7921_reg_addr(dev, offset); dev->bus_ops->wr(mdev, addr, val); } static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); u32 addr = __mt7921_reg_addr(dev, offset); return dev->bus_ops->rmw(mdev, addr, mask, val); } static int mt7921_dma_init(struct mt792x_dev *dev) { int ret; mt76_dma_attach(&dev->mt76); ret = mt792x_dma_disable(dev, true); if (ret) return ret; /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); /* command to WM */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM, MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; /* firmware download */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7921_TXQ_FWDL, MT7921_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; /* event from WM before firmware download */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7921_RXQ_MCU_WM, MT7921_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; /* Change mcu queue after firmware download */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7921_RXQ_MCU_WM, - MT7921_RX_MCU_RING_SIZE, + MT7921_RX_MCU_WA_RING_SIZE, MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); if (ret) return ret; /* rx data */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT7921_RXQ_BAND0, MT7921_RX_RING_SIZE, MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); if (ret) return ret; ret = mt76_init_queues(dev, mt792x_poll_rx); if (ret < 0) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt792x_poll_tx); napi_enable(&dev->mt76.tx_napi); return mt792x_dma_enable(dev); } 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 mt76_connac_hw_txp), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .token_size = MT7921_TOKEN_SIZE, .tx_prepare_skb = mt7921e_tx_prepare_skb, .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_check = mt7921_rx_check, .rx_skb = mt7921_queue_rx_skb, .rx_poll_complete = mt792x_rx_poll_complete, .sta_add = mt7921_mac_sta_add, - .sta_assoc = mt7921_mac_sta_assoc, + .sta_event = mt7921_mac_sta_event, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt792x_update_channel, + .set_channel = mt7921_set_channel, }; static const struct mt792x_hif_ops mt7921_pcie_ops = { .init_reset = mt7921e_init_reset, .reset = mt7921e_mac_reset, .mcu_init = mt7921e_mcu_init, .drv_own = mt792xe_mcu_drv_pmctrl, .fw_own = mt792xe_mcu_fw_pmctrl, }; static const struct mt792x_irq_map irq_map = { .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, .tx = { .all_complete_mask = MT_INT_TX_DONE_ALL, .mcu_complete_mask = MT_INT_TX_DONE_MCU, }, .rx = { .data_complete_mask = MT_INT_RX_DONE_DATA, .wm_complete_mask = MT_INT_RX_DONE_WM, .wm2_complete_mask = MT_INT_RX_DONE_WM2, }, }; struct ieee80211_ops *ops; struct mt76_bus_ops *bus_ops; struct mt792x_dev *dev; struct mt76_dev *mdev; + u16 cmd, chipid; u8 features; int ret; - u16 cmd; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_read_config_word(pdev, PCI_COMMAND, &cmd); if (!(cmd & PCI_COMMAND_MEMORY)) { cmd |= PCI_COMMAND_MEMORY; pci_write_config_word(pdev, PCI_COMMAND, cmd); } pci_set_master(pdev); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) goto err_free_pci_vec; if (mt7921_disable_aspm) mt76_pci_disable_aspm(pdev); ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops, (void *)id->driver_data, &features); if (!ops) { ret = -ENOMEM; goto err_free_pci_vec; } mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) { ret = -ENOMEM; goto err_free_pci_vec; } pci_set_drvdata(pdev, mdev); dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &mt7921_pcie_ops; dev->irq_map = &irq_map; mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); 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); if (!bus_ops) { ret = -ENOMEM; goto err_free_dev; } bus_ops->rr = mt7921_rr; bus_ops->wr = mt7921_wr; bus_ops->rmw = mt7921_rmw; dev->mt76.bus = bus_ops; + if (!mt7921_disable_aspm && mt76_pci_aspm_supported(pdev)) + dev->aspm_supported = true; + ret = mt792xe_mcu_fw_pmctrl(dev); if (ret) goto err_free_dev; ret = __mt792xe_mcu_drv_pmctrl(dev); if (ret) goto err_free_dev; - mdev->rev = (mt7921_l1_rr(dev, MT_HW_CHIPID) << 16) | + chipid = mt7921_l1_rr(dev, MT_HW_CHIPID); + if (chipid == 0x7961 && (mt7921_l1_rr(dev, MT_HW_BOUND) & BIT(7))) + chipid = 0x7920; + mdev->rev = (chipid << 16) | (mt7921_l1_rr(dev, MT_HW_REV) & 0xff); dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); ret = mt792x_wfsys_reset(dev); if (ret) goto err_free_dev; mt76_wr(dev, irq_map.host_irq_enable, 0); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); 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; +#if defined(CONFIG_OF) + if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source")) + device_init_wakeup(dev->mt76.dev, true); +#endif + return 0; err_free_irq: devm_free_irq(&pdev->dev, pdev->irq, dev); err_free_dev: mt76_free_device(&dev->mt76); err_free_pci_vec: pci_free_irq_vectors(pdev); return ret; } static void mt7921_pci_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); +#if defined(CONFIG_OF) + if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source")) + device_init_wakeup(dev->mt76.dev, false); +#endif + mt7921e_unregister_device(dev); + set_bit(MT76_REMOVED, &mdev->phy.state); devm_free_irq(&pdev->dev, pdev->irq, dev); mt76_free_device(&dev->mt76); pci_free_irq_vectors(pdev); } #if !defined(__FreeBSD__) || defined(CONFIG_PM_SLEEP) static int mt7921_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt76_connac_pm *pm = &dev->pm; int i, err; pm->suspended = true; flush_work(&dev->reset_work); cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); + mt7921_roc_abort_sync(dev); + err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) goto restore_suspend; - err = mt76_connac_mcu_set_hif_suspend(mdev, true); + wait_event_timeout(dev->wait, + !dev->regd_in_progress, 5 * HZ); + + err = mt7921_mcu_radio_led_ctrl(dev, EXT_CMD_RADIO_OFF_LED); + if (err < 0) + goto restore_suspend; + + err = mt76_connac_mcu_set_hif_suspend(mdev, true, true); if (err) goto restore_suspend; /* always enable deep sleep during suspend to reduce * power consumption */ mt76_connac_mcu_set_deep_sleep(&dev->mt76, true); napi_disable(&mdev->tx_napi); mt76_worker_disable(&mdev->tx_worker); mt76_for_each_q_rx(mdev, i) { napi_disable(&mdev->napi[i]); } /* wait until dma is idle */ mt76_poll(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); /* put dma disabled */ mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); /* disable interrupt */ mt76_wr(dev, dev->irq_map->host_irq_enable, 0); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); synchronize_irq(pdev->irq); tasklet_kill(&mdev->irq_tasklet); err = mt792x_mcu_fw_pmctrl(dev); if (err) goto restore_napi; return 0; restore_napi: mt76_for_each_q_rx(mdev, i) { napi_enable(&mdev->napi[i]); } napi_enable(&mdev->tx_napi); if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); - mt76_connac_mcu_set_hif_suspend(mdev, false); + mt76_connac_mcu_set_hif_suspend(mdev, false, true); restore_suspend: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } static int mt7921_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt76_connac_pm *pm = &dev->pm; int i, err; err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) goto failed; mt792x_wpdma_reinit_cond(dev); /* enable interrupt */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask | MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); /* put dma enabled */ mt76_set(dev, MT_WFDMA0_GLO_CFG, 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); + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + napi_schedule(&mdev->napi[i]); + } napi_schedule(&mdev->tx_napi); local_bh_enable(); /* restore previous ds setting */ if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); - err = mt76_connac_mcu_set_hif_suspend(mdev, false); + err = mt76_connac_mcu_set_hif_suspend(mdev, false, true); + if (err < 0) + goto failed; + + mt7921_regd_update(dev); + err = mt7921_mcu_radio_led_ctrl(dev, EXT_CMD_RADIO_ON_LED); failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } #endif static void mt7921_pci_shutdown(struct pci_dev *pdev) { mt7921_pci_remove(pdev); } static DEFINE_SIMPLE_DEV_PM_OPS(mt7921_pm_ops, mt7921_pci_suspend, mt7921_pci_resume); static struct pci_driver mt7921_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7921_pci_device_table, .probe = mt7921_pci_probe, .remove = mt7921_pci_remove, .shutdown = mt7921_pci_shutdown, .driver.pm = pm_sleep_ptr(&mt7921_pm_ops), }; module_pci_driver(mt7921_pci_driver); MODULE_DEVICE_TABLE(pci, mt7921_pci_device_table); +MODULE_FIRMWARE(MT7920_FIRMWARE_WM); +MODULE_FIRMWARE(MT7920_ROM_PATCH); MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); MODULE_FIRMWARE(MT7922_FIRMWARE_WM); MODULE_FIRMWARE(MT7922_ROM_PATCH); MODULE_AUTHOR("Sean Wang "); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); #if defined(__FreeBSD__) MODULE_VERSION(mt7921_pci, 1); MODULE_DEPEND(mt7921_pci, linuxkpi, 1, 1, 1); MODULE_DEPEND(mt7921_pci, linuxkpi_wlan, 1, 1, 1); MODULE_DEPEND(mt7921_pci, mt76_core, 1, 1, 1); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c b/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c index e7a995e7e70a..881812ba03ff 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c @@ -1,128 +1,129 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2021 MediaTek Inc. */ #include "mt7921.h" #include "../dma.h" #include "../mt76_connac2_mac.h" 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 mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct mt76_connac_hw_txp *txp; struct mt76_txwi_cache *t; 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 mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt76_connac2_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, pid, qid, 0); txp = (struct mt76_connac_hw_txp *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt76_connac_hw_txp)); mt76_connac_write_hw_txp(mdev, tx_info, txp, id); - tx_info->skb = DMA_DUMMY_DATA; + tx_info->skb = NULL; return 0; } int mt7921e_mac_reset(struct mt792x_dev *dev) { int i, err; mt792xe_mcu_drv_pmctrl(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt76_wr(dev, dev->irq_map->host_irq_enable, 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); mt76_connac2_tx_token_put(&dev->mt76); idr_init(&dev->mt76.token); mt792x_wpdma_reset(dev, true); - local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + + local_bh_disable(); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } local_bh_enable(); dev->fw_assert = false; clear_bit(MT76_MCU_RESET, &dev->mphy.state); mt76_wr(dev, dev->irq_map->host_irq_enable, dev->irq_map->tx.all_complete_mask | MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); err = mt7921e_driver_own(dev); if (err) goto out; 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); + local_bh_disable(); napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); mt76_worker_enable(&dev->mt76.tx_worker); return err; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/sdio.c b/sys/contrib/dev/mediatek/mt76/mt7921/sdio.c index dc1beb76df3e..45b9f35aab17 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/sdio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/sdio.c @@ -1,325 +1,331 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2021 MediaTek Inc. * */ #include #include #include #include #include #include #include "mt7921.h" #include "../sdio.h" #include "../mt76_connac2_mac.h" #include "mcu.h" static const struct sdio_device_id mt7921s_table[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901), .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, { } /* 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 mt792x_dev *dev = container_of(mdev, struct mt792x_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 mt792x_dev *dev) { struct mt76_connac_pm *pm = &dev->pm; cancel_work_sync(&dev->init_work); 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); skb_queue_purge(&dev->mt76.mcu.res_q); 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; sdio_claim_host(sdio->func); err = sdio_readsb(sdio->func, irq_data, MCR_WHISR, sizeof(*irq_data)); sdio_release_host(sdio->func); if (err < 0) return err; if (irq_data->rx.num[0] > 16 || irq_data->rx.num[1] > 128) return -EINVAL; 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, .drv_flags = MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb, .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb, .tx_status_data = mt7921_usb_sdio_tx_status_data, .rx_skb = mt7921_queue_rx_skb, .rx_check = mt7921_rx_check, .sta_add = mt7921_mac_sta_add, - .sta_assoc = mt7921_mac_sta_assoc, + .sta_event = mt7921_mac_sta_event, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt792x_update_channel, + .set_channel = mt7921_set_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 mt792x_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 ieee80211_ops *ops; struct mt792x_dev *dev; struct mt76_dev *mdev; u8 features; int ret; ops = mt792x_get_mac80211_ops(&func->dev, &mt7921_ops, (void *)id->driver_data, &features); if (!ops) return -ENOMEM; mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; 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; } 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 mt792x_dev *dev = sdio_get_drvdata(func); mt7921s_unregister_device(dev); } static int mt7921s_suspend(struct device *__dev) { struct sdio_func *func = dev_to_sdio_func(__dev); struct mt792x_dev *dev = sdio_get_drvdata(func); struct mt76_connac_pm *pm = &dev->pm; struct mt76_dev *mdev = &dev->mt76; int err; pm->suspended = true; set_bit(MT76_STATE_SUSPEND, &mdev->phy.state); flush_work(&dev->reset_work); cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); + mt7921_roc_abort_sync(dev); + err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) 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.status_worker); - cancel_work_sync(&mdev->sdio.stat_work); + mt76_worker_disable(&mdev->sdio.stat_worker); clear_bit(MT76_READING_STATS, &dev->mphy.state); mt76_tx_status_check(mdev, true); mt76_worker_schedule(&mdev->sdio.txrx_worker); wait_event_timeout(dev->mt76.sdio.wait, mt76s_txqs_empty(&dev->mt76), 5 * HZ); /* It is supposed that SDIO bus is idle at the point */ - err = mt76_connac_mcu_set_hif_suspend(mdev, true); + err = mt76_connac_mcu_set_hif_suspend(mdev, true, true); if (err) goto restore_worker; mt76_worker_disable(&mdev->sdio.txrx_worker); mt76_worker_disable(&mdev->sdio.net_worker); err = mt792x_mcu_fw_pmctrl(dev); if (err) goto restore_txrx_worker; sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); return 0; restore_txrx_worker: mt76_worker_enable(&mdev->sdio.net_worker); mt76_worker_enable(&mdev->sdio.txrx_worker); - mt76_connac_mcu_set_hif_suspend(mdev, false); + mt76_connac_mcu_set_hif_suspend(mdev, false, true); restore_worker: mt76_worker_enable(&mdev->tx_worker); mt76_worker_enable(&mdev->sdio.status_worker); + mt76_worker_enable(&mdev->sdio.stat_worker); if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(mdev, false); restore_suspend: clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state); pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } static int mt7921s_resume(struct device *__dev) { struct sdio_func *func = dev_to_sdio_func(__dev); struct mt792x_dev *dev = sdio_get_drvdata(func); struct mt76_connac_pm *pm = &dev->pm; struct mt76_dev *mdev = &dev->mt76; int err; clear_bit(MT76_STATE_SUSPEND, &mdev->phy.state); err = mt792x_mcu_drv_pmctrl(dev); if (err < 0) goto failed; 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); + mt76_worker_enable(&mdev->sdio.stat_worker); /* restore previous ds setting */ if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(mdev, false); - err = mt76_connac_mcu_set_hif_suspend(mdev, false); + err = mt76_connac_mcu_set_hif_suspend(mdev, false, true); failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } MODULE_DEVICE_TABLE(sdio, mt7921s_table); MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume); static struct sdio_driver mt7921s_driver = { .name = KBUILD_MODNAME, .probe = mt7921s_probe, .remove = mt7921s_remove, .id_table = mt7921s_table, .drv.pm = pm_sleep_ptr(&mt7921s_pm_ops), }; module_sdio_driver(mt7921s_driver); +MODULE_DESCRIPTION("MediaTek MT7921S (SDIO) wireless driver"); MODULE_AUTHOR("Sean Wang "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c index 8edd0291c128..1f77cf71ca70 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c @@ -1,142 +1,141 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2021 MediaTek Inc. */ #include #include #include "mt7921.h" #include "../mt76_connac2_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 mt792x_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); clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); /* activate mt7921s again */ mt7921s_mcu_drv_pmctrl(dev); mt76_clear(dev, MT_CONN_STATUS, MT_WIFI_PATCH_DL_STATE); mt7921s_mcu_fw_pmctrl(dev); mt7921s_mcu_drv_pmctrl(dev); return 0; } int mt7921s_init_reset(struct mt792x_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_MCU_RESET, &dev->mphy.state); mt7921s_enable_irq(&dev->mt76); return 0; } int mt7921s_mac_reset(struct mt792x_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); + mt76_worker_disable(&dev->mt76.sdio.stat_worker); 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); + mt76_worker_enable(&dev->mt76.sdio.stat_worker); dev->fw_assert = false; 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; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c index 310eeca024ad..5e4501d7f1c0 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c @@ -1,175 +1,175 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2021 MediaTek Inc. */ #include #include #include #include #include "mt7921.h" #include "../sdio.h" #include "../mt76_connac2_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 mt792x_dev *dev = container_of(mdev, struct mt792x_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 mt792x_mac_work that is excuting register access via sdio * bus. */ if (dev->fw_assert) return -EBUSY; ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; mdev->mcu.timeout = 3 * HZ; if (cmd == MCU_CMD(FW_SCATTER)) type = MT7921_SDIO_FWDL; - mt7921_skb_add_usb_sdio_hdr(dev, skb, type); + mt792x_skb_add_usb_sdio_hdr(dev, 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; } static u32 mt7921s_read_rm3r(struct mt792x_dev *dev) { struct mt76_sdio *sdio = &dev->mt76.sdio; return sdio_readl(sdio->func, MCR_D2HRM3R, NULL); } static u32 mt7921s_clear_rm3r_drv_own(struct mt792x_dev *dev) { struct mt76_sdio *sdio = &dev->mt76.sdio; u32 val; val = sdio_readl(sdio->func, MCR_D2HRM3R, NULL); if (val) sdio_writel(sdio->func, H2D_SW_INT_CLEAR_MAILBOX_ACK, MCR_WSICR, NULL); return val; } int mt7921s_mcu_init(struct mt792x_dev *dev) { static const struct mt76_mcu_ops mt7921s_mcu_ops = { .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt76_connac2_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 mt792x_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; u32 status; int err; 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); if (!err && test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) err = readx_poll_timeout(mt7921s_read_rm3r, dev, status, status & D2HRM3R_IS_DRIVER_OWN, 2000, 1000000); sdio_release_host(func); if (err < 0) { dev_err(dev->mt76.dev, "driver own failed\n"); return -EIO; } 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; return 0; } int mt7921s_mcu_fw_pmctrl(struct mt792x_dev *dev) { struct sdio_func *func = dev->mt76.sdio.func; struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; u32 status; int err; sdio_claim_host(func); if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) { err = readx_poll_timeout(mt7921s_clear_rm3r_drv_own, dev, status, !(status & D2HRM3R_IS_DRIVER_OWN), 2000, 1000000); if (err < 0) { dev_err(dev->mt76.dev, "mailbox ACK not cleared\n"); goto out; } } 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); out: sdio_release_host(func); if (err < 0) { dev_err(dev->mt76.dev, "firmware own failed\n"); clear_bit(MT76_STATE_PM, &mphy->state); return -EIO; } pm->stats.last_doze_event = jiffies; pm->stats.awake_time += pm->stats.last_doze_event - pm->stats.last_wake_event; return 0; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/usb.c b/sys/contrib/dev/mediatek/mt76/mt7921/usb.c index 59cd3d98bf90..fe9751851ff7 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/usb.c +++ b/sys/contrib/dev/mediatek/mt76/mt7921/usb.c @@ -1,348 +1,345 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2022 MediaTek Inc. * * Author: Lorenzo Bianconi */ #include #include #include #include "mt7921.h" #include "mcu.h" #include "../mt76_connac2_mac.h" static const struct usb_device_id mt7921u_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, /* Comfast CF-952AX */ { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6211, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, /* Netgear, Inc. [A8000,AXE3000] */ { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, + /* TP-Link TXE50UH */ + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0107, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, { }, }; static int mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *seq) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); u32 pad, ep; int ret; ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; mdev->mcu.timeout = 3 * HZ; if (cmd != MCU_CMD(FW_SCATTER)) ep = MT_EP_OUT_INBAND_CMD; else ep = MT_EP_OUT_AC_BE; - mt7921_skb_add_usb_sdio_hdr(dev, skb, 0); + mt792x_skb_add_usb_sdio_hdr(dev, skb, 0); pad = round_up(skb->len, 4) + 4 - skb->len; __skb_put_zero(skb, pad); ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 1000, ep); dev_kfree_skb(skb); return ret; } static int mt7921u_mcu_init(struct mt792x_dev *dev) { static const struct mt76_mcu_ops mcu_ops = { .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt76_connac2_mcu_txd), .tailroom = MT_USB_TAIL_SIZE, .mcu_skb_send_msg = mt7921u_mcu_send_message, .mcu_parse_response = mt7921_mcu_parse_response, }; int ret; dev->mt76.mcu_ops = &mcu_ops; mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); ret = mt7921_run_firmware(dev); if (ret) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); return 0; } static int mt7921u_mac_reset(struct mt792x_dev *dev) { int err; 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); mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); mt792xu_wfsys_reset(dev); clear_bit(MT76_MCU_RESET, &dev->mphy.state); err = mt76u_resume_rx(&dev->mt76); if (err) goto out; err = mt792xu_mcu_power_on(dev); if (err) goto out; err = mt792xu_dma_init(dev, false); if (err) goto out; mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); err = mt7921_run_firmware(dev); if (err) goto out; mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); 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 mt7921u_stop(struct ieee80211_hw *hw) -{ - struct mt792x_dev *dev = mt792x_hw_dev(hw); - - mt76u_stop_tx(&dev->mt76); - mt7921_stop(hw); -} - static int mt7921u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_SDIO_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ | MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb, .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb, .tx_status_data = mt7921_usb_sdio_tx_status_data, .rx_skb = mt7921_queue_rx_skb, .rx_check = mt7921_rx_check, .sta_add = mt7921_mac_sta_add, - .sta_assoc = mt7921_mac_sta_assoc, + .sta_event = mt7921_mac_sta_event, .sta_remove = mt7921_mac_sta_remove, .update_survey = mt792x_update_channel, + .set_channel = mt7921_set_channel, }; static const struct mt792x_hif_ops hif_ops = { .mcu_init = mt7921u_mcu_init, .init_reset = mt792xu_init_reset, .reset = mt7921u_mac_reset, }; static struct mt76_bus_ops bus_ops = { .rr = mt792xu_rr, .wr = mt792xu_wr, .rmw = mt792xu_rmw, .read_copy = mt76u_read_copy, .write_copy = mt792xu_copy, .type = MT76_BUS_USB, }; struct usb_device *udev = interface_to_usbdev(usb_intf); struct ieee80211_ops *ops; struct ieee80211_hw *hw; struct mt792x_dev *dev; struct mt76_dev *mdev; u8 features; int ret; ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7921_ops, (void *)id->driver_info, &features); if (!ops) return -ENOMEM; - ops->stop = mt7921u_stop; + ops->stop = mt792xu_stop; mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &hif_ops; udev = usb_get_dev(udev); usb_reset_device(udev); usb_set_intfdata(usb_intf, dev); ret = __mt76u_init(mdev, usb_intf, &bus_ops); if (ret < 0) 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); if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) { ret = mt792xu_wfsys_reset(dev); if (ret) goto error; } ret = mt792xu_mcu_power_on(dev); if (ret) goto error; ret = mt76u_alloc_mcu_queue(&dev->mt76); if (ret) goto error; ret = mt76u_alloc_queues(&dev->mt76); if (ret) goto error; ret = mt792xu_dma_init(dev, false); if (ret) goto error; hw = mt76_hw(dev); /* check hw sg support in order to enable AMSDU */ hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; ret = mt7921_register_device(dev); if (ret) goto error; return 0; error: mt76u_queues_deinit(&dev->mt76); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); mt76_free_device(&dev->mt76); return ret; } #ifdef CONFIG_PM static int mt7921u_suspend(struct usb_interface *intf, pm_message_t state) { struct mt792x_dev *dev = usb_get_intfdata(intf); struct mt76_connac_pm *pm = &dev->pm; int err; pm->suspended = true; flush_work(&dev->reset_work); - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, true); if (err) goto failed; mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); return 0; failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } static int mt7921u_resume(struct usb_interface *intf) { struct mt792x_dev *dev = usb_get_intfdata(intf); struct mt76_connac_pm *pm = &dev->pm; bool reinit = true; int err, i; for (i = 0; i < 10; i++) { u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT); if (!(val & MT_WF_SW_SER_TRIGGER_SUSPEND)) { reinit = false; break; } if (val & MT_WF_SW_SER_DONE_SUSPEND) { mt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0); break; } msleep(20); } if (reinit || mt792x_dma_need_reinit(dev)) { err = mt792xu_dma_init(dev, true); if (err) goto failed; } err = mt76u_resume_rx(&dev->mt76); if (err < 0) goto failed; - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); + err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, true); failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } #endif /* CONFIG_PM */ MODULE_DEVICE_TABLE(usb, mt7921u_device_table); MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); static struct usb_driver mt7921u_driver = { .name = KBUILD_MODNAME, .id_table = mt7921u_device_table, .probe = mt7921u_probe, .disconnect = mt792xu_disconnect, #ifdef CONFIG_PM .suspend = mt7921u_suspend, .resume = mt7921u_resume, .reset_resume = mt7921u_resume, #endif /* CONFIG_PM */ .soft_unbind = 1, .disable_hub_initiated_lpm = 1, }; module_usb_driver(mt7921u_driver); +MODULE_DESCRIPTION("MediaTek MT7921U (USB) wireless driver"); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/Kconfig b/sys/contrib/dev/mediatek/mt76/mt7925/Kconfig new file mode 100644 index 000000000000..5854e95e68a5 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: ISC +config MT7925_COMMON + tristate + select MT792x_LIB + select WANT_DEV_COREDUMP + +config MT7925E + tristate "MediaTek MT7925E (PCIe) support" + select MT7925_COMMON + depends on MAC80211 + depends on PCI + help + This adds support for MT7925-based wireless PCIe devices, + which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be + 2x2:2SS 4096-QAM, 160MHz channels. + + To compile this driver as a module, choose M here. + +config MT7925U + tristate "MediaTek MT7925U (USB) support" + select MT792x_USB + select MT7925_COMMON + depends on MAC80211 + depends on USB + help + This adds support for MT7925-based wireless USB devices, + which support operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be + 2x2:2SS 4096-QAM, 160MHz channels. + + To compile this driver as a module, choose M here. diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/Makefile b/sys/contrib/dev/mediatek/mt76/mt7925/Makefile new file mode 100644 index 000000000000..d321e4ed732f --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: ISC + +obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o +obj-$(CONFIG_MT7925E) += mt7925e.o +obj-$(CONFIG_MT7925U) += mt7925u.o + +mt7925-common-y := mac.o mcu.o main.o init.o debugfs.o +mt7925e-y := pci.o pci_mac.o pci_mcu.o +mt7925u-y := usb.o diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/debugfs.c b/sys/contrib/dev/mediatek/mt76/mt7925/debugfs.c new file mode 100644 index 000000000000..1e2fc6577e78 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/debugfs.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include "mt7925.h" +#include "mcu.h" + +static int +mt7925_reg_set(void *data, u64 val) +{ + struct mt792x_dev *dev = data; + u32 regval = val; + + mt792x_mutex_acquire(dev); + mt7925_mcu_regval(dev, dev->mt76.debugfs_reg, ®val, true); + mt792x_mutex_release(dev); + + return 0; +} + +static int +mt7925_reg_get(void *data, u64 *val) +{ + struct mt792x_dev *dev = data; + u32 regval; + int ret; + + mt792x_mutex_acquire(dev); + ret = mt7925_mcu_regval(dev, dev->mt76.debugfs_reg, ®val, false); + mt792x_mutex_release(dev); + if (!ret) + *val = regval; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt7925_reg_get, mt7925_reg_set, + "0x%08llx\n"); +static int +mt7925_fw_debug_set(void *data, u64 val) +{ + struct mt792x_dev *dev = data; + + mt792x_mutex_acquire(dev); + + dev->fw_debug = (u8)val; + mt7925_mcu_fw_log_2_host(dev, dev->fw_debug); + + mt792x_mutex_release(dev); + + return 0; +} + +static int +mt7925_fw_debug_get(void *data, u64 *val) +{ + struct mt792x_dev *dev = data; + + *val = dev->fw_debug; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7925_fw_debug_get, + mt7925_fw_debug_set, "%lld\n"); + +DEFINE_SHOW_ATTRIBUTE(mt792x_tx_stats); + +static void +mt7925_seq_puts_array(struct seq_file *file, const char *str, + s8 val[][2], int len, u8 band_idx) +{ + int i; + + seq_printf(file, "%-22s:", str); + for (i = 0; i < len; i++) + if (val[i][band_idx] == 127) + seq_printf(file, " %6s", "N.A"); + else + seq_printf(file, " %6d", val[i][band_idx]); + seq_puts(file, "\n"); +} + +#define mt7925_print_txpwr_entry(prefix, rate, idx) \ +({ \ + mt7925_seq_puts_array(s, #prefix " (tmac)", \ + txpwr->rate, \ + ARRAY_SIZE(txpwr->rate), \ + idx); \ +}) + +static inline void +mt7925_eht_txpwr(struct seq_file *s, struct mt7925_txpwr *txpwr, u8 band_idx) +{ + seq_printf(s, "%-22s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11", + "mcs12", "mcs13", "mcs14", "mcs15"); + mt7925_print_txpwr_entry(EHT26, eht26, band_idx); + mt7925_print_txpwr_entry(EHT52, eht52, band_idx); + mt7925_print_txpwr_entry(EHT106, eht106, band_idx); + mt7925_print_txpwr_entry(EHT242, eht242, band_idx); + mt7925_print_txpwr_entry(EHT484, eht484, band_idx); + + mt7925_print_txpwr_entry(EHT996, eht996, band_idx); + mt7925_print_txpwr_entry(EHT996x2, eht996x2, band_idx); + mt7925_print_txpwr_entry(EHT996x4, eht996x4, band_idx); + mt7925_print_txpwr_entry(EHT26_52, eht26_52, band_idx); + mt7925_print_txpwr_entry(EHT26_106, eht26_106, band_idx); + mt7925_print_txpwr_entry(EHT484_242, eht484_242, band_idx); + mt7925_print_txpwr_entry(EHT996_484, eht996_484, band_idx); + mt7925_print_txpwr_entry(EHT996_484_242, eht996_484_242, band_idx); + mt7925_print_txpwr_entry(EHT996x2_484, eht996x2_484, band_idx); + mt7925_print_txpwr_entry(EHT996x3, eht996x3, band_idx); + mt7925_print_txpwr_entry(EHT996x3_484, eht996x3_484, band_idx); +} + +static int +mt7925_txpwr(struct seq_file *s, void *data) +{ + struct mt792x_dev *dev = dev_get_drvdata(s->private); + struct mt7925_txpwr *txpwr = NULL; + u8 band_idx = dev->mphy.band_idx; + int ret = 0; + + txpwr = devm_kmalloc(dev->mt76.dev, sizeof(*txpwr), GFP_KERNEL); + + if (!txpwr) + return -ENOMEM; + + mt792x_mutex_acquire(dev); + ret = mt7925_get_txpwr_info(dev, band_idx, txpwr); + mt792x_mutex_release(dev); + + if (ret) + goto out; + + seq_printf(s, "%-22s %6s %6s %6s %6s\n", + " ", "1m", "2m", "5m", "11m"); + mt7925_print_txpwr_entry(CCK, cck, band_idx); + + seq_printf(s, "%-22s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "6m", "9m", "12m", "18m", "24m", "36m", + "48m", "54m"); + mt7925_print_txpwr_entry(OFDM, ofdm, band_idx); + + seq_printf(s, "%-22s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7"); + mt7925_print_txpwr_entry(HT20, ht20, band_idx); + + seq_printf(s, "%-22s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7", "mcs32"); + mt7925_print_txpwr_entry(HT40, ht40, band_idx); + + seq_printf(s, "%-22s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11"); + mt7925_print_txpwr_entry(VHT20, vht20, band_idx); + mt7925_print_txpwr_entry(VHT40, vht40, band_idx); + + mt7925_print_txpwr_entry(VHT80, vht80, band_idx); + mt7925_print_txpwr_entry(VHT160, vht160, band_idx); + + mt7925_print_txpwr_entry(HE26, he26, band_idx); + mt7925_print_txpwr_entry(HE52, he52, band_idx); + mt7925_print_txpwr_entry(HE106, he106, band_idx); + mt7925_print_txpwr_entry(HE242, he242, band_idx); + mt7925_print_txpwr_entry(HE484, he484, band_idx); + + mt7925_print_txpwr_entry(HE996, he996, band_idx); + mt7925_print_txpwr_entry(HE996x2, he996x2, band_idx); + + mt7925_eht_txpwr(s, txpwr, band_idx); + +out: + devm_kfree(dev->mt76.dev, txpwr); + return ret; +} + +static int +mt7925_pm_set(void *data, u64 val) +{ + struct mt792x_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; + + if (mt76_is_usb(&dev->mt76)) + return -EOPNOTSUPP; + + mutex_lock(&dev->mt76.mutex); + + if (val == pm->enable_user) + goto out; + + if (!pm->enable_user) { + pm->stats.last_wake_event = jiffies; + pm->stats.last_doze_event = jiffies; + } + /* make sure the chip is awake here and ps_work is scheduled + * just at end of the this routine. + */ + pm->enable = false; + mt76_connac_pm_wake(&dev->mphy, pm); + + pm->enable_user = val; + mt7925_set_runtime_pm(dev); + mt76_connac_power_save_sched(&dev->mphy, pm); +out: + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static int +mt7925_pm_get(void *data, u64 *val) +{ + struct mt792x_dev *dev = data; + + *val = dev->pm.enable_user; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7925_pm_get, mt7925_pm_set, "%lld\n"); + +static int +mt7925_deep_sleep_set(void *data, u64 val) +{ + struct mt792x_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; + bool monitor = !!(dev->mphy.hw->conf.flags & IEEE80211_CONF_MONITOR); + bool enable = !!val; + + if (mt76_is_usb(&dev->mt76)) + return -EOPNOTSUPP; + + mt792x_mutex_acquire(dev); + if (pm->ds_enable_user == enable) + goto out; + + pm->ds_enable_user = enable; + pm->ds_enable = enable && !monitor; + mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); +out: + mt792x_mutex_release(dev); + + return 0; +} + +static int +mt7925_deep_sleep_get(void *data, u64 *val) +{ + struct mt792x_dev *dev = data; + + *val = dev->pm.ds_enable_user; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_ds, mt7925_deep_sleep_get, + mt7925_deep_sleep_set, "%lld\n"); + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt792x_pm_idle_timeout_get, + mt792x_pm_idle_timeout_set, "%lld\n"); + +static int mt7925_chip_reset(void *data, u64 val) +{ + struct mt792x_dev *dev = data; + int ret = 0; + + switch (val) { + case 1: + /* Reset wifisys directly. */ + mt792x_reset(&dev->mt76); + break; + default: + /* Collect the core dump before reset wifisys. */ + mt792x_mutex_acquire(dev); + ret = mt7925_mcu_chip_config(dev, "assert"); + mt792x_mutex_release(dev); + break; + } + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7925_chip_reset, "%lld\n"); + +int mt7925_init_debugfs(struct mt792x_dev *dev) +{ + struct dentry *dir; + + dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval); + if (!dir) + return -ENOMEM; + + if (mt76_is_mmio(&dev->mt76)) + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", + dir, mt792x_queues_read); + else + debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", + dir, mt76_queues_read); + + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt792x_queues_acq); + debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir, + mt7925_txpwr); + debugfs_create_file("tx_stats", 0400, dir, dev, &mt792x_tx_stats_fops); + debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); + debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); + debugfs_create_file("idle-timeout", 0600, dir, dev, + &fops_pm_idle_timeout); + debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset); + debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir, + mt792x_pm_stats); + debugfs_create_file("deep-sleep", 0600, dir, dev, &fops_ds); + + return 0; +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/init.c b/sys/contrib/dev/mediatek/mt76/mt7925/init.c similarity index 55% copy from sys/contrib/dev/mediatek/mt76/mt7921/init.c copy to sys/contrib/dev/mediatek/mt76/mt7925/init.c index bb2e1eb8d684..c7ea94e9c803 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7925/init.c @@ -1,274 +1,327 @@ // SPDX-License-Identifier: ISC -/* Copyright (C) 2020 MediaTek Inc. */ +/* Copyright (C) 2023 MediaTek Inc. */ #include #include #include #include #include -#include "mt7921.h" -#include "../mt76_connac2_mac.h" +#include "mt7925.h" +#include "mac.h" #include "mcu.h" -#if defined(__linux__) -static ssize_t mt7921_thermal_temp_show(struct device *dev, +#if defined(CONFIG_HWMON) +static ssize_t mt7925_thermal_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { switch (to_sensor_dev_attr(attr)->index) { case 0: { struct mt792x_phy *phy = dev_get_drvdata(dev); struct mt792x_dev *mdev = phy->dev; int temperature; mt792x_mutex_acquire(mdev); - temperature = mt7921_mcu_get_temperature(phy); + temperature = mt7925_mcu_get_temperature(phy); mt792x_mutex_release(mdev); if (temperature < 0) return temperature; /* display in millidegree Celsius */ return sprintf(buf, "%u\n", temperature * 1000); } default: return -EINVAL; } } -static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7921_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7925_thermal_temp, 0); -static struct attribute *mt7921_hwmon_attrs[] = { +static struct attribute *mt7925_hwmon_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, NULL, }; -ATTRIBUTE_GROUPS(mt7921_hwmon); +ATTRIBUTE_GROUPS(mt7925_hwmon); -static int mt7921_thermal_init(struct mt792x_phy *phy) +static int mt7925_thermal_init(struct mt792x_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; struct device *hwmon; const char *name; if (!IS_REACHABLE(CONFIG_HWMON)) return 0; - name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7921_%s", + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7925_%s", wiphy_name(wiphy)); hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, - mt7921_hwmon_groups); - if (IS_ERR(hwmon)) - return PTR_ERR(hwmon); - - return 0; + mt7925_hwmon_groups); + return PTR_ERR_OR_ZERO(hwmon); } #endif +void mt7925_regd_update(struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_hw *hw = mdev->hw; + + if (!dev->regd_change) + return; + + mt7925_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env); + mt7925_mcu_set_channel_domain(hw->priv); + mt7925_set_tx_sar_pwr(hw, NULL); + dev->regd_change = false; +} +EXPORT_SYMBOL_GPL(mt7925_regd_update); + static void -mt7921_regd_notifier(struct wiphy *wiphy, - struct regulatory_request *request) +mt7925_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *req) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; + struct mt76_connac_pm *pm = &dev->pm; - memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); - dev->mt76.region = request->dfs_region; - dev->country_ie_env = request->country_ie_env; + /* allow world regdom at the first boot only */ + if (!memcmp(req->alpha2, "00", 2) && + mdev->alpha2[0] && mdev->alpha2[1]) + return; + + /* do not need to update the same country twice */ + if (!memcmp(req->alpha2, mdev->alpha2, 2) && + dev->country_ie_env == req->country_ie_env) + return; + + memcpy(mdev->alpha2, req->alpha2, 2); + mdev->region = req->dfs_region; + dev->country_ie_env = req->country_ie_env; + dev->regd_change = true; + if (pm->suspended) + return; + + dev->regd_in_progress = true; mt792x_mutex_acquire(dev); - mt7921_mcu_set_clc(dev, request->alpha2, request->country_ie_env); - mt76_connac_mcu_set_channel_domain(hw->priv); - mt7921_set_tx_sar_pwr(hw, NULL); + mt7925_regd_update(dev); mt792x_mutex_release(dev); + dev->regd_in_progress = false; + wake_up(&dev->wait); +} + +static void mt7925_mac_init_basic_rates(struct mt792x_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) { + u16 rate = mt76_rates[i].hw_value; + u16 idx = MT792x_BASIC_RATES_TBL + i; + + rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) | + FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0)); + mt7925_mac_set_fixed_rate_table(dev, idx, rate); + } } -int mt7921_mac_init(struct mt792x_dev *dev) +int mt7925_mac_init(struct mt792x_dev *dev) { int i; mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536); /* enable hardware de-agg */ mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN); - /* enable hardware rx header translation */ - mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN); for (i = 0; i < MT792x_WTBL_SIZE; i++) - mt7921_mac_wtbl_update(dev, i, + mt7925_mac_wtbl_update(dev, i, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); for (i = 0; i < 2; i++) mt792x_mac_init_band(dev, i); - return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0); + mt7925_mac_init_basic_rates(dev); + + memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); + + return 0; } -EXPORT_SYMBOL_GPL(mt7921_mac_init); +EXPORT_SYMBOL_GPL(mt7925_mac_init); -static int __mt7921_init_hardware(struct mt792x_dev *dev) +static int __mt7925_init_hardware(struct mt792x_dev *dev) { 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 = mt792x_mcu_init(dev); if (ret) goto out; mt76_eeprom_override(&dev->mphy); - ret = mt7921_mcu_set_eeprom(dev); + ret = mt7925_mcu_set_eeprom(dev); + if (ret) + goto out; + + ret = mt7925_mac_init(dev); if (ret) goto out; - ret = mt7921_mac_init(dev); out: return ret; } -static int mt7921_init_hardware(struct mt792x_dev *dev) +static int mt7925_init_hardware(struct mt792x_dev *dev) { int ret, i; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); for (i = 0; i < MT792x_MCU_INIT_RETRY_COUNT; i++) { - ret = __mt7921_init_hardware(dev); + ret = __mt7925_init_hardware(dev); if (!ret) break; mt792x_init_reset(dev); } if (i == MT792x_MCU_INIT_RETRY_COUNT) { dev_err(dev->mt76.dev, "hardware init failed\n"); return ret; } return 0; } -static void mt7921_init_work(struct work_struct *work) +static void mt7925_init_work(struct work_struct *work) { struct mt792x_dev *dev = container_of(work, struct mt792x_dev, init_work); int ret; - ret = mt7921_init_hardware(dev); + ret = mt7925_init_hardware(dev); if (ret) return; mt76_set_stream_caps(&dev->mphy, true); - mt7921_set_stream_he_caps(&dev->phy); + mt7925_set_stream_he_eht_caps(&dev->phy); + mt792x_config_mac_addr_list(dev); + + ret = mt7925_init_mlo_caps(&dev->phy); + if (ret) { + dev_err(dev->mt76.dev, "MLO init failed\n"); + return; + } ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) { dev_err(dev->mt76.dev, "register device failed\n"); return; } -#if !defined(__FreeBSD__) || defined(CONFIG_MT7921_DEBUGFS) - ret = mt7921_init_debugfs(dev); +#if !defined(__FreeBSD__) || defined(CONFIG_MT7925_DEBUGFS) + ret = mt7925_init_debugfs(dev); if (ret) { dev_err(dev->mt76.dev, "register debugfs failed\n"); return; } #endif -#if defined(__linux__) - ret = mt7921_thermal_init(&dev->phy); +#if defined(CONFIG_HWMON) + ret = mt7925_thermal_init(&dev->phy); if (ret) { dev_err(dev->mt76.dev, "thermal init failed\n"); return; } #endif /* we support chip reset now */ dev->hw_init_done = true; - mt76_connac_mcu_set_deep_sleep(&dev->mt76, dev->pm.ds_enable); + mt7925_mcu_set_deep_sleep(dev, dev->pm.ds_enable); } -int mt7921_register_device(struct mt792x_dev *dev) +int mt7925_register_device(struct mt792x_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); int ret; dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; dev->mt76.tx_worker.fn = mt792x_tx_worker; INIT_DELAYED_WORK(&dev->pm.ps_work, mt792x_pm_power_save_work); INIT_WORK(&dev->pm.wake_work, mt792x_pm_wake_work); 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); + init_waitqueue_head(&dev->wait); spin_lock_init(&dev->pm.txq_lock); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt792x_mac_work); - INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work); - INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work); + INIT_DELAYED_WORK(&dev->phy.scan_work, mt7925_scan_work); + INIT_DELAYED_WORK(&dev->coredump.work, mt7925_coredump_work); #if IS_ENABLED(CONFIG_IPV6) - INIT_WORK(&dev->ipv6_ns_work, mt7921_set_ipv6_ns_work); + INIT_WORK(&dev->ipv6_ns_work, mt7925_set_ipv6_ns_work); skb_queue_head_init(&dev->ipv6_ns_list); #endif skb_queue_head_init(&dev->phy.scan_event_list); skb_queue_head_init(&dev->coredump.msg_list); - INIT_WORK(&dev->reset_work, mt7921_mac_reset_work); - INIT_WORK(&dev->init_work, mt7921_init_work); + INIT_WORK(&dev->reset_work, mt7925_mac_reset_work); + INIT_WORK(&dev->init_work, mt7925_init_work); - INIT_WORK(&dev->phy.roc_work, mt7921_roc_work); + INIT_WORK(&dev->phy.roc_work, mt7925_roc_work); timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0); init_waitqueue_head(&dev->phy.roc_wait); dev->pm.idle_timeout = MT792x_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; if (!mt76_is_usb(&dev->mt76)) { dev->pm.enable_user = true; dev->pm.enable = true; dev->pm.ds_enable_user = true; dev->pm.ds_enable = true; } if (!mt76_is_mmio(&dev->mt76)) hw->extra_tx_headroom += MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE; mt792x_init_acpi_sar(dev); ret = mt792x_init_wcid(dev); if (ret) return ret; ret = mt792x_init_wiphy(hw); if (ret) return ret; - hw->wiphy->reg_notifier = mt7921_regd_notifier; + hw->wiphy->reg_notifier = mt7925_regd_notifier; dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_2; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING | IEEE80211_HT_CAP_MAX_AMSDU; + dev->mphy.sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_1; dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); - if (is_mt7922(&dev->mt76)) - dev->mphy.sband_5g.sband.vht_cap.cap |= + dev->mphy.sband_5g.sband.vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_SHORT_GI_160; dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; queue_work(system_wq, &dev->init_work); return 0; } -EXPORT_SYMBOL_GPL(mt7921_register_device); +EXPORT_SYMBOL_GPL(mt7925_register_device); diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/mac.c b/sys/contrib/dev/mediatek/mt76/mt7925/mac.c new file mode 100644 index 000000000000..e00e7407410f --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/mac.c @@ -0,0 +1,1499 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include +#include +#include +#include "mt7925.h" +#include "../dma.h" +#include "mac.h" +#include "mcu.h" + +bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + +static void mt7925_mac_sta_poll(struct mt792x_dev *dev) +{ + static const u8 ac_to_tid[] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; + u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; + LIST_HEAD(sta_poll_list); + struct rate_info *rate; + s8 rssi[4]; + int i; + + spin_lock_bh(&dev->mt76.sta_poll_lock); + list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + + while (true) { + bool clear = false; + u32 addr, val; + u16 idx; + u8 bw; + + if (list_empty(&sta_poll_list)) + break; + mlink = list_first_entry(&sta_poll_list, + struct mt792x_link_sta, wcid.poll_list); + msta = mlink->sta; + spin_lock_bh(&dev->mt76.sta_poll_lock); + list_del_init(&mlink->wcid.poll_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + + idx = mlink->wcid.idx; + addr = mt7925_mac_wtbl_lmac_addr(dev, idx, MT_WTBL_AC0_CTT_OFFSET); + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u32 tx_last = mlink->airtime_ac[i]; + u32 rx_last = mlink->airtime_ac[i + 4]; + + mlink->airtime_ac[i] = mt76_rr(dev, addr); + mlink->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + + tx_time[i] = mlink->airtime_ac[i] - tx_last; + rx_time[i] = mlink->airtime_ac[i + 4] - rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + + addr += 8; + } + + if (clear) { + mt7925_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); + } + + if (!mlink->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u8 q = mt76_connac_lmac_mapping(i); + u32 tx_cur = tx_time[q]; + u32 rx_cur = rx_time[q]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + 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 = &mlink->wcid.rate; + + 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; + } + + addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 6); + val = mt76_rr(dev, addr); + if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { + addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 5); + val = mt76_rr(dev, addr); + rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); + } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { + u8 offs = MT_WTBL_TXRX_RATE_G2_HE + 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(MT_WTBL_TXRX_RATE_G2 + bw)) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + } + + /* get signal strength of resp frames (CTS/BA/ACK) */ + addr = mt7925_mac_wtbl_lmac_addr(dev, idx, 34); + val = mt76_rr(dev, addr); + + rssi[0] = to_rssi(GENMASK(7, 0), val); + rssi[1] = to_rssi(GENMASK(15, 8), val); + rssi[2] = to_rssi(GENMASK(23, 16), val); + rssi[3] = to_rssi(GENMASK(31, 14), val); + + mlink->ack_signal = + mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); + + ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal); + } +} + +void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev, + u8 tbl_idx, u16 rate_idx) +{ + u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; + + mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); + /* use wtbl spe idx */ + mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); + mt76_wr(dev, MT_WTBL_ITCR, ctrl); +} + +/* The HW does not translate the mac header to 802.3 for mesh point */ +static int mt7925_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); + struct mt792x_sta *msta = (struct mt792x_sta *)status->wcid; + __le32 *rxd = (__le32 *)skb->data; + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + struct ieee80211_hdr hdr; + u16 frame_control; + + if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != + MT_RXD3_NORMAL_U2M) + return -EINVAL; + + if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) + return -EINVAL; + + if (!msta || !msta->vif) + return -EINVAL; + + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + + /* store the info from RXD and ethhdr to avoid being overridden */ + frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL); + hdr.frame_control = cpu_to_le16(frame_control); + hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL)); + hdr.duration_id = 0; + + ether_addr_copy(hdr.addr1, vif->addr); + ether_addr_copy(hdr.addr2, sta->addr); + switch (frame_control & (IEEE80211_FCTL_TODS | + IEEE80211_FCTL_FROMDS)) { + case 0: + ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); + break; + case IEEE80211_FCTL_FROMDS: + ether_addr_copy(hdr.addr3, eth_hdr->h_source); + break; + case IEEE80211_FCTL_TODS: + ether_addr_copy(hdr.addr3, eth_hdr->h_dest); + break; + case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: + ether_addr_copy(hdr.addr3, eth_hdr->h_dest); + ether_addr_copy(hdr.addr4, eth_hdr->h_source); + break; + default: + break; + } + + skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); + if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || + eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) + ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); + else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) + ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); + else + skb_pull(skb, 2); + + if (ieee80211_has_order(hdr.frame_control)) + memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11], + IEEE80211_HT_CTL_LEN); + if (ieee80211_is_data_qos(hdr.frame_control)) { + __le16 qos_ctrl; + + qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL)); + memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, + IEEE80211_QOS_CTL_LEN); + } + + if (ieee80211_has_a4(hdr.frame_control)) + memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); + else + memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); + + return 0; +} + +static int +mt7925_mac_fill_rx_rate(struct mt792x_dev *dev, + struct mt76_rx_status *status, + struct ieee80211_supported_band *sband, + __le32 *rxv, u8 *mode) +{ + u32 v0, v2; + u8 stbc, gi, bw, dcm, nss; + int i, idx; + bool cck = false; + + v0 = le32_to_cpu(rxv[0]); + v2 = le32_to_cpu(rxv[2]); + + idx = FIELD_GET(MT_PRXV_TX_RATE, v0); + i = idx; + nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; + + stbc = FIELD_GET(MT_PRXV_HT_STBC, v2); + gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2); + *mode = FIELD_GET(MT_PRXV_TX_MODE, v2); + dcm = FIELD_GET(MT_PRXV_DCM, v2); + bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2); + + switch (*mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + i = mt76_get_rate(&dev->mt76, sband, i, cck); + break; + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_HT: + status->encoding = RX_ENC_HT; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + if (i > 31) + return -EINVAL; + break; + case MT_PHY_TYPE_VHT: + status->nss = nss; + status->encoding = RX_ENC_VHT; + if (gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + if (i > 11) + return -EINVAL; + break; + case MT_PHY_TYPE_HE_MU: + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + status->nss = nss; + status->encoding = RX_ENC_HE; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_HE_GI_3_2) + status->he_gi = gi; + + status->he_dcm = dcm; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + status->nss = nss; + status->encoding = RX_ENC_EHT; + i &= GENMASK(3, 0); + + if (gi <= NL80211_RATE_INFO_EHT_GI_3_2) + status->eht.gi = gi; + break; + default: + return -EINVAL; + } + status->rate_idx = i; + + switch (bw) { + case IEEE80211_STA_RX_BW_20: + break; + case IEEE80211_STA_RX_BW_40: + if (*mode & MT_PHY_TYPE_HE_EXT_SU && + (idx & MT_PRXV_TX_ER_SU_106T)) { + status->bw = RATE_INFO_BW_HE_RU; + status->he_ru = + NL80211_RATE_INFO_HE_RU_ALLOC_106; + } else { + status->bw = RATE_INFO_BW_40; + } + break; + case IEEE80211_STA_RX_BW_80: + status->bw = RATE_INFO_BW_80; + break; + case IEEE80211_STA_RX_BW_160: + status->bw = RATE_INFO_BW_160; + break; + default: + return -EINVAL; + } + + status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; + if (*mode < MT_PHY_TYPE_HE_SU && gi) + status->enc_flags |= RX_ENC_FLAG_SHORT_GI; + + return 0; +} + +static int +mt7925_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) +{ + u32 csum_mask = MT_RXD3_NORMAL_IP_SUM | MT_RXD3_NORMAL_UDP_TCP_SUM; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + bool hdr_trans, unicast, insert_ccmp_hdr = false; + u8 chfreq, qos_ctl = 0, remove_pad, amsdu_info; + u16 hdr_gap; + __le32 *rxv = NULL, *rxd = (__le32 *)skb->data; + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt792x_phy *phy = &dev->phy; + struct ieee80211_supported_band *sband; + u32 csum_status = *(u32 *)skb->cb; + u32 rxd1 = le32_to_cpu(rxd[1]); + u32 rxd2 = le32_to_cpu(rxd[2]); + u32 rxd3 = le32_to_cpu(rxd[3]); + u32 rxd4 = le32_to_cpu(rxd[4]); + struct mt792x_link_sta *mlink; + u8 mode = 0; /* , band_idx; */ + u16 seq_ctrl = 0; + __le16 fc = 0; + int idx; + + memset(status, 0, sizeof(*status)); + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return -EINVAL; + + if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) + return -EINVAL; + + hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; + if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) + return -EINVAL; + + /* ICV error or CCMP/BIP/WPI MIC error */ + if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) + status->flag |= RX_FLAG_ONLY_MONITOR; + + chfreq = FIELD_GET(MT_RXD3_NORMAL_CH_FREQ, rxd3); + unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; + idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); + status->wcid = mt792x_rx_get_wcid(dev, idx, unicast); + + if (status->wcid) { + mlink = container_of(status->wcid, struct mt792x_link_sta, wcid); + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); + } + + mt792x_get_status_freq_info(status, chfreq); + + switch (status->band) { + case NL80211_BAND_5GHZ: + sband = &mphy->sband_5g.sband; + break; + case NL80211_BAND_6GHZ: + sband = &mphy->sband_6g.sband; + break; + default: + sband = &mphy->sband_2g.sband; + break; + } + + if (!sband->channels) + return -EINVAL; + + if (mt76_is_mmio(&dev->mt76) && (rxd3 & csum_mask) == csum_mask && + !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + + if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) + status->flag |= RX_FLAG_MMIC_ERROR; + + if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && + !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED; + status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; + } + + remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); + + if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) + return -EINVAL; + + rxd += 8; + if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { + u32 v0 = le32_to_cpu(rxd[0]); + u32 v2 = le32_to_cpu(rxd[2]); + + /* TODO: need to map rxd address */ + fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0)); + seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2); + qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2); + + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { + u8 *data = (u8 *)rxd; + + if (status->flag & RX_FLAG_DECRYPTED) { + switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { + case MT_CIPHER_AES_CCMP: + case MT_CIPHER_CCMP_CCX: + case MT_CIPHER_CCMP_256: + insert_ccmp_hdr = + FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); + fallthrough; + case MT_CIPHER_TKIP: + case MT_CIPHER_TKIP_NO_MIC: + case MT_CIPHER_GCMP: + case MT_CIPHER_GCMP_256: + status->iv[0] = data[5]; + status->iv[1] = data[4]; + status->iv[2] = data[3]; + status->iv[3] = data[2]; + status->iv[4] = data[1]; + status->iv[5] = data[0]; + break; + default: + break; + } + } + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { + status->timestamp = le32_to_cpu(rxd[0]); + status->flag |= RX_FLAG_MACTIME_START; + + if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (phy->rx_ampdu_ts != status->timestamp) { + if (!++phy->ampdu_ref) + phy->ampdu_ref++; + } + phy->rx_ampdu_ts = status->timestamp; + + status->ampdu_ref = phy->ampdu_ref; + } + + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + /* RXD Group 3 - P-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { + u32 v3; + int ret; + + rxv = rxd; + rxd += 4; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + + v3 = le32_to_cpu(rxv[3]); + + status->chains = mphy->antenna_mask; + status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3); + status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3); + status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3); + status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3); + + /* RXD Group 5 - C-RXV */ + if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { + rxd += 24; + if ((u8 *)rxd - skb->data >= skb->len) + return -EINVAL; + } + + ret = mt7925_mac_fill_rx_rate(dev, status, sband, rxv, &mode); + if (ret < 0) + return ret; + } + + amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); + status->amsdu = !!amsdu_info; + if (status->amsdu) { + status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; + status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; + } + + hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; + if (hdr_trans && ieee80211_has_morefrags(fc)) { + if (mt7925_reverse_frag0_hdr_trans(skb, hdr_gap)) + return -EINVAL; + hdr_trans = false; + } else { + int pad_start = 0; + + skb_pull(skb, hdr_gap); + if (!hdr_trans && status->amsdu) { + pad_start = ieee80211_get_hdrlen_from_skb(skb); + } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { + /* When header translation failure is indicated, + * the hardware will insert an extra 2-byte field + * containing the data length after the protocol + * type field. + */ + pad_start = 12; + if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) + pad_start += 4; + else + pad_start = 0; + } + + if (pad_start) { + memmove(skb->data + 2, skb->data, pad_start); + skb_pull(skb, 2); + } + } + + if (!hdr_trans) { + struct ieee80211_hdr *hdr; + + if (insert_ccmp_hdr) { + u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); + + mt76_insert_ccmp_hdr(skb, key_id); + } + + hdr = mt76_skb_get_hdr(skb); + fc = hdr->frame_control; + if (ieee80211_is_data_qos(fc)) { + seq_ctrl = le16_to_cpu(hdr->seq_ctrl); + qos_ctl = *ieee80211_get_qos_ctl(hdr); + } + skb_set_mac_header(skb, (unsigned char *)hdr - skb->data); + } else { + status->flag |= RX_FLAG_8023; + } + + mt792x_mac_assoc_rssi(dev, skb); + + if (rxv && !(status->flag & RX_FLAG_8023)) { + switch (status->encoding) { + case RX_ENC_EHT: + mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode); + break; + case RX_ENC_HE: + mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); + break; + default: + break; + } + } + + if (!status->wcid || !ieee80211_is_data_qos(fc)) + return 0; + + status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); + status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); + status->qos_ctl = qos_ctl; + + return 0; +} + +static void +mt7925_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb, + struct mt76_wcid *wcid) +{ + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + u8 fc_type, fc_stype; + u16 ethertype; + bool wmm = false; + u32 val; + + if (wcid->sta) { + struct ieee80211_sta *sta; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + wmm = sta->wme; + } + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | + FIELD_PREP(MT_TXD1_TID, tid); + + ethertype = get_unaligned_be16(&skb->data[12]); + if (ethertype >= ETH_P_802_3_MIN) + val |= MT_TXD1_ETH_802_3; + + txwi[1] |= cpu_to_le32(val); + + fc_type = IEEE80211_FTYPE_DATA >> 2; + fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); + + txwi[2] |= cpu_to_le32(val); +} + +static void +mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, + struct ieee80211_key_conf *key) +{ + 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; + + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) + tid = MT_TX_ADDBA; + else if (ieee80211_is_mgmt(hdr->frame_control)) + tid = MT_TX_NORMAL; + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | + FIELD_PREP(MT_TXD1_HDR_INFO, + ieee80211_get_hdrlen_from_skb(skb) / 2) | + FIELD_PREP(MT_TXD1_TID, tid); + + if (!ieee80211_is_data(fc) || multicast || + info->flags & IEEE80211_TX_CTL_USE_MINRATE) + val |= MT_TXD1_FIXED_RATE; + + if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD1_BIP; + txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + + txwi[1] |= cpu_to_le32(val); + + fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; + fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; + + val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | + FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); + + txwi[2] |= cpu_to_le32(val); + + txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast)); + if (ieee80211_is_beacon(fc)) + txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); + + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + u16 seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; + + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val = MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); + txwi[3] |= cpu_to_le32(val); + txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); + } +} + +void +mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, int pid, + enum mt76_txq_id qid, u32 changed) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_vif *vif = info->control.vif; + u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0, band_idx = 0; + u32 val, sz_txd = mt76_is_mmio(dev) ? MT_TXD_SIZE : MT_SDIO_TXD_SIZE; + bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + struct mt76_vif_link *mvif; + bool beacon = !!(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)); + bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | + BSS_CHANGED_FILS_DISCOVERY)); + struct mt792x_bss_conf *mconf; + + mconf = vif ? mt792x_vif_to_link((struct mt792x_vif *)vif->drv_priv, + wcid->link_id) : NULL; + mvif = mconf ? (struct mt76_vif_link *)&mconf->mt76 : NULL; + + if (mvif) { + omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; + band_idx = mvif->band_idx; + } + + if (inband_disc) { + p_fmt = MT_TX_TYPE_FW; + q_idx = MT_LMAC_ALTX0; + } else if (beacon) { + p_fmt = MT_TX_TYPE_FW; + q_idx = MT_LMAC_BCN0; + } else if (qid >= MT_TXQ_PSD) { + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + q_idx = MT_LMAC_ALTX0; + } else { + p_fmt = mt76_is_mmio(dev) ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; + q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS + + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); + + /* counting non-offloading skbs */ + wcid->stats.tx_bytes += skb->len; + wcid->stats.tx_packets++; + } + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) | + FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | + FIELD_PREP(MT_TXD0_Q_IDX, q_idx); + txwi[0] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | + FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + + if (band_idx) + val |= FIELD_PREP(MT_TXD1_TGID, band_idx); + + txwi[1] = cpu_to_le32(val); + txwi[2] = 0; + + val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); + + if (key) + val |= MT_TXD3_PROTECT_FRAME; + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + val |= MT_TXD3_NO_ACK; + if (wcid->amsdu) + val |= MT_TXD3_HW_AMSDU; + + txwi[3] = cpu_to_le32(val); + txwi[4] = 0; + + val = FIELD_PREP(MT_TXD5_PID, pid); + if (pid >= MT_PACKET_ID_FIRST) { + val |= MT_TXD5_TX_STATUS_HOST; + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); + } + + txwi[5] = cpu_to_le32(val); + + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + if (!ieee80211_vif_is_mld(vif) || + (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) + val |= MT_TXD6_DIS_MAT; + txwi[6] = cpu_to_le32(val); + txwi[7] = 0; + + if (is_8023) + mt7925_mac_write_txwi_8023(txwi, skb, wcid); + else + mt7925_mac_write_txwi_80211(dev, txwi, skb, key); + + if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool mcast = ieee80211_is_data(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr1); + u8 idx = MT792x_BASIC_RATES_TBL; + + if (mvif) { + if (mcast && mvif->mcast_rates_idx) + idx = mvif->mcast_rates_idx; + else if (beacon && mvif->beacon_rates_idx) + idx = mvif->beacon_rates_idx; + else + idx = mvif->basic_rates_idx; + } + + txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); + } +} +EXPORT_SYMBOL_GPL(mt7925_mac_write_txwi); + +static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, + struct mt76_wcid *wcid) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + bool is_8023; + u16 fc, tid; + + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + return; + + if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) + return; + + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; + is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + + if (is_8023) { + fc = IEEE80211_FTYPE_DATA | + (sta->wme ? IEEE80211_STYPE_QOS_DATA : + IEEE80211_STYPE_DATA); + } else { + /* No need to get precise TID for Action/Management Frame, + * since it will not meet the following Frame Control + * condition anyway. + */ + + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + fc = le16_to_cpu(hdr->frame_control) & + (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + } + + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) + return; + + msta = (struct mt792x_sta *)sta->drv_priv; + + if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) + mlink = rcu_dereference(msta->link[msta->deflink_id]); + else + mlink = &msta->deflink; + + if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) + ieee80211_start_tx_ba_session(sta, tid, 0); +} + +static bool +mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid, + int pid, __le32 *txs_data) +{ + struct mt76_sta_stats *stats = &wcid->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, stbc; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out_no_skb; + + txs = le32_to_cpu(txs_data[0]); + + info = IEEE80211_SKB_CB(skb); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + + 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; + stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC); + + if (stbc && rate.nss > 1) + rate.nss >>= 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 = mt76_dev_phy(mdev, wcid->phy_idx); + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) + sband = &mphy->sband_6g.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: + 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; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (rate.mcs > 13) + goto out; + + rate.eht_gi = wcid->rate.eht_gi; + rate.flags = RATE_INFO_FLAGS_EHT_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; +} + +void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) +{ + struct mt792x_link_sta *mlink = NULL; + struct mt76_wcid *wcid; + __le32 *txs_data = data; + u16 wcidx; + u8 pid; + + if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1) + return; + + wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); + pid = le32_get_bits(txs_data[3], MT_TXS3_PID); + + if (pid < MT_PACKET_ID_FIRST) + return; + + if (wcidx >= MT792x_WTBL_SIZE) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + if (!wcid) + goto out; + + mlink = container_of(wcid, struct mt792x_link_sta, wcid); + + mt7925_mac_add_txs_skb(dev, wcid, pid, txs_data); + if (!wcid->sta) + goto out; + + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); + +out: + rcu_read_unlock(); +} + +void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, + struct list_head *free_list) +{ + struct mt76_dev *mdev = &dev->mt76; + __le32 *txwi; + u16 wcid_idx; + + mt76_connac_txp_skb_unmap(mdev, t); + if (!t->skb) + goto out; + + txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); + if (sta) { + if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt7925_tx_check_aggr(sta, t->skb, wcid); + + wcid_idx = wcid->idx; + } else { + wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); + } + + __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); +out: + t->skb = NULL; + mt76_put_txwi(mdev, t); +} +EXPORT_SYMBOL_GPL(mt7925_txwi_free); + +static void +mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len) +{ + __le32 *tx_free = (__le32 *)data, *cur_info; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_txwi_cache *txwi; + struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; + LIST_HEAD(free_list); + struct sk_buff *skb, *tmp; +#if defined(__linux__) + void *end = data + len; +#elif defined(__FreeBSD__) + void *end = (u8 *)data + len; +#endif + bool wake = false; + u16 total, count = 0; + + /* 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); + + if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4)) + return; + + total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT); + for (cur_info = &tx_free[2]; count < total; cur_info++) { + u32 msdu, info; + u8 i; + + if (WARN_ON_ONCE((void *)cur_info >= end)) + return; + /* 1'b1: new wcid pair. + * 1'b0: msdu_id with the same 'wcid pair' as above. + */ + info = le32_to_cpu(*cur_info); + if (info & MT_TXFREE_INFO_PAIR) { + struct mt792x_link_sta *mlink; + u16 idx; + + idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); + wcid = rcu_dereference(dev->mt76.wcid[idx]); + sta = wcid_to_sta(wcid); + if (!sta) + continue; + + mlink = container_of(wcid, struct mt792x_link_sta, wcid); + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); + continue; + } + + if (info & MT_TXFREE_INFO_HEADER) { + if (wcid) { + wcid->stats.tx_retries += + FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1; + wcid->stats.tx_failed += + !!FIELD_GET(MT_TXFREE_INFO_STAT, info); + } + continue; + } + + for (i = 0; i < 2; i++) { + msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID; + if (msdu == MT_TXFREE_INFO_MSDU_ID) + continue; + + count++; + txwi = mt76_token_release(mdev, msdu, &wake); + if (!txwi) + continue; + + mt7925_txwi_free(dev, txwi, sta, wcid, &free_list); + } + } + + mt7925_mac_sta_poll(dev); + + if (wake) + mt76_set_tx_blocked(&dev->mt76, false); + + mt76_worker_schedule(&dev->mt76.tx_worker); + + list_for_each_entry_safe(skb, tmp, &free_list, list) { + skb_list_del_init(skb); + napi_consume_skb(skb, 1); + } +} + +bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + __le32 *rxd = (__le32 *)data; + __le32 *end = (__le32 *)&rxd[len / 4]; + enum rx_pkt_type type; + + type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); + if (type != PKT_TYPE_NORMAL) { + u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); + + if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == + MT_RXD0_SW_PKT_TYPE_FRAME)) + return true; + } + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ + mt7925_mac_tx_free(dev, data, len); /* mmio */ + return false; + case PKT_TYPE_TXS: + for (rxd += 4; rxd + 12 <= end; rxd += 12) + mt7925_mac_add_txs(dev, rxd); + return false; + default: + return true; + } +} +EXPORT_SYMBOL_GPL(mt7925_rx_check); + +void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + __le32 *rxd = (__le32 *)skb->data; + __le32 *end = (__le32 *)&skb->data[skb->len]; + enum rx_pkt_type type; + u16 flag; + + type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); + flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG); + if (type != PKT_TYPE_NORMAL) { + u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); + + if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == + MT_RXD0_SW_PKT_TYPE_FRAME)) + type = PKT_TYPE_NORMAL; + } + + if (type == PKT_TYPE_RX_EVENT && flag == 0x1) + type = PKT_TYPE_NORMAL_MCU; + + switch (type) { + case PKT_TYPE_TXRX_NOTIFY: + /* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */ + mt7925_mac_tx_free(dev, skb->data, skb->len); + napi_consume_skb(skb, 1); + break; + case PKT_TYPE_RX_EVENT: + mt7925_mcu_rx_event(dev, skb); + break; + case PKT_TYPE_TXS: + for (rxd += 2; rxd + 8 <= end; rxd += 8) + mt7925_mac_add_txs(dev, rxd); + dev_kfree_skb(skb); + break; + case PKT_TYPE_NORMAL_MCU: + case PKT_TYPE_NORMAL: + if (!mt7925_mac_fill_rx(dev, skb)) { + mt76_rx(&dev->mt76, q, skb); + return; + } + fallthrough; + default: + dev_kfree_skb(skb); + break; + } +} +EXPORT_SYMBOL_GPL(mt7925_queue_rx_skb); + +static void +mt7925_vif_connect_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct mt792x_dev *dev = mvif->phy->dev; + struct ieee80211_hw *hw = mt76_hw(dev); + struct ieee80211_bss_conf *bss_conf; + struct mt792x_bss_conf *mconf; + int i; + + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_disconnect(vif, true); + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mconf = mt792x_vif_to_link(mvif, i); + + mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76, + &mvif->sta.deflink.wcid, true); + mt7925_mcu_set_tx(dev, bss_conf); + } + + if (vif->type == NL80211_IFTYPE_AP) { + mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, + true, NULL); + mt7925_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_NONE); + mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); + } +} + +/* system error recovery */ +void mt7925_mac_reset_work(struct work_struct *work) +{ + struct mt792x_dev *dev = container_of(work, struct mt792x_dev, + reset_work); + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_connac_pm *pm = &dev->pm; + int i, ret; + + dev_dbg(dev->mt76.dev, "chip reset\n"); + dev->hw_full_reset = true; + ieee80211_stop_queues(hw); + + cancel_delayed_work_sync(&dev->mphy.mac_work); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + dev->sar_inited = false; + + for (i = 0; i < 10; i++) { + mutex_lock(&dev->mt76.mutex); + ret = mt792x_dev_reset(dev); + mutex_unlock(&dev->mt76.mutex); + + if (!ret) + break; + } + + if (i == 10) + dev_err(dev->mt76.dev, "chip reset failed\n"); + + if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(dev->mphy.hw, &info); + } + + dev->hw_full_reset = false; + pm->suspended = false; + ieee80211_wake_queues(hw); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_vif_connect_iter, NULL); + mt76_connac_power_save_sched(&dev->mt76.phy, pm); +} + +void mt7925_coredump_work(struct work_struct *work) +{ + struct mt792x_dev *dev; + char *dump, *data; + + dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, + coredump.work.work); + + if (time_is_after_jiffies(dev->coredump.last_activity + + 4 * MT76_CONNAC_COREDUMP_TIMEOUT)) { + queue_delayed_work(dev->mt76.wq, &dev->coredump.work, + MT76_CONNAC_COREDUMP_TIMEOUT); + return; + } + + dump = vzalloc(MT76_CONNAC_COREDUMP_SZ); + data = dump; + + while (true) { + struct sk_buff *skb; + + spin_lock_bh(&dev->mt76.lock); + skb = __skb_dequeue(&dev->coredump.msg_list); + spin_unlock_bh(&dev->mt76.lock); + + if (!skb) + break; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 8); + if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) { + dev_kfree_skb(skb); + continue; + } + + memcpy(data, skb->data, skb->len); + data += skb->len; + + dev_kfree_skb(skb); + } + + if (dump) + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); + + mt792x_reset(&dev->mt76); +} + +/* usb_sdio */ +static void +mt7925_usb_sdio_write_txwi(struct mt792x_dev *dev, struct mt76_wcid *wcid, + enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int pid, + struct sk_buff *skb) +{ + __le32 *txwi = (__le32 *)(skb->data - MT_SDIO_TXD_SIZE); + + memset(txwi, 0, MT_SDIO_TXD_SIZE); + mt7925_mac_write_txwi(&dev->mt76, txwi, skb, wcid, key, pid, qid, 0); + skb_push(skb, MT_SDIO_TXD_SIZE); +} + +int mt7925_usb_sdio_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 mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); + struct ieee80211_key_conf *key = info->control.hw_key; + struct sk_buff *skb = tx_info->skb; + int err, pad, pktid; + + if (unlikely(tx_info->skb->len <= ETH_HLEN)) + return -EINVAL; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + if (sta) { + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { + info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; + msta->deflink.last_txs = jiffies; + } + } + + pktid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + mt7925_usb_sdio_write_txwi(dev, wcid, qid, sta, key, pktid, skb); + + mt792x_skb_add_usb_sdio_hdr(dev, skb, 0); + pad = round_up(skb->len, 4) - skb->len; + if (mt76_is_usb(mdev)) + pad += 4; + + err = mt76_skb_adjust_pad(skb, pad); + if (err) + /* Release pktid in case of error. */ + idr_remove(&wcid->pktid, pktid); + + return err; +} +EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_prepare_skb); + +void mt7925_usb_sdio_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 = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); + wcid = rcu_dereference(mdev->wcid[idx]); + sta = wcid_to_sta(wcid); + + if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) + mt76_connac2_tx_check_aggr(sta, txwi); + + skb_pull(e->skb, headroom); + mt76_tx_complete_skb(mdev, e->wcid, e->skb); +} +EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_complete_skb); + +bool mt7925_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + + mt792x_mutex_acquire(dev); + mt7925_mac_sta_poll(dev); + mt792x_mutex_release(dev); + + return false; +} +EXPORT_SYMBOL_GPL(mt7925_usb_sdio_tx_status_data); + +#if IS_ENABLED(CONFIG_IPV6) +void mt7925_set_ipv6_ns_work(struct work_struct *work) +{ + struct mt792x_dev *dev = container_of(work, struct mt792x_dev, + ipv6_ns_work); + struct sk_buff *skb; + int ret = 0; + + do { + skb = skb_dequeue(&dev->ipv6_ns_list); + + if (!skb) + break; + + mt792x_mutex_acquire(dev); + ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(OFFLOAD), true); + mt792x_mutex_release(dev); + + } while (!ret); + + if (ret) + skb_queue_purge(&dev->ipv6_ns_list); +} +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/mac.h b/sys/contrib/dev/mediatek/mt76/mt7925/mac.h new file mode 100644 index 000000000000..b10a993326b9 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/mac.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2023 MediaTek Inc. */ + +#ifndef __MT7925_MAC_H +#define __MT7925_MAC_H + +#include "../mt76_connac3_mac.h" + +#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 mt7925_mac_wtbl_lmac_addr(struct mt792x_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, dw); +} + +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/main.c b/sys/contrib/dev/mediatek/mt76/mt7925/main.c new file mode 100644 index 000000000000..98daf80ac131 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/main.c @@ -0,0 +1,2209 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include +#include +#include +#include +#include +#include +#include "mt7925.h" +#include "mcu.h" +#include "mac.h" + +static void +mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, + struct ieee80211_sband_iftype_data *data, + enum nl80211_iftype iftype) +{ + struct ieee80211_sta_he_cap *he_cap = &data->he_cap; + struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; + struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp; + int i, nss = hweight8(phy->mt76->antenna_mask); + u16 mcs_map = 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)); + } + + he_cap->has_he = true; + + he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; + he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; + he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + else + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + he_cap_elem->phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; + he_cap_elem->phy_cap_info[2] = + IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + + switch (iftype) { + case NL80211_IFTYPE_AP: + he_cap_elem->mac_cap_info[2] |= + IEEE80211_HE_MAC_CAP2_BSR; + he_cap_elem->mac_cap_info[4] |= + IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->mac_cap_info[5] |= + IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; + he_cap_elem->phy_cap_info[3] |= + 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] |= + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; + else + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; + + he_cap_elem->phy_cap_info[1] |= + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + he_cap_elem->phy_cap_info[3] |= + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + he_cap_elem->phy_cap_info[5] |= + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; + he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + he_cap_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; + he_cap_elem->phy_cap_info[9] |= + IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; + break; + default: + break; + } + + 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); + + memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); + + if (he_cap_elem->phy_cap_info[6] & + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { + mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss, band); + } else { + he_cap_elem->phy_cap_info[9] |= + u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); + } + + if (band == NL80211_BAND_6GHZ) { + u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | + IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; + + cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | + u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | + u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); + + data->he_6ghz_capa.capa = cpu_to_le16(cap); + } +} + +static void +mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, + struct ieee80211_sband_iftype_data *data) +{ + struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; + struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; + struct ieee80211_eht_mcs_nss_supp *eht_nss = &eht_cap->eht_mcs_nss_supp; + enum nl80211_chan_width width = phy->mt76->chandef.width; + int nss = hweight8(phy->mt76->antenna_mask); + int sts = hweight16(phy->mt76->chainmask); + u8 val; + + if (!phy->dev->has_eht) + return; + + eht_cap->has_eht = true; + + eht_cap_elem->mac_cap_info[0] = + IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | + IEEE80211_EHT_MAC_CAP0_OM_CONTROL; + + eht_cap_elem->phy_cap_info[0] = + IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + + eht_cap_elem->phy_cap_info[0] |= + u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); + + eht_cap_elem->phy_cap_info[1] = + u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)), + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) | + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); + + eht_cap_elem->phy_cap_info[2] = + u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) | + u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK); + + eht_cap_elem->phy_cap_info[3] = + IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK; + + eht_cap_elem->phy_cap_info[4] = + u8_encode_bits(min_t(int, sts - 1, 2), + IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK); + + eht_cap_elem->phy_cap_info[5] = + IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | + u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK) | + u8_encode_bits(u8_get_bits(0x11, GENMASK(1, 0)), + IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK); + + val = width == NL80211_CHAN_WIDTH_160 ? 0x7 : + width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1; + eht_cap_elem->phy_cap_info[6] = + u8_encode_bits(u8_get_bits(0x11, GENMASK(4, 2)), + IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK) | + u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK); + + eht_cap_elem->phy_cap_info[7] = + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ; + + val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) | + u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX); + + eht_nss->bw._80.rx_tx_mcs9_max_nss = val; + eht_nss->bw._80.rx_tx_mcs11_max_nss = val; + eht_nss->bw._80.rx_tx_mcs13_max_nss = val; + eht_nss->bw._160.rx_tx_mcs9_max_nss = val; + eht_nss->bw._160.rx_tx_mcs11_max_nss = val; + eht_nss->bw._160.rx_tx_mcs13_max_nss = val; +} + +int mt7925_init_mlo_caps(struct mt792x_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + static const u8 ext_capa_sta[] = { + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, + }; + static struct wiphy_iftype_ext_capab ext_capab[] = { + { + .iftype = NL80211_IFTYPE_STATION, + .extended_capabilities = ext_capa_sta, + .extended_capabilities_mask = ext_capa_sta, + .extended_capabilities_len = sizeof(ext_capa_sta), + }, + }; + + if (!(phy->chip_cap & MT792x_CHIP_CAP_MLO_EVT_EN)) + return 0; + + ext_capab[0].eml_capabilities = phy->eml_cap; + ext_capab[0].mld_capa_and_ops = + u16_encode_bits(1, IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS); + + wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; + wiphy->iftype_ext_capab = ext_capab; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(ext_capab); + + return 0; +} + +static void +__mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy, + struct ieee80211_supported_band *sband, + enum nl80211_band band) +{ + struct ieee80211_sband_iftype_data *data = phy->iftype[band]; + int i, n = 0; + + for (i = 0; i < NUM_NL80211_IFTYPES; i++) { + switch (i) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_AP: + break; + default: + continue; + } + + data[n].types_mask = BIT(i); + mt7925_init_he_caps(phy, band, &data[n], i); + mt7925_init_eht_caps(phy, band, &data[n]); + + n++; + } + + _ieee80211_set_sband_iftype_data(sband, data, n); +} + +void mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy) +{ + if (phy->mt76->cap.has_2ghz) + __mt7925_set_stream_he_eht_caps(phy, &phy->mt76->sband_2g.sband, + NL80211_BAND_2GHZ); + + if (phy->mt76->cap.has_5ghz) + __mt7925_set_stream_he_eht_caps(phy, &phy->mt76->sband_5g.sband, + NL80211_BAND_5GHZ); + + if (phy->mt76->cap.has_6ghz) + __mt7925_set_stream_he_eht_caps(phy, &phy->mt76->sband_6g.sband, + NL80211_BAND_6GHZ); +} + +int __mt7925_start(struct mt792x_phy *phy) +{ + struct mt76_phy *mphy = phy->mt76; + struct mt792x_dev *dev = phy->dev; + int err; + + err = mt7925_mcu_set_channel_domain(mphy); + if (err) + return err; + + err = mt7925_mcu_set_rts_thresh(phy, 0x92b); + if (err) + return err; + + if (!dev->sar_inited) { + err = mt7925_set_tx_sar_pwr(mphy->hw, NULL); + if (err) + return err; + dev->sar_inited = true; + } + + mt792x_mac_reset_counters(phy); + set_bit(MT76_STATE_RUNNING, &mphy->state); + + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, + MT792x_WATCHDOG_TIME); + + return 0; +} +EXPORT_SYMBOL_GPL(__mt7925_start); + +static int mt7925_start(struct ieee80211_hw *hw) +{ + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int err; + + mt792x_mutex_acquire(phy->dev); + err = __mt7925_start(phy); + mt792x_mutex_release(phy->dev); + + return err; +} + +static int mt7925_mac_link_bss_add(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, + struct mt792x_link_sta *mlink) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_vif *mvif = mconf->vif; + struct mt76_txq *mtxq; + int idx, ret = 0; + + mconf->mt76.idx = __ffs64(~dev->mt76.vif_mask); + if (mconf->mt76.idx >= MT792x_MAX_INTERFACES) { + ret = -ENOSPC; + goto out; + } + + mconf->mt76.omac_idx = ieee80211_vif_is_mld(vif) ? + 0 : mconf->mt76.idx; + mconf->mt76.band_idx = 0xff; + mconf->mt76.wmm_idx = ieee80211_vif_is_mld(vif) ? + 0 : mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; + + if (mvif->phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) + mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; + else + mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; + + dev->mt76.vif_mask |= BIT_ULL(mconf->mt76.idx); + mvif->phy->omac_mask |= BIT_ULL(mconf->mt76.omac_idx); + + idx = MT792x_WTBL_RESERVED - mconf->mt76.idx; + + mlink->wcid.idx = idx; + mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&mlink->wcid, 0); + + mt7925_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + ewma_rssi_init(&mconf->rssi); + + rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid); + + ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf, &mconf->mt76, + &mlink->wcid, true); + if (ret) + goto out; + + if (vif->txq) { + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mtxq->wcid = idx; + } + +out: + return ret; +} + +static int +mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int ret = 0; + + mt792x_mutex_acquire(dev); + + mvif->phy = phy; + mvif->bss_conf.vif = mvif; + mvif->sta.vif = mvif; + mvif->deflink_id = IEEE80211_LINK_UNSPECIFIED; + + ret = mt7925_mac_link_bss_add(dev, &vif->bss_conf, &mvif->sta.deflink); + if (ret < 0) + goto out; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; +out: + mt792x_mutex_release(dev); + + return ret; +} + +static void mt7925_roc_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = priv; + + mt7925_mcu_abort_roc(phy, &mvif->bss_conf, phy->roc_token_id); +} + +void mt7925_roc_abort_sync(struct mt792x_dev *dev) +{ + struct mt792x_phy *phy = &dev->phy; + + del_timer_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + ieee80211_iterate_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_roc_iter, (void *)phy); +} +EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); + +void mt7925_roc_work(struct work_struct *work) +{ + struct mt792x_phy *phy; + + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + roc_work); + + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + return; + + mt792x_mutex_acquire(phy->dev); + ieee80211_iterate_active_interfaces(phy->mt76->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_roc_iter, phy); + mt792x_mutex_release(phy->dev); + ieee80211_remain_on_channel_expired(phy->mt76->hw); +} + +static int mt7925_abort_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf) +{ + int err = 0; + + del_timer_sync(&phy->roc_timer); + cancel_work_sync(&phy->roc_work); + + mt792x_mutex_acquire(phy->dev); + if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + err = mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + mt792x_mutex_release(phy->dev); + + return err; +} + +static int mt7925_set_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, + int duration, + enum mt7925_roc_req type) +{ + int err; + + if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) + return -EBUSY; + + phy->roc_grant = false; + + err = mt7925_mcu_set_roc(phy, mconf, chan, duration, type, + ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; + } + + if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + err = -ETIMEDOUT; + } + +out: + return err; +} + +static int mt7925_set_mlo_roc(struct mt792x_phy *phy, + struct mt792x_bss_conf *mconf, + u16 sel_links) +{ + int err; + + if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))) + return -EBUSY; + + phy->roc_grant = false; + + err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); + if (err < 0) { + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + goto out; + } + + if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) { + mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id); + clear_bit(MT76_STATE_ROC, &phy->mt76->state); + err = -ETIMEDOUT; + } + +out: + return err; +} + +static int mt7925_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int err; + + mt792x_mutex_acquire(phy->dev); + err = mt7925_set_roc(phy, &mvif->bss_conf, + chan, duration, MT7925_ROC_REQ_ROC); + mt792x_mutex_release(phy->dev); + + return err; +} + +static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + + return mt7925_abort_roc(phy, &mvif->bss_conf); +} + +static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, int link_id) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : + &mvif->sta; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_link_sta *link_sta; + int idx = key->keyidx, err = 0; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; + struct mt76_wcid *wcid; + u8 *wcid_keyidx; + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + wcid = &mlink->wcid; + wcid_keyidx = &wcid->hw_key_idx; + + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + wcid_keyidx = &wcid->hw_key_idx2; + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (!mvif->wep_sta) + return -EOPNOTSUPP; + break; + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + case WLAN_CIPHER_SUITE_SMS4: + break; + default: + return -EOPNOTSUPP; + } + + if (cmd == SET_KEY && !mconf->mt76.cipher) { + struct mt792x_phy *phy = mt792x_hw_phy(hw); + + mconf->mt76.cipher = mt7925_mcu_get_cipher(key->cipher); + mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf, + link_sta, true); + } + + if (cmd == SET_KEY) + *wcid_keyidx = idx; + else if (idx == *wcid_keyidx) + *wcid_keyidx = -1; + else + goto out; + + mt76_wcid_key_setup(&dev->mt76, wcid, + cmd == SET_KEY ? key : NULL); + + err = mt7925_mcu_add_key(&dev->mt76, vif, &mlink->bip, + key, MCU_UNI_CMD(STA_REC_UPDATE), + &mlink->wcid, cmd, msta); + + if (err) + goto out; + + if (key->cipher == WLAN_CIPHER_SUITE_WEP104 || + key->cipher == WLAN_CIPHER_SUITE_WEP40) + err = mt7925_mcu_add_key(&dev->mt76, vif, &mvif->wep_sta->deflink.bip, + key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &mvif->wep_sta->deflink.wcid, cmd, msta); +out: + return err; +} + +static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : + &mvif->sta; + int err; + + /* The hardware does not support per-STA RX GTK, fallback + * to software mode for these. + */ + if ((vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT) && + (key->cipher == WLAN_CIPHER_SUITE_TKIP || + key->cipher == WLAN_CIPHER_SUITE_CCMP) && + !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + return -EOPNOTSUPP; + + mt792x_mutex_acquire(dev); + + if (ieee80211_vif_is_mld(vif)) { + unsigned int link_id; + unsigned long add; + + add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id); + if (err < 0) + break; + } + } else { + err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); + } + + mt792x_mutex_release(dev); + + return err; +} + +static void +mt7925_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = priv; + struct ieee80211_hw *hw = mt76_hw(dev); + bool pm_enable = dev->pm.enable; + int err; + + err = mt7925_mcu_set_beacon_filter(dev, vif, pm_enable); + if (err < 0) + return; + + if (pm_enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); + } +} + +static void +mt7925_sniffer_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = priv; + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_connac_pm *pm = &dev->pm; + bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); + + mt7925_mcu_set_sniffer(dev, vif, monitor); + pm->enable = pm->enable_user && !monitor; + pm->ds_enable = pm->ds_enable_user && !monitor; + + mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); + + if (monitor) + mt7925_mcu_set_beacon_filter(dev, vif, false); +} + +void mt7925_set_runtime_pm(struct mt792x_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt76_connac_pm *pm = &dev->pm; + bool monitor = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); + + pm->enable = pm->enable_user && !monitor; + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_pm_interface_iter, dev); + pm->ds_enable = pm->ds_enable_user && !monitor; + mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); +} + +static int mt7925_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int ret = 0; + + mt792x_mutex_acquire(dev); + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + ret = mt7925_set_tx_sar_pwr(hw, NULL); + if (ret) + goto out; + } + + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_sniffer_interface_iter, dev); + } + +out: + mt792x_mutex_release(dev); + + return ret; +} + +static void mt7925_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ +#define MT7925_FILTER_FCSFAIL BIT(2) +#define MT7925_FILTER_CONTROL BIT(5) +#define MT7925_FILTER_OTHER_BSS BIT(6) +#define MT7925_FILTER_ENABLE BIT(31) + struct mt792x_dev *dev = mt792x_hw_dev(hw); + u32 flags = MT7925_FILTER_ENABLE; + +#define MT7925_FILTER(_fif, _type) do { \ + if (*total_flags & (_fif)) \ + flags |= MT7925_FILTER_##_type; \ + } while (0) + + MT7925_FILTER(FIF_FCSFAIL, FCSFAIL); + MT7925_FILTER(FIF_CONTROL, CONTROL); + MT7925_FILTER(FIF_OTHER_BSS, OTHER_BSS); + + mt792x_mutex_acquire(dev); + mt7925_mcu_set_rxfilter(dev, flags, 0, 0); + mt792x_mutex_release(dev); + + *total_flags &= (FIF_OTHER_BSS | FIF_FCSFAIL | FIF_CONTROL); +} + +static u8 +mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + bool beacon, bool mcast) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_phy *mphy = hw->priv; + u16 rate; + u8 i, idx, ht; + + rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon, mcast); + ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; + + if (beacon && ht) { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + /* must odd index */ + idx = MT7925_BEACON_RATES_TBL + 2 * (mvif->idx % 20); + mt7925_mac_set_fixed_rate_table(dev, idx, rate); + return idx; + } + + idx = FIELD_GET(MT_TX_RATE_IDX, rate); + for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) + if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) + return MT792x_BASIC_RATES_TBL + i; + + return mvif->basic_rates_idx; +} + +static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf; + struct mt792x_bss_conf *mconf; + u8 link_id = link_sta->link_id; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + struct mt76_wcid *wcid; + int ret, idx; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_id); + + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); + if (idx < 0) + return -ENOSPC; + + mconf = mt792x_vif_to_link(mvif, link_id); + mt76_wcid_init(&mlink->wcid, 0); + mlink->wcid.sta = 1; + mlink->wcid.idx = idx; + mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET; + mlink->last_txs = jiffies; + mlink->wcid.link_id = link_sta->link_id; + mlink->wcid.link_valid = !!link_sta->sta->valid_links; + mlink->sta = msta; + + wcid = &mlink->wcid; + ewma_signal_init(&wcid->rssi); + rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); + mt76_wcid_init(wcid, 0); + ewma_avg_signal_init(&mlink->avg_ack_signal); + memset(mlink->airtime_ac, 0, + sizeof(msta->deflink.airtime_ac)); + + ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); + if (ret) + return ret; + + mt7925_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + + /* should update bss info before STA add */ + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + if (ieee80211_vif_is_mld(vif)) + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, link_sta != mlink->pri_link); + else + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, false); + } + + if (ieee80211_vif_is_mld(vif) && + link_sta == mlink->pri_link) { + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) + return ret; + } else if (ieee80211_vif_is_mld(vif) && + link_sta != mlink->pri_link) { + ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, + true, MT76_STA_INFO_STATE_ASSOC); + if (ret) + return ret; + + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_ASSOC); + if (ret) + return ret; + } else { + ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + MT76_STA_INFO_STATE_NONE); + if (ret) + return ret; + } + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + + return 0; +} + +static int +mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long new_links) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned int link_id; + int err = 0; + + for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; + + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { + mlink = &msta->deflink; + msta->deflink_id = link_id; + } else { + mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); + if (!mlink) { + err = -ENOMEM; + break; + } + } + + msta->valid_links |= BIT(link_id); + rcu_assign_pointer(msta->link[link_id], mlink); + mlink->sta = msta; + mlink->pri_link = &sta->deflink; + mlink->wcid.def_wcid = &msta->deflink.wcid; + + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta); + } + + return err; +} + +int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + int err; + + msta->vif = mvif; + + if (vif->type == NL80211_IFTYPE_STATION) + mvif->wep_sta = msta; + + if (ieee80211_vif_is_mld(vif)) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + + err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); + } else { + err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); + } + + return err; +} +EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); + +static u16 +mt7925_mac_select_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) +{ + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct { + u8 link_id; + enum nl80211_band band; + } data[IEEE80211_MLD_MAX_NUM_LINKS]; + u8 link_id, i, j, n_data = 0; + u16 sel_links = 0; + + if (!ieee80211_vif_is_mld(vif)) + return 0; + + if (vif->active_links == usable_links) + return vif->active_links; + + rcu_read_lock(); + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + rcu_dereference(vif->link_conf[link_id]); + + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].band = link_conf->chanreq.oper.chan->band; + n_data++; + } + rcu_read_unlock(); + + for (i = 0; i < n_data; i++) { + if (!(BIT(data[i].link_id) & vif->active_links)) + continue; + + sel_links = BIT(data[i].link_id); + + for (j = 0; j < n_data; j++) { + if (data[i].band != data[j].band) { + sel_links |= BIT(data[j].link_id); + break; + } + } + + break; + } + + return sel_links; +} + +static void +mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf = + mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; + enum nl80211_band band = chandef->chan->band, secondary_band; + + u16 sel_links = mt7925_mac_select_links(mdev, vif); + u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); + + if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) + return; + + link_conf = mt792x_vif_to_bss_conf(vif, secondary_link_id); + secondary_band = link_conf->chanreq.oper.chan->band; + + if (band == NL80211_BAND_2GHZ || + (band == NL80211_BAND_5GHZ && secondary_band == NL80211_BAND_6GHZ)) { + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); + + mt792x_mutex_acquire(dev); + + mt7925_set_mlo_roc(mvif->phy, &mvif->bss_conf, sel_links); + + mt792x_mutex_release(dev); + } + + ieee80211_set_active_links_async(vif, sel_links); +} + +static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct ieee80211_bss_conf *link_conf; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + + mt792x_mutex_acquire(dev); + + if (ieee80211_vif_is_mld(vif)) { + link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); + } else { + link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id); + } + + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); + mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, true); + } + + ewma_avg_signal_init(&mlink->avg_ack_signal); + + mt7925_mac_wtbl_update(dev, mlink->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); + + mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC); + + mt792x_mutex_release(dev); +} + +int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) +{ + struct ieee80211_link_sta *link_sta = &sta->deflink; + + if (ev != MT76_STA_EVENT_ASSOC) + return 0; + + if (ieee80211_vif_is_mld(vif)) { + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + + link_sta = mt792x_sta_to_link_sta(vif, sta, msta->deflink_id); + mt7925_mac_set_links(mdev, vif); + } + + mt7925_mac_link_sta_assoc(mdev, vif, link_sta); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7925_mac_sta_event); + +static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct ieee80211_bss_conf *link_conf; + u8 link_id = link_sta->link_id; + struct mt792x_link_sta *mlink; + struct mt792x_sta *msta; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_id); + + mt7925_roc_abort_sync(dev); + + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); + mt76_connac_pm_wake(&dev->mphy, &dev->pm); + + mt7925_mcu_sta_update(dev, link_sta, vif, false, + MT76_STA_INFO_STATE_NONE); + mt7925_mac_wtbl_update(dev, mlink->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + + if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { + struct mt792x_bss_conf *mconf; + + mconf = mt792x_link_conf_to_mconf(link_conf); + mt792x_mac_link_bss_remove(dev, mconf, mlink); + } + + spin_lock_bh(&mdev->sta_poll_lock); + if (!list_empty(&mlink->wcid.poll_list)) + list_del_init(&mlink->wcid.poll_list); + spin_unlock_bh(&mdev->sta_poll_lock); + + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +} + +static int +mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long old_links) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt76_dev *mdev = &dev->mt76; + struct mt76_wcid *wcid; + unsigned int link_id; + + for_each_set_bit(link_id, &old_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_link_sta *link_sta; + struct mt792x_link_sta *mlink; + + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + if (!link_sta) + continue; + + mlink = mt792x_sta_to_link(msta, link_id); + if (!mlink) + continue; + + mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta); + + wcid = &mlink->wcid; + rcu_assign_pointer(msta->link[link_id], NULL); + msta->valid_links &= ~BIT(link_id); + mlink->sta = NULL; + mlink->pri_link = NULL; + + if (link_sta != mlink->pri_link) { + mt76_wcid_cleanup(mdev, wcid); + mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); + } + + if (msta->deflink_id == link_id) + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + } + + return 0; +} + +void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct { + struct { + u8 omac_idx; + u8 band_idx; + __le16 pad; + } __packed hdr; + struct req_tlv { + __le16 tag; + __le16 len; + u8 active; + u8 link_idx; /* hw link idx */ + u8 omac_addr[ETH_ALEN]; + } __packed tlv; + } dev_req = { + .hdr = { + .omac_idx = 0, + .band_idx = 0, + }, + .tlv = { + .tag = cpu_to_le16(DEV_INFO_ACTIVE), + .len = cpu_to_le16(sizeof(struct req_tlv)), + .active = true, + }, + }; + unsigned long rem; + + rem = ieee80211_vif_is_mld(vif) ? msta->valid_links : BIT(0); + + mt7925_mac_sta_remove_links(dev, vif, sta, rem); + + if (ieee80211_vif_is_mld(vif)) { + mt7925_mcu_set_dbdc(&dev->mphy, false); + + /* recovery omac address for the legacy interface */ + memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN); + mt76_mcu_send_msg(mdev, MCU_UNI_CMD(DEV_INFO_UPDATE), + &dev_req, sizeof(dev_req), true); + } + + if (vif->type == NL80211_IFTYPE_STATION) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + mvif->wep_sta = NULL; + ewma_rssi_init(&mvif->bss_conf.rssi); + } +} +EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove); + +static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt792x_mutex_acquire(dev); + mt7925_mcu_set_rts_thresh(&dev->phy, val); + mt792x_mutex_release(dev); + + return 0; +} + +static int +mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + enum ieee80211_ampdu_mlme_action action = params->action; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_sta *sta = params->sta; + struct ieee80211_txq *txq = sta->txq[params->tid]; + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + u16 tid = params->tid; + u16 ssn = params->ssn; + struct mt76_txq *mtxq; + int ret = 0; + + if (!txq) + return -EINVAL; + + mtxq = (struct mt76_txq *)txq->drv_priv; + + mt792x_mutex_acquire(dev); + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, + params->buf_size); + mt7925_mcu_uni_rx_ba(dev, vif, params, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); + mt7925_mcu_uni_rx_ba(dev, vif, params, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + mt7925_mcu_uni_tx_ba(dev, vif, params, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); + mt7925_mcu_uni_tx_ba(dev, vif, params, false); + break; + case IEEE80211_AMPDU_TX_START: + set_bit(tid, &msta->deflink.wcid.ampdu_state); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); + mt7925_mcu_uni_tx_ba(dev, vif, params, false); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + mt792x_mutex_release(dev); + + return ret; +} + +static bool is_valid_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + + if (alpha2[0] == '0' && alpha2[1] == '0') + return true; + + if (isalpha(alpha2[0]) && isalpha(alpha2[1])) + return true; + + return false; +} + +void mt7925_scan_work(struct work_struct *work) +{ + struct mt792x_phy *phy; + + phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, + scan_work.work); + + while (true) { + struct mt76_dev *mdev = &phy->dev->mt76; + struct sk_buff *skb; + struct tlv *tlv; + int tlv_len; + + spin_lock_bh(&phy->dev->mt76.lock); + skb = __skb_dequeue(&phy->scan_event_list); + spin_unlock_bh(&phy->dev->mt76.lock); + + if (!skb) + break; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; + + while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + struct mt7925_mcu_scan_chinfo_event *evt; + + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_SCAN_DONE_BASIC: + if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + ieee80211_scan_completed(phy->mt76->hw, &info); + } + break; + case UNI_EVENT_SCAN_DONE_CHNLINFO: + evt = (struct mt7925_mcu_scan_chinfo_event *)tlv->data; + + if (!is_valid_alpha2(evt->alpha2)) + break; + + if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') + break; + + mt7925_mcu_set_clc(phy->dev, evt->alpha2, ENVIRON_INDOOR); + + break; + case UNI_EVENT_SCAN_DONE_NLO: + ieee80211_sched_scan_results(phy->mt76->hw); + break; + default: + break; + } + + tlv_len -= le16_to_cpu(tlv->len); + tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); + } + + dev_kfree_skb(skb); + } +} + +static int +mt7925_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt792x_mutex_acquire(dev); + err = mt7925_mcu_hw_scan(mphy, vif, req); + mt792x_mutex_release(dev); + + return err; +} + +static void +mt7925_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + + mt792x_mutex_acquire(dev); + mt7925_mcu_cancel_hw_scan(mphy, vif); + mt792x_mutex_release(dev); +} + +static int +mt7925_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *req, + struct ieee80211_scan_ies *ies) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt792x_mutex_acquire(dev); + + err = mt7925_mcu_sched_scan_req(mphy, vif, req); + if (err < 0) + goto out; + + err = mt7925_mcu_sched_scan_enable(mphy, vif, true); +out: + mt792x_mutex_release(dev); + + return err; +} + +static int +mt7925_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; + int err; + + mt792x_mutex_acquire(dev); + err = mt7925_mcu_sched_scan_enable(mphy, vif, false); + mt792x_mutex_release(dev); + + return err; +} + +static int +mt7925_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int max_nss = hweight8(hw->wiphy->available_antennas_tx); + + if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + return -EINVAL; + + if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) + tx_ant = BIT(ffs(tx_ant) - 1) - 1; + + mt792x_mutex_acquire(dev); + + phy->mt76->antenna_mask = tx_ant; + phy->mt76->chainmask = tx_ant; + + mt76_set_stream_caps(phy->mt76, true); + mt7925_set_stream_he_eht_caps(phy); + + /* TODO: update bmc_wtbl spe_idx when antenna changes */ + mt792x_mutex_release(dev); + + return 0; +} + +#ifdef CONFIG_PM +static int mt7925_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); + + cancel_delayed_work_sync(&dev->pm.ps_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + mt792x_mutex_acquire(dev); + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_set_suspend_iter, + &dev->mphy); + + mt792x_mutex_release(dev); + + return 0; +} + +static int mt7925_resume(struct ieee80211_hw *hw) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + + mt792x_mutex_acquire(dev); + + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_set_suspend_iter, + &dev->mphy); + + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT792x_WATCHDOG_TIME); + + mt792x_mutex_release(dev); + + return 0; +} + +static void mt7925_set_rekey_data(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_gtk_rekey_data *data) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt792x_mutex_acquire(dev); + mt76_connac_mcu_update_gtk_rekey(hw, vif, data); + mt792x_mutex_release(dev); +} +#endif /* CONFIG_PM */ + +static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool enabled) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + unsigned long valid = mvif->valid_links; + u8 i; + + mt792x_mutex_acquire(dev); + + valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt792x_link_sta *mlink; + + mlink = mt792x_sta_to_link(msta, i); + + if (enabled) + set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags); + else + clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags); + + mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i); + } + + mt792x_mutex_release(dev); +} + +#if IS_ENABLED(CONFIG_IPV6) +static void __mt7925_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_bss_conf *link_conf, + struct inet6_dev *idev) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct inet6_ifaddr *ifa; + struct sk_buff *skb; + u8 idx = 0; + + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7925_arpns_tlv arpns; + struct in6_addr ns_addrs[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; + } req_hdr = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .arpns = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND), + .len = cpu_to_le16(sizeof(req_hdr) - 4), + .enable = true, + }, + }; + + read_lock_bh(&idev->lock); + list_for_each_entry(ifa, &idev->addr_list, if_list) { + if (ifa->flags & IFA_F_TENTATIVE) + continue; + req_hdr.ns_addrs[idx] = ifa->addr; + if (++idx >= IEEE80211_BSS_ARP_ADDR_LIST_LEN) + break; + } + read_unlock_bh(&idev->lock); + + if (!idx) + return; + + req_hdr.arpns.ips_num = idx; + + skb = __mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr), + 0, GFP_ATOMIC); + if (!skb) + return; + + skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + + skb_queue_tail(&dev->ipv6_ns_list, skb); + + ieee80211_queue_work(dev->mt76.hw, &dev->ipv6_ns_work); +} + +static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct inet6_dev *idev) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; + int i; + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + __mt7925_ipv6_addr_change(hw, bss_conf, idev); + } +} + +#endif + +int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + struct mt76_phy *mphy = hw->priv; + + if (sar) { + int err = mt76_init_sar_power(hw, sar); + + if (err) + return err; + } + mt792x_init_acpi_sar_power(mt792x_hw_phy(hw), !sar); + + return mt7925_mcu_set_rate_txpower(mphy); +} + +static int mt7925_set_sar_specs(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err; + + mt792x_mutex_acquire(dev); + err = mt7925_mcu_set_clc(dev, dev->mt76.alpha2, + dev->country_ie_env); + if (err < 0) + goto out; + + err = mt7925_set_tx_sar_pwr(hw, sar); +out: + mt792x_mutex_release(dev); + + return err; +} + +static void +mt7925_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt792x_mutex_acquire(dev); + mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); + mt792x_mutex_release(dev); +} + +static int +mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + unsigned int link_id, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, link_id); + static const u8 mq_to_aci[] = { + [IEEE80211_AC_VO] = 3, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + }; + + /* firmware uses access class index */ + mconf->queue_params[mq_to_aci[queue]] = *params; + + return 0; +} + +static int +mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err; + + mt792x_mutex_acquire(dev); + + err = mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, + link_conf, NULL, true); + if (err) + goto out; + + err = mt7925_mcu_set_bss_pm(dev, link_conf, true); + if (err) + goto out; + + err = mt7925_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_NONE); +out: + mt792x_mutex_release(dev); + + return err; +} + +static void +mt7925_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err; + + mt792x_mutex_acquire(dev); + + err = mt7925_mcu_set_bss_pm(dev, link_conf, false); + if (err) + goto out; + + mt7925_mcu_add_bss_info(&dev->phy, mvif->bss_conf.mt76.ctx, link_conf, + NULL, false); + +out: + mt792x_mutex_release(dev); +} + +static int +mt7925_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + return 0; +} + +static void +mt7925_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ +} + +static void +mt7925_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx, + u32 changed) +{ + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_bss_conf *mconf; + struct ieee80211_vif *vif; + struct mt792x_vif *mvif; + + if (!mctx->bss_conf) + return; + + mconf = mctx->bss_conf; + mvif = mconf->vif; + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + mt792x_mutex_acquire(phy->dev); + if (vif->type == NL80211_IFTYPE_MONITOR) { + mt7925_mcu_set_sniffer(mvif->phy->dev, vif, true); + mt7925_mcu_config_sniffer(mvif, ctx); + } else { + if (ieee80211_vif_is_mld(vif)) { + unsigned long valid = mvif->valid_links; + u8 i; + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, i); + if (mconf && mconf->mt76.ctx == ctx) + break; + } + + } else { + mconf = &mvif->bss_conf; + } + + if (mconf) { + struct ieee80211_bss_conf *link_conf; + + link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, + link_conf, ctx); + } + } + + mt792x_mutex_release(phy->dev); +} + +static void mt7925_mgd_prepare_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + u16 duration = info->duration ? info->duration : + jiffies_to_msecs(HZ); + + mt792x_mutex_acquire(dev); + mt7925_set_roc(mvif->phy, &mvif->bss_conf, + mvif->bss_conf.mt76.ctx->def.chan, duration, + MT7925_ROC_REQ_JOIN); + mt792x_mutex_release(dev); +} + +static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_prep_tx_info *info) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); +} + +static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + unsigned long valid = ieee80211_vif_is_mld(vif) ? + mvif->valid_links : BIT(0); + struct ieee80211_bss_conf *bss_conf; + int i; + + mt792x_mutex_acquire(dev); + + if (changed & BSS_CHANGED_ASSOC) { + mt7925_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_ASSOC); + mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mt7925_mcu_update_arp_filter(&dev->mt76, bss_conf); + } + } + + if (changed & BSS_CHANGED_PS) { + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + bss_conf = mt792x_vif_to_bss_conf(vif, i); + mt7925_mcu_uni_bss_ps(dev, bss_conf); + } + } + + mt792x_mutex_release(dev); +} + +static void mt7925_link_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; + + mconf = mt792x_vif_to_link(mvif, info->link_id); + + mt792x_mutex_acquire(dev); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + if (slottime != phy->slottime) { + phy->slottime = slottime; + mt7925_mcu_set_timing(phy, info); + } + } + + if (changed & BSS_CHANGED_MCAST_RATE) + mconf->mt76.mcast_rates_idx = + mt7925_get_rates_table(hw, vif, false, true); + + if (changed & BSS_CHANGED_BASIC_RATES) + mconf->mt76.basic_rates_idx = + mt7925_get_rates_table(hw, vif, false, false); + + if (changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) { + mconf->mt76.beacon_rates_idx = + mt7925_get_rates_table(hw, vif, true, false); + + mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, + info->enable_beacon); + } + + /* ensure that enable txcmd_mode after bss_info */ + if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) + mt7925_mcu_set_tx(dev, info); + + if (changed & BSS_CHANGED_BSSID) { + if (ieee80211_vif_is_mld(vif) && + hweight16(mvif->valid_links) == 2) + /* Indicate the secondary setup done */ + mt7925_mcu_uni_bss_bcnft(dev, info, true); + } + + mt792x_mutex_release(dev); +} + +static int +mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + struct mt792x_bss_conf *mconfs[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mconf; + struct mt792x_link_sta *mlinks[IEEE80211_MLD_MAX_NUM_LINKS] = {}, *mlink; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + int err; + + if (old_links == new_links) + return 0; + + mt792x_mutex_acquire(dev); + + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(&mvif->sta, link_id); + + if (!mconf || !mlink) + continue; + + if (mconf != &mvif->bss_conf) { + mt792x_mac_link_bss_remove(dev, mconf, mlink); + devm_kfree(dev->mt76.dev, mconf); + devm_kfree(dev->mt76.dev, mlink); + } + + rcu_assign_pointer(mvif->link_conf[link_id], NULL); + rcu_assign_pointer(mvif->sta.link[link_id], NULL); + } + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + if (!old_links) { + mvif->deflink_id = link_id; + mconf = &mvif->bss_conf; + mlink = &mvif->sta.deflink; + } else { + mconf = devm_kzalloc(dev->mt76.dev, sizeof(*mconf), + GFP_KERNEL); + mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), + GFP_KERNEL); + if (!mconf || !mlink) + return -ENOMEM; + } + + mconfs[link_id] = mconf; + mlinks[link_id] = mlink; + mconf->link_id = link_id; + mconf->vif = mvif; + mlink->wcid.link_id = link_id; + mlink->wcid.link_valid = !!vif->valid_links; + mlink->wcid.def_wcid = &mvif->sta.deflink.wcid; + } + + if (hweight16(mvif->valid_links) == 0) + mt792x_mac_link_bss_remove(dev, &mvif->bss_conf, + &mvif->sta.deflink); + + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mconfs[link_id]; + mlink = mlinks[link_id]; + link_conf = mt792x_vif_to_bss_conf(vif, link_id); + + rcu_assign_pointer(mvif->link_conf[link_id], mconf); + rcu_assign_pointer(mvif->sta.link[link_id], mlink); + + err = mt7925_mac_link_bss_add(dev, link_conf, mlink); + if (err < 0) + goto free; + + if (mconf != &mvif->bss_conf) { + mt7925_mcu_set_bss_pm(dev, link_conf, true); + + err = mt7925_set_mlo_roc(phy, &mvif->bss_conf, + vif->active_links); + if (err < 0) + goto free; + } + } + + mvif->valid_links = new_links; + + mt792x_mutex_release(dev); + + return 0; + +free: + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { + rcu_assign_pointer(mvif->link_conf[link_id], NULL); + rcu_assign_pointer(mvif->sta.link[link_id], NULL); + + if (mconf != &mvif->bss_conf) + devm_kfree(dev->mt76.dev, mconfs[link_id]); + if (mlink != &mvif->sta.deflink) + devm_kfree(dev->mt76.dev, mlinks[link_id]); + } + + mt792x_mutex_release(dev); + + return err; +} + +static int +mt7925_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 old_links, u16 new_links) +{ + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err = 0; + + if (old_links == new_links) + return 0; + + mt792x_mutex_acquire(dev); + + err = mt7925_mac_sta_remove_links(dev, vif, sta, rem); + if (err < 0) + goto out; + + err = mt7925_mac_sta_add_links(dev, vif, sta, add); + if (err < 0) + goto out; + +out: + mt792x_mutex_release(dev); + + return err; +} + +static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_bss_conf *pri_link_conf; + struct mt792x_bss_conf *mconf; + + mutex_lock(&dev->mt76.mutex); + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); + pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id); + + if (vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) + mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf, + NULL, true); + } else { + mconf = &mvif->bss_conf; + } + + mconf->mt76.ctx = ctx; + mctx->bss_conf = mconf; + mutex_unlock(&dev->mt76.mutex); + + return 0; +} + +static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; + + mutex_lock(&dev->mt76.mutex); + + if (ieee80211_vif_is_mld(vif)) { + mconf = mt792x_vif_to_link(mvif, link_conf->link_id); + + if (vif->type == NL80211_IFTYPE_STATION && + mconf == &mvif->bss_conf) + mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, + NULL, false); + } else { + mconf = &mvif->bss_conf; + } + + mctx->bss_conf = NULL; + mconf->mt76.ctx = NULL; + mutex_unlock(&dev->mt76.mutex); +} + +const struct ieee80211_ops mt7925_ops = { + .tx = mt792x_tx, + .start = mt7925_start, + .stop = mt792x_stop, + .add_interface = mt7925_add_interface, + .remove_interface = mt792x_remove_interface, + .config = mt7925_config, + .conf_tx = mt7925_conf_tx, + .configure_filter = mt7925_configure_filter, + .start_ap = mt7925_start_ap, + .stop_ap = mt7925_stop_ap, + .sta_state = mt76_sta_state, + .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .set_key = mt7925_set_key, + .sta_set_decap_offload = mt7925_sta_set_decap_offload, +#if IS_ENABLED(CONFIG_IPV6) + .ipv6_addr_change = mt7925_ipv6_addr_change, +#endif /* CONFIG_IPV6 */ + .ampdu_action = mt7925_ampdu_action, + .set_rts_threshold = mt7925_set_rts_threshold, + .wake_tx_queue = mt76_wake_tx_queue, + .release_buffered_frames = mt76_release_buffered_frames, + .channel_switch_beacon = mt7925_channel_switch_beacon, + .get_txpower = mt76_get_txpower, + .get_stats = mt792x_get_stats, + .get_et_sset_count = mt792x_get_et_sset_count, + .get_et_strings = mt792x_get_et_strings, + .get_et_stats = mt792x_get_et_stats, + .get_tsf = mt792x_get_tsf, + .set_tsf = mt792x_set_tsf, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, + .set_antenna = mt7925_set_antenna, + .set_coverage_class = mt792x_set_coverage_class, + .hw_scan = mt7925_hw_scan, + .cancel_hw_scan = mt7925_cancel_hw_scan, + .sta_statistics = mt792x_sta_statistics, + .sched_scan_start = mt7925_start_sched_scan, + .sched_scan_stop = mt7925_stop_sched_scan, +#ifdef CONFIG_PM + .suspend = mt7925_suspend, + .resume = mt7925_resume, + .set_wakeup = mt792x_set_wakeup, + .set_rekey_data = mt7925_set_rekey_data, +#endif /* CONFIG_PM */ + .flush = mt792x_flush, + .set_sar_specs = mt7925_set_sar_specs, + .remain_on_channel = mt7925_remain_on_channel, + .cancel_remain_on_channel = mt7925_cancel_remain_on_channel, + .add_chanctx = mt7925_add_chanctx, + .remove_chanctx = mt7925_remove_chanctx, + .change_chanctx = mt7925_change_chanctx, + .assign_vif_chanctx = mt7925_assign_vif_chanctx, + .unassign_vif_chanctx = mt7925_unassign_vif_chanctx, + .mgd_prepare_tx = mt7925_mgd_prepare_tx, + .mgd_complete_tx = mt7925_mgd_complete_tx, + .vif_cfg_changed = mt7925_vif_cfg_changed, + .link_info_changed = mt7925_link_info_changed, + .change_vif_links = mt7925_change_vif_links, + .change_sta_links = mt7925_change_sta_links, +}; +EXPORT_SYMBOL_GPL(mt7925_ops); + +MODULE_AUTHOR("Deren Wu "); +MODULE_DESCRIPTION("MediaTek MT7925 core driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7925/mcu.c new file mode 100644 index 000000000000..f1be88f3b00b --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/mcu.c @@ -0,0 +1,3597 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include +#include +#include "mt7925.h" +#include "mcu.h" +#include "mac.h" + +#define MT_STA_BFER BIT(0) +#define MT_STA_BFEE BIT(1) + +static bool mt7925_disable_clc; +module_param_named(disable_clc, mt7925_disable_clc, bool, 0644); +MODULE_PARM_DESC(disable_clc, "disable CLC support"); + +int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq) +{ + int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); + struct mt7925_mcu_rxd *rxd; + int ret = 0; + + if (!skb) { + dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); + mt792x_reset(mdev); + + return -ETIMEDOUT; + } + + rxd = (struct mt7925_mcu_rxd *)skb->data; + if (seq != rxd->seq) + return -EAGAIN; + + if (cmd == MCU_CMD(PATCH_SEM_CONTROL) || + cmd == MCU_CMD(PATCH_FINISH_REQ)) { + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; + } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || + cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || + cmd == MCU_UNI_CMD(STA_REC_UPDATE) || + cmd == MCU_UNI_CMD(OFFLOAD) || + cmd == MCU_UNI_CMD(SUSPEND)) { + struct mt7925_mcu_uni_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7925_mcu_uni_event *)skb->data; + ret = le32_to_cpu(event->status); + /* skip invalid event */ + if (mcu_cmd != event->cid) + ret = -EAGAIN; + } else { + skb_pull(skb, sizeof(*rxd)); + } + + return ret; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_parse_response); + +int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set) +{ +#define MT_RF_REG_HDR GENMASK(31, 24) +#define MT_RF_REG_ANT GENMASK(23, 16) +#define RF_REG_PREFIX 0x99 + struct { + u8 __rsv[4]; + union { + struct uni_cmd_access_reg_basic { + __le16 tag; + __le16 len; + __le32 idx; + __le32 data; + } __packed reg; + struct uni_cmd_access_rf_reg_basic { + __le16 tag; + __le16 len; + __le16 ant; + u8 __rsv[2]; + __le32 idx; + __le32 data; + } __packed rf_reg; + }; + } __packed * res, req; + struct sk_buff *skb; + int ret; + + if (u32_get_bits(regidx, MT_RF_REG_HDR) == RF_REG_PREFIX) { + req.rf_reg.tag = cpu_to_le16(UNI_CMD_ACCESS_RF_REG_BASIC); + req.rf_reg.len = cpu_to_le16(sizeof(req.rf_reg)); + req.rf_reg.ant = cpu_to_le16(u32_get_bits(regidx, MT_RF_REG_ANT)); + req.rf_reg.idx = cpu_to_le32(regidx); + req.rf_reg.data = set ? cpu_to_le32(*val) : 0; + } else { + req.reg.tag = cpu_to_le16(UNI_CMD_ACCESS_REG_BASIC); + req.reg.len = cpu_to_le16(sizeof(req.reg)); + req.reg.idx = cpu_to_le32(regidx); + req.reg.data = set ? cpu_to_le32(*val) : 0; + } + + if (set) + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REG_ACCESS), + &req, sizeof(req), true); + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_WM_UNI_CMD_QUERY(REG_ACCESS), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (void *)skb->data; + if (u32_get_bits(regidx, MT_RF_REG_HDR) == RF_REG_PREFIX) + *val = le32_to_cpu(res->rf_reg.data); + else + *val = le32_to_cpu(res->reg.data); + + dev_kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_regval); + +int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct ieee80211_vif *mvif = link_conf->vif; + struct sk_buff *skb; + int i, len = min_t(int, mvif->cfg.arp_addr_cnt, + IEEE80211_BSS_ARP_ADDR_LIST_LEN); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7925_arpns_tlv arp; + } req = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .arp = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(req) - 4 + len * 2 * sizeof(__be32)), + .ips_num = len, + .enable = true, + }, + }; + + skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(req) + len * 2 * sizeof(__be32)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req, sizeof(req)); + for (i = 0; i < len; i++) { + skb_put_data(skb, &mvif->cfg.arp_addr_list[i], sizeof(__be32)); + skb_put_zero(skb, sizeof(__be32)); + } + + return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(OFFLOAD), true); +} + +#ifdef CONFIG_PM +static int +mt7925_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, + bool suspend, struct cfg80211_wowlan *wowlan) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt76_connac_wow_ctrl_tlv wow_ctrl_tlv; + struct mt76_connac_wow_gpio_param_tlv gpio_tlv; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .wow_ctrl_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_WOW_CTRL), + .len = cpu_to_le16(sizeof(struct mt76_connac_wow_ctrl_tlv)), + .cmd = suspend ? 1 : 2, + }, + .gpio_tlv = { + .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM), + .len = cpu_to_le16(sizeof(struct mt76_connac_wow_gpio_param_tlv)), + .gpio_pin = 0xff, /* follow fw about GPIO pin */ + }, + }; + + if (wowlan->magic_pkt) + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_MAGIC; + if (wowlan->disconnect) + req.wow_ctrl_tlv.trigger |= (UNI_WOW_DETECT_TYPE_DISCONNECT | + UNI_WOW_DETECT_TYPE_BCN_LOST); + if (wowlan->nd_config) { + mt7925_mcu_sched_scan_req(phy, vif, wowlan->nd_config); + req.wow_ctrl_tlv.trigger |= UNI_WOW_DETECT_TYPE_SCH_SCAN_HIT; + mt7925_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; + else if (mt76_is_usb(dev)) + req.wow_ctrl_tlv.wakeup_hif = WOW_USB; + else if (mt76_is_sdio(dev)) + req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO; + + return mt76_mcu_send_msg(dev, MCU_UNI_CMD(SUSPEND), &req, + sizeof(req), true); +} + +static int +mt7925_mcu_set_wow_pattern(struct mt76_dev *dev, + struct ieee80211_vif *vif, + u8 index, bool enable, + struct cfg80211_pkt_pattern *pattern) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt7925_wow_pattern_tlv *tlv; + struct sk_buff *skb; + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr = { + .bss_idx = mvif->idx, + }; + + skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*tlv)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + tlv = (struct mt7925_wow_pattern_tlv *)skb_put(skb, sizeof(*tlv)); + tlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); + tlv->len = cpu_to_le16(sizeof(*tlv)); + tlv->bss_idx = 0xF; + tlv->data_len = pattern->pattern_len; + tlv->enable = enable; + tlv->index = index; + tlv->offset = 0; + + memcpy(tlv->pattern, pattern->pattern, pattern->pattern_len); + memcpy(tlv->mask, pattern->mask, DIV_ROUND_UP(pattern->pattern_len, 8)); + + return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SUSPEND), true); +} + +void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_phy *phy = priv; + bool suspend = !test_bit(MT76_STATE_RUNNING, &phy->state); + struct ieee80211_hw *hw = phy->hw; + struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; + int i; + + mt76_connac_mcu_set_gtk_rekey(phy->dev, vif, suspend); + + mt76_connac_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); + + for (i = 0; i < wowlan->n_patterns; i++) + mt7925_mcu_set_wow_pattern(phy->dev, vif, i, suspend, + &wowlan->patterns[i]); + mt7925_connac_mcu_set_wow_ctrl(phy, vif, suspend, wowlan); +} + +#endif /* CONFIG_PM */ + +static void +mt7925_mcu_connection_loss_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt7925_uni_beacon_loss_event *event = priv; + + if (mvif->idx != event->hdr.bss_idx) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) || + vif->type != NL80211_IFTYPE_STATION) + return; + + ieee80211_connection_loss(vif); +} + +static void +mt7925_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct mt7925_uni_beacon_loss_event *event; + struct mt76_phy *mphy = &dev->mt76.phy; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd)); + event = (struct mt7925_uni_beacon_loss_event *)skb->data; + + ieee80211_iterate_active_interfaces_atomic(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_connection_loss_iter, event); +} + +static void +mt7925_mcu_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct mt7925_roc_grant_tlv *grant = priv; + + if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION) + return; + + if (mvif->idx != grant->bss_idx) + return; + + mvif->band_idx = grant->dbdcband; +} + +static void mt7925_mcu_roc_handle_grant(struct mt792x_dev *dev, + struct tlv *tlv) +{ + struct ieee80211_hw *hw = dev->mt76.hw; + struct mt7925_roc_grant_tlv *grant; + int duration; + + grant = (struct mt7925_roc_grant_tlv *)tlv; + + /* should never happen */ + WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT)); + + if (grant->reqtype == MT7925_ROC_REQ_ROC) + ieee80211_ready_on_channel(hw); + else if (grant->reqtype == MT7925_ROC_REQ_JOIN) + ieee80211_iterate_active_interfaces_atomic(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_roc_iter, grant); + dev->phy.roc_grant = true; + wake_up(&dev->phy.roc_wait); + duration = le32_to_cpu(grant->max_interval); + mod_timer(&dev->phy.roc_timer, + jiffies + msecs_to_jiffies(duration)); +} + +static void +mt7925_mcu_handle_hif_ctrl_basic(struct mt792x_dev *dev, struct tlv *tlv) +{ + struct mt7925_mcu_hif_ctrl_basic_tlv *basic; + + basic = (struct mt7925_mcu_hif_ctrl_basic_tlv *)tlv; + + if (basic->hifsuspend) { + if (basic->hif_tx_traffic_status == HIF_TRAFFIC_IDLE && + basic->hif_rx_traffic_status == HIF_TRAFFIC_IDLE) + /* success */ + dev->hif_idle = true; + else + /* busy */ + /* invalid */ + dev->hif_idle = false; + } else { + dev->hif_resumed = true; + } + wake_up(&dev->wait); +} + +static void +mt7925_mcu_uni_hif_ctrl_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct tlv *tlv; + u32 tlv_len; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; + + while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_HIF_CTRL_BASIC: + mt7925_mcu_handle_hif_ctrl_basic(dev, tlv); + break; + default: + break; + } + tlv_len -= le16_to_cpu(tlv->len); + tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); + } +} + +static void +mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct tlv *tlv; + int i = 0; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + + while (i < skb->len) { + tlv = (struct tlv *)(skb->data + i); + + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_ROC_GRANT: + mt7925_mcu_roc_handle_grant(dev, tlv); + break; + case UNI_EVENT_ROC_GRANT_SUB_LINK: + break; + } + + i += le16_to_cpu(tlv->len); + } +} + +static void +mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt792x_phy *phy = mphy->priv; + + spin_lock_bh(&dev->mt76.lock); + __skb_queue_tail(&phy->scan_event_list, skb); + spin_unlock_bh(&dev->mt76.lock); + + ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work, + MT792x_HW_SCAN_TIMEOUT); +} + +static void +mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ +#define UNI_EVENT_TX_DONE_MSG 0 +#define UNI_EVENT_TX_DONE_RAW 1 + struct mt7925_mcu_txs_event { + u8 ver; + u8 rsv[3]; + u8 data[]; + } __packed * txs; + struct tlv *tlv; + u32 tlv_len; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; + + while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_TX_DONE_RAW: + txs = (struct mt7925_mcu_txs_event *)tlv->data; + mt7925_mac_add_txs(dev, txs->data); + break; + default: + break; + } + tlv_len -= le16_to_cpu(tlv->len); + tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); + } +} + +static void +mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct mt7925_uni_debug_msg { + __le16 tag; + __le16 len; + u8 fmt; + u8 rsv[3]; + u8 id; + u8 type:3; + u8 nr_args:5; + union { + struct idxlog { + __le16 rsv; + __le32 ts; + __le32 idx; + u8 data[]; + } __packed idx; + struct txtlog { + u8 len; + u8 rsv; + __le32 ts; + u8 data[]; + } __packed txt; + }; + } __packed * hdr; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + hdr = (struct mt7925_uni_debug_msg *)skb->data; + + if (hdr->id == 0x28) { + skb_pull(skb, offsetof(struct mt7925_uni_debug_msg, id)); + wiphy_info(mt76_hw(dev)->wiphy, "%.*s", skb->len, skb->data); + return; + } else if (hdr->id != 0xa8) { + return; + } + + if (hdr->type == 0) { /* idx log */ + int i, ret, len = PAGE_SIZE - 1, nr_val; + struct page *page = dev_alloc_pages(get_order(len)); + __le32 *val; + char *buf, *cur; + + if (!page) + return; + + buf = page_address(page); + cur = buf; + + nr_val = (le16_to_cpu(hdr->len) - sizeof(*hdr)) / 4; + val = (__le32 *)hdr->idx.data; + for (i = 0; i < nr_val && len > 0; i++) { + ret = snprintf(cur, len, "0x%x,", le32_to_cpu(val[i])); + if (ret <= 0) + break; + + cur += ret; + len -= ret; + } + if (cur > buf) + wiphy_info(mt76_hw(dev)->wiphy, "idx: 0x%X,%d,%s", + le32_to_cpu(hdr->idx.idx), nr_val, buf); + put_page(page); + } else if (hdr->type == 2) { /* str log */ + wiphy_info(mt76_hw(dev)->wiphy, "%.*s", hdr->txt.len, hdr->txt.data); + } +} + +static void +mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev, + struct sk_buff *skb) +{ + struct mt7925_mcu_rxd *rxd; + + rxd = (struct mt7925_mcu_rxd *)skb->data; + + switch (rxd->eid) { + case MCU_UNI_EVENT_HIF_CTRL: + mt7925_mcu_uni_hif_ctrl_event(dev, skb); + break; + case MCU_UNI_EVENT_FW_LOG_2_HOST: + mt7925_mcu_uni_debug_msg_event(dev, skb); + break; + case MCU_UNI_EVENT_ROC: + mt7925_mcu_uni_roc_event(dev, skb); + break; + case MCU_UNI_EVENT_SCAN_DONE: + mt7925_mcu_scan_event(dev, skb); + return; + case MCU_UNI_EVENT_TX_DONE: + mt7925_mcu_tx_done_event(dev, skb); + break; + case MCU_UNI_EVENT_BSS_BEACON_LOSS: + mt7925_mcu_connection_loss_event(dev, skb); + break; + case MCU_UNI_EVENT_COREDUMP: + dev->fw_assert = true; + mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); + return; + default: + break; + } + dev_kfree_skb(skb); +} + +void mt7925_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct mt7925_mcu_rxd *rxd = (struct mt7925_mcu_rxd *)skb->data; + + if (skb_linearize(skb)) + return; + + if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) { + mt7925_mcu_uni_rx_unsolicited_event(dev, skb); + return; + } + + mt76_mcu_rx_event(&dev->mt76, skb); +} + +static int +mt7925_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, + struct mt76_wcid *wcid, + struct ieee80211_ampdu_params *params, + bool enable, bool tx) +{ + struct sta_rec_ba_uni *ba; + struct sk_buff *skb; + struct tlv *tlv; + int len; + + len = sizeof(struct sta_req_hdr) + sizeof(*ba); + skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); + + ba = (struct sta_rec_ba_uni *)tlv; + ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT; + ba->winsize = cpu_to_le16(params->buf_size); + ba->ssn = cpu_to_le16(params->ssn); + ba->ba_en = enable << params->tid; + ba->amsdu = params->amsdu; + ba->tid = params->tid; + + return mt76_mcu_skb_send_msg(dev, skb, + MCU_UNI_CMD(STA_REC_UPDATE), true); +} + +/** starec & wtbl **/ +int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params, + bool enable) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct mt76_wcid *wcid; + u8 link_id, ret; + + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + wcid = &mlink->wcid; + + if (enable && !params->amsdu) + mlink->wcid.amsdu = false; + + ret = mt7925_mcu_sta_ba(&dev->mt76, &mconf->mt76, wcid, params, + enable, true); + if (ret < 0) + break; + } + + return ret; +} + +int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params, + bool enable) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct mt76_wcid *wcid; + u8 link_id, ret; + + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + mconf = mt792x_vif_to_link(mvif, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + wcid = &mlink->wcid; + + ret = mt7925_mcu_sta_ba(&dev->mt76, &mconf->mt76, wcid, params, + enable, false); + if (ret < 0) + break; + } + + return ret; +} + +static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name) +{ + const struct mt76_connac2_fw_trailer *hdr; + const struct mt76_connac2_fw_region *region; + const struct mt7925_clc *clc; + struct mt76_dev *mdev = &dev->mt76; + struct mt792x_phy *phy = &dev->phy; + const struct firmware *fw; + int ret, i, len, offset = 0; +#if defined(__linux__) + u8 *clc_base = NULL; +#elif defined(__FreeBSD__) + const u8 *clc_base = NULL; +#endif + + if (mt7925_disable_clc || + mt76_is_usb(&dev->mt76)) + return 0; + + ret = request_firmware(&fw, fw_name, mdev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(mdev->dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); + for (i = 0; i < hdr->n_region; i++) { + region = (const void *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + len = le32_to_cpu(region->len); + + /* check if we have valid buffer size */ + if (offset + len > fw->size) { + dev_err(mdev->dev, "Invalid firmware region\n"); + ret = -EINVAL; + goto out; + } + + if ((region->feature_set & FW_FEATURE_NON_DL) && + region->type == FW_TYPE_CLC) { +#if defined(__linux__) + clc_base = (u8 *)(fw->data + offset); +#elif defined(__FreeBSD__) + clc_base = (const u8 *)(fw->data + offset); +#endif + break; + } + offset += len; + } + + if (!clc_base) + goto out; + + for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { + clc = (const struct mt7925_clc *)(clc_base + offset); + + if (clc->idx >= ARRAY_SIZE(phy->clc)) + break; + + /* do not init buf again if chip reset triggered */ + if (phy->clc[clc->idx]) + continue; + + phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc, + le32_to_cpu(clc->len), + GFP_KERNEL); + + if (!phy->clc[clc->idx]) { + ret = -ENOMEM; + goto out; + } + } + + ret = mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR); +out: + release_firmware(fw); + + return ret; +} + +int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + u8 ctrl; + u8 interval; + u8 _rsv2[2]; + } __packed req = { + .tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_LOG_CTRL), + .len = cpu_to_le16(sizeof(req) - 4), + .ctrl = ctrl, + }; + int ret; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(WSYS_CONFIG), + &req, sizeof(req), false, NULL); + return ret; +} + +int mt7925_mcu_get_temperature(struct mt792x_phy *phy) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + u8 _rsv2[4]; + } __packed req = { + .tag = cpu_to_le16(0x0), + .len = cpu_to_le16(sizeof(req) - 4), + }; + struct mt7925_thermal_evt { + u8 rsv[4]; + __le32 temperature; + } __packed * evt; + struct mt792x_dev *dev = phy->dev; + int temperature, ret; + struct sk_buff *skb; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_WM_UNI_CMD_QUERY(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + skb_pull(skb, 4 + sizeof(struct tlv)); + evt = (struct mt7925_thermal_evt *)skb->data; + + temperature = le32_to_cpu(evt->temperature); + + dev_kfree_skb(skb); + + return temperature; +} + +static void +mt7925_mcu_parse_phy_cap(struct mt792x_dev *dev, char *data) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt76_dev *mdev = mphy->dev; + struct mt7925_mcu_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; + u8 eht; + } __packed * cap; + enum { + WF0_24G, + WF0_5G + }; + + cap = (struct mt7925_mcu_phy_cap *)data; + + mdev->phy.antenna_mask = BIT(cap->nss) - 1; + mdev->phy.chainmask = mdev->phy.antenna_mask; + mdev->phy.cap.has_2ghz = cap->hw_path & BIT(WF0_24G); + mdev->phy.cap.has_5ghz = cap->hw_path & BIT(WF0_5G); + dev->has_eht = cap->eht; +} + +static void +mt7925_mcu_parse_eml_cap(struct mt792x_dev *dev, char *data) +{ + struct mt7925_mcu_eml_cap { + u8 rsv[4]; + __le16 eml_cap; + u8 rsv2[6]; + } __packed * cap; + + cap = (struct mt7925_mcu_eml_cap *)data; + + dev->phy.eml_cap = le16_to_cpu(cap->eml_cap); +} + +static int +mt7925_mcu_get_nic_capability(struct mt792x_dev *dev) +{ + struct mt76_phy *mphy = &dev->mt76.phy; + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + } __packed req = { + .tag = cpu_to_le16(UNI_CHIP_CONFIG_NIC_CAPA), + .len = cpu_to_le16(sizeof(req) - 4), + }; + 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(&dev->mt76, MCU_UNI_CMD(CHIP_CONFIG), + &req, sizeof(req), 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 *tlv = (struct tlv *)skb->data; + int len; + + if (skb->len < sizeof(*tlv)) + break; + + len = le16_to_cpu(tlv->len); + if (skb->len < len) + break; + + switch (le16_to_cpu(tlv->tag)) { + case MT_NIC_CAP_6G: + mphy->cap.has_6ghz = !!tlv->data[0]; + break; + case MT_NIC_CAP_MAC_ADDR: + memcpy(mphy->macaddr, (void *)tlv->data, ETH_ALEN); + break; + case MT_NIC_CAP_PHY: + mt7925_mcu_parse_phy_cap(dev, tlv->data); + break; + case MT_NIC_CAP_CHIP_CAP: + dev->phy.chip_cap = le64_to_cpu(*(__le64 *)tlv->data); + break; + case MT_NIC_CAP_EML_CAP: + mt7925_mcu_parse_eml_cap(dev, tlv->data); + break; + default: + break; + } + skb_pull(skb, len); + } +out: + dev_kfree_skb(skb); + return ret; +} + +int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd) +{ + u16 len = strlen(cmd) + 1; + struct { + u8 _rsv[4]; + __le16 tag; + __le16 len; + struct mt76_connac_config config; + } __packed req = { + .tag = cpu_to_le16(UNI_CHIP_CONFIG_CHIP_CFG), + .len = cpu_to_le16(sizeof(req) - 4), + .config = { + .resp_type = 0, + .type = 0, + .data_size = cpu_to_le16(len), + }, + }; + + memcpy(req.config.data, cmd, len); + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(CHIP_CONFIG), + &req, sizeof(req), false); +} + +int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable) +{ + char cmd[16]; + + snprintf(cmd, sizeof(cmd), "KeepFullPwr %d", !enable); + + return mt7925_mcu_chip_config(dev, cmd); +} +EXPORT_SYMBOL_GPL(mt7925_mcu_set_deep_sleep); + +int mt7925_run_firmware(struct mt792x_dev *dev) +{ + int err; + + err = mt792x_load_firmware(dev); + if (err) + return err; + + err = mt7925_mcu_get_nic_capability(dev); + if (err) + return err; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + err = mt7925_load_clc(dev, mt792x_ram_name(dev)); + if (err) + return err; + + return mt7925_mcu_fw_log_2_host(dev, 1); +} +EXPORT_SYMBOL_GPL(mt7925_run_firmware); + +static void +mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct sta_rec_hdr_trans *hdr_trans; + struct mt76_wcid *wcid; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans)); + hdr_trans = (struct sta_rec_hdr_trans *)tlv; + hdr_trans->dis_rx_hdr_tran = true; + + if (vif->type == NL80211_IFTYPE_STATION) + hdr_trans->to_ds = true; + else + hdr_trans->from_ds = true; + + if (link_sta) { + struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + struct mt792x_link_sta *mlink; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + wcid = &mlink->wcid; + } else { + wcid = &mvif->sta.deflink.wcid; + } + + if (!wcid) + return; + + hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); + if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { + hdr_trans->to_ds = true; + hdr_trans->from_ds = true; + } +} + +int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + int link_id) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; + struct mt792x_link_sta *mlink; + struct mt792x_bss_conf *mconf; + struct mt792x_sta *msta; + struct sk_buff *skb; + + msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; + + mlink = mt792x_sta_to_link(msta, link_id); + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); + mconf = mt792x_vif_to_link(mvif, link_id); + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, + &mlink->wcid, + MT7925_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* starec hdr trans */ + mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta); + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + +int mt7925_mcu_set_tx(struct mt792x_dev *dev, + struct ieee80211_bss_conf *bss_conf) +{ +#define MCU_EDCA_AC_PARAM 0 +#define WMM_AIFS_SET BIT(0) +#define WMM_CW_MIN_SET BIT(1) +#define WMM_CW_MAX_SET BIT(2) +#define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ + WMM_CW_MAX_SET | WMM_TXOP_SET) + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(bss_conf); + struct { + u8 bss_idx; + u8 __rsv[3]; + } __packed hdr = { + .bss_idx = mconf->mt76.idx, + }; + struct sk_buff *skb; + int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca); + int ac; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &hdr, sizeof(hdr)); + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_tx_queue_params *q = &mconf->queue_params[ac]; + struct edca *e; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, MCU_EDCA_AC_PARAM, sizeof(*e)); + + e = (struct edca *)tlv; + e->set = WMM_PARAM_SET; + e->queue = ac; + e->aifs = q->aifs; + e->txop = cpu_to_le16(q->txop); + + if (q->cw_min) + e->cw_min = fls(q->cw_min); + else + e->cw_min = 5; + + if (q->cw_max) + e->cw_max = fls(q->cw_max); + else + e->cw_max = 10; + } + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(EDCA_UPDATE), true); +} + +static int +mt7925_mcu_sta_key_tlv(struct mt76_wcid *wcid, + struct mt76_connac_sta_key_conf *sta_key_conf, + struct sk_buff *skb, + struct ieee80211_key_conf *key, + enum set_key_cmd cmd, + struct mt792x_sta *msta) +{ + struct mt792x_vif *mvif = msta->vif; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id); + struct sta_rec_sec_uni *sec; + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + struct tlv *tlv; + + sta = msta == &mvif->sta ? + NULL : + container_of((void *)msta, struct ieee80211_sta, drv_priv); + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V3, sizeof(*sec)); + sec = (struct sta_rec_sec_uni *)tlv; + sec->bss_idx = mconf->mt76.idx; + sec->is_authenticator = 0; + sec->mgmt_prot = 1; /* only used in MLO mode */ + sec->wlan_idx = (u8)wcid->idx; + + if (sta) { + struct ieee80211_link_sta *link_sta; + + sec->tx_key = 1; + sec->key_type = 1; + link_sta = mt792x_sta_to_link_sta(vif, sta, wcid->link_id); + + if (link_sta) + memcpy(sec->peer_addr, link_sta->addr, ETH_ALEN); + } else { + struct ieee80211_bss_conf *link_conf; + + link_conf = mt792x_vif_to_bss_conf(vif, wcid->link_id); + + if (link_conf) + memcpy(sec->peer_addr, link_conf->bssid, ETH_ALEN); + } + + if (cmd == SET_KEY) { + u8 cipher; + + sec->add = 1; + cipher = mt7925_mcu_get_cipher(key->cipher); + if (cipher == CONNAC3_CIPHER_NONE) + return -EOPNOTSUPP; + + if (cipher == CONNAC3_CIPHER_BIP_CMAC_128) { + sec->cipher_id = CONNAC3_CIPHER_BIP_CMAC_128; + sec->key_id = sta_key_conf->keyidx; + sec->key_len = 32; + memcpy(sec->key, sta_key_conf->key, 16); + memcpy(sec->key + 16, key->key, 16); + } else { + sec->cipher_id = cipher; + sec->key_id = key->keyidx; + sec->key_len = key->keylen; + memcpy(sec->key, key->key, key->keylen); + + if (cipher == CONNAC3_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec->key + 16, key->key + 24, 8); + memcpy(sec->key + 24, key->key + 16, 8); + } + + /* store key_conf for BIP batch update */ + if (cipher == CONNAC3_CIPHER_AES_CCMP) { + memcpy(sta_key_conf->key, key->key, key->keylen); + sta_key_conf->keyidx = key->keyidx; + } + } + } else { + sec->add = 0; + } + + return 0; +} + +int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + struct mt76_connac_sta_key_conf *sta_key_conf, + struct ieee80211_key_conf *key, int mcu_cmd, + struct mt76_wcid *wcid, enum set_key_cmd cmd, + struct mt792x_sta *msta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_vif_to_link(mvif, wcid->link_id); + struct sk_buff *skb; + int ret; + + skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, wcid, + MT7925_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); + if (ret) + return ret; + + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); +} + +int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + int duration, u8 token_id) +{ + struct mt792x_vif *mvif = mconf->vif; + struct ieee80211_vif *vif = container_of((void *)mvif, + struct ieee80211_vif, drv_priv); + struct ieee80211_bss_conf *link_conf; + struct ieee80211_channel *chan; + const u8 ch_band[] = { + [NL80211_BAND_2GHZ] = 1, + [NL80211_BAND_5GHZ] = 2, + [NL80211_BAND_6GHZ] = 3, + }; + enum mt7925_roc_req type; + int center_ch, i = 0; + bool is_AG_band = false; + struct { + u8 id; + u8 bss_idx; + u16 tag; + struct mt792x_bss_conf *mconf; + struct ieee80211_channel *chan; + } links[2]; + + struct { + struct { + u8 rsv[4]; + } __packed hdr; + struct roc_acquire_tlv roc[2]; + } __packed req = { + .roc[0].tag = cpu_to_le16(UNI_ROC_NUM), + .roc[0].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)), + .roc[1].tag = cpu_to_le16(UNI_ROC_NUM), + .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) + }; + + if (!mconf || hweight16(vif->valid_links) < 2 || + hweight16(sel_links) != 2) + return -EPERM; + + for (i = 0; i < ARRAY_SIZE(links); i++) { + links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) : + mconf->link_id; + link_conf = mt792x_vif_to_bss_conf(vif, links[i].id); + if (WARN_ON_ONCE(!link_conf)) + return -EPERM; + + links[i].chan = link_conf->chanreq.oper.chan; + if (WARN_ON_ONCE(!links[i].chan)) + return -EPERM; + + links[i].mconf = mt792x_vif_to_link(mvif, links[i].id); + links[i].tag = links[i].id == mconf->link_id ? + UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK; + + is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; + } + + if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) + type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : + MT7925_ROC_REQ_MLSR_AA; + else + type = MT7925_ROC_REQ_JOIN; + + for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) { + if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan)) + continue; + + chan = links[i].chan; + center_ch = ieee80211_frequency_to_channel(chan->center_freq); + req.roc[i].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)); + req.roc[i].tag = cpu_to_le16(links[i].tag); + req.roc[i].tokenid = token_id; + req.roc[i].reqtype = type; + req.roc[i].maxinterval = cpu_to_le32(duration); + req.roc[i].bss_idx = links[i].mconf->mt76.idx; + req.roc[i].control_channel = chan->hw_value; + req.roc[i].bw = CMD_CBW_20MHZ; + req.roc[i].bw_from_ap = CMD_CBW_20MHZ; + req.roc[i].center_chan = center_ch; + req.roc[i].center_chan_from_ap = center_ch; + req.roc[i].center_chan2 = 0; + req.roc[i].center_chan2_from_ap = 0; + + /* STR : 0xfe indicates BAND_ALL with enabling DBDC + * EMLSR : 0xff indicates (BAND_AUTO) without DBDC + */ + req.roc[i].dbdcband = type == MT7925_ROC_REQ_JOIN ? 0xfe : 0xff; + + if (chan->hw_value < center_ch) + req.roc[i].sco = 1; /* SCA */ + else if (chan->hw_value > center_ch) + req.roc[i].sco = 3; /* SCB */ + + req.roc[i].band = ch_band[chan->band]; + } + + return mt76_mcu_send_msg(&mvif->phy->dev->mt76, MCU_UNI_CMD(ROC), + &req, sizeof(req), true); +} + +int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, int duration, + enum mt7925_roc_req type, u8 token_id) +{ + int center_ch = ieee80211_frequency_to_channel(chan->center_freq); + struct mt792x_dev *dev = phy->dev; + struct { + struct { + u8 rsv[4]; + } __packed hdr; + struct roc_acquire_tlv roc; + } __packed req = { + .roc = { + .tag = cpu_to_le16(UNI_ROC_ACQUIRE), + .len = cpu_to_le16(sizeof(struct roc_acquire_tlv)), + .tokenid = token_id, + .reqtype = type, + .maxinterval = cpu_to_le32(duration), + .bss_idx = mconf->mt76.idx, + .control_channel = chan->hw_value, + .bw = CMD_CBW_20MHZ, + .bw_from_ap = CMD_CBW_20MHZ, + .center_chan = center_ch, + .center_chan_from_ap = center_ch, + .dbdcband = 0xff, /* auto */ + }, + }; + + if (chan->hw_value < center_ch) + req.roc.sco = 1; /* SCA */ + else if (chan->hw_value > center_ch) + req.roc.sco = 3; /* SCB */ + + switch (chan->band) { + case NL80211_BAND_6GHZ: + req.roc.band = 3; + break; + case NL80211_BAND_5GHZ: + req.roc.band = 2; + break; + default: + req.roc.band = 1; + break; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), + &req, sizeof(req), true); +} + +int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + u8 token_id) +{ + struct mt792x_dev *dev = phy->dev; + struct { + struct { + u8 rsv[4]; + } __packed hdr; + struct roc_abort_tlv { + __le16 tag; + __le16 len; + u8 bss_idx; + u8 tokenid; + u8 dbdcband; + u8 rsv[5]; + } __packed abort; + } __packed req = { + .abort = { + .tag = cpu_to_le16(UNI_ROC_ABORT), + .len = cpu_to_le16(sizeof(struct roc_abort_tlv)), + .tokenid = token_id, + .bss_idx = mconf->mt76.idx, + .dbdcband = 0xff, /* auto*/ + }, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC), + &req, sizeof(req), true); +} + +int mt7925_mcu_set_eeprom(struct mt792x_dev *dev) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + u8 buffer_mode; + u8 format; + __le16 buf_len; + } __packed req = { + .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), + .len = cpu_to_le16(sizeof(req) - 4), + .buffer_mode = EE_MODE_EFUSE, + .format = EE_FORMAT_WHOLE + }; + + return mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(EFUSE_CTRL), + &req, sizeof(req), false, NULL); +} +EXPORT_SYMBOL_GPL(mt7925_mcu_set_eeprom); + +int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct ps_tlv { + __le16 tag; + __le16 len; + u8 ps_state; /* 0: device awake + * 1: static power save + * 2: dynamic power saving + * 3: enter TWT power saving + * 4: leave TWT power saving + */ + u8 pad[3]; + } __packed ps; + } __packed ps_req = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .ps = { + .tag = cpu_to_le16(UNI_BSS_INFO_PS), + .len = cpu_to_le16(sizeof(struct ps_tlv)), + .ps_state = link_conf->vif->cfg.ps ? 2 : 0, + }, + }; + + if (link_conf->vif->type != NL80211_IFTYPE_STATION) + return -EOPNOTSUPP; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), + &ps_req, sizeof(ps_req), true); +} + +int +mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, bool enable) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bcnft_tlv { + __le16 tag; + __le16 len; + __le16 bcn_interval; + u8 dtim_period; + u8 bmc_delivered_ac; + u8 bmc_triggered_ac; + u8 pad[3]; + } __packed bcnft; + } __packed bcnft_req = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .bcnft = { + .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), + .len = cpu_to_le16(sizeof(struct bcnft_tlv)), + .bcn_interval = cpu_to_le16(link_conf->beacon_int), + .dtim_period = link_conf->dtim_period, + }, + }; + + if (link_conf->vif->type != NL80211_IFTYPE_STATION) + return 0; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), + &bcnft_req, sizeof(bcnft_req), true); +} + +int +mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, + bool enable) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bcnft_tlv { + __le16 tag; + __le16 len; + __le16 bcn_interval; + u8 dtim_period; + u8 bmc_delivered_ac; + u8 bmc_triggered_ac; + u8 pad[3]; + } __packed enable; + } req = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .enable = { + .tag = cpu_to_le16(UNI_BSS_INFO_BCNFT), + .len = cpu_to_le16(sizeof(struct bcnft_tlv)), + .dtim_period = link_conf->dtim_period, + .bcn_interval = cpu_to_le16(link_conf->beacon_int), + }, + }; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct pm_disable { + __le16 tag; + __le16 len; + } __packed disable; + } req1 = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .disable = { + .tag = cpu_to_le16(UNI_BSS_INFO_PM_DISABLE), + .len = cpu_to_le16(sizeof(struct pm_disable)) + }, + }; + int err; + + err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), + &req1, sizeof(req1), true); + if (err < 0 || !enable) + return err; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), + &req, sizeof(req), true); +} + +static void +mt7925_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) +{ + if (!link_sta->he_cap.has_he) + return; + + mt76_connac_mcu_sta_he_tlv_v2(skb, link_sta->sta); +} + +static void +mt7925_mcu_sta_he_6g_tlv(struct sk_buff *skb, + struct ieee80211_link_sta *link_sta) +{ + struct sta_rec_he_6g_capa *he_6g; + struct tlv *tlv; + + if (!link_sta->he_6ghz_capa.capa) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g)); + + he_6g = (struct sta_rec_he_6g_capa *)tlv; + he_6g->capa = link_sta->he_6ghz_capa.capa; +} + +static void +mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) +{ + struct ieee80211_eht_mcs_nss_supp *mcs_map; + struct ieee80211_eht_cap_elem_fixed *elem; + struct sta_rec_eht *eht; + struct tlv *tlv; + + if (!link_sta->eht_cap.has_eht) + return; + + mcs_map = &link_sta->eht_cap.eht_mcs_nss_supp; + elem = &link_sta->eht_cap.eht_cap_elem; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht)); + + eht = (struct sta_rec_eht *)tlv; + eht->tid_bitmap = 0xff; + eht->mac_cap = cpu_to_le16(*(u16 *)elem->mac_cap_info); + eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info); + eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]); + + if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) + memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); + memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); + memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); +} + +static void +mt7925_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) +{ + struct sta_rec_ht *ht; + struct tlv *tlv; + + if (!link_sta->ht_cap.ht_supported) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); + + ht = (struct sta_rec_ht *)tlv; + ht->ht_cap = cpu_to_le16(link_sta->ht_cap.cap); +} + +static void +mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) +{ + struct sta_rec_vht *vht; + struct tlv *tlv; + + /* For 6G band, this tlv is necessary to let hw work normally */ + if (!link_sta->he_6ghz_capa.capa && !link_sta->vht_cap.vht_supported) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); + + vht = (struct sta_rec_vht *)tlv; + vht->vht_cap = cpu_to_le32(link_sta->vht_cap.cap); + vht->vht_rx_mcs_map = link_sta->vht_cap.vht_mcs.rx_mcs_map; + vht->vht_tx_mcs_map = link_sta->vht_cap.vht_mcs.tx_mcs_map; +} + +static void +mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + struct mt792x_link_sta *mlink; + struct sta_rec_amsdu *amsdu; + struct tlv *tlv; + + if (vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_AP) + return; + + if (!link_sta->agg.max_amsdu_len) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); + amsdu = (struct sta_rec_amsdu *)tlv; + amsdu->max_amsdu_num = 8; + amsdu->amsdu_en = true; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + mlink->wcid.amsdu = true; + + switch (link_sta->agg.max_amsdu_len) { + case IEEE80211_MAX_MPDU_LEN_VHT_11454: + amsdu->max_mpdu_size = + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + return; + case IEEE80211_MAX_MPDU_LEN_HT_7935: + case IEEE80211_MAX_MPDU_LEN_VHT_7991: + amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; + return; + default: + amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; + return; + } +} + +static void +mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf; + struct cfg80211_chan_def *chandef; + struct mt792x_bss_conf *mconf; + struct sta_rec_phy *phy; + struct tlv *tlv; + u8 af = 0, mm = 0; + + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); + phy = (struct sta_rec_phy *)tlv; + phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, + chandef->chan->band, + link_sta); + phy->basic_rate = cpu_to_le16((u16)link_conf->basic_rates); + if (link_sta->ht_cap.ht_supported) { + af = link_sta->ht_cap.ampdu_factor; + mm = link_sta->ht_cap.ampdu_density; + } + + if (link_sta->vht_cap.vht_supported) { + u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + link_sta->vht_cap.cap); + + af = max_t(u8, af, vht_af); + } + + if (link_sta->he_6ghz_capa.capa) { + af = le16_get_bits(link_sta->he_6ghz_capa.capa, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); + mm = le16_get_bits(link_sta->he_6ghz_capa.capa, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); + } + + phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) | + FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm); + phy->max_ampdu_len = af; +} + +static void +mt7925_mcu_sta_state_v2_tlv(struct mt76_phy *mphy, struct sk_buff *skb, + struct ieee80211_link_sta *link_sta, + struct ieee80211_vif *vif, + u8 rcpi, u8 sta_state) +{ + struct sta_rec_state_v2 { + __le16 tag; + __le16 len; + u8 state; + u8 rsv[3]; + __le32 flags; + u8 vht_opmode; + u8 action; + u8 rsv2[2]; + } __packed * state; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state)); + state = (struct sta_rec_state_v2 *)tlv; + state->state = sta_state; + + if (link_sta->vht_cap.vht_supported) { + state->vht_opmode = link_sta->bandwidth; + state->vht_opmode |= link_sta->rx_nss << + IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT; + } +} + +static void +mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf; + struct cfg80211_chan_def *chandef; + struct sta_rec_ra_info *ra_info; + struct mt792x_bss_conf *mconf; + enum nl80211_band band; + struct tlv *tlv; + u16 supp_rates; + + link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id); + mconf = mt792x_vif_to_link(mvif, link_sta->link_id); + chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : + &link_conf->chanreq.oper; + band = chandef->chan->band; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); + ra_info = (struct sta_rec_ra_info *)tlv; + + supp_rates = link_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 (link_sta->ht_cap.ht_supported) + memcpy(ra_info->rx_mcs_bitmask, + link_sta->ht_cap.mcs.rx_mask, + HT_MCS_MASK_NUM); +} + +static void +mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct wiphy *wiphy = mvif->phy->mt76->hw->wiphy; + const struct wiphy_iftype_ext_capab *ext_capa; + struct sta_rec_eht_mld *eht_mld; + struct tlv *tlv; + u16 eml_cap; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld)); + eht_mld = (struct sta_rec_eht_mld *)tlv; + eht_mld->mld_type = 0xff; + + if (!ieee80211_vif_is_mld(vif)) + return; + + ext_capa = cfg80211_get_iftype_ext_capa(wiphy, + ieee80211_vif_type_p2p(vif)); + if (!ext_capa) + return; + + eml_cap = (vif->cfg.eml_cap & (IEEE80211_EML_CAP_EMLSR_SUPP | + IEEE80211_EML_CAP_TRANSITION_TIMEOUT)) | + (ext_capa->eml_capabilities & (IEEE80211_EML_CAP_EMLSR_PADDING_DELAY | + IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)); + + if (eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) { + eht_mld->eml_cap[0] = u16_get_bits(eml_cap, GENMASK(7, 0)); + eht_mld->eml_cap[1] = u16_get_bits(eml_cap, GENMASK(15, 8)); + } else { + eht_mld->str_cap[0] = BIT(1); + } +} + +static void +mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned long valid = mvif->valid_links; + struct mt792x_bss_conf *mconf; + struct mt792x_link_sta *mlink; + struct sta_rec_mld *mld; + struct tlv *tlv; + int i, cnt = 0; + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); + mld = (struct sta_rec_mld *)tlv; + memcpy(mld->mac_addr, sta->addr, ETH_ALEN); + mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); + mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx); + mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2); + + for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + if (cnt == mld->link_num) + break; + + mconf = mt792x_vif_to_link(mvif, i); + mlink = mt792x_sta_to_link(msta, i); + mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); + mld->link[cnt++].bss_idx = mconf->mt76.idx; + + if (mlink != &msta->deflink) + mld->secondary_id = cpu_to_le16(mlink->wcid.idx); + } +} + +static int +mt7925_mcu_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)info->vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct sk_buff *skb; + int conn_state; + + skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, info->wcid, + MT7925_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + conn_state = info->enable ? CONN_STATE_PORT_SECURE : + CONN_STATE_DISCONNECT; + if (info->link_sta) + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, + info->link_sta, + conn_state, info->newly); + if (info->link_sta && info->enable) { + mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_ht_tlv(skb, info->link_sta); + mt7925_mcu_sta_vht_tlv(skb, info->link_sta); + mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_he_tlv(skb, info->link_sta); + mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); + mt7925_mcu_sta_eht_tlv(skb, info->link_sta); + mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, + info->link_sta); + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, + info->vif, info->rcpi, + info->state); + mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); + } + + if (info->enable) + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); + + return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); +} + +static void +mt7925_mcu_sta_remove_tlv(struct sk_buff *skb) +{ + struct sta_rec_remove *rem; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, 0x25, sizeof(*rem)); + rem = (struct sta_rec_remove *)tlv; + rem->action = 0; +} + +static int +mt7925_mcu_mlo_sta_cmd(struct mt76_phy *phy, + struct mt76_sta_cmd_info *info) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; + struct mt76_dev *dev = phy->dev; + struct mt792x_bss_conf *mconf; + struct sk_buff *skb; + + mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); + + skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, + MT7925_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + if (info->enable) + mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, + info->link_sta, + info->enable, info->newly); + + if (info->enable && info->link_sta) { + mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_ht_tlv(skb, info->link_sta); + mt7925_mcu_sta_vht_tlv(skb, info->link_sta); + mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_he_tlv(skb, info->link_sta); + mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); + mt7925_mcu_sta_eht_tlv(skb, info->link_sta); + mt7925_mcu_sta_rate_ctrl_tlv(skb, info->vif, + info->link_sta); + mt7925_mcu_sta_state_v2_tlv(phy, skb, info->link_sta, + info->vif, info->rcpi, + info->state); + + if (info->state != MT76_STA_INFO_STATE_NONE) { + mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); + } + + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); + } + + if (!info->enable) { + mt7925_mcu_sta_remove_tlv(skb); + mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, + sizeof(struct tlv)); + } + + return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); +} + +int mt7925_mcu_sta_update(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); + struct mt76_sta_cmd_info info = { + .link_sta = link_sta, + .vif = vif, + .link_conf = &vif->bss_conf, + .enable = enable, + .cmd = MCU_UNI_CMD(STA_REC_UPDATE), + .state = state, + .offload_fw = true, + .rcpi = to_rcpi(rssi), + }; + struct mt792x_sta *msta; + struct mt792x_link_sta *mlink; + int err; + + if (link_sta) { + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + } + info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; + + if (link_sta) + info.newly = state != MT76_STA_INFO_STATE_ASSOC; + else + info.newly = state == MT76_STA_INFO_STATE_ASSOC ? false : true; + + if (ieee80211_vif_is_mld(vif)) + err = mt7925_mcu_mlo_sta_cmd(&dev->mphy, &info); + else + err = mt7925_mcu_sta_cmd(&dev->mphy, &info); + + return err; +} + +int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + bool enable) +{ +#define MT7925_FIF_BIT_CLR BIT(1) +#define MT7925_FIF_BIT_SET BIT(0) + int err = 0; + + if (enable) { + err = mt7925_mcu_uni_bss_bcnft(dev, &vif->bss_conf, true); + if (err < 0) + return err; + + return mt7925_mcu_set_rxfilter(dev, 0, + MT7925_FIF_BIT_SET, + MT_WF_RFCR_DROP_OTHER_BEACON); + } + + err = mt7925_mcu_set_bss_pm(dev, &vif->bss_conf, false); + if (err < 0) + return err; + + return mt7925_mcu_set_rxfilter(dev, 0, + MT7925_FIF_BIT_CLR, + MT_WF_RFCR_DROP_OTHER_BEACON); +} + +int mt7925_get_txpwr_info(struct mt792x_dev *dev, u8 band_idx, struct mt7925_txpwr *txpwr) +{ +#define TX_POWER_SHOW_INFO 0x7 +#define TXPOWER_ALL_RATE_POWER_INFO 0x2 + struct mt7925_txpwr_event *event; + struct mt7925_txpwr_req req = { + .tag = cpu_to_le16(TX_POWER_SHOW_INFO), + .len = cpu_to_le16(sizeof(req) - 4), + .catg = TXPOWER_ALL_RATE_POWER_INFO, + .band_idx = band_idx, + }; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(TXPOWER), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + event = (struct mt7925_txpwr_event *)skb->data; + memcpy(txpwr, &event->txpwr, sizeof(event->txpwr)); + + dev_kfree_skb(skb); + + return 0; +} + +int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, + bool enable) +{ + struct { + struct { + u8 band_idx; + u8 pad[3]; + } __packed hdr; + struct sniffer_enable_tlv { + __le16 tag; + __le16 len; + u8 enable; + u8 pad[3]; + } __packed enable; + } __packed req = { + .hdr = { + .band_idx = 0, + }, + .enable = { + .tag = cpu_to_le16(UNI_SNIFFER_ENABLE), + .len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)), + .enable = enable, + }, + }; + + mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), + true); +} + +int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct mt76_phy *mphy = vif->phy->mt76; + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &mphy->chandef; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; + + static const u8 ch_band[] = { + [NL80211_BAND_2GHZ] = 1, + [NL80211_BAND_5GHZ] = 2, + [NL80211_BAND_6GHZ] = 3, + }; + static const u8 ch_width[] = { + [NL80211_CHAN_WIDTH_20_NOHT] = 0, + [NL80211_CHAN_WIDTH_20] = 0, + [NL80211_CHAN_WIDTH_40] = 0, + [NL80211_CHAN_WIDTH_80] = 1, + [NL80211_CHAN_WIDTH_160] = 2, + [NL80211_CHAN_WIDTH_80P80] = 3, + [NL80211_CHAN_WIDTH_5] = 4, + [NL80211_CHAN_WIDTH_10] = 5, + [NL80211_CHAN_WIDTH_320] = 6, + }; + + struct { + struct { + u8 band_idx; + u8 pad[3]; + } __packed hdr; + struct config_tlv { + __le16 tag; + __le16 len; + u16 aid; + u8 ch_band; + u8 bw; + u8 control_ch; + u8 sco; + u8 center_ch; + u8 center_ch2; + u8 drop_err; + u8 pad[3]; + } __packed tlv; + } __packed req = { + .hdr = { + .band_idx = 0, + }, + .tlv = { + .tag = cpu_to_le16(UNI_SNIFFER_CONFIG), + .len = cpu_to_le16(sizeof(req.tlv)), + .control_ch = chandef->chan->hw_value, + .center_ch = ieee80211_frequency_to_channel(freq1), + .drop_err = 1, + }, + }; + + if (chandef->chan->band < ARRAY_SIZE(ch_band)) + req.tlv.ch_band = ch_band[chandef->chan->band]; + if (chandef->width < ARRAY_SIZE(ch_width)) + req.tlv.bw = ch_width[chandef->width]; + + if (freq2) + req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2); + + if (req.tlv.control_ch < req.tlv.center_ch) + req.tlv.sco = 1; /* SCA */ + else if (req.tlv.control_ch > req.tlv.center_ch) + req.tlv.sco = 3; /* SCB */ + + return mt76_mcu_send_msg(mphy->dev, MCU_UNI_CMD(SNIFFER), + &req, sizeof(req), true); +} + +int +mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, + struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + bool enable) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_mutable_offsets offs; + struct { + struct req_hdr { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bcn_content_tlv { + __le16 tag; + __le16 len; + __le16 tim_ie_pos; + __le16 csa_ie_pos; + __le16 bcc_ie_pos; + /* 0: disable beacon offload + * 1: enable beacon offload + * 2: update probe respond offload + */ + u8 enable; + /* 0: legacy format (TXD + payload) + * 1: only cap field IE + */ + u8 type; + __le16 pkt_len; + u8 pkt[512]; + } __packed beacon_tlv; + } req = { + .hdr = { + .bss_idx = mvif->bss_conf.mt76.idx, + }, + .beacon_tlv = { + .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT), + .len = cpu_to_le16(sizeof(struct bcn_content_tlv)), + .enable = enable, + .type = 1, + }, + }; + struct sk_buff *skb; + u8 cap_offs; + + /* support enable/update process only + * disable flow would be handled in bss stop handler automatically + */ + if (!enable) + return -EOPNOTSUPP; + + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0); + if (!skb) + return -EINVAL; + + cap_offs = offsetof(struct ieee80211_mgmt, u.beacon.capab_info); + if (!skb_pull(skb, cap_offs)) { + dev_err(dev->mt76.dev, "beacon format err\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + + if (skb->len > 512) { + dev_err(dev->mt76.dev, "beacon size limit exceed\n"); + dev_kfree_skb(skb); + return -EINVAL; + } + + memcpy(req.beacon_tlv.pkt, skb->data, skb->len); + req.beacon_tlv.pkt_len = cpu_to_le16(skb->len); + offs.tim_offset -= cap_offs; + req.beacon_tlv.tim_ie_pos = cpu_to_le16(offs.tim_offset); + + if (offs.cntdwn_counter_offs[0]) { + u16 csa_offs; + + csa_offs = offs.cntdwn_counter_offs[0] - cap_offs - 4; + req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs); + } + dev_kfree_skb(skb); + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE), + &req, sizeof(req), true); +} + +static +void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; + enum nl80211_band band = chandef->chan->band; + struct bss_rlm_tlv *req; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req)); + req = (struct bss_rlm_tlv *)tlv; + req->control_channel = chandef->chan->hw_value; + req->center_chan = ieee80211_frequency_to_channel(freq1); + req->center_chan2 = 0; + req->tx_streams = hweight8(phy->antenna_mask); + req->ht_op_info = 4; /* set HT 40M allowed */ + req->rx_streams = hweight8(phy->antenna_mask); + req->center_chan2 = 0; + req->sco = 0; + req->band = 1; + + switch (band) { + case NL80211_BAND_2GHZ: + req->band = 1; + break; + case NL80211_BAND_5GHZ: + req->band = 2; + break; + case NL80211_BAND_6GHZ: + req->band = 3; + break; + default: + break; + } + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_40: + req->bw = CMD_CBW_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + req->bw = CMD_CBW_80MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + req->bw = CMD_CBW_8080MHZ; + req->center_chan2 = ieee80211_frequency_to_channel(freq2); + break; + case NL80211_CHAN_WIDTH_160: + req->bw = CMD_CBW_160MHZ; + break; + case NL80211_CHAN_WIDTH_5: + req->bw = CMD_CBW_5MHZ; + break; + case NL80211_CHAN_WIDTH_10: + req->bw = CMD_CBW_10MHZ; + break; + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + default: + req->bw = CMD_CBW_20MHZ; + req->ht_op_info = 0; + break; + } + + if (req->control_channel < req->center_chan) + req->sco = 1; /* SCA */ + else if (req->control_channel > req->center_chan) + req->sco = 3; /* SCB */ +} + +static struct sk_buff * +__mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int len) +{ + struct bss_req_hdr hdr = { + .bss_idx = mvif->idx, + }; + struct sk_buff *skb; + + skb = mt76_mcu_msg_alloc(dev, NULL, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + skb_put_data(skb, &hdr, sizeof(hdr)); + + return skb; +} + +int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(phy->dev, mvif, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7925_mcu_bss_rlm_tlv(skb, phy, link_conf, ctx); + + return mt76_mcu_skb_send_msg(phy->dev, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + +static u8 +mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, + enum nl80211_band band, + struct ieee80211_link_sta *link_sta) +{ + struct ieee80211_he_6ghz_capa *he_6ghz_capa; + const struct ieee80211_sta_eht_cap *eht_cap; + __le16 capa = 0; + u8 mode = 0; + + if (link_sta) { + he_6ghz_capa = &link_sta->he_6ghz_capa; + eht_cap = &link_sta->eht_cap; + } else { + struct ieee80211_supported_band *sband; + + sband = phy->hw->wiphy->bands[band]; + capa = ieee80211_get_he_6ghz_capa(sband, vif->type); + he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa; + + eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); + } + + switch (band) { + case NL80211_BAND_2GHZ: + if (eht_cap && eht_cap->has_eht) + mode |= PHY_MODE_BE_24G; + break; + case NL80211_BAND_5GHZ: + if (eht_cap && eht_cap->has_eht) + mode |= PHY_MODE_BE_5G; + break; + case NL80211_BAND_6GHZ: + if (he_6ghz_capa && he_6ghz_capa->capa) + mode |= PHY_MODE_AX_6G; + + if (eht_cap && eht_cap->has_eht) + mode |= PHY_MODE_BE_6G; + break; + default: + break; + } + + return mode; +} + +static void +mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + struct ieee80211_chanctx_conf *ctx, + struct mt76_phy *phy, u16 wlan_idx, + bool enable) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; + enum nl80211_band band = chandef->chan->band; + struct mt76_connac_bss_basic_tlv *basic_req; + struct mt792x_link_sta *mlink; + struct tlv *tlv; + int conn_type; + u8 idx; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*basic_req)); + basic_req = (struct mt76_connac_bss_basic_tlv *)tlv; + + idx = mconf->mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 : + mconf->mt76.omac_idx; + basic_req->hw_bss_idx = idx; + + basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, + link_sta); + + if (band == NL80211_BAND_2GHZ) + basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); + else + basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); + + memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN); + basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); + basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); + basic_req->dtim_period = link_conf->dtim_period; + basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); + basic_req->link_idx = mconf->mt76.idx; + + if (link_sta) { + struct mt792x_sta *msta; + + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + + } else { + mlink = &mconf->vif->sta.deflink; + } + + basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx); + basic_req->omac_idx = mconf->mt76.omac_idx; + basic_req->band_idx = mconf->mt76.band_idx; + basic_req->wmm_idx = mconf->mt76.wmm_idx; + basic_req->conn_state = !enable; + + switch (vif->type) { + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_AP: + if (vif->p2p) + conn_type = CONNECTION_P2P_GO; + else + conn_type = CONNECTION_INFRA_AP; + basic_req->conn_type = cpu_to_le32(conn_type); + basic_req->active = enable; + break; + case NL80211_IFTYPE_STATION: + if (vif->p2p) + conn_type = CONNECTION_P2P_GC; + else + conn_type = CONNECTION_INFRA_STA; + basic_req->conn_type = cpu_to_le32(conn_type); + basic_req->active = true; + break; + case NL80211_IFTYPE_ADHOC: + basic_req->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + basic_req->active = true; + break; + default: + WARN_ON(1); + break; + } +} + +static void +mt7925_mcu_bss_sec_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt76_vif_link *mvif = &mconf->mt76; + struct bss_sec_tlv { + __le16 tag; + __le16 len; + u8 mode; + u8 status; + u8 cipher; + u8 __rsv; + } __packed * sec; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec)); + sec = (struct bss_sec_tlv *)tlv; + + switch (mvif->cipher) { + case CONNAC3_CIPHER_GCMP_256: + case CONNAC3_CIPHER_GCMP: + sec->mode = MODE_WPA3_SAE; + sec->status = 8; + break; + case CONNAC3_CIPHER_AES_CCMP: + sec->mode = MODE_WPA2_PSK; + sec->status = 6; + break; + case CONNAC3_CIPHER_TKIP: + sec->mode = MODE_WPA2_PSK; + sec->status = 4; + break; + case CONNAC3_CIPHER_WEP104: + case CONNAC3_CIPHER_WEP40: + sec->mode = MODE_SHARED; + sec->status = 0; + break; + default: + sec->mode = MODE_OPEN; + sec->status = 1; + break; + } + + sec->cipher = mvif->cipher; +} + +static void +mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf) +{ + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + enum nl80211_band band = chandef->chan->band; + struct mt76_vif_link *mvif = &mconf->mt76; + struct bss_rate_tlv *bmc; + struct tlv *tlv; + u8 idx = mvif->mcast_rates_idx ? + mvif->mcast_rates_idx : mvif->basic_rates_idx; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc)); + + bmc = (struct bss_rate_tlv *)tlv; + + if (band == NL80211_BAND_2GHZ) + bmc->basic_rate = cpu_to_le16(HR_DSSS_ERP_BASIC_RATE); + else + bmc->basic_rate = cpu_to_le16(OFDM_BASIC_RATE); + + bmc->short_preamble = (band == NL80211_BAND_2GHZ); + bmc->bc_fixed_rate = idx; + bmc->mc_fixed_rate = idx; +} + +static void +mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct bss_mld_tlv *mld; + struct tlv *tlv; + bool is_mld; + + is_mld = ieee80211_vif_is_mld(link_conf->vif) || + (hweight16(mvif->valid_links) > 1); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); + mld = (struct bss_mld_tlv *)tlv; + + mld->link_id = is_mld ? link_conf->link_id : 0xff; + /* apply the index of the primary link */ + mld->group_mld_id = is_mld ? mvif->bss_conf.mt76.idx : 0xff; + mld->own_mld_id = mconf->mt76.idx + 32; + mld->remap_idx = 0xff; + mld->eml_enable = !!(link_conf->vif->cfg.eml_cap & + IEEE80211_EML_CAP_EMLSR_SUPP); + + memcpy(mld->mac_addr, vif->addr, ETH_ALEN); +} + +static void +mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf) +{ + struct mt76_connac_bss_qos_tlv *qos; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_QBSS, sizeof(*qos)); + qos = (struct mt76_connac_bss_qos_tlv *)tlv; + qos->qos = link_conf->qos; +} + +static void +mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + struct mt792x_phy *phy) +{ +#define DEFAULT_HE_PE_DURATION 4 +#define DEFAULT_HE_DURATION_RTS_THRES 1023 + const struct ieee80211_sta_he_cap *cap; + struct bss_info_uni_he *he; + struct tlv *tlv; + + cap = mt76_connac_get_he_phy_cap(phy->mt76, link_conf->vif); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); + + he = (struct bss_info_uni_he *)tlv; + he->he_pe_duration = link_conf->htc_trig_based_pkt_ext; + if (!he->he_pe_duration) + he->he_pe_duration = DEFAULT_HE_PE_DURATION; + + he->he_rts_thres = cpu_to_le16(link_conf->frame_time_rts_th); + if (!he->he_rts_thres) + he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; + he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; + he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; +} + +static void +mt7925_mcu_bss_color_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + bool enable) +{ + struct bss_info_uni_bss_color *color; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BSS_COLOR, sizeof(*color)); + color = (struct bss_info_uni_bss_color *)tlv; + + color->enable = enable ? + link_conf->he_bss_color.enabled : 0; + color->bss_color = enable ? + link_conf->he_bss_color.color : 0; +} + +static void +mt7925_mcu_bss_ifs_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_phy *phy = mvif->phy; + struct bss_ifs_time_tlv *ifs_time; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time)); + ifs_time = (struct bss_ifs_time_tlv *)tlv; + ifs_time->slot_valid = true; + ifs_time->slot_time = cpu_to_le16(phy->slottime); +} + +int mt7925_mcu_set_timing(struct mt792x_phy *phy, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_dev *dev = phy->dev; + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7925_mcu_bss_ifs_tlv(skb, link_conf); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + +int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + int enable) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_dev *dev = phy->dev; + struct mt792x_link_sta *mlink_bc; + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); + + /* bss_basic must be first */ + mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, + mlink_bc->wcid.idx, enable); + mt7925_mcu_bss_sec_tlv(skb, link_conf); + mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); + mt7925_mcu_bss_qos_tlv(skb, link_conf); + mt7925_mcu_bss_mld_tlv(skb, link_conf); + mt7925_mcu_bss_ifs_tlv(skb, link_conf); + + if (link_conf->he_support) { + mt7925_mcu_bss_he_tlv(skb, link_conf, phy); + mt7925_mcu_bss_color_tlv(skb, link_conf, enable); + } + + if (enable) + mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + +int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) +{ + struct mt76_dev *mdev = phy->dev; + + struct mbmc_conf_tlv *conf; + struct mbmc_set_req *hdr; + struct sk_buff *skb; + struct tlv *tlv; + int max_len, err; + + max_len = sizeof(*hdr) + sizeof(*conf); + skb = mt76_mcu_msg_alloc(mdev, NULL, max_len); + if (!skb) + return -ENOMEM; + + hdr = (struct mbmc_set_req *)skb_put(skb, sizeof(*hdr)); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_MBMC_SETTING, sizeof(*conf)); + conf = (struct mbmc_conf_tlv *)tlv; + + conf->mbmc_en = enable; + conf->band = 0; /* unused */ + + err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SET_DBDC_PARMS), + false); + + return err; +} + +int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct cfg80211_scan_request *sreq = &scan_req->req; + int n_ssids = 0, err, i; + struct ieee80211_channel **scan_list = sreq->channels; + struct mt76_dev *mdev = phy->dev; + struct mt76_connac_mcu_scan_channel *chan; + struct sk_buff *skb; + + struct scan_hdr_tlv *hdr; + struct scan_req_tlv *req; + struct scan_ssid_tlv *ssid; + struct scan_bssid_tlv *bssid; + struct scan_chan_info_tlv *chan_info; + struct scan_ie_tlv *ie; + struct scan_misc_tlv *misc; + struct tlv *tlv; + int max_len; + + max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) + + sizeof(*bssid) + sizeof(*chan_info) + + sizeof(*misc) + sizeof(*ie); + + skb = mt76_mcu_msg_alloc(mdev, NULL, max_len); + if (!skb) + return -ENOMEM; + + set_bit(MT76_HW_SCANNING, &phy->state); + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr)); + hdr->seq_num = mvif->scan_seq_num | mvif->band_idx << 7; + hdr->bss_idx = mvif->idx; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_REQ, sizeof(*req)); + req = (struct scan_req_tlv *)tlv; + req->scan_type = sreq->n_ssids ? 1 : 0; + req->probe_req_num = sreq->n_ssids ? 2 : 0; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid)); + ssid = (struct scan_ssid_tlv *)tlv; + for (i = 0; i < sreq->n_ssids; i++) { + if (!sreq->ssids[i].ssid_len) + continue; + + ssid->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); + memcpy(ssid->ssids[i].ssid, sreq->ssids[i].ssid, + sreq->ssids[i].ssid_len); + n_ssids++; + } + ssid->ssid_type = n_ssids ? BIT(2) : BIT(0); + ssid->ssids_num = n_ssids; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, sizeof(*bssid)); + bssid = (struct scan_bssid_tlv *)tlv; + + memcpy(bssid->bssid, sreq->bssid, ETH_ALEN); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info)); + chan_info = (struct scan_chan_info_tlv *)tlv; + chan_info->channels_num = min_t(u8, sreq->n_channels, + ARRAY_SIZE(chan_info->channels)); + for (i = 0; i < chan_info->channels_num; i++) { + chan = &chan_info->channels[i]; + + 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; + } + chan_info->channel_type = sreq->n_channels ? 4 : 0; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE, sizeof(*ie)); + ie = (struct scan_ie_tlv *)tlv; + if (sreq->ie_len > 0) { + memcpy(ie->ies, sreq->ie, sreq->ie_len); + ie->ies_len = cpu_to_le16(sreq->ie_len); + } + + req->scan_func |= SCAN_FUNC_SPLIT_SCAN; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_MISC, sizeof(*misc)); + misc = (struct scan_misc_tlv *)tlv; + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + get_random_mask_addr(misc->random_mac, sreq->mac_addr, + sreq->mac_addr_mask); + req->scan_func |= SCAN_FUNC_RANDOM_MAC; + } + + err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), + false); + if (err < 0) + clear_bit(MT76_HW_SCANNING, &phy->state); + + return err; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_hw_scan); + +int mt7925_mcu_sched_scan_req(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct ieee80211_channel **scan_list = sreq->channels; + struct mt76_connac_mcu_scan_channel *chan; + struct mt76_dev *mdev = phy->dev; + struct cfg80211_match_set *cfg_match; + struct cfg80211_ssid *cfg_ssid; + + struct scan_hdr_tlv *hdr; + struct scan_sched_req *req; + struct scan_ssid_tlv *ssid; + struct scan_chan_info_tlv *chan_info; + struct scan_ie_tlv *ie; + struct scan_sched_ssid_match_sets *match; + struct sk_buff *skb; + struct tlv *tlv; + int i, max_len; + + max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) + + sizeof(*chan_info) + sizeof(*ie) + + sizeof(*match); + + skb = mt76_mcu_msg_alloc(mdev, NULL, max_len); + if (!skb) + return -ENOMEM; + + mvif->scan_seq_num = (mvif->scan_seq_num + 1) & 0x7f; + + hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr)); + hdr->seq_num = mvif->scan_seq_num | mvif->band_idx << 7; + hdr->bss_idx = mvif->idx; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_REQ, sizeof(*req)); + req = (struct scan_sched_req *)tlv; + req->version = 1; + + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) + req->scan_func |= SCAN_FUNC_RANDOM_MAC; + + req->intervals_num = sreq->n_scan_plans; + for (i = 0; i < req->intervals_num; i++) + req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID, sizeof(*ssid)); + ssid = (struct scan_ssid_tlv *)tlv; + + ssid->ssids_num = sreq->n_ssids; + ssid->ssid_type = BIT(2); + for (i = 0; i < ssid->ssids_num; i++) { + cfg_ssid = &sreq->ssids[i]; + memcpy(ssid->ssids[i].ssid, cfg_ssid->ssid, cfg_ssid->ssid_len); + ssid->ssids[i].ssid_len = cpu_to_le32(cfg_ssid->ssid_len); + } + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SSID_MATCH_SETS, sizeof(*match)); + match = (struct scan_sched_ssid_match_sets *)tlv; + match->match_num = sreq->n_match_sets; + for (i = 0; i < match->match_num; i++) { + cfg_match = &sreq->match_sets[i]; + memcpy(match->match[i].ssid, cfg_match->ssid.ssid, + cfg_match->ssid.ssid_len); + match->match[i].rssi_th = cpu_to_le32(cfg_match->rssi_thold); + match->match[i].ssid_len = cfg_match->ssid.ssid_len; + } + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info)); + chan_info = (struct scan_chan_info_tlv *)tlv; + chan_info->channels_num = min_t(u8, sreq->n_channels, + ARRAY_SIZE(chan_info->channels)); + for (i = 0; i < chan_info->channels_num; i++) { + chan = &chan_info->channels[i]; + + 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; + } + chan_info->channel_type = sreq->n_channels ? 4 : 0; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE, sizeof(*ie)); + ie = (struct scan_ie_tlv *)tlv; + if (sreq->ie_len > 0) { + memcpy(ie->ies, sreq->ie, sreq->ie_len); + ie->ies_len = cpu_to_le16(sreq->ie_len); + } + + return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), + false); +} +EXPORT_SYMBOL_GPL(mt7925_mcu_sched_scan_req); + +int +mt7925_mcu_sched_scan_enable(struct mt76_phy *phy, + struct ieee80211_vif *vif, + bool enable) +{ + struct mt76_dev *mdev = phy->dev; + struct scan_sched_enable *req; + struct scan_hdr_tlv *hdr; + struct sk_buff *skb; + struct tlv *tlv; + int max_len; + + max_len = sizeof(*hdr) + sizeof(*req); + + skb = mt76_mcu_msg_alloc(mdev, NULL, max_len); + if (!skb) + return -ENOMEM; + + hdr = (struct scan_hdr_tlv *)skb_put(skb, sizeof(*hdr)); + hdr->seq_num = 0; + hdr->bss_idx = 0; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_SCHED_ENABLE, sizeof(*req)); + req = (struct scan_sched_enable *)tlv; + req->active = !enable; + + if (enable) + set_bit(MT76_HW_SCHED_SCANNING, &phy->state); + else + clear_bit(MT76_HW_SCHED_SCANNING, &phy->state); + + return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), + false); +} + +int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy, + struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; + struct { + struct scan_hdr { + u8 seq_num; + u8 bss_idx; + u8 pad[2]; + } __packed hdr; + struct scan_cancel_tlv { + __le16 tag; + __le16 len; + u8 is_ext_channel; + u8 rsv[3]; + } __packed cancel; + } req = { + .hdr = { + .seq_num = mvif->scan_seq_num, + .bss_idx = mvif->idx, + }, + .cancel = { + .tag = cpu_to_le16(UNI_SCAN_CANCEL), + .len = cpu_to_le16(sizeof(struct scan_cancel_tlv)), + }, + }; + + if (test_and_clear_bit(MT76_HW_SCANNING, &phy->state)) { + struct cfg80211_scan_info info = { + .aborted = true, + }; + + ieee80211_scan_completed(phy->hw, &info); + } + + return mt76_mcu_send_msg(phy->dev, MCU_UNI_CMD(SCAN_REQ), + &req, sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt7925_mcu_cancel_hw_scan); + +int mt7925_mcu_set_channel_domain(struct mt76_phy *phy) +{ + int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0; + struct { + struct { + u8 alpha2[4]; /* regulatory_request.alpha2 */ + u8 bw_2g; /* BW_20_40M 0 + * BW_20M 1 + * BW_20_40_80M 2 + * BW_20_40_80_160M 3 + * BW_20_40_80_8080M 4 + */ + u8 bw_5g; + u8 bw_6g; + u8 pad; + } __packed hdr; + struct n_chan { + __le16 tag; + __le16 len; + u8 n_2ch; + u8 n_5ch; + u8 n_6ch; + u8 pad; + } __packed n_ch; + } req = { + .hdr = { + .bw_2g = 0, + .bw_5g = 3, /* BW_20_40_80_160M */ + .bw_6g = 3, + }, + .n_ch = { + .tag = cpu_to_le16(2), + }, + }; + struct mt76_connac_mcu_chan { + __le16 hw_value; + __le16 pad; + __le32 flags; + } __packed channel; + 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_6g.sband.n_channels; + len = sizeof(req) + n_max_channels * sizeof(channel); + + skb = mt76_mcu_msg_alloc(dev, NULL, len); + if (!skb) + return -ENOMEM; + + skb_reserve(skb, sizeof(req)); + + for (i = 0; i < phy->sband_2g.sband.n_channels; i++) { + chan = &phy->sband_2g.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_2ch++; + } + for (i = 0; i < phy->sband_5g.sband.n_channels; i++) { + chan = &phy->sband_5g.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_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(req.hdr.alpha2)); + memcpy(req.hdr.alpha2, dev->alpha2, sizeof(dev->alpha2)); + req.n_ch.n_2ch = n_2ch; + req.n_ch.n_5ch = n_5ch; + req.n_ch.n_6ch = n_6ch; + len = sizeof(struct n_chan) + (n_2ch + n_5ch + n_6ch) * sizeof(channel); + req.n_ch.len = cpu_to_le16(len); + memcpy(__skb_push(skb, sizeof(req)), &req, sizeof(req)); + + return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SET_DOMAIN_INFO), + false); +} +EXPORT_SYMBOL_GPL(mt7925_mcu_set_channel_domain); + +static int +__mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap, + struct mt7925_clc *clc, u8 idx) +{ + struct mt7925_clc_segment *seg; + struct sk_buff *skb; + struct { + u8 rsv[4]; + __le16 tag; + __le16 len; + + u8 ver; + u8 pad0; + __le16 size; + u8 idx; + u8 env; + u8 acpi_conf; + u8 pad1; + u8 alpha2[2]; + u8 type[2]; + u8 rsvd[64]; + } __packed req = { + .tag = cpu_to_le16(0x3), + .len = cpu_to_le16(sizeof(req) - 4), + + .idx = idx, + .env = env_cap, + .acpi_conf = mt792x_acpi_get_flags(&dev->phy), + }; + int ret, valid_cnt = 0; + u8 i, *pos; + + if (!clc) + return 0; + + pos = clc->data + sizeof(*seg) * clc->nr_seg; + for (i = 0; i < clc->nr_country; i++) { + struct mt7925_clc_rule *rule = (struct mt7925_clc_rule *)pos; + + pos += sizeof(*rule); + if (rule->alpha2[0] != alpha2[0] || + rule->alpha2[1] != alpha2[1]) + continue; + + seg = (struct mt7925_clc_segment *)clc->data + + rule->seg_idx - 1; + + memcpy(req.alpha2, rule->alpha2, 2); + memcpy(req.type, rule->type, 2); + + req.size = cpu_to_le16(seg->len); + skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, + le16_to_cpu(req.size) + sizeof(req), + sizeof(req), GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_put_data(skb, clc->data + seg->offset, seg->len); + + ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD(SET_POWER_LIMIT), + true); + if (ret < 0) + return ret; + valid_cnt++; + } + + if (!valid_cnt) + return -ENOENT; + + return 0; +} + +int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap) +{ + struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy; + int i, ret; + + /* submit all clc config */ + for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { + ret = __mt7925_mcu_set_clc(dev, alpha2, env_cap, + phy->clc[i], i); + + /* If no country found, set "00" as default */ + if (ret == -ENOENT) + ret = __mt7925_mcu_set_clc(dev, "00", + ENVIRON_INDOOR, + phy->clc[i], i); + if (ret < 0) + return ret; + } + return 0; +} + +int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq) +{ + int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); + struct mt76_connac2_mcu_uni_txd *uni_txd; + struct mt76_connac2_mcu_txd *mcu_txd; + __le32 *txd; + u32 val; + u8 seq; + + /* TODO: make dynamic based on msg type */ + mdev->mcu.timeout = 20 * HZ; + + seq = ++mdev->mcu.msg_seq & 0xf; + if (!seq) + seq = ++mdev->mcu.msg_seq & 0xf; + + if (cmd == MCU_CMD(FW_SCATTER)) + goto exit; + + txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); + txd = (__le32 *)skb_push(skb, txd_len); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | + FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); + txd[0] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); + txd[1] = cpu_to_le32(val); + + if (cmd & __MCU_CMD_FIELD_UNI) { + uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; + uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); + uni_txd->cid = cpu_to_le16(mcu_cmd); + uni_txd->s2d_index = MCU_S2D_H2N; + uni_txd->pkt_type = MCU_PKT_ID; + uni_txd->seq = seq; + + if (cmd & __MCU_CMD_FIELD_QUERY) + uni_txd->option = MCU_CMD_UNI_QUERY_ACK; + else + uni_txd->option = MCU_CMD_UNI_EXT_ACK; + + goto exit; + } + + mcu_txd = (struct mt76_connac2_mcu_txd *)txd; + mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); + mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, + MT_TX_MCU_PORT_RX_Q0)); + mcu_txd->pkt_type = MCU_PKT_ID; + mcu_txd->seq = seq; + mcu_txd->cid = mcu_cmd; + mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); + + if (mcu_txd->ext_cid || (cmd & __MCU_CMD_FIELD_CE)) { + if (cmd & __MCU_CMD_FIELD_QUERY) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->ext_cid_ack = !!mcu_txd->ext_cid; + } else { + mcu_txd->set_query = MCU_Q_NA; + } + + if (cmd & __MCU_CMD_FIELD_WA) + mcu_txd->s2d_index = MCU_S2D_H2C; + else + mcu_txd->s2d_index = MCU_S2D_H2N; + +exit: + if (wait_seq) + *wait_seq = seq; + + return 0; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_fill_message); + +int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val) +{ + struct { + u8 band_idx; + u8 _rsv[3]; + + __le16 tag; + __le16 len; + __le32 len_thresh; + __le32 pkt_thresh; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = cpu_to_le16(UNI_BAND_CONFIG_RTS_THRESHOLD), + .len = cpu_to_le16(sizeof(req) - 4), + .len_thresh = cpu_to_le32(val), + .pkt_thresh = cpu_to_le32(0x2), + }; + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); +} + +int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable) +{ + struct { + u8 band_idx; + u8 _rsv[3]; + + __le16 tag; + __le16 len; + u8 enable; + u8 _rsv2[3]; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = cpu_to_le16(UNI_BAND_CONFIG_RADIO_ENABLE), + .len = cpu_to_le16(sizeof(req) - 4), + .enable = enable, + }; + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); +} + +static void +mt7925_mcu_build_sku(struct mt76_dev *dev, s8 *sku, + struct mt76_power_limits *limits, + enum nl80211_band band) +{ + int i, offset = sizeof(limits->cck); + + memset(sku, 127, MT_CONNAC3_SKU_POWER_LIMIT); + + if (band == NL80211_BAND_2GHZ) { + /* cck */ + memcpy(sku, limits->cck, sizeof(limits->cck)); + } + + /* ofdm */ + memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm)); + offset += (sizeof(limits->ofdm) * 5); + + /* ht */ + for (i = 0; i < 2; i++) { + memcpy(&sku[offset], limits->mcs[i], 8); + offset += 8; + } + sku[offset++] = limits->mcs[0][0]; + + /* vht */ + for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) { + memcpy(&sku[offset], limits->mcs[i], + ARRAY_SIZE(limits->mcs[i])); + offset += 12; + } + + /* he */ + for (i = 0; i < ARRAY_SIZE(limits->ru); i++) { + memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i])); + offset += ARRAY_SIZE(limits->ru[i]); + } + + /* eht */ + for (i = 0; i < ARRAY_SIZE(limits->eht); i++) { + memcpy(&sku[offset], limits->eht[i], ARRAY_SIZE(limits->eht[i])); + offset += ARRAY_SIZE(limits->eht[i]); + } +} + +static int +mt7925_mcu_rate_txpower_band(struct mt76_phy *phy, + enum nl80211_band band) +{ + int tx_power, n_chan, last_ch, err = 0, idx = 0; + int i, sku_len, batch_size, batch_len = 3; + struct mt76_dev *dev = phy->dev; + static const u8 chan_list_2ghz[] = { + 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14 + }; + static const u8 chan_list_5ghz[] = { + 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, + 64, 100, 102, 104, 106, 108, 110, + 112, 114, 116, 118, 120, 122, 124, + 126, 128, 132, 134, 136, 138, 140, + 142, 144, 149, 151, 153, 155, 157, + 159, 161, 165, 167 + }; + 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 + }; + struct mt76_power_limits *limits; + struct mt7925_sku_tlv *sku_tlbv; + const u8 *ch_list; + + sku_len = sizeof(*sku_tlbv); + 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); + ch_list = chan_list_2ghz; + last_ch = chan_list_2ghz[ARRAY_SIZE(chan_list_2ghz) - 1]; + } else if (band == NL80211_BAND_6GHZ) { + n_chan = ARRAY_SIZE(chan_list_6ghz); + ch_list = chan_list_6ghz; + last_ch = chan_list_6ghz[ARRAY_SIZE(chan_list_6ghz) - 1]; + } else { + n_chan = ARRAY_SIZE(chan_list_5ghz); + ch_list = chan_list_5ghz; + last_ch = chan_list_5ghz[ARRAY_SIZE(chan_list_5ghz) - 1]; + } + batch_size = DIV_ROUND_UP(n_chan, batch_len); + + limits = devm_kmalloc(dev->dev, sizeof(*limits), GFP_KERNEL); + if (!limits) + return -ENOMEM; + + sku_tlbv = devm_kmalloc(dev->dev, sku_len, GFP_KERNEL); + if (!sku_tlbv) { + devm_kfree(dev->dev, limits); + return -ENOMEM; + } + + for (i = 0; i < batch_size; i++) { + struct mt7925_tx_power_limit_tlv *tx_power_tlv; + int j, msg_len, num_ch; + struct sk_buff *skb; + + num_ch = i == batch_size - 1 ? n_chan % batch_len : batch_len; + msg_len = sizeof(*tx_power_tlv) + num_ch * sku_len; + skb = mt76_mcu_msg_alloc(dev, NULL, msg_len); + if (!skb) { + err = -ENOMEM; + goto out; + } + + tx_power_tlv = (struct mt7925_tx_power_limit_tlv *) + skb_put(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; + tx_power_tlv->tag = cpu_to_le16(0x1); + tx_power_tlv->len = cpu_to_le16(sizeof(*tx_power_tlv)); + + 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_get_sar_power(phy, &chan, reg_power); + + mt76_get_rate_power_limits(phy, &chan, limits, + sar_power); + + tx_power_tlv->last_msg = ch_list[idx] == last_ch; + sku_tlbv->channel = ch_list[idx]; + + mt7925_mcu_build_sku(dev, sku_tlbv->pwr_limit, + limits, band); + skb_put_data(skb, sku_tlbv, sku_len); + } + err = mt76_mcu_skb_send_msg(dev, skb, + MCU_UNI_CMD(SET_POWER_LIMIT), + true); + if (err < 0) + goto out; + } + +out: + devm_kfree(dev->dev, sku_tlbv); + devm_kfree(dev->dev, limits); + return err; +} + +int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy) +{ + int err; + + if (phy->cap.has_2ghz) { + err = mt7925_mcu_rate_txpower_band(phy, + NL80211_BAND_2GHZ); + if (err < 0) + return err; + } + + if (phy->cap.has_5ghz) { + err = mt7925_mcu_rate_txpower_band(phy, + NL80211_BAND_5GHZ); + if (err < 0) + return err; + } + + if (phy->cap.has_6ghz) { + err = mt7925_mcu_rate_txpower_band(phy, + NL80211_BAND_6GHZ); + if (err < 0) + return err; + } + + return 0; +} + +int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, + u8 bit_op, u32 bit_map) +{ + struct mt792x_phy *phy = &dev->phy; + struct { + u8 band_idx; + u8 rsv1[3]; + + __le16 tag; + __le16 len; + u8 mode; + u8 rsv2[3]; + __le32 fif; + __le32 bit_map; /* bit_* for bitmap update */ + u8 bit_op; + u8 pad[51]; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = cpu_to_le16(UNI_BAND_CONFIG_SET_MAC80211_RX_FILTER), + .len = cpu_to_le16(sizeof(req) - 4), + + .mode = fif ? 0 : 1, + .fif = cpu_to_le32(fif), + .bit_map = cpu_to_le32(bit_map), + .bit_op = bit_op, + }; + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/mcu.h b/sys/contrib/dev/mediatek/mt76/mt7925/mcu.h new file mode 100644 index 000000000000..1e47d2c61b54 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/mcu.h @@ -0,0 +1,649 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2023 MediaTek Inc. */ + +#ifndef __MT7925_MCU_H +#define __MT7925_MCU_H + +#include "../mt76_connac_mcu.h" + +/* ext event table */ +enum { + MCU_EXT_EVENT_RATE_REPORT = 0x87, +}; + +struct mt7925_mcu_eeprom_info { + __le32 addr; + __le32 valid; + u8 data[MT7925_EEPROM_BLOCK_SIZE]; +} __packed; + +#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 mt7925_mcu_rxd { + __le32 rxd[8]; + + __le16 len; + __le16 pkt_type_id; + + u8 eid; + u8 seq; + u8 option; + u8 __rsv; + + u8 ext_eid; + u8 __rsv1[2]; + u8 s2d_index; + + u8 tlv[]; +}; + +struct mt7925_mcu_uni_event { + u8 cid; + u8 pad[3]; + __le32 status; /* 0: success, others: fail */ +} __packed; + +enum { + MT_EBF = BIT(0), /* explicit beamforming */ + MT_IBF = BIT(1) /* implicit beamforming */ +}; + +struct mt7925_mcu_reg_event { + __le32 reg; + __le32 val; +} __packed; + +struct mt7925_mcu_ant_id_config { + u8 ant_id[4]; +} __packed; + +struct mt7925_txpwr_req { + u8 _rsv[4]; + __le16 tag; + __le16 len; + + u8 format_id; + u8 catg; + u8 band_idx; + u8 _rsv1; +} __packed; + +struct mt7925_txpwr_event { + u8 rsv[4]; + __le16 tag; + __le16 len; + + u8 catg; + u8 band_idx; + u8 ch_band; + u8 format; /* 0:Legacy, 1:HE */ + + /* Rate power info */ + struct mt7925_txpwr txpwr; + + s8 pwr_max; + s8 pwr_min; + u8 rsv1; +} __packed; + +enum { + TM_SWITCH_MODE, + TM_SET_AT_CMD, + TM_QUERY_AT_CMD, +}; + +enum { + MT7925_TM_NORMAL, + MT7925_TM_TESTMODE, + MT7925_TM_ICAP, + MT7925_TM_ICAP_OVERLAP, + MT7925_TM_WIFISPECTRUM, +}; + +struct mt7925_rftest_cmd { + u8 action; + u8 rsv[3]; + __le32 param0; + __le32 param1; +} __packed; + +struct mt7925_rftest_evt { + __le32 param0; + __le32 param1; +} __packed; + +enum { + UNI_CHANNEL_SWITCH, + UNI_CHANNEL_RX_PATH, +}; + +enum { + UNI_CHIP_CONFIG_CHIP_CFG = 0x2, + UNI_CHIP_CONFIG_NIC_CAPA = 0x3, +}; + +enum { + UNI_BAND_CONFIG_RADIO_ENABLE, + UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, + UNI_BAND_CONFIG_SET_MAC80211_RX_FILTER = 0x0C, +}; + +enum { + UNI_WSYS_CONFIG_FW_LOG_CTRL, + UNI_WSYS_CONFIG_FW_DBG_CTRL, +}; + +enum { + UNI_EFUSE_ACCESS = 1, + UNI_EFUSE_BUFFER_MODE, + UNI_EFUSE_FREE_BLOCK, + UNI_EFUSE_BUFFER_RD, +}; + +enum { + UNI_CMD_ACCESS_REG_BASIC = 0x0, + UNI_CMD_ACCESS_RF_REG_BASIC, +}; + +enum { + UNI_MBMC_SETTING, +}; + +enum { + UNI_EVENT_SCAN_DONE_BASIC = 0, + UNI_EVENT_SCAN_DONE_CHNLINFO = 2, + UNI_EVENT_SCAN_DONE_NLO = 3, +}; + +enum connac3_mcu_cipher_type { + CONNAC3_CIPHER_NONE = 0, + CONNAC3_CIPHER_WEP40 = 1, + CONNAC3_CIPHER_TKIP = 2, + CONNAC3_CIPHER_AES_CCMP = 4, + CONNAC3_CIPHER_WEP104 = 5, + CONNAC3_CIPHER_BIP_CMAC_128 = 6, + CONNAC3_CIPHER_WEP128 = 7, + CONNAC3_CIPHER_WAPI = 8, + CONNAC3_CIPHER_CCMP_256 = 10, + CONNAC3_CIPHER_GCMP = 11, + CONNAC3_CIPHER_GCMP_256 = 12, +}; + +struct mt7925_mcu_scan_chinfo_event { + u8 nr_chan; + u8 alpha2[3]; +} __packed; + +enum { + UNI_SCAN_REQ = 1, + UNI_SCAN_CANCEL = 2, + UNI_SCAN_SCHED_REQ = 3, + UNI_SCAN_SCHED_ENABLE = 4, + UNI_SCAN_SSID = 10, + UNI_SCAN_BSSID, + UNI_SCAN_CHANNEL, + UNI_SCAN_IE, + UNI_SCAN_MISC, + UNI_SCAN_SSID_MATCH_SETS, +}; + +enum { + UNI_SNIFFER_ENABLE, + UNI_SNIFFER_CONFIG, +}; + +struct scan_hdr_tlv { + /* fixed field */ + u8 seq_num; + u8 bss_idx; + u8 pad[2]; + /* tlv */ + u8 data[]; +} __packed; + +struct scan_req_tlv { + __le16 tag; + __le16 len; + + u8 scan_type; /* 0: PASSIVE SCAN + * 1: ACTIVE SCAN + */ + u8 probe_req_num; /* Number of probe request for each SSID */ + u8 scan_func; /* BIT(0) Enable random MAC scan + * BIT(1) Disable DBDC scan type 1~3. + * BIT(2) Use DBDC scan type 3 (dedicated one RF to scan). + */ + u8 src_mask; + __le16 channel_min_dwell_time; + __le16 channel_dwell_time; /* channel Dwell interval */ + __le16 timeout_value; + __le16 probe_delay_time; + __le32 func_mask_ext; +}; + +struct scan_ssid_tlv { + __le16 tag; + __le16 len; + + u8 ssid_type; /* BIT(0) wildcard SSID + * BIT(1) P2P wildcard SSID + * BIT(2) specified SSID + wildcard SSID + * BIT(2) + ssid_type_ext BIT(0) specified SSID only + */ + u8 ssids_num; + u8 pad[2]; + struct mt76_connac_mcu_scan_ssid ssids[4]; +}; + +struct scan_bssid_tlv { + __le16 tag; + __le16 len; + + u8 bssid[ETH_ALEN]; + u8 match_ch; + u8 match_ssid_ind; + u8 rcpi; + u8 pad[3]; +}; + +struct scan_chan_info_tlv { + __le16 tag; + __le16 len; + + u8 channel_type; /* 0: Full channels + * 1: Only 2.4GHz channels + * 2: Only 5GHz channels + * 3: P2P social channel only (channel #1, #6 and #11) + * 4: Specified channels + * Others: Reserved + */ + u8 channels_num; /* valid when channel_type is 4 */ + u8 pad[2]; + struct mt76_connac_mcu_scan_channel channels[64]; +}; + +struct scan_ie_tlv { + __le16 tag; + __le16 len; + + __le16 ies_len; + u8 band; + u8 pad; + u8 ies[MT76_CONNAC_SCAN_IE_LEN]; +}; + +struct scan_misc_tlv { + __le16 tag; + __le16 len; + + u8 random_mac[ETH_ALEN]; + u8 rsv[2]; +}; + +struct scan_sched_req { + __le16 tag; + __le16 len; + + u8 version; + u8 stop_on_match; + u8 intervals_num; + u8 scan_func; + __le16 intervals[MT76_CONNAC_MAX_NUM_SCHED_SCAN_INTERVAL]; +}; + +struct scan_sched_ssid_match_sets { + __le16 tag; + __le16 len; + + u8 match_num; + u8 rsv[3]; + + struct mt76_connac_mcu_scan_match match[MT76_CONNAC_MAX_SCAN_MATCH]; +}; + +struct scan_sched_enable { + __le16 tag; + __le16 len; + + u8 active; + u8 rsv[3]; +}; + +struct mbmc_set_req { + u8 pad[4]; + u8 data[]; +} __packed; + +struct mbmc_conf_tlv { + __le16 tag; + __le16 len; + + u8 mbmc_en; + u8 band; + u8 pad[2]; +} __packed; + +struct edca { + __le16 tag; + __le16 len; + + u8 queue; + u8 set; + u8 cw_min; + u8 cw_max; + __le16 txop; + u8 aifs; + u8 __rsv; +}; + +struct bss_req_hdr { + u8 bss_idx; + u8 __rsv[3]; +} __packed; + +struct bss_rate_tlv { + __le16 tag; + __le16 len; + u8 __rsv1[2]; + __le16 basic_rate; + __le16 bc_trans; + __le16 mc_trans; + u8 short_preamble; + u8 bc_fixed_rate; + u8 mc_fixed_rate; + u8 __rsv2; +} __packed; + +struct bss_mld_tlv { + __le16 tag; + __le16 len; + u8 group_mld_id; + u8 own_mld_id; + u8 mac_addr[ETH_ALEN]; + u8 remap_idx; + u8 link_id; + u8 eml_enable; + u8 max_link_num; + u8 hybrid_mode; + u8 __rsv[3]; +} __packed; + +struct sta_rec_ba_uni { + __le16 tag; + __le16 len; + u8 tid; + u8 ba_type; + u8 amsdu; + u8 ba_en; + __le16 ssn; + __le16 winsize; + u8 ba_rdd_rro; + u8 __rsv[3]; +} __packed; + +struct sta_rec_eht { + __le16 tag; + __le16 len; + u8 tid_bitmap; + u8 _rsv; + __le16 mac_cap; + __le64 phy_cap; + __le64 phy_cap_ext; + u8 mcs_map_bw20[4]; + u8 mcs_map_bw80[3]; + u8 mcs_map_bw160[3]; + u8 mcs_map_bw320[3]; + u8 _rsv2[3]; +} __packed; + +struct sta_rec_sec_uni { + __le16 tag; + __le16 len; + u8 add; + u8 tx_key; + u8 key_type; + u8 is_authenticator; + u8 peer_addr[6]; + u8 bss_idx; + u8 cipher_id; + u8 key_id; + u8 key_len; + u8 wlan_idx; + u8 mgmt_prot; + u8 key[32]; + u8 key_rsc[16]; +} __packed; + +struct sta_rec_hdr_trans { + __le16 tag; + __le16 len; + u8 from_ds; + u8 to_ds; + u8 dis_rx_hdr_tran; + u8 rsv; +} __packed; + +struct sta_rec_mld { + __le16 tag; + __le16 len; + u8 mac_addr[ETH_ALEN]; + __le16 primary_id; + __le16 secondary_id; + __le16 wlan_id; + u8 link_num; + u8 rsv[3]; + struct { + __le16 wlan_id; + u8 bss_idx; + u8 rsv; + } __packed link[2]; +} __packed; + +struct sta_rec_eht_mld { + __le16 tag; + __le16 len; + u8 nsep; + u8 mld_type; + u8 __rsv1[1]; + u8 str_cap[3]; + u8 eml_cap[3]; + u8 __rsv2[3]; +} __packed; + +struct bss_ifs_time_tlv { + __le16 tag; + __le16 len; + u8 slot_valid; + u8 sifs_valid; + u8 rifs_valid; + u8 eifs_valid; + __le16 slot_time; + __le16 sifs_time; + __le16 rifs_time; + __le16 eifs_time; + u8 eifs_cck_valid; + u8 rsv; + __le16 eifs_cck_time; +} __packed; + +struct bss_rlm_tlv { + __le16 tag; + __le16 len; + u8 control_channel; + u8 center_chan; + u8 center_chan2; + u8 bw; + u8 tx_streams; + u8 rx_streams; + u8 ht_op_info; + u8 sco; + u8 band; + u8 pad[3]; +} __packed; + +#define MT7925_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_v2) + \ + sizeof(struct sta_rec_ba_uni) + \ + sizeof(struct sta_rec_vht) + \ + sizeof(struct sta_rec_uapsd) + \ + sizeof(struct sta_rec_amsdu) + \ + sizeof(struct sta_rec_bfee) + \ + sizeof(struct sta_rec_phy) + \ + sizeof(struct sta_rec_ra) + \ + sizeof(struct sta_rec_sec_uni) + \ + sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_he_6g_capa) + \ + sizeof(struct sta_rec_eht) + \ + sizeof(struct sta_rec_hdr_trans) + \ + sizeof(struct sta_rec_mld) + \ + sizeof(struct tlv) * 2 + \ + sizeof(struct sta_rec_remove)) + +#define MT7925_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ + sizeof(struct mt76_connac_bss_basic_tlv) + \ + sizeof(struct mt76_connac_bss_qos_tlv) + \ + sizeof(struct bss_rate_tlv) + \ + sizeof(struct bss_mld_tlv) + \ + sizeof(struct bss_info_uni_he) + \ + sizeof(struct bss_info_uni_bss_color) + \ + sizeof(struct bss_ifs_time_tlv) + \ + sizeof(struct bss_rlm_tlv) + \ + sizeof(struct tlv)) + +#define MT_CONNAC3_SKU_POWER_LIMIT 449 +struct mt7925_sku_tlv { + u8 channel; + s8 pwr_limit[MT_CONNAC3_SKU_POWER_LIMIT]; +} __packed; + +struct mt7925_tx_power_limit_tlv { + u8 rsv[4]; + + __le16 tag; + __le16 len; + + /* DW0 - common info*/ + u8 ver; + u8 pad0; + __le16 rsv1; + /* DW1 - cmd hint */ + u8 n_chan; /* # channel */ + u8 band; /* 2.4GHz - 5GHz - 6GHz */ + u8 last_msg; + u8 limit_type; + /* DW3 */ + u8 alpha2[4]; /* regulatory_request.alpha2 */ + u8 pad2[32]; + + u8 data[]; +} __packed; + +struct mt7925_arpns_tlv { + __le16 tag; + __le16 len; + + u8 enable; + u8 ips_num; + u8 rsv[2]; +} __packed; + +struct mt7925_wow_pattern_tlv { + __le16 tag; + __le16 len; + u8 bss_idx; + u8 index; /* pattern index */ + u8 enable; /* 0: disable + * 1: enable + */ + u8 data_len; /* pattern length */ + u8 offset; + u8 mask[MT76_CONNAC_WOW_MASK_MAX_LEN]; + u8 pattern[MT76_CONNAC_WOW_PATTEN_MAX_LEN]; + u8 rsv[7]; +} __packed; + +struct roc_acquire_tlv { + __le16 tag; + __le16 len; + u8 bss_idx; + u8 tokenid; + u8 control_channel; + u8 sco; + u8 band; + u8 bw; + u8 center_chan; + u8 center_chan2; + u8 bw_from_ap; + u8 center_chan_from_ap; + u8 center_chan2_from_ap; + u8 reqtype; + __le32 maxinterval; + u8 dbdcband; + u8 rsv[3]; +} __packed; + +static inline enum connac3_mcu_cipher_type +mt7925_mcu_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return CONNAC3_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return CONNAC3_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return CONNAC3_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return CONNAC3_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return CONNAC3_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return CONNAC3_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return CONNAC3_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return CONNAC3_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return CONNAC3_CIPHER_WAPI; + default: + return CONNAC3_CIPHER_NONE; + } +} + +int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable); +int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_scan_request *scan_req); +int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy, + struct ieee80211_vif *vif); +int mt7925_mcu_sched_scan_req(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct cfg80211_sched_scan_request *sreq); +int mt7925_mcu_sched_scan_enable(struct mt76_phy *phy, + struct ieee80211_vif *vif, + bool enable); +int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + int enable); +int mt7925_mcu_set_timing(struct mt792x_phy *phy, + struct ieee80211_bss_conf *link_conf); +int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); +int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); +int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); +int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx); +int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy); +int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, + struct ieee80211_bss_conf *link_conf); +int +mt7925_mcu_uni_bss_bcnft(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, bool enable); +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/mt7925.h b/sys/contrib/dev/mediatek/mt76/mt7925/mt7925.h new file mode 100644 index 000000000000..8707b5d04743 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/mt7925.h @@ -0,0 +1,347 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2023 MediaTek Inc. */ + +#ifndef __MT7925_H +#define __MT7925_H + +#include "../mt792x.h" +#include "regs.h" + +#define MT7925_BEACON_RATES_TBL 25 + +#define MT7925_TX_RING_SIZE 2048 +#define MT7925_TX_MCU_RING_SIZE 256 +#define MT7925_TX_FWDL_RING_SIZE 128 + +#define MT7925_RX_RING_SIZE 1536 +#define MT7925_RX_MCU_RING_SIZE 512 + +#define MT7925_EEPROM_SIZE 3584 +#define MT7925_TOKEN_SIZE 8192 + +#define MT7925_EEPROM_BLOCK_SIZE 16 + +#define MT7925_SKU_RATE_NUM 161 +#define MT7925_SKU_MAX_DELTA_IDX MT7925_SKU_RATE_NUM +#define MT7925_SKU_TABLE_SIZE (MT7925_SKU_RATE_NUM + 1) + +#define MCU_UNI_EVENT_ROC 0x27 + +#define HIF_TRAFFIC_IDLE 0x2 + +enum { + UNI_EVENT_HIF_CTRL_BASIC = 0, + UNI_EVENT_HIF_CTRL_TAG_NUM +}; + +struct mt7925_mcu_hif_ctrl_basic_tlv { + __le16 tag; + __le16 len; + u8 cid; + u8 pad[3]; + u32 status; + u8 hif_type; + u8 hif_tx_traffic_status; + u8 hif_rx_traffic_status; + u8 hifsuspend; + u8 rsv[4]; +} __packed; + +enum { + UNI_ROC_ACQUIRE, + UNI_ROC_ABORT, + UNI_ROC_SUB_LINK = 3, + UNI_ROC_NUM +}; + +enum mt7925_roc_req { + MT7925_ROC_REQ_JOIN, + MT7925_ROC_REQ_ROC, + MT7925_ROC_REQ_SUB_LINK, + MT7925_ROC_REQ_MLSR_AG = 10, + MT7925_ROC_REQ_MLSR_AA, + MT7925_ROC_REQ_NUM +}; + +enum { + UNI_EVENT_ROC_GRANT = 0, + UNI_EVENT_ROC_GRANT_SUB_LINK = 4, + UNI_EVENT_ROC_TAG_NUM +}; + +struct mt7925_roc_grant_tlv { + __le16 tag; + __le16 len; + u8 bss_idx; + u8 tokenid; + u8 status; + u8 primarychannel; + u8 rfsco; + u8 rfband; + u8 channelwidth; + u8 centerfreqseg1; + u8 centerfreqseg2; + u8 reqtype; + u8 dbdcband; + u8 rsv[1]; + __le32 max_interval; +} __packed; + +struct mt7925_beacon_loss_tlv { + __le16 tag; + __le16 len; + u8 reason; + u8 nr_btolink; + u8 pad[2]; +} __packed; + +struct mt7925_uni_beacon_loss_event { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7925_beacon_loss_tlv beacon_loss; +} __packed; + +#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) +#define to_rcpi(rssi) (2 * (rssi) + 220) + +enum mt7925_txq_id { + MT7925_TXQ_BAND0, + MT7925_TXQ_BAND1, + MT7925_TXQ_MCU_WM = 15, + MT7925_TXQ_FWDL, +}; + +enum mt7925_rxq_id { + MT7925_RXQ_BAND0 = 2, + MT7925_RXQ_BAND1, + MT7925_RXQ_MCU_WM = 0, + MT7925_RXQ_MCU_WM2, /* for tx done */ +}; + +enum { + MODE_OPEN = 0, + MODE_SHARED = 1, + MODE_WPA = 3, + MODE_WPA_PSK = 4, + MODE_WPA_NONE = 5, + MODE_WPA2 = 6, + MODE_WPA2_PSK = 7, + MODE_WPA3_SAE = 11, +}; + +enum { + MT7925_CLC_POWER, + MT7925_CLC_CHAN, + MT7925_CLC_MAX_NUM, +}; + +struct mt7925_clc_rule { + u8 alpha2[2]; + u8 type[2]; + u8 seg_idx; + u8 rsv[3]; +} __packed; + +struct mt7925_clc_segment { + u8 idx; + u8 rsv1[3]; + u32 offset; + u32 len; + u8 rsv2[4]; +} __packed; + +struct mt7925_clc { + __le32 len; + u8 idx; + u8 ver; + u8 nr_country; + u8 type; + u8 nr_seg; + u8 rsv[7]; + u8 data[]; +} __packed; + +enum mt7925_eeprom_field { + MT_EE_CHIP_ID = 0x000, + MT_EE_VERSION = 0x002, + MT_EE_MAC_ADDR = 0x004, + __MT_EE_MAX = 0x9ff +}; + +enum { + TXPWR_USER, + TXPWR_EEPROM, + TXPWR_MAC, + TXPWR_MAX_NUM, +}; + +struct mt7925_txpwr { + s8 cck[4][2]; + s8 ofdm[8][2]; + s8 ht20[8][2]; + s8 ht40[9][2]; + s8 vht20[12][2]; + s8 vht40[12][2]; + s8 vht80[12][2]; + s8 vht160[12][2]; + s8 he26[12][2]; + s8 he52[12][2]; + s8 he106[12][2]; + s8 he242[12][2]; + s8 he484[12][2]; + s8 he996[12][2]; + s8 he996x2[12][2]; + s8 eht26[16][2]; + s8 eht52[16][2]; + s8 eht106[16][2]; + s8 eht242[16][2]; + s8 eht484[16][2]; + s8 eht996[16][2]; + s8 eht996x2[16][2]; + s8 eht996x4[16][2]; + s8 eht26_52[16][2]; + s8 eht26_106[16][2]; + s8 eht484_242[16][2]; + s8 eht996_484[16][2]; + s8 eht996_484_242[16][2]; + s8 eht996x2_484[16][2]; + s8 eht996x3[16][2]; + s8 eht996x3_484[16][2]; +}; + +extern const struct ieee80211_ops mt7925_ops; + +int __mt7925_start(struct mt792x_phy *phy); +int mt7925_register_device(struct mt792x_dev *dev); +void mt7925_unregister_device(struct mt792x_dev *dev); +int mt7925_run_firmware(struct mt792x_dev *dev); +int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf, + bool enable); +int mt7925_mcu_sta_update(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta, + struct ieee80211_vif *vif, bool enable, + enum mt76_sta_info_state state); +int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); +int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf); +int mt7925_mcu_set_eeprom(struct mt792x_dev *dev); +int mt7925_mcu_get_rx_rate(struct mt792x_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct rate_info *rate); +int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl); +void mt7925_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb); +int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd); +int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, + u8 bit_op, u32 bit_map); + +void mt7925_regd_update(struct mt792x_dev *dev); +int mt7925_mac_init(struct mt792x_dev *dev); +int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask); +int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); +void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void mt7925_mac_reset_work(struct work_struct *work); +int mt7925e_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 mt7925_tx_token_put(struct mt792x_dev *dev); +bool mt7925_rx_check(struct mt76_dev *mdev, void *data, int len); +void mt7925_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info); +void mt7925_stats_work(struct work_struct *work); +void mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy); +int mt7925_init_mlo_caps(struct mt792x_phy *phy); +int mt7925_init_debugfs(struct mt792x_dev *dev); + +int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + bool enable); +int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params, + bool enable); +int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params, + bool enable); +void mt7925_scan_work(struct work_struct *work); +void mt7925_roc_work(struct work_struct *work); +int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, + struct ieee80211_bss_conf *link_conf); +void mt7925_coredump_work(struct work_struct *work); +int mt7925_get_txpwr_info(struct mt792x_dev *dev, u8 band_idx, + struct mt7925_txpwr *txpwr); +void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev, + u8 tbl_idx, u16 rate_idx); +void mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, int pid, + enum mt76_txq_id qid, u32 changed); +void mt7925_txwi_free(struct mt792x_dev *dev, struct mt76_txwi_cache *t, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, + struct list_head *free_list); +int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, + struct sk_buff *skb, int seq); + +int mt7925e_mac_reset(struct mt792x_dev *dev); +int mt7925e_mcu_init(struct mt792x_dev *dev); +void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data); +void mt7925_set_runtime_pm(struct mt792x_dev *dev); +void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif); +void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif); +void mt7925_set_ipv6_ns_work(struct work_struct *work); + +int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, + bool enable); +int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, + struct ieee80211_chanctx_conf *ctx); +int mt7925_mcu_get_temperature(struct mt792x_phy *phy); + +int mt7925_usb_sdio_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 mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, + struct mt76_queue_entry *e); +bool mt7925_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update); + +int mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, + struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + bool enable); +int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, + const struct cfg80211_sar_specs *sar); + +int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); +int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env_cap); +int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, + int duration, u8 token_id); +int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + struct ieee80211_channel *chan, int duration, + enum mt7925_roc_req type, u8 token_id); +int mt7925_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + u8 token_id); +void mt7925_roc_abort_sync(struct mt792x_dev *dev); +int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *wait_seq); +int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, + struct mt76_connac_sta_key_conf *sta_key_conf, + struct ieee80211_key_conf *key, int mcu_cmd, + struct mt76_wcid *wcid, enum set_key_cmd cmd, + struct mt792x_sta *msta); +int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); +int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + int link_id); + +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/pci.c b/sys/contrib/dev/mediatek/mt76/mt7925/pci.c new file mode 100644 index 000000000000..e2fc3dee0698 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/pci.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include +#include +#include + +#include "mt7925.h" +#include "mac.h" +#include "mcu.h" +#include "../dma.h" + +static const struct pci_device_id mt7925_pci_device_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7925), + .driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0717), + .driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM }, + { }, +}; + +static bool mt7925_disable_aspm; +module_param_named(disable_aspm, mt7925_disable_aspm, bool, 0644); +MODULE_PARM_DESC(disable_aspm, "disable PCI ASPM support"); + +static int mt7925e_init_reset(struct mt792x_dev *dev) +{ + return mt792x_wpdma_reset(dev, true); +} + +static void mt7925e_unregister_device(struct mt792x_dev *dev) +{ + int i; + struct mt76_connac_pm *pm = &dev->pm; + + cancel_work_sync(&dev->init_work); + 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); + cancel_work_sync(&dev->reset_work); + + mt7925_tx_token_put(dev); + __mt792x_mcu_drv_pmctrl(dev); + mt792x_dma_cleanup(dev); + mt792x_wfsys_reset(dev); + skb_queue_purge(&dev->mt76.mcu.res_q); + + tasklet_disable(&dev->mt76.irq_tasklet); +} + +static void mt7925_reg_remap_restore(struct mt792x_dev *dev) +{ + /* remap to ori status */ + if (unlikely(dev->backup_l1)) { + dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->backup_l1); + dev->backup_l1 = 0; + } + + if (dev->backup_l2) { + dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->backup_l2); + dev->backup_l2 = 0; + } +} + +static u32 mt7925_reg_map_l1(struct mt792x_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); + + dev->backup_l1 = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); + + dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, + MT_HIF_REMAP_L1_MASK, + FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); + + /* use read to push write */ + dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); + + return MT_HIF_REMAP_BASE_L1 + offset; +} + +static u32 mt7925_reg_map_l2(struct mt792x_dev *dev, u32 addr) +{ + u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, MT_HIF_REMAP_BASE_L2); + + dev->backup_l2 = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); + + dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, + MT_HIF_REMAP_L1_MASK, + FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); + + dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, addr); + /* use read to push write */ + dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); + + return MT_HIF_REMAP_BASE_L1; +} + +static u32 __mt7925_reg_addr(struct mt792x_dev *dev, u32 addr) +{ + static const struct mt76_connac_reg_map fixed_map[] = { + { 0x830c0000, 0x000000, 0x0001000 }, /* WF_MCU_BUS_CR_REMAP */ + { 0x54000000, 0x002000, 0x0001000 }, /* WFDMA PCIE0 MCU DMA0 */ + { 0x55000000, 0x003000, 0x0001000 }, /* WFDMA PCIE0 MCU DMA1 */ + { 0x56000000, 0x004000, 0x0001000 }, /* WFDMA reserved */ + { 0x57000000, 0x005000, 0x0001000 }, /* WFDMA MCU wrap CR */ + { 0x58000000, 0x006000, 0x0001000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ + { 0x59000000, 0x007000, 0x0001000 }, /* WFDMA PCIE1 MCU DMA1 */ + { 0x820c0000, 0x008000, 0x0004000 }, /* WF_UMAC_TOP (PLE) */ + { 0x820c8000, 0x00c000, 0x0002000 }, /* WF_UMAC_TOP (PSE) */ + { 0x820cc000, 0x00e000, 0x0002000 }, /* WF_UMAC_TOP (PP) */ + { 0x74030000, 0x010000, 0x0001000 }, /* PCIe MAC */ + { 0x820e0000, 0x020000, 0x0000400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */ + { 0x820e1000, 0x020400, 0x0000200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */ + { 0x820e2000, 0x020800, 0x0000400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */ + { 0x820e3000, 0x020c00, 0x0000400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */ + { 0x820e4000, 0x021000, 0x0000400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + { 0x820e5000, 0x021400, 0x0000800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */ + { 0x820ce000, 0x021c00, 0x0000200 }, /* WF_LMAC_TOP (WF_SEC) */ + { 0x820e7000, 0x021e00, 0x0000200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ + { 0x820cf000, 0x022000, 0x0001000 }, /* WF_LMAC_TOP (WF_PF) */ + { 0x820e9000, 0x023400, 0x0000200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ + { 0x820ea000, 0x024000, 0x0000200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */ + { 0x820eb000, 0x024200, 0x0000400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */ + { 0x820ec000, 0x024600, 0x0000200 }, /* WF_LMAC_TOP BN0 (WF_INT) */ + { 0x820ed000, 0x024800, 0x0000800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */ + { 0x820ca000, 0x026000, 0x0002000 }, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ + { 0x820d0000, 0x030000, 0x0010000 }, /* WF_LMAC_TOP (WF_WTBLON) */ + { 0x40000000, 0x070000, 0x0010000 }, /* WF_UMAC_SYSRAM */ + { 0x00400000, 0x080000, 0x0010000 }, /* WF_MCU_SYSRAM */ + { 0x00410000, 0x090000, 0x0010000 }, /* WF_MCU_SYSRAM (configure register) */ + { 0x820f0000, 0x0a0000, 0x0000400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */ + { 0x820f1000, 0x0a0600, 0x0000200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */ + { 0x820f2000, 0x0a0800, 0x0000400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */ + { 0x820f3000, 0x0a0c00, 0x0000400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ + { 0x820f4000, 0x0a1000, 0x0000400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ + { 0x820f5000, 0x0a1400, 0x0000800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ + { 0x820f7000, 0x0a1e00, 0x0000200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ + { 0x820f9000, 0x0a3400, 0x0000200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + { 0x820fa000, 0x0a4000, 0x0000200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ + { 0x820fb000, 0x0a4200, 0x0000400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ + { 0x820fc000, 0x0a4600, 0x0000200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ + { 0x820fd000, 0x0a4800, 0x0000800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ + { 0x820c4000, 0x0a8000, 0x0004000 }, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ + { 0x820b0000, 0x0ae000, 0x0001000 }, /* [APB2] WFSYS_ON */ + { 0x80020000, 0x0b0000, 0x0010000 }, /* WF_TOP_MISC_OFF */ + { 0x81020000, 0x0c0000, 0x0010000 }, /* WF_TOP_MISC_ON */ + { 0x7c020000, 0x0d0000, 0x0010000 }, /* CONN_INFRA, wfdma */ + { 0x7c060000, 0x0e0000, 0x0010000 }, /* CONN_INFRA, conn_host_csr_top */ + { 0x7c000000, 0x0f0000, 0x0010000 }, /* CONN_INFRA */ + { 0x70020000, 0x1f0000, 0x0010000 }, /* Reserved for CBTOP, can't switch */ + { 0x7c500000, 0x060000, 0x2000000 }, /* remap */ + { 0x0, 0x0, 0x0 } /* End */ + }; + int i; + + if (addr < 0x200000) + return addr; + + mt7925_reg_remap_restore(dev); + + for (i = 0; i < ARRAY_SIZE(fixed_map); i++) { + u32 ofs; + + if (addr < fixed_map[i].phys) + continue; + + ofs = addr - fixed_map[i].phys; + if (ofs > fixed_map[i].size) + continue; + + return fixed_map[i].maps + ofs; + } + + if ((addr >= 0x18000000 && addr < 0x18c00000) || + (addr >= 0x70000000 && addr < 0x78000000) || + (addr >= 0x7c000000 && addr < 0x7c400000)) + return mt7925_reg_map_l1(dev, addr); + + return mt7925_reg_map_l2(dev, addr); +} + +static u32 mt7925_rr(struct mt76_dev *mdev, u32 offset) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + u32 addr = __mt7925_reg_addr(dev, offset); + + return dev->bus_ops->rr(mdev, addr); +} + +static void mt7925_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + u32 addr = __mt7925_reg_addr(dev, offset); + + dev->bus_ops->wr(mdev, addr, val); +} + +static u32 mt7925_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + u32 addr = __mt7925_reg_addr(dev, offset); + + return dev->bus_ops->rmw(mdev, addr, mask, val); +} + +static int mt7925_dma_init(struct mt792x_dev *dev) +{ + int ret; + + mt76_dma_attach(&dev->mt76); + + ret = mt792x_dma_disable(dev, true); + if (ret) + return ret; + + /* init tx queue */ + ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0, + MT7925_TX_RING_SIZE, + MT_TX_RING_BASE, NULL, 0); + if (ret) + return ret; + + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); + + /* command to WM */ + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7925_TXQ_MCU_WM, + MT7925_TX_MCU_RING_SIZE, MT_TX_RING_BASE); + if (ret) + return ret; + + /* firmware download */ + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7925_TXQ_FWDL, + MT7925_TX_FWDL_RING_SIZE, MT_TX_RING_BASE); + if (ret) + return ret; + + /* rx event */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], + MT7925_RXQ_MCU_WM, MT7925_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); + if (ret) + return ret; + + /* rx data */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], + MT7925_RXQ_BAND0, MT7925_RX_RING_SIZE, + MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE); + if (ret) + return ret; + + ret = mt76_init_queues(dev, mt792x_poll_rx); + if (ret < 0) + return ret; + + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + mt792x_poll_tx); + napi_enable(&dev->mt76.tx_napi); + + return mt792x_dma_enable(dev); +} + +static int mt7925_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 mt76_connac_hw_txp), + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | + MT_DRV_AMSDU_OFFLOAD, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, + .token_size = MT7925_TOKEN_SIZE, + .tx_prepare_skb = mt7925e_tx_prepare_skb, + .tx_complete_skb = mt76_connac_tx_complete_skb, + .rx_check = mt7925_rx_check, + .rx_skb = mt7925_queue_rx_skb, + .rx_poll_complete = mt792x_rx_poll_complete, + .sta_add = mt7925_mac_sta_add, + .sta_event = mt7925_mac_sta_event, + .sta_remove = mt7925_mac_sta_remove, + .update_survey = mt792x_update_channel, + }; + static const struct mt792x_hif_ops mt7925_pcie_ops = { + .init_reset = mt7925e_init_reset, + .reset = mt7925e_mac_reset, + .mcu_init = mt7925e_mcu_init, + .drv_own = mt792xe_mcu_drv_pmctrl, + .fw_own = mt792xe_mcu_fw_pmctrl, + }; + static const struct mt792x_irq_map irq_map = { + .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, + .tx = { + .all_complete_mask = MT_INT_TX_DONE_ALL, + .mcu_complete_mask = MT_INT_TX_DONE_MCU, + }, + .rx = { + .data_complete_mask = HOST_RX_DONE_INT_ENA2, + .wm_complete_mask = HOST_RX_DONE_INT_ENA0, + }, + }; + struct ieee80211_ops *ops; + struct mt76_bus_ops *bus_ops; + struct mt792x_dev *dev; + struct mt76_dev *mdev; + u8 features; + int ret; + u16 cmd; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret) + return ret; + + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MEMORY)) { + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + pci_set_master(pdev); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + goto err_free_pci_vec; + + if (mt7925_disable_aspm) + mt76_pci_disable_aspm(pdev); + + ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7925_ops, + (void *)id->driver_data, &features); + if (!ops) { + ret = -ENOMEM; + goto err_free_pci_vec; + } + + mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops); + if (!mdev) { + ret = -ENOMEM; + goto err_free_pci_vec; + } + + pci_set_drvdata(pdev, mdev); + + dev = container_of(mdev, struct mt792x_dev, mt76); + dev->fw_features = features; + dev->hif_ops = &mt7925_pcie_ops; + dev->irq_map = &irq_map; + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); + + 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); + if (!bus_ops) { + ret = -ENOMEM; + goto err_free_dev; + } + + bus_ops->rr = mt7925_rr; + bus_ops->wr = mt7925_wr; + bus_ops->rmw = mt7925_rmw; + dev->mt76.bus = bus_ops; + + if (!mt7925_disable_aspm && mt76_pci_aspm_supported(pdev)) + dev->aspm_supported = true; + + ret = __mt792x_mcu_fw_pmctrl(dev); + if (ret) + goto err_free_dev; + + ret = __mt792xe_mcu_drv_pmctrl(dev); + if (ret) + goto err_free_dev; + + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + + dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); + + ret = mt792x_wfsys_reset(dev); + if (ret) + goto err_free_dev; + + mt76_wr(dev, irq_map.host_irq_enable, 0); + + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + + ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) + goto err_free_dev; + + ret = mt7925_dma_init(dev); + if (ret) + goto err_free_irq; + + ret = mt7925_register_device(dev); + if (ret) + goto err_free_irq; + + return 0; + +err_free_irq: + devm_free_irq(&pdev->dev, pdev->irq, dev); +err_free_dev: + mt76_free_device(&dev->mt76); +err_free_pci_vec: + pci_free_irq_vectors(pdev); + + return ret; +} + +static void mt7925_pci_remove(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + + mt7925e_unregister_device(dev); + set_bit(MT76_REMOVED, &mdev->phy.state); + devm_free_irq(&pdev->dev, pdev->irq, dev); + mt76_free_device(&dev->mt76); + pci_free_irq_vectors(pdev); +} + +#if !defined(__FreeBSD__) || defined(CONFIG_PM_SLEEP) +static int mt7925_pci_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; + int i, err, ret; + + pm->suspended = true; + dev->hif_resumed = false; + flush_work(&dev->reset_work); + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + + mt7925_roc_abort_sync(dev); + + err = mt792x_mcu_drv_pmctrl(dev); + if (err < 0) + goto restore_suspend; + + wait_event_timeout(dev->wait, + !dev->regd_in_progress, 5 * HZ); + + /* always enable deep sleep during suspend to reduce + * power consumption + */ + mt7925_mcu_set_deep_sleep(dev, true); + + mt76_connac_mcu_set_hif_suspend(mdev, true, false); + ret = wait_event_timeout(dev->wait, + dev->hif_idle, 3 * HZ); + if (!ret) { + err = -ETIMEDOUT; + goto restore_suspend; + } + + napi_disable(&mdev->tx_napi); + mt76_worker_disable(&mdev->tx_worker); + + mt76_for_each_q_rx(mdev, i) { + napi_disable(&mdev->napi[i]); + } + + /* wait until dma is idle */ + mt76_poll(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | + MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); + + /* put dma disabled */ + mt76_clear(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + /* disable interrupt */ + mt76_wr(dev, dev->irq_map->host_irq_enable, 0); + mt76_wr(dev, MT_WFDMA0_HOST_INT_DIS, + dev->irq_map->tx.all_complete_mask | + MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); + + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + + synchronize_irq(pdev->irq); + tasklet_kill(&mdev->irq_tasklet); + + err = mt792x_mcu_fw_pmctrl(dev); + if (err) + goto restore_napi; + + return 0; + +restore_napi: + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + + if (!pm->ds_enable) + mt7925_mcu_set_deep_sleep(dev, false); + + mt76_connac_mcu_set_hif_suspend(mdev, false, false); + ret = wait_event_timeout(dev->wait, + dev->hif_resumed, 3 * HZ); + if (!ret) + err = -ETIMEDOUT; +restore_suspend: + pm->suspended = false; + + if (err < 0) + mt792x_reset(&dev->mt76); + + return err; +} + +static int mt7925_pci_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt76_connac_pm *pm = &dev->pm; + int i, err, ret; + + dev->hif_idle = false; + err = mt792x_mcu_drv_pmctrl(dev); + if (err < 0) + goto failed; + + mt792x_wpdma_reinit_cond(dev); + + /* enable interrupt */ + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt76_connac_irq_enable(&dev->mt76, + dev->irq_map->tx.all_complete_mask | + MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); + mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); + + /* put dma enabled */ + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + + mt76_worker_enable(&mdev->tx_worker); + + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + + local_bh_disable(); + mt76_for_each_q_rx(mdev, i) { + napi_schedule(&mdev->napi[i]); + } + napi_schedule(&mdev->tx_napi); + local_bh_enable(); + + mt76_connac_mcu_set_hif_suspend(mdev, false, false); + ret = wait_event_timeout(dev->wait, + dev->hif_resumed, 3 * HZ); + if (!ret) { + err = -ETIMEDOUT; + goto failed; + } + + /* restore previous ds setting */ + if (!pm->ds_enable) + mt7925_mcu_set_deep_sleep(dev, false); + + mt7925_regd_update(dev); +failed: + pm->suspended = false; + + if (err < 0) + mt792x_reset(&dev->mt76); + + return err; +} +#endif + +static void mt7925_pci_shutdown(struct pci_dev *pdev) +{ + mt7925_pci_remove(pdev); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(mt7925_pm_ops, mt7925_pci_suspend, mt7925_pci_resume); + +static struct pci_driver mt7925_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7925_pci_device_table, + .probe = mt7925_pci_probe, + .remove = mt7925_pci_remove, + .shutdown = mt7925_pci_shutdown, + .driver.pm = pm_sleep_ptr(&mt7925_pm_ops), +}; + +module_pci_driver(mt7925_pci_driver); + +MODULE_DEVICE_TABLE(pci, mt7925_pci_device_table); +MODULE_FIRMWARE(MT7925_FIRMWARE_WM); +MODULE_FIRMWARE(MT7925_ROM_PATCH); +MODULE_AUTHOR("Deren Wu "); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver"); +MODULE_LICENSE("Dual BSD/GPL"); +#if defined(__FreeBSD__) +MODULE_VERSION(mt7925_pci, 1); +MODULE_DEPEND(mt7925_pci, linuxkpi, 1, 1, 1); +MODULE_DEPEND(mt7925_pci, linuxkpi_wlan, 1, 1, 1); +MODULE_DEPEND(mt7925_pci, mt76_core, 1, 1, 1); +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c b/sys/contrib/dev/mediatek/mt76/mt7925/pci_mac.c similarity index 61% copy from sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c copy to sys/contrib/dev/mediatek/mt76/mt7925/pci_mac.c index e7a995e7e70a..4578d16bf456 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7925/pci_mac.c @@ -1,128 +1,151 @@ // SPDX-License-Identifier: ISC -/* Copyright (C) 2021 MediaTek Inc. */ +/* Copyright (C) 2023 MediaTek Inc. */ -#include "mt7921.h" +#include "mt7925.h" #include "../dma.h" -#include "../mt76_connac2_mac.h" +#include "mac.h" -int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, +int mt7925e_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 mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct mt76_connac_hw_txp *txp; struct mt76_txwi_cache *t; 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 mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - if (time_after(jiffies, msta->last_txs + HZ / 4)) { + if (time_after(jiffies, msta->deflink.last_txs + HZ / 4)) { info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->last_txs = jiffies; + msta->deflink.last_txs = jiffies; } } pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt76_connac2_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, - pid, qid, 0); + mt7925_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, key, + pid, qid, 0); txp = (struct mt76_connac_hw_txp *)(txwi + MT_TXD_SIZE); memset(txp, 0, sizeof(struct mt76_connac_hw_txp)); mt76_connac_write_hw_txp(mdev, tx_info, txp, id); - tx_info->skb = DMA_DUMMY_DATA; + tx_info->skb = NULL; return 0; } -int mt7921e_mac_reset(struct mt792x_dev *dev) +void mt7925_tx_token_put(struct mt792x_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) { + mt7925_txwi_free(dev, txwi, NULL, NULL, NULL); + dev->mt76.token_count--; + } + spin_unlock_bh(&dev->mt76.token_lock); + idr_destroy(&dev->mt76.token); +} + +int mt7925e_mac_reset(struct mt792x_dev *dev) +{ + const struct mt792x_irq_map *irq_map = dev->irq_map; int i, err; mt792xe_mcu_drv_pmctrl(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt76_wr(dev, dev->irq_map->host_irq_enable, 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); - - mt76_connac2_tx_token_put(&dev->mt76); + if (irq_map->rx.data_complete_mask) + napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); + if (irq_map->rx.wm_complete_mask) + napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); + if (irq_map->rx.wm2_complete_mask) + napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); + if (irq_map->tx.all_complete_mask) + napi_disable(&dev->mt76.tx_napi); + + mt7925_tx_token_put(dev); idr_init(&dev->mt76.token); mt792x_wpdma_reset(dev, true); - local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { napi_enable(&dev->mt76.napi[i]); + } + napi_enable(&dev->mt76.tx_napi); + + local_bh_disable(); + mt76_for_each_q_rx(&dev->mt76, i) { napi_schedule(&dev->mt76.napi[i]); } + napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); dev->fw_assert = false; clear_bit(MT76_MCU_RESET, &dev->mphy.state); mt76_wr(dev, dev->irq_map->host_irq_enable, dev->irq_map->tx.all_complete_mask | MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); - err = mt7921e_driver_own(dev); + err = mt792xe_mcu_fw_pmctrl(dev); + if (err) + return err; + + err = __mt792xe_mcu_drv_pmctrl(dev); if (err) goto out; - err = mt7921_run_firmware(dev); + err = mt7925_run_firmware(dev); if (err) goto out; - err = mt7921_mcu_set_eeprom(dev); + err = mt7925_mcu_set_eeprom(dev); if (err) goto out; - err = mt7921_mac_init(dev); + err = mt7925_mac_init(dev); if (err) goto out; - err = __mt7921_start(&dev->phy); + err = __mt7925_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; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/pci_mcu.c b/sys/contrib/dev/mediatek/mt76/mt7925/pci_mcu.c new file mode 100644 index 000000000000..f95bc5dcd830 --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/pci_mcu.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2023 MediaTek Inc. */ + +#include "mt7925.h" +#include "mcu.h" + +static int +mt7925_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, int *seq) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + enum mt76_mcuq_id txq = MT_MCUQ_WM; + int ret; + + ret = mt7925_mcu_fill_message(mdev, skb, cmd, seq); + if (ret) + return ret; + + mdev->mcu.timeout = 3 * HZ; + + if (cmd == MCU_CMD(FW_SCATTER)) + txq = MT_MCUQ_FWDL; + + return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0); +} + +int mt7925e_mcu_init(struct mt792x_dev *dev) +{ + static const struct mt76_mcu_ops mt7925_mcu_ops = { + .headroom = sizeof(struct mt76_connac2_mcu_txd), + .mcu_skb_send_msg = mt7925_mcu_send_message, + .mcu_parse_response = mt7925_mcu_parse_response, + }; + int err; + + dev->mt76.mcu_ops = &mt7925_mcu_ops; + + err = mt792xe_mcu_fw_pmctrl(dev); + if (err) + return err; + + err = __mt792xe_mcu_drv_pmctrl(dev); + if (err) + return err; + + mt76_rmw_field(dev, MT_PCIE_MAC_PM, MT_PCIE_MAC_PM_L0S_DIS, 1); + + err = mt7925_run_firmware(dev); + + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); + + return err; +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7925/regs.h b/sys/contrib/dev/mediatek/mt76/mt7925/regs.h new file mode 100644 index 000000000000..985794a40c1a --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/mt7925/regs.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2023 MediaTek Inc. */ + +#ifndef __MT7925_REGS_H +#define __MT7925_REGS_H + +#include "../mt792x_regs.h" + +#define MT_MDP_BASE 0x820cc800 +#define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) + +#define MT_MDP_DCR0 MT_MDP(0x000) +#define MT_MDP_DCR0_DAMSDU_EN BIT(15) +#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) + +#define MT_MDP_DCR1 MT_MDP(0x004) +#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3) + +#define MT_MDP_BNRCFR0(_band) MT_MDP(0x090 + ((_band) << 8)) +#define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4) +#define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6) +#define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8) + +#define MT_MDP_BNRCFR1(_band) MT_MDP(0x094 + ((_band) << 8)) +#define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22) +#define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27) +#define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29) +#define MT_MDP_TO_HIF 0 +#define MT_MDP_TO_WM 1 + +#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x228) +#define MT_WFDMA0_HOST_INT_DIS MT_WFDMA0(0x22c) +#define HOST_RX_DONE_INT_ENA4 BIT(12) +#define HOST_RX_DONE_INT_ENA5 BIT(13) +#define HOST_RX_DONE_INT_ENA6 BIT(14) +#define HOST_RX_DONE_INT_ENA7 BIT(15) +#define HOST_RX_DONE_INT_ENA8 BIT(16) +#define HOST_RX_DONE_INT_ENA9 BIT(17) +#define HOST_RX_DONE_INT_ENA10 BIT(18) +#define HOST_RX_DONE_INT_ENA11 BIT(19) +#define HOST_TX_DONE_INT_ENA15 BIT(25) +#define HOST_TX_DONE_INT_ENA16 BIT(26) +#define HOST_TX_DONE_INT_ENA17 BIT(27) + +/* WFDMA interrupt */ +#define MT_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 +#define MT_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 +#define MT_INT_RX_DONE_WM2 HOST_RX_DONE_INT_ENA1 +#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_DATA | \ + MT_INT_RX_DONE_WM | \ + MT_INT_RX_DONE_WM2) + +#define MT_INT_TX_DONE_MCU_WM (HOST_TX_DONE_INT_ENA15 | \ + HOST_TX_DONE_INT_ENA17) + +#define MT_INT_TX_DONE_FWDL HOST_TX_DONE_INT_ENA16 +#define MT_INT_TX_DONE_BAND0 HOST_TX_DONE_INT_ENA0 + +#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WM | \ + MT_INT_TX_DONE_FWDL) +#define MT_INT_TX_DONE_ALL (MT_INT_TX_DONE_MCU_WM | \ + MT_INT_TX_DONE_BAND0 | \ + GENMASK(18, 4)) + +#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x500) + +#define MT_INFRA_CFG_BASE 0xd1000 +#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs)) + +#define MT_HIF_REMAP_L1 0x155024 +#define MT_HIF_REMAP_L1_MASK GENMASK(31, 16) +#define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) +#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_L1 0x130000 + +#define MT_HIF_REMAP_L2 0x0120 +#if IS_ENABLED(CONFIG_MT76_DEV) +#define MT_HIF_REMAP_BASE_L2 (0x7c500000 - (0x7c000000 - 0x18000000)) +#else +#define MT_HIF_REMAP_BASE_L2 0x18500000 +#endif + +#define MT_WFSYS_SW_RST_B 0x7c000140 + +#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x370) +#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(4, 0) + +#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x380) +#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(11, 0) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(14) + +#endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7921/usb.c b/sys/contrib/dev/mediatek/mt76/mt7925/usb.c similarity index 68% copy from sys/contrib/dev/mediatek/mt76/mt7921/usb.c copy to sys/contrib/dev/mediatek/mt76/mt7925/usb.c index 59cd3d98bf90..4dfbc1b6cfdd 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7921/usb.c +++ b/sys/contrib/dev/mediatek/mt76/mt7925/usb.c @@ -1,348 +1,343 @@ // SPDX-License-Identifier: ISC -/* Copyright (C) 2022 MediaTek Inc. - * - * Author: Lorenzo Bianconi - */ +/* Copyright (C) 2023 MediaTek Inc. */ #include #include #include -#include "mt7921.h" +#include "mt7925.h" #include "mcu.h" -#include "../mt76_connac2_mac.h" - -static const struct usb_device_id mt7921u_device_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, - /* Comfast CF-952AX */ - { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6211, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, - /* Netgear, Inc. [A8000,AXE3000] */ - { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, +#include "mac.h" + +static const struct usb_device_id mt7925u_device_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM }, { }, }; static int -mt7921u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, +mt7925u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *seq) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); u32 pad, ep; int ret; - ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, seq); + ret = mt7925_mcu_fill_message(mdev, skb, cmd, seq); if (ret) return ret; mdev->mcu.timeout = 3 * HZ; if (cmd != MCU_CMD(FW_SCATTER)) ep = MT_EP_OUT_INBAND_CMD; else ep = MT_EP_OUT_AC_BE; - mt7921_skb_add_usb_sdio_hdr(dev, skb, 0); + mt792x_skb_add_usb_sdio_hdr(dev, skb, 0); pad = round_up(skb->len, 4) + 4 - skb->len; __skb_put_zero(skb, pad); ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 1000, ep); dev_kfree_skb(skb); return ret; } -static int mt7921u_mcu_init(struct mt792x_dev *dev) +static int mt7925u_mcu_init(struct mt792x_dev *dev) { static const struct mt76_mcu_ops mcu_ops = { .headroom = MT_SDIO_HDR_SIZE + sizeof(struct mt76_connac2_mcu_txd), .tailroom = MT_USB_TAIL_SIZE, - .mcu_skb_send_msg = mt7921u_mcu_send_message, - .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_skb_send_msg = mt7925u_mcu_send_message, + .mcu_parse_response = mt7925_mcu_parse_response, }; int ret; dev->mt76.mcu_ops = &mcu_ops; mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); - ret = mt7921_run_firmware(dev); + ret = mt7925_run_firmware(dev); if (ret) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); return 0; } -static int mt7921u_mac_reset(struct mt792x_dev *dev) +static int mt7925u_mac_reset(struct mt792x_dev *dev) { int err; 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); mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); mt792xu_wfsys_reset(dev); clear_bit(MT76_MCU_RESET, &dev->mphy.state); err = mt76u_resume_rx(&dev->mt76); if (err) goto out; err = mt792xu_mcu_power_on(dev); if (err) goto out; err = mt792xu_dma_init(dev, false); if (err) goto out; mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE); mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); - err = mt7921_run_firmware(dev); + err = mt7925_run_firmware(dev); if (err) goto out; mt76_clear(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); - err = mt7921_mcu_set_eeprom(dev); + err = mt7925_mcu_set_eeprom(dev); if (err) goto out; - err = mt7921_mac_init(dev); + err = mt7925_mac_init(dev); if (err) goto out; - err = __mt7921_start(&dev->phy); + err = __mt7925_start(&dev->phy); out: clear_bit(MT76_RESET, &dev->mphy.state); mt76_worker_enable(&dev->mt76.tx_worker); return err; } -static void mt7921u_stop(struct ieee80211_hw *hw) -{ - struct mt792x_dev *dev = mt792x_hw_dev(hw); - - mt76u_stop_tx(&dev->mt76); - mt7921_stop(hw); -} - -static int mt7921u_probe(struct usb_interface *usb_intf, +static int mt7925u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_SDIO_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ | MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, - .tx_prepare_skb = mt7921_usb_sdio_tx_prepare_skb, - .tx_complete_skb = mt7921_usb_sdio_tx_complete_skb, - .tx_status_data = mt7921_usb_sdio_tx_status_data, - .rx_skb = mt7921_queue_rx_skb, - .rx_check = mt7921_rx_check, - .sta_add = mt7921_mac_sta_add, - .sta_assoc = mt7921_mac_sta_assoc, - .sta_remove = mt7921_mac_sta_remove, + .tx_prepare_skb = mt7925_usb_sdio_tx_prepare_skb, + .tx_complete_skb = mt7925_usb_sdio_tx_complete_skb, + .tx_status_data = mt7925_usb_sdio_tx_status_data, + .rx_skb = mt7925_queue_rx_skb, + .rx_check = mt7925_rx_check, + .sta_add = mt7925_mac_sta_add, + .sta_event = mt7925_mac_sta_event, + .sta_remove = mt7925_mac_sta_remove, .update_survey = mt792x_update_channel, }; static const struct mt792x_hif_ops hif_ops = { - .mcu_init = mt7921u_mcu_init, + .mcu_init = mt7925u_mcu_init, .init_reset = mt792xu_init_reset, - .reset = mt7921u_mac_reset, + .reset = mt7925u_mac_reset, }; static struct mt76_bus_ops bus_ops = { .rr = mt792xu_rr, .wr = mt792xu_wr, .rmw = mt792xu_rmw, .read_copy = mt76u_read_copy, .write_copy = mt792xu_copy, .type = MT76_BUS_USB, }; struct usb_device *udev = interface_to_usbdev(usb_intf); struct ieee80211_ops *ops; struct ieee80211_hw *hw; struct mt792x_dev *dev; struct mt76_dev *mdev; u8 features; int ret; - ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7921_ops, + ops = mt792x_get_mac80211_ops(&usb_intf->dev, &mt7925_ops, (void *)id->driver_info, &features); if (!ops) return -ENOMEM; - ops->stop = mt7921u_stop; + ops->stop = mt792xu_stop; + mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) return -ENOMEM; dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &hif_ops; udev = usb_get_dev(udev); usb_reset_device(udev); usb_set_intfdata(usb_intf, dev); ret = __mt76u_init(mdev, usb_intf, &bus_ops); if (ret < 0) 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); if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) { ret = mt792xu_wfsys_reset(dev); if (ret) goto error; } ret = mt792xu_mcu_power_on(dev); if (ret) goto error; ret = mt76u_alloc_mcu_queue(&dev->mt76); if (ret) goto error; ret = mt76u_alloc_queues(&dev->mt76); if (ret) goto error; ret = mt792xu_dma_init(dev, false); if (ret) goto error; hw = mt76_hw(dev); /* check hw sg support in order to enable AMSDU */ hw->max_tx_fragments = mdev->usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; - ret = mt7921_register_device(dev); + ret = mt7925_register_device(dev); if (ret) goto error; return 0; error: mt76u_queues_deinit(&dev->mt76); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); mt76_free_device(&dev->mt76); return ret; } #ifdef CONFIG_PM -static int mt7921u_suspend(struct usb_interface *intf, pm_message_t state) +static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state) { struct mt792x_dev *dev = usb_get_intfdata(intf); struct mt76_connac_pm *pm = &dev->pm; - int err; + int err, ret; pm->suspended = true; + dev->hif_resumed = false; flush_work(&dev->reset_work); - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, true); - if (err) + mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false); + ret = wait_event_timeout(dev->wait, + dev->hif_idle, 3 * HZ); + if (!ret) { + err = -ETIMEDOUT; goto failed; + } mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); return 0; failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } -static int mt7921u_resume(struct usb_interface *intf) +static int mt7925u_resume(struct usb_interface *intf) { struct mt792x_dev *dev = usb_get_intfdata(intf); struct mt76_connac_pm *pm = &dev->pm; bool reinit = true; - int err, i; + int err, i, ret; + dev->hif_idle = false; for (i = 0; i < 10; i++) { u32 val = mt76_rr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT); if (!(val & MT_WF_SW_SER_TRIGGER_SUSPEND)) { reinit = false; break; } if (val & MT_WF_SW_SER_DONE_SUSPEND) { mt76_wr(dev, MT_WF_SW_DEF_CR_USB_MCU_EVENT, 0); break; } msleep(20); } if (reinit || mt792x_dma_need_reinit(dev)) { err = mt792xu_dma_init(dev, true); if (err) goto failed; } err = mt76u_resume_rx(&dev->mt76); if (err < 0) goto failed; - err = mt76_connac_mcu_set_hif_suspend(&dev->mt76, false); + mt76_connac_mcu_set_hif_suspend(&dev->mt76, false, false); + ret = wait_event_timeout(dev->wait, + dev->hif_resumed, 3 * HZ); + if (!ret) + err = -ETIMEDOUT; failed: pm->suspended = false; if (err < 0) mt792x_reset(&dev->mt76); return err; } #endif /* CONFIG_PM */ -MODULE_DEVICE_TABLE(usb, mt7921u_device_table); -MODULE_FIRMWARE(MT7921_FIRMWARE_WM); -MODULE_FIRMWARE(MT7921_ROM_PATCH); +MODULE_DEVICE_TABLE(usb, mt7925u_device_table); +MODULE_FIRMWARE(MT7925_FIRMWARE_WM); +MODULE_FIRMWARE(MT7925_ROM_PATCH); -static struct usb_driver mt7921u_driver = { +static struct usb_driver mt7925u_driver = { .name = KBUILD_MODNAME, - .id_table = mt7921u_device_table, - .probe = mt7921u_probe, + .id_table = mt7925u_device_table, + .probe = mt7925u_probe, .disconnect = mt792xu_disconnect, #ifdef CONFIG_PM - .suspend = mt7921u_suspend, - .resume = mt7921u_resume, - .reset_resume = mt7921u_resume, + .suspend = mt7925u_suspend, + .resume = mt7925u_resume, + .reset_resume = mt7925u_resume, #endif /* CONFIG_PM */ .soft_unbind = 1, .disable_hub_initiated_lpm = 1, }; -module_usb_driver(mt7921u_driver); +module_usb_driver(mt7925u_driver); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt792x.h b/sys/contrib/dev/mediatek/mt76/mt792x.h index 5d5ab8630041..32ed01a96bf7 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x.h +++ b/sys/contrib/dev/mediatek/mt76/mt792x.h @@ -1,367 +1,524 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT792X_H #define __MT792X_H #include #include #include "mt76_connac_mcu.h" #include "mt792x_regs.h" #include "mt792x_acpi_sar.h" #define MT792x_PM_TIMEOUT (HZ / 12) #define MT792x_HW_SCAN_TIMEOUT (HZ / 10) #define MT792x_MAX_INTERFACES 4 #define MT792x_WTBL_SIZE 20 #define MT792x_WTBL_RESERVED (MT792x_WTBL_SIZE - 1) #define MT792x_WTBL_STA (MT792x_WTBL_RESERVED - MT792x_MAX_INTERFACES) #define MT792x_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT792x_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT792x_FW_TAG_FEATURE 4 #define MT792x_FW_CAP_CNM BIT(7) +#define MT792x_CHIP_CAP_CLC_EVT_EN BIT(0) +#define MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN BIT(1) +#define MT792x_CHIP_CAP_MLO_EVT_EN BIT(2) +#define MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN BIT(3) + /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ #define MT792x_BASIC_RATES_TBL 11 #define MT792x_WATCHDOG_TIME (HZ / 4) #define MT792x_DRV_OWN_RETRY_COUNT 10 #define MT792x_MCU_INIT_RETRY_COUNT 10 #define MT792x_WFSYS_INIT_RETRY_COUNT 2 +#define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin" #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" +#define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin" +#define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" +#define MT7925_ROM_PATCH "mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin" + +#define MT792x_SDIO_HDR_TX_BYTES GENMASK(15, 0) +#define MT792x_SDIO_HDR_PKT_TYPE GENMASK(17, 16) struct mt792x_vif; struct mt792x_sta; struct mt792x_realease_info { __le16 len; u8 pad_len; u8 tag; } __packed; struct mt792x_fw_features { u8 segment; u8 data; u8 rsv[14]; } __packed; enum { MT792x_CLC_POWER, - MT792x_CLC_CHAN, + MT792x_CLC_POWER_EXT, MT792x_CLC_MAX_NUM, }; +enum mt792x_reg_power_type { + MT_AP_UNSET = 0, + MT_AP_DEFAULT, + MT_AP_LPI, + MT_AP_SP, + MT_AP_VLP, +}; + DECLARE_EWMA(avg_signal, 10, 8) -struct mt792x_sta { +struct mt792x_link_sta { struct mt76_wcid wcid; /* must be first */ - struct mt792x_vif *vif; - u32 airtime_ac[8]; int ack_signal; struct ewma_avg_signal avg_ack_signal; unsigned long last_txs; struct mt76_connac_sta_key_conf bip; + + struct mt792x_sta *sta; + + struct ieee80211_link_sta *pri_link; +}; + +struct mt792x_sta { + struct mt792x_link_sta deflink; /* must be first */ + struct mt792x_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + + struct mt792x_vif *vif; + + u16 valid_links; + u8 deflink_id; }; DECLARE_EWMA(rssi, 10, 8); +struct mt792x_chanctx { + struct mt792x_bss_conf *bss_conf; +}; + +struct mt792x_bss_conf { + struct mt76_vif_link mt76; /* must be first */ + struct mt792x_vif *vif; + struct ewma_rssi rssi; + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; + unsigned int link_id; +}; + struct mt792x_vif { - struct mt76_vif mt76; /* must be first */ + struct mt792x_bss_conf bss_conf; /* must be first */ + struct mt792x_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; struct mt792x_sta sta; struct mt792x_sta *wep_sta; struct mt792x_phy *phy; + u16 valid_links; + u8 deflink_id; - struct ewma_rssi rssi; - - struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; - struct ieee80211_chanctx_conf *ctx; + struct work_struct csa_work; + struct timer_list csa_timer; }; struct mt792x_phy { struct mt76_phy *mt76; struct mt792x_dev *dev; struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; u64 omac_mask; u16 noise; s16 coverage_class; u8 slottime; u32 rx_ampdu_ts; u32 ampdu_ref; struct mt76_mib_stats mib; u8 sta_work_count; + u8 clc_chan_conf; + enum mt792x_reg_power_type power_type; struct sk_buff_head scan_event_list; struct delayed_work scan_work; #ifdef CONFIG_ACPI void *acpisar; #endif void *clc[MT792x_CLC_MAX_NUM]; + u64 chip_cap; + u16 eml_cap; struct work_struct roc_work; struct timer_list roc_timer; wait_queue_head_t roc_wait; u8 roc_token_id; bool roc_grant; }; struct mt792x_irq_map { u32 host_irq_enable; struct { u32 all_complete_mask; u32 mcu_complete_mask; } tx; struct { u32 data_complete_mask; u32 wm_complete_mask; u32 wm2_complete_mask; } rx; }; #define mt792x_init_reset(dev) ((dev)->hif_ops->init_reset(dev)) #define mt792x_dev_reset(dev) ((dev)->hif_ops->reset(dev)) #define mt792x_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev)) #define __mt792x_mcu_drv_pmctrl(dev) ((dev)->hif_ops->drv_own(dev)) #define __mt792x_mcu_fw_pmctrl(dev) ((dev)->hif_ops->fw_own(dev)) struct mt792x_hif_ops { int (*init_reset)(struct mt792x_dev *dev); int (*reset)(struct mt792x_dev *dev); int (*mcu_init)(struct mt792x_dev *dev); int (*drv_own)(struct mt792x_dev *dev); int (*fw_own)(struct mt792x_dev *dev); }; struct mt792x_dev { union { /* must be first */ struct mt76_dev mt76; struct mt76_phy mphy; }; + struct mac_address macaddr_list[8]; + const struct mt76_bus_ops *bus_ops; struct mt792x_phy phy; struct work_struct reset_work; bool hw_full_reset:1; bool hw_init_done:1; bool fw_assert:1; bool has_eht:1; + bool regd_in_progress:1; + bool aspm_supported:1; + bool hif_idle:1; + bool hif_resumed:1; + bool sar_inited:1; + bool regd_change:1; + wait_queue_head_t wait; struct work_struct init_work; u8 fw_debug; u8 fw_features; struct mt76_connac_pm pm; struct mt76_connac_coredump coredump; const struct mt792x_hif_ops *hif_ops; const struct mt792x_irq_map *irq_map; struct work_struct ipv6_ns_work; /* IPv6 addresses for WoWLAN */ struct sk_buff_head ipv6_ns_list; enum environment_cap country_ie_env; u32 backup_l1; u32 backup_l2; + + struct ieee80211_chanctx_conf *new_ctx; }; +static inline struct mt792x_bss_conf * +mt792x_vif_to_link(struct mt792x_vif *mvif, u8 link_id) +{ + struct ieee80211_vif *vif; + struct mt792x_bss_conf *bss_conf; + + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &mvif->bss_conf; + + bss_conf = rcu_dereference_protected(mvif->link_conf[link_id], + lockdep_is_held(&mvif->phy->dev->mt76.mutex)); + + return bss_conf ? bss_conf : &mvif->bss_conf; +} + +static inline struct mt792x_link_sta * +mt792x_sta_to_link(struct mt792x_sta *msta, u8 link_id) +{ + struct ieee80211_vif *vif; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &msta->deflink; + + return rcu_dereference_protected(msta->link[link_id], + lockdep_is_held(&msta->vif->phy->dev->mt76.mutex)); +} + +static inline struct mt792x_bss_conf * +mt792x_link_conf_to_mconf(struct ieee80211_bss_conf *link_conf) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + return mt792x_vif_to_link(mvif, link_conf->link_id); +} + +static inline struct ieee80211_bss_conf * +mt792x_vif_to_bss_conf(struct ieee80211_vif *vif, unsigned int link_id) +{ + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &vif->bss_conf; + + return link_conf_dereference_protected(vif, link_id); +} + +static inline struct ieee80211_link_sta * +mt792x_sta_to_link_sta(struct ieee80211_vif *vif, struct ieee80211_sta *sta, + unsigned int link_id) +{ + if (!ieee80211_vif_is_mld(vif) || + link_id >= IEEE80211_LINK_UNSPECIFIED) + return &sta->deflink; + + return link_sta_dereference_protected(sta, link_id); +} + static inline struct mt792x_dev * mt792x_hw_dev(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return container_of(phy->dev, struct mt792x_dev, mt76); } static inline struct mt792x_phy * mt792x_hw_phy(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return phy->priv; } static inline void mt792x_get_status_freq_info(struct mt76_rx_status *status, u8 chfreq) { if (chfreq > 180) { status->band = NL80211_BAND_6GHZ; chfreq = (chfreq - 181) * 4 + 1; } else if (chfreq > 14) { status->band = NL80211_BAND_5GHZ; } else { status->band = NL80211_BAND_2GHZ; } status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } static inline bool mt792x_dma_need_reinit(struct mt792x_dev *dev) { return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } #define mt792x_mutex_acquire(dev) \ mt76_connac_mutex_acquire(&(dev)->mt76, &(dev)->pm) #define mt792x_mutex_release(dev) \ mt76_connac_mutex_release(&(dev)->mt76, &(dev)->pm) +void mt792x_stop(struct ieee80211_hw *hw, bool suspend); void mt792x_pm_wake_work(struct work_struct *work); void mt792x_pm_power_save_work(struct work_struct *work); void mt792x_reset(struct mt76_dev *mdev); void mt792x_update_channel(struct mt76_phy *mphy); void mt792x_mac_reset_counters(struct mt792x_phy *phy); void mt792x_mac_init_band(struct mt792x_dev *dev, u8 band); void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb); struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx, bool unicast); void mt792x_mac_update_mib_stats(struct mt792x_phy *phy); void mt792x_mac_set_timeing(struct mt792x_phy *phy); void mt792x_mac_work(struct work_struct *work); void mt792x_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb); int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params); int mt792x_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 timestamp); void mt792x_tx_worker(struct mt76_worker *w); void mt792x_roc_timer(struct timer_list *timer); +void mt792x_csa_timer(struct timer_list *timer); void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); void mt792x_set_wakeup(struct ieee80211_hw *hw, bool enabled); void mt792x_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data); int mt792x_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int sset); void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data); void mt792x_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo); void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class); void mt792x_dma_cleanup(struct mt792x_dev *dev); int mt792x_dma_enable(struct mt792x_dev *dev); int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force); int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev); int mt792x_dma_disable(struct mt792x_dev *dev, bool force); irqreturn_t mt792x_irq_handler(int irq, void *dev_instance); void mt792x_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q); int mt792x_poll_tx(struct napi_struct *napi, int budget); int mt792x_poll_rx(struct napi_struct *napi, int budget); void mt792x_irq_tasklet(unsigned long data); int mt792x_wfsys_reset(struct mt792x_dev *dev); int mt792x_tx_stats_show(struct seq_file *file, void *data); int mt792x_queues_acq(struct seq_file *s, void *data); int mt792x_queues_read(struct seq_file *s, void *data); int mt792x_pm_stats(struct seq_file *s, void *data); int mt792x_pm_idle_timeout_set(void *data, u64 val); int mt792x_pm_idle_timeout_get(void *data, u64 *val); int mt792x_init_wiphy(struct ieee80211_hw *hw); struct ieee80211_ops * mt792x_get_mac80211_ops(struct device *dev, const struct ieee80211_ops *mac80211_ops, void *drv_data, u8 *fw_features); int mt792x_init_wcid(struct mt792x_dev *dev); int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev); +void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink); +void mt792x_config_mac_addr_list(struct mt792x_dev *dev); static inline char *mt792x_ram_name(struct mt792x_dev *dev) { switch (mt76_chip(&dev->mt76)) { + case 0x7920: + return MT7920_FIRMWARE_WM; case 0x7922: return MT7922_FIRMWARE_WM; + case 0x7925: + return MT7925_FIRMWARE_WM; default: return MT7921_FIRMWARE_WM; } } static inline char *mt792x_patch_name(struct mt792x_dev *dev) { switch (mt76_chip(&dev->mt76)) { + case 0x7920: + return MT7920_ROM_PATCH; case 0x7922: return MT7922_ROM_PATCH; + case 0x7925: + return MT7925_ROM_PATCH; default: return MT7921_ROM_PATCH; } } int mt792x_load_firmware(struct mt792x_dev *dev); /* usb */ #define MT_USB_TYPE_VENDOR (USB_TYPE_VENDOR | 0x1f) #define MT_USB_TYPE_UHW_VENDOR (USB_TYPE_VENDOR | 0x1e) int mt792xu_dma_init(struct mt792x_dev *dev, bool resume); int mt792xu_mcu_power_on(struct mt792x_dev *dev); int mt792xu_wfsys_reset(struct mt792x_dev *dev); int mt792xu_init_reset(struct mt792x_dev *dev); u32 mt792xu_rr(struct mt76_dev *dev, u32 addr); void mt792xu_wr(struct mt76_dev *dev, u32 addr, u32 val); u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val); void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len); void mt792xu_disconnect(struct usb_interface *usb_intf); +void mt792xu_stop(struct ieee80211_hw *hw, bool suspend); + +static inline void +mt792x_skb_add_usb_sdio_hdr(struct mt792x_dev *dev, struct sk_buff *skb, + int type) +{ + u32 hdr, len; + + len = mt76_is_usb(&dev->mt76) ? skb->len : skb->len + sizeof(hdr); + hdr = FIELD_PREP(MT792x_SDIO_HDR_TX_BYTES, len) | + FIELD_PREP(MT792x_SDIO_HDR_PKT_TYPE, type); + + put_unaligned_le32(hdr, skb_push(skb, sizeof(hdr))); +} int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev); int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev); #ifdef CONFIG_ACPI int mt792x_init_acpi_sar(struct mt792x_dev *dev); int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); u8 mt792x_acpi_get_flags(struct mt792x_phy *phy); +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2); #else static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev) { return 0; } static inline int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) { return 0; } static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) { return 0; } + +static inline u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + return 0xf; +} #endif #endif /* __MT7925_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.c b/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.c index 303c0f5c9c66..9317f8ff2070 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.c +++ b/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.c @@ -1,350 +1,409 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. */ #include #include "mt792x.h" static int mt792x_acpi_read(struct mt792x_dev *dev, u8 *method, u8 **tbl, u32 *len) { struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; struct mt76_dev *mdev = &dev->mt76; union acpi_object *sar_root; acpi_handle root, handle; acpi_status status; u32 i = 0; int ret; root = ACPI_HANDLE(mdev->dev); if (!root) return -EOPNOTSUPP; status = acpi_get_handle(root, method, &handle); if (ACPI_FAILURE(status)) return -EIO; status = acpi_evaluate_object(handle, NULL, NULL, &buf); if (ACPI_FAILURE(status)) return -EIO; sar_root = buf.pointer; if (sar_root->type != ACPI_TYPE_PACKAGE || sar_root->package.count < 4 || sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) { dev_err(mdev->dev, "sar cnt = %d\n", sar_root->package.count); ret = -EINVAL; goto free; } if (!*tbl) { *tbl = devm_kzalloc(mdev->dev, sar_root->package.count, GFP_KERNEL); if (!*tbl) { ret = -ENOMEM; goto free; } } if (len) *len = sar_root->package.count; for (i = 0; i < sar_root->package.count; i++) { union acpi_object *sar_unit = &sar_root->package.elements[i]; if (sar_unit->type != ACPI_TYPE_INTEGER) break; *(*tbl + i) = (u8)sar_unit->integer.value; } ret = i == sar_root->package.count ? 0 : -EINVAL; free: kfree(sar_root); return ret; } /* MTCL : Country List Table for 6G band */ -static void +static int mt792x_asar_acpi_read_mtcl(struct mt792x_dev *dev, u8 **table, u8 *version) { - if (mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL) < 0) - *version = 1; - else - *version = 2; + int ret; + + *version = ((ret = mt792x_acpi_read(dev, MT792x_ACPI_MTCL, table, NULL)) < 0) + ? 1 : 2; + + return ret; } /* MTDS : Dynamic SAR Power Table */ static int mt792x_asar_acpi_read_mtds(struct mt792x_dev *dev, u8 **table, u8 version) { int len, ret, sarlen, prelen, tblcnt; bool enable; ret = mt792x_acpi_read(dev, MT792x_ACPI_MTDS, table, &len); if (ret) return ret; /* Table content validation */ switch (version) { case 1: enable = ((struct mt792x_asar_dyn *)*table)->enable; sarlen = sizeof(struct mt792x_asar_dyn_limit); prelen = sizeof(struct mt792x_asar_dyn); break; case 2: enable = ((struct mt792x_asar_dyn_v2 *)*table)->enable; sarlen = sizeof(struct mt792x_asar_dyn_limit_v2); prelen = sizeof(struct mt792x_asar_dyn_v2); break; default: return -EINVAL; } tblcnt = (len - prelen) / sarlen; if (!enable || tblcnt > MT792x_ASAR_MAX_DYN || tblcnt < MT792x_ASAR_MIN_DYN) return -EINVAL; return 0; } /* MTGS : Geo SAR Power Table */ static int mt792x_asar_acpi_read_mtgs(struct mt792x_dev *dev, u8 **table, u8 version) { int len, ret, sarlen, prelen, tblcnt; ret = mt792x_acpi_read(dev, MT792x_ACPI_MTGS, table, &len); if (ret) return ret; /* Table content validation */ switch (version) { case 1: sarlen = sizeof(struct mt792x_asar_geo_limit); prelen = sizeof(struct mt792x_asar_geo); break; case 2: sarlen = sizeof(struct mt792x_asar_geo_limit_v2); prelen = sizeof(struct mt792x_asar_geo_v2); break; default: return -EINVAL; } tblcnt = (len - prelen) / sarlen; if (tblcnt > MT792x_ASAR_MAX_GEO || tblcnt < MT792x_ASAR_MIN_GEO) return -EINVAL; return 0; } /* MTFG : Flag Table */ static int mt792x_asar_acpi_read_mtfg(struct mt792x_dev *dev, u8 **table) { int len, ret; ret = mt792x_acpi_read(dev, MT792x_ACPI_MTFG, table, &len); if (ret) return ret; if (len < MT792x_ASAR_MIN_FG) return -EINVAL; return 0; } int mt792x_init_acpi_sar(struct mt792x_dev *dev) { struct mt792x_acpi_sar *asar; int ret; asar = devm_kzalloc(dev->mt76.dev, sizeof(*asar), GFP_KERNEL); if (!asar) return -ENOMEM; - mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + ret = mt792x_asar_acpi_read_mtcl(dev, (u8 **)&asar->countrylist, &asar->ver); + if (ret) { + devm_kfree(dev->mt76.dev, asar->countrylist); + asar->countrylist = NULL; + } - /* MTDS is mandatory. Return error if table is invalid */ ret = mt792x_asar_acpi_read_mtds(dev, (u8 **)&asar->dyn, asar->ver); if (ret) { devm_kfree(dev->mt76.dev, asar->dyn); - devm_kfree(dev->mt76.dev, asar->countrylist); - devm_kfree(dev->mt76.dev, asar); - - return ret; + asar->dyn = NULL; } /* MTGS is optional */ ret = mt792x_asar_acpi_read_mtgs(dev, (u8 **)&asar->geo, asar->ver); if (ret) { devm_kfree(dev->mt76.dev, asar->geo); asar->geo = NULL; } /* MTFG is optional */ ret = mt792x_asar_acpi_read_mtfg(dev, (u8 **)&asar->fg); if (ret) { devm_kfree(dev->mt76.dev, asar->fg); asar->fg = NULL; } dev->phy.acpisar = asar; return 0; } EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar); static s8 mt792x_asar_get_geo_pwr(struct mt792x_phy *phy, enum nl80211_band band, s8 dyn_power) { struct mt792x_acpi_sar *asar = phy->acpisar; struct mt792x_asar_geo_band *band_pwr; s8 geo_power; u8 idx, max; if (!asar->geo) return dyn_power; switch (phy->mt76->dev->region) { case NL80211_DFS_FCC: idx = 0; break; case NL80211_DFS_ETSI: idx = 1; break; default: /* WW */ idx = 2; break; } if (asar->ver == 1) { band_pwr = &asar->geo->tbl[idx].band[0]; max = ARRAY_SIZE(asar->geo->tbl[idx].band); } else { band_pwr = &asar->geo_v2->tbl[idx].band[0]; max = ARRAY_SIZE(asar->geo_v2->tbl[idx].band); } switch (band) { case NL80211_BAND_2GHZ: idx = 0; break; case NL80211_BAND_5GHZ: idx = 1; break; case NL80211_BAND_6GHZ: idx = 2; break; default: return dyn_power; } if (idx >= max) return dyn_power; geo_power = (band_pwr + idx)->pwr; dyn_power += (band_pwr + idx)->offset; return min(geo_power, dyn_power); } static s8 mt792x_asar_range_pwr(struct mt792x_phy *phy, const struct cfg80211_sar_freq_ranges *range, u8 idx) { const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; struct mt792x_acpi_sar *asar = phy->acpisar; u8 *limit, band, max; if (!capa) return 127; if (asar->ver == 1) { limit = &asar->dyn->tbl[0].frp[0]; max = ARRAY_SIZE(asar->dyn->tbl[0].frp); } else { limit = &asar->dyn_v2->tbl[0].frp[0]; max = ARRAY_SIZE(asar->dyn_v2->tbl[0].frp); } if (idx >= max) return 127; if (range->start_freq >= 5945) band = NL80211_BAND_6GHZ; else if (range->start_freq >= 5150) band = NL80211_BAND_5GHZ; else band = NL80211_BAND_2GHZ; return mt792x_asar_get_geo_pwr(phy, band, limit[idx]); } int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) { const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; int i; - if (!phy->acpisar) + if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn) return 0; /* When ACPI SAR enabled in HW, we should apply rules for .frp * 1. w/o .sar_specs : set ACPI SAR power as the defatul value * 2. w/ .sar_specs : set power with min(.sar_specs, ACPI_SAR) */ for (i = 0; i < capa->num_freq_ranges; i++) { struct mt76_freq_range_power *frp = &phy->mt76->frp[i]; frp->range = set_default ? &capa->freq_ranges[i] : frp->range; if (!frp->range) continue; frp->power = min_t(s8, set_default ? 127 : frp->power, mt792x_asar_range_pwr(phy, frp->range, i)); } return 0; } EXPORT_SYMBOL_GPL(mt792x_init_acpi_sar_power); u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) { struct mt792x_acpi_sar *acpisar = phy->acpisar; struct mt792x_asar_fg *fg; struct { u8 acpi_idx; u8 chip_idx; } map[] = { { 1, 1 }, { 4, 2 }, }; u8 flags = BIT(0); int i, j; if (!acpisar) return 0; fg = acpisar->fg; if (!fg) return flags; /* pickup necessary settings per device and * translate the index of bitmap for chip command. */ for (i = 0; i < fg->nr_flag; i++) { for (j = 0; j < ARRAY_SIZE(map); j++) { if (fg->flag[i] == map[j].acpi_idx) { flags |= BIT(map[j].chip_idx); break; } } } return flags; } EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags); + +static u8 +mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) +{ + u8 config = 0; + u8 mode_6g, mode_5g9; + + mode_6g = (cl->mode_6g > 0x02) ? 0 : cl->mode_6g; + mode_5g9 = (cl->mode_5g9 > 0x01) ? 0 : cl->mode_5g9; + + if ((cl->cl6g[row] & BIT(column)) || cl->mode_6g == 0x02) + config |= (mode_6g & 0x3) << 2; + if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) + config |= (mode_5g9 & 0x3); + + return config; +} + +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + static const char * const cc_list_all[] = { + "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR", + "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME", + "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR", + "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY", + }; + static const char * const cc_list_eu[] = { + "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", + "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", + "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", + "PT", "RO", "SK", "SI", "ES", "SE", "CH", + }; + struct mt792x_acpi_sar *sar = phy->acpisar; + struct mt792x_asar_cl *cl; + int col, row, i; + + if (!sar) + return 0xf; + + cl = sar->countrylist; + if (!cl) + return 0xc; + + for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) { + col = 7 - i % 8; + row = i / 8; + if (!memcmp(cc_list_all[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(row, col, cl); + } + + for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) + if (!memcmp(cc_list_eu[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(0, 6, cl); + + return mt792x_acpi_get_mtcl_map(0, 7, cl); +} +EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf); diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.h b/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.h index d6d332e863ba..2298983b6342 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.h +++ b/sys/contrib/dev/mediatek/mt76/mt792x_acpi_sar.h @@ -1,105 +1,107 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT7921_ACPI_SAR_H #define __MT7921_ACPI_SAR_H #define MT792x_ASAR_MIN_DYN 1 #define MT792x_ASAR_MAX_DYN 8 #define MT792x_ASAR_MIN_GEO 3 #define MT792x_ASAR_MAX_GEO 8 #define MT792x_ASAR_MIN_FG 8 #define MT792x_ACPI_MTCL "MTCL" #define MT792x_ACPI_MTDS "MTDS" #define MT792x_ACPI_MTGS "MTGS" #define MT792x_ACPI_MTFG "MTFG" struct mt792x_asar_dyn_limit { u8 idx; u8 frp[5]; } __packed; struct mt792x_asar_dyn { u8 names[4]; u8 enable; u8 nr_tbl; DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit, tbl); } __packed; struct mt792x_asar_dyn_limit_v2 { u8 idx; u8 frp[11]; } __packed; struct mt792x_asar_dyn_v2 { u8 names[4]; u8 enable; u8 rsvd; u8 nr_tbl; DECLARE_FLEX_ARRAY(struct mt792x_asar_dyn_limit_v2, tbl); } __packed; struct mt792x_asar_geo_band { u8 pwr; u8 offset; } __packed; struct mt792x_asar_geo_limit { u8 idx; /* 0:2G, 1:5G */ struct mt792x_asar_geo_band band[2]; } __packed; struct mt792x_asar_geo { u8 names[4]; u8 version; u8 nr_tbl; DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit, tbl); } __packed; struct mt792x_asar_geo_limit_v2 { u8 idx; /* 0:2G, 1:5G, 2:6G */ struct mt792x_asar_geo_band band[3]; } __packed; struct mt792x_asar_geo_v2 { u8 names[4]; u8 version; u8 rsvd; u8 nr_tbl; DECLARE_FLEX_ARRAY(struct mt792x_asar_geo_limit_v2, tbl); } __packed; struct mt792x_asar_cl { u8 names[4]; u8 version; u8 mode_6g; u8 cl6g[6]; + u8 mode_5g9; + u8 cl5g9[6]; } __packed; struct mt792x_asar_fg { u8 names[4]; u8 version; u8 rsvd; u8 nr_flag; u8 rsvd1; u8 flag[]; } __packed; struct mt792x_acpi_sar { u8 ver; union { struct mt792x_asar_dyn *dyn; struct mt792x_asar_dyn_v2 *dyn_v2; }; union { struct mt792x_asar_geo *geo; struct mt792x_asar_geo_v2 *geo_v2; }; struct mt792x_asar_cl *countrylist; struct mt792x_asar_fg *fg; }; #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_core.c b/sys/contrib/dev/mediatek/mt76/mt792x_core.c index 950d43d54baf..c42d1105e5a1 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_core.c +++ b/sys/contrib/dev/mediatek/mt76/mt792x_core.c @@ -1,862 +1,979 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. */ #include #include +#if defined(__FreeBSD__) +#include +#endif #include "mt792x.h" #include "dma.h" static const struct ieee80211_iface_limit if_limits[] = { { .max = MT792x_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_STATION) }, { .max = 1, .types = BIT(NL80211_IFTYPE_AP) } }; static const struct ieee80211_iface_combination if_comb[] = { { .limits = if_limits, .n_limits = ARRAY_SIZE(if_limits), .max_interfaces = MT792x_MAX_INTERFACES, .num_different_channels = 1, .beacon_int_infra_match = true, }, }; static const struct ieee80211_iface_limit if_limits_chanctx[] = { { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) }, { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) } }; static const struct ieee80211_iface_combination if_comb_chanctx[] = { { .limits = if_limits_chanctx, .n_limits = ARRAY_SIZE(if_limits_chanctx), - .max_interfaces = 2, + .max_interfaces = 3, .num_different_channels = 2, .beacon_int_infra_match = false, } }; void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + u8 link_id; int qid; if (control->sta) { + struct mt792x_link_sta *mlink; struct mt792x_sta *sta; - + link_id = u32_get_bits(info->control.flags, + IEEE80211_TX_CTRL_MLO_LINK); sta = (struct mt792x_sta *)control->sta->drv_priv; - wcid = &sta->wcid; + mlink = mt792x_sta_to_link(sta, link_id); + wcid = &mlink->wcid; } if (vif && !control->sta) { struct mt792x_vif *mvif; mvif = (struct mt792x_vif *)vif->drv_priv; - wcid = &mvif->sta.wcid; + wcid = &mvif->sta.deflink.wcid; + } + + if (vif && control->sta && ieee80211_vif_is_mld(vif)) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_link_sta *link_sta; + struct ieee80211_bss_conf *conf; + + link_id = wcid->link_id; + rcu_read_lock(); + conf = rcu_dereference(vif->link_conf[link_id]); + memcpy(hdr->addr2, conf->addr, ETH_ALEN); + + link_sta = rcu_dereference(control->sta->link[link_id]); + memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); + + if (vif->type == NL80211_IFTYPE_STATION) + memcpy(hdr->addr3, conf->bssid, ETH_ALEN); + rcu_read_unlock(); } if (mt76_connac_pm_ref(mphy, &dev->pm)) { mt76_tx(mphy, control->sta, wcid, skb); mt76_connac_pm_unref(mphy, &dev->pm); return; } qid = skb_get_queue_mapping(skb); if (qid >= MT_TXQ_PSD) { qid = IEEE80211_AC_BE; skb_set_queue_mapping(skb, qid); } mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); } EXPORT_SYMBOL_GPL(mt792x_tx); -void mt792x_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void mt792x_stop(struct ieee80211_hw *hw, bool suspend) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt792x_sta *msta = &mvif->sta; struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); - int idx = msta->wcid.idx; - mt792x_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); + cancel_delayed_work_sync(&phy->mt76->mac_work); + + cancel_delayed_work_sync(&dev->pm.ps_work); + cancel_work_sync(&dev->pm.wake_work); + cancel_work_sync(&dev->reset_work); + mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + if (is_mt7921(&dev->mt76)) { + mt792x_mutex_acquire(dev); + mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); + mt792x_mutex_release(dev); + } + + clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); +} +EXPORT_SYMBOL_GPL(mt792x_stop); + +void mt792x_mac_link_bss_remove(struct mt792x_dev *dev, + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink) +{ + struct ieee80211_vif *vif = container_of((void *)mconf->vif, + struct ieee80211_vif, drv_priv); + struct ieee80211_bss_conf *link_conf; + int idx = mlink->wcid.idx; + + link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); + + mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); + mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf, &mconf->mt76, + &mlink->wcid, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); - phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); - mt792x_mutex_release(dev); + dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx); + mconf->vif->phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx); spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta->wcid.poll_list)) - list_del_init(&msta->wcid.poll_list); + if (!list_empty(&mlink->wcid.poll_list)) + list_del_init(&mlink->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - mt76_packet_id_flush(&dev->mt76, &msta->wcid); + mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); +} +EXPORT_SYMBOL_GPL(mt792x_mac_link_bss_remove); + +void mt792x_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; + + mt792x_mutex_acquire(dev); + + mconf = mt792x_link_conf_to_mconf(&vif->bss_conf); + mt792x_mac_link_bss_remove(dev, mconf, &mvif->sta.deflink); + + mt792x_mutex_release(dev); } EXPORT_SYMBOL_GPL(mt792x_remove_interface); int mt792x_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; /* no need to update right away, we'll get BSS_CHANGED_QOS */ queue = mt76_connac_lmac_mapping(queue); - mvif->queue_params[queue] = *params; + mvif->bss_conf.queue_params[queue] = *params; return 0; } EXPORT_SYMBOL_GPL(mt792x_conf_tx); int mt792x_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt76_mib_stats *mib = &phy->mib; mt792x_mutex_acquire(phy->dev); stats->dot11RTSSuccessCount = mib->rts_cnt; stats->dot11RTSFailureCount = mib->rts_retries_cnt; stats->dot11FCSErrorCount = mib->fcs_err_cnt; stats->dot11ACKFailureCount = mib->ack_fail_cnt; mt792x_mutex_release(phy->dev); return 0; } EXPORT_SYMBOL_GPL(mt792x_get_stats); u64 mt792x_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); - u8 omac_idx = mvif->mt76.omac_idx; + u8 omac_idx = mvif->bss_conf.mt76.omac_idx; union { u64 t64; u32 t32[2]; } tsf; u16 n; mt792x_mutex_acquire(dev); n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; /* TSF software read */ mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_MODE); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(0)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(0)); mt792x_mutex_release(dev); return tsf.t64; } EXPORT_SYMBOL_GPL(mt792x_get_tsf); void mt792x_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 timestamp) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); - u8 omac_idx = mvif->mt76.omac_idx; + u8 omac_idx = mvif->bss_conf.mt76.omac_idx; union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; mt792x_mutex_acquire(dev); n = omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : omac_idx; mt76_wr(dev, MT_LPON_UTTR0(0), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(0), tsf.t32[1]); /* TSF software overwrite */ mt76_set(dev, MT_LPON_TCR(0, n), MT_LPON_TCR_SW_WRITE); mt792x_mutex_release(dev); } EXPORT_SYMBOL_GPL(mt792x_set_tsf); void mt792x_tx_worker(struct mt76_worker *w) { struct mt792x_dev *dev = container_of(w, struct mt792x_dev, mt76.tx_worker); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { queue_work(dev->mt76.wq, &dev->pm.wake_work); return; } mt76_txq_schedule_all(&dev->mphy); mt76_connac_pm_unref(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt792x_tx_worker); void mt792x_roc_timer(struct timer_list *timer) { struct mt792x_phy *phy = from_timer(phy, timer, roc_timer); ieee80211_queue_work(phy->mt76->hw, &phy->roc_work); } EXPORT_SYMBOL_GPL(mt792x_roc_timer); +void mt792x_csa_timer(struct timer_list *timer) +{ + struct mt792x_vif *mvif = from_timer(mvif, timer, csa_timer); + + ieee80211_queue_work(mvif->phy->mt76->hw, &mvif->csa_work); +} +EXPORT_SYMBOL_GPL(mt792x_csa_timer); + void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { struct mt792x_dev *dev = mt792x_hw_dev(hw); wait_event_timeout(dev->mt76.tx_wait, !mt76_has_tx_pending(&dev->mphy), HZ / 2); } EXPORT_SYMBOL_GPL(mt792x_flush); int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mvif->ctx = ctx; + mvif->bss_conf.mt76.ctx = ctx; + mctx->bss_conf = &mvif->bss_conf; mutex_unlock(&dev->mt76.mutex); return 0; } EXPORT_SYMBOL_GPL(mt792x_assign_vif_chanctx); void mt792x_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_chanctx *mctx = (struct mt792x_chanctx *)ctx->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_dev *dev = mt792x_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mvif->ctx = NULL; + mctx->bss_conf = NULL; + mvif->bss_conf.mt76.ctx = NULL; mutex_unlock(&dev->mt76.mutex); + + if (vif->bss_conf.csa_active) { + del_timer_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); + } } EXPORT_SYMBOL_GPL(mt792x_unassign_vif_chanctx); void mt792x_set_wakeup(struct ieee80211_hw *hw, bool enabled) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_dev *mdev = &dev->mt76; device_set_wakeup_enable(mdev->dev, enabled); } EXPORT_SYMBOL_GPL(mt792x_set_wakeup); static const char mt792x_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_mode_eht_su", "v_tx_mode_eht_trig", "v_tx_mode_eht_mu", "v_tx_bw_20", "v_tx_bw_40", "v_tx_bw_80", "v_tx_bw_160", + "v_tx_bw_320", "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", "v_tx_mcs_12", "v_tx_mcs_13", "v_tx_nss_1", "v_tx_nss_2", "v_tx_nss_3", "v_tx_nss_4", }; void mt792x_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data) { if (sset != ETH_SS_STATS) return; - memcpy(data, *mt792x_gstrings_stats, sizeof(mt792x_gstrings_stats)); + memcpy(data, mt792x_gstrings_stats, sizeof(mt792x_gstrings_stats)); data += sizeof(mt792x_gstrings_stats); page_pool_ethtool_stats_get_strings(data); } EXPORT_SYMBOL_GPL(mt792x_get_et_strings); int mt792x_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int sset) { if (sset != ETH_SS_STATS) return 0; return ARRAY_SIZE(mt792x_gstrings_stats) + page_pool_ethtool_stats_get_count(); } EXPORT_SYMBOL_GPL(mt792x_get_et_sset_count); static void mt792x_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt76_ethtool_worker_info *wi = wi_data; - if (msta->vif->mt76.idx != wi->idx) + if (msta->vif->bss_conf.mt76.idx != wi->idx) return; - mt76_ethtool_worker(wi, &msta->wcid.stats, true); + mt76_ethtool_worker(wi, &msta->deflink.wcid.stats, true); } void mt792x_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; int stats_size = ARRAY_SIZE(mt792x_gstrings_stats); struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = phy->dev; struct mt76_mib_stats *mib = &phy->mib; struct mt76_ethtool_worker_info wi = { .data = data, - .idx = mvif->mt76.idx, + .idx = mvif->bss_conf.mt76.idx, }; int i, ei = 0; mt792x_mutex_acquire(dev); mt792x_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++] = phy->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, mt792x_ethtool_worker, &wi); mt792x_mutex_release(dev); if (!wi.sta_count) return; ei += wi.worker_stat_count; mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei); stats_size += page_pool_ethtool_stats_get_count(); if (ei != stats_size) dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %d", ei, stats_size); } EXPORT_SYMBOL_GPL(mt792x_get_et_stats); void mt792x_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - struct rate_info *txrate = &msta->wcid.rate; + struct rate_info *txrate = &msta->deflink.wcid.rate; if (!txrate->legacy && !txrate->flags) return; if (txrate->legacy) { sinfo->txrate.legacy = txrate->legacy; } else { 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->tx_failed = msta->wcid.stats.tx_failed; + sinfo->tx_failed = msta->deflink.wcid.stats.tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); - sinfo->tx_retries = msta->wcid.stats.tx_retries; + sinfo->tx_retries = msta->deflink.wcid.stats.tx_retries; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); - sinfo->ack_signal = (s8)msta->ack_signal; + sinfo->ack_signal = (s8)msta->deflink.ack_signal; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); - sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); + sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->deflink.avg_ack_signal); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); } EXPORT_SYMBOL_GPL(mt792x_sta_statistics); void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = phy->dev; mt792x_mutex_acquire(dev); phy->coverage_class = max_t(s16, coverage_class, 0); mt792x_mac_set_timeing(phy); mt792x_mutex_release(dev); } EXPORT_SYMBOL_GPL(mt792x_set_coverage_class); int mt792x_init_wiphy(struct ieee80211_hw *hw) { struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = phy->dev; struct wiphy *wiphy = hw->wiphy; hw->queues = 4; if (dev->has_eht) { hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; } else { hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; } hw->netdev_features = NETIF_F_RXCSUM; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; hw->sta_data_size = sizeof(struct mt792x_sta); hw->vif_data_size = sizeof(struct mt792x_vif); + hw->chanctx_data_size = sizeof(struct mt792x_chanctx); if (dev->fw_features & MT792x_FW_CAP_CNM) { wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; wiphy->iface_combinations = if_comb_chanctx; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx); } else { wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP | WIPHY_FLAG_4ADDR_STATION); wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); wiphy->max_remain_on_channel_duration = 5000; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; wiphy->max_sched_scan_plan_interval = MT76_CONNAC_MAX_TIME_SCHED_SCAN_INTERVAL; wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN; wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID; wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH; wiphy->max_sched_scan_reqs = 1; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_SPLIT_SCAN_6GHZ; wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); 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); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); if (dev->pm.enable) ieee80211_hw_set(hw, CONNECTION_MONITOR); hw->max_tx_fragments = 4; return 0; } EXPORT_SYMBOL_GPL(mt792x_init_wiphy); static u8 mt792x_get_offload_capability(struct device *dev, const char *fw_wm) { const struct mt76_connac2_fw_trailer *hdr; #if defined(__lnux__) struct mt792x_realease_info *rel_info; #elif defined(__FreeBSD__) const struct mt792x_realease_info *rel_info; #endif const struct firmware *fw; int ret, i, offset = 0; const u8 *data, *end; u8 offload_caps = 0; ret = request_firmware(&fw, fw_wm, dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev, "Invalid firmware\n"); goto out; } data = fw->data; hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); for (i = 0; i < hdr->n_region; i++) { const struct mt76_connac2_fw_region *region; region = (const void *)((const u8 *)hdr - (hdr->n_region - i) * sizeof(*region)); offset += le32_to_cpu(region->len); } data += offset + 16; #if defined(__linux__) rel_info = (struct mt792x_realease_info *)data; #elif defined(__FreeBSD__) rel_info = (const struct mt792x_realease_info *)data; #endif data += sizeof(*rel_info); end = data + le16_to_cpu(rel_info->len); while (data < end) { #if defined(__linux__) rel_info = (struct mt792x_realease_info *)data; #elif defined(__FreeBSD__) rel_info = (const struct mt792x_realease_info *)data; #endif data += sizeof(*rel_info); if (rel_info->tag == MT792x_FW_TAG_FEATURE) { #if defined(__linux__) struct mt792x_fw_features *features; features = (struct mt792x_fw_features *)data; #elif defined(__FreeBSD__) const struct mt792x_fw_features *features; features = (const struct mt792x_fw_features *)data; #endif offload_caps = features->data; break; } data += le16_to_cpu(rel_info->len) + rel_info->pad_len; } out: release_firmware(fw); return offload_caps; } struct ieee80211_ops * mt792x_get_mac80211_ops(struct device *dev, const struct ieee80211_ops *mac80211_ops, void *drv_data, u8 *fw_features) { struct ieee80211_ops *ops; ops = devm_kmemdup(dev, mac80211_ops, sizeof(struct ieee80211_ops), GFP_KERNEL); if (!ops) return NULL; *fw_features = mt792x_get_offload_capability(dev, drv_data); if (!(*fw_features & MT792x_FW_CAP_CNM)) { ops->remain_on_channel = NULL; ops->cancel_remain_on_channel = NULL; - ops->add_chanctx = NULL; - ops->remove_chanctx = NULL; - ops->change_chanctx = NULL; + ops->add_chanctx = ieee80211_emulate_add_chanctx; + ops->remove_chanctx = ieee80211_emulate_remove_chanctx; + ops->change_chanctx = ieee80211_emulate_change_chanctx; + ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx; ops->assign_vif_chanctx = NULL; ops->unassign_vif_chanctx = NULL; ops->mgd_prepare_tx = NULL; ops->mgd_complete_tx = NULL; } return ops; } EXPORT_SYMBOL_GPL(mt792x_get_mac80211_ops); int mt792x_init_wcid(struct mt792x_dev *dev) { int idx; /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx) return -ENOSPC; dev->mt76.global_wcid.idx = idx; dev->mt76.global_wcid.hw_key_idx = -1; dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); return 0; } EXPORT_SYMBOL_GPL(mt792x_init_wcid); int mt792x_mcu_drv_pmctrl(struct mt792x_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int err = 0; mutex_lock(&pm->mutex); if (!test_bit(MT76_STATE_PM, &mphy->state)) goto out; err = __mt792x_mcu_drv_pmctrl(dev); out: mutex_unlock(&pm->mutex); if (err) mt792x_reset(&dev->mt76); return err; } EXPORT_SYMBOL_GPL(mt792x_mcu_drv_pmctrl); int mt792x_mcu_fw_pmctrl(struct mt792x_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int err = 0; mutex_lock(&pm->mutex); if (mt76_connac_skip_fw_pmctrl(mphy, pm)) goto out; err = __mt792x_mcu_fw_pmctrl(dev); out: mutex_unlock(&pm->mutex); if (err) mt792x_reset(&dev->mt76); return err; } EXPORT_SYMBOL_GPL(mt792x_mcu_fw_pmctrl); int __mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev) { int i, err = 0; for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN); + + if (dev->aspm_supported) + usleep_range(2000, 3000); + if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1)) break; } if (i == MT792x_DRV_OWN_RETRY_COUNT) { dev_err(dev->mt76.dev, "driver own failed\n"); err = -EIO; } return err; } EXPORT_SYMBOL_GPL(__mt792xe_mcu_drv_pmctrl); int mt792xe_mcu_drv_pmctrl(struct mt792x_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int err; err = __mt792xe_mcu_drv_pmctrl(dev); if (err < 0) goto out; mt792x_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; } EXPORT_SYMBOL_GPL(mt792xe_mcu_drv_pmctrl); int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_connac_pm *pm = &dev->pm; int i; for (i = 0; i < MT792x_DRV_OWN_RETRY_COUNT; i++) { mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN); if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_OWN_SYNC, 4, 50, 1)) break; } if (i == MT792x_DRV_OWN_RETRY_COUNT) { dev_err(dev->mt76.dev, "firmware own failed\n"); clear_bit(MT76_STATE_PM, &mphy->state); return -EIO; } pm->stats.last_doze_event = jiffies; pm->stats.awake_time += pm->stats.last_doze_event - pm->stats.last_wake_event; return 0; } EXPORT_SYMBOL_GPL(mt792xe_mcu_fw_pmctrl); int mt792x_load_firmware(struct mt792x_dev *dev) { int ret; ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); if (ret) return ret; if (mt76_is_sdio(&dev->mt76)) { /* activate again */ ret = __mt792x_mcu_fw_pmctrl(dev); if (!ret) ret = __mt792x_mcu_drv_pmctrl(dev); } ret = mt76_connac2_load_ram(&dev->mt76, mt792x_ram_name(dev), NULL); if (ret) return ret; if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY, MT_TOP_MISC2_FW_N9_RDY, 1500)) { dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } #ifdef CONFIG_PM dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support; #endif /* CONFIG_PM */ dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; } EXPORT_SYMBOL_GPL(mt792x_load_firmware); +void mt792x_config_mac_addr_list(struct mt792x_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { + u8 *addr = dev->macaddr_list[i].addr; + + memcpy(addr, dev->mphy.macaddr, ETH_ALEN); + + if (!i) + continue; + + addr[0] |= BIT(1); + addr[0] ^= ((i - 1) << 2); + } + wiphy->addresses = dev->macaddr_list; + wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); +} +EXPORT_SYMBOL_GPL(mt792x_config_mac_addr_list); + +MODULE_DESCRIPTION("MediaTek MT792x core driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Lorenzo Bianconi "); diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_dma.c b/sys/contrib/dev/mediatek/mt76/mt792x_dma.c index c39257956ce0..d68f814b3581 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_dma.c +++ b/sys/contrib/dev/mediatek/mt76/mt792x_dma.c @@ -1,347 +1,375 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. */ #include #include #if defined(__FreeBSD__) #include #endif #include "mt792x.h" #include "dma.h" #include "trace.h" irqreturn_t mt792x_irq_handler(int irq, void *dev_instance) { struct mt792x_dev *dev = dev_instance; + if (test_bit(MT76_REMOVED, &dev->mt76.phy.state)) + return IRQ_NONE; mt76_wr(dev, dev->irq_map->host_irq_enable, 0); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; tasklet_schedule(&dev->mt76.irq_tasklet); return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(mt792x_irq_handler); void mt792x_irq_tasklet(unsigned long data) { struct mt792x_dev *dev = (struct mt792x_dev *)data; const struct mt792x_irq_map *irq_map = dev->irq_map; u32 intr, mask = 0; mt76_wr(dev, irq_map->host_irq_enable, 0); intr = mt76_rr(dev, MT_WFDMA0_HOST_INT_STA); intr &= dev->mt76.mmio.irqmask; mt76_wr(dev, MT_WFDMA0_HOST_INT_STA, intr); trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask |= intr & (irq_map->rx.data_complete_mask | irq_map->rx.wm_complete_mask | irq_map->rx.wm2_complete_mask); if (intr & dev->irq_map->tx.mcu_complete_mask) mask |= dev->irq_map->tx.mcu_complete_mask; if (intr & MT_INT_MCU_CMD) { u32 intr_sw; intr_sw = mt76_rr(dev, MT_MCU_CMD); /* ack MCU2HOST_SW_INT_STA */ mt76_wr(dev, MT_MCU_CMD, intr_sw); if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) { mask |= irq_map->rx.data_complete_mask; intr |= irq_map->rx.data_complete_mask; } } mt76_set_irq_mask(&dev->mt76, irq_map->host_irq_enable, mask, 0); if (intr & dev->irq_map->tx.all_complete_mask) napi_schedule(&dev->mt76.tx_napi); if (intr & irq_map->rx.wm_complete_mask) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]); if (intr & irq_map->rx.wm2_complete_mask) napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]); if (intr & irq_map->rx.data_complete_mask) napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]); } EXPORT_SYMBOL_GPL(mt792x_irq_tasklet); void mt792x_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); const struct mt792x_irq_map *irq_map = dev->irq_map; if (q == MT_RXQ_MAIN) mt76_connac_irq_enable(mdev, irq_map->rx.data_complete_mask); else if (q == MT_RXQ_MCU_WA) mt76_connac_irq_enable(mdev, irq_map->rx.wm2_complete_mask); else mt76_connac_irq_enable(mdev, irq_map->rx.wm_complete_mask); } EXPORT_SYMBOL_GPL(mt792x_rx_poll_complete); #define PREFETCH(base, depth) ((base) << 16 | (depth)) static void mt792x_dma_prefetch(struct mt792x_dev *dev) { - mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0xc0, 0x4)); - mt76_wr(dev, MT_WFDMA0_RX_RING5_EXT_CTRL, PREFETCH(0x100, 0x4)); - - mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x140, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x180, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x1c0, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x200, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x240, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x280, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x2c0, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x340, 0x4)); - mt76_wr(dev, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4)); + if (is_mt7925(&dev->mt76)) { + /* rx ring */ + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4)); + /* tx ring */ + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0200, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0300, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4)); + } else { + /* rx ring */ + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x40, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x80, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0xc0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING5_EXT_CTRL, PREFETCH(0x100, 0x4)); + /* tx ring */ + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x140, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x180, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x1c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x200, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x240, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x280, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x2c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x340, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING17_EXT_CTRL, PREFETCH(0x380, 0x4)); + } } int mt792x_dma_enable(struct mt792x_dev *dev) { /* configure perfetch settings */ mt792x_dma_prefetch(dev); /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); + if (is_mt7925(&dev->mt76)) + mt76_wr(dev, MT_WFDMA0_RST_DRX_PTR, ~0); /* configure delay interrupt */ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_WB_DDONE | MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 3) | + MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | + MT_WFDMA0_GLO_CFG_RX_WB_DDONE | MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); + if (is_mt7925(&dev->mt76)) { + mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28)); + mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00); + mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00); + } mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); /* enable interrupts for TX/RX rings */ mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask | dev->irq_map->rx.data_complete_mask | dev->irq_map->rx.wm2_complete_mask | dev->irq_map->rx.wm_complete_mask | MT_INT_MCU_CMD); mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); return 0; } EXPORT_SYMBOL_GPL(mt792x_dma_enable); static int mt792x_dma_reset(struct mt792x_dev *dev, bool force) { int i, err; err = mt792x_dma_disable(dev, force); if (err) return err; /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) mt76_queue_reset(dev, dev->mphy.q_tx[i]); for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_reset(dev, &dev->mt76.q_rx[i]); mt76_tx_status_check(&dev->mt76, true); return mt792x_dma_enable(dev); } int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force) { int i, err; /* clean up hw queues */ for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++) mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); if (force) { err = mt792x_wfsys_reset(dev); if (err) return err; } err = mt792x_dma_reset(dev, force); if (err) return err; mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); return 0; } EXPORT_SYMBOL_GPL(mt792x_wpdma_reset); int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev) { struct mt76_connac_pm *pm = &dev->pm; int err; /* check if the wpdma must be reinitialized */ if (mt792x_dma_need_reinit(dev)) { /* disable interrutpts */ mt76_wr(dev, dev->irq_map->host_irq_enable, 0); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); err = mt792x_wpdma_reset(dev, false); if (err) { dev_err(dev->mt76.dev, "wpdma reset failed\n"); return err; } /* enable interrutpts */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); pm->stats.lp_wake++; } return 0; } EXPORT_SYMBOL_GPL(mt792x_wpdma_reinit_cond); int mt792x_dma_disable(struct mt792x_dev *dev, bool force) { /* disable WFDMA0 */ mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (!mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1)) return -ETIMEDOUT; /* disable dmashdl */ mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0, MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); if (force) { /* reset */ mt76_clear(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); } return 0; } EXPORT_SYMBOL_GPL(mt792x_dma_disable); void mt792x_dma_cleanup(struct mt792x_dev *dev) { /* disable */ mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1); /* reset */ mt76_clear(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_dma_cleanup(&dev->mt76); } EXPORT_SYMBOL_GPL(mt792x_dma_cleanup); int mt792x_poll_tx(struct napi_struct *napi, int budget) { struct mt792x_dev *dev; dev = container_of(napi, struct mt792x_dev, mt76.tx_napi); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { napi_complete(napi); queue_work(dev->mt76.wq, &dev->pm.wake_work); return 0; } mt76_connac_tx_cleanup(&dev->mt76); if (napi_complete(napi)) mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask); mt76_connac_pm_unref(&dev->mphy, &dev->pm); return 0; } EXPORT_SYMBOL_GPL(mt792x_poll_tx); int mt792x_poll_rx(struct napi_struct *napi, int budget) { struct mt792x_dev *dev; int done; - dev = container_of(napi->dev, struct mt792x_dev, mt76.napi_dev); + dev = mt76_priv(napi->dev); if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) { napi_complete(napi); queue_work(dev->mt76.wq, &dev->pm.wake_work); return 0; } done = mt76_dma_rx_poll(napi, budget); mt76_connac_pm_unref(&dev->mphy, &dev->pm); return done; } EXPORT_SYMBOL_GPL(mt792x_poll_rx); int mt792x_wfsys_reset(struct mt792x_dev *dev) { u32 addr = is_mt7921(&dev->mt76) ? 0x18000140 : 0x7c000140; mt76_clear(dev, addr, WFSYS_SW_RST_B); msleep(50); mt76_set(dev, addr, WFSYS_SW_RST_B); if (!__mt76_poll_msec(&dev->mt76, addr, WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500)) return -ETIMEDOUT; return 0; } EXPORT_SYMBOL_GPL(mt792x_wfsys_reset); diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_mac.c b/sys/contrib/dev/mediatek/mt76/mt792x_mac.c index f7ca340d7436..d60b4124d71a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt792x_mac.c @@ -1,388 +1,390 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. */ #include #if defined(__FreeBSD__) #include #endif #include "mt792x.h" #include "mt792x_regs.h" void mt792x_mac_work(struct work_struct *work) { struct mt792x_phy *phy; struct mt76_phy *mphy; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); phy = mphy->priv; mt792x_mutex_acquire(phy->dev); mt76_update_survey(mphy); if (++mphy->mac_work_count == 2) { mphy->mac_work_count = 0; mt792x_mac_update_mib_stats(phy); } mt792x_mutex_release(phy->dev); mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work, MT792x_WATCHDOG_TIME); } EXPORT_SYMBOL_GPL(mt792x_mac_work); void mt792x_mac_set_timeing(struct mt792x_phy *phy) { s16 coverage_class = phy->coverage_class; struct mt792x_dev *dev = phy->dev; u32 val, reg_offset; u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ; int sifs = is_2ghz ? 10 : 16, offset; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; mt76_set(dev, MT_ARB_SCR(0), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); udelay(1); offset = 3 * coverage_class; reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); mt76_wr(dev, MT_TMAC_CDTR(0), cck + reg_offset); mt76_wr(dev, MT_TMAC_ODTR(0), ofdm + reg_offset); mt76_wr(dev, MT_TMAC_ICR0(0), FIELD_PREP(MT_IFS_EIFS, 360) | FIELD_PREP(MT_IFS_RIFS, 2) | FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); if (phy->slottime < 20 || !is_2ghz) val = MT792x_CFEND_RATE_DEFAULT; else val = MT792x_CFEND_RATE_11B; mt76_rmw_field(dev, MT_AGG_ACR0(0), MT_AGG_ACR_CFEND_RATE, val); mt76_clear(dev, MT_ARB_SCR(0), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); } EXPORT_SYMBOL_GPL(mt792x_mac_set_timeing); void mt792x_mac_update_mib_stats(struct mt792x_phy *phy) { struct mt76_mib_stats *mib = &phy->mib; struct mt792x_dev *dev = phy->dev; int i, aggr0 = 0, aggr1; u32 val; mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(0), MT_MIB_SDR3_FCS_ERR_MASK); mib->ack_fail_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR3(0), MT_MIB_ACK_FAIL_COUNT_MASK); mib->ba_miss_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR2(0), MT_MIB_BA_FAIL_COUNT_MASK); mib->rts_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR0(0), MT_MIB_RTS_COUNT_MASK); mib->rts_retries_cnt += mt76_get_field(dev, MT_MIB_MB_BSDR1(0), MT_MIB_RTS_FAIL_COUNT_MASK); mib->tx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR12(0)); mib->tx_mpdu_attempts_cnt += mt76_rr(dev, MT_MIB_SDR14(0)); mib->tx_mpdu_success_cnt += mt76_rr(dev, MT_MIB_SDR15(0)); val = mt76_rr(dev, MT_MIB_SDR32(0)); mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR9_EBF_CNT_MASK, val); mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR9_IBF_CNT_MASK, val); val = mt76_rr(dev, MT_ETBF_TX_APP_CNT(0)); mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, val); mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, val); val = mt76_rr(dev, MT_ETBF_RX_FB_CNT(0)); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, val); mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, val); mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, val); mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, val); mib->rx_mpdu_cnt += mt76_rr(dev, MT_MIB_SDR5(0)); mib->rx_ampdu_cnt += mt76_rr(dev, MT_MIB_SDR22(0)); mib->rx_ampdu_bytes_cnt += mt76_rr(dev, MT_MIB_SDR23(0)); mib->rx_ba_cnt += mt76_rr(dev, MT_MIB_SDR31(0)); for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) { val = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i)); mib->tx_amsdu[i] += val; mib->tx_amsdu_cnt += val; } for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) { u32 val2; val = mt76_rr(dev, MT_TX_AGG_CNT(0, i)); val2 = mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); phy->mt76->aggr_stats[aggr0++] += val & 0xffff; phy->mt76->aggr_stats[aggr0++] += val >> 16; phy->mt76->aggr_stats[aggr1++] += val2 & 0xffff; phy->mt76->aggr_stats[aggr1++] += val2 >> 16; } } EXPORT_SYMBOL_GPL(mt792x_mac_update_mib_stats); struct mt76_wcid *mt792x_rx_get_wcid(struct mt792x_dev *dev, u16 idx, bool unicast) { + struct mt792x_link_sta *link; struct mt792x_sta *sta; struct mt76_wcid *wcid; if (idx >= ARRAY_SIZE(dev->mt76.wcid)) return NULL; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (unicast || !wcid) return wcid; if (!wcid->sta) return NULL; - sta = container_of(wcid, struct mt792x_sta, wcid); + link = container_of(wcid, struct mt792x_link_sta, wcid); + sta = link->sta; if (!sta->vif) return NULL; - return &sta->vif->sta.wcid; + return &sta->vif->sta.deflink.wcid; } EXPORT_SYMBOL_GPL(mt792x_rx_get_wcid); static void mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct sk_buff *skb = priv; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); if (status->signal > 0) return; if (!ether_addr_equal(vif->addr, hdr->addr1)) return; - ewma_rssi_add(&mvif->rssi, -status->signal); + ewma_rssi_add(&mvif->bss_conf.rssi, -status->signal); } void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb) { struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); if (!ieee80211_is_assoc_resp(hdr->frame_control) && !ieee80211_is_auth(hdr->frame_control)) return; ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt792x_mac_rssi_iter, skb); } EXPORT_SYMBOL_GPL(mt792x_mac_assoc_rssi); void mt792x_mac_reset_counters(struct mt792x_phy *phy) { struct mt792x_dev *dev = phy->dev; int i; for (i = 0; i < 4; i++) { mt76_rr(dev, MT_TX_AGG_CNT(0, i)); mt76_rr(dev, MT_TX_AGG_CNT2(0, i)); } dev->mt76.phy.survey_time = ktime_get_boottime(); memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); /* reset airtime counters */ mt76_rr(dev, MT_MIB_SDR9(0)); mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); } EXPORT_SYMBOL_GPL(mt792x_mac_reset_counters); static u8 mt792x_phy_get_nf(struct mt792x_phy *phy, int idx) { return 0; } static void mt792x_phy_update_channel(struct mt76_phy *mphy, int idx) { struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; struct mt76_channel_state *state; u64 busy_time, tx_time, rx_time, obss_time; int nf; busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx), MT_MIB_SDR9_BUSY_MASK); tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx), MT_MIB_SDR36_TXTIME_MASK); rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx), MT_MIB_SDR37_RXTIME_MASK); obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx), MT_MIB_OBSSTIME_MASK); nf = mt792x_phy_get_nf(phy, idx); if (!phy->noise) phy->noise = nf << 4; else if (nf) phy->noise += nf - (phy->noise >> 4); state = mphy->chan_state; state->cc_busy += busy_time; state->cc_tx += tx_time; state->cc_rx += rx_time + obss_time; state->cc_bss_rx += rx_time; state->noise = -(phy->noise >> 4); } void mt792x_update_channel(struct mt76_phy *mphy) { struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); if (mt76_connac_pm_wake(mphy, &dev->pm)) return; mt792x_phy_update_channel(mphy, 0); /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0(0), MT_WF_RMAC_MIB_RXTIME_CLR); mt76_connac_power_save_sched(mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt792x_update_channel); void mt792x_reset(struct mt76_dev *mdev) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt76_connac_pm *pm = &dev->pm; if (!dev->hw_init_done) return; if (dev->hw_full_reset) return; if (pm->suspended) return; queue_work(dev->mt76.wq, &dev->reset_work); } EXPORT_SYMBOL_GPL(mt792x_reset); void mt792x_mac_init_band(struct mt792x_dev *dev, u8 band) { u32 mask, set; mt76_rmw_field(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); mt76_set(dev, MT_TMAC_CTCR0(band), MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN | MT_TMAC_CTCR0_INS_DDLMT_EN); 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); /* filter out non-resp frames and get instantaneous signal reporting */ mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM; set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); } EXPORT_SYMBOL_GPL(mt792x_mac_init_band); void mt792x_pm_wake_work(struct work_struct *work) { struct mt792x_dev *dev; struct mt76_phy *mphy; dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, pm.wake_work); mphy = dev->phy.mt76; if (!mt792x_mcu_drv_pmctrl(dev)) { struct mt76_dev *mdev = &dev->mt76; int i; if (mt76_is_sdio(mdev)) { mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_worker_schedule(&mdev->sdio.txrx_worker); } else { local_bh_disable(); mt76_for_each_q_rx(mdev, i) napi_schedule(&mdev->napi[i]); local_bh_enable(); mt76_connac_pm_dequeue_skbs(mphy, &dev->pm); mt76_connac_tx_cleanup(mdev); } if (test_bit(MT76_STATE_RUNNING, &mphy->state)) ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT792x_WATCHDOG_TIME); } ieee80211_wake_queues(mphy->hw); wake_up(&dev->pm.wait); } EXPORT_SYMBOL_GPL(mt792x_pm_wake_work); void mt792x_pm_power_save_work(struct work_struct *work) { struct mt792x_dev *dev; unsigned long delta; struct mt76_phy *mphy; dev = (struct mt792x_dev *)container_of(work, struct mt792x_dev, pm.ps_work.work); mphy = dev->phy.mt76; delta = dev->pm.idle_timeout; if (test_bit(MT76_HW_SCANNING, &mphy->state) || test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) || dev->fw_assert) goto out; if (mutex_is_locked(&dev->mt76.mutex)) /* if mt76 mutex is held we should not put the device * to sleep since we are currently accessing device * register map. We need to wait for the next power_save * trigger. */ goto out; if (time_is_after_jiffies(dev->pm.last_activity + delta)) { delta = dev->pm.last_activity + delta - jiffies; goto out; } if (!mt792x_mcu_fw_pmctrl(dev)) { cancel_delayed_work_sync(&mphy->mac_work); return; } out: queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); } EXPORT_SYMBOL_GPL(mt792x_pm_power_save_work); diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_regs.h b/sys/contrib/dev/mediatek/mt76/mt792x_regs.h index a99af23e4b56..458cfd0260b1 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_regs.h +++ b/sys/contrib/dev/mediatek/mt76/mt792x_regs.h @@ -1,479 +1,487 @@ /* SPDX-License-Identifier: ISC */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT792X_REGS_H #define __MT792X_REGS_H /* MCU WFDMA1 */ #define MT_MCU_WFDMA1_BASE 0x3000 #define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs)) #define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108) #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) #define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2) #define MT_MCU_INT_EVENT_RESET_DONE BIT(3) #define MT_PLE_BASE 0x820c0000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) #define MT_PLE_FL_Q0_CTRL MT_PLE(0x3e0) #define MT_PLE_FL_Q1_CTRL MT_PLE(0x3e4) #define MT_PLE_FL_Q2_CTRL MT_PLE(0x3e8) #define MT_PLE_FL_Q3_CTRL MT_PLE(0x3ec) #define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) /* TMAC: band 0(0x21000), band 1(0xa1000) */ #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) #define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25) #define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090) #define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094) #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) #define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) #define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4) #define MT_IFS_EIFS GENMASK(8, 0) #define MT_IFS_RIFS GENMASK(14, 10) #define MT_IFS_SIFS GENMASK(22, 16) #define MT_IFS_SLOT GENMASK(30, 24) #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) #define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18) #define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c) #define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0) #define MT_WF_DMA_BASE(_band) ((_band) ? 0x820f7000 : 0x820e7000) #define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs)) #define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000) #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) /* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */ #define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000) #define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs)) #define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008) #define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30) #define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24) /* LPON: band 0(0x24200), band 1(0xa4200) */ #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) #define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x084) #define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (n) * 4) #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) ? 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, 0x054) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) #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) #define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) #define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_MB_BSDR0(_band) MT_WF_MIB(_band, 0x688) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_BSDR1(_band) MT_WF_MIB(_band, 0x690) #define MT_MIB_RTS_FAIL_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_BSDR2(_band) MT_WF_MIB(_band, 0x518) #define MT_MIB_BA_FAIL_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_BSDR3(_band) MT_WF_MIB(_band, 0x520) #define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(15, 0) #define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4)) #define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0) #define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x7dc + ((n) << 2)) #define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x7ec + ((n) << 2)) #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 0x820d4000 #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) #define MT_WTBL_UPDATE_BUSY BIT(31) #define MT_WTBL_ITCR MT_WTBLON_TOP(0x3b0) #define MT_WTBL_ITCR_WR BIT(16) #define MT_WTBL_ITCR_EXEC BIT(31) #define MT_WTBL_ITDR0 MT_WTBLON_TOP(0x3b8) #define MT_WTBL_ITDR1 MT_WTBLON_TOP(0x3bc) #define MT_WTBL_SPE_IDX_SEL BIT(6) #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 | \ FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) /* AGG: band 0(0x20800), band 1(0xa0800) */ #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) #define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4) #define MT_AGG_PCR0_MM_PROT BIT(0) #define MT_AGG_PCR0_GF_PROT BIT(1) #define MT_AGG_PCR0_BW20_PROT BIT(2) #define MT_AGG_PCR0_BW40_PROT BIT(4) #define MT_AGG_PCR0_BW80_PROT BIT(6) #define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8) #define MT_AGG_PCR0_VHT_PROT BIT(13) #define MT_AGG_PCR0_PTA_WIN_DIS BIT(15) #define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23) #define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0) #define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084) #define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) #define MT_AGG_ACR_BAR_RATE GENMASK(29, 16) #define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098) #define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12) #define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6) #define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7) #define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24) #define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0) #define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4) /* ARB: band 0(0x20c00), band 1(0xa0c00) */ #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) #define MT_ARB_SCR_TX_DISABLE BIT(8) #define MT_ARB_SCR_RX_DISABLE BIT(9) #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) ? 0x820f5000 : 0x820e5000) #define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) #define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) #define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) #define MT_WF_RFCR_DROP_FCSFAIL BIT(1) #define MT_WF_RFCR_DROP_VERSION BIT(3) #define MT_WF_RFCR_DROP_PROBEREQ BIT(4) #define MT_WF_RFCR_DROP_MCAST BIT(5) #define MT_WF_RFCR_DROP_BCAST BIT(6) #define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) #define MT_WF_RFCR_DROP_A3_MAC BIT(8) #define MT_WF_RFCR_DROP_A3_BSSID BIT(9) #define MT_WF_RFCR_DROP_A2_BSSID BIT(10) #define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) #define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) #define MT_WF_RFCR_DROP_CTL_RSV BIT(13) #define MT_WF_RFCR_DROP_CTS BIT(14) #define MT_WF_RFCR_DROP_RTS BIT(15) #define MT_WF_RFCR_DROP_DUPLICATE BIT(16) #define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) #define MT_WF_RFCR_DROP_OTHER_UC BIT(18) #define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) #define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) #define MT_WF_RFCR1_DROP_ACK BIT(4) #define MT_WF_RFCR1_DROP_BF_POLL BIT(5) #define MT_WF_RFCR1_DROP_BA BIT(6) #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) #define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4) #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) #define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) #define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8) #define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) #define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) /* WFDMA0 */ #define MT_WFDMA0_BASE 0xd4000 #define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) #define MT_WFDMA0_RST MT_WFDMA0(0x100) #define MT_WFDMA0_RST_LOGIC_RST BIT(4) #define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) #define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) #define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) #define MT_MCU_CMD MT_WFDMA0(0x1f0) #define MT_MCU_CMD_WAKE_RX_PCIE BIT(0) #define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1) #define MT_MCU_CMD_STOP_DMA BIT(2) #define MT_MCU_CMD_RESET_DONE BIT(3) #define MT_MCU_CMD_RECOVERY_DONE BIT(4) #define MT_MCU_CMD_NORMAL_STATE BIT(5) #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) #define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4) #define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200) #define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */ #define HOST_RX_DONE_INT_STS2 BIT(2) /* Rx data */ #define HOST_RX_DONE_INT_STS4 BIT(22) /* Rx mcu after fw downloaded */ #define HOST_TX_DONE_INT_STS16 BIT(26) #define HOST_TX_DONE_INT_STS17 BIT(27) /* MCU tx done*/ #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY BIT(1) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WFDMA0_GLO_CFG_DMA_SIZE GENMASK(5, 4) #define MT_WFDMA0_GLO_CFG_TX_WB_DDONE BIT(6) #define MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL BIT(9) +#define MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK BIT(11) #define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) +#define MT_WFDMA0_GLO_CFG_RX_WB_DDONE BIT(13) #define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) #define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS BIT(30) #define HOST_RX_DONE_INT_ENA0 BIT(0) #define HOST_RX_DONE_INT_ENA1 BIT(1) #define HOST_RX_DONE_INT_ENA2 BIT(2) #define HOST_RX_DONE_INT_ENA3 BIT(3) #define HOST_TX_DONE_INT_ENA0 BIT(4) #define HOST_TX_DONE_INT_ENA1 BIT(5) #define HOST_TX_DONE_INT_ENA2 BIT(6) #define HOST_TX_DONE_INT_ENA3 BIT(7) #define HOST_TX_DONE_INT_ENA4 BIT(8) #define HOST_TX_DONE_INT_ENA5 BIT(9) #define HOST_TX_DONE_INT_ENA6 BIT(10) #define HOST_TX_DONE_INT_ENA7 BIT(11) #define HOST_RX_COHERENT_EN BIT(20) #define HOST_TX_COHERENT_EN BIT(21) #define MCU2HOST_SW_INT_ENA BIT(29) #define HOST_TX_DONE_INT_ENA18 BIT(30) #define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) #define MT_WFDMA0_RST_DRX_PTR MT_WFDMA0(0x280) +#define MT_WFDMA0_INT_RX_PRI MT_WFDMA0(0x298) +#define MT_WFDMA0_INT_TX_PRI MT_WFDMA0(0x29c) #define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6) #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) #define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600) #define MT_WFDMA0_TX_RING1_EXT_CTRL MT_WFDMA0(0x604) #define MT_WFDMA0_TX_RING2_EXT_CTRL MT_WFDMA0(0x608) #define MT_WFDMA0_TX_RING3_EXT_CTRL MT_WFDMA0(0x60c) #define MT_WFDMA0_TX_RING4_EXT_CTRL MT_WFDMA0(0x610) #define MT_WFDMA0_TX_RING5_EXT_CTRL MT_WFDMA0(0x614) #define MT_WFDMA0_TX_RING6_EXT_CTRL MT_WFDMA0(0x618) #define MT_WFDMA0_TX_RING15_EXT_CTRL MT_WFDMA0(0x63c) #define MT_WFDMA0_TX_RING16_EXT_CTRL MT_WFDMA0(0x640) #define MT_WFDMA0_TX_RING17_EXT_CTRL MT_WFDMA0(0x644) #define MT_WPDMA0_MAX_CNT_MASK GENMASK(7, 0) #define MT_WPDMA0_BASE_PTR_MASK GENMASK(31, 16) #define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680) #define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684) #define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688) #define MT_WFDMA0_RX_RING3_EXT_CTRL MT_WFDMA0(0x68c) #define MT_WFDMA0_RX_RING4_EXT_CTRL MT_WFDMA0(0x690) #define MT_WFDMA0_RX_RING5_EXT_CTRL MT_WFDMA0(0x694) #define MT_WFDMA0_RX_RING6_EXT_CTRL MT_WFDMA0(0x698) #define MT_WFDMA0_RX_RING7_EXT_CTRL MT_WFDMA0(0x69c) #define MT_TX_RING_BASE MT_WFDMA0(0x300) #define MT_RX_EVENT_RING_BASE MT_WFDMA0(0x500) /* WFDMA CSR */ #define MT_WFDMA_EXT_CSR_BASE 0xd7000 #define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) #define MT_SWDEF_BASE 0x41f200 #define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs)) #define MT_SWDEF_MODE MT_SWDEF(0x3c) #define MT_SWDEF_NORMAL_MODE 0 #define MT_SWDEF_ICAP_MODE 1 #define MT_SWDEF_SPECTRUM_MODE 2 #define MT_TOP_BASE 0x18060000 #define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) #define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10) #define MT_TOP_LPCR_HOST_FW_OWN BIT(0) #define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) #define MT_MCU_WPDMA0_BASE 0x54000000 #define MT_MCU_WPDMA0(ofs) (MT_MCU_WPDMA0_BASE + (ofs)) #define MT_WFDMA_DUMMY_CR MT_MCU_WPDMA0(0x120) #define MT_WFDMA_NEED_REINIT BIT(1) #define MT_CBTOP_RGU(ofs) (0x70002000 + (ofs)) #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600) #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0) #define MT_HW_BOUND 0x70010020 #define MT_HW_CHIPID 0x70010200 #define MT_HW_REV 0x70010204 +#define MT_HW_EMI_CTL 0x18011100 +#define MT_HW_EMI_CTL_SLPPROT_EN BIT(1) + #define MT_PCIE_MAC_BASE 0x10000 #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) #define MT_PCIE_MAC_PM MT_PCIE_MAC(0x194) #define MT_PCIE_MAC_PM_L0S_DIS BIT(8) #define MT_DMA_SHDL(ofs) (0x7c026000 + (ofs)) #define MT_DMASHDL_SW_CONTROL MT_DMA_SHDL(0x004) #define MT_DMASHDL_DMASHDL_BYPASS BIT(28) #define MT_DMASHDL_OPTIONAL MT_DMA_SHDL(0x008) #define MT_DMASHDL_PAGE MT_DMA_SHDL(0x00c) #define MT_DMASHDL_GROUP_SEQ_ORDER BIT(16) #define MT_DMASHDL_REFILL MT_DMA_SHDL(0x010) #define MT_DMASHDL_REFILL_MASK GENMASK(31, 16) #define MT_DMASHDL_PKT_MAX_SIZE MT_DMA_SHDL(0x01c) #define MT_DMASHDL_PKT_MAX_SIZE_PLE GENMASK(11, 0) #define MT_DMASHDL_PKT_MAX_SIZE_PSE GENMASK(27, 16) #define MT_DMASHDL_GROUP_QUOTA(_n) MT_DMA_SHDL(0x020 + ((_n) << 2)) #define MT_DMASHDL_GROUP_QUOTA_MIN GENMASK(11, 0) #define MT_DMASHDL_GROUP_QUOTA_MAX GENMASK(27, 16) #define MT_DMASHDL_Q_MAP(_n) MT_DMA_SHDL(0x060 + ((_n) << 2)) #define MT_DMASHDL_Q_MAP_MASK GENMASK(3, 0) #define MT_DMASHDL_Q_MAP_SHIFT(_n) (4 * ((_n) % 8)) #define MT_DMASHDL_SCHED_SET(_n) MT_DMA_SHDL(0x070 + ((_n) << 2)) #define MT_WFDMA_HOST_CONFIG 0x7c027030 #define MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN BIT(6) #define MT_UMAC(ofs) (0x74000000 + (ofs)) #define MT_UDMA_TX_QSEL MT_UMAC(0x008) #define MT_FW_DL_EN BIT(3) #define MT_UDMA_WLCFG_1 MT_UMAC(0x00c) #define MT_WL_RX_AGG_PKT_LMT GENMASK(7, 0) #define MT_WL_TX_TMOUT_LMT GENMASK(27, 8) #define MT_UDMA_WLCFG_0 MT_UMAC(0x18) #define MT_WL_RX_AGG_TO GENMASK(7, 0) #define MT_WL_RX_AGG_LMT GENMASK(15, 8) #define MT_WL_TX_TMOUT_FUNC_EN BIT(16) #define MT_WL_TX_DPH_CHK_EN BIT(17) #define MT_WL_RX_MPSZ_PAD0 BIT(18) #define MT_WL_RX_FLUSH BIT(19) #define MT_TICK_1US_EN BIT(20) #define MT_WL_RX_AGG_EN BIT(21) #define MT_WL_RX_EN BIT(22) #define MT_WL_TX_EN BIT(23) #define MT_WL_RX_BUSY BIT(30) #define MT_WL_TX_BUSY BIT(31) #define MT_UDMA_CONN_INFRA_STATUS MT_UMAC(0xa20) #define MT_UDMA_CONN_WFSYS_INIT_DONE BIT(22) #define MT_UDMA_CONN_INFRA_STATUS_SEL MT_UMAC(0xa24) #define MT_SSUSB_EPCTL_CSR(ofs) (0x74011800 + (ofs)) #define MT_SSUSB_EPCTL_CSR_EP_RST_OPT MT_SSUSB_EPCTL_CSR(0x090) #define MT_UWFDMA0(ofs) (0x7c024000 + (ofs)) #define MT_UWFDMA0_GLO_CFG MT_UWFDMA0(0x208) #define MT_UWFDMA0_GLO_CFG_EXT0 MT_UWFDMA0(0x2b0) #define MT_UWFDMA0_GLO_CFG_EXT1 MT_UWFDMA0(0x2b4) #define MT_UWFDMA0_TX_RING_EXT_CTRL(_n) MT_UWFDMA0(0x600 + ((_n) << 2)) #define MT_CONN_STATUS 0x7c053c10 #define MT_WIFI_PATCH_DL_STATE BIT(0) #define MT_CONN_ON_LPCTL 0x7c060010 #define PCIE_LPCR_HOST_SET_OWN BIT(0) #define PCIE_LPCR_HOST_CLR_OWN BIT(1) #define PCIE_LPCR_HOST_OWN_SYNC BIT(2) #define MT_CONN_ON_MISC 0x7c0600f0 #define MT_TOP_MISC2_FW_PWR_ON BIT(0) #define MT_TOP_MISC2_FW_N9_ON BIT(1) #define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0) #define MT_WF_SW_DEF_CR(ofs) (0x401a00 + (ofs)) #define MT_WF_SW_DEF_CR_USB_MCU_EVENT MT_WF_SW_DEF_CR(0x028) #define MT_WF_SW_SER_TRIGGER_SUSPEND BIT(6) #define MT_WF_SW_SER_DONE_SUSPEND BIT(7) #define WFSYS_SW_RST_B BIT(0) #define WFSYS_SW_INIT_DONE BIT(4) #endif /* __MT792X_REGS_H */ diff --git a/sys/contrib/dev/mediatek/mt76/mt792x_usb.c b/sys/contrib/dev/mediatek/mt76/mt792x_usb.c index 20e7f9c7c88c..76272a03b22e 100644 --- a/sys/contrib/dev/mediatek/mt76/mt792x_usb.c +++ b/sys/contrib/dev/mediatek/mt76/mt792x_usb.c @@ -1,309 +1,317 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2023 MediaTek Inc. * * Author: Lorenzo Bianconi */ #include #include #include #include "mt792x.h" #include "mt76_connac2_mac.h" u32 mt792xu_rr(struct mt76_dev *dev, u32 addr) { u32 ret; mutex_lock(&dev->usb.usb_ctrl_mtx); ret = ___mt76u_rr(dev, MT_VEND_READ_EXT, USB_DIR_IN | MT_USB_TYPE_VENDOR, addr); mutex_unlock(&dev->usb.usb_ctrl_mtx); return ret; } EXPORT_SYMBOL_GPL(mt792xu_rr); void mt792xu_wr(struct mt76_dev *dev, u32 addr, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); ___mt76u_wr(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } EXPORT_SYMBOL_GPL(mt792xu_wr); u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); val |= ___mt76u_rr(dev, MT_VEND_READ_EXT, USB_DIR_IN | MT_USB_TYPE_VENDOR, addr) & ~mask; ___mt76u_wr(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | MT_USB_TYPE_VENDOR, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); return val; } EXPORT_SYMBOL_GPL(mt792xu_rmw); void mt792xu_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { struct mt76_usb *usb = &dev->usb; int ret, i = 0, batch_len; const u8 *val = data; len = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); while (i < len) { batch_len = min_t(int, usb->data_len, len - i); memcpy(usb->data, val + i, batch_len); ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | MT_USB_TYPE_VENDOR, (offset + i) >> 16, offset + i, usb->data, batch_len); if (ret < 0) break; i += batch_len; } mutex_unlock(&usb->usb_ctrl_mtx); } EXPORT_SYMBOL_GPL(mt792xu_copy); int mt792xu_mcu_power_on(struct mt792x_dev *dev) { int ret; ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON, USB_DIR_OUT | MT_USB_TYPE_VENDOR, 0x0, 0x1, NULL, 0); if (ret) return ret; if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_PWR_ON, MT_TOP_MISC2_FW_PWR_ON, 500)) { dev_err(dev->mt76.dev, "Timeout for power on\n"); ret = -EIO; } return ret; } EXPORT_SYMBOL_GPL(mt792xu_mcu_power_on); static void mt792xu_cleanup(struct mt792x_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); mt792xu_wfsys_reset(dev); skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_queues_deinit(&dev->mt76); } static u32 mt792xu_uhw_rr(struct mt76_dev *dev, u32 addr) { u32 ret; mutex_lock(&dev->usb.usb_ctrl_mtx); ret = ___mt76u_rr(dev, MT_VEND_DEV_MODE, USB_DIR_IN | MT_USB_TYPE_UHW_VENDOR, addr); mutex_unlock(&dev->usb.usb_ctrl_mtx); return ret; } static void mt792xu_uhw_wr(struct mt76_dev *dev, u32 addr, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); ___mt76u_wr(dev, MT_VEND_WRITE, USB_DIR_OUT | MT_USB_TYPE_UHW_VENDOR, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } static void mt792xu_dma_prefetch(struct mt792x_dev *dev) { - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(0), - MT_WPDMA0_BASE_PTR_MASK, 0x80); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(1), - MT_WPDMA0_BASE_PTR_MASK, 0xc0); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(2), - MT_WPDMA0_BASE_PTR_MASK, 0x100); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(3), - MT_WPDMA0_BASE_PTR_MASK, 0x140); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(4), - MT_WPDMA0_BASE_PTR_MASK, 0x180); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(16), - MT_WPDMA0_BASE_PTR_MASK, 0x280); - - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17), - MT_WPDMA0_MAX_CNT_MASK, 4); - mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL(17), - MT_WPDMA0_BASE_PTR_MASK, 0x2c0); +#define DMA_PREFETCH_CONF(_idx_, _cnt_, _base_) \ + mt76_rmw(dev, MT_UWFDMA0_TX_RING_EXT_CTRL((_idx_)), \ + MT_WPDMA0_MAX_CNT_MASK | MT_WPDMA0_BASE_PTR_MASK, \ + FIELD_PREP(MT_WPDMA0_MAX_CNT_MASK, (_cnt_)) | \ + FIELD_PREP(MT_WPDMA0_BASE_PTR_MASK, (_base_))) + + DMA_PREFETCH_CONF(0, 4, 0x080); + DMA_PREFETCH_CONF(1, 4, 0x0c0); + DMA_PREFETCH_CONF(2, 4, 0x100); + DMA_PREFETCH_CONF(3, 4, 0x140); + DMA_PREFETCH_CONF(4, 4, 0x180); + DMA_PREFETCH_CONF(16, 4, 0x280); + DMA_PREFETCH_CONF(17, 4, 0x2c0); } static void mt792xu_wfdma_init(struct mt792x_dev *dev) { + int i; + mt792xu_dma_prefetch(dev); mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_OMIT_RX_INFO); mt76_set(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL | MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); - /* disable dmashdl */ - mt76_clear(dev, MT_UWFDMA0_GLO_CFG_EXT0, - MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); - mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); + mt76_rmw(dev, MT_DMASHDL_REFILL, MT_DMASHDL_REFILL_MASK, 0xffe00000); + mt76_clear(dev, MT_DMASHDL_PAGE, MT_DMASHDL_GROUP_SEQ_ORDER); + mt76_rmw(dev, MT_DMASHDL_PKT_MAX_SIZE, + MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 0)); + for (i = 0; i < 5; i++) + mt76_wr(dev, MT_DMASHDL_GROUP_QUOTA(i), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0xfff)); + for (i = 5; i < 16; i++) + mt76_wr(dev, MT_DMASHDL_GROUP_QUOTA(i), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x0) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x0)); + mt76_wr(dev, MT_DMASHDL_Q_MAP(0), 0x32013201); + mt76_wr(dev, MT_DMASHDL_Q_MAP(1), 0x32013201); + mt76_wr(dev, MT_DMASHDL_Q_MAP(2), 0x55555444); + mt76_wr(dev, MT_DMASHDL_Q_MAP(3), 0x55555444); + + mt76_wr(dev, MT_DMASHDL_SCHED_SET(0), 0x76540132); + mt76_wr(dev, MT_DMASHDL_SCHED_SET(1), 0xFEDCBA98); mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT); } static int mt792xu_dma_rx_evt_ep4(struct mt792x_dev *dev) { if (!mt76_poll(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000)) return -ETIMEDOUT; mt76_clear(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN); mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_USB_RXEVT_EP4_EN); mt76_set(dev, MT_UWFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_RX_DMA_EN); return 0; } static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset) { u32 val; /* usb endpoint reset opt * bits[4,9]: out blk ep 4-9 * bits[20,21]: in blk ep 4-5 * bits[22]: in int ep 6 */ val = mt792xu_uhw_rr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT); if (reset) val |= GENMASK(9, 4) | GENMASK(22, 20); else val &= ~(GENMASK(9, 4) | GENMASK(22, 20)); mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val); } int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) { int err; mt792xu_wfdma_init(dev); mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_RX_EN | MT_WL_TX_EN | MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN); mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_TO | MT_WL_RX_AGG_LMT); mt76_clear(dev, MT_UDMA_WLCFG_1, MT_WL_RX_AGG_PKT_LMT); if (resume) return 0; err = mt792xu_dma_rx_evt_ep4(dev); if (err) return err; mt792xu_epctl_rst_opt(dev, false); return 0; } EXPORT_SYMBOL_GPL(mt792xu_dma_init); int mt792xu_wfsys_reset(struct mt792x_dev *dev) { u32 val; int i; mt792xu_epctl_rst_opt(dev, false); val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); usleep_range(10, 20); val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0); for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) { val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS); if (val & MT_UDMA_CONN_WFSYS_INIT_DONE) break; msleep(100); } if (i == MT792x_WFSYS_INIT_RETRY_COUNT) return -ETIMEDOUT; return 0; } EXPORT_SYMBOL_GPL(mt792xu_wfsys_reset); int mt792xu_init_reset(struct mt792x_dev *dev) { set_bit(MT76_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_stop_rx(&dev->mt76); mt76u_stop_tx(&dev->mt76); mt792xu_wfsys_reset(dev); clear_bit(MT76_RESET, &dev->mphy.state); return mt76u_resume_rx(&dev->mt76); } EXPORT_SYMBOL_GPL(mt792xu_init_reset); +void mt792xu_stop(struct ieee80211_hw *hw, bool suspend) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + mt76u_stop_tx(&dev->mt76); + mt792x_stop(hw, false); +} +EXPORT_SYMBOL_GPL(mt792xu_stop); + void mt792xu_disconnect(struct usb_interface *usb_intf) { struct mt792x_dev *dev = usb_get_intfdata(usb_intf); cancel_work_sync(&dev->init_work); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return; mt76_unregister_device(&dev->mt76); mt792xu_cleanup(dev); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); mt76_free_device(&dev->mt76); } EXPORT_SYMBOL_GPL(mt792xu_disconnect); +MODULE_DESCRIPTION("MediaTek MT792x USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Lorenzo Bianconi "); diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/Kconfig b/sys/contrib/dev/mediatek/mt76/mt7996/Kconfig index 1afa2f662e47..bb44d4a5e2dc 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/Kconfig +++ b/sys/contrib/dev/mediatek/mt76/mt7996/Kconfig @@ -1,14 +1,14 @@ # SPDX-License-Identifier: ISC config MT7996E tristate "MediaTek MT7996 (PCIe) support" select MT76_CONNAC_LIB select WANT_DEV_COREDUMP select RELAY depends on MAC80211 depends on PCI help - This adds support for MT7996-based wireless PCIe devices, + This adds support for MT7996-based PCIe wireless devices, which support concurrent tri-band operation at 6GHz, 5GHz, and 2.4GHz IEEE 802.11be 4x4:4SS 4096-QAM, 320MHz channels. To compile this driver as a module, choose M here. diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/debugfs.c b/sys/contrib/dev/mediatek/mt76/mt7996/debugfs.c index 4d40ec7ff57f..7b2bb72b407d 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/debugfs.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/debugfs.c @@ -1,971 +1,1007 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include "mt7996.h" #include "eeprom.h" #include "mcu.h" #include "mac.h" #define FW_BIN_LOG_MAGIC 0x44d9c99a /** global debugfs **/ struct hw_queue_map { const char *name; u8 index; u8 pid; u8 qid; }; static int mt7996_implicit_txbf_set(void *data, u64 val) { struct mt7996_dev *dev = data; /* The existing connected stations shall reconnect to apply * new implicit txbf configuration. */ dev->ibf = !!val; return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE); } static int mt7996_implicit_txbf_get(void *data, u64 *val) { struct mt7996_dev *dev = data; *val = dev->ibf; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7996_implicit_txbf_get, mt7996_implicit_txbf_set, "%lld\n"); /* test knob of system error recovery */ static ssize_t mt7996_sys_recovery_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct mt7996_phy *phy = file->private_data; - struct mt7996_dev *dev = phy->dev; - bool band = phy->mt76->band_idx; - char buf[16]; + struct mt7996_dev *dev = file->private_data; + char buf[16], *sep; int ret = 0; - u16 val; + u16 band, val; if (count >= sizeof(buf)) return -EINVAL; if (copy_from_user(buf, user_buf, count)) return -EFAULT; if (count && buf[count - 1] == '\n') buf[count - 1] = '\0'; else buf[count] = '\0'; - if (kstrtou16(buf, 0, &val)) + sep = strchr(buf, ','); + if (!sep) + return -EINVAL; + + *sep = 0; + if (kstrtou16(buf, 0, &band) || kstrtou16(sep + 1, 0, &val)) return -EINVAL; switch (val) { /* - * 0: grab firmware current SER state. - * 1: trigger & enable system error L1 recovery. - * 2: trigger & enable system error L2 recovery. - * 3: trigger & enable system error L3 rx abort. - * 4: trigger & enable system error L3 tx abort - * 5: trigger & enable system error L3 tx disable. - * 6: trigger & enable system error L3 bf recovery. - * 7: trigger & enable system error L4 mdp recovery. - * 8: trigger & enable system error full recovery. - * 9: trigger firmware crash. + * ,0: grab firmware current SER state. + * ,1: trigger & enable system error L1 recovery. + * ,2: trigger & enable system error L2 recovery. + * ,3: trigger & enable system error L3 rx abort. + * ,4: trigger & enable system error L3 tx abort + * ,5: trigger & enable system error L3 tx disable. + * ,6: trigger & enable system error L3 bf recovery. + * ,7: trigger & enable system error L4 mdp recovery. + * ,8: trigger & enable system error full recovery. + * ,9: trigger firmware crash. */ case UNI_CMD_SER_QUERY: ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band); break; case UNI_CMD_SER_SET_RECOVER_L1: case UNI_CMD_SER_SET_RECOVER_L2: case UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT: case UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT: case UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE: case UNI_CMD_SER_SET_RECOVER_L3_BF: case UNI_CMD_SER_SET_RECOVER_L4_MDP: ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_SET, BIT(val), band); if (ret) return ret; ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, val, band); break; /* enable full chip reset */ case UNI_CMD_SER_SET_RECOVER_FULL: mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); dev->recovery.state |= MT_MCU_CMD_WDT_MASK; mt7996_reset(dev); break; /* WARNING: trigger firmware crash */ case UNI_CMD_SER_SET_SYSTEM_ASSERT: ret = mt7996_mcu_trigger_assert(dev); if (ret) return ret; break; default: break; } return ret ? ret : count; } static ssize_t mt7996_sys_recovery_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct mt7996_phy *phy = file->private_data; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private_data; char *buff; int desc = 0; ssize_t ret; static const size_t bufsz = 1024; buff = kmalloc(bufsz, GFP_KERNEL); if (!buff) return -ENOMEM; /* HELP */ desc += scnprintf(buff + desc, bufsz - desc, "Please echo the correct value ...\n"); desc += scnprintf(buff + desc, bufsz - desc, - "0: grab firmware transient SER state\n"); + ",0: grab firmware transient SER state\n"); desc += scnprintf(buff + desc, bufsz - desc, - "1: trigger system error L1 recovery\n"); + ",1: trigger system error L1 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "2: trigger system error L2 recovery\n"); + ",2: trigger system error L2 recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "3: trigger system error L3 rx abort\n"); + ",3: trigger system error L3 rx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, - "4: trigger system error L3 tx abort\n"); + ",4: trigger system error L3 tx abort\n"); desc += scnprintf(buff + desc, bufsz - desc, - "5: trigger system error L3 tx disable\n"); + ",5: trigger system error L3 tx disable\n"); desc += scnprintf(buff + desc, bufsz - desc, - "6: trigger system error L3 bf recovery\n"); + ",6: trigger system error L3 bf recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "7: trigger system error L4 mdp recovery\n"); + ",7: trigger system error L4 mdp recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "8: trigger system error full recovery\n"); + ",8: trigger system error full recovery\n"); desc += scnprintf(buff + desc, bufsz - desc, - "9: trigger firmware crash\n"); + ",9: trigger firmware crash\n"); /* SER statistics */ desc += scnprintf(buff + desc, bufsz - desc, "\nlet's dump firmware SER statistics...\n"); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_STATUS = 0x%08x\n", mt76_rr(dev, MT_SWDEF_SER_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR_1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PSE_ERR = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PSE_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_PSE_ERR_1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_PSE1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR6_B2 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN2_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B2 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN2_STATS)); desc += scnprintf(buff + desc, bufsz - desc, "\nSYS_RESET_COUNT: WM %d, WA %d\n", dev->recovery.wm_reset_count, dev->recovery.wa_reset_count); ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); return ret; } static const struct file_operations mt7996_sys_recovery_ops = { .write = mt7996_sys_recovery_set, .read = mt7996_sys_recovery_get, .open = simple_open, .llseek = default_llseek, }; static int mt7996_radar_trigger(void *data, u64 val) { struct mt7996_dev *dev = data; if (val > MT_RX_SEL2) return -EINVAL; + if (val == MT_RX_SEL2 && !dev->rdd2_phy) { + dev_err(dev->mt76.dev, "Background radar is not enabled\n"); + return -EINVAL; + } + return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, val, 0, 0); } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, mt7996_radar_trigger, "%lld\n"); static int mt7996_rdd_monitor(struct seq_file *s, void *data) { struct mt7996_dev *dev = dev_get_drvdata(s->private); struct cfg80211_chan_def *chandef = &dev->rdd2_chandef; const char *bw; int ret = 0; mutex_lock(&dev->mt76.mutex); if (!cfg80211_chandef_valid(chandef)) { ret = -EINVAL; goto out; } if (!dev->rdd2_phy) { seq_puts(s, "not running\n"); goto out; } switch (chandef->width) { case NL80211_CHAN_WIDTH_40: bw = "40"; break; case NL80211_CHAN_WIDTH_80: bw = "80"; break; case NL80211_CHAN_WIDTH_160: bw = "160"; break; case NL80211_CHAN_WIDTH_80P80: bw = "80P80"; break; default: bw = "20"; break; } seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n", chandef->chan->hw_value, chandef->chan->center_freq, bw, chandef->center_freq1); out: mutex_unlock(&dev->mt76.mutex); return ret; } static int mt7996_fw_debug_wm_set(void *data, u64 val) { struct mt7996_dev *dev = data; enum { DEBUG_TXCMD = 62, DEBUG_CMD_RPT_TX, DEBUG_CMD_RPT_TRIG, DEBUG_SPL, DEBUG_RPT_RX, DEBUG_RPT_RA = 68, } debug; bool tx, rx, en; int ret; dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0; if (dev->fw_debug_bin) val = MCU_FW_LOG_RELAY; else val = dev->fw_debug_wm; tx = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(1)); rx = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(2)); en = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(0)); ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val); if (ret) return ret; for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RA; debug++) { if (debug == 67) continue; if (debug == DEBUG_RPT_RX) val = en && rx; else val = en && tx; ret = mt7996_mcu_fw_dbg_ctrl(dev, debug, val); if (ret) return ret; } return 0; } static int mt7996_fw_debug_wm_get(void *data, u64 *val) { struct mt7996_dev *dev = data; *val = dev->fw_debug_wm; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wm, mt7996_fw_debug_wm_get, mt7996_fw_debug_wm_set, "%lld\n"); static int mt7996_fw_debug_wa_set(void *data, u64 val) { struct mt7996_dev *dev = data; int ret; dev->fw_debug_wa = val ? MCU_FW_LOG_TO_HOST : 0; ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, dev->fw_debug_wa); if (ret) return ret; return mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_PDMA_RX, !!dev->fw_debug_wa, 0); } static int mt7996_fw_debug_wa_get(void *data, u64 *val) { struct mt7996_dev *dev = data; *val = dev->fw_debug_wa; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7996_fw_debug_wa_get, mt7996_fw_debug_wa_set, "%lld\n"); static struct dentry * create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode, struct rchan_buf *buf, int *is_global) { struct dentry *f; f = debugfs_create_file("fwlog_data", mode, parent, buf, &relay_file_operations); if (IS_ERR(f)) return NULL; *is_global = 1; return f; } static int remove_buf_file_cb(struct dentry *f) { debugfs_remove(f); return 0; } static int mt7996_fw_debug_bin_set(void *data, u64 val) { static struct rchan_callbacks relay_cb = { .create_buf_file = create_buf_file_cb, .remove_buf_file = remove_buf_file_cb, }; struct mt7996_dev *dev = data; if (!dev->relay_fwlog) dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir, 1500, 512, &relay_cb, NULL); if (!dev->relay_fwlog) return -ENOMEM; dev->fw_debug_bin = val; relay_reset(dev->relay_fwlog); return mt7996_fw_debug_wm_set(dev, dev->fw_debug_wm); } static int mt7996_fw_debug_bin_get(void *data, u64 *val) { struct mt7996_dev *dev = data; *val = dev->fw_debug_bin; return 0; } DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7996_fw_debug_bin_get, mt7996_fw_debug_bin_set, "%lld\n"); static int mt7996_fw_util_wa_show(struct seq_file *file, void *data) { struct mt7996_dev *dev = file->private; if (dev->fw_debug_wa) return mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_CPU_UTIL, 0, 0); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7996_fw_util_wa); static void mt7996_ampdu_stat_read_phy(struct mt7996_phy *phy, struct seq_file *file) { struct mt7996_dev *dev = phy->dev; int bound[15], range[8], i; u8 band_idx = phy->mt76->band_idx; /* Tx ampdu stat */ for (i = 0; i < ARRAY_SIZE(range); i++) range[i] = mt76_rr(dev, MT_MIB_ARNG(band_idx, i)); for (i = 0; i < ARRAY_SIZE(bound); i++) bound[i] = MT_MIB_ARNCR_RANGE(range[i / 2], i % 2) + 1; seq_printf(file, "\nPhy %s, Phy band %d\n", wiphy_name(phy->mt76->hw->wiphy), band_idx); seq_printf(file, "Length: %8d | ", bound[0]); for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) seq_printf(file, "%3d -%3d | ", bound[i] + 1, bound[i + 1]); seq_puts(file, "\nCount: "); for (i = 0; i < ARRAY_SIZE(bound); i++) seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]); seq_puts(file, "\n"); seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); } static void mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) { struct mt76_mib_stats *mib = &phy->mib; static const char * const bw[] = { - "BW20", "BW40", "BW80", "BW160" + "BW20", "BW40", "BW80", "BW160", "BW320" }; /* Tx Beamformer monitor */ seq_puts(s, "\nTx Beamformer applied PPDU counts: "); 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: "); - seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", + seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ", mib->tx_bf_rx_fb_all_cnt, + mib->tx_bf_rx_fb_eht_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 */ 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 */ seq_printf(s, "Tx multi-user Beamforming counts: %d\n", mib->tx_mu_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"); } -static int -mt7996_tx_stats_show(struct seq_file *file, void *data) +static void +mt7996_tx_stats_show_phy(struct seq_file *file, struct mt7996_phy *phy) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; struct mt76_mib_stats *mib = &phy->mib; - int i; u32 attempts, success, per; - - mutex_lock(&dev->mt76.mutex); + int i; mt7996_mac_update_stats(phy); mt7996_ampdu_stat_read_phy(phy, file); attempts = mib->tx_mpdu_attempts_cnt; success = mib->tx_mpdu_success_cnt; per = attempts ? 100 - success * 100 / attempts : 100; seq_printf(file, "Tx attempts: %8u (MPDUs)\n", attempts); seq_printf(file, "Tx success: %8u (MPDUs)\n", success); seq_printf(file, "Tx PER: %u%%\n", per); mt7996_txbf_stat_read_phy(phy, file); /* Tx amsdu info */ seq_puts(file, "Tx MSDU statistics:\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"); } +} + +static int +mt7996_tx_stats_show(struct seq_file *file, void *data) +{ + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy = &dev->phy; + + mutex_lock(&dev->mt76.mutex); + + mt7996_tx_stats_show_phy(file, phy); + phy = mt7996_phy2(dev); + if (phy) + mt7996_tx_stats_show_phy(file, phy); + phy = mt7996_phy3(dev); + if (phy) + mt7996_tx_stats_show_phy(file, phy); mutex_unlock(&dev->mt76.mutex); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7996_tx_stats); static void mt7996_hw_queue_read(struct seq_file *s, u32 size, const struct hw_queue_map *map) { struct mt7996_phy *phy = s->private; struct mt7996_dev *dev = phy->dev; u32 i, val; val = mt76_rr(dev, MT_FL_Q_EMPTY); for (i = 0; i < size; i++) { u32 ctrl, head, tail, queued; if (val & BIT(map[i].index)) continue; ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); head = mt76_get_field(dev, MT_FL_Q2_CTRL, GENMASK(11, 0)); tail = mt76_get_field(dev, MT_FL_Q2_CTRL, GENMASK(27, 16)); queued = mt76_get_field(dev, 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 mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_dev *dev = msta->vif->phy->dev; + struct mt7996_dev *dev = msta->vif->deflink.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_FL_Q0_CTRL, ctrl | msta->wcid.idx); qlen = mt76_get_field(dev, 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->mt76.wmm_idx, ac, qlen); + msta->vif->deflink.mt76.wmm_idx, ac, qlen); } } static int mt7996_hw_queues_show(struct seq_file *file, void *data) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy = &dev->phy; 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"); mt7996_hw_queue_read(file, ARRAY_SIZE(ple_queue_map), &ple_queue_map[0]); /* iterate per-sta ple queue */ ieee80211_iterate_stations_atomic(phy->mt76->hw, mt7996_sta_hw_queue_read, file); + phy = mt7996_phy2(dev); + if (phy) + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7996_sta_hw_queue_read, file); + phy = mt7996_phy3(dev); + if (phy) + ieee80211_iterate_stations_atomic(phy->mt76->hw, + mt7996_sta_hw_queue_read, file); + /* pse queue */ seq_puts(file, "PSE non-empty queue info:\n"); mt7996_hw_queue_read(file, ARRAY_SIZE(pse_queue_map), &pse_queue_map[0]); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7996_hw_queues); static int mt7996_xmit_queues_show(struct seq_file *file, void *data) { - struct mt7996_phy *phy = file->private; - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = file->private; + struct mt7996_phy *phy; struct { struct mt76_queue *q; char *queue; } queue_map[] = { - { phy->mt76->q_tx[MT_TXQ_BE], " MAIN" }, + { dev->mphy.q_tx[MT_TXQ_BE], " MAIN0" }, + { NULL, " MAIN1" }, + { NULL, " MAIN2" }, { 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; + phy = mt7996_phy2(dev); + if (phy) + queue_map[1].q = phy->mt76->q_tx[MT_TXQ_BE]; + + phy = mt7996_phy3(dev); + if (phy) + queue_map[2].q = phy->mt76->q_tx[MT_TXQ_BE]; + 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(file, " %s | %9d | %9d | %9d |\n", queue_map[i].queue, q->queued, q->head, q->tail); } return 0; } DEFINE_SHOW_ATTRIBUTE(mt7996_xmit_queues); static int mt7996_twt_stats(struct seq_file *s, void *data) { struct mt7996_dev *dev = dev_get_drvdata(s->private); struct mt7996_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; } /* The index of RF registers use the generic regidx, combined with two parts: * WF selection [31:24] and offset [23:0]. */ static int mt7996_rf_regval_get(void *data, u64 *val) { struct mt7996_dev *dev = data; u32 regval; int ret; ret = mt7996_mcu_rf_regval(dev, dev->mt76.debugfs_reg, ®val, false); if (ret) return ret; *val = regval; return 0; } static int mt7996_rf_regval_set(void *data, u64 val) { struct mt7996_dev *dev = data; u32 val32 = val; return mt7996_mcu_rf_regval(dev, dev->mt76.debugfs_reg, &val32, true); } DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7996_rf_regval_get, mt7996_rf_regval_set, "0x%08llx\n"); -int mt7996_init_debugfs(struct mt7996_phy *phy) +int mt7996_init_debugfs(struct mt7996_dev *dev) { - struct mt7996_dev *dev = phy->dev; struct dentry *dir; - dir = mt76_register_debugfs_fops(phy->mt76, NULL); + dir = mt76_register_debugfs_fops(&dev->mphy, NULL); if (!dir) return -ENOMEM; - debugfs_create_file("hw-queues", 0400, dir, phy, + + debugfs_create_file("hw-queues", 0400, dir, dev, &mt7996_hw_queues_fops); - debugfs_create_file("xmit-queues", 0400, dir, phy, + debugfs_create_file("xmit-queues", 0400, dir, dev, &mt7996_xmit_queues_fops); - debugfs_create_file("tx_stats", 0400, dir, phy, &mt7996_tx_stats_fops); - debugfs_create_file("sys_recovery", 0600, dir, phy, + debugfs_create_file("tx_stats", 0400, dir, dev, &mt7996_tx_stats_fops); + debugfs_create_file("sys_recovery", 0600, dir, dev, &mt7996_sys_recovery_ops); debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); /* TODO: wm fw cpu utilization */ debugfs_create_file("fw_util_wa", 0400, dir, dev, &mt7996_fw_util_wa_fops); debugfs_create_file("implicit_txbf", 0600, dir, dev, &fops_implicit_txbf); debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir, mt7996_twt_stats); debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); - if (phy->mt76->cap.has_5ghz) { - debugfs_create_u32("dfs_hw_pattern", 0400, dir, - &dev->hw_pattern); - debugfs_create_file("radar_trigger", 0200, dir, dev, - &fops_radar_trigger); - debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, - mt7996_rdd_monitor); - } + debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_trigger); + debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, + mt7996_rdd_monitor); - if (phy == &dev->phy) - dev->debugfs_dir = dir; + dev->debugfs_dir = dir; return 0; } static void mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen, const void *data, int len) { static DEFINE_SPINLOCK(lock); unsigned long flags; void *dest; spin_lock_irqsave(&lock, flags); dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4); if (dest) { *(u32 *)dest = hdrlen + len; dest += 4; if (hdrlen) { memcpy(dest, hdr, hdrlen); dest += hdrlen; } memcpy(dest, data, len); relay_flush(dev->relay_fwlog); } spin_unlock_irqrestore(&lock, flags); } void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len) { struct { __le32 magic; u8 version; u8 _rsv; __le16 serial_id; __le32 timestamp; __le16 msg_type; __le16 len; } hdr = { .version = 0x1, .magic = cpu_to_le32(FW_BIN_LOG_MAGIC), .msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR), }; if (!dev->relay_fwlog) return; hdr.serial_id = cpu_to_le16(dev->fw_debug_seq++); hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0))); hdr.len = *(__le16 *)data; mt7996_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len); } bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len) { if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC) return false; if (dev->relay_fwlog) mt7996_debugfs_write_fwlog(dev, NULL, 0, data, len); return true; } #ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ static ssize_t mt7996_sta_fixed_rate_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { #define SHORT_PREAMBLE 0 #define LONG_PREAMBLE 1 struct ieee80211_sta *sta = file->private_data; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_dev *dev = msta->vif->phy->dev; + struct mt7996_dev *dev = msta->vif->deflink.phy->dev; struct ra_rate phy = {}; char buf[100]; int ret; u16 gi, ltf; if (count >= sizeof(buf)) return -EINVAL; if (copy_from_user(buf, user_buf, count)) return -EFAULT; if (count && buf[count - 1] == '\n') buf[count - 1] = '\0'; else buf[count] = '\0'; /* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 EHT: 15 * bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3, BW320: 4 * nss - vht: 1~4, he: 1~4, eht: 1~4, others: ignore * mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2, eht: 0~13 * gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2 * preamble - short: 1, long: 0 * ldpc - off: 0, on: 1 * stbc - off: 0, on: 1 * ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 */ if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu", &phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi, &phy.preamble, &phy.stbc, &phy.ldpc, &phy.spe, <f) != 10) { dev_warn(dev->mt76.dev, "format: Mode BW MCS NSS GI Preamble STBC LDPC SPE ltf\n"); goto out; } phy.wlan_idx = cpu_to_le16(msta->wcid.idx); phy.gi = cpu_to_le16(gi); phy.ltf = cpu_to_le16(ltf); phy.ldpc = phy.ldpc ? 7 : 0; phy.preamble = phy.preamble ? SHORT_PREAMBLE : LONG_PREAMBLE; ret = mt7996_mcu_set_fixed_rate_ctrl(dev, &phy, 0); if (ret) return -EFAULT; out: return count; } static const struct file_operations fops_fixed_rate = { .write = mt7996_sta_fixed_rate_set, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static int mt7996_queues_show(struct seq_file *s, void *data) { struct ieee80211_sta *sta = s->private; mt7996_sta_hw_queue_read(s, sta); return 0; } DEFINE_SHOW_ATTRIBUTE(mt7996_queues); void mt7996_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("hw-queues", 0400, dir, sta, &mt7996_queues_fops); } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/dma.c b/sys/contrib/dev/mediatek/mt76/mt7996/dma.c index 285b2b89379a..af317e04ae9e 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/dma.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/dma.c @@ -1,442 +1,737 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include "mt7996.h" #include "../dma.h" #include "mac.h" #if defined(__FreeBSD__) #include #endif +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, + int ring_base, struct mtk_wed_device *wed) +{ + struct mt7996_dev *dev = phy->dev; + u32 flags = 0; + + if (mtk_wed_device_active(wed)) { + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; + idx -= MT_TXQ_ID(0); + + if (phy->mt76->band_idx == MT_BAND2) + flags = MT_WED_Q_TX(0); + else + flags = MT_WED_Q_TX(idx); + } + + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, + ring_base, wed, flags); +} + static int mt7996_poll_tx(struct napi_struct *napi, int budget) { struct mt7996_dev *dev; dev = container_of(napi, struct mt7996_dev, mt76.tx_napi); mt76_connac_tx_cleanup(&dev->mt76); if (napi_complete_done(napi, 0)) mt7996_irq_enable(dev, MT_INT_TX_DONE_MCU); return 0; } static void mt7996_dma_config(struct mt7996_dev *dev) { #define Q_CONFIG(q, wfdma, int, id) do { \ if (wfdma) \ dev->q_wfdma_mask |= (1 << (q)); \ dev->q_int_mask[(q)] = int; \ dev->q_id[(q)] = id; \ } while (0) #define MCUQ_CONFIG(q, wfdma, int, id) Q_CONFIG(q, (wfdma), (int), (id)) #define RXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__RXQ(q), (wfdma), (int), (id)) #define TXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__TXQ(q), (wfdma), (int), (id)) /* rx queue */ RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA); - /* band0/band1 */ + /* mt7996: band0 and band1, mt7992: band0 */ RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN); - /* band2 */ - RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); - RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + if (is_mt7996(&dev->mt76)) { + /* mt7996 band2 */ + RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); + RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + } else { + /* mt7992 band1 */ + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + } + + if (dev->has_rro) { + /* band0 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, + MT7996_RXQ_RRO_BAND0); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, + MT7996_RXQ_MSDU_PG_BAND0); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, + MT7996_RXQ_TXFREE0); + /* band1 */ + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, + MT7996_RXQ_MSDU_PG_BAND1); + /* band2 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, + MT7996_RXQ_RRO_BAND2); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, + MT7996_RXQ_MSDU_PG_BAND2); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, + MT7996_RXQ_TXFREE2); + + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, + MT7996_RXQ_RRO_IND); + } /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + if (is_mt7996(&dev->mt76)) { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + } else { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + } /* mcu tx queue */ MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA, MT7996_TXQ_MCU_WA); MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL); } +static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) +{ + u32 ret = *base << 16 | depth; + + *base = *base + (depth << 4); + + return ret; +} + static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { -#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth)) + u16 base = 0; + u8 queue; + +#define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2)); + + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1; + mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10)); + + if (dev->has_rro) { + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, + PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, + PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, + PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, + PREFETCH(0x4)); + } +#undef PREFETCH mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE); } void mt7996_dma_prefetch(struct mt7996_dev *dev) { __mt7996_dma_prefetch(dev, 0); if (dev->hif2) __mt7996_dma_prefetch(dev, MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0)); } static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) { u32 hif1_ofs = 0; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); if (reset) { mt76_clear(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); if (dev->hif2) { mt76_clear(dev, MT_WFDMA0_RST + hif1_ofs, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); mt76_set(dev, MT_WFDMA0_RST + hif1_ofs, MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); } } /* disable */ mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (dev->hif2) { mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); } } -void mt7996_dma_start(struct mt7996_dev *dev, bool reset) +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; u32 hif1_ofs = 0; u32 irq_mask; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); /* enable WFDMA Tx/Rx */ if (!reset) { - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_EXT_EN); + else + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); if (dev->hif2) mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); } /* enable interrupts for TX/RX rings */ - irq_mask = MT_INT_MCU_CMD; - if (reset) - goto done; - - irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; + irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; - if (!dev->mphy.band_idx) + if (mt7996_band_valid(dev, MT_BAND0)) irq_mask |= MT_INT_BAND0_RX_DONE; - if (dev->dbdc_support) + if (mt7996_band_valid(dev, MT_BAND1)) irq_mask |= MT_INT_BAND1_RX_DONE; - if (dev->tbtc_support) + if (mt7996_band_valid(dev, MT_BAND2)) irq_mask |= MT_INT_BAND2_RX_DONE; -done: + if (mtk_wed_device_active(wed) && wed_reset) { + u32 wed_irq_mask = irq_mask; + + wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + mtk_wed_device_start(wed, wed_irq_mask); + } + + irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; + mt7996_irq_enable(dev, irq_mask); mt7996_irq_disable(dev, 0); } static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) { u32 hif1_ofs = 0; if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); if (dev->hif2) mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR + hif1_ofs, ~0); /* configure delay interrupt off */ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2, 0); if (dev->hif2) { mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0 + hif1_ofs, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG1 + hif1_ofs, 0); mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG2 + hif1_ofs, 0); } /* configure perfetch settings */ mt7996_dma_prefetch(dev); /* hif wait WFDMA idle */ mt76_set(dev, MT_WFDMA0_BUSY_ENA, MT_WFDMA0_BUSY_ENA_TX_FIFO0 | MT_WFDMA0_BUSY_ENA_TX_FIFO1 | MT_WFDMA0_BUSY_ENA_RX_FIFO); if (dev->hif2) mt76_set(dev, MT_WFDMA0_BUSY_ENA + hif1_ofs, MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 | MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 | MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO); mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC, MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000); /* GLO_CFG_EXT0 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0, WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD | WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE); /* GLO_CFG_EXT1 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1, WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20); + if (dev->hif2) { /* GLO_CFG_EXT0 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD | WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE); /* GLO_CFG_EXT1 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + hif1_ofs, WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_PDMA_BAND); + MT_WFDMA_HOST_CONFIG_PDMA_BAND | + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + + /* AXI read outstanding number */ + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, + MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); + + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20); } if (dev->hif2) { /* fix hardware limitation, pcie1's rx ring3 is not available * so, redirect pcie0 rx ring3 interrupt to pcie1 */ - mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, - MT_WFDMA0_RX_INT_SEL_RING3); + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + dev->has_rro) + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, + MT_WFDMA0_RX_INT_SEL_RING6); + else + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, + MT_WFDMA0_RX_INT_SEL_RING3); + } - /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */ + mt7996_dma_start(dev, reset, true); +} + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + u32 irq_mask; + int ret; + + /* ind cmd */ + mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], + MT_RXQ_ID(MT_RXQ_RRO_IND), + MT7996_RX_RING_SIZE, + 0, MT_RXQ_RRO_IND_RING_BASE); + if (ret) + return ret; + + /* rx msdu page queue for band0 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = + MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); + if (ret) + return ret; + + if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx msdu page queue for band1 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = + MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); + if (ret) + return ret; } - mt7996_dma_start(dev, reset); + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx msdu page queue for band2 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = + MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); + if (ret) + return ret; + } + + irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | + MT_INT_TX_DONE_BAND2; + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mt7996_irq_enable(dev, irq_mask); + + return 0; } +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ int mt7996_dma_init(struct mt7996_dev *dev) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; + u32 rx_base; u32 hif1_ofs = 0; int ret; mt7996_dma_config(dev); mt76_dma_attach(&dev->mt76); if (dev->hif2) hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); mt7996_dma_disable(dev, true); /* init tx queue */ - ret = mt76_connac_init_tx_queues(dev->phy.mt76, - MT_TXQ_ID(dev->mphy.band_idx), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), 0); + ret = mt7996_init_tx_queues(&dev->phy, + MT_TXQ_ID(dev->mphy.band_idx), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(0), + wed); if (ret) return ret; /* command to WM */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_MCUQ_ID(MT_MCUQ_WM), MT7996_TX_MCU_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_WM)); if (ret) return ret; /* command to WA */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, MT_MCUQ_ID(MT_MCUQ_WA), MT7996_TX_MCU_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_WA)); if (ret) return ret; /* firmware download */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT_MCUQ_ID(MT_MCUQ_FWDL), MT7996_TX_FWDL_RING_SIZE, MT_MCUQ_RING_BASE(MT_MCUQ_FWDL)); if (ret) return ret; /* event from WM */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT_RXQ_ID(MT_RXQ_MCU), MT7996_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MCU)); if (ret) return ret; /* event from WA */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT_RXQ_ID(MT_RXQ_MCU_WA), MT7996_RX_MCU_RING_SIZE_WA, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MCU_WA)); if (ret) return ret; - /* rx data queue for band0 and band1 */ + /* rx data queue for band0 and mt7996 band1 */ + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); + dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7996_RX_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MAIN)); if (ret) return ret; /* tx free notify event from WA for band0 */ + if (mtk_wed_device_active(wed) && !dev->has_rro) { + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], MT_RXQ_ID(MT_RXQ_MAIN_WA), MT7996_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA)); if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { - /* rx data queue for band2 */ + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx data queue for mt7996 band2 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs); + rx_base); if (ret) return ret; - /* tx free notify event from WA for band2 + /* tx free notify event from WA for mt7996 band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ + if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { + dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA], MT_RXQ_ID(MT_RXQ_BAND2_WA), MT7996_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA)); if (ret) return ret; + } else if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx data queue for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], + MT_RXQ_ID(MT_RXQ_BAND1), + MT7996_RX_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + + /* tx free notify event from WA for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], + MT_RXQ_ID(MT_RXQ_BAND1_WA), + MT7996_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + } + + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && + dev->has_rro) { + /* rx rro data queue for band0 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = + MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], + MT_RXQ_ID(MT_RXQ_RRO_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0)); + if (ret) + return ret; + + /* tx free notify event from WA for band0 */ + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); + if (ret) + return ret; + + if (mt7996_band_valid(dev, MT_BAND2)) { + /* rx rro data queue for band2 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], + MT_RXQ_ID(MT_RXQ_RRO_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); + if (ret) + return ret; + + /* tx free notify event from MAC for band2 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND2), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs); + if (ret) + return ret; + } } ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret < 0) return ret; - netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt7996_poll_tx); napi_enable(&dev->mt76.tx_napi); mt7996_dma_enable(dev, false); return 0; } void mt7996_dma_reset(struct mt7996_dev *dev, bool force) { struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1]; struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2]; u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); int i; mt76_clear(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); if (dev->hif2) mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); usleep_range(1000, 2000); for (i = 0; i < __MT_TXQ_MAX; i++) { mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); if (phy2) mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true); if (phy3) mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); mt76_tx_status_check(&dev->mt76, true); /* reset wfsys */ if (force) mt7996_wfsys_reset(dev); + if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed); + mt7996_dma_disable(dev, force); + mt76_wed_dma_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_reset(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (phy2) - mt76_queue_reset(dev, phy2->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]); if (phy3) - mt76_queue_reset(dev, phy3->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) + continue; + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); } mt76_tx_status_check(&dev->mt76, true); mt76_for_each_q_rx(&dev->mt76, i) mt76_queue_rx_reset(dev, i); mt7996_dma_enable(dev, !force); } void mt7996_dma_cleanup(struct mt7996_dev *dev) { mt7996_dma_disable(dev, true); mt76_dma_cleanup(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.c b/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.c index 633581e37d26..e854ab32acba 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.c @@ -1,262 +1,376 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include "mt7996.h" #include "eeprom.h" static int mt7996_check_eeprom(struct mt7996_dev *dev) { u8 *eeprom = dev->mt76.eeprom.data; u16 val = get_unaligned_le16(eeprom); switch (val) { case 0x7990: - return 0; + return is_mt7996(&dev->mt76) ? 0 : -EINVAL; + case 0x7992: + return is_mt7992(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; } } static char *mt7996_eeprom_name(struct mt7996_dev *dev) { - /* reserve for future variants */ - return MT7996_EEPROM_DEFAULT; + switch (mt76_chip(&dev->mt76)) { + case 0x7992: + switch (dev->var.type) { + case MT7992_VAR_TYPE_23: + if (dev->var.fem == MT7996_FEM_INT) + return MT7992_EEPROM_DEFAULT_23_INT; + return MT7992_EEPROM_DEFAULT_23; + case MT7992_VAR_TYPE_44: + default: + if (dev->var.fem == MT7996_FEM_INT) + return MT7992_EEPROM_DEFAULT_INT; + if (dev->var.fem == MT7996_FEM_MIX) + return MT7992_EEPROM_DEFAULT_MIX; + return MT7992_EEPROM_DEFAULT; + } + case 0x7990: + default: + switch (dev->var.type) { + case MT7996_VAR_TYPE_233: + if (dev->var.fem == MT7996_FEM_INT) + return MT7996_EEPROM_DEFAULT_233_INT; + return MT7996_EEPROM_DEFAULT_233; + case MT7996_VAR_TYPE_444: + default: + if (dev->var.fem == MT7996_FEM_INT) + return MT7996_EEPROM_DEFAULT_INT; + return MT7996_EEPROM_DEFAULT; + } + } +} + +static void +mt7996_eeprom_parse_stream(const u8 *eeprom, u8 band_idx, u8 *path, + u8 *rx_path, u8 *nss) +{ + switch (band_idx) { + case MT_BAND1: + *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1, + eeprom[MT_EE_WIFI_CONF + 2]); + *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1, + eeprom[MT_EE_WIFI_CONF + 3]); + *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1, + eeprom[MT_EE_WIFI_CONF + 5]); + break; + case MT_BAND2: + *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2, + eeprom[MT_EE_WIFI_CONF + 2]); + *rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2, + eeprom[MT_EE_WIFI_CONF + 4]); + *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2, + eeprom[MT_EE_WIFI_CONF + 5]); + break; + default: + *path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0, + eeprom[MT_EE_WIFI_CONF + 1]); + *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0, + eeprom[MT_EE_WIFI_CONF + 3]); + *nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0, + eeprom[MT_EE_WIFI_CONF + 4]); + break; + } +} + +static bool mt7996_eeprom_variant_valid(struct mt7996_dev *dev, const u8 *def) +{ +#define FEM_INT 0 +#define FEM_EXT 3 + u8 *eeprom = dev->mt76.eeprom.data, fem[2]; + int i; + + for (i = 0; i < 2; i++) + fem[i] = u8_get_bits(eeprom[MT_EE_WIFI_CONF + 6 + i], + MT_EE_WIFI_PA_LNA_CONFIG); + + if (dev->var.fem == MT7996_FEM_EXT && + !(fem[0] == FEM_EXT && fem[1] == FEM_EXT)) + return false; + else if (dev->var.fem == MT7996_FEM_INT && + !(fem[0] == FEM_INT && fem[1] == FEM_INT)) + return false; + else if (dev->var.fem == MT7996_FEM_MIX && + !(fem[0] == FEM_INT && fem[1] == FEM_EXT)) + return false; + + for (i = 0; i < __MT_MAX_BAND; i++) { + u8 path, rx_path, nss; + u8 def_path, def_rx_path, def_nss; + + if (!dev->mt76.phys[i]) + continue; + + mt7996_eeprom_parse_stream(eeprom, i, &path, &rx_path, &nss); + mt7996_eeprom_parse_stream(def, i, &def_path, &def_rx_path, + &def_nss); + if (path > def_path || rx_path > def_rx_path || nss > def_nss) + return false; + } + + return true; } static int -mt7996_eeprom_load_default(struct mt7996_dev *dev) +mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) { u8 *eeprom = dev->mt76.eeprom.data; const struct firmware *fw = NULL; int ret; ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data) { dev_err(dev->mt76.dev, "Invalid default bin\n"); ret = -EINVAL; goto out; } + if (!use_default && mt7996_eeprom_variant_valid(dev, fw->data)) + goto out; + + dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); dev->flash_mode = true; out: release_firmware(fw); return ret; } static int mt7996_eeprom_load(struct mt7996_dev *dev) { + bool use_default = false; int ret; ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); if (ret < 0) return ret; - if (ret) { + if (ret && !mt7996_check_eeprom(dev)) { dev->flash_mode = true; - } else { - u8 free_block_num; - u32 block_num, i; + goto out; + } + + if (!dev->flash_mode) { u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; + u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + u8 free_block_num; + int i; + memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); if (ret < 0) return ret; /* efuse info isn't enough */ - if (free_block_num >= 59) - return -EINVAL; - - /* read eeprom data from efuse */ - block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); - for (i = 0; i < block_num; i++) { - ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size); - if (ret < 0) - return ret; + if (free_block_num >= 59) { + use_default = true; + goto out; + } + + /* check if eeprom data from fw is valid */ + if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || + mt7996_check_eeprom(dev)) { + use_default = true; + goto out; + } + + /* read eeprom data from fw */ + for (i = 1; i < block_num; i++) { + u32 len = eeprom_blk_size; + + if (i == block_num - 1) + len = MT7996_EEPROM_SIZE % eeprom_blk_size; + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, + NULL, len); + if (ret && ret != -EINVAL) { + use_default = true; + goto out; + } } } - return mt7996_check_eeprom(dev); +out: + return mt7996_eeprom_check_or_use_default(dev, use_default); } -static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) +static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_phy *phy, + u8 *path, u8 *rx_path, u8 *nss) { #define MODE_HE_ONLY BIT(0) #define WTBL_SIZE_GROUP GENMASK(31, 28) +#define STREAM_CAP(_offs) ((cap & (0x7 << (_offs))) >> (_offs)) + struct mt7996_dev *dev = phy->dev; u32 cap = 0; int ret; ret = mt7996_mcu_get_chip_config(dev, &cap); if (ret) return ret; if (cap) { + u8 band_offs = phy->mt76->band_idx * 3; + dev->has_eht = !(cap & MODE_HE_ONLY); dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP); + *nss = min_t(u8, *nss, STREAM_CAP(1 + band_offs)); + *path = min_t(u8, *path, STREAM_CAP(10 + band_offs)); + *rx_path = min_t(u8, *rx_path, STREAM_CAP(19 + band_offs)); } if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4) - dev->wtbl_size_group = 2; /* set default */ + dev->wtbl_size_group = is_mt7996(&dev->mt76) ? 4 : 2; return 0; } static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy) { u8 *eeprom = phy->dev->mt76.eeprom.data; u32 val = eeprom[MT_EE_WIFI_CONF]; int ret = 0; switch (phy->mt76->band_idx) { case MT_BAND1: val = FIELD_GET(MT_EE_WIFI_CONF1_BAND_SEL, val); break; case MT_BAND2: val = eeprom[MT_EE_WIFI_CONF + 1]; val = FIELD_GET(MT_EE_WIFI_CONF2_BAND_SEL, val); break; default: val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); break; } switch (val) { case MT_EE_BAND_SEL_2GHZ: phy->mt76->cap.has_2ghz = true; break; case MT_EE_BAND_SEL_5GHZ: phy->mt76->cap.has_5ghz = true; break; case MT_EE_BAND_SEL_6GHZ: phy->mt76->cap.has_6ghz = true; break; default: ret = -EINVAL; break; } return ret; } int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) { - u8 path, nss, band_idx = phy->mt76->band_idx; + u8 path, rx_path, nss, band_idx = phy->mt76->band_idx; u8 *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; + int max_path = 5, max_nss = 4; int ret; - switch (band_idx) { - case MT_BAND1: - path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1, - eeprom[MT_EE_WIFI_CONF + 2]); - nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1, - eeprom[MT_EE_WIFI_CONF + 5]); - break; - case MT_BAND2: - path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2, - eeprom[MT_EE_WIFI_CONF + 2]); - nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2, - eeprom[MT_EE_WIFI_CONF + 5]); - break; - default: - path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0, - eeprom[MT_EE_WIFI_CONF + 1]); - nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0, - eeprom[MT_EE_WIFI_CONF + 4]); - break; - } + mt7996_eeprom_parse_stream(eeprom, band_idx, &path, &rx_path, &nss); + ret = mt7996_eeprom_parse_efuse_hw_cap(phy, &path, &rx_path, &nss); + if (ret) + return ret; + + if (!path || path > max_path) + path = max_path; - if (!path || path > 4) - path = 4; + if (!nss || nss > max_nss) + nss = max_nss; - nss = min_t(u8, min_t(u8, 4, nss), path); + nss = min_t(u8, nss, path); + + if (path != rx_path) + phy->has_aux_rx = true; mphy->antenna_mask = BIT(nss) - 1; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; + phy->orig_chainmask = mphy->chainmask; dev->chainmask |= mphy->chainmask; if (band_idx < MT_BAND2) dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] + hweight16(mphy->chainmask); - ret = mt7996_eeprom_parse_efuse_hw_cap(dev); - if (ret) - return ret; - return mt7996_eeprom_parse_band_config(phy); } int mt7996_eeprom_init(struct mt7996_dev *dev) { int ret; ret = mt7996_eeprom_load(dev); - if (ret < 0) { - if (ret != -EINVAL) - return ret; - - dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); - ret = mt7996_eeprom_load_default(dev); - if (ret) - return ret; - } + if (ret < 0) + return ret; ret = mt7996_eeprom_parse_hw_cap(dev, &dev->phy); if (ret < 0) return ret; #if defined(__linux__) memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); #elif defined(__FreeBSD__) memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); #endif mt76_eeprom_override(&dev->mphy); return 0; } int mt7996_eeprom_get_target_power(struct mt7996_dev *dev, struct ieee80211_channel *chan) { u8 *eeprom = dev->mt76.eeprom.data; int target_power; if (chan->band == NL80211_BAND_5GHZ) target_power = eeprom[MT_EE_TX0_POWER_5G + mt7996_get_channel_group_5g(chan->hw_value)]; else if (chan->band == NL80211_BAND_6GHZ) target_power = eeprom[MT_EE_TX0_POWER_6G + mt7996_get_channel_group_6g(chan->hw_value)]; else target_power = eeprom[MT_EE_TX0_POWER_2G]; return target_power; } s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band) { u8 *eeprom = dev->mt76.eeprom.data; u32 val; s8 delta; if (band == NL80211_BAND_5GHZ) val = eeprom[MT_EE_RATE_DELTA_5G]; else if (band == NL80211_BAND_6GHZ) val = eeprom[MT_EE_RATE_DELTA_6G]; else val = eeprom[MT_EE_RATE_DELTA_2G]; if (!(val & MT_EE_RATE_DELTA_EN)) return 0; delta = FIELD_GET(MT_EE_RATE_DELTA_MASK, val); return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.h b/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.h index 0c749774f6b1..7a771ca2434c 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.h +++ b/sys/contrib/dev/mediatek/mt76/mt7996/eeprom.h @@ -1,74 +1,79 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2022 MediaTek Inc. */ #ifndef __MT7996_EEPROM_H #define __MT7996_EEPROM_H #include "mt7996.h" enum mt7996_eeprom_field { MT_EE_CHIP_ID = 0x000, MT_EE_VERSION = 0x002, MT_EE_MAC_ADDR = 0x004, MT_EE_MAC_ADDR2 = 0x00a, MT_EE_WIFI_CONF = 0x190, MT_EE_MAC_ADDR3 = 0x2c0, MT_EE_RATE_DELTA_2G = 0x1400, MT_EE_RATE_DELTA_5G = 0x147d, MT_EE_RATE_DELTA_6G = 0x154a, MT_EE_TX0_POWER_2G = 0x1300, MT_EE_TX0_POWER_5G = 0x1301, MT_EE_TX0_POWER_6G = 0x1310, __MT_EE_MAX = 0x1dff, }; #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) #define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(2, 0) #define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(5, 3) #define MT_EE_WIFI_CONF2_BAND_SEL GENMASK(2, 0) #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3) +#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0) #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_PA_LNA_CONFIG GENMASK(1, 0) + #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0) #define MT_EE_RATE_DELTA_SIGN BIT(6) #define MT_EE_RATE_DELTA_EN BIT(7) enum mt7996_eeprom_band { MT_EE_BAND_SEL_DEFAULT, MT_EE_BAND_SEL_2GHZ, MT_EE_BAND_SEL_5GHZ, MT_EE_BAND_SEL_6GHZ, }; static inline int mt7996_get_channel_group_5g(int channel) { if (channel <= 64) return 0; if (channel <= 96) return 1; if (channel <= 128) return 2; if (channel <= 144) return 3; return 4; } static inline int mt7996_get_channel_group_6g(int channel) { if (channel <= 29) return 0; return DIV_ROUND_UP(channel - 29, 32); } #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/init.c b/sys/contrib/dev/mediatek/mt76/mt7996/init.c index ac53accb5511..1f25bd681fc9 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/init.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/init.c @@ -1,930 +1,1575 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include +#include +#include #include #include "mt7996.h" #include "mac.h" #include "mcu.h" #include "coredump.h" #include "eeprom.h" #if defined(__FreeBSD__) #include #endif +static const struct ieee80211_iface_limit if_limits_global = { + .max = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS, + .types = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_AP) +#ifdef CONFIG_MAC80211_MESH + | BIT(NL80211_IFTYPE_MESH_POINT) +#endif +}; + +static const struct ieee80211_iface_combination if_comb_global = { + .limits = &if_limits_global, + .n_limits = 1, + .max_interfaces = MT7996_MAX_INTERFACES * MT7996_MAX_RADIOS, + .num_different_channels = MT7996_MAX_RADIOS, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), +}; + static const struct ieee80211_iface_limit if_limits[] = { { - .max = 1, - .types = BIT(NL80211_IFTYPE_ADHOC) - }, { .max = 16, .types = BIT(NL80211_IFTYPE_AP) #ifdef CONFIG_MAC80211_MESH | BIT(NL80211_IFTYPE_MESH_POINT) #endif }, { .max = MT7996_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_STATION) } }; -static const struct ieee80211_iface_combination if_comb[] = { - { - .limits = if_limits, - .n_limits = ARRAY_SIZE(if_limits), - .max_interfaces = MT7996_MAX_INTERFACES, - .num_different_channels = 1, - .beacon_int_infra_match = true, - .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80) | - BIT(NL80211_CHAN_WIDTH_160), +static const struct ieee80211_iface_combination if_comb = { + .limits = if_limits, + .n_limits = ARRAY_SIZE(if_limits), + .max_interfaces = MT7996_MAX_INTERFACES, + .num_different_channels = 1, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), + .beacon_int_min_gcd = 100, +}; + +#if defined(CONFIG_HWMON) +static ssize_t mt7996_thermal_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int i = to_sensor_dev_attr(attr)->index; + int temperature; + + switch (i) { + case 0: + temperature = mt7996_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); + case 1: + case 2: + return sprintf(buf, "%u\n", + phy->throttle_temp[i - 1] * 1000); + case 3: + return sprintf(buf, "%hhu\n", phy->throttle_state); + default: + return -EINVAL; } +} + +static ssize_t mt7996_thermal_temp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mt7996_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 = DIV_ROUND_CLOSEST(clamp_val(val, 40 * 1000, 130 * 1000), 1000); + + /* add a safety margin ~10 */ + if ((i - 1 == MT7996_CRIT_TEMP_IDX && + val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) || + (i - 1 == MT7996_MAX_TEMP_IDX && + val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) { + dev_err(phy->dev->mt76.dev, + "temp1_max shall be 10 degrees higher than temp1_crit."); + mutex_unlock(&phy->dev->mt76.mutex); + return -EINVAL; + } + + phy->throttle_temp[i - 1] = val; + mutex_unlock(&phy->dev->mt76.mutex); + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + return ret; + + return count; +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2); +static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3); + +static struct attribute *mt7996_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, + &sensor_dev_attr_throttle1.dev_attr.attr, + NULL, }; +ATTRIBUTE_GROUPS(mt7996_hwmon); + +static int +mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7996_CDEV_THROTTLE_MAX; + + return 0; +} + +static int +mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7996_phy *phy = cdev->devdata; + + *state = phy->cdev_state; + + return 0; +} + +static int +mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7996_phy *phy = cdev->devdata; + u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state; + int ret; + + if (state > MT7996_CDEV_THROTTLE_MAX) { + dev_err(phy->dev->mt76.dev, + "please specify a valid throttling state\n"); + return -EINVAL; + } + + if (state == phy->cdev_state) + return 0; + + /* cooling_device convention: 0 = no cooling, more = more cooling + * mcu convention: 1 = max cooling, more = less cooling + */ + ret = mt7996_mcu_set_thermal_throttling(phy, throttling); + if (ret) + return ret; + + phy->cdev_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7996_thermal_ops = { + .get_max_state = mt7996_thermal_get_max_throttle_state, + .get_cur_state = mt7996_thermal_get_cur_throttle_state, + .set_cur_state = mt7996_thermal_set_cur_throttle_state, +}; + +static void mt7996_unregister_thermal(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + char name[sizeof("cooling_deviceXXX")]; + + if (!phy->cdev) + return; + + snprintf(name, sizeof(name), "cooling_device%d", phy->mt76->band_idx); + sysfs_remove_link(&wiphy->dev.kobj, name); + thermal_cooling_device_unregister(phy->cdev); +} + +static int mt7996_thermal_init(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + char cname[sizeof("cooling_deviceXXX")]; + struct thermal_cooling_device *cdev; + struct device *hwmon; + const char *name; + + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s.%d", + wiphy_name(wiphy), phy->mt76->band_idx); + snprintf(cname, sizeof(cname), "cooling_device%d", phy->mt76->band_idx); + + cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + cname) < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + + /* initialize critical/maximum high temperature */ + phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; + phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, + mt7996_hwmon_groups); + + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + + return 0; +} +#endif static void mt7996_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { struct mt7996_dev *dev; struct mt76_phy *mphy; u32 val; mphy = container_of(led_cdev, struct mt76_phy, leds.cdev); dev = container_of(mphy->dev, struct mt7996_dev, mt76); /* select TX blink mode, 2: only data frames */ - mt76_rmw_field(dev, MT_TMAC_TCR0(0), MT_TMAC_TCR0_TX_BLINK, 2); + mt76_rmw_field(dev, MT_TMAC_TCR0(mphy->band_idx), MT_TMAC_TCR0_TX_BLINK, 2); /* enable LED */ - mt76_wr(dev, MT_LED_EN(0), 1); + mt76_wr(dev, MT_LED_EN(mphy->band_idx), 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); + mt76_wr(dev, MT_LED_TX_BLINK(mphy->band_idx), val); + + /* turn LED off */ + if (delay_off == 0xff && delay_on == 0x0) { + val = MT_LED_CTRL_POLARITY | MT_LED_CTRL_KICK; + } else { + /* control LED */ + val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK; + if (mphy->band_idx == MT_BAND1) + val |= MT_LED_CTRL_BLINK_BAND_SEL; + } - /* control LED */ - val = MT_LED_CTRL_BLINK_MODE | MT_LED_CTRL_KICK; if (mphy->leds.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); + mt76_wr(dev, MT_LED_CTRL(mphy->band_idx), val); + mt76_clear(dev, MT_LED_CTRL(mphy->band_idx), MT_LED_CTRL_KICK); } static int mt7996_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); mt7996_led_set_config(led_cdev, delta_on, delta_off); return 0; } static void mt7996_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { if (!brightness) mt7996_led_set_config(led_cdev, 0, 0xff); else mt7996_led_set_config(led_cdev, 0xff, 0); } -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7996_init_txpower(struct mt7996_phy *phy, + struct ieee80211_supported_band *sband) { - int i, nss = hweight8(dev->mphy.antenna_mask); + struct mt7996_dev *dev = phy->dev; + int i, nss = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(nss); int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; for (i = 0; i < sband->n_channels; i++) { struct ieee80211_channel *chan = &sband->channels[i]; int target_power = mt7996_eeprom_get_target_power(dev, chan); target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; target_power = DIV_ROUND_UP(target_power, 2); chan->max_power = min_t(int, chan->max_reg_power, target_power); chan->orig_mpwr = target_power; } } +void mt7996_init_txpower(struct mt7996_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7996_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; - if (dev->mt76.region == NL80211_DFS_UNSET) - mt7996_mcu_rdd_background_enable(phy, NULL); + mt7996_for_each_phy(dev, phy) { + if (dev->mt76.region == NL80211_DFS_UNSET) + mt7996_mcu_rdd_background_enable(phy, NULL); + + mt7996_init_txpower(phy); + phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; + mt7996_dfs_init_radar_detector(phy); + } +} + +static void +mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy) +{ + struct mt7996_dev *dev = phy->dev; + struct wiphy *wiphy = hw->wiphy; + int n_radios = hw->wiphy->n_radio; + struct wiphy_radio_freq_range *freq = &dev->radio_freqs[n_radios]; + struct wiphy_radio *radio = &dev->radios[n_radios]; + + phy->slottime = 9; + phy->beacon_rate = -1; + + if (phy->mt76->cap.has_2ghz) { + phy->mt76->sband_2g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + phy->mt76->sband_2g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_2; + freq->start_freq = 2400000; + freq->end_freq = 2500000; + } else if (phy->mt76->cap.has_5ghz) { + phy->mt76->sband_5g.sband.ht_cap.cap |= + IEEE80211_HT_CAP_LDPC_CODING | + IEEE80211_HT_CAP_MAX_AMSDU; + + phy->mt76->sband_5g.sband.vht_cap.cap |= + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + phy->mt76->sband_5g.sband.ht_cap.ampdu_density = + IEEE80211_HT_MPDU_DENSITY_1; - mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband); + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + freq->start_freq = 5000000; + freq->end_freq = 5900000; + } else if (phy->mt76->cap.has_6ghz) { + freq->start_freq = 5900000; + freq->end_freq = 7200000; + } else { + return; + } + + dev->radio_phy[n_radios] = phy; + radio->freq_range = freq; + radio->n_freq_range = 1; + radio->iface_combinations = &if_comb; + radio->n_iface_combinations = 1; + hw->wiphy->n_radio++; - phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; - mt7996_dfs_init_radar_detector(phy); + wiphy->available_antennas_rx |= phy->mt76->chainmask; + wiphy->available_antennas_tx |= phy->mt76->chainmask; + + mt76_set_stream_caps(phy->mt76, true); + mt7996_set_stream_vht_txbf_caps(phy); + mt7996_set_stream_he_eht_caps(phy); + mt7996_init_txpower(phy); } static void -mt7996_init_wiphy(struct ieee80211_hw *hw) +mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_dev *dev = mt7996_hw_dev(hw); #if defined(CONFIG_OF) - struct mt76_dev *mdev = &phy->dev->mt76; + struct mt76_dev *mdev = &dev->mt76; #endif struct wiphy *wiphy = hw->wiphy; - u16 max_subframes = phy->dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT : - IEEE80211_MAX_AMPDU_BUF_HE; + u16 max_subframes = dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT : + IEEE80211_MAX_AMPDU_BUF_HE; hw->queues = 4; hw->max_rx_aggregation_subframes = max_subframes; hw->max_tx_aggregation_subframes = max_subframes; hw->netdev_features = NETIF_F_RXCSUM; + if (mtk_wed_device_active(wed)) + hw->netdev_features |= NETIF_F_HW_TC; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; - phy->slottime = 9; - hw->sta_data_size = sizeof(struct mt7996_sta); hw->vif_data_size = sizeof(struct mt7996_vif); + hw->chanctx_data_size = sizeof(struct mt76_chanctx); + + wiphy->iface_combinations = &if_comb_global; + wiphy->n_iface_combinations = 1; + + wiphy->radio = dev->radios; - wiphy->iface_combinations = if_comb; - wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); wiphy->reg_notifier = mt7996_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->mbssid_max_interfaces = 16; 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); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + if (mt7996_has_background_radar(dev) && #if defined(CONFIG_OF) - if (!mdev->dev->of_node || - !of_property_read_bool(mdev->dev->of_node, - "mediatek,disable-radar-background")) + (!mdev->dev->of_node || + !of_property_read_bool(mdev->dev->of_node, + "mediatek,disable-radar-background"))) +#else + 1) #endif wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RADAR_BACKGROUND); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); - ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); hw->max_tx_fragments = 4; - if (phy->mt76->cap.has_2ghz) { - phy->mt76->sband_2g.sband.ht_cap.cap |= - IEEE80211_HT_CAP_LDPC_CODING | - IEEE80211_HT_CAP_MAX_AMSDU; - phy->mt76->sband_2g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_2; + /* init led callbacks */ + if (IS_ENABLED(CONFIG_MT76_LEDS)) { + dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness; + dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink; } - if (phy->mt76->cap.has_5ghz) { - phy->mt76->sband_5g.sband.ht_cap.cap |= - IEEE80211_HT_CAP_LDPC_CODING | - IEEE80211_HT_CAP_MAX_AMSDU; - - phy->mt76->sband_5g.sband.vht_cap.cap |= - IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | - IEEE80211_VHT_CAP_SHORT_GI_160 | - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - phy->mt76->sband_5g.sband.ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_1; - - ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); - } + wiphy->max_scan_ssids = 4; + wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - mt76_set_stream_caps(phy->mt76, true); - mt7996_set_stream_vht_txbf_caps(phy); - mt7996_set_stream_he_eht_caps(phy); - - wiphy->available_antennas_rx = phy->mt76->antenna_mask; - wiphy->available_antennas_tx = phy->mt76->antenna_mask; + mt7996_init_wiphy_band(hw, &dev->phy); } static void mt7996_mac_init_band(struct mt7996_dev *dev, u8 band) { u32 mask, set; /* clear estimated value of EIFS for Rx duration & OBSS time */ mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR); /* clear backoff time for Rx duration */ mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band), MT_WF_RMAC_MIB_NONQOSD_BACKOFF); mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band), MT_WF_RMAC_MIB_QOS01_BACKOFF); mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band), MT_WF_RMAC_MIB_QOS23_BACKOFF); + /* clear backoff time for Tx duration */ + mt76_clear(dev, MT_WTBLOFF_ACR(band), + MT_WTBLOFF_ADM_BACKOFFTIME); + /* clear backoff time and set software compensation for OBSS time */ mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET; set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) | FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4); mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set); /* filter out non-resp frames and get instanstaeous signal reporting */ mask = MT_WTBLOFF_RSCR_RCPI_MODE | MT_WTBLOFF_RSCR_RCPI_PARAM; set = FIELD_PREP(MT_WTBLOFF_RSCR_RCPI_MODE, 0) | FIELD_PREP(MT_WTBLOFF_RSCR_RCPI_PARAM, 0x3); mt76_rmw(dev, MT_WTBLOFF_RSCR(band), mask, set); + + /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than + * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. + */ + mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H); } static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) { int i; for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) { u16 rate = mt76_rates[i].hw_value; - u16 idx = MT7996_BASIC_RATES_TBL + i; + /* odd index for driver, even index for firmware */ + u16 idx = MT7996_BASIC_RATES_TBL + 2 * i; rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) | FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0)); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); + mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false); } } void mt7996_mac_init(struct mt7996_dev *dev) { -#define HIF_TXD_V2_1 4 +#define HIF_TXD_V2_1 0x21 int i; mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); for (i = 0; i < mt7996_wtbl_size(dev); i++) mt7996_mac_wtbl_update(dev, i, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (IS_ENABLED(CONFIG_MT76_LEDS)) { i = dev->mphy.leds.pin ? MT_LED_GPIO_MUX3 : MT_LED_GPIO_MUX2; mt76_rmw_field(dev, i, MT_LED_GPIO_SEL_MASK, 4); } - /* txs report queue */ - mt76_rmw_field(dev, MT_DMA_TCRF1(0), MT_DMA_TCRF1_QIDX, 0); - mt76_rmw_field(dev, MT_DMA_TCRF1(1), MT_DMA_TCRF1_QIDX, 6); - mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0); - /* rro module init */ - mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + if (is_mt7996(&dev->mt76)) + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + else + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, + dev->hif2 ? 7 : 0); + + if (dev->has_rro) { + u16 timeout; + + timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; + mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); + } else { + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + } mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_HW_PATH_HIF_VER, HIF_TXD_V2_1, 0); for (i = MT_BAND0; i <= MT_BAND2; i++) mt7996_mac_init_band(dev, i); mt7996_mac_init_basic_rates(dev); } int mt7996_txbf_init(struct mt7996_dev *dev) { int ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1) || + mt7996_band_valid(dev, MT_BAND2)) { ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL); if (ret) return ret; } /* trigger sounding packets */ ret = mt7996_mcu_set_txbf(dev, BF_SOUNDING_ON); if (ret) return ret; /* enable eBF */ return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE); } -static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, - enum mt76_band_id band) +static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) { + struct mt7996_phy *phy; struct mt76_phy *mphy; u32 mac_ofs, hif1_ofs = 0; int ret; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (band != MT_BAND1 && band != MT_BAND2) + if (!mt7996_band_valid(dev, band)) return 0; - if ((band == MT_BAND1 && !dev->dbdc_support) || - (band == MT_BAND2 && !dev->tbtc_support)) - return 0; - - if (phy) - return 0; - - if (band == MT_BAND2 && dev->hif2) + if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + wed = &dev->mt76.mmio.wed_hif2; + } - mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); + mphy = mt76_alloc_radio_phy(&dev->mt76, sizeof(*phy), band); if (!mphy) return -ENOMEM; phy = mphy->priv; phy->dev = dev; phy->mt76 = mphy; mphy->dev->phys[band] = mphy; INIT_DELAYED_WORK(&mphy->mac_work, mt7996_mac_work); ret = mt7996_eeprom_parse_hw_cap(dev, phy); if (ret) goto error; mac_ofs = band == MT_BAND2 ? MT_EE_MAC_ADDR3 : MT_EE_MAC_ADDR2; #if defined(__linux__) memcpy(mphy->macaddr, dev->mt76.eeprom.data + mac_ofs, ETH_ALEN); #elif defined(__FreeBSD__) memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + mac_ofs, ETH_ALEN); #endif /* Make the extra PHY MAC address local without overlapping with * the usual MAC address allocation scheme on multiple virtual interfaces */ if (!is_valid_ether_addr(mphy->macaddr)) { #if defined(__linux__) memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #elif defined(__FreeBSD__) memcpy(mphy->macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, #endif ETH_ALEN); mphy->macaddr[0] |= 2; mphy->macaddr[0] ^= BIT(7); if (band == MT_BAND2) mphy->macaddr[0] ^= BIT(6); } mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7996_init_wiphy(mphy->hw); - ret = mt76_connac_init_tx_queues(phy->mt76, - MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, 0); + mt7996_init_wiphy_band(mphy->hw, phy); + ret = mt7996_init_tx_queues(mphy->priv, + MT_TXQ_ID(band), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(band) + hif1_ofs, + wed); if (ret) goto error; ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) goto error; - ret = mt7996_init_debugfs(phy); - if (ret) - goto error; + if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { + u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; + + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); + } return 0; error: mphy->dev->phys[band] = NULL; - ieee80211_free_hw(mphy->hw); return ret; } static void -mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) +mt7996_unregister_phy(struct mt7996_phy *phy) { - struct mt76_phy *mphy; - - if (!phy) - return; - - mphy = phy->dev->mt76.phys[band]; - mt76_unregister_phy(mphy); - ieee80211_free_hw(mphy->hw); - phy->dev->mt76.phys[band] = NULL; +#if defined(CONFIG_HWMON) + if (phy) + mt7996_unregister_thermal(phy); +#endif } static void mt7996_init_work(struct work_struct *work) { struct mt7996_dev *dev = container_of(work, struct mt7996_dev, init_work); mt7996_mcu_set_eeprom(dev); mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7996_txbf_init(dev); } void mt7996_wfsys_reset(struct mt7996_dev *dev) { mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); msleep(20); mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); msleep(20); } +static int mt7996_wed_rro_init(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; + struct mt7996_wed_rro_addr *addr; + void *ptr; + int i; + + if (!dev->has_rro) + return 0; + + if (!mtk_wed_device_active(wed)) + return 0; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + &dev->wed_rro.ba_bitmap[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.ba_bitmap[i].ptr = ptr; + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + int j; + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr), + &dev->wed_rro.addr_elem[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.addr_elem[i].ptr = ptr; + memset(dev->wed_rro.addr_elem[i].ptr, 0, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr)); + + addr = dev->wed_rro.addr_elem[i].ptr; + for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { + addr->signature = 0xff; + addr++; + } + + wed->wlan.ind_cmd.addr_elem_phys[i] = + dev->wed_rro.addr_elem[i].phy_addr; + } + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), + &dev->wed_rro.session.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.session.ptr = ptr; + addr = dev->wed_rro.session.ptr; + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + addr->signature = 0xff; + addr++; + } + + /* rro hw init */ + /* TODO: remove line after WM has set */ + mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); + + /* setup BA bitmap cache address */ + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, + dev->wed_rro.ba_bitmap[0].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, + dev->wed_rro.ba_bitmap[1].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); + + /* setup Address element address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); + reg += 4; + } + + /* setup Address element address - separate address segment mode */ + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); + + wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; + wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; + wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; + + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); + + /* particular session configure */ + /* use max session idx + 1 as particular session id */ + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, + MT_RRO_PARTICULAR_CONFG_EN | + FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); + + /* interrupt enable */ + mt76_wr(dev, MT_RRO_HOST_INT_ENA, + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); + + /* rro ind cmd queue init */ + return mt7996_dma_rro_init(dev); +#else + return 0; +#endif +} + +static void mt7996_wed_rro_free(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + int i; + + if (!dev->has_rro) + return; + + if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) + return; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + if (!dev->wed_rro.ba_bitmap[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + dev->wed_rro.ba_bitmap[i].ptr, + dev->wed_rro.ba_bitmap[i].phy_addr); + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + if (!dev->wed_rro.addr_elem[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.addr_elem[i].ptr, + dev->wed_rro.addr_elem[i].phy_addr); + } + + if (!dev->wed_rro.session.ptr) + return; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.session.ptr, + dev->wed_rro.session.phy_addr); +#endif +} + +static void mt7996_wed_rro_work(struct work_struct *work) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mt7996_dev *dev; + LIST_HEAD(list); + + dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev, + wed_rro.work); + + spin_lock_bh(&dev->wed_rro.lock); + list_splice_init(&dev->wed_rro.poll_list, &list); + spin_unlock_bh(&dev->wed_rro.lock); + + while (!list_empty(&list)) { + struct mt7996_wed_rro_session_id *e; + int i; + + e = list_first_entry(&list, struct mt7996_wed_rro_session_id, + list); + list_del_init(&e->list); + + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + void *ptr = dev->wed_rro.session.ptr; + struct mt7996_wed_rro_addr *elem; + u32 idx, elem_id = i; + + if (e->id == MT7996_RRO_MAX_SESSION) + goto reset; + + idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE; + if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem)) + goto out; + + ptr = dev->wed_rro.addr_elem[idx].ptr; + elem_id += + (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) * + MT7996_RRO_WINDOW_MAX_LEN; +reset: + elem = ptr + elem_id * sizeof(*elem); + elem->signature = 0xff; + } + mt7996_mcu_wed_rro_reset_sessions(dev, e->id); +out: + kfree(e); + } +#endif +} + +static int mt7996_variant_type_init(struct mt7996_dev *dev) +{ + u32 val = mt76_rr(dev, MT_PAD_GPIO); + u8 var_type; + + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + if (val & MT_PAD_GPIO_2ADIE_TBTC) + var_type = MT7996_VAR_TYPE_233; + else + var_type = MT7996_VAR_TYPE_444; + break; + case 0x7992: + if (val & MT_PAD_GPIO_ADIE_SINGLE) + var_type = MT7992_VAR_TYPE_23; + else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) + var_type = MT7992_VAR_TYPE_44; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + dev->var.type = var_type; + return 0; +} + +static int mt7996_variant_fem_init(struct mt7996_dev *dev) +{ +#define MT7976C_EFUSE_OFFSET 0x470 + u8 buf[MT7996_EEPROM_BLOCK_SIZE], idx, adie_idx, adie_comb; + u32 regval, val = mt76_rr(dev, MT_PAD_GPIO); + u16 adie_id, adie_ver; + bool is_7976c; + int ret; + + if (is_mt7992(&dev->mt76)) { + adie_idx = (val & MT_PAD_GPIO_ADIE_SINGLE) ? 0 : 1; + adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992); + } else { + adie_idx = 0; + adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB); + } + + ret = mt7996_mcu_rf_regval(dev, MT_ADIE_CHIP_ID(adie_idx), ®val, false); + if (ret) + return ret; + + ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf)); + if (ret && ret != -EINVAL) + return ret; + + adie_ver = u32_get_bits(regval, MT_ADIE_VERSION_MASK); + idx = MT7976C_EFUSE_OFFSET % MT7996_EEPROM_BLOCK_SIZE; + is_7976c = adie_ver == 0x8a10 || adie_ver == 0x8b00 || + adie_ver == 0x8c10 || buf[idx] == 0xc; + + adie_id = u32_get_bits(regval, MT_ADIE_CHIP_ID_MASK); + if (adie_id == 0x7975 || adie_id == 0x7979 || + (adie_id == 0x7976 && is_7976c)) + dev->var.fem = MT7996_FEM_INT; + else if (adie_id == 0x7977 && adie_comb == 1) + dev->var.fem = MT7996_FEM_MIX; + else + dev->var.fem = MT7996_FEM_EXT; + + return 0; +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + if (is_mt7992(&dev->mt76)) { + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + } INIT_WORK(&dev->init_work, mt7996_init_work); + INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); + INIT_LIST_HEAD(&dev->wed_rro.poll_list); + spin_lock_init(&dev->wed_rro.lock); - dev->dbdc_support = true; - dev->tbtc_support = true; + ret = mt7996_variant_type_init(dev); + if (ret) + return ret; ret = mt7996_dma_init(dev); if (ret) return ret; set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); ret = mt7996_mcu_init(dev); if (ret) return ret; + ret = mt7996_wed_rro_init(dev); + if (ret) + return ret; + + ret = mt7996_variant_fem_init(dev); + if (ret) + return ret; + ret = mt7996_eeprom_init(dev); if (ret < 0) return ret; /* Beacon and mgmt frames should occupy wcid 0 */ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); if (idx) return -ENOSPC; dev->mt76.global_wcid.idx = idx; dev->mt76.global_wcid.hw_key_idx = -1; dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET; rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); return 0; } void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy) { int sts; u32 *cap; if (!phy->mt76->cap.has_5ghz) return; sts = hweight16(phy->mt76->chainmask); cap = &phy->mt76->sband_5g.sband.vht_cap.cap; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | - FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1); + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if (is_mt7996(phy->mt76->dev)) + *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 3); + else + *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 4); *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); if (sts < 2) return; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, sts - 1); } static void mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy, - struct ieee80211_sta_he_cap *he_cap, int vif) + struct ieee80211_sta_he_cap *he_cap, int vif, + enum nl80211_band band) { struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; int sts = hweight16(phy->mt76->chainmask); + bool non_2g = band != NL80211_BAND_2GHZ; u8 c; #ifdef CONFIG_MAC80211_MESH if (vif == NL80211_IFTYPE_MESH_POINT) return; #endif elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; elem->phy_cap_info[5] &= ~c; c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] &= ~c; elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; elem->phy_cap_info[2] |= c; - c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; + + if (is_mt7996(phy->mt76->dev)) + c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | + (IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 * non_2g); + else + c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 | + (IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 * non_2g); + elem->phy_cap_info[4] |= c; /* do not support NG16 due to spec D4.0 changes subcarrier idx */ c = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU; if (vif == NL80211_IFTYPE_STATION) c |= IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; elem->phy_cap_info[6] |= c; if (sts < 2) return; /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; - if (vif != NL80211_IFTYPE_AP) + if (!(vif == NL80211_IFTYPE_AP || vif == NL80211_IFTYPE_STATION)) return; elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; - elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, sts - 1) | - FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, - sts - 1); + (FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, + sts - 1) * non_2g); + elem->phy_cap_info[5] |= c; + if (vif != NL80211_IFTYPE_AP) + return; + + elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; elem->phy_cap_info[6] |= c; - c = IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | - IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; + c = 0; + if (non_2g) + c |= IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; elem->phy_cap_info[7] |= c; } static void mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data, enum nl80211_iftype iftype) { struct ieee80211_sta_he_cap *he_cap = &data->he_cap; struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp; int i, nss = hweight8(phy->mt76->antenna_mask); u16 mcs_map = 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)); } he_cap->has_he = true; he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; else he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; he_cap_elem->phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + he_cap_elem->phy_cap_info[7] = + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + switch (iftype) { 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] |= IEEE80211_HE_MAC_CAP4_BQR; he_cap_elem->mac_cap_info[5] |= IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; he_cap_elem->phy_cap_info[3] |= 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] |= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G; else he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; he_cap_elem->phy_cap_info[1] |= IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; he_cap_elem->phy_cap_info[3] |= 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_TRIG_CQI_FB | IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; he_cap_elem->phy_cap_info[7] |= - IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; break; default: break; } 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); - mt7996_set_stream_he_txbf_caps(phy, he_cap, iftype); + mt7996_set_stream_he_txbf_caps(phy, he_cap, iftype, band); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { - mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss); + mt76_connac_gen_ppe_thresh(he_cap->ppe_thres, nss, band); } else { he_cap_elem->phy_cap_info[9] |= u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); } if (band == NL80211_BAND_6GHZ) { u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); data->he_6ghz_capa.capa = cpu_to_le16(cap); } } static void mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data, enum nl80211_iftype iftype) { struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; struct ieee80211_eht_mcs_nss_supp *eht_nss = &eht_cap->eht_mcs_nss_supp; enum nl80211_chan_width width = phy->mt76->chandef.width; int nss = hweight8(phy->mt76->antenna_mask); int sts = hweight16(phy->mt76->chainmask); u8 val; if (!phy->dev->has_eht) return; eht_cap->has_eht = true; eht_cap_elem->mac_cap_info[0] = IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | - IEEE80211_EHT_MAC_CAP0_OM_CONTROL; + IEEE80211_EHT_MAC_CAP0_OM_CONTROL | + u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, + IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); eht_cap_elem->phy_cap_info[0] = - IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + /* Set the maximum capability regardless of the antenna configuration. */ + val = is_mt7992(phy->mt76->dev) ? 4 : 3; eht_cap_elem->phy_cap_info[0] |= - u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + u8_encode_bits(u8_get_bits(val, BIT(0)), IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); eht_cap_elem->phy_cap_info[1] = - u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)), - IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) | - u8_encode_bits(sts - 1, - IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK) | - u8_encode_bits(sts - 1, - IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); + u8_encode_bits(u8_get_bits(val, GENMASK(2, 1)), + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK); eht_cap_elem->phy_cap_info[2] = - u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) | - u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK) | - u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK); + u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK); + + if (band != NL80211_BAND_2GHZ) { + eht_cap_elem->phy_cap_info[1] |= + u8_encode_bits(val, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); + + eht_cap_elem->phy_cap_info[2] |= + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK); + } + + if (band == NL80211_BAND_6GHZ) { + eht_cap_elem->phy_cap_info[0] |= + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + + eht_cap_elem->phy_cap_info[1] |= + u8_encode_bits(val, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); + + eht_cap_elem->phy_cap_info[2] |= + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK); + } eht_cap_elem->phy_cap_info[3] = IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | - IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK; + IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK; eht_cap_elem->phy_cap_info[4] = + IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI | u8_encode_bits(min_t(int, sts - 1, 2), IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK); eht_cap_elem->phy_cap_info[5] = - IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US, IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK) | - u8_encode_bits(u8_get_bits(0x11, GENMASK(1, 0)), + u8_encode_bits(u8_get_bits(1, GENMASK(1, 0)), IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK); val = width == NL80211_CHAN_WIDTH_320 ? 0xf : width == NL80211_CHAN_WIDTH_160 ? 0x7 : width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1; eht_cap_elem->phy_cap_info[6] = - u8_encode_bits(u8_get_bits(0x11, GENMASK(4, 2)), - IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK) | u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK); - eht_cap_elem->phy_cap_info[7] = - IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | - IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | - IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | - IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | - IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | - IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ; - val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) | u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX); #define SET_EHT_MAX_NSS(_bw, _val) do { \ eht_nss->bw._##_bw.rx_tx_mcs9_max_nss = _val; \ eht_nss->bw._##_bw.rx_tx_mcs11_max_nss = _val; \ eht_nss->bw._##_bw.rx_tx_mcs13_max_nss = _val; \ } while (0) SET_EHT_MAX_NSS(80, val); SET_EHT_MAX_NSS(160, val); - SET_EHT_MAX_NSS(320, val); + if (band == NL80211_BAND_6GHZ) + SET_EHT_MAX_NSS(320, val); #undef SET_EHT_MAX_NSS + + if (iftype != NL80211_IFTYPE_AP) + return; + + eht_cap_elem->phy_cap_info[3] |= + IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK; + + eht_cap_elem->phy_cap_info[7] = + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ; + + if (band == NL80211_BAND_2GHZ) + return; + + eht_cap_elem->phy_cap_info[7] |= + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ; + + if (band != NL80211_BAND_6GHZ) + return; + + eht_cap_elem->phy_cap_info[7] |= + IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ | + IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ; } static void __mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy, struct ieee80211_supported_band *sband, enum nl80211_band band) { struct ieee80211_sband_iftype_data *data = phy->iftype[band]; int i, n = 0; for (i = 0; i < NUM_NL80211_IFTYPES; i++) { switch (i) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: #endif break; default: continue; } data[n].types_mask = BIT(i); mt7996_init_he_caps(phy, band, &data[n], i); mt7996_init_eht_caps(phy, band, &data[n], i); n++; } - sband->iftype_data = data; - sband->n_iftype_data = n; + _ieee80211_set_sband_iftype_data(sband, data, n); } void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy) { if (phy->mt76->cap.has_2ghz) __mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_2g.sband, NL80211_BAND_2GHZ); if (phy->mt76->cap.has_5ghz) __mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_5g.sband, NL80211_BAND_5GHZ); if (phy->mt76->cap.has_6ghz) __mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_6g.sband, NL80211_BAND_6GHZ); } int mt7996_register_device(struct mt7996_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); +#if defined(CONFIG_HWMON) + struct mt7996_phy *phy; +#endif int ret; dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work); INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work); INIT_LIST_HEAD(&dev->sta_rc_list); INIT_LIST_HEAD(&dev->twt_list); init_waitqueue_head(&dev->reset_wait); INIT_WORK(&dev->reset_work, mt7996_mac_reset_work); INIT_WORK(&dev->dump_work, mt7996_mac_dump_work); mutex_init(&dev->dump_mutex); ret = mt7996_init_hardware(dev); if (ret) return ret; - mt7996_init_wiphy(hw); + mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); - /* init led callbacks */ - if (IS_ENABLED(CONFIG_MT76_LEDS)) { - dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness; - dev->mphy.leds.cdev.blink_set = mt7996_led_set_blink; - } + ret = mt7996_register_phy(dev, MT_BAND1); + if (ret) + return ret; + + ret = mt7996_register_phy(dev, MT_BAND2); + if (ret) + return ret; ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) return ret; +#if defined(CONFIG_HWMON) + mt7996_for_each_phy(dev, phy) + mt7996_thermal_init(phy); +#endif + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); - ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); + dev->recovery.hw_init_done = true; + +#if defined(CONFIG_MT7996_DEBUGFS) + ret = mt7996_init_debugfs(dev); if (ret) - return ret; + goto error; +#endif - ret = mt7996_register_phy(dev, mt7996_phy3(dev), MT_BAND2); + ret = mt7996_coredump_register(dev); if (ret) - return ret; + goto error; - dev->recovery.hw_init_done = true; + return 0; - ret = mt7996_init_debugfs(&dev->phy); - if (ret) - return ret; +error: + cancel_work_sync(&dev->init_work); - return mt7996_coredump_register(dev); + return ret; } void mt7996_unregister_device(struct mt7996_dev *dev) { - mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); - mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); + cancel_work_sync(&dev->wed_rro.work); + mt7996_unregister_phy(mt7996_phy3(dev)); + mt7996_unregister_phy(mt7996_phy2(dev)); +#if defined(CONFIG_HWMON) + mt7996_unregister_thermal(&dev->phy); +#endif mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); + mt7996_wed_rro_free(dev); mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); tasklet_disable(&dev->mt76.irq_tasklet); mt76_free_device(&dev->mt76); } diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c index 33ab7b6b2985..3f1536f2bbe7 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mac.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mac.c @@ -1,2546 +1,2695 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include #include "coredump.h" #include "mt7996.h" #include "../dma.h" #include "mac.h" #include "mcu.h" #if defined(__FreeBSD__) #include #endif #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) static const struct mt7996_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, }, }; static const struct mt7996_dfs_radar_spec fcc_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, }, }; static const struct mt7996_dfs_radar_spec jp_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, .radar_pattern = { [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, }, }; static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, u16 idx, bool unicast) { struct mt7996_sta *sta; struct mt76_wcid *wcid; if (idx >= ARRAY_SIZE(dev->mt76.wcid)) return NULL; wcid = rcu_dereference(dev->mt76.wcid[idx]); if (unicast || !wcid) return wcid; if (!wcid->sta) return NULL; sta = container_of(wcid, struct mt7996_sta, wcid); if (!sta->vif) return NULL; - return &sta->vif->sta.wcid; + return &sta->vif->deflink.sta.wcid; } bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask) { mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); } u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_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, dw); } static void mt7996_mac_sta_poll(struct mt7996_dev *dev) { static const u8 ac_to_tid[] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 4, [IEEE80211_AC_VO] = 6 }; struct ieee80211_sta *sta; struct mt7996_sta *msta; - struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); int i; spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); rcu_read_lock(); while (true) { bool clear = false; u32 addr, val; u16 idx; s8 rssi[4]; - u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { spin_unlock_bh(&dev->mt76.sta_poll_lock); break; } msta = list_first_entry(&sta_poll_list, struct mt7996_sta, wcid.poll_list); list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); idx = msta->wcid.idx; /* refresh peer's airtime reporting */ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u32 tx_last = msta->airtime_ac[i]; u32 rx_last = msta->airtime_ac[i + 4]; msta->airtime_ac[i] = mt76_rr(dev, addr); msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); tx_time[i] = msta->airtime_ac[i] - tx_last; rx_time[i] = msta->airtime_ac[i + 4] - rx_last; if ((tx_last | rx_last) & BIT(30)) clear = true; addr += 8; } if (clear) { mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); } if (!msta->wcid.sta) continue; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < IEEE80211_NUM_ACS; i++) { u8 q = mt76_connac_lmac_mapping(i); u32 tx_cur = tx_time[q]; u32 rx_cur = rx_time[q]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) continue; 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; - - switch (rate->bw) { - case RATE_INFO_BW_320: - bw = IEEE80211_STA_RX_BW_320; - break; - 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; - } - - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6); - val = mt76_rr(dev, addr); - if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5); - val = mt76_rr(dev, addr); - rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); - } else 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; - } - /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); val = mt76_rr(dev, addr); rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); rssi[3] = to_rssi(GENMASK(31, 14), val); msta->ack_signal = - mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); + mt76_rx_signal(msta->vif->deflink.phy->mt76->antenna_mask, rssi); ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); } rcu_read_unlock(); } void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, struct ieee80211_vif *vif, bool enable) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; u32 addr; - addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); + addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->deflink.sta.wcid.idx, 5); if (enable) mt76_set(dev, addr, BIT(5)); else mt76_clear(dev, addr, BIT(5)); } -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx) -{ - u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; - - mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); - /* use wtbl spe idx */ - mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); - mt76_wr(dev, MT_WTBL_ITCR, ctrl); -} - /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid; __le32 *rxd = (__le32 *)skb->data; struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct ieee80211_hdr hdr; u16 frame_control; if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) != MT_RXD3_NORMAL_U2M) return -EINVAL; if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4)) return -EINVAL; if (!msta || !msta->vif) return -EINVAL; sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); /* store the info from RXD and ethhdr to avoid being overridden */ frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL); hdr.frame_control = cpu_to_le16(frame_control); hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL)); hdr.duration_id = 0; ether_addr_copy(hdr.addr1, vif->addr); ether_addr_copy(hdr.addr2, sta->addr); switch (frame_control & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case 0: ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); break; case IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_source); break; case IEEE80211_FCTL_TODS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); break; case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_dest); ether_addr_copy(hdr.addr4, eth_hdr->h_source); break; default: return -EINVAL; } skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2); if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) || eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX)) ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header); else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN) ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header); else skb_pull(skb, 2); if (ieee80211_has_order(hdr.frame_control)) memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11], IEEE80211_HT_CTL_LEN); if (ieee80211_is_data_qos(hdr.frame_control)) { __le16 qos_ctrl; qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL)); memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl, IEEE80211_QOS_CTL_LEN); } if (ieee80211_has_a4(hdr.frame_control)) memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr)); else memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6); return 0; } static int mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, struct mt76_rx_status *status, struct ieee80211_supported_band *sband, __le32 *rxv, u8 *mode) { u32 v0, v2; u8 stbc, gi, bw, dcm, nss; int i, idx; bool cck = false; v0 = le32_to_cpu(rxv[0]); v2 = le32_to_cpu(rxv[2]); idx = FIELD_GET(MT_PRXV_TX_RATE, v0); i = idx; nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1; stbc = FIELD_GET(MT_PRXV_HT_STBC, v2); gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2); *mode = FIELD_GET(MT_PRXV_TX_MODE, v2); dcm = FIELD_GET(MT_PRXV_DCM, v2); bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2); switch (*mode) { case MT_PHY_TYPE_CCK: cck = true; fallthrough; case MT_PHY_TYPE_OFDM: i = mt76_get_rate(&dev->mt76, sband, i, cck); break; case MT_PHY_TYPE_HT_GF: case MT_PHY_TYPE_HT: status->encoding = RX_ENC_HT; if (gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (i > 31) return -EINVAL; break; case MT_PHY_TYPE_VHT: status->nss = nss; status->encoding = RX_ENC_VHT; if (gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; if (i > 11) return -EINVAL; break; case MT_PHY_TYPE_HE_MU: case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: case MT_PHY_TYPE_HE_TB: status->nss = nss; status->encoding = RX_ENC_HE; i &= GENMASK(3, 0); if (gi <= NL80211_RATE_INFO_HE_GI_3_2) status->he_gi = gi; status->he_dcm = dcm; break; case MT_PHY_TYPE_EHT_SU: case MT_PHY_TYPE_EHT_TRIG: case MT_PHY_TYPE_EHT_MU: status->nss = nss; status->encoding = RX_ENC_EHT; i &= GENMASK(3, 0); if (gi <= NL80211_RATE_INFO_EHT_GI_3_2) status->eht.gi = gi; break; default: return -EINVAL; } status->rate_idx = i; switch (bw) { case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: if (*mode & MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106; } else { status->bw = RATE_INFO_BW_40; } break; case IEEE80211_STA_RX_BW_80: status->bw = RATE_INFO_BW_80; break; case IEEE80211_STA_RX_BW_160: status->bw = RATE_INFO_BW_160; break; + /* rxv reports bw 320-1 and 320-2 separately */ case IEEE80211_STA_RX_BW_320: + case IEEE80211_STA_RX_BW_320 + 1: status->bw = RATE_INFO_BW_320; break; default: return -EINVAL; } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; if (*mode < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; return 0; } +static void +mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q, + struct mt7996_sta *msta, struct sk_buff *skb, + u32 info) +{ + struct ieee80211_vif *vif; + struct wireless_dev *wdev; + + if (!msta || !msta->vif) + return; + + if (!mt76_queue_is_wed_rx(q)) + return; + + if (!(info & MT_DMA_INFO_PPE_VLD)) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + wdev = ieee80211_vif_to_wdev(vif); + skb->dev = wdev->netdev; + + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), + FIELD_GET(MT_DMA_PPE_ENTRY, info)); +} + static int -mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) +mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7996_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; __le32 *rxd = (__le32 *)skb->data; __le32 *rxv = NULL; u32 rxd0 = le32_to_cpu(rxd[0]); u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); u32 rxd4 = le32_to_cpu(rxd[4]); - u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM; + u32 csum_mask = MT_RXD3_NORMAL_IP_SUM | MT_RXD3_NORMAL_UDP_TCP_SUM; u32 csum_status = *(u32 *)skb->cb; u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP; bool is_mesh = (rxd0 & mesh_mask) == mesh_mask; bool unicast, insert_ccmp_hdr = false; u8 remove_pad, amsdu_info, band_idx; u8 mode = 0, qos_ctl = 0; bool hdr_trans; u16 hdr_gap; u16 seq_ctrl = 0; __le16 fc = 0; int idx; + u8 hw_aggr = false; + struct mt7996_sta *msta = NULL; + hw_aggr = status->aggr; memset(status, 0, sizeof(*status)); band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); mphy = dev->mt76.phys[band_idx]; phy = mphy->priv; status->phy_idx = mphy->band_idx; if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) return -EINVAL; if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR) return -EINVAL; hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS; if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM)) return -EINVAL; /* ICV error or CCMP/BIP/WPI MIC error */ if (rxd1 & MT_RXD1_NORMAL_ICV_ERR) status->flag |= RX_FLAG_ONLY_MONITOR; unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M; idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1); status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7996_sta *msta; - msta = container_of(status->wcid, struct mt7996_sta, wcid); - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); } status->freq = mphy->chandef.chan->center_freq; status->band = mphy->chandef.chan->band; if (status->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (status->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.sband; else sband = &mphy->sband_2g.sband; if (!sband->channels) return -EINVAL; - if ((rxd0 & csum_mask) == csum_mask && + if ((rxd3 & csum_mask) == csum_mask && !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) status->flag |= RX_FLAG_MMIC_ERROR; if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 && !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_IV_STRIPPED; status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2); if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) return -EINVAL; rxd += 8; if (rxd1 & MT_RXD1_NORMAL_GROUP_4) { u32 v0 = le32_to_cpu(rxd[0]); u32 v2 = le32_to_cpu(rxd[2]); fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0)); qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2); seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2); rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_1) { u8 *data = (u8 *)rxd; if (status->flag & RX_FLAG_DECRYPTED) { switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) { case MT_CIPHER_AES_CCMP: case MT_CIPHER_CCMP_CCX: case MT_CIPHER_CCMP_256: insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2); fallthrough; case MT_CIPHER_TKIP: case MT_CIPHER_TKIP_NO_MIC: case MT_CIPHER_GCMP: case MT_CIPHER_GCMP_256: status->iv[0] = data[5]; status->iv[1] = data[4]; status->iv[2] = data[3]; status->iv[3] = data[2]; status->iv[4] = data[1]; status->iv[5] = data[0]; break; default: break; } } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } if (rxd1 & MT_RXD1_NORMAL_GROUP_2) { status->timestamp = le32_to_cpu(rxd[0]); status->flag |= RX_FLAG_MACTIME_START; if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) { status->flag |= RX_FLAG_AMPDU_DETAILS; /* all subframes of an A-MPDU have the same timestamp */ if (phy->rx_ampdu_ts != status->timestamp) { if (!++phy->ampdu_ref) phy->ampdu_ref++; } phy->rx_ampdu_ts = status->timestamp; status->ampdu_ref = phy->ampdu_ref; } rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } /* RXD Group 3 - P-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { u32 v3; int ret; rxv = rxd; rxd += 4; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; v3 = le32_to_cpu(rxv[3]); status->chains = mphy->antenna_mask; status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3); status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3); /* RXD Group 5 - C-RXV */ if (rxd1 & MT_RXD1_NORMAL_GROUP_5) { rxd += 24; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; } ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode); if (ret < 0) return ret; } amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); status->amsdu = !!amsdu_info; if (status->amsdu) { status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME; status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; } hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap)) return -EINVAL; hdr_trans = false; } else { int pad_start = 0; skb_pull(skb, hdr_gap); if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) { pad_start = ieee80211_get_hdrlen_from_skb(skb); } else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) { /* When header translation failure is indicated, * the hardware will insert an extra 2-byte field * containing the data length after the protocol * type field. This happens either when the LLC-SNAP * pattern did not match, or if a VLAN header was * detected. */ pad_start = 12; if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) pad_start += 4; else pad_start = 0; } if (pad_start) { memmove(skb->data + 2, skb->data, pad_start); skb_pull(skb, 2); } } if (!hdr_trans) { struct ieee80211_hdr *hdr; if (insert_ccmp_hdr) { u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1); mt76_insert_ccmp_hdr(skb, key_id); } hdr = mt76_skb_get_hdr(skb); fc = hdr->frame_control; if (ieee80211_is_data_qos(fc)) { u8 *qos = ieee80211_get_qos_ctl(hdr); seq_ctrl = le16_to_cpu(hdr->seq_ctrl); qos_ctl = *qos; /* Mesh DA/SA/Length will be stripped after hardware * de-amsdu, so here needs to clear amsdu present bit * to mark it as a normal mesh frame. */ if (ieee80211_has_a4(fc) && is_mesh && status->amsdu) *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; } + skb_set_mac_header(skb, (unsigned char *)hdr - skb->data); } else { status->flag |= RX_FLAG_8023; + mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, + *info); } - if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) - mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); + if (rxv && !(status->flag & RX_FLAG_8023)) { + switch (status->encoding) { + case RX_ENC_EHT: + mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode); + break; + case RX_ENC_HE: + mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); + break; + default: + break; + } + } - if (!status->wcid || !ieee80211_is_data_qos(fc)) + if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) return 0; status->aggr = unicast && !ieee80211_is_qos_nullfunc(fc); status->qos_ctl = qos_ctl; status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl); return 0; } static void mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid) { u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; u8 fc_type, fc_stype; u16 ethertype; bool wmm = false; u32 val; if (wcid->sta) { struct ieee80211_sta *sta; sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); wmm = sta->wme; } val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) | FIELD_PREP(MT_TXD1_TID, tid); ethertype = get_unaligned_be16(&skb->data[12]); if (ethertype >= ETH_P_802_3_MIN) val |= MT_TXD1_ETH_802_3; txwi[1] |= cpu_to_le32(val); fc_type = IEEE80211_FTYPE_DATA >> 2; fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0; val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); txwi[2] |= cpu_to_le32(val); + + if (wcid->amsdu) + txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU); } static void mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct ieee80211_key_conf *key) { 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; + __le16 fc = hdr->frame_control, sc = hdr->seq_ctrl; u8 fc_type, fc_stype; u32 val; if (ieee80211_is_action(fc) && mgmt->u.action.category == WLAN_CATEGORY_BACK && mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) tid = MT_TX_ADDBA; else if (ieee80211_is_mgmt(hdr->frame_control)) tid = MT_TX_NORMAL; val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, ieee80211_get_hdrlen_from_skb(skb) / 2) | FIELD_PREP(MT_TXD1_TID, tid); if (!ieee80211_is_data(fc) || multicast || info->flags & IEEE80211_TX_CTL_USE_MINRATE) val |= MT_TXD1_FIXED_RATE; if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) && key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { val |= MT_TXD1_BIP; txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME); } txwi[1] |= cpu_to_le32(val); fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype); + if (ieee80211_has_morefrags(fc) && ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_FIRST); + else if (ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_MID); + else if (!ieee80211_has_morefrags(fc) && !ieee80211_is_first_frag(sc)) + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_LAST); + else + val |= FIELD_PREP(MT_TXD2_FRAG, MT_TX_FRAG_NONE); + txwi[2] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast)); if (ieee80211_is_beacon(fc)) { txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT); txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); } if (info->flags & IEEE80211_TX_CTL_INJECTED) { - u16 seqno = le16_to_cpu(hdr->seq_ctrl); + u16 seqno = le16_to_cpu(sc); if (ieee80211_is_back_req(hdr->frame_control)) { struct ieee80211_bar *bar; bar = (struct ieee80211_bar *)skb->data; seqno = le16_to_cpu(bar->start_seq_num); } val = MT_TXD3_SN_VALID | FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); txwi[3] |= cpu_to_le32(val); txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); } } void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2; u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; - struct mt76_vif *mvif; + struct mt76_vif_link *mvif; u16 tx_count = 15; u32 val; - bool beacon = !!(changed & (BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED)); bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); + bool beacon = !!(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); - mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL; + mvif = vif ? (struct mt76_vif_link *)vif->drv_priv : NULL; if (mvif) { omac_idx = mvif->omac_idx; wmm_idx = mvif->wmm_idx; band_idx = mvif->band_idx; } if (inband_disc) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_ALTX0; } else if (beacon) { p_fmt = MT_TX_TYPE_FW; q_idx = MT_LMAC_BCN0; } else if (qid >= MT_TXQ_PSD) { p_fmt = MT_TX_TYPE_CT; q_idx = MT_LMAC_ALTX0; } else { p_fmt = MT_TX_TYPE_CT; q_idx = wmm_idx * MT7996_MAX_WMM_SETS + mt76_connac_lmac_mapping(skb_get_queue_mapping(skb)); } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txwi[0] = cpu_to_le32(val); val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); if (band_idx) val |= FIELD_PREP(MT_TXD1_TGID, band_idx); txwi[1] = cpu_to_le32(val); txwi[2] = 0; val = MT_TXD3_SW_POWER_MGMT | FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); if (key) val |= MT_TXD3_PROTECT_FRAME; if (info->flags & IEEE80211_TX_CTL_NO_ACK) val |= MT_TXD3_NO_ACK; - if (wcid->amsdu) - val |= MT_TXD3_HW_AMSDU; txwi[3] = cpu_to_le32(val); txwi[4] = 0; val = FIELD_PREP(MT_TXD5_PID, pid); if (pid >= MT_PACKET_ID_FIRST) val |= MT_TXD5_TX_STATUS_HOST; txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | - FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + val = MT_TXD6_DIS_MAT | MT_TXD6_DAS; + if (is_mt7996(&dev->mt76)) + val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + else if (is_8023 || !ieee80211_is_mgmt(hdr->frame_control)) + val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1); + txwi[6] = cpu_to_le32(val); txwi[7] = 0; if (is_8023) mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid); else mt7996_mac_write_txwi_80211(dev, txwi, skb, key); if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; bool mcast = ieee80211_is_data(hdr->frame_control) && is_multicast_ether_addr(hdr->addr1); u8 idx = MT7996_BASIC_RATES_TBL; if (mvif) { if (mcast && mvif->mcast_rates_idx) idx = mvif->mcast_rates_idx; else if (beacon && mvif->beacon_rates_idx) idx = mvif->beacon_rates_idx; else idx = mvif->basic_rates_idx; } - txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW; + txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } int mt7996_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 ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; struct mt76_connac_txp_common *txp; struct mt76_txwi_cache *t; int id, i, pid, nbuf = tx_info->nbuf - 1; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u8 *txwi = (u8 *)txwi_ptr; if (unlikely(tx_info->skb->len <= ETH_HLEN)) return -EINVAL; if (!wcid) wcid = &dev->mt76.global_wcid; - if (sta) { - struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - - if (time_after(jiffies, msta->jiffies + HZ / 4)) { - info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; - msta->jiffies = jiffies; - } - } - 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; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, pid, qid, 0); txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { + u16 len; + + len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + len |= FIELD_PREP(MT_TXP_DMA_ADDR_H, + tx_info->buf[i + 1].addr >> 32); +#endif + txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); - txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + txp->fw.len[i] = cpu_to_le16(len); } txp->fw.nbuf = nbuf; txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD); if (!key) txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control)) txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); if (vif) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - txp->fw.bss_idx = mvif->mt76.idx; + txp->fw.bss_idx = mvif->deflink.mt76.idx; } txp->fw.token = cpu_to_le16(id); - if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) - txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx); - else - txp->fw.rept_wds_wcid = cpu_to_le16(0xfff); - tx_info->skb = DMA_DUMMY_DATA; + txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff); + + tx_info->skb = NULL; /* pass partial skb header to fw */ tx_info->buf[1].len = MT_CT_PARSE_LEN; tx_info->buf[1].skip_unmap = true; tx_info->nbuf = MT_CT_DMA_BUF_NUM; return 0; } +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) +{ +#if defined(__linux__) + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; +#elif defined(__FreeBSD__) + struct mt76_connac_fw_txp *txp = (void *)((u8 *)ptr + MT_TXD_SIZE); +#endif + __le32 *txwi = ptr; + u32 val; + + memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); + txwi[0] = cpu_to_le32(val); + + val = BIT(31) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); + txwi[1] = cpu_to_le32(val); + + txp->token = cpu_to_le16(token_id); + txp->nbuf = 1; + txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); + + return MT_TXD_SIZE + sizeof(*txp); +} + static void -mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) +mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) { struct mt7996_sta *msta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; u16 fc, tid; - u32 val; if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) return; - tid = le32_get_bits(txwi[1], MT_TXD1_TID); + tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; if (tid >= 6) /* skip VO queue */ return; - val = le32_to_cpu(txwi[2]); - fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | - FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4; + if (is_8023) { + fc = IEEE80211_FTYPE_DATA | + (sta->wme ? IEEE80211_STYPE_QOS_DATA : IEEE80211_STYPE_DATA); + } else { + /* No need to get precise TID for Action/Management Frame, + * since it will not meet the following Frame Control + * condition anyway. + */ + + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + fc = le16_to_cpu(hdr->frame_control) & + (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); + } + if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; msta = (struct mt7996_sta *)sta->drv_priv; if (!test_and_set_bit(tid, &msta->wcid.ampdu_state)) ieee80211_start_tx_ba_session(sta, tid, 0); } static void mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_sta *sta, struct list_head *free_list) { struct mt76_dev *mdev = &dev->mt76; struct mt76_wcid *wcid; __le32 *txwi; u16 wcid_idx; mt76_connac_txp_skb_unmap(mdev, t); if (!t->skb) goto out; txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); if (sta) { wcid = (struct mt76_wcid *)sta->drv_priv; wcid_idx = wcid->idx; if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7996_tx_check_aggr(sta, txwi); + mt7996_tx_check_aggr(sta, t->skb); } else { - wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); + wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX); } __mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list); out: t->skb = NULL; mt76_put_txwi(mdev, t); } static void mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) { __le32 *tx_free = (__le32 *)data, *cur_info; struct mt76_dev *mdev = &dev->mt76; struct mt76_phy *phy2 = mdev->phys[MT_BAND1]; struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; LIST_HEAD(free_list); struct sk_buff *skb, *tmp; #if defined(__linux__) void *end = data + len; #elif defined(__FreeBSD__) void *end = (u8 *)data + len; #endif bool wake = false; u16 total, count = 0; /* 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); if (phy2) { mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false); mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false); } if (phy3) { mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false); mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false); } - if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4)) + if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 5)) return; total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT); for (cur_info = &tx_free[2]; count < total; cur_info++) { u32 msdu, info; u8 i; if (WARN_ON_ONCE((void *)cur_info >= end)) return; /* 1'b1: new wcid pair. * 1'b0: msdu_id with the same 'wcid pair' as above. */ info = le32_to_cpu(*cur_info); if (info & MT_TXFREE_INFO_PAIR) { struct mt7996_sta *msta; - struct mt76_wcid *wcid; u16 idx; idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); wcid = rcu_dereference(dev->mt76.wcid[idx]); sta = wcid_to_sta(wcid); if (!sta) continue; msta = container_of(wcid, struct mt7996_sta, wcid); - spin_lock_bh(&mdev->sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, - &mdev->sta_poll_list); - spin_unlock_bh(&mdev->sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); continue; - } + } else if (info & MT_TXFREE_INFO_HEADER) { + u32 tx_retries = 0, tx_failed = 0; + + if (!wcid) + continue; + + tx_retries = + FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1; + tx_failed = tx_retries + + !!FIELD_GET(MT_TXFREE_INFO_STAT, info); - if (info & MT_TXFREE_INFO_HEADER) + wcid->stats.tx_retries += tx_retries; + wcid->stats.tx_failed += tx_failed; continue; + } for (i = 0; i < 2; i++) { msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID; if (msdu == MT_TXFREE_INFO_MSDU_ID) continue; count++; txwi = mt76_token_release(mdev, msdu, &wake); if (!txwi) continue; mt7996_txwi_free(dev, txwi, sta, &free_list); } } mt7996_mac_sta_poll(dev); if (wake) mt76_set_tx_blocked(&dev->mt76, false); mt76_worker_schedule(&dev->mt76.tx_worker); list_for_each_entry_safe(skb, tmp, &free_list, list) { skb_list_del_init(skb); napi_consume_skb(skb, 1); } } static bool mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid, __le32 *txs_data) { struct mt76_sta_stats *stats = &wcid->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; + struct sk_buff *skb = NULL; bool cck = false; u32 txrate, txs, mode, stbc; + txs = le32_to_cpu(txs_data[0]); + mt76_tx_status_lock(mdev, &list); - skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); - if (!skb) - goto out_no_skb; - txs = le32_to_cpu(txs_data[0]); + /* only report MPDU TXS */ + if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) == 0) { + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (skb) { + info = IEEE80211_SKB_CB(skb); + if (!(txs & MT_TXS0_ACK_ERROR_MASK)) + info->flags |= IEEE80211_TX_STAT_ACK; - info = IEEE80211_SKB_CB(skb); - if (!(txs & MT_TXS0_ACK_ERROR_MASK)) - info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = + !!(info->flags & IEEE80211_TX_STAT_ACK); - info->status.ampdu_len = 1; - info->status.ampdu_ack_len = !!(info->flags & - IEEE80211_TX_STAT_ACK); + info->status.rates[0].idx = -1; + } + } - info->status.rates[0].idx = -1; + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wcid->sta) { + struct ieee80211_sta *sta; + u8 tid; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + tid = FIELD_GET(MT_TXS0_TID, txs); + ieee80211_refresh_tx_agg_session_timer(sta, tid); + } 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; stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC); if (stbc && rate.nss > 1) rate.nss >>= 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 = mt76_dev_phy(mdev, wcid->phy_idx); if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) sband = &mphy->sband_5g.sband; else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) sband = &mphy->sband_6g.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: 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; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: case MT_PHY_TYPE_HE_TB: case MT_PHY_TYPE_HE_MU: if (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; case MT_PHY_TYPE_EHT_SU: case MT_PHY_TYPE_EHT_TRIG: case MT_PHY_TYPE_EHT_MU: if (rate.mcs > 13) goto out; rate.eht_gi = wcid->rate.eht_gi; rate.flags = RATE_INFO_FLAGS_EHT_MCS; break; default: goto out; } stats->tx_mode[mode]++; switch (FIELD_GET(MT_TXS0_BW, txs)) { case IEEE80211_STA_RX_BW_320: rate.bw = RATE_INFO_BW_320; stats->tx_bw[4]++; break; 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: + if (skb) + mt76_tx_status_skb_done(mdev, skb, &list); mt76_tx_status_unlock(mdev, &list); return !!skb; } static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data) { struct mt7996_sta *msta = NULL; struct mt76_wcid *wcid; __le32 *txs_data = data; u16 wcidx; u8 pid; - if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1) - return; - wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); pid = le32_get_bits(txs_data[3], MT_TXS3_PID); - if (pid < MT_PACKET_ID_FIRST) + if (pid < MT_PACKET_ID_NO_SKB) return; if (wcidx >= mt7996_wtbl_size(dev)) return; rcu_read_lock(); wcid = rcu_dereference(dev->mt76.wcid[wcidx]); if (!wcid) goto out; msta = container_of(wcid, struct mt7996_sta, wcid); mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data); if (!wcid->sta) goto out; - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (list_empty(&msta->wcid.poll_list)) - list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt76_wcid_add_poll(&dev->mt76, &msta->wcid); out: rcu_read_unlock(); } bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); __le32 *rxd = (__le32 *)data; __le32 *end = (__le32 *)&rxd[len / 4]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); if (type != PKT_TYPE_NORMAL) { u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == MT_RXD0_SW_PKT_TYPE_FRAME)) return true; } switch (type) { case PKT_TYPE_TXRX_NOTIFY: mt7996_mac_tx_free(dev, data, len); return false; case PKT_TYPE_TXS: for (rxd += 4; rxd + 8 <= end; rxd += 8) mt7996_mac_add_txs(dev, rxd); return false; case PKT_TYPE_RX_FW_MONITOR: +#if defined(CONFIG_MT7996_DEBUGFS) mt7996_debugfs_rx_fw_monitor(dev, data, len); +#endif return false; default: return true; } } void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); __le32 *rxd = (__le32 *)skb->data; __le32 *end = (__le32 *)&skb->data[skb->len]; enum rx_pkt_type type; type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE); if (type != PKT_TYPE_NORMAL) { u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK); if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) == MT_RXD0_SW_PKT_TYPE_FRAME)) type = PKT_TYPE_NORMAL; } switch (type) { case PKT_TYPE_TXRX_NOTIFY: + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) && + q == MT_RXQ_TXFREE_BAND2) { + dev_kfree_skb(skb); + break; + } + mt7996_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; case PKT_TYPE_RX_EVENT: mt7996_mcu_rx_event(dev, skb); break; case PKT_TYPE_TXS: for (rxd += 4; rxd + 8 <= end; rxd += 8) mt7996_mac_add_txs(dev, rxd); dev_kfree_skb(skb); break; case PKT_TYPE_RX_FW_MONITOR: +#if defined(CONFIG_MT7996_DEBUGFS) mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len); +#endif dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: - if (!mt7996_mac_fill_rx(dev, skb)) { + if (!mt7996_mac_fill_rx(dev, q, skb, info)) { mt76_rx(&dev->mt76, q, skb); return; } fallthrough; default: dev_kfree_skb(skb); break; } } void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx); mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN); mt76_set(dev, reg, BIT(11) | BIT(9)); } void mt7996_mac_reset_counters(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; u8 band_idx = phy->mt76->band_idx; int i; for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i)); phy->mt76->survey_time = ktime_get_boottime(); memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); /* reset airtime counters */ mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx), MT_WF_RMAC_MIB_RXTIME_CLR); mt7996_mcu_get_chan_mib_info(phy, true); } void mt7996_mac_set_coverage_class(struct mt7996_phy *phy) { s16 coverage_class = phy->coverage_class; struct mt7996_dev *dev = phy->dev; struct mt7996_phy *phy2 = mt7996_phy2(dev); struct mt7996_phy *phy3 = mt7996_phy3(dev); u32 reg_offset; u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); u8 band_idx = phy->mt76->band_idx; int offset; if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; if (phy2) coverage_class = max_t(s16, dev->phy.coverage_class, phy2->coverage_class); if (phy3) coverage_class = max_t(s16, coverage_class, phy3->coverage_class); offset = 3 * coverage_class; reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset); mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset); } void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band) { mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band), MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY | MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR); mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band), FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5)); } static u8 mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx) { static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 }; struct mt7996_dev *dev = phy->dev; u32 val, sum = 0, n = 0; int ant, i; for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) { u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant); for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) { val = mt76_rr(dev, reg); sum += val * nf_power[i]; n += val; } } return n ? sum / n : 0; } void mt7996_update_channel(struct mt76_phy *mphy) { - struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv; + struct mt7996_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; mt7996_mcu_get_chan_mib_info(phy, false); nf = mt7996_phy_get_nf(phy, mphy->band_idx); if (!phy->noise) phy->noise = nf << 4; else if (nf) phy->noise += nf - (phy->noise >> 4); state->noise = -(phy->noise >> 4); } static bool mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state) { bool ret; ret = wait_event_timeout(dev->reset_wait, (READ_ONCE(dev->recovery.state) & state), MT7996_RESET_TIMEOUT); WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); return ret; } static void mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { struct ieee80211_hw *hw = priv; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: - mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon); + mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); break; default: break; } } static void mt7996_update_beacons(struct mt7996_dev *dev) { struct mt76_phy *phy2, *phy3; ieee80211_iterate_active_interfaces(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7996_update_vif_beacon, dev->mt76.hw); phy2 = dev->mt76.phys[MT_BAND1]; if (!phy2) return; ieee80211_iterate_active_interfaces(phy2->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7996_update_vif_beacon, phy2->hw); phy3 = dev->mt76.phys[MT_BAND2]; if (!phy3) return; ieee80211_iterate_active_interfaces(phy3->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7996_update_vif_beacon, phy3->hw); } void mt7996_tx_token_put(struct mt7996_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) { mt7996_txwi_free(dev, txwi, NULL, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); idr_destroy(&dev->mt76.token); } static int mt7996_mac_restart(struct mt7996_dev *dev) { struct mt7996_phy *phy2, *phy3; struct mt76_dev *mdev = &dev->mt76; int i, ret; phy2 = mt7996_phy2(dev); phy3 = mt7996_phy3(dev); if (dev->hif2) { mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); } if (dev_is_pci(mdev->dev)) { mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); if (dev->hif2) mt76_wr(dev, MT_PCIE1_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); - if (phy2) { + if (phy2) set_bit(MT76_RESET, &phy2->mt76->state); - set_bit(MT76_MCU_RESET, &phy2->mt76->state); - } - if (phy3) { + if (phy3) set_bit(MT76_RESET, &phy3->mt76->state); - set_bit(MT76_MCU_RESET, &phy3->mt76->state); - } /* lock/unlock all queues to ensure that no tx is pending */ mt76_txq_schedule_all(&dev->mphy); if (phy2) mt76_txq_schedule_all(phy2->mt76); if (phy3) mt76_txq_schedule_all(phy3->mt76); /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) napi_disable(&dev->mt76.napi[i]); } napi_disable(&dev->mt76.tx_napi); /* token reinit */ mt7996_tx_token_put(dev); idr_init(&dev->mt76.token); mt7996_dma_reset(dev, true); - local_bh_disable(); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) { napi_enable(&dev->mt76.napi[i]); + local_bh_disable(); napi_schedule(&dev->mt76.napi[i]); + local_bh_enable(); } } - local_bh_enable(); clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); if (dev->hif2) { mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); } if (dev_is_pci(mdev->dev)) { mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); if (dev->hif2) mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); } /* load firmware */ ret = mt7996_mcu_init_firmware(dev); if (ret) goto out; /* set the necessary init items */ ret = mt7996_mcu_set_eeprom(dev); if (ret) goto out; mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); + mt7996_init_txpower(&dev->phy); + mt7996_init_txpower(phy2); + mt7996_init_txpower(phy3); ret = mt7996_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { - ret = mt7996_run(dev->mphy.hw); + ret = mt7996_run(&dev->phy); if (ret) goto out; } if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) { - ret = mt7996_run(phy2->mt76->hw); + ret = mt7996_run(phy2); if (ret) goto out; } if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) { - ret = mt7996_run(phy3->mt76->hw); + ret = mt7996_run(phy3); if (ret) goto out; } out: /* reset done */ clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); if (phy3) clear_bit(MT76_RESET, &phy3->mt76->state); - local_bh_disable(); napi_enable(&dev->mt76.tx_napi); + local_bh_disable(); napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); mt76_worker_enable(&dev->mt76.tx_worker); return ret; } static void mt7996_mac_full_reset(struct mt7996_dev *dev) { struct mt7996_phy *phy2, *phy3; int i; phy2 = mt7996_phy2(dev); phy3 = mt7996_phy3(dev); dev->recovery.hw_full_reset = true; wake_up(&dev->mt76.mcu.wait); ieee80211_stop_queues(mt76_hw(dev)); if (phy2) ieee80211_stop_queues(phy2->mt76->hw); if (phy3) ieee80211_stop_queues(phy3->mt76->hw); + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) cancel_delayed_work_sync(&phy2->mt76->mac_work); if (phy3) cancel_delayed_work_sync(&phy3->mt76->mac_work); mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { if (!mt7996_mac_restart(dev)) break; } mutex_unlock(&dev->mt76.mutex); if (i == 10) dev_err(dev->mt76.dev, "chip full reset failed\n"); ieee80211_restart_hw(mt76_hw(dev)); if (phy2) ieee80211_restart_hw(phy2->mt76->hw); if (phy3) ieee80211_restart_hw(phy3->mt76->hw); ieee80211_wake_queues(mt76_hw(dev)); if (phy2) ieee80211_wake_queues(phy2->mt76->hw); if (phy3) ieee80211_wake_queues(phy3->mt76->hw); dev->recovery.hw_full_reset = false; ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT7996_WATCHDOG_TIME); if (phy2) ieee80211_queue_delayed_work(phy2->mt76->hw, &phy2->mt76->mac_work, MT7996_WATCHDOG_TIME); if (phy3) ieee80211_queue_delayed_work(phy3->mt76->hw, &phy3->mt76->mac_work, MT7996_WATCHDOG_TIME); } void mt7996_mac_reset_work(struct work_struct *work) { struct mt7996_phy *phy2, *phy3; struct mt7996_dev *dev; int i; dev = container_of(work, struct mt7996_dev, reset_work); phy2 = mt7996_phy2(dev); phy3 = mt7996_phy3(dev); /* chip full reset */ if (dev->recovery.restart) { /* disable WA/WM WDT */ mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT) dev->recovery.wa_reset_count++; else dev->recovery.wm_reset_count++; mt7996_mac_full_reset(dev); /* enable mcu irq */ mt7996_irq_enable(dev, MT_INT_MCU_CMD); mt7996_irq_disable(dev, 0); /* enable WA/WM WDT */ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; dev->recovery.restart = false; return; } if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) return; dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", wiphy_name(dev->mt76.hw->wiphy)); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + ieee80211_stop_queues(mt76_hw(dev)); if (phy2) ieee80211_stop_queues(phy2->mt76->hw); if (phy3) ieee80211_stop_queues(phy3->mt76->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); + + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); cancel_delayed_work_sync(&phy2->mt76->mac_work); } if (phy3) { set_bit(MT76_RESET, &phy3->mt76->state); cancel_delayed_work_sync(&phy3->mt76->mac_work); } mt76_worker_disable(&dev->mt76.tx_worker); - mt76_for_each_q_rx(&dev->mt76, i) + mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_disable(&dev->mt76.napi[i]); + } napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { mt7996_dma_reset(dev, false); mt7996_tx_token_put(dev); idr_init(&dev->mt76.token); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); } mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); /* enable DMA Tx/Tx and interrupt */ - mt7996_dma_start(dev, false); + mt7996_dma_start(dev, false, false); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 | + dev->mt76.mmio.irqmask; + + if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) + wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND; + + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, + true); + mt7996_irq_enable(dev, wed_irq_mask); + mt7996_irq_disable(dev, 0); + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); + } clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) clear_bit(MT76_RESET, &phy2->mt76->state); if (phy3) clear_bit(MT76_RESET, &phy3->mt76->state); - local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_enable(&dev->mt76.napi[i]); + local_bh_disable(); napi_schedule(&dev->mt76.napi[i]); + local_bh_enable(); } - local_bh_enable(); tasklet_schedule(&dev->mt76.irq_tasklet); mt76_worker_enable(&dev->mt76.tx_worker); - local_bh_disable(); napi_enable(&dev->mt76.tx_napi); + local_bh_disable(); napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); ieee80211_wake_queues(mt76_hw(dev)); if (phy2) ieee80211_wake_queues(phy2->mt76->hw); if (phy3) ieee80211_wake_queues(phy3->mt76->hw); mutex_unlock(&dev->mt76.mutex); mt7996_update_beacons(dev); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, MT7996_WATCHDOG_TIME); if (phy2) ieee80211_queue_delayed_work(phy2->mt76->hw, &phy2->mt76->mac_work, MT7996_WATCHDOG_TIME); if (phy3) ieee80211_queue_delayed_work(phy3->mt76->hw, &phy3->mt76->mac_work, MT7996_WATCHDOG_TIME); dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.", wiphy_name(dev->mt76.hw->wiphy)); } /* firmware coredump */ void mt7996_mac_dump_work(struct work_struct *work) { const struct mt7996_mem_region *mem_region; struct mt7996_crash_data *crash_data; struct mt7996_dev *dev; struct mt7996_mem_hdr *hdr; size_t buf_len; int i; u32 num; u8 *buf; dev = container_of(work, struct mt7996_dev, dump_work); mutex_lock(&dev->dump_mutex); crash_data = mt7996_coredump_new(dev); if (!crash_data) { mutex_unlock(&dev->dump_mutex); goto skip_coredump; } mem_region = mt7996_coredump_get_mem_layout(dev, &num); if (!mem_region || !crash_data->memdump_buf_len) { mutex_unlock(&dev->dump_mutex); goto skip_memdump; } buf = crash_data->memdump_buf; buf_len = crash_data->memdump_buf_len; /* dumping memory content... */ memset(buf, 0, buf_len); for (i = 0; i < num; i++) { if (mem_region->len > buf_len) { dev_warn(dev->mt76.dev, "%s len %zu is too large\n", mem_region->name, mem_region->len); break; } /* reserve space for the header */ hdr = (void *)buf; buf += sizeof(*hdr); buf_len -= sizeof(*hdr); mt7996_memcpy_fromio(dev, buf, mem_region->start, mem_region->len); hdr->start = mem_region->start; hdr->len = mem_region->len; if (!mem_region->len) /* note: the header remains, just with zero length */ break; buf += mem_region->len; buf_len -= mem_region->len; mem_region++; } mutex_unlock(&dev->dump_mutex); skip_memdump: mt7996_coredump_submit(dev); skip_coredump: queue_work(dev->mt76.wq, &dev->reset_work); } void mt7996_reset(struct mt7996_dev *dev) { if (!dev->recovery.hw_init_done) return; if (dev->recovery.hw_full_reset) return; /* wm/wa exception: do full recovery */ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { dev->recovery.restart = true; dev_info(dev->mt76.dev, "%s indicated firmware crash, attempting recovery\n", wiphy_name(dev->mt76.hw->wiphy)); mt7996_irq_disable(dev, MT_INT_MCU_CMD); queue_work(dev->mt76.wq, &dev->dump_work); return; } queue_work(dev->mt76.wq, &dev->reset_work); wake_up(&dev->reset_wait); } void mt7996_mac_update_stats(struct mt7996_phy *phy) { struct mt76_mib_stats *mib = &phy->mib; struct mt7996_dev *dev = phy->dev; u8 band_idx = phy->mt76->band_idx; u32 cnt; int i; cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx)); mib->fcs_err_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx)); mib->rx_fifo_full_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx)); mib->rx_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx)); mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx)); mib->rx_vector_mismatch_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx)); mib->rx_delimiter_fail_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx)); mib->rx_len_mismatch_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx)); mib->tx_ampdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx)); mib->tx_stop_q_empty_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx)); mib->tx_mpdu_attempts_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx)); mib->tx_mpdu_success_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx)); mib->rx_ampdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx)); mib->rx_ampdu_bytes_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx)); mib->rx_ampdu_valid_subframe_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx)); mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx)); mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt); cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx)); mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt); cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx)); mib->rx_pfdrop_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx)); mib->rx_vec_queue_overflow_drop_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx)); mib->rx_ba_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx)); mib->tx_bf_ebf_ppdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx)); mib->tx_bf_ibf_ppdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx)); mib->tx_mu_bf_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx)); mib->tx_mu_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx)); mib->tx_mu_acked_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx)); mib->tx_su_acked_mpdu_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx)); mib->tx_bf_rx_fb_ht_cnt += cnt; mib->tx_bf_rx_fb_all_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx)); mib->tx_bf_rx_fb_vht_cnt += cnt; mib->tx_bf_rx_fb_all_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx)); mib->tx_bf_rx_fb_he_cnt += cnt; mib->tx_bf_rx_fb_all_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx)); mib->tx_bf_rx_fb_eht_cnt += cnt; mib->tx_bf_rx_fb_all_cnt += cnt; cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx)); 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_MIB_BSCR7(band_idx)); mib->tx_bf_fb_trig_cnt += cnt; cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx)); mib->tx_bf_fb_cpl_cnt += 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; } /* rts count */ cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx)); mib->rts_cnt += cnt; /* rts retry count */ cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx)); mib->rts_retries_cnt += cnt; /* ba miss count */ cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx)); mib->ba_miss_cnt += cnt; /* ack fail count */ cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx)); mib->ack_fail_cnt += cnt; for (i = 0; i < 16; i++) { cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i)); phy->mt76->aggr_stats[i] += cnt; } } void mt7996_mac_sta_rc_work(struct work_struct *work) { struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work); struct ieee80211_sta *sta; struct ieee80211_vif *vif; struct mt7996_sta *msta; u32 changed; LIST_HEAD(list); spin_lock_bh(&dev->mt76.sta_poll_lock); list_splice_init(&dev->sta_rc_list, &list); while (!list_empty(&list)) { msta = list_first_entry(&list, struct mt7996_sta, rc_list); list_del_init(&msta->rc_list); changed = msta->changed; msta->changed = 0; spin_unlock_bh(&dev->mt76.sta_poll_lock); sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED | IEEE80211_RC_NSS_CHANGED | IEEE80211_RC_BW_CHANGED)) mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); - /* TODO: smps change */ + if (changed & IEEE80211_RC_SMPS_CHANGED) + mt7996_mcu_set_fixed_field(dev, vif, sta, NULL, + RATE_PARAM_MMPS_UPDATE); spin_lock_bh(&dev->mt76.sta_poll_lock); } spin_unlock_bh(&dev->mt76.sta_poll_lock); } void mt7996_mac_work(struct work_struct *work) { struct mt7996_phy *phy; struct mt76_phy *mphy; mphy = (struct mt76_phy *)container_of(work, struct mt76_phy, mac_work.work); phy = mphy->priv; mutex_lock(&mphy->dev->mutex); mt76_update_survey(mphy); if (++mphy->mac_work_count == 5) { mphy->mac_work_count = 0; mt7996_mac_update_stats(phy); + + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE); + if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT); + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT); + } } mutex_unlock(&mphy->dev->mutex); mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7996_WATCHDOG_TIME); } static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; if (phy->rdd_state & BIT(0)) mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0, MT_RX_SEL0, 0); if (phy->rdd_state & BIT(1)) mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1, MT_RX_SEL0, 0); } static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain) { int err, region; switch (dev->mt76.region) { case NL80211_DFS_ETSI: region = 0; break; case NL80211_DFS_JP: region = 2; break; case NL80211_DFS_FCC: default: region = 1; break; } err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, region); if (err < 0) return err; return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, MT_RX_SEL0, 1); } static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) { struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7996_dev *dev = phy->dev; u8 band_idx = phy->mt76->band_idx; int err; /* start CAC */ err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx, MT_RX_SEL0, 0); if (err < 0) return err; err = mt7996_dfs_start_rdd(dev, band_idx); if (err < 0) return err; phy->rdd_state |= BIT(band_idx); if (chandef->width == NL80211_CHAN_WIDTH_160 || chandef->width == NL80211_CHAN_WIDTH_80P80) { err = mt7996_dfs_start_rdd(dev, 1); if (err < 0) return err; phy->rdd_state |= BIT(1); } return 0; } static int mt7996_dfs_init_radar_specs(struct mt7996_phy *phy) { const struct mt7996_dfs_radar_spec *radar_specs; struct mt7996_dev *dev = phy->dev; int err, i; switch (dev->mt76.region) { case NL80211_DFS_FCC: radar_specs = &fcc_radar_specs; err = mt7996_mcu_set_fcc5_lpn(dev, 8); if (err < 0) return err; break; case NL80211_DFS_ETSI: radar_specs = &etsi_radar_specs; break; case NL80211_DFS_JP: radar_specs = &jp_radar_specs; break; default: return -EINVAL; } for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { err = mt7996_mcu_set_radar_th(dev, i, &radar_specs->radar_pattern[i]); if (err < 0) return err; } return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th); } int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; enum mt76_dfs_state dfs_state, prev_state; int err; prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); if (prev_state == dfs_state) return 0; if (prev_state == MT_DFS_STATE_UNKNOWN) mt7996_dfs_stop_radar_detector(phy); if (dfs_state == MT_DFS_STATE_DISABLED) goto stop; if (prev_state <= MT_DFS_STATE_DISABLED) { err = mt7996_dfs_init_radar_specs(phy); if (err < 0) return err; err = mt7996_dfs_start_radar_detector(phy); if (err < 0) return err; phy->mt76->dfs_state = MT_DFS_STATE_CAC; } if (dfs_state == MT_DFS_STATE_CAC) return 0; err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; } phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE; return 0; stop: err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) return err; mt7996_dfs_stop_radar_detector(phy); phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; return 0; } static int mt7996_mac_twt_duration_align(int duration) { return duration << 8; } static u64 mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev, struct mt7996_twt_flow *flow) { struct mt7996_twt_flow *iter, *iter_next; u32 duration = flow->duration << 8; u64 start_tsf; iter = list_first_entry_or_null(&dev->twt_list, struct mt7996_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 + mt7996_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 mt7996_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; } +static bool +mt7996_mac_twt_param_equal(struct mt7996_sta *msta, + struct ieee80211_twt_params *twt_agrt) +{ + u16 type = le16_to_cpu(twt_agrt->req_type); + u8 exp; + int i; + + exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type); + for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) { + struct mt7996_twt_flow *f; + + if (!(msta->twt.flowid_mask & BIT(i))) + continue; + + f = &msta->twt.flow[i]; + if (f->duration == twt_agrt->min_twt_dur && + f->mantissa == twt_agrt->mantissa && + f->exp == exp && + f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) && + f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) && + f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER)) + return true; + } + + return false; +} + void mt7996_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 mt7996_sta *msta = (struct mt7996_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 mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_twt_flow *flow; - int flowid, table_id; - u8 exp; + u8 flowid, table_id, exp; if (mt7996_mac_check_twt_req(twt)) goto out; mutex_lock(&dev->mt76.mutex); if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT) goto unlock; if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow)) goto unlock; + if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) { + setup_cmd = TWT_SETUP_CMD_DICTATE; + twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR; + goto unlock; + } + + if (mt7996_mac_twt_param_equal(msta, twt_agrt)) + goto unlock; + flowid = ffs(~msta->twt.flowid_mask) - 1; - le16p_replace_bits(&twt_agrt->req_type, flowid, - IEEE80211_TWT_REQTYPE_FLOWID); + twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID); + twt_agrt->req_type |= le16_encode_bits(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 = mt7996_mac_twt_sched_list_add(dev, flow); curr_tsf = __mt7996_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 (mt7996_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); + twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD); + twt_agrt->req_type |= + le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD); + twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED; } void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, struct mt7996_sta *msta, u8 flowid) { struct mt7996_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 (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_DELETE)) return; list_del_init(&flow->list); msta->twt.flowid_mask &= ~BIT(flowid); dev->twt.table_mask &= ~BIT(flow->table_id); dev->twt.n_agrt--; } diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/main.c b/sys/contrib/dev/mediatek/mt76/mt7996/main.c index c3a479dc3f53..69dd565d8319 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/main.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/main.c @@ -1,1418 +1,1680 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include "mt7996.h" #include "mcu.h" #include "mac.h" -static bool mt7996_dev_running(struct mt7996_dev *dev) +int mt7996_run(struct mt7996_phy *phy) { - struct mt7996_phy *phy; - - if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) - return true; - - phy = mt7996_phy2(dev); - if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) - return true; - - phy = mt7996_phy3(dev); - - return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); -} - -int mt7996_run(struct ieee80211_hw *hw) -{ - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - bool running; + struct mt7996_dev *dev = phy->dev; int ret; - running = mt7996_dev_running(dev); - if (!running) { - ret = mt7996_mcu_set_hdr_trans(dev, true); - if (ret) - goto out; - } - mt7996_mac_enable_nf(dev, phy->mt76->band_idx); ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_radio_en(phy, true); if (ret) - goto out; + return ret; ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); if (ret) - goto out; + return ret; + + ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); + if (ret) + return ret; + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + return ret; set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + ieee80211_queue_delayed_work(dev->mphy.hw, &phy->mt76->mac_work, MT7996_WATCHDOG_TIME); - if (!running) + if (!phy->counter_reset) { mt7996_mac_reset_counters(phy); + phy->counter_reset = true; + } -out: - return ret; + return 0; } static int mt7996_start(struct ieee80211_hw *hw) { struct mt7996_dev *dev = mt7996_hw_dev(hw); int ret; flush_work(&dev->init_work); mutex_lock(&dev->mt76.mutex); - ret = mt7996_run(hw); + ret = mt7996_mcu_set_hdr_trans(dev, true); + if (!ret && is_mt7992(&dev->mt76)) { + u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); + + ret = mt7996_mcu_cp_support(dev, queue); + } mutex_unlock(&dev->mt76.mutex); return ret; } -static void mt7996_stop(struct ieee80211_hw *hw) +static void mt7996_stop_phy(struct mt7996_phy *phy) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_dev *dev = phy->dev; + + if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); mt7996_mcu_set_radio_en(phy, false); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); mutex_unlock(&dev->mt76.mutex); } +static void mt7996_stop(struct ieee80211_hw *hw, bool suspend) +{ +} + static inline int get_free_idx(u32 mask, u8 start, u8 end) { return ffs(~mask & GENMASK(end, start)); } static int get_omac_idx(enum nl80211_iftype type, u64 mask) { int i; switch (type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: /* prefer hw bssid slot 1-3 */ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); if (i) return i - 1; if (type != NL80211_IFTYPE_STATION) break; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; break; case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP: /* ap uses hw bssid 0 and ext bssid */ if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); if (i) return i - 1; break; default: WARN_ON(1); break; } return -1; } -static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) +static void +mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlink) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; int i; - for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { - mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; - mvif->bitrate_mask.control[i].he_gi = 0xff; - mvif->bitrate_mask.control[i].he_ltf = 0xff; - mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); - memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, - sizeof(mvif->bitrate_mask.control[i].ht_mcs)); - memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, - sizeof(mvif->bitrate_mask.control[i].vht_mcs)); - memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, - sizeof(mvif->bitrate_mask.control[i].he_mcs)); + for (i = 0; i < ARRAY_SIZE(mlink->bitrate_mask.control); i++) { + mlink->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; + mlink->bitrate_mask.control[i].he_gi = 0xff; + mlink->bitrate_mask.control[i].he_ltf = 0xff; + mlink->bitrate_mask.control[i].legacy = GENMASK(31, 0); + memset(mlink->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(mlink->bitrate_mask.control[i].ht_mcs)); + memset(mlink->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(mlink->bitrate_mask.control[i].vht_mcs)); + memset(mlink->bitrate_mask.control[i].he_mcs, 0xff, + sizeof(mlink->bitrate_mask.control[i].he_mcs)); } } -static int mt7996_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int +mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct mt7996_vif_link *mlink, struct ieee80211_key_conf *key) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt76_txq *mtxq; - u8 band_idx = phy->mt76->band_idx; - int idx, ret = 0; + struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : + &mlink->sta; + struct mt76_wcid *wcid = &msta->wcid; + u8 *wcid_keyidx = &wcid->hw_key_idx; + struct mt7996_phy *phy; + int idx = key->keyidx; - mutex_lock(&dev->mt76.mutex); + phy = mt7996_vif_link_phy(mlink); + if (!phy) + return -EINVAL; - if (vif->type == NL80211_IFTYPE_MONITOR && - is_zero_ether_addr(vif->addr)) - phy->monitor_vif = vif; + if (sta && !wcid->sta) + return -EOPNOTSUPP; - mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); - if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { - ret = -ENOSPC; - goto out; + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + if (key->keyidx == 6 || key->keyidx == 7) { + wcid_keyidx = &wcid->hw_key_idx2; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + } + break; + default: + break; } - idx = get_omac_idx(vif->type, phy->omac_mask); - if (idx < 0) { - ret = -ENOSPC; - goto out; + if (cmd == SET_KEY && !sta && !mlink->mt76.cipher) { + mlink->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); + mt7996_mcu_add_bss_info(phy, vif, &vif->bss_conf, &mlink->mt76, true); + } + + if (cmd == SET_KEY) { + *wcid_keyidx = idx; + } else { + if (idx == *wcid_keyidx) + *wcid_keyidx = -1; + return 0; } - mvif->mt76.omac_idx = idx; - mvif->phy = phy; - mvif->mt76.band_idx = band_idx; - mvif->mt76.wmm_idx = band_idx; - ret = mt7996_mcu_add_dev_info(phy, vif, true); + mt76_wcid_key_setup(&dev->mt76, wcid, key); + + if (key->keyidx == 6 || key->keyidx == 7) + return mt7996_mcu_bcn_prot_enable(dev, vif, key); + + return mt7996_mcu_add_key(&dev->mt76, vif, key, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &msta->wcid, cmd); +} + +static void +mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct ieee80211_key_conf *key, + void *data) +{ + struct mt7996_vif_link *mlink = data; + + if (sta) + return; + + WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, mlink, key)); +} + +int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink) +{ + struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); + struct mt7996_phy *phy = mphy->priv; + struct mt7996_dev *dev = phy->dev; + u8 band_idx = phy->mt76->band_idx; + struct mt76_txq *mtxq; + int idx, ret; + + mlink->idx = __ffs64(~dev->mt76.vif_mask); + if (mlink->idx >= mt7996_max_interface_num(dev)) + return -ENOSPC; + + idx = get_omac_idx(vif->type, phy->omac_mask); + if (idx < 0) + return -ENOSPC; + + link->phy = phy; + mlink->omac_idx = idx; + mlink->band_idx = band_idx; + mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; + mlink->wcid = &link->sta.wcid; + + ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true); if (ret) - goto out; + return ret; - dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); - phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); + dev->mt76.vif_mask |= BIT_ULL(mlink->idx); + phy->omac_mask |= BIT_ULL(mlink->omac_idx); - idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; + idx = MT7996_WTBL_RESERVED - mlink->idx; - INIT_LIST_HEAD(&mvif->sta.rc_list); - INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); - mvif->sta.wcid.idx = idx; - mvif->sta.wcid.phy_idx = 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); + INIT_LIST_HEAD(&link->sta.rc_list); + link->sta.wcid.idx = idx; + link->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; + mt76_wcid_init(&link->sta.wcid, band_idx); mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); if (vif->txq) { mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = idx; } if (vif->type != NL80211_IFTYPE_AP && - (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) + (!mlink->omac_idx || mlink->omac_idx > 3)) vif->offload_flags = 0; - vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) - mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; + mlink->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; else - mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL; + mlink->basic_rates_idx = MT7996_BASIC_RATES_TBL; - mt7996_init_bitrate_mask(vif); + mt7996_init_bitrate_mask(vif, link); - mt7996_mcu_add_bss_info(phy, vif, true); - mt7996_mcu_add_sta(dev, vif, NULL, true); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, true); + /* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA + * interface, since firmware only records BSSID when the entry is new + */ + if (vif->type != NL80211_IFTYPE_STATION) + mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_PORT_SECURE, true); + rcu_assign_pointer(dev->mt76.wcid[idx], &link->sta.wcid); -out: - mutex_unlock(&dev->mt76.mutex); + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, link); - return ret; + return 0; } -static void mt7996_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_sta *msta = &mvif->sta; - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int idx = msta->wcid.idx; - - mt7996_mcu_add_bss_info(phy, vif, false); - mt7996_mcu_add_sta(dev, vif, NULL, false); + struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); + struct mt7996_phy *phy = mphy->priv; + struct mt7996_dev *dev = phy->dev; + struct mt7996_sta *msta; + int idx; - if (vif == phy->monitor_vif) - phy->monitor_vif = NULL; + msta = &link->sta; + idx = msta->wcid.idx; + mt7996_mcu_add_sta(dev, vif, mlink, NULL, CONN_STATE_DISCONNECT, false); + mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, false); - mt7996_mcu_add_dev_info(phy, vif, false); + mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); - mutex_lock(&dev->mt76.mutex); - dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); - phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); - mutex_unlock(&dev->mt76.mutex); + dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); + phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); - mt76_packet_id_flush(&dev->mt76, &msta->wcid); + mt76_wcid_cleanup(&dev->mt76, &msta->wcid); } -int mt7996_set_channel(struct mt7996_phy *phy) +static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; - int ret; + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; + u32 filter = phy->rxfilter; - cancel_delayed_work_sync(&phy->mt76->mac_work); + if (filter & MT_WF_RFCR_DROP_OTHER_UC) { + filter |= MT_WF_RFCR_DROP_CTS | + MT_WF_RFCR_DROP_RTS | + MT_WF_RFCR_DROP_CTL_RSV | + MT_WF_RFCR_DROP_FCSFAIL; + } + + mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), filter); + if (filter & MT_WF_RFCR_DROP_CTL_RSV) + mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); + else + mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); +} + +static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) +{ + struct mt7996_dev *dev = phy->dev; + + if (!phy) + return; + + if (enabled == !(phy->rxfilter & MT_WF_RFCR_DROP_OTHER_UC)) + return; + + if (!enabled) + phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; + else + phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; + + mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), + MT_DMA_DCR0_RXD_G5_EN, enabled); + mt7996_phy_set_rxfilter(phy); + mt7996_mcu_set_sniffer_mode(phy, enabled); +} + +static int mt7996_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int i, err = 0; mutex_lock(&dev->mt76.mutex); - set_bit(MT76_RESET, &phy->mt76->state); - mt76_set_channel(phy->mt76); + for (i = 0; i < MT7996_MAX_RADIOS; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!phy || !(wdev->radio_mask & BIT(i)) || + test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + continue; + + err = mt7996_run(phy); + if (err) + goto out; + + if (vif->type == NL80211_IFTYPE_MONITOR) + mt7996_set_monitor(phy, true); + } + + mt76_vif_init(vif, &mvif->mt76); + + vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; + +out: + mutex_unlock(&dev->mt76.mutex); + + return err; +} + +struct mt7996_radio_data { + u32 active_mask; + u32 monitor_mask; +}; + +static void mt7996_remove_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); + struct mt7996_radio_data *rdata = data; + + rdata->active_mask |= wdev->radio_mask; + if (vif->type == NL80211_IFTYPE_MONITOR) + rdata->monitor_mask |= wdev->radio_mask; +} + +static void mt7996_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_radio_data rdata = {}; + int i; + + ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, + &rdata); + mt76_vif_cleanup(&dev->mt76, vif); + + for (i = 0; i < MT7996_MAX_RADIOS; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!phy) + continue; + if (!(rdata.monitor_mask & BIT(i))) + mt7996_set_monitor(phy, false); + if (!(rdata.active_mask & BIT(i))) + mt7996_stop_phy(phy); + } +} + +int mt7996_set_channel(struct mt76_phy *mphy) +{ + struct mt7996_phy *phy = mphy->priv; + int ret; ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); if (ret) goto out; + ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); + if (ret) + goto out; + + ret = mt7996_mcu_set_txpower_sku(phy); + if (ret) + goto out; + ret = mt7996_dfs_init_radar_detector(phy); mt7996_mac_cca_stats_reset(phy); mt7996_mac_reset_counters(phy); phy->noise = 0; out: - clear_bit(MT76_RESET, &phy->mt76->state); - mutex_unlock(&dev->mt76.mutex); - - mt76_txq_schedule_all(phy->mt76); - - ieee80211_queue_delayed_work(phy->mt76->hw, - &phy->mt76->mac_work, + ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT7996_WATCHDOG_TIME); return ret; } static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : - &mvif->sta; - struct mt76_wcid *wcid = &msta->wcid; - u8 *wcid_keyidx = &wcid->hw_key_idx; - int idx = key->keyidx; - int err = 0; + struct mt7996_vif_link *mlink = &mvif->deflink; + int err; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. */ if ((vif->type == NL80211_IFTYPE_ADHOC || vif->type == NL80211_IFTYPE_MESH_POINT) && (key->cipher == WLAN_CIPHER_SUITE_TKIP || key->cipher == WLAN_CIPHER_SUITE_CCMP) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; /* fall back to sw encryption for unsupported ciphers */ switch (key->cipher) { - case WLAN_CIPHER_SUITE_AES_CMAC: - wcid_keyidx = &wcid->hw_key_idx2; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; - break; case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: break; + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + if (key->keyidx == 6 || key->keyidx == 7) + break; + fallthrough; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: default: return -EOPNOTSUPP; } - mutex_lock(&dev->mt76.mutex); - - if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { - mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); - mt7996_mcu_add_bss_info(phy, vif, true); - } + if (!mt7996_vif_link_phy(mlink)) + return 0; /* defer until after link add */ - if (cmd == SET_KEY) { - *wcid_keyidx = idx; - } else { - if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - goto out; - } - - mt76_wcid_key_setup(&dev->mt76, wcid, key); - err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, - key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); -out: + mutex_lock(&dev->mt76.mutex); + err = mt7996_set_hw_key(hw, cmd, vif, sta, mlink, key); mutex_unlock(&dev->mt76.mutex); return err; } static int mt7996_config(struct ieee80211_hw *hw, u32 changed) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int ret; - - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { - ieee80211_stop_queues(hw); - ret = mt7996_set_channel(phy); - if (ret) - return ret; - ieee80211_wake_queues(hw); - } - - mutex_lock(&dev->mt76.mutex); - - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); - - if (!enabled) - phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; - else - phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; - - mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), - MT_DMA_DCR0_RXD_G5_EN, enabled); - mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); - } - - mutex_unlock(&dev->mt76.mutex); - return 0; } static int mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue, const struct ieee80211_tx_queue_params *params) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_vif_link *mlink = mt7996_vif_link(dev, vif, link_id); + static const u8 mq_to_aci[] = { + [IEEE80211_AC_VO] = 3, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + }; + /* firmware uses access class index */ + mlink->queue_params[mq_to_aci[queue]] = *params; /* no need to update right away, we'll get BSS_CHANGED_QOS */ - queue = mt76_connac_lmac_mapping(queue); - mvif->queue_params[queue] = *params; return 0; } static void mt7996_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 multicast) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | - MT_WF_RFCR1_DROP_BF_POLL | - MT_WF_RFCR1_DROP_BA | - MT_WF_RFCR1_DROP_CFEND | - MT_WF_RFCR1_DROP_CFACK; + struct mt7996_phy *phy; + u32 filter_mask = 0, filter_set = 0; u32 flags = 0; -#define MT76_FILTER(_flag, _hw) do { \ - flags |= *total_flags & FIF_##_flag; \ - phy->rxfilter &= ~(_hw); \ - phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + filter_mask |= (_hw); \ + filter_set |= !(flags & FIF_##_flag) * (_hw); \ } while (0) mutex_lock(&dev->mt76.mutex); - phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | - MT_WF_RFCR_DROP_OTHER_BEACON | - MT_WF_RFCR_DROP_FRAME_REPORT | - MT_WF_RFCR_DROP_PROBEREQ | - MT_WF_RFCR_DROP_MCAST_FILTERED | - MT_WF_RFCR_DROP_MCAST | - MT_WF_RFCR_DROP_BCAST | - MT_WF_RFCR_DROP_DUPLICATE | - MT_WF_RFCR_DROP_A2_BSSID | - MT_WF_RFCR_DROP_UNWANTED_CTL | - MT_WF_RFCR_DROP_STBC_MULTI); - MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | MT_WF_RFCR_DROP_A3_MAC | MT_WF_RFCR_DROP_A3_BSSID); MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | MT_WF_RFCR_DROP_RTS | - MT_WF_RFCR_DROP_CTL_RSV | - MT_WF_RFCR_DROP_NDPA); + MT_WF_RFCR_DROP_CTL_RSV); *total_flags = flags; - mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); - if (*total_flags & FIF_CONTROL) - mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); - else - mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); + mt7996_for_each_phy(dev, phy) { + phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | + MT_WF_RFCR_DROP_OTHER_BEACON | + MT_WF_RFCR_DROP_FRAME_REPORT | + MT_WF_RFCR_DROP_PROBEREQ | + MT_WF_RFCR_DROP_MCAST_FILTERED | + MT_WF_RFCR_DROP_MCAST | + MT_WF_RFCR_DROP_BCAST | + MT_WF_RFCR_DROP_DUPLICATE | + MT_WF_RFCR_DROP_A2_BSSID | + MT_WF_RFCR_DROP_UNWANTED_CTL | + MT_WF_RFCR_DROP_STBC_MULTI | + filter_mask); + phy->rxfilter |= filter_set; + mt7996_phy_set_rxfilter(phy); + } mutex_unlock(&dev->mt76.mutex); } -static void -mt7996_update_bss_color(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct cfg80211_he_bss_color *bss_color) -{ - struct mt7996_dev *dev = mt7996_hw_dev(hw); - - switch (vif->type) { - case NL80211_IFTYPE_AP: { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - - if (mvif->mt76.omac_idx > HW_BSSID_MAX) - return; - fallthrough; - } - case NL80211_IFTYPE_STATION: - mt7996_mcu_update_bss_color(dev, vif, bss_color); - break; - default: - break; - } -} - static u8 -mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +mt7996_get_rates_table(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf, bool beacon, bool mcast) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; - struct mt76_phy *mphy = hw->priv; + struct mt7996_dev *dev = phy->dev; + struct mt76_vif_link *mvif = mt76_vif_conf_link(&dev->mt76, conf->vif, conf); u16 rate; - u8 i, idx, ht; + u8 i, idx; - rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); - ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; + rate = mt76_connac2_mac_tx_rate_val(phy->mt76, conf, beacon, mcast); - if (beacon && ht) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); + if (beacon) { + /* odd index for driver, even index for firmware */ + idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; + if (phy->beacon_rate != rate) + mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon); - /* must odd index */ - idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); return idx; } idx = FIELD_GET(MT_TX_RATE_IDX, rate); for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) - return MT7996_BASIC_RATES_TBL + i; + return MT7996_BASIC_RATES_TBL + 2 * i; return mvif->basic_rates_idx; } static void mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - u8 band = mvif->mt76.band_idx; + u8 band = mvif->deflink.mt76.band_idx; u32 *mu; mu = (u32 *)info->mu_group.membership; mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]); mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]); mu = (u32 *)info->mu_group.position; mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]); mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]); mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]); mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]); } static void mt7996_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt76_vif_link *mvif; + struct mt7996_phy *phy; + struct mt76_phy *mphy; mutex_lock(&dev->mt76.mutex); + mvif = mt76_vif_conf_link(&dev->mt76, vif, info); + if (!mvif) + goto out; + + mphy = mt76_vif_link_phy(mvif); + if (!mphy) + goto out; + + phy = mphy->priv; + /* station mode uses BSSID to map the wlan entry to a peer, * and then peer references bss_info_rfch to set bandwidth cap. */ - if (changed & BSS_CHANGED_BSSID && - vif->type == NL80211_IFTYPE_STATION) { - bool join = !is_zero_ether_addr(info->bssid); - - mt7996_mcu_add_bss_info(phy, vif, join); - mt7996_mcu_add_sta(dev, vif, NULL, join); + if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) || + (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) || + (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) { + mt7996_mcu_add_bss_info(phy, vif, info, mvif, true); + mt7996_mcu_add_sta(dev, vif, mvif, NULL, CONN_STATE_PORT_SECURE, + !!(changed & BSS_CHANGED_BSSID)); } - if (changed & BSS_CHANGED_ASSOC) - mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc); - if (changed & BSS_CHANGED_ERP_CTS_PROT) mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; if (slottime != phy->slottime) { phy->slottime = slottime; - mt7996_mcu_set_timing(phy, vif); + mt7996_mcu_set_timing(phy, vif, info); } } if (changed & BSS_CHANGED_MCAST_RATE) mvif->mcast_rates_idx = - mt7996_get_rates_table(hw, vif, false, true); + mt7996_get_rates_table(phy, info, false, true); if (changed & BSS_CHANGED_BASIC_RATES) mvif->basic_rates_idx = - mt7996_get_rates_table(hw, vif, false, false); - - if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { - mt7996_mcu_add_bss_info(phy, vif, true); - mt7996_mcu_add_sta(dev, vif, NULL, true); - } + mt7996_get_rates_table(phy, info, false, false); /* ensure that enable txcmd_mode after bss_info */ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) - mt7996_mcu_set_tx(dev, vif); + mt7996_mcu_set_tx(dev, vif, info); if (changed & BSS_CHANGED_HE_OBSS_PD) mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); - if (changed & BSS_CHANGED_HE_BSS_COLOR) - mt7996_update_bss_color(hw, vif, &info->he_bss_color); + if (changed & BSS_CHANGED_HE_BSS_COLOR) { + if ((vif->type == NL80211_IFTYPE_AP && + mvif->omac_idx <= HW_BSSID_MAX) || + vif->type == NL80211_IFTYPE_STATION) + mt7996_mcu_update_bss_color(dev, mvif, + &info->he_bss_color); + } if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) { mvif->beacon_rates_idx = - mt7996_get_rates_table(hw, vif, true, false); + mt7996_get_rates_table(phy, info, true, false); - mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); + mt7996_mcu_add_beacon(hw, vif, info); } - if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || - changed & BSS_CHANGED_FILS_DISCOVERY) + if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | + BSS_CHANGED_FILS_DISCOVERY)) mt7996_mcu_beacon_inband_discov(dev, vif, changed); if (changed & BSS_CHANGED_MU_GROUPS) mt7996_update_mu_group(hw, vif, info); + if (changed & BSS_CHANGED_TXPOWER && + info->txpower != phy->txpower) { + phy->txpower = info->txpower; + mt7996_mcu_set_txpower_sku(phy); + } + +out: mutex_unlock(&dev->mt76.mutex); } static void mt7996_channel_switch_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_chan_def *chandef) { struct mt7996_dev *dev = mt7996_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mt7996_mcu_add_beacon(hw, vif, true); + mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); mutex_unlock(&dev->mt76.mutex); } int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - u8 band_idx = mvif->phy->mt76->band_idx; - int ret, idx; + struct mt7996_vif_link *link = &mvif->deflink; + u8 band_idx = link->phy->mt76->band_idx; + int idx; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); if (idx < 0) return -ENOSPC; INIT_LIST_HEAD(&msta->rc_list); INIT_LIST_HEAD(&msta->wcid.poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; msta->wcid.phy_idx = band_idx; - msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta->jiffies = jiffies; ewma_avg_signal_init(&msta->avg_ack_signal); mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, CONN_STATE_DISCONNECT, + true); - ret = mt7996_mcu_add_sta(dev, vif, sta, true); - if (ret) - return ret; + return 0; +} + +int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) +{ + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_vif_link *link = &mvif->deflink; + int i, ret; + + switch (ev) { + case MT76_STA_EVENT_ASSOC: + ret = mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_CONNECT, true); + if (ret) + return ret; + + ret = mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); + if (ret) + return ret; + + msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + msta->wcid.sta = 1; + + return 0; - return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); + case MT76_STA_EVENT_AUTHORIZE: + return mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_PORT_SECURE, false); + + case MT76_STA_EVENT_DISASSOC: + for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) + mt7996_mac_twt_teardown_flow(dev, msta, i); + + mt7996_mcu_add_sta(dev, vif, &link->mt76, sta, + CONN_STATE_DISCONNECT, false); + msta->wcid.sta_disabled = 1; + msta->wcid.sta = 0; + + return 0; + } + + return 0; } void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - int i; - - mt7996_mcu_add_sta(dev, vif, sta, false); mt7996_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) - mt7996_mac_twt_teardown_flow(dev, msta, i); - spin_lock_bh(&mdev->sta_poll_lock); if (!list_empty(&msta->wcid.poll_list)) list_del_init(&msta->wcid.poll_list); if (!list_empty(&msta->rc_list)) list_del_init(&msta->rc_list); spin_unlock_bh(&mdev->sta_poll_lock); } static void mt7996_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt76_phy *mphy = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + if (vif) { + struct mt7996_vif *mvif; + + mvif = (struct mt7996_vif *)vif->drv_priv; + wcid = &mvif->deflink.sta.wcid; + + if (mvif->mt76.roc_phy && + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) { + mphy = mvif->mt76.roc_phy; + if (mphy->roc_link) + wcid = mphy->roc_link->wcid; + } else { + mphy = mt76_vif_link_phy(&mvif->deflink.mt76); + } + } + if (control->sta) { struct mt7996_sta *sta; sta = (struct mt7996_sta *)control->sta->drv_priv; wcid = &sta->wcid; } - if (vif && !control->sta) { - struct mt7996_vif *mvif; - - mvif = (struct mt7996_vif *)vif->drv_priv; - wcid = &mvif->sta.wcid; + if (!mphy) { + ieee80211_free_txskb(hw, skb); + return; } mt76_tx(mphy, control->sta, wcid, skb); } static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int ret; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int i, ret; + + mutex_lock(&dev->mt76.mutex); + + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + ret = mt7996_mcu_set_rts_thresh(phy, val); + if (ret) + break; + } - mutex_lock(&phy->dev->mt76.mutex); - ret = mt7996_mcu_set_rts_thresh(phy, val); - mutex_unlock(&phy->dev->mt76.mutex); + mutex_unlock(&dev->mt76.mutex); return ret; } static int mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { enum ieee80211_ampdu_mlme_action action = params->action; struct mt7996_dev *dev = mt7996_hw_dev(hw); struct ieee80211_sta *sta = params->sta; struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; int ret = 0; if (!txq) return -EINVAL; mtxq = (struct mt76_txq *)txq->drv_priv; mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); ret = mt7996_mcu_add_rx_ba(dev, params, true); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); ret = mt7996_mcu_add_rx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; ret = mt7996_mcu_add_tx_ba(dev, params, true); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; clear_bit(tid, &msta->wcid.ampdu_state); ret = mt7996_mcu_add_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: set_bit(tid, &msta->wcid.ampdu_state); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; clear_bit(tid, &msta->wcid.ampdu_state); ret = mt7996_mcu_add_tx_ba(dev, params, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } mutex_unlock(&dev->mt76.mutex); return ret; } -static int -mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, - IEEE80211_STA_NONE); -} - -static int -mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, - IEEE80211_STA_NOTEXIST); -} - static int mt7996_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt76_mib_stats *mib = &phy->mib; + int i; 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(stats, 0, sizeof(*stats)); + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + struct mt76_mib_stats *mib = &phy->mib; + + stats->dot11RTSSuccessCount += mib->rts_cnt; + stats->dot11RTSFailureCount += mib->rts_retries_cnt; + stats->dot11FCSErrorCount += mib->fcs_err_cnt; + stats->dot11ACKFailureCount += mib->ack_fail_cnt; + } mutex_unlock(&dev->mt76.mutex); return 0; } u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf; u16 n; + if (!phy) + return 0; + lockdep_assert_held(&dev->mt76.mutex); - n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 - : mvif->mt76.omac_idx; + n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 + : mvif->deflink.mt76.omac_idx; /* TSF software read */ mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_READ); tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); return tsf.t64; } static u64 mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); u64 ret; mutex_lock(&dev->mt76.mutex); ret = __mt7996_get_tsf(hw, mvif); mutex_unlock(&dev->mt76.mutex); return ret; } static void mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 timestamp) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); - n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 - : mvif->mt76.omac_idx; + n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 + : mvif->deflink.mt76.omac_idx; mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); /* TSF software overwrite */ mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_WRITE); mutex_unlock(&dev->mt76.mutex); } static void mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, s64 timestamp) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); union { u64 t64; u32 t32[2]; } tsf = { .t64 = timestamp, }; u16 n; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); - n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 - : mvif->mt76.omac_idx; + n = mvif->deflink.mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 + : mvif->deflink.mt76.omac_idx; mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); /* TSF software adjust*/ mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, MT_LPON_TCR_SW_ADJUST); mutex_unlock(&dev->mt76.mutex); } static void mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; mutex_lock(&dev->mt76.mutex); - phy->coverage_class = max_t(s16, coverage_class, 0); - mt7996_mac_set_coverage_class(phy); + mt7996_for_each_phy(dev, phy) { + phy->coverage_class = max_t(s16, coverage_class, 0); + mt7996_mac_set_coverage_class(phy); + } mutex_unlock(&dev->mt76.mutex); } static int mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - int max_nss = hweight8(hw->wiphy->available_antennas_tx); - u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; + int i; - if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) + if (tx_ant != rx_ant) return -EINVAL; - if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) - tx_ant = BIT(ffs(tx_ant) - 1) - 1; + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + + if (!(tx_ant & phy->orig_chainmask)) + return -EINVAL; + } mutex_lock(&dev->mt76.mutex); - phy->mt76->antenna_mask = tx_ant; + for (i = 0; i < hw->wiphy->n_radio; i++) { + struct mt7996_phy *phy = dev->radio_phy[i]; + u8 band_idx = phy->mt76->band_idx; + u8 shift = dev->chainshift[band_idx]; - /* restore to the origin chainmask which might have auxiliary path */ - if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) - phy->mt76->chainmask = ((dev->chainmask >> shift) & - (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; - else if (hweight8(tx_ant) == max_nss) - phy->mt76->chainmask = (dev->chainmask >> shift) << shift; - else - phy->mt76->chainmask = tx_ant << shift; + phy->mt76->chainmask = tx_ant & phy->orig_chainmask; + phy->mt76->antenna_mask = phy->mt76->chainmask >> shift; - mt76_set_stream_caps(phy->mt76, true); - mt7996_set_stream_vht_txbf_caps(phy); - mt7996_set_stream_he_eht_caps(phy); + mt76_set_stream_caps(phy->mt76, true); + mt7996_set_stream_vht_txbf_caps(phy); + mt7996_set_stream_he_eht_caps(phy); + mt7996_mcu_set_txpower_sku(phy); + } - /* TODO: update bmc_wtbl spe_idx when antenna changes */ mutex_unlock(&dev->mt76.mutex); return 0; } static void mt7996_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct rate_info *txrate = &msta->wcid.rate; if (txrate->legacy || txrate->flags) { if (txrate->legacy) { sinfo->txrate.legacy = txrate->legacy; } else { 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.eht_gi = txrate->eht_gi; } sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + sinfo->tx_failed = msta->wcid.stats.tx_failed; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); + + sinfo->tx_retries = msta->wcid.stats.tx_retries; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + sinfo->ack_signal = (s8)msta->ack_signal; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + sinfo->tx_bytes = msta->wcid.stats.tx_bytes; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); + + sinfo->rx_bytes = msta->wcid.stats.rx_bytes; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); + + sinfo->tx_packets = msta->wcid.stats.tx_packets; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); + + sinfo->rx_packets = msta->wcid.stats.rx_packets; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); + } } static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_dev *dev = msta->vif->phy->dev; + struct mt7996_dev *dev = msta->vif->deflink.phy->dev; u32 *changed = data; spin_lock_bh(&dev->mt76.sta_poll_lock); msta->changed |= *changed; if (list_empty(&msta->rc_list)) list_add_tail(&msta->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); } static void mt7996_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct ieee80211_sta *sta = link_sta->sta; mt7996_sta_rc_work(&changed, sta); ieee80211_queue_work(hw, &dev->rc_work); } static int mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; - mvif->bitrate_mask = *mask; + mvif->deflink.bitrate_mask = *mask; /* if multiple rates across different preambles are given we can * reconfigure this info with all peers using sta_rec command with * the below exception cases. * - single rate : if a rate is passed along with different preambles, * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT * then multiple MCS setting (MCS 4,5,6) is not supported. */ ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); ieee80211_queue_work(hw, &dev->rc_work); return 0; } static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; if (enabled) set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); + if (!msta->wcid.sta) + return; + mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); } static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enabled) { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; if (enabled) set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); else clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); + if (!msta->wcid.sta) + return; + mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); } static const char mt7996_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_mode_eht_su", "v_tx_mode_eht_trig", "v_tx_mode_eht_mu", "v_tx_bw_20", "v_tx_bw_40", "v_tx_bw_80", "v_tx_bw_160", "v_tx_bw_320", "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", "v_tx_mcs_12", "v_tx_mcs_13", "v_tx_nss_1", "v_tx_nss_2", "v_tx_nss_3", "v_tx_nss_4", }; #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) /* Ethtool related API */ static void mt7996_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data) { if (sset == ETH_SS_STATS) - memcpy(data, *mt7996_gstrings_stats, + memcpy(data, mt7996_gstrings_stats, sizeof(mt7996_gstrings_stats)); } static int mt7996_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int sset) { if (sset == ETH_SS_STATS) return MT7996_SSTATS_LEN; return 0; } static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) { struct mt76_ethtool_worker_info *wi = wi_data; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - if (msta->vif->mt76.idx != wi->idx) + if (msta->vif->deflink.mt76.idx != wi->idx) return; mt76_ethtool_worker(wi, &msta->wcid.stats, true); } static void mt7996_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ethtool_stats *stats, u64 *data) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); struct mt76_mib_stats *mib = &phy->mib; struct mt76_ethtool_worker_info wi = { .data = data, - .idx = mvif->mt76.idx, + .idx = mvif->deflink.mt76.idx, }; /* See mt7996_ampdu_stat_read_phy, etc */ int i, ei = 0; + if (!phy) + return; + mutex_lock(&dev->mt76.mutex); mt7996_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_bf_ebf_ppdu_cnt; data[ei++] = mib->tx_bf_ibf_ppdu_cnt; /* Tx ampdu stat */ for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) data[ei++] = phy->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; 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_mu_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, mt7996_ethtool_worker, &wi); mutex_unlock(&dev->mt76.mutex); if (wi.sta_count == 0) return; ei += wi.worker_stat_count; if (ei != MT7996_SSTATS_LEN) dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", ei, (int)MT7996_SSTATS_LEN); } static void mt7996_twt_teardown_request(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 flowid) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_dev *dev = mt7996_hw_dev(hw); mutex_lock(&dev->mt76.mutex); mt7996_mac_twt_teardown_flow(dev, msta, flowid); mutex_unlock(&dev->mt76.mutex); } static int mt7996_set_radar_background(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef) { - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; int ret = -EINVAL; bool running; + if (chandef) + phy = mt7996_band_phy(dev, chandef->chan->band); + else + phy = dev->rdd2_phy; + if (!phy) + return -EINVAL; + mutex_lock(&dev->mt76.mutex); if (dev->mt76.region == NL80211_DFS_UNSET) goto out; if (dev->rdd2_phy && dev->rdd2_phy != phy) { /* rdd2 is already locked */ ret = -EBUSY; goto out; } /* rdd2 already configured on a radar channel */ running = dev->rdd2_phy && cfg80211_chandef_valid(&dev->rdd2_chandef) && !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); if (!chandef || running || !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { ret = mt7996_mcu_rdd_background_enable(phy, NULL); if (ret) goto out; if (!running) goto update_phy; } ret = mt7996_mcu_rdd_background_enable(phy, chandef); if (ret) goto out; update_phy: dev->rdd2_phy = chandef ? phy : NULL; if (chandef) dev->rdd2_chandef = *chandef; out: mutex_unlock(&dev->mt76.mutex); return ret; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int +mt7996_net_fill_forward_path(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_vif_link *mlink = &mvif->deflink; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mt7996_phy *phy; + + phy = mt7996_vif_link_phy(mlink); + if (!phy) + return -ENODEV; + + if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) + wed = &dev->mt76.mmio.wed_hif2; + + if (!mtk_wed_device_active(wed)) + return -ENODEV; + + if (!msta->wcid.sta || msta->wcid.idx > MT7996_WTBL_STA) + return -EIO; + + path->type = DEV_PATH_MTK_WDMA; + path->dev = ctx->dev; + path->mtk_wdma.wdma_idx = wed->wdma_idx; + path->mtk_wdma.bss = mvif->deflink.mt76.idx; + path->mtk_wdma.queue = 0; + path->mtk_wdma.wcid = msta->wcid.idx; + + path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); + ctx->dev = NULL; + + return 0; +} + +#endif + const struct ieee80211_ops mt7996_ops = { + .add_chanctx = mt76_add_chanctx, + .remove_chanctx = mt76_remove_chanctx, + .change_chanctx = mt76_change_chanctx, + .assign_vif_chanctx = mt76_assign_vif_chanctx, + .unassign_vif_chanctx = mt76_unassign_vif_chanctx, + .switch_vif_chanctx = mt76_switch_vif_chanctx, .tx = mt7996_tx, .start = mt7996_start, .stop = mt7996_stop, .add_interface = mt7996_add_interface, .remove_interface = mt7996_remove_interface, .config = mt7996_config, .conf_tx = mt7996_conf_tx, .configure_filter = mt7996_configure_filter, .bss_info_changed = mt7996_bss_info_changed, - .sta_add = mt7996_sta_add, - .sta_remove = mt7996_sta_remove, + .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7996_sta_rc_update, + .link_sta_rc_update = mt7996_sta_rc_update, .set_key = mt7996_set_key, .ampdu_action = mt7996_ampdu_action, .set_rts_threshold = mt7996_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, - .sw_scan_start = mt76_sw_scan, - .sw_scan_complete = mt76_sw_scan_complete, + .hw_scan = mt76_hw_scan, + .cancel_hw_scan = mt76_cancel_hw_scan, + .remain_on_channel = mt76_remain_on_channel, + .cancel_remain_on_channel = mt76_cancel_remain_on_channel, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7996_channel_switch_beacon, .get_stats = mt7996_get_stats, .get_et_sset_count = mt7996_get_et_sset_count, .get_et_stats = mt7996_get_et_stats, .get_et_strings = mt7996_get_et_strings, .get_tsf = mt7996_get_tsf, .set_tsf = mt7996_set_tsf, .offset_tsf = mt7996_offset_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7996_set_antenna, .set_bitrate_mask = mt7996_set_bitrate_mask, .set_coverage_class = mt7996_set_coverage_class, .sta_statistics = mt7996_sta_statistics, .sta_set_4addr = mt7996_sta_set_4addr, .sta_set_decap_offload = mt7996_sta_set_decap_offload, .add_twt_setup = mt7996_mac_add_twt_setup, .twt_teardown_request = mt7996_twt_teardown_request, #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = mt7996_sta_add_debugfs, #endif .set_radar_background = mt7996_set_radar_background, +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + .net_fill_forward_path = mt7996_net_fill_forward_path, + .net_setup_tc = mt76_wed_net_setup_tc, +#endif }; diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c index 6323b9144b28..381f9ff41d9a 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.c @@ -1,3809 +1,4657 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include #include "mt7996.h" #include "mcu.h" #include "mac.h" #include "eeprom.h" +#define fw_name(_dev, name, ...) ({ \ + char *_fw; \ + switch (mt76_chip(&(_dev)->mt76)) { \ + case 0x7992: \ + switch ((_dev)->var.type) { \ + case MT7992_VAR_TYPE_23: \ + _fw = MT7992_##name##_23; \ + break; \ + default: \ + _fw = MT7992_##name; \ + } \ + break; \ + case 0x7990: \ + default: \ + switch ((_dev)->var.type) { \ + case MT7996_VAR_TYPE_233: \ + _fw = MT7996_##name##_233; \ + break; \ + default: \ + _fw = MT7996_##name; \ + } \ + break; \ + } \ + _fw; \ +}) + struct mt7996_patch_hdr { char build_date[16]; char platform[4]; __be32 hw_sw_ver; __be32 patch_ver; __be16 checksum; u16 reserved; struct { __be32 patch_ver; __be32 subsys; __be32 feature; __be32 n_region; __be32 crc; u32 reserved[11]; } desc; } __packed; struct mt7996_patch_sec { __be32 type; __be32 offs; __be32 size; union { __be32 spec[13]; struct { __be32 addr; __be32 len; __be32 sec_key_idx; __be32 align_len; u32 reserved[9]; } info; }; } __packed; struct mt7996_fw_trailer { u8 chip_id; u8 eco_code; u8 n_region; u8 format_ver; u8 format_flag; u8 reserved[2]; char fw_ver[10]; char build_date[15]; u32 crc; } __packed; struct mt7996_fw_region { __le32 decomp_crc; __le32 decomp_len; __le32 decomp_blk_sz; u8 reserved[4]; __le32 addr; __le32 len; u8 feature_set; u8 reserved1[15]; } __packed; #define MCU_PATCH_ADDRESS 0x200000 #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) #define EHT_PHY(p, c) u8_get_bits(c, IEEE80211_EHT_PHY_##p) static bool sr_scene_detect = true; module_param(sr_scene_detect, bool, 0644); MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm"); static u8 mt7996_mcu_get_sta_nss(u16 mcs_map) { u8 nss; for (nss = 8; nss > 0; nss--) { u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3; if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) break; } return nss - 1; } static void mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs, u16 mcs_map) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band; - const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs; + enum nl80211_band band = msta->vif->deflink.phy->mt76->chandef.chan->band; + const u16 *mask = msta->vif->deflink.bitrate_mask.control[band].he_mcs; int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; for (nss = 0; nss < max_nss; nss++) { int mcs; switch ((mcs_map >> (2 * nss)) & 0x3) { case IEEE80211_HE_MCS_SUPPORT_0_11: mcs = GENMASK(11, 0); break; case IEEE80211_HE_MCS_SUPPORT_0_9: mcs = GENMASK(9, 0); break; case IEEE80211_HE_MCS_SUPPORT_0_7: mcs = GENMASK(7, 0); break; default: mcs = 0; } mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1; switch (mcs) { case 0 ... 7: mcs = IEEE80211_HE_MCS_SUPPORT_0_7; break; case 8 ... 9: mcs = IEEE80211_HE_MCS_SUPPORT_0_9; break; case 10 ... 11: mcs = IEEE80211_HE_MCS_SUPPORT_0_11; break; default: mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; break; } mcs_map &= ~(0x3 << (nss * 2)); mcs_map |= mcs << (nss * 2); } *he_mcs = cpu_to_le16(mcs_map); } static void mt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs, const u16 *mask) { u16 mcs, mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) { switch (mcs_map & 0x3) { case IEEE80211_VHT_MCS_SUPPORT_0_9: mcs = GENMASK(9, 0); break; case IEEE80211_VHT_MCS_SUPPORT_0_8: mcs = GENMASK(8, 0); break; case IEEE80211_VHT_MCS_SUPPORT_0_7: mcs = GENMASK(7, 0); break; default: mcs = 0; } vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]); } } static void mt7996_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs, const u8 *mask) { int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss; for (nss = 0; nss < max_nss; nss++) ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss]; } static int mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { struct mt7996_mcu_rxd *rxd; struct mt7996_mcu_uni_event *event; int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); int ret = 0; if (!skb) { dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); return -ETIMEDOUT; } rxd = (struct mt7996_mcu_rxd *)skb->data; if (seq != rxd->seq) return -EAGAIN; if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if ((rxd->option & MCU_UNI_CMD_EVENT) && rxd->eid == MCU_UNI_EVENT_RESULT) { skb_pull(skb, sizeof(*rxd)); event = (struct mt7996_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); /* skip invalid event */ if (mcu_cmd != event->cid) ret = -EAGAIN; } else { skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); } return ret; } static int mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); struct mt76_connac2_mcu_uni_txd *uni_txd; struct mt76_connac2_mcu_txd *mcu_txd; enum mt76_mcuq_id qid; __le32 *txd; u32 val; u8 seq; mdev->mcu.timeout = 20 * HZ; seq = ++dev->mt76.mcu.msg_seq & 0xf; if (!seq) seq = ++dev->mt76.mcu.msg_seq & 0xf; if (cmd == MCU_CMD(FW_SCATTER)) { qid = MT_MCUQ_FWDL; goto exit; } txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); txd = (__le32 *)skb_push(skb, txd_len); if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) qid = MT_MCUQ_WA; else qid = MT_MCUQ_WM; val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) | FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0); txd[0] = cpu_to_le32(val); val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD); txd[1] = cpu_to_le32(val); if (cmd & __MCU_CMD_FIELD_UNI) { uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd; uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd)); uni_txd->cid = cpu_to_le16(mcu_cmd); uni_txd->s2d_index = MCU_S2D_H2CN; uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; if (cmd & __MCU_CMD_FIELD_QUERY) uni_txd->option = MCU_CMD_UNI_QUERY_ACK; else uni_txd->option = MCU_CMD_UNI_EXT_ACK; if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) uni_txd->s2d_index = MCU_S2D_H2CN; else if (cmd & __MCU_CMD_FIELD_WA) uni_txd->s2d_index = MCU_S2D_H2C; else if (cmd & __MCU_CMD_FIELD_WM) uni_txd->s2d_index = MCU_S2D_H2N; goto exit; } mcu_txd = (struct mt76_connac2_mcu_txd *)txd; mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd)); mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, MT_TX_MCU_PORT_RX_Q0)); mcu_txd->pkt_type = MCU_PKT_ID; mcu_txd->seq = seq; mcu_txd->cid = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); mcu_txd->set_query = MCU_Q_NA; mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd); if (mcu_txd->ext_cid) { mcu_txd->ext_cid_ack = 1; if (cmd & __MCU_CMD_FIELD_QUERY) mcu_txd->set_query = MCU_Q_QUERY; else mcu_txd->set_query = MCU_Q_SET; } if (cmd & __MCU_CMD_FIELD_WA) mcu_txd->s2d_index = MCU_S2D_H2C; else mcu_txd->s2d_index = MCU_S2D_H2N; exit: if (wait_seq) *wait_seq = seq; return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0); } int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) { struct { __le32 args[3]; } req = { .args = { cpu_to_le32(a1), cpu_to_le32(a2), cpu_to_le32(a3), }, }; return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false); } static void mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (vif->bss_conf.csa_active) - ieee80211_csa_finish(vif); + if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) + return; + + ieee80211_csa_finish(vif, 0); } static void mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7996_mcu_rdd_report *r; r = (struct mt7996_mcu_rdd_report *)skb->data; if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys)) return; - if (dev->rdd2_phy && r->band_idx == MT_RX_SEL2) + if (r->band_idx == MT_RX_SEL2 && !dev->rdd2_phy) + return; + + if (r->band_idx == MT_RX_SEL2) mphy = dev->rdd2_phy->mt76; else mphy = dev->mt76.phys[r->band_idx]; if (!mphy) return; if (r->band_idx == MT_RX_SEL2) cfg80211_background_radar_event(mphy->hw->wiphy, &dev->rdd2_chandef, GFP_ATOMIC); else - ieee80211_radar_detected(mphy->hw); + ieee80211_radar_detected(mphy->hw, NULL); dev->hw_pattern++; } static void mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb) { #define UNI_EVENT_FW_LOG_FORMAT 0 struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; const char *data = (char *)&rxd[1] + 4, *type; #if defined(__linux__) struct tlv *tlv = (struct tlv *)data; #elif defined(__FreeBSD__) const struct tlv *tlv = (const struct tlv *)data; #endif int len; if (!(rxd->option & MCU_UNI_CMD_EVENT)) { len = skb->len - sizeof(*rxd); data = (char *)&rxd[1]; goto out; } if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT) return; data += sizeof(*tlv) + 4; len = le16_to_cpu(tlv->len) - sizeof(*tlv) - 4; out: switch (rxd->s2d_index) { case 0: +#if defined(CONFIG_MT7996_DEBUGFS) if (mt7996_debugfs_rx_log(dev, data, len)) return; +#endif type = "WM"; break; case 2: type = "WA"; break; default: type = "unknown"; break; } wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); } static void mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (!vif->bss_conf.color_change_active) + if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) return; - ieee80211_color_change_finish(vif); + ieee80211_color_change_finish(vif, 0); } static void mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) { #define UNI_EVENT_IE_COUNTDOWN_CSA 0 #define UNI_EVENT_IE_COUNTDOWN_BCC 1 struct header { u8 band; u8 rsv[3]; }; struct mt76_phy *mphy = &dev->mt76.phy; struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; const char *data = (char *)&rxd[1], *tail; #if defined(__linux__) struct header *hdr = (struct header *)data; struct tlv *tlv = (struct tlv *)(data + 4); #elif defined(__FreeBSD__) const struct header *hdr = (const struct header *)data; const struct tlv *tlv = (const struct tlv *)(data + 4); #endif if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) return; if (hdr->band && dev->mt76.phys[hdr->band]) mphy = dev->mt76.phys[hdr->band]; tail = skb->data + skb->len; data += sizeof(struct header); while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) { switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_IE_COUNTDOWN_CSA: ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7996_mcu_csa_finish, mphy->hw); break; case UNI_EVENT_IE_COUNTDOWN_BCC: ieee80211_iterate_active_interfaces_atomic(mphy->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7996_mcu_cca_finish, mphy->hw); break; } data += le16_to_cpu(tlv->len); #if defined(__linux__) tlv = (struct tlv *)data; #elif defined(__FreeBSD__) tlv = (const struct tlv *)data; #endif } } +static int +mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) +{ + switch (mcu_rate->tx_mode) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_VHT: + if (mcu_rate->tx_gi) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2) + return -EINVAL; + rate->he_gi = mcu_rate->tx_gi; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2) + return -EINVAL; + rate->eht_gi = mcu_rate->tx_gi; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void +mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_all_sta_info_event *res; + u16 i; + + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); + + res = (struct mt7996_mcu_all_sta_info_event *)skb->data; + + for (i = 0; i < le16_to_cpu(res->sta_num); i++) { + u8 ac; + u16 wlan_idx; + struct mt76_wcid *wcid; + + switch (le16_to_cpu(res->tag)) { + case UNI_ALL_STA_TXRX_RATE: + wlan_idx = le16_to_cpu(res->rate[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i])) + dev_err(dev->mt76.dev, "Failed to update TX GI\n"); + break; + case UNI_ALL_STA_TXRX_ADM_STAT: + wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + wcid->stats.tx_bytes += + le32_to_cpu(res->adm_stat[i].tx_bytes[ac]); + wcid->stats.rx_bytes += + le32_to_cpu(res->adm_stat[i].rx_bytes[ac]); + } + break; + case UNI_ALL_STA_TXRX_MSDU_COUNT: + wlan_idx = le16_to_cpu(res->msdu_cnt[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + wcid->stats.tx_packets += + le32_to_cpu(res->msdu_cnt[i].tx_msdu_cnt); + wcid->stats.rx_packets += + le32_to_cpu(res->msdu_cnt[i].rx_msdu_cnt); + break; + default: + break; + } + } +} + +static void +mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb) +{ +#define THERMAL_NOTIFY_TAG 0x4 +#define THERMAL_NOTIFY 0x2 + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7996_mcu_thermal_notify *n; + struct mt7996_phy *phy; + + n = (struct mt7996_mcu_thermal_notify *)skb->data; + + if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG) + return; + + if (n->event_id != THERMAL_NOTIFY) + return; + + if (n->band_idx > MT_BAND2) + return; + + mphy = dev->mt76.phys[n->band_idx]; + if (!mphy) + return; + + phy = (struct mt7996_phy *)mphy->priv; + phy->throttle_state = n->duty_percent; +} + static void mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; switch (rxd->ext_eid) { case MCU_EXT_EVENT_FW_LOG_2_HOST: mt7996_mcu_rx_log_message(dev, skb); break; default: break; } } static void mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_EVENT_EXT: mt7996_mcu_rx_ext_event(dev, skb); break; + case MCU_UNI_EVENT_THERMAL: + mt7996_mcu_rx_thermal_notify(dev, skb); + break; default: break; } dev_kfree_skb(skb); } +static void +mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_wed_rro_event *event = (void *)skb->data; + + if (!dev->has_rro) + return; + + skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4); + + switch (le16_to_cpu(event->tag)) { + case UNI_WED_RRO_BA_SESSION_STATUS: { + struct mt7996_mcu_wed_rro_ba_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt76_rx_tid *tid; + struct mt76_wcid *wcid; + u16 idx; + + e = (void *)skb->data; + idx = le16_to_cpu(e->wlan_id); + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + break; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (!wcid || !wcid->sta) + break; + + if (e->tid >= ARRAY_SIZE(wcid->aggr)) + break; + + tid = rcu_dereference(wcid->aggr[e->tid]); + if (!tid) + break; + + tid->id = le16_to_cpu(e->id); + skb_pull(skb, sizeof(*e)); + } + break; + } + case UNI_WED_RRO_BA_SESSION_DELETE: { + struct mt7996_mcu_wed_rro_ba_delete_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt7996_wed_rro_session_id *session; + + e = (void *)skb->data; + session = kzalloc(sizeof(*session), GFP_ATOMIC); + if (!session) + break; + + session->id = le16_to_cpu(e->session_id); + + spin_lock_bh(&dev->wed_rro.lock); + list_add_tail(&session->list, &dev->wed_rro.poll_list); + spin_unlock_bh(&dev->wed_rro.lock); + + ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work); + skb_pull(skb, sizeof(*e)); + } + break; + } + default: + break; + } +} + static void mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; switch (rxd->eid) { case MCU_UNI_EVENT_FW_LOG_2_HOST: mt7996_mcu_rx_log_message(dev, skb); break; case MCU_UNI_EVENT_IE_COUNTDOWN: mt7996_mcu_ie_countdown(dev, skb); break; case MCU_UNI_EVENT_RDD_REPORT: mt7996_mcu_rx_radar_detected(dev, skb); break; + case MCU_UNI_EVENT_ALL_STA_INFO: + mt7996_mcu_rx_all_sta_info_event(dev, skb); + break; + case MCU_UNI_EVENT_WED_RRO: + mt7996_mcu_wed_rro_event(dev, skb); + break; default: break; } dev_kfree_skb(skb); } void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) { mt7996_mcu_uni_rx_unsolicited_event(dev, skb); return; } /* WA still uses legacy event*/ if (rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || !rxd->seq) mt7996_mcu_rx_unsolicited_event(dev, skb); else mt76_mcu_rx_event(&dev->mt76, skb); } static struct tlv * mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len) { - struct tlv *ptlv, tlv = { - .tag = cpu_to_le16(tag), - .len = cpu_to_le16(len), - }; + struct tlv *ptlv = skb_put_zero(skb, len); - ptlv = skb_put(skb, len); - memcpy(ptlv, &tlv, sizeof(tlv)); + ptlv->tag = cpu_to_le16(tag); + ptlv->len = cpu_to_le16(len); return ptlv; } static void -mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct mt7996_phy *phy) +mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { static const u8 rlm_ch_band[] = { [NL80211_BAND_2GHZ] = 1, [NL80211_BAND_5GHZ] = 2, [NL80211_BAND_6GHZ] = 3, }; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct bss_rlm_tlv *ch; struct tlv *tlv; int freq1 = chandef->center_freq1; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*ch)); ch = (struct bss_rlm_tlv *)tlv; ch->control_channel = chandef->chan->hw_value; ch->center_chan = ieee80211_frequency_to_channel(freq1); ch->bw = mt76_connac_chan_bw(chandef); ch->tx_streams = hweight8(phy->mt76->antenna_mask); ch->rx_streams = hweight8(phy->mt76->antenna_mask); ch->band = rlm_ch_band[chandef->chan->band]; if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; ch->center_chan2 = ieee80211_frequency_to_channel(freq2); } } static void -mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct mt7996_phy *phy) +mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { struct bss_ra_tlv *ra; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RA, sizeof(*ra)); ra = (struct bss_ra_tlv *)tlv; ra->short_preamble = true; } static void mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, struct mt7996_phy *phy) { #define DEFAULT_HE_PE_DURATION 4 #define DEFAULT_HE_DURATION_RTS_THRES 1023 const struct ieee80211_sta_he_cap *cap; struct bss_info_uni_he *he; struct tlv *tlv; cap = mt76_connac_get_he_phy_cap(phy->mt76, vif); tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he)); he = (struct bss_info_uni_he *)tlv; - he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext; + he->he_pe_duration = link_conf->htc_trig_based_pkt_ext; if (!he->he_pe_duration) he->he_pe_duration = DEFAULT_HE_PE_DURATION; - he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + he->he_rts_thres = cpu_to_le16(link_conf->frame_time_rts_th); if (!he->he_rts_thres) he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80; he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160; he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80; } static void -mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, +mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + bool enable) +{ + struct bss_info_uni_mbssid *mbssid; + struct tlv *tlv; + + if (!link_conf->bssid_indicator && enable) + return; + + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_11V_MBSSID, sizeof(*mbssid)); + + mbssid = (struct bss_info_uni_mbssid *)tlv; + + if (enable) { + mbssid->max_indicator = link_conf->bssid_indicator; + mbssid->mbss_idx = link_conf->bssid_index; + mbssid->tx_bss_omac_idx = 0; + } +} + +static void +mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink, struct mt7996_phy *phy) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct bss_rate_tlv *bmc; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; enum nl80211_band band = chandef->chan->band; struct tlv *tlv; - u8 idx = mvif->mcast_rates_idx ? - mvif->mcast_rates_idx : mvif->basic_rates_idx; + u8 idx = mlink->mcast_rates_idx ? + mlink->mcast_rates_idx : mlink->basic_rates_idx; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc)); bmc = (struct bss_rate_tlv *)tlv; bmc->short_preamble = (band == NL80211_BAND_2GHZ); bmc->bc_fixed_rate = idx; bmc->mc_fixed_rate = idx; } static void mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en) { struct bss_txcmd_tlv *txcmd; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_TXCMD, sizeof(*txcmd)); txcmd = (struct bss_txcmd_tlv *)tlv; txcmd->txcmd_mode = en; } static void -mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct bss_mld_tlv *mld; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); mld = (struct bss_mld_tlv *)tlv; mld->group_mld_id = 0xff; - mld->own_mld_id = mvif->mt76.idx; + mld->own_mld_id = mlink->idx; mld->remap_idx = 0xff; } static void -mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct bss_sec_tlv *sec; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec)); sec = (struct bss_sec_tlv *)tlv; - sec->cipher = mvif->cipher; + sec->cipher = mlink->cipher; } static int -mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif, - bool bssid, bool enable) +mt7996_mcu_muar_config(struct mt7996_dev *dev, struct mt76_vif_link *mlink, + const u8 *addr, bool bssid, bool enable) { #define UNI_MUAR_ENTRY 2 - struct mt7996_dev *dev = phy->dev; - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START; - const u8 *addr = vif->addr; - + u32 idx = mlink->omac_idx - REPEATER_BSSID_START; struct { struct { u8 band; u8 __rsv[3]; } hdr; __le16 tag; __le16 len; bool smesh; u8 bssid; u8 index; u8 entry_add; u8 addr[ETH_ALEN]; u8 __rsv[2]; } __packed req = { - .hdr.band = phy->mt76->band_idx, + .hdr.band = mlink->band_idx, .tag = cpu_to_le16(UNI_MUAR_ENTRY), .len = cpu_to_le16(sizeof(req) - sizeof(req.hdr)), .smesh = false, .index = idx * 2 + bssid, .entry_add = true, }; - if (bssid) - addr = vif->bss_conf.bssid; - if (enable) memcpy(req.addr, addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req, sizeof(req), true); } static void -mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif) +mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mvif->phy; struct bss_ifs_time_tlv *ifs_time; struct tlv *tlv; bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time)); ifs_time = (struct bss_ifs_time_tlv *)tlv; ifs_time->slot_valid = true; ifs_time->sifs_valid = true; ifs_time->rifs_valid = true; ifs_time->eifs_valid = true; ifs_time->slot_time = cpu_to_le16(phy->slottime); ifs_time->sifs_time = cpu_to_le16(10); ifs_time->rifs_time = cpu_to_le16(2); ifs_time->eifs_time = cpu_to_le16(is_2ghz ? 78 : 84); if (is_2ghz) { ifs_time->eifs_cck_valid = true; ifs_time->eifs_cck_time = cpu_to_le16(314); } } static int mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mvif, struct mt76_phy *phy, u16 wlan_idx, bool enable) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct cfg80211_chan_def *chandef = &phy->chandef; struct mt76_connac_bss_basic_tlv *bss; u32 type = CONNECTION_INFRA_AP; u16 sta_wlan_idx = wlan_idx; + struct ieee80211_sta *sta; struct tlv *tlv; int idx; switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MONITOR: break; case NL80211_IFTYPE_STATION: if (enable) { rcu_read_lock(); - if (!sta) - sta = ieee80211_find_sta(vif, - vif->bss_conf.bssid); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */ if (sta) { struct mt76_wcid *wcid; wcid = (struct mt76_wcid *)sta->drv_priv; sta_wlan_idx = wcid->idx; } rcu_read_unlock(); } type = CONNECTION_INFRA_STA; break; case NL80211_IFTYPE_ADHOC: type = CONNECTION_IBSS_ADHOC; break; default: WARN_ON(1); break; } tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*bss)); bss = (struct mt76_connac_bss_basic_tlv *)tlv; - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); - bss->dtim_period = vif->bss_conf.dtim_period; + bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); + bss->dtim_period = link_conf->dtim_period; bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); bss->sta_idx = cpu_to_le16(sta_wlan_idx); bss->conn_type = cpu_to_le32(type); bss->omac_idx = mvif->omac_idx; bss->band_idx = mvif->band_idx; bss->wmm_idx = mvif->wmm_idx; bss->conn_state = !enable; bss->active = enable; idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx; bss->hw_bss_idx = idx; if (vif->type == NL80211_IFTYPE_MONITOR) { memcpy(bss->bssid, phy->macaddr, ETH_ALEN); return 0; } - memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN); - bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int); + memcpy(bss->bssid, link_conf->bssid, ETH_ALEN); + bss->bcn_interval = cpu_to_le16(link_conf->beacon_int); bss->dtim_period = vif->bss_conf.dtim_period; bss->phymode = mt76_connac_get_phy_mode(phy, vif, chandef->chan->band, NULL); - bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif, + bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, &vif->bss_conf, chandef->chan->band); return 0; } static struct sk_buff * -__mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len) +__mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int len) { struct bss_req_hdr hdr = { .bss_idx = mvif->idx, }; struct sk_buff *skb; skb = mt76_mcu_msg_alloc(dev, NULL, len); if (!skb) return ERR_PTR(-ENOMEM); skb_put_data(skb, &hdr, sizeof(hdr)); return skb; } -int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, int enable) +int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, int enable) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = phy->dev; struct sk_buff *skb; - if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) { - mt7996_mcu_muar_config(phy, vif, false, enable); - mt7996_mcu_muar_config(phy, vif, true, enable); + if (mlink->omac_idx >= REPEATER_BSSID_START) { + mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); + mt7996_mcu_muar_config(dev, mlink, link_conf->bssid, true, enable); } - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* bss_basic must be first */ - mt7996_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76, - mvif->sta.wcid.idx, enable); - mt7996_mcu_bss_sec_tlv(skb, vif); + mt7996_mcu_bss_basic_tlv(skb, vif, link_conf, mlink, phy->mt76, + mlink->wcid->idx, enable); + mt7996_mcu_bss_sec_tlv(skb, mlink); if (vif->type == NL80211_IFTYPE_MONITOR) goto out; if (enable) { - mt7996_mcu_bss_rfch_tlv(skb, vif, phy); - mt7996_mcu_bss_bmc_tlv(skb, vif, phy); - mt7996_mcu_bss_ra_tlv(skb, vif, phy); + mt7996_mcu_bss_rfch_tlv(skb, phy); + mt7996_mcu_bss_bmc_tlv(skb, mlink, phy); + mt7996_mcu_bss_ra_tlv(skb, phy); mt7996_mcu_bss_txcmd_tlv(skb, true); - mt7996_mcu_bss_ifs_timing_tlv(skb, vif); + mt7996_mcu_bss_ifs_timing_tlv(skb, phy); if (vif->bss_conf.he_support) - mt7996_mcu_bss_he_tlv(skb, vif, phy); + mt7996_mcu_bss_he_tlv(skb, vif, link_conf, phy); /* this tag is necessary no matter if the vif is MLD */ - mt7996_mcu_bss_mld_tlv(skb, vif); + mt7996_mcu_bss_mld_tlv(skb, mlink); } + + mt7996_mcu_bss_mbssid_tlv(skb, link_conf, enable); + out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } -int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = phy->dev; + struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); struct sk_buff *skb; - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7996_mcu_bss_ifs_timing_tlv(skb, vif); + mt7996_mcu_bss_ifs_timing_tlv(skb, phy); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } static int -mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif, struct ieee80211_ampdu_params *params, bool enable, bool tx) { struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv; struct sta_rec_ba_uni *ba; struct sk_buff *skb; struct tlv *tlv; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba)); ba = (struct sta_rec_ba_uni *)tlv; ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT; ba->winsize = cpu_to_le16(params->buf_size); ba->ssn = cpu_to_le16(params->ssn); ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; + ba->ba_rdd_rro = !tx && enable && dev->has_rro; - return mt76_mcu_skb_send_msg(dev, skb, + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } /** starec & wtbl **/ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; struct mt7996_vif *mvif = msta->vif; if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, true); + return mt7996_mcu_sta_ba(dev, &mvif->deflink.mt76, params, enable, true); } int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, bool enable) { struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; struct mt7996_vif *mvif = msta->vif; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, false); + return mt7996_mcu_sta_ba(dev, &mvif->deflink.mt76, params, enable, false); } static void mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; struct ieee80211_he_mcs_nss_supp mcs_map; struct sta_rec_he_v2 *he; struct tlv *tlv; int i = 0; if (!sta->deflink.he_cap.has_he) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he)); he = (struct sta_rec_he_v2 *)tlv; for (i = 0; i < 11; i++) { if (i < 6) he->he_mac_cap[i] = elem->mac_cap_info[i]; he->he_phy_cap[i] = elem->phy_cap_info[i]; } mcs_map = sta->deflink.he_cap.he_mcs_nss_supp; switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: if (elem->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) mt7996_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW8080], le16_to_cpu(mcs_map.rx_mcs_80p80)); mt7996_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW160], le16_to_cpu(mcs_map.rx_mcs_160)); fallthrough; default: mt7996_mcu_set_sta_he_mcs(sta, &he->max_nss_mcs[CMD_HE_MCS_BW80], le16_to_cpu(mcs_map.rx_mcs_80)); break; } he->pkt_ext = 2; } static void mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct sta_rec_he_6g_capa *he_6g; struct tlv *tlv; if (!sta->deflink.he_6ghz_capa.capa) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g)); he_6g = (struct sta_rec_he_6g_capa *)tlv; he_6g->capa = sta->deflink.he_6ghz_capa.capa; } static void mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct ieee80211_vif *vif = container_of((void *)msta->vif, + struct ieee80211_vif, drv_priv); struct ieee80211_eht_mcs_nss_supp *mcs_map; struct ieee80211_eht_cap_elem_fixed *elem; struct sta_rec_eht *eht; struct tlv *tlv; if (!sta->deflink.eht_cap.has_eht) return; mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp; elem = &sta->deflink.eht_cap.eht_cap_elem; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht)); eht = (struct sta_rec_eht *)tlv; eht->tid_bitmap = 0xff; eht->mac_cap = cpu_to_le16(*(u16 *)elem->mac_cap_info); eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info); eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]); - if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) - memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20)); + if (vif->type != NL80211_IFTYPE_STATION && + (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) { + memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, + sizeof(eht->mcs_map_bw20)); + return; + } + memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80)); memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160)); memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320)); } static void mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct sta_rec_ht *ht; + struct sta_rec_ht_uni *ht; struct tlv *tlv; if (!sta->deflink.ht_cap.ht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; + ht = (struct sta_rec_ht_uni *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); + ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor, + IEEE80211_HT_AMPDU_PARM_FACTOR) | + u8_encode_bits(sta->deflink.ht_cap.ampdu_density, + IEEE80211_HT_AMPDU_PARM_DENSITY); } static void mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { struct sta_rec_vht *vht; struct tlv *tlv; /* For 6G band, this tlv is necessary to let hw work normally */ if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht)); vht = (struct sta_rec_vht *)tlv; vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map; vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map; } static void mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct sta_rec_amsdu *amsdu; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_MESH_POINT && vif->type != NL80211_IFTYPE_AP) return; if (!sta->deflink.agg.max_amsdu_len) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu)); amsdu = (struct sta_rec_amsdu *)tlv; amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; msta->wcid.amsdu = true; switch (sta->deflink.agg.max_amsdu_len) { case IEEE80211_MAX_MPDU_LEN_VHT_11454: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; return; case IEEE80211_MAX_MPDU_LEN_HT_7935: case IEEE80211_MAX_MPDU_LEN_VHT_7991: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; return; default: amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; return; } } static void mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem; struct sta_rec_muru *muru; struct tlv *tlv; if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru)); muru = (struct sta_rec_muru *)tlv; muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer || vif->bss_conf.he_mu_beamformer || vif->bss_conf.vht_mu_beamformer || vif->bss_conf.vht_mu_beamformee; muru->cfg.ofdma_dl_en = true; if (sta->deflink.vht_cap.vht_supported) muru->mimo_dl.vht_mu_bfee = !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); if (!sta->deflink.he_cap.has_he) return; muru->mimo_dl.partial_bw_dl_mimo = HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]); muru->mimo_ul.full_ul_mimo = HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]); muru->mimo_ul.partial_ul_mimo = HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); muru->ofdma_dl.punc_pream_rx = HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]); muru->ofdma_dl.he_20m_in_40m_2g = HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]); muru->ofdma_dl.he_20m_in_160m = HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); muru->ofdma_dl.he_80m_in_160m = HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]); muru->ofdma_ul.t_frame_dur = HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]); muru->ofdma_ul.mu_cascading = HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]); muru->ofdma_ul.uo_ra = HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]); + muru->ofdma_ul.rx_ctrl_frame_to_mbss = + HE_MAC(CAP3_RX_CTRL_FRAME_TO_MULTIBSS, elem->mac_cap_info[3]); } static inline bool mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool bfee) { int sts = hweight16(phy->mt76->chainmask); if (vif->type != NL80211_IFTYPE_STATION && vif->type != NL80211_IFTYPE_AP) return false; if (!bfee && sts < 2) return false; if (sta->deflink.eht_cap.has_eht) { struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap; struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem; if (bfee) return vif->bss_conf.eht_su_beamformee && - EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]); + EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]); else return vif->bss_conf.eht_su_beamformer && - EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]); + EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]); } if (sta->deflink.he_cap.has_he) { struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; if (bfee) return vif->bss_conf.he_su_beamformee && HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]); else return vif->bss_conf.he_su_beamformer && HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]); } if (sta->deflink.vht_cap.vht_supported) { u32 cap = sta->deflink.vht_cap.cap; if (bfee) return vif->bss_conf.vht_su_beamformee && (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); else return vif->bss_conf.vht_su_beamformer && (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE); } return false; } static void -mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf) +mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf, struct mt7996_phy *phy) { bf->sounding_phy = MT_PHY_TYPE_OFDM; bf->ndp_rate = 0; /* mcs0 */ - bf->ndpa_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */ + if (is_mt7996(phy->mt76->dev)) + bf->ndpa_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */ + else + bf->ndpa_rate = MT7992_CFEND_RATE_DEFAULT; /* ofdm 6m */ + bf->rept_poll_rate = MT7996_CFEND_RATE_DEFAULT; /* ofdm 24m */ } static void mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy, - struct sta_rec_bf *bf) + struct sta_rec_bf *bf, bool explicit) { struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs; u8 n = 0; bf->tx_mode = MT_PHY_TYPE_HT; if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) && (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED)) n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK, mcs->tx_params); else if (mcs->rx_mask[3]) n = 3; else if (mcs->rx_mask[2]) n = 2; else if (mcs->rx_mask[1]) n = 1; bf->nrow = hweight8(phy->mt76->antenna_mask) - 1; bf->ncol = min_t(u8, bf->nrow, n); - bf->ibf_ncol = n; + bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) : + min_t(u8, MT7996_IBF_MAX_NC, n); } static void mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy, struct sta_rec_bf *bf, bool explicit) { struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap; u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map); u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); u8 tx_ant = hweight8(phy->mt76->antenna_mask) - 1; bf->tx_mode = MT_PHY_TYPE_VHT; if (explicit) { u8 sts, snd_dim; - mt7996_mcu_sta_sounding_rate(bf); + mt7996_mcu_sta_sounding_rate(bf, phy); sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, pc->cap); snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, vc->cap); bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant); bf->ncol = min_t(u8, nss_mcs, bf->nrow); - bf->ibf_ncol = bf->ncol; + bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, bf->ncol); if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) bf->nrow = 1; } else { bf->nrow = tx_ant; bf->ncol = min_t(u8, nss_mcs, bf->nrow); - bf->ibf_ncol = nss_mcs; + bf->ibf_ncol = min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) bf->ibf_nrow = 1; } } static void mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, - struct mt7996_phy *phy, struct sta_rec_bf *bf) + struct mt7996_phy *phy, struct sta_rec_bf *bf, + bool explicit) { struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap; struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem; const struct ieee80211_sta_he_cap *vc = mt76_connac_get_he_phy_cap(phy->mt76, vif); const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem; u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80); u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); u8 snd_dim, sts; + if (!vc) + return; + bf->tx_mode = MT_PHY_TYPE_HE_SU; - mt7996_mcu_sta_sounding_rate(bf); + mt7996_mcu_sta_sounding_rate(bf, phy); bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB, pe->phy_cap_info[6]); bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB, pe->phy_cap_info[6]); snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, ve->phy_cap_info[5]); sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK, pe->phy_cap_info[4]); bf->nrow = min_t(u8, snd_dim, sts); bf->ncol = min_t(u8, nss_mcs, bf->nrow); - bf->ibf_ncol = bf->ncol; + bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) : + min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160) return; /* go over for 160MHz and 80p80 */ if (pe->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) { mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); bf->ncol_gt_bw80 = nss_mcs; } if (pe->phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); nss_mcs = mt7996_mcu_get_sta_nss(mcs_map); if (bf->ncol_gt_bw80) bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs); else bf->ncol_gt_bw80 = nss_mcs; } snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, ve->phy_cap_info[5]); sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, pe->phy_cap_info[4]); bf->nrow_gt_bw80 = min_t(int, snd_dim, sts); } static void mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif, - struct mt7996_phy *phy, struct sta_rec_bf *bf) + struct mt7996_phy *phy, struct sta_rec_bf *bf, + bool explicit) { struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap; struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem; struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp; const struct ieee80211_sta_eht_cap *vc = mt76_connac_get_eht_phy_cap(phy->mt76, vif); const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem; u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss, IEEE80211_EHT_MCS_NSS_RX) - 1; u8 snd_dim, sts; bf->tx_mode = MT_PHY_TYPE_EHT_MU; - mt7996_mcu_sta_sounding_rate(bf); + mt7996_mcu_sta_sounding_rate(bf, phy); bf->trigger_su = EHT_PHY(CAP3_TRIG_SU_BF_FDBK, pe->phy_cap_info[3]); bf->trigger_mu = EHT_PHY(CAP3_TRIG_MU_BF_PART_BW_FDBK, pe->phy_cap_info[3]); snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_80MHZ_MASK, ve->phy_cap_info[2]); sts = EHT_PHY(CAP0_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[0]) + (EHT_PHY(CAP1_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[1]) << 1); bf->nrow = min_t(u8, snd_dim, sts); bf->ncol = min_t(u8, nss_mcs, bf->nrow); - bf->ibf_ncol = bf->ncol; + bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) : + min_t(u8, MT7996_IBF_MAX_NC, nss_mcs); if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160) return; switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]); sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]); nss_mcs = u8_get_bits(eht_nss->bw._160.rx_tx_mcs9_max_nss, IEEE80211_EHT_MCS_NSS_RX) - 1; bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts); bf->ncol_gt_bw80 = nss_mcs; break; case IEEE80211_STA_RX_BW_320: snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_320MHZ_MASK, ve->phy_cap_info[2]) + (EHT_PHY(CAP3_SOUNDING_DIM_320MHZ_MASK, ve->phy_cap_info[3]) << 1); sts = EHT_PHY(CAP1_BEAMFORMEE_SS_320MHZ_MASK, pe->phy_cap_info[1]); nss_mcs = u8_get_bits(eht_nss->bw._320.rx_tx_mcs9_max_nss, IEEE80211_EHT_MCS_NSS_RX) - 1; bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts) << 4; bf->ncol_gt_bw80 = nss_mcs << 4; break; default: break; } } static void mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { +#define EBF_MODE BIT(0) +#define IBF_MODE BIT(1) +#define BF_MAT_ORDER 4 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mvif->phy; - int tx_ant = hweight8(phy->mt76->chainmask) - 1; + struct mt7996_phy *phy = mvif->deflink.phy; + int tx_ant = hweight16(phy->mt76->chainmask) - 1; struct sta_rec_bf *bf; struct tlv *tlv; - const u8 matrix[4][4] = { + static const u8 matrix[BF_MAT_ORDER][BF_MAT_ORDER] = { {0, 0, 0, 0}, {1, 1, 0, 0}, /* 2x1, 2x2, 2x3, 2x4 */ {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ }; bool ebf; if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) return; ebf = mt7996_is_ebf_supported(phy, vif, sta, false); if (!ebf && !dev->ibf) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf)); bf = (struct sta_rec_bf *)tlv; - /* he/eht: eBF only, in accordance with spec + /* he/eht: eBF only, except mt7992 that has 5T on 5GHz also supports iBF * vht: support eBF and iBF * ht: iBF only, since mac80211 lacks of eBF support */ - if (sta->deflink.eht_cap.has_eht && ebf) - mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf); - else if (sta->deflink.he_cap.has_he && ebf) - mt7996_mcu_sta_bfer_he(sta, vif, phy, bf); + if (sta->deflink.eht_cap.has_eht) + mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf, ebf); + else if (sta->deflink.he_cap.has_he) + mt7996_mcu_sta_bfer_he(sta, vif, phy, bf, ebf); else if (sta->deflink.vht_cap.vht_supported) mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf); else if (sta->deflink.ht_cap.ht_supported) - mt7996_mcu_sta_bfer_ht(sta, phy, bf); + mt7996_mcu_sta_bfer_ht(sta, phy, bf, ebf); else return; - bf->bf_cap = ebf ? ebf : dev->ibf << 1; + bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0); + if (is_mt7992(&dev->mt76) && tx_ant == 4) + bf->bf_cap |= IBF_MODE; bf->bw = sta->deflink.bandwidth; bf->ibf_dbw = sta->deflink.bandwidth; bf->ibf_nrow = tx_ant; - if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) - bf->ibf_timeout = 0x48; + if (sta->deflink.eht_cap.has_eht || sta->deflink.he_cap.has_he) + bf->ibf_timeout = is_mt7996(&dev->mt76) ? MT7996_IBF_TIMEOUT : + MT7992_IBF_TIMEOUT; + else if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol) + bf->ibf_timeout = MT7996_IBF_TIMEOUT_LEGACY; else - bf->ibf_timeout = 0x18; + bf->ibf_timeout = MT7996_IBF_TIMEOUT; - if (ebf && bf->nrow != tx_ant) - bf->mem_20m = matrix[tx_ant][bf->ncol]; - else - bf->mem_20m = matrix[bf->nrow][bf->ncol]; + if (bf->ncol < BF_MAT_ORDER) { + if (ebf) + bf->mem_20m = tx_ant < BF_MAT_ORDER ? + matrix[tx_ant][bf->ncol] : 0; + else + bf->mem_20m = bf->nrow < BF_MAT_ORDER ? + matrix[bf->nrow][bf->ncol] : 0; + } switch (sta->deflink.bandwidth) { case IEEE80211_STA_RX_BW_160: case IEEE80211_STA_RX_BW_80: bf->mem_total = bf->mem_20m * 2; break; case IEEE80211_STA_RX_BW_40: bf->mem_total = bf->mem_20m; break; case IEEE80211_STA_RX_BW_20: default: break; } } static void mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_phy *phy = mvif->phy; + struct mt7996_phy *phy = mvif->deflink.phy; int tx_ant = hweight8(phy->mt76->antenna_mask) - 1; struct sta_rec_bfee *bfee; struct tlv *tlv; u8 nrow = 0; if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he)) return; if (!mt7996_is_ebf_supported(phy, vif, sta, true)) return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee)); bfee = (struct sta_rec_bfee *)tlv; if (sta->deflink.he_cap.has_he) { struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem; nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, pe->phy_cap_info[5]); } else if (sta->deflink.vht_cap.vht_supported) { struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap; nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, pc->cap); } /* reply with identity matrix to avoid 2x2 BF negative gain */ bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } static void -mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) +mt7996_mcu_sta_tx_proc_tlv(struct sk_buff *skb) { - struct sta_rec_phy *phy; + struct sta_rec_tx_proc *tx_proc; struct tlv *tlv; - u8 af = 0, mm = 0; - if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) - return; - - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); - - phy = (struct sta_rec_phy *)tlv; - if (sta->deflink.ht_cap.ht_supported) { - af = sta->deflink.ht_cap.ampdu_factor; - mm = sta->deflink.ht_cap.ampdu_density; - } - - if (sta->deflink.vht_cap.vht_supported) { - u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, - sta->deflink.vht_cap.cap); + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_TX_PROC, sizeof(*tx_proc)); - af = max_t(u8, af, vht_af); - } - - if (sta->deflink.he_6ghz_capa.capa) { - af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); - mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); - } - - phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) | - FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm); - phy->max_ampdu_len = af; + tx_proc = (struct sta_rec_tx_proc *)tlv; + tx_proc->flag = cpu_to_le32(0); } static void mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb) { struct sta_rec_hdrt *hdrt; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDRT, sizeof(*hdrt)); hdrt = (struct sta_rec_hdrt *)tlv; hdrt->hdrt_mode = 1; } static void mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_vif *vif, struct mt76_wcid *wcid) { struct sta_rec_hdr_trans *hdr_trans; - struct mt76_wcid *wcid; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans)); hdr_trans = (struct sta_rec_hdr_trans *)tlv; hdr_trans->dis_rx_hdr_tran = true; if (vif->type == NL80211_IFTYPE_STATION) hdr_trans->to_ds = true; else hdr_trans->from_ds = true; - wcid = (struct mt76_wcid *)sta->drv_priv; if (!wcid) return; hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { hdr_trans->to_ds = true; hdr_trans->from_ds = true; } if (vif->type == NL80211_IFTYPE_MESH_POINT) { hdr_trans->to_ds = true; hdr_trans->from_ds = true; hdr_trans->mesh = true; } } static enum mcu_mmps_mode mt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps) { switch (smps) { case IEEE80211_SMPS_OFF: return MCU_MMPS_DISABLE; case IEEE80211_SMPS_STATIC: return MCU_MMPS_STATIC; case IEEE80211_SMPS_DYNAMIC: return MCU_MMPS_DYNAMIC; default: return MCU_MMPS_DISABLE; } } int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version) { struct ra_fixed_rate *req; struct uni_header hdr; struct sk_buff *skb; struct tlv *tlv; int len; len = sizeof(hdr) + sizeof(*req); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); tlv = mt7996_mcu_add_uni_tlv(skb, UNI_RA_FIXED_RATE, sizeof(*req)); req = (struct ra_fixed_rate *)tlv; req->version = cpu_to_le16(version); memcpy(&req->rate, data, sizeof(req->rate)); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(RA), true); } +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct sta_phy_uni *phy = data; + struct sta_rec_ra_fixed_uni *ra; + struct sk_buff *skb; + struct tlv *tlv; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, + &msta->wcid, + MT7996_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); + ra = (struct sta_rec_ra_fixed_uni *)tlv; + + switch (field) { + case RATE_PARAM_AUTO: + break; + case RATE_PARAM_FIXED: + case RATE_PARAM_FIXED_MCS: + case RATE_PARAM_FIXED_GI: + case RATE_PARAM_FIXED_HE_LTF: + if (phy) + ra->phy = *phy; + break; + case RATE_PARAM_MMPS_UPDATE: + ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); + break; + default: + break; + } + ra->field = cpu_to_le32(field); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + +static int +mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct cfg80211_chan_def *chandef = &mvif->deflink.phy->mt76->chandef; + struct cfg80211_bitrate_mask *mask = &mvif->deflink.bitrate_mask; + enum nl80211_band band = chandef->chan->band; + struct sta_phy_uni phy = {}; + int ret, nrates = 0; + +#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ + do { \ + u8 i, gi = mask->control[band]._gi; \ + gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI; \ + phy.sgi = gi; \ + phy.he_ltf = mask->control[band].he_ltf; \ + for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) { \ + if (!mask->control[band]._mcs[i]) \ + continue; \ + nrates += hweight16(mask->control[band]._mcs[i]); \ + phy.mcs = ffs(mask->control[band]._mcs[i]) - 1; \ + if (_ht) \ + phy.mcs += 8 * i; \ + } \ + } while (0) + + if (sta->deflink.he_cap.has_he) { + __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1); + } else if (sta->deflink.vht_cap.vht_supported) { + __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0); + } else if (sta->deflink.ht_cap.ht_supported) { + __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0); + } else { + nrates = hweight32(mask->control[band].legacy); + phy.mcs = ffs(mask->control[band].legacy) - 1; + } +#undef __sta_phy_bitrate_mask_check + + /* fall back to auto rate control */ + if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI && + mask->control[band].he_gi == GENMASK(7, 0) && + mask->control[band].he_ltf == GENMASK(7, 0) && + nrates != 1) + return 0; + + /* fixed single rate */ + if (nrates == 1) { + ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, + RATE_PARAM_FIXED_MCS); + if (ret) + return ret; + } + + /* fixed GI */ + if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI || + mask->control[band].he_gi != GENMASK(7, 0)) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + u32 addr; + + /* firmware updates only TXCMD but doesn't take WTBL into + * account, so driver should update here to reflect the + * actual txrate hardware sends out. + */ + addr = mt7996_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7); + if (sta->deflink.he_cap.has_he) + mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi); + else + mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi); + + ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, + RATE_PARAM_FIXED_GI); + if (ret) + return ret; + } + + /* fixed HE_LTF */ + if (mask->control[band].he_ltf != GENMASK(7, 0)) { + ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy, + RATE_PARAM_FIXED_HE_LTF); + if (ret) + return ret; + } + + return 0; +} + static void mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { +#define INIT_RCPI 180 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt76_phy *mphy = mvif->phy->mt76; + struct mt76_phy *mphy = mvif->deflink.phy->mt76; struct cfg80211_chan_def *chandef = &mphy->chandef; - struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; + struct cfg80211_bitrate_mask *mask = &mvif->deflink.bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_rec_ra *ra; + struct sta_rec_ra_uni *ra; struct tlv *tlv; u32 supp_rate = sta->deflink.supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); - ra = (struct sta_rec_ra *)tlv; + ra = (struct sta_rec_ra_uni *)tlv; ra->valid = true; ra->auto_rate = true; - ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta); + ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink); ra->channel = chandef->chan->hw_value; ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ? CMD_CBW_320MHZ : sta->deflink.bandwidth; ra->phy.bw = ra->bw; ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); if (supp_rate) { supp_rate &= mask->control[band].legacy; ra->rate_len = hweight32(supp_rate); if (band == NL80211_BAND_2GHZ) { ra->supp_mode = MODE_CCK; ra->supp_cck_rate = supp_rate & GENMASK(3, 0); if (ra->rate_len > 4) { ra->supp_mode |= MODE_OFDM; ra->supp_ofdm_rate = supp_rate >> 4; } } else { ra->supp_mode = MODE_OFDM; ra->supp_ofdm_rate = supp_rate; } } if (sta->deflink.ht_cap.ht_supported) { ra->supp_mode |= MODE_HT; ra->af = sta->deflink.ht_cap.ampdu_factor; ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); cap |= STA_CAP_HT; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) cap |= STA_CAP_SGI_20; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40) cap |= STA_CAP_SGI_40; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC) cap |= STA_CAP_TX_STBC; if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) cap |= STA_CAP_RX_STBC; if (vif->bss_conf.ht_ldpc && (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING)) cap |= STA_CAP_LDPC; mt7996_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mask->control[band].ht_mcs); ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs; } if (sta->deflink.vht_cap.vht_supported) { u8 af; ra->supp_mode |= MODE_VHT; af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, sta->deflink.vht_cap.cap); ra->af = max_t(u8, ra->af, af); cap |= STA_CAP_VHT; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) cap |= STA_CAP_VHT_SGI_80; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160) cap |= STA_CAP_VHT_SGI_160; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) cap |= STA_CAP_VHT_TX_STBC; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) cap |= STA_CAP_VHT_RX_STBC; - if (vif->bss_conf.vht_ldpc && + if ((vif->type != NL80211_IFTYPE_AP || vif->bss_conf.vht_ldpc) && (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) cap |= STA_CAP_VHT_LDPC; mt7996_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mask->control[band].vht_mcs); } if (sta->deflink.he_cap.has_he) { ra->supp_mode |= MODE_HE; cap |= STA_CAP_HE; if (sta->deflink.he_6ghz_capa.capa) ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); } ra->sta_cap = cpu_to_le32(cap); + + memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi)); } int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct sk_buff *skb; + int ret; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, &msta->wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* firmware rc algorithm refers to sta_rec_he for HE control. * once dev->rc_work changes the settings driver should also * update sta_rec_he here. */ if (changed) mt7996_mcu_sta_he_tlv(skb, sta); /* sta_rec_ra accommodates BW, NSS and only MCS range format * i.e 0-{7,8,9} for VHT. */ mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta); - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); + ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); + if (ret) + return ret; + + return mt7996_mcu_add_rate_ctrl_fixed(dev, vif, sta); } static int mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { #define MT_STA_BSS_GROUP 1 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta; struct { u8 __rsv1[4]; __le16 tag; __le16 len; __le16 wlan_idx; u8 __rsv2[2]; __le32 action; __le32 val; u8 __rsv3[8]; } __packed req = { .tag = cpu_to_le16(UNI_VOW_DRR_CTRL), .len = cpu_to_le16(sizeof(req) - 4), .action = cpu_to_le32(MT_STA_BSS_GROUP), - .val = cpu_to_le32(mvif->mt76.idx % 16), + .val = cpu_to_le32(mvif->deflink.mt76.idx % 16), }; - msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta; + msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->deflink.sta; req.wlan_idx = cpu_to_le16(msta->wcid.idx); return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req, sizeof(req), true); } int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable) + struct mt76_vif_link *mlink, + struct ieee80211_sta *sta, int conn_state, bool newly) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_sta *msta; + struct ieee80211_link_sta *link_sta = NULL; + struct mt76_wcid *wcid = mlink->wcid; struct sk_buff *skb; int ret; - msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta; + if (sta) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, - &msta->wcid, + wcid = &msta->wcid; + link_sta = &sta->deflink; + } + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mlink, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* starec basic */ - mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable, - !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx])); - if (!enable) + mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta, + conn_state, newly); + + if (conn_state == CONN_STATE_DISCONNECT) goto out; + /* starec hdr trans */ + mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, wcid); + /* starec tx proc */ + mt7996_mcu_sta_tx_proc_tlv(skb); + /* tag order is in accordance with firmware dependency. */ if (sta) { - /* starec phy */ - mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta); /* starec hdrt mode */ mt7996_mcu_sta_hdrt_tlv(dev, skb); /* starec bfer */ mt7996_mcu_sta_bfer_tlv(dev, skb, vif, sta); /* starec ht */ mt7996_mcu_sta_ht_tlv(skb, sta); /* starec vht */ mt7996_mcu_sta_vht_tlv(skb, sta); /* starec uapsd */ mt76_connac_mcu_sta_uapsd(skb, vif, sta); /* starec amsdu */ mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta); /* starec he */ mt7996_mcu_sta_he_tlv(skb, sta); /* starec he 6g*/ mt7996_mcu_sta_he_6g_tlv(skb, sta); /* starec eht */ mt7996_mcu_sta_eht_tlv(skb, sta); /* starec muru */ mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta); /* starec bfee */ mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta); - /* starec hdr trans */ - mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta); } ret = mt7996_mcu_add_group(dev, vif, sta); if (ret) { dev_kfree_skb(skb); return ret; } out: return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } static int mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, - struct mt76_connac_sta_key_conf *sta_key_conf, struct sk_buff *skb, struct ieee80211_key_conf *key, enum set_key_cmd cmd) { struct sta_rec_sec_uni *sec; struct tlv *tlv; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; sec->add = cmd; if (cmd == SET_KEY) { struct sec_key_uni *sec_key; u8 cipher; cipher = mt76_connac_mcu_get_cipher(key->cipher); if (cipher == MCU_CIPHER_NONE) return -EOPNOTSUPP; sec_key = &sec->key[0]; + sec_key->wlan_idx = cpu_to_le16(wcid->idx); + sec_key->mgmt_prot = 0; + sec_key->cipher_id = cipher; sec_key->cipher_len = sizeof(*sec_key); - - if (cipher == MCU_CIPHER_BIP_CMAC_128) { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_AES_CCMP; - sec_key->key_id = sta_key_conf->keyidx; - sec_key->key_len = 16; - memcpy(sec_key->key, sta_key_conf->key, 16); - - sec_key = &sec->key[1]; - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; - sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_len = 16; - memcpy(sec_key->key, key->key, 16); - sec->n_cipher = 2; - } else { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = cipher; - sec_key->key_id = key->keyidx; - sec_key->key_len = key->keylen; - memcpy(sec_key->key, key->key, key->keylen); - - if (cipher == MCU_CIPHER_TKIP) { - /* Rx/Tx MIC keys are swapped */ - memcpy(sec_key->key + 16, key->key + 24, 8); - memcpy(sec_key->key + 24, key->key + 16, 8); - } - - /* store key_conf for BIP batch update */ - if (cipher == MCU_CIPHER_AES_CCMP) { - memcpy(sta_key_conf->key, key->key, key->keylen); - sta_key_conf->keyidx = key->keyidx; - } - - sec->n_cipher = 1; + sec_key->key_id = key->keyidx; + sec_key->key_len = key->keylen; + sec_key->need_resp = 0; + memcpy(sec_key->key, key->key, key->keylen); + + if (cipher == MCU_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); } + + sec->n_cipher = 1; } else { sec->n_cipher = 0; } return 0; } int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd) { - struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct sk_buff *skb; int ret; skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7996_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd); + ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd); if (ret) return ret; return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } -int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, bool enable) +static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif, + u8 *pn) { - struct mt7996_dev *dev = phy->dev; +#define TSC_TYPE_BIGTK_PN 2 struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct sta_rec_pn_info *pn_info; + struct sk_buff *skb, *rskb; + struct tlv *tlv; + int ret; + + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, &mvif->deflink.sta.wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info)); + pn_info = (struct sta_rec_pn_info *)tlv; + + pn_info->tsc_type = TSC_TYPE_BIGTK_PN; + ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE), + true, &rskb); + if (ret) + return ret; + + skb_pull(rskb, 4); + + pn_info = (struct sta_rec_pn_info *)rskb->data; + if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO) + memcpy(pn, pn_info->pn, 6); + + dev_kfree_skb(rskb); + return 0; +} + +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_mcu_bcn_prot_tlv *bcn_prot; + struct sk_buff *skb; + struct tlv *tlv; + u8 pn[6] = {}; + int len = sizeof(struct bss_req_hdr) + + sizeof(struct mt7996_mcu_bcn_prot_tlv); + int ret; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot)); + + bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv; + + ret = mt7996_mcu_get_pn(dev, vif, pn); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + default: + dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n"); + dev_kfree_skb(skb); + return -EOPNOTSUPP; + } + + pn[0]++; + memcpy(bcn_prot->pn, pn, 6); + bcn_prot->enable = BP_SW_MODE; + memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN); + bcn_prot->key_id = key->keyidx; + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); +} + +int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, bool enable) +{ + struct mt7996_dev *dev = phy->dev; struct { struct req_hdr { u8 omac_idx; u8 band_idx; u8 __rsv[2]; } __packed hdr; struct req_tlv { __le16 tag; __le16 len; u8 active; u8 __rsv; u8 omac_addr[ETH_ALEN]; } __packed tlv; } data = { .hdr = { - .omac_idx = mvif->mt76.omac_idx, - .band_idx = mvif->mt76.band_idx, + .omac_idx = mlink->omac_idx, + .band_idx = mlink->band_idx, }, .tlv = { .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, }, }; - if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) - return mt7996_mcu_muar_config(phy, vif, false, enable); + if (mlink->omac_idx >= REPEATER_BSSID_START) + return mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); - memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN); + memcpy(data.tlv.omac_addr, link_conf->addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); } static void -mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb, - struct sk_buff *skb, - struct ieee80211_mutable_offsets *offs) +mt7996_mcu_beacon_cntdwn(struct sk_buff *rskb, struct sk_buff *skb, + struct ieee80211_mutable_offsets *offs, + bool csa) { struct bss_bcn_cntdwn_tlv *info; struct tlv *tlv; u16 tag; if (!offs->cntdwn_counter_offs[0]) return; - tag = vif->bss_conf.csa_active ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC; + tag = csa ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC; tlv = mt7996_mcu_add_uni_tlv(rskb, tag, sizeof(*info)); info = (struct bss_bcn_cntdwn_tlv *)tlv; info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; } static void -mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif, +mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb, + struct bss_bcn_content_tlv *bcn, + struct ieee80211_mutable_offsets *offs) +{ + struct bss_bcn_mbss_tlv *mbss; + const struct element *elem; + struct tlv *tlv; + + tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_MBSSID, sizeof(*mbss)); + + mbss = (struct bss_bcn_mbss_tlv *)tlv; + mbss->offset[0] = cpu_to_le16(offs->tim_offset); + mbss->bitmap = cpu_to_le32(1); + + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, + &skb->data[offs->mbssid_off], + skb->len - offs->mbssid_off) { + const struct element *sub_elem; + + if (elem->datalen < 2) + continue; + + for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) { + const struct ieee80211_bssid_index *idx; + const u8 *idx_ie; + + /* not a valid BSS profile */ + if (sub_elem->id || sub_elem->datalen < 4) + continue; + + /* Find WLAN_EID_MULTI_BSSID_IDX + * in the merged nontransmitted profile + */ + idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, + sub_elem->data, sub_elem->datalen); + if (!idx_ie || idx_ie[1] < sizeof(*idx)) + continue; + +#if defined(__linux__) + idx = (void *)(idx_ie + 2); +#elif defined(__FreeBSD__) + idx = (const void *)(idx_ie + 2); +#endif + if (!idx->bssid_index || idx->bssid_index > 31) + continue; + + mbss->offset[idx->bssid_index] = cpu_to_le16(idx_ie - + skb->data); + mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index)); + } + } +} + +static void +mt7996_mcu_beacon_cont(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, struct sk_buff *rskb, struct sk_buff *skb, struct bss_bcn_content_tlv *bcn, struct ieee80211_mutable_offsets *offs) { struct mt76_wcid *wcid = &dev->mt76.global_wcid; u8 *buf; bcn->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); bcn->tim_ie_pos = cpu_to_le16(offs->tim_offset); if (offs->cntdwn_counter_offs[0]) { u16 offset = offs->cntdwn_counter_offs[0]; - if (vif->bss_conf.csa_active) + if (link_conf->csa_active) bcn->csa_ie_pos = cpu_to_le16(offset - 4); - if (vif->bss_conf.color_change_active) + if (link_conf->color_change_active) bcn->bcc_ie_pos = cpu_to_le16(offset - 3); } - buf = (u8 *)bcn + sizeof(*bcn) - MAX_BEACON_SIZE; + buf = (u8 *)bcn + sizeof(*bcn); mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); } -int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int en) +int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = mt7996_hw_phy(hw); - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct sk_buff *skb, *rskb; struct tlv *tlv; struct bss_bcn_content_tlv *bcn; + int len, extra_len = 0; - rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, - MT7996_BEACON_UPDATE_SIZE); - if (IS_ERR(rskb)) - return PTR_ERR(rskb); + if (link_conf->nontransmitted) + return 0; - tlv = mt7996_mcu_add_uni_tlv(rskb, - UNI_BSS_INFO_BCN_CONTENT, sizeof(*bcn)); - bcn = (struct bss_bcn_content_tlv *)tlv; - bcn->enable = en; + if (!mlink) + return -EINVAL; - if (!en) - goto out; + rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, + MT7996_MAX_BSS_OFFLOAD_SIZE); + if (IS_ERR(rskb)) + return PTR_ERR(rskb); - skb = ieee80211_beacon_get_template(hw, vif, &offs, 0); - if (!skb) + skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id); + if (link_conf->enable_beacon && !skb) { + dev_kfree_skb(rskb); return -EINVAL; + } - if (skb->len > MAX_BEACON_SIZE - MT_TXD_SIZE) { - dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); - dev_kfree_skb(skb); - return -EINVAL; + if (skb) { + if (skb->len > MT7996_MAX_BEACON_SIZE) { + dev_err(dev->mt76.dev, "Bcn size limit exceed\n"); + dev_kfree_skb(rskb); + dev_kfree_skb(skb); + return -EINVAL; + } + + extra_len = skb->len; } + len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + extra_len, 4); + tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len); + bcn = (struct bss_bcn_content_tlv *)tlv; + bcn->enable = link_conf->enable_beacon; + if (!bcn->enable) + goto out; + info = IEEE80211_SKB_CB(skb); - info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mlink->band_idx); - mt7996_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs); - /* TODO: subtag - 11v MBSSID */ - mt7996_mcu_beacon_cntdwn(vif, rskb, skb, &offs); - dev_kfree_skb(skb); + mt7996_mcu_beacon_cont(dev, link_conf, rskb, skb, bcn, &offs); + if (link_conf->bssid_indicator) + mt7996_mcu_beacon_mbss(rskb, skb, bcn, &offs); + mt7996_mcu_beacon_cntdwn(rskb, skb, &offs, link_conf->csa_active); out: - return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, + dev_kfree_skb(skb); + return mt76_mcu_skb_send_msg(&dev->mt76, rskb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, struct ieee80211_vif *vif, u32 changed) { #define OFFLOAD_TX_MODE_SU BIT(0) #define OFFLOAD_TX_MODE_MU BIT(1) struct ieee80211_hw *hw = mt76_hw(dev); - struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; - enum nl80211_band band = chandef->chan->band; + struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct bss_inband_discovery_tlv *discov; struct ieee80211_tx_info *info; struct sk_buff *rskb, *skb = NULL; + struct cfg80211_chan_def *chandef; + enum nl80211_band band; struct tlv *tlv; u8 *buf, interval; + int len; - rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, - MT7996_INBAND_FRAME_SIZE); + if (!phy) + return -EINVAL; + + chandef = &phy->mt76->chandef; + band = chandef->chan->band; + + if (vif->bss_conf.nontransmitted) + return 0; + + rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->deflink.mt76, + MT7996_MAX_BSS_OFFLOAD_SIZE); if (IS_ERR(rskb)) return PTR_ERR(rskb); if (changed & BSS_CHANGED_FILS_DISCOVERY && vif->bss_conf.fils_discovery.max_interval) { interval = vif->bss_conf.fils_discovery.max_interval; skb = ieee80211_get_fils_discovery_tmpl(hw, vif); } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP && vif->bss_conf.unsol_bcast_probe_resp_interval) { interval = vif->bss_conf.unsol_bcast_probe_resp_interval; skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif); } - if (!skb) + if (!skb) { + dev_kfree_skb(rskb); return -EINVAL; + } - if (skb->len > MAX_INBAND_FRAME_SIZE - MT_TXD_SIZE) { + if (skb->len > MT7996_MAX_BEACON_SIZE) { dev_err(dev->mt76.dev, "inband discovery size limit exceed\n"); + dev_kfree_skb(rskb); dev_kfree_skb(skb); return -EINVAL; } info = IEEE80211_SKB_CB(skb); info->control.vif = vif; info->band = band; info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); - tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, sizeof(*discov)); + len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); + tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len); discov = (struct bss_inband_discovery_tlv *)tlv; discov->tx_mode = OFFLOAD_TX_MODE_SU; /* 0: UNSOL PROBE RESP, 1: FILS DISCOV */ discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY); discov->tx_interval = interval; discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len); discov->enable = true; discov->wcid = cpu_to_le16(MT7996_WTBL_RESERVED); - buf = (u8 *)tlv + sizeof(*discov) - MAX_INBAND_FRAME_SIZE; + buf = (u8 *)tlv + sizeof(*discov); mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed); memcpy(buf + MT_TXD_SIZE, skb->data, skb->len); dev_kfree_skb(skb); return mt76_mcu_skb_send_msg(&dev->mt76, rskb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } static int mt7996_driver_own(struct mt7996_dev *dev, u8 band) { mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN); if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) { dev_err(dev->mt76.dev, "Timeout for driver own\n"); return -EIO; } /* clear irq when the driver own success */ mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band), MT_TOP_LPCR_HOST_BAND_STAT); return 0; } static u32 mt7996_patch_sec_mode(u32 key_info) { u32 sec = u32_get_bits(key_info, MT7996_PATCH_SEC), key = 0; if (key_info == GENMASK(31, 0) || sec == MT7996_SEC_MODE_PLAIN) return 0; if (sec == MT7996_SEC_MODE_AES) key = u32_get_bits(key_info, MT7996_PATCH_AES_KEY); else key = u32_get_bits(key_info, MT7996_PATCH_SCRAMBLE_KEY); return MT7996_SEC_ENCRYPT | MT7996_SEC_IV | u32_encode_bits(key, MT7996_SEC_KEY_IDX); } static int mt7996_load_patch(struct mt7996_dev *dev) { const struct mt7996_patch_hdr *hdr; const struct firmware *fw = NULL; int i, ret, sem; sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 1); switch (sem) { case PATCH_IS_DL: return 0; case PATCH_NOT_DL_SEM_SUCCESS: break; default: dev_err(dev->mt76.dev, "Failed to get patch semaphore\n"); return -EAGAIN; } - ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev); + ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev); if (ret) goto out; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const struct mt7996_patch_hdr *)(fw->data); dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { #if defined(__linux__) struct mt7996_patch_sec *sec; #elif defined(__FreeBSD__) const struct mt7996_patch_sec *sec; #endif const u8 *dl; u32 len, addr, sec_key_idx, mode = DL_MODE_NEED_RSP; #if defined(__linux__) sec = (struct mt7996_patch_sec *)(fw->data + sizeof(*hdr) + #elif defined(__FreeBSD__) sec = (const struct mt7996_patch_sec *)(fw->data + sizeof(*hdr) + #endif i * sizeof(*sec)); if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) != PATCH_SEC_TYPE_INFO) { ret = -EINVAL; goto out; } addr = be32_to_cpu(sec->info.addr); len = be32_to_cpu(sec->info.len); sec_key_idx = be32_to_cpu(sec->info.sec_key_idx); dl = fw->data + be32_to_cpu(sec->offs); mode |= mt7996_patch_sec_mode(sec_key_idx); ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len, 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, 4096); if (ret) { dev_err(dev->mt76.dev, "Failed to send patch\n"); goto out; } } ret = mt76_connac_mcu_start_patch(&dev->mt76); if (ret) dev_err(dev->mt76.dev, "Failed to start patch\n"); out: sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 0); switch (sem) { case PATCH_REL_SEM_SUCCESS: break; default: ret = -EAGAIN; dev_err(dev->mt76.dev, "Failed to release patch semaphore\n"); break; } release_firmware(fw); return ret; } static int mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev, const struct mt7996_fw_trailer *hdr, const u8 *data, enum mt7996_ram_type type) { int i, offset = 0; u32 override = 0, option = 0; for (i = 0; i < hdr->n_region; i++) { const struct mt7996_fw_region *region; int err; u32 len, addr, mode; region = (const struct mt7996_fw_region *)((const u8 *)hdr - (hdr->n_region - i) * sizeof(*region)); /* DSP and WA use same mode */ mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76, region->feature_set, type != MT7996_RAM_TYPE_WM); len = le32_to_cpu(region->len); addr = le32_to_cpu(region->addr); if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) override = addr; err = mt76_connac_mcu_init_download(&dev->mt76, addr, len, mode); if (err) { dev_err(dev->mt76.dev, "Download request failed\n"); return err; } err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER), data + offset, len, 4096); if (err) { dev_err(dev->mt76.dev, "Failed to send firmware.\n"); return err; } offset += len; } if (override) option |= FW_START_OVERRIDE; if (type == MT7996_RAM_TYPE_WA) option |= FW_START_WORKING_PDA_CR4; else if (type == MT7996_RAM_TYPE_DSP) option |= FW_START_WORKING_PDA_DSP; return mt76_connac_mcu_start_firmware(&dev->mt76, override, option); } static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type, const char *fw_file, enum mt7996_ram_type ram_type) { const struct mt7996_fw_trailer *hdr; const struct firmware *fw; int ret; ret = request_firmware(&fw, fw_file, dev->mt76.dev); if (ret) return ret; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); ret = -EINVAL; goto out; } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); dev_info(dev->mt76.dev, "%s Firmware Version: %.10s, Build Time: %.15s\n", fw_type, hdr->fw_ver, hdr->build_date); ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, ram_type); if (ret) { dev_err(dev->mt76.dev, "Failed to start %s firmware\n", fw_type); goto out; } snprintf(dev->mt76.hw->wiphy->fw_version, sizeof(dev->mt76.hw->wiphy->fw_version), "%.10s-%.15s", hdr->fw_ver, hdr->build_date); out: release_firmware(fw); return ret; } static int mt7996_load_ram(struct mt7996_dev *dev) { int ret; - ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM, + ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM), MT7996_RAM_TYPE_WM); if (ret) return ret; - ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP, + ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP), MT7996_RAM_TYPE_DSP); if (ret) return ret; - return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA, + return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA), MT7996_RAM_TYPE_WA); } static int mt7996_firmware_state(struct mt7996_dev *dev, bool wa) { u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD); if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE, state, 1000)) { dev_err(dev->mt76.dev, "Timeout for initializing firmware\n"); return -EIO; } return 0; } static int mt7996_mcu_restart(struct mt76_dev *dev) { struct { u8 __rsv1[4]; __le16 tag; __le16 len; u8 power_mode; u8 __rsv2[3]; } __packed req = { .tag = cpu_to_le16(UNI_POWER_OFF), .len = cpu_to_le16(sizeof(req) - 4), .power_mode = 1, }; return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CTRL), &req, sizeof(req), false); } static int mt7996_load_firmware(struct mt7996_dev *dev) { int ret; /* make sure fw is download state */ if (mt7996_firmware_state(dev, false)) { /* restart firmware once */ mt7996_mcu_restart(&dev->mt76); ret = mt7996_firmware_state(dev, false); if (ret) { dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); return ret; } } ret = mt7996_load_patch(dev); if (ret) return ret; ret = mt7996_load_ram(dev); if (ret) return ret; ret = mt7996_firmware_state(dev, true); if (ret) return ret; mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; } int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl) { struct { u8 _rsv[4]; __le16 tag; __le16 len; u8 ctrl; u8 interval; u8 _rsv2[2]; } __packed data = { .tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_LOG_CTRL), .len = cpu_to_le16(sizeof(data) - 4), .ctrl = ctrl, }; if (type == MCU_FW_LOG_WA) return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(WSYS_CONFIG), &data, sizeof(data), true); return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(WSYS_CONFIG), &data, sizeof(data), true); } int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level) { struct { u8 _rsv[4]; __le16 tag; __le16 len; __le32 module_idx; u8 level; u8 _rsv2[3]; } data = { .tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_DBG_CTRL), .len = cpu_to_le16(sizeof(data) - 4), .module_idx = cpu_to_le32(module), .level = level, }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(WSYS_CONFIG), &data, sizeof(data), false); } static int mt7996_mcu_set_mwds(struct mt7996_dev *dev, bool enabled) { struct { u8 enable; u8 _rsv[3]; } __packed req = { .enable = enabled }; return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req, sizeof(req), false); } static void mt7996_add_rx_airtime_tlv(struct sk_buff *skb, u8 band_idx) { struct vow_rx_airtime *req; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_VOW_RX_AT_AIRTIME_CLR_EN, sizeof(*req)); req = (struct vow_rx_airtime *)tlv; req->enable = true; req->band = band_idx; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_VOW_RX_AT_AIRTIME_EN, sizeof(*req)); req = (struct vow_rx_airtime *)tlv; req->enable = true; req->band = band_idx; } static int mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) { struct uni_header hdr = {}; struct sk_buff *skb; - int len, num; + int len, num, i; - num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support); + num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); - mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx); - - if (dev->dbdc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND1); - - if (dev->tbtc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND2); + for (i = 0; i < __MT_MAX_BAND; i++) { + if (mt7996_band_valid(dev, i)) + mt7996_add_rx_airtime_tlv(skb, i); + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(VOW), true); } int mt7996_mcu_init_firmware(struct mt7996_dev *dev) { 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 = mt7996_driver_own(dev, 0); if (ret) return ret; /* set driver own for band1 when two hif exist */ if (dev->hif2) { ret = mt7996_driver_own(dev, 1); if (ret) return ret; } ret = mt7996_load_firmware(dev); if (ret) return ret; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0); if (ret) return ret; ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); if (ret) return ret; ret = mt7996_mcu_set_mwds(dev, 1); if (ret) return ret; ret = mt7996_mcu_init_rx_airtime(dev); if (ret) return ret; return mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_RED, 0, 0); } int mt7996_mcu_init(struct mt7996_dev *dev) { static const struct mt76_mcu_ops mt7996_mcu_ops = { .headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */ .mcu_skb_send_msg = mt7996_mcu_send_message, .mcu_parse_response = mt7996_mcu_parse_response, }; dev->mt76.mcu_ops = &mt7996_mcu_ops; return mt7996_mcu_init_firmware(dev); } void mt7996_mcu_exit(struct mt7996_dev *dev) { mt7996_mcu_restart(&dev->mt76); if (mt7996_firmware_state(dev, false)) { dev_err(dev->mt76.dev, "Failed to exit mcu\n"); goto out; } mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN); if (dev->hif2) mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1), MT_TOP_LPCR_HOST_FW_OWN); out: skb_queue_purge(&dev->mt76.mcu.res_q); } int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans) { struct { u8 __rsv[4]; } __packed hdr; struct hdr_trans_blacklist *req_blacklist; struct hdr_trans_en *req_en; struct sk_buff *skb; struct tlv *tlv; int len = MT7996_HDR_TRANS_MAX_SIZE + sizeof(hdr); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_EN, sizeof(*req_en)); req_en = (struct hdr_trans_en *)tlv; req_en->enable = hdr_trans; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_VLAN, sizeof(struct hdr_trans_vlan)); if (hdr_trans) { tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_BLACKLIST, sizeof(*req_blacklist)); req_blacklist = (struct hdr_trans_blacklist *)tlv; req_blacklist->enable = 1; req_blacklist->type = cpu_to_le16(ETH_P_PAE); } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(RX_HDR_TRANS), true); } -int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif) +int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { #define MCU_EDCA_AC_PARAM 0 #define WMM_AIFS_SET BIT(0) #define WMM_CW_MIN_SET BIT(1) #define WMM_CW_MAX_SET BIT(2) #define WMM_TXOP_SET BIT(3) #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ WMM_CW_MAX_SET | WMM_TXOP_SET) - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); struct { u8 bss_idx; u8 __rsv[3]; } __packed hdr = { - .bss_idx = mvif->mt76.idx, + .bss_idx = link->mt76.idx, }; struct sk_buff *skb; int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca); int ac; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; + struct ieee80211_tx_queue_params *q = &link->queue_params[ac]; struct edca *e; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, MCU_EDCA_AC_PARAM, sizeof(*e)); e = (struct edca *)tlv; e->set = WMM_PARAM_SET; - e->queue = ac + mvif->mt76.wmm_idx * MT7996_MAX_WMM_SETS; + e->queue = ac; e->aifs = q->aifs; e->txop = cpu_to_le16(q->txop); if (q->cw_min) e->cw_min = fls(q->cw_min); else e->cw_min = 5; if (q->cw_max) e->cw_max = fls(q->cw_max); else e->cw_max = 10; } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(EDCA_UPDATE), true); } int mt7996_mcu_set_fcc5_lpn(struct mt7996_dev *dev, int val) { struct { u8 _rsv[4]; __le16 tag; __le16 len; __le32 ctrl; __le16 min_lpn; u8 rsv[2]; } __packed req = { .tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH), .len = cpu_to_le16(sizeof(req) - 4), .ctrl = cpu_to_le32(0x1), .min_lpn = cpu_to_le16(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL), &req, sizeof(req), true); } int mt7996_mcu_set_pulse_th(struct mt7996_dev *dev, const struct mt7996_dfs_pulse *pulse) { struct { u8 _rsv[4]; __le16 tag; __le16 len; __le32 ctrl; __le32 max_width; /* us */ __le32 max_pwr; /* dbm */ __le32 min_pwr; /* dbm */ __le32 min_stgr_pri; /* us */ __le32 max_stgr_pri; /* us */ __le32 min_cr_pri; /* us */ __le32 max_cr_pri; /* us */ } __packed req = { .tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH), .len = cpu_to_le16(sizeof(req) - 4), .ctrl = cpu_to_le32(0x3), #define __req_field(field) .field = cpu_to_le32(pulse->field) __req_field(max_width), __req_field(max_pwr), __req_field(min_pwr), __req_field(min_stgr_pri), __req_field(max_stgr_pri), __req_field(min_cr_pri), __req_field(max_cr_pri), #undef __req_field }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL), &req, sizeof(req), true); } int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index, const struct mt7996_dfs_pattern *pattern) { struct { u8 _rsv[4]; __le16 tag; __le16 len; __le32 ctrl; __le16 radar_type; u8 enb; u8 stgr; u8 min_crpn; u8 max_crpn; u8 min_crpr; u8 min_pw; __le32 min_pri; __le32 max_pri; u8 max_pw; u8 min_crbn; u8 max_crbn; u8 min_stgpn; u8 max_stgpn; u8 min_stgpr; u8 rsv[2]; __le32 min_stgpr_diff; } __packed req = { .tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH), .len = cpu_to_le16(sizeof(req) - 4), .ctrl = cpu_to_le32(0x2), .radar_type = cpu_to_le16(index), #define __req_field_u8(field) .field = pattern->field #define __req_field_u32(field) .field = cpu_to_le32(pattern->field) __req_field_u8(enb), __req_field_u8(stgr), __req_field_u8(min_crpn), __req_field_u8(max_crpn), __req_field_u8(min_crpr), __req_field_u8(min_pw), __req_field_u32(min_pri), __req_field_u32(max_pri), __req_field_u8(max_pw), __req_field_u8(min_crbn), __req_field_u8(max_crbn), __req_field_u8(min_stgpn), __req_field_u8(max_stgpn), __req_field_u8(min_stgpr), __req_field_u32(min_stgpr_diff), #undef __req_field_u8 #undef __req_field_u32 }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL), &req, sizeof(req), true); } static int mt7996_mcu_background_chain_ctrl(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef, int cmd) { struct mt7996_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; struct ieee80211_channel *chan = mphy->chandef.chan; int freq = mphy->chandef.center_freq1; struct mt7996_mcu_background_chain_ctrl req = { .tag = cpu_to_le16(0), .len = cpu_to_le16(sizeof(req) - 4), .monitor_scan_type = 2, /* simple rx */ }; if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP) return -EINVAL; if (!cfg80211_chandef_valid(&mphy->chandef)) return -EINVAL; switch (cmd) { case CH_SWITCH_BACKGROUND_SCAN_START: { req.chan = chan->hw_value; req.central_chan = ieee80211_frequency_to_channel(freq); req.bw = mt76_connac_chan_bw(&mphy->chandef); req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.monitor_bw = mt76_connac_chan_bw(chandef); req.band_idx = phy->mt76->band_idx; req.scan_mode = 1; break; } case CH_SWITCH_BACKGROUND_SCAN_RUNNING: req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.band_idx = phy->mt76->band_idx; req.scan_mode = 2; break; case CH_SWITCH_BACKGROUND_SCAN_STOP: req.chan = chan->hw_value; req.central_chan = ieee80211_frequency_to_channel(freq); req.bw = mt76_connac_chan_bw(&mphy->chandef); req.tx_stream = hweight8(mphy->antenna_mask); req.rx_stream = mphy->antenna_mask; break; default: return -EINVAL; } req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(OFFCH_SCAN_CTRL), &req, sizeof(req), false); } int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef) { struct mt7996_dev *dev = phy->dev; int err, region; if (!chandef) { /* disable offchain */ err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, 0, 0); if (err) return err; return mt7996_mcu_background_chain_ctrl(phy, NULL, CH_SWITCH_BACKGROUND_SCAN_STOP); } err = mt7996_mcu_background_chain_ctrl(phy, chandef, CH_SWITCH_BACKGROUND_SCAN_START); if (err) return err; switch (dev->mt76.region) { case NL80211_DFS_ETSI: region = 0; break; case NL80211_DFS_JP: region = 2; break; case NL80211_DFS_FCC: default: region = 1; break; } return mt7996_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, 0, region); } int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) { static const u8 ch_band[] = { [NL80211_BAND_2GHZ] = 0, [NL80211_BAND_5GHZ] = 1, [NL80211_BAND_6GHZ] = 2, }; struct mt7996_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; u8 band_idx = phy->mt76->band_idx; struct { /* fixed field */ u8 __rsv[4]; __le16 tag; __le16 len; u8 control_ch; u8 center_ch; u8 bw; u8 tx_path_num; u8 rx_path; /* mask or num */ u8 switch_reason; u8 band_idx; u8 center_ch2; /* for 80+80 only */ __le16 cac_case; u8 channel_band; u8 rsv0; __le32 outband_freq; u8 txpower_drop; u8 ap_bw; u8 ap_center_ch; u8 rsv1[53]; } __packed req = { .tag = cpu_to_le16(tag), .len = cpu_to_le16(sizeof(req) - 4), .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx], + .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx], .band_idx = band_idx, .channel_band = ch_band[chandef->chan->band], }; - if (tag == UNI_CHANNEL_RX_PATH || - dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) + if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; - else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + else if (phy->mt76->offchannel || + phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, NL80211_IFTYPE_AP)) req.switch_reason = CH_SWITCH_DFS; else req.switch_reason = CH_SWITCH_NORMAL; if (tag == UNI_CHANNEL_SWITCH) req.rx_path = hweight8(req.rx_path); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; req.center_ch2 = ieee80211_frequency_to_channel(freq2); } return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(CHANNEL_SWITCH), &req, sizeof(req), true); } static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) { #define MAX_PAGE_IDX_MASK GENMASK(7, 5) #define PAGE_IDX_MASK GENMASK(4, 2) #define PER_PAGE_SIZE 0x400 struct mt7996_mcu_eeprom req = { .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), .buffer_mode = EE_MODE_BUFFER }; u16 eeprom_size = MT7996_EEPROM_SIZE; u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); u8 *eep = (u8 *)dev->mt76.eeprom.data; int eep_len, i; for (i = 0; i < total; i++, eep += eep_len) { struct sk_buff *skb; int ret, msg_len; if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) eep_len = eeprom_size % PER_PAGE_SIZE; else eep_len = PER_PAGE_SIZE; msg_len = sizeof(req) + eep_len; skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len); if (!skb) return -ENOMEM; req.len = cpu_to_le16(msg_len - 4); req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) | FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE; req.buf_len = cpu_to_le16(eep_len); skb_put_data(skb, &req, sizeof(req)); skb_put_data(skb, eep, eep_len); ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(EFUSE_CTRL), true); if (ret) return ret; } return 0; } int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) { struct mt7996_mcu_eeprom req = { .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), .len = cpu_to_le16(sizeof(req) - 4), .buffer_mode = EE_MODE_EFUSE, .format = EE_FORMAT_WHOLE }; if (dev->flash_mode) return mt7996_mcu_set_eeprom_flash(dev); return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL), &req, sizeof(req), true); } -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len) { struct { u8 _rsv[4]; __le16 tag; __le16 len; __le32 addr; __le32 valid; u8 data[16]; } __packed req = { .tag = cpu_to_le16(UNI_EFUSE_ACCESS), .len = cpu_to_le16(sizeof(req) - 4), .addr = cpu_to_le32(round_down(offset, MT7996_EEPROM_BLOCK_SIZE)), }; struct sk_buff *skb; bool valid; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), &req, sizeof(req), true, &skb); if (ret) return ret; valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); if (valid) { u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); - u8 *buf = (u8 *)dev->mt76.eeprom.data + addr; - skb_pull(skb, 64); - memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE); + if (!buf) + buf = (u8 *)dev->mt76.eeprom.data + addr; + if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EEPROM_BLOCK_SIZE; + + skb_pull(skb, 48); + memcpy(buf, skb->data, buf_len); + } else { + ret = -EINVAL; } dev_kfree_skb(skb); - return 0; + return ret; } int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) { struct { u8 _rsv[4]; __le16 tag; __le16 len; u8 num; u8 version; u8 die_idx; u8 _rsv2; } __packed req = { .tag = cpu_to_le16(UNI_EFUSE_FREE_BLOCK), .len = cpu_to_le16(sizeof(req) - 4), .version = 2, }; struct sk_buff *skb; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), &req, sizeof(req), true, &skb); if (ret) return ret; *block_num = *(u8 *)(skb->data + 8); dev_kfree_skb(skb); return 0; } int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) { #define NIC_CAP 3 #define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21 struct { u8 _rsv[4]; __le16 tag; __le16 len; } __packed req = { .tag = cpu_to_le16(NIC_CAP), .len = cpu_to_le16(sizeof(req) - 4), }; struct sk_buff *skb; u8 *buf; int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(CHIP_CONFIG), &req, sizeof(req), true, &skb); if (ret) return ret; /* fixed field */ skb_pull(skb, 4); buf = skb->data; while (buf - skb->data < skb->len) { struct tlv *tlv = (struct tlv *)buf; switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION: *cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv))); break; default: break; } buf += le16_to_cpu(tlv->len); } dev_kfree_skb(skb); return 0; } int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch) { + enum { + IDX_TX_TIME, + IDX_RX_TIME, + IDX_OBSS_AIRTIME, + IDX_NON_WIFI_TIME, + IDX_NUM + }; struct { struct { u8 band; u8 __rsv[3]; } hdr; struct { __le16 tag; __le16 len; __le32 offs; - } data[4]; + } data[IDX_NUM]; } __packed req = { .hdr.band = phy->mt76->band_idx, }; - /* strict order */ static const u32 offs[] = { - UNI_MIB_TX_TIME, - UNI_MIB_RX_TIME, - UNI_MIB_OBSS_AIRTIME, - UNI_MIB_NON_WIFI_TIME, + [IDX_TX_TIME] = UNI_MIB_TX_TIME, + [IDX_RX_TIME] = UNI_MIB_RX_TIME, + [IDX_OBSS_AIRTIME] = UNI_MIB_OBSS_AIRTIME, + [IDX_NON_WIFI_TIME] = UNI_MIB_NON_WIFI_TIME, }; struct mt76_channel_state *state = phy->mt76->chan_state; struct mt76_channel_state *state_ts = &phy->state_ts; struct mt7996_dev *dev = phy->dev; struct mt7996_mcu_mib *res; struct sk_buff *skb; int i, ret; - for (i = 0; i < 4; i++) { + for (i = 0; i < IDX_NUM; i++) { req.data[i].tag = cpu_to_le16(UNI_CMD_MIB_DATA); req.data[i].len = cpu_to_le16(sizeof(req.data[i])); req.data[i].offs = cpu_to_le32(offs[i]); } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(GET_MIB_INFO), &req, sizeof(req), true, &skb); if (ret) return ret; skb_pull(skb, sizeof(req.hdr)); res = (struct mt7996_mcu_mib *)(skb->data); if (chan_switch) goto out; #define __res_u64(s) le64_to_cpu(res[s].data) - state->cc_tx += __res_u64(1) - state_ts->cc_tx; - state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; - state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; - state->cc_busy += __res_u64(0) + __res_u64(1) + __res_u64(2) + __res_u64(3) - + state->cc_tx += __res_u64(IDX_TX_TIME) - state_ts->cc_tx; + state->cc_bss_rx += __res_u64(IDX_RX_TIME) - state_ts->cc_bss_rx; + state->cc_rx += __res_u64(IDX_RX_TIME) + + __res_u64(IDX_OBSS_AIRTIME) - + state_ts->cc_rx; + state->cc_busy += __res_u64(IDX_TX_TIME) + + __res_u64(IDX_RX_TIME) + + __res_u64(IDX_OBSS_AIRTIME) + + __res_u64(IDX_NON_WIFI_TIME) - state_ts->cc_busy; - out: - state_ts->cc_tx = __res_u64(1); - state_ts->cc_bss_rx = __res_u64(2); - state_ts->cc_rx = __res_u64(2) + __res_u64(3); - state_ts->cc_busy = __res_u64(0) + __res_u64(1) + __res_u64(2) + __res_u64(3); + state_ts->cc_tx = __res_u64(IDX_TX_TIME); + state_ts->cc_bss_rx = __res_u64(IDX_RX_TIME); + state_ts->cc_rx = __res_u64(IDX_RX_TIME) + __res_u64(IDX_OBSS_AIRTIME); + state_ts->cc_busy = __res_u64(IDX_TX_TIME) + + __res_u64(IDX_RX_TIME) + + __res_u64(IDX_OBSS_AIRTIME) + + __res_u64(IDX_NON_WIFI_TIME); #undef __res_u64 dev_kfree_skb(skb); return 0; } +int mt7996_mcu_get_temperature(struct mt7996_phy *phy) +{ +#define TEMPERATURE_QUERY 0 +#define GET_TEMPERATURE 0 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 rsv1; + u8 action; + u8 band_idx; + u8 rsv2; + } req = { + .tag = cpu_to_le16(TEMPERATURE_QUERY), + .len = cpu_to_le16(sizeof(req) - 4), + .action = GET_TEMPERATURE, + .band_idx = phy->mt76->band_idx, + }; + struct mt7996_mcu_thermal { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + __le32 rsv; + __le32 temperature; + } __packed * res; + struct sk_buff *skb; + int ret; + u32 temp; + + ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (void *)skb->data; + temp = le32_to_cpu(res->temperature); + dev_kfree_skb(skb); + + return temp; +} + +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + } __packed req = { + .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG), + .len = cpu_to_le16(sizeof(req) - 4), + .ctrl = { + .band_idx = phy->mt76->band_idx, + }, + }; + int level, ret; + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state /= 2; + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); + if (ret) + return ret; + } + + return 0; +} + +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable) +{ +#define SUSTAIN_PERIOD 10 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + struct mt7996_mcu_thermal_enable enable; + } __packed req = { + .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)), + .ctrl = { + .band_idx = phy->mt76->band_idx, + .type.protect_type = 1, + .type.trigger_type = 1, + }, + }; + int ret; + + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE); + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req) - sizeof(req.enable), false); + if (ret || !enable) + return ret; + + /* set high-temperature trigger threshold */ + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE); + req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]); + req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); + req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + + req.len = cpu_to_le16(sizeof(req) - 4); + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); +} + int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band) { struct { u8 rsv[4]; __le16 tag; __le16 len; union { struct { __le32 mask; } __packed set; struct { u8 method; u8 band; u8 rsv2[2]; } __packed trigger; }; } __packed req = { .tag = cpu_to_le16(action), .len = cpu_to_le16(sizeof(req) - 4), }; switch (action) { case UNI_CMD_SER_SET: req.set.mask = cpu_to_le32(val); break; case UNI_CMD_SER_TRIGGER: req.trigger.method = val; req.trigger.band = band; break; default: return -EINVAL; } return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SER), &req, sizeof(req), false); } int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action) { #define MT7996_BF_MAX_SIZE sizeof(union bf_tag_tlv) #define BF_PROCESSING 4 struct uni_header hdr; struct sk_buff *skb; struct tlv *tlv; int len = sizeof(hdr) + MT7996_BF_MAX_SIZE; memset(&hdr, 0, sizeof(hdr)); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); switch (action) { case BF_SOUNDING_ON: { struct bf_sounding_on *req_snd_on; tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_snd_on)); req_snd_on = (struct bf_sounding_on *)tlv; req_snd_on->snd_mode = BF_PROCESSING; break; } case BF_HW_EN_UPDATE: { struct bf_hw_en_status_update *req_hw_en; tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_hw_en)); req_hw_en = (struct bf_hw_en_status_update *)tlv; req_hw_en->ebf = true; req_hw_en->ibf = dev->ibf; break; } case BF_MOD_EN_CTRL: { struct bf_mod_en_ctrl *req_mod_en; tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_mod_en)); req_mod_en = (struct bf_mod_en_ctrl *)tlv; - req_mod_en->bf_num = 2; - req_mod_en->bf_bitmap = GENMASK(0, 0); + req_mod_en->bf_num = mt7996_band_valid(dev, MT_BAND2) ? 3 : 2; + req_mod_en->bf_bitmap = mt7996_band_valid(dev, MT_BAND2) ? + GENMASK(2, 0) : GENMASK(1, 0); break; } default: return -EINVAL; } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(BF), true); } static int mt7996_mcu_enable_obss_spr(struct mt7996_phy *phy, u16 action, u8 val) { struct mt7996_dev *dev = phy->dev; struct { u8 band_idx; u8 __rsv[3]; __le16 tag; __le16 len; __le32 val; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(action), .len = cpu_to_le16(sizeof(req) - 4), .val = cpu_to_le32(val), }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR), &req, sizeof(req), true); } static int mt7996_mcu_set_obss_spr_pd(struct mt7996_phy *phy, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7996_dev *dev = phy->dev; u8 max_th = 82, non_srg_max_th = 62; struct { u8 band_idx; u8 __rsv[3]; __le16 tag; __le16 len; u8 pd_th_non_srg; u8 pd_th_srg; u8 period_offs; u8 rcpi_src; __le16 obss_pd_min; __le16 obss_pd_min_srg; u8 resp_txpwr_mode; u8 txpwr_restrict_mode; u8 txpwr_ref; u8 __rsv2[3]; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(UNI_CMD_SR_SET_PARAM), .len = cpu_to_le16(sizeof(req) - 4), .obss_pd_min = cpu_to_le16(max_th), .obss_pd_min_srg = cpu_to_le16(max_th), .txpwr_restrict_mode = 2, .txpwr_ref = 21 }; int ret; /* disable firmware dynamical PD asjustment */ ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_DPD, false); if (ret) return ret; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED) req.pd_th_non_srg = max_th; else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) req.pd_th_non_srg = max_th - he_obss_pd->non_srg_max_offset; else req.pd_th_non_srg = non_srg_max_th; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) req.pd_th_srg = max_th - he_obss_pd->max_offset; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR), &req, sizeof(req), true); } static int mt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_dev *dev = phy->dev; - u8 omac = mvif->mt76.omac_idx; + u8 omac = mvif->deflink.mt76.omac_idx; struct { u8 band_idx; u8 __rsv[3]; __le16 tag; __le16 len; u8 omac; u8 __rsv2[3]; u8 flag[20]; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(UNI_CMD_SR_SET_SIGA), .len = cpu_to_le16(sizeof(req) - 4), .omac = omac > HW_BSSID_MAX ? omac - 12 : omac, }; int ret; if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED) req.flag[req.omac] = 0xf; else return 0; /* switch to normal AP mode */ ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_MODE, 0); if (ret) return ret; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR), &req, sizeof(req), true); } static int mt7996_mcu_set_obss_spr_bitmap(struct mt7996_phy *phy, struct ieee80211_he_obss_pd *he_obss_pd) { struct mt7996_dev *dev = phy->dev; struct { u8 band_idx; u8 __rsv[3]; __le16 tag; __le16 len; __le32 color_l[2]; __le32 color_h[2]; __le32 bssid_l[2]; __le32 bssid_h[2]; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(UNI_CMD_SR_SET_SRG_BITMAP), .len = cpu_to_le16(sizeof(req) - 4), }; u32 bitmap; memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap)); req.color_l[req.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap)); req.color_h[req.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap)); req.bssid_l[req.band_idx] = cpu_to_le32(bitmap); memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap)); req.bssid_h[req.band_idx] = cpu_to_le32(bitmap); return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR), &req, sizeof(req), true); } int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd) { int ret; /* enable firmware scene detection algorithms */ ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_SD, sr_scene_detect); if (ret) return ret; /* firmware dynamically adjusts PD threshold so skip manual control */ if (sr_scene_detect && !he_obss_pd->enable) return 0; /* enable spatial reuse */ ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE, he_obss_pd->enable); if (ret) return ret; if (sr_scene_detect || !he_obss_pd->enable) return 0; ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_TX, true); if (ret) return ret; /* set SRG/non-SRG OBSS PD threshold */ ret = mt7996_mcu_set_obss_spr_pd(phy, he_obss_pd); if (ret) return ret; /* Set SR prohibit */ ret = mt7996_mcu_set_obss_spr_siga(phy, vif, he_obss_pd); if (ret) return ret; /* set SRG BSS color/BSSID bitmap */ return mt7996_mcu_set_obss_spr_bitmap(phy, he_obss_pd); } -int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, + struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color) { int len = sizeof(struct bss_req_hdr) + sizeof(struct bss_color_tlv); - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct bss_color_tlv *bss_color; struct sk_buff *skb; struct tlv *tlv; - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len); + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, len); if (IS_ERR(skb)) return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BSS_COLOR, sizeof(*bss_color)); bss_color = (struct bss_color_tlv *)tlv; bss_color->enable = he_bss_color->enabled; bss_color->color = he_bss_color->color; return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } #define TWT_AGRT_TRIGGER BIT(0) #define TWT_AGRT_ANNOUNCE BIT(1) #define TWT_AGRT_PROTECT BIT(2) int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, struct mt7996_vif *mvif, struct mt7996_twt_flow *flow, int cmd) { struct { - u8 _rsv[4]; + /* fixed field */ + u8 bss; + u8 _rsv[3]; __le16 tag; __le16 len; u8 tbl_idx; u8 cmd; u8 own_mac_idx; u8 flowid; /* 0xff for group id */ __le16 peer_id; /* specify the peer_id (msb=0) * or group_id (msb=1) */ u8 duration; /* 256 us */ u8 bss_idx; __le64 start_tsf; __le16 mantissa; u8 exponent; u8 is_ap; u8 agrt_params; - u8 __rsv2[135]; + u8 __rsv2[23]; } __packed req = { .tag = cpu_to_le16(UNI_CMD_TWT_ARGT_UPDATE), .len = cpu_to_le16(sizeof(req) - 4), .tbl_idx = flow->table_id, .cmd = cmd, - .own_mac_idx = mvif->mt76.omac_idx, + .own_mac_idx = mvif->deflink.mt76.omac_idx, .flowid = flow->id, .peer_id = cpu_to_le16(flow->wcid), .duration = flow->duration, - .bss_idx = mvif->mt76.idx, + .bss = mvif->deflink.mt76.idx, + .bss_idx = mvif->deflink.mt76.idx, .start_tsf = cpu_to_le64(flow->tsf), .mantissa = flow->mantissa, .exponent = flow->exp, .is_ap = true, }; if (flow->protection) req.agrt_params |= TWT_AGRT_PROTECT; if (!flow->flowtype) req.agrt_params |= TWT_AGRT_ANNOUNCE; if (flow->trigger) req.agrt_params |= TWT_AGRT_TRIGGER; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TWT), &req, sizeof(req), true); } int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val) { struct { u8 band_idx; u8 _rsv[3]; __le16 tag; __le16 len; __le32 len_thresh; __le32 pkt_thresh; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(UNI_BAND_CONFIG_RTS_THRESHOLD), .len = cpu_to_le16(sizeof(req) - 4), .len_thresh = cpu_to_le32(val), .pkt_thresh = cpu_to_le32(0x2), }; return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), &req, sizeof(req), true); } int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) { struct { u8 band_idx; u8 _rsv[3]; __le16 tag; __le16 len; u8 enable; u8 _rsv2[3]; } __packed req = { .band_idx = phy->mt76->band_idx, .tag = cpu_to_le16(UNI_BAND_CONFIG_RADIO_ENABLE), .len = cpu_to_le16(sizeof(req) - 4), .enable = enable, }; return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), &req, sizeof(req), true); } int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val) { struct { u8 _rsv[4]; __le16 tag; __le16 len; u8 ctrl; u8 rdd_idx; u8 rdd_rx_sel; u8 val; u8 rsv[4]; } __packed req = { .tag = cpu_to_le16(UNI_RDD_CTRL_PARM), .len = cpu_to_le16(sizeof(req) - 4), .ctrl = cmd, .rdd_idx = index, .rdd_rx_sel = rx_sel, .val = val, }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL), &req, sizeof(req), true); } int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta; struct sk_buff *skb; - msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta; + msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->deflink.sta; - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->deflink.mt76, &msta->wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); /* starec hdr trans */ - mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta); + mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, &msta->wcid); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon) +{ +#define UNI_FIXED_RATE_TABLE_SET 0 +#define SPE_IXD_SELECT_TXD 0 +#define SPE_IXD_SELECT_BMC_WTBL 1 + struct mt7996_dev *dev = phy->dev; + struct fixed_rate_table_ctrl req = { + .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET), + .len = cpu_to_le16(sizeof(req) - 4), + .table_idx = table_idx, + .rate_idx = cpu_to_le16(rate_idx), + .gi = 1, + .he_ltf = 1, + }; + u8 band_idx = phy->mt76->band_idx; + + if (beacon) { + req.spe_idx_sel = SPE_IXD_SELECT_TXD; + req.spe_idx = 24 + band_idx; + phy->beacon_rate = rate_idx; + } else { + req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE), + &req, sizeof(req), false); +} + int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set) { struct { u8 __rsv1[4]; __le16 tag; __le16 len; __le16 idx; u8 __rsv2[2]; __le32 ofs; __le32 data; } __packed *res, req = { .tag = cpu_to_le16(UNI_CMD_ACCESS_RF_REG_BASIC), .len = cpu_to_le16(sizeof(req) - 4), .idx = cpu_to_le16(u32_get_bits(regidx, GENMASK(31, 24))), .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))), .data = set ? cpu_to_le32(*val) : 0, }; struct sk_buff *skb; int ret; if (set) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REG_ACCESS), &req, sizeof(req), true); ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(REG_ACCESS), &req, sizeof(req), true, &skb); if (ret) return ret; res = (void *)skb->data; *val = le32_to_cpu(res->data); dev_kfree_skb(skb); return 0; } int mt7996_mcu_trigger_assert(struct mt7996_dev *dev) { struct { __le16 tag; __le16 len; u8 enable; u8 rsv[3]; } __packed req = { .len = cpu_to_le16(sizeof(req) - 4), .enable = true, }; return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ASSERT_DUMP), &req, sizeof(req), false); } -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; - __le16 tag; __le16 len; - union { struct { u8 type; u8 __rsv2[3]; } __packed platform_type; struct { u8 type; u8 dest; u8 __rsv2[2]; } __packed bypass_mode; struct { u8 path; u8 __rsv2[3]; } __packed txfree_path; + struct { + __le16 flush_one; + __le16 flush_all; + u8 __rsv2[4]; + } __packed timeout; }; } __packed req = { .tag = cpu_to_le16(tag), .len = cpu_to_le16(sizeof(req) - 4), }; switch (tag) { case UNI_RRO_SET_PLATFORM_TYPE: req.platform_type.type = val; break; case UNI_RRO_SET_BYPASS_MODE: req.bypass_mode.type = val; break; case UNI_RRO_SET_TXFREE_PATH: req.txfree_path.path = val; break; + case UNI_RRO_SET_FLUSH_TIMEOUT: + req.timeout.flush_one = cpu_to_le16(val); + req.timeout.flush_all = cpu_to_le16(2 * val); + break; default: return -EINVAL; } return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, sizeof(req), true); } + +int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) +{ + struct mt7996_dev *dev = phy->dev; + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + } __packed req = { + .tag = cpu_to_le16(tag), + .len = cpu_to_le16(sizeof(req) - 4), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO), + &req, sizeof(req), false); +} + +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) +{ + struct { + u8 __rsv[4]; + + __le16 tag; + __le16 len; + __le16 session_id; + u8 pad[4]; + } __packed req = { + .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION), + .len = cpu_to_le16(sizeof(req) - 4), + .session_id = cpu_to_le16(id), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, + sizeof(req), true); +} + +int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled) +{ + struct mt7996_dev *dev = phy->dev; + struct { + u8 band_idx; + u8 _rsv[3]; + __le16 tag; + __le16 len; + u8 enable; + u8 _pad[3]; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = 0, + .len = cpu_to_le16(sizeof(req) - 4), + .enable = enabled, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SNIFFER), &req, + sizeof(req), true); +} + +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) +{ +#define TX_POWER_LIMIT_TABLE_RATE 0 + struct mt7996_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct tx_power_limit_table_ctrl { + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + u8 power_ctrl_id; + u8 power_limit_type; + u8 band_idx; + } __packed req = { + .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL), + .len = cpu_to_le16(sizeof(req) + MT7996_SKU_PATH_NUM - 4), + .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL, + .power_limit_type = TX_POWER_LIMIT_TABLE_RATE, + .band_idx = phy->mt76->band_idx, + }; + struct mt76_power_limits la = {}; + struct sk_buff *skb; + int i, tx_power; + + tx_power = mt7996_get_power_bound(phy, phy->txpower); + tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, + &la, tx_power); + mphy->txpower_cur = tx_power; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req) + MT7996_SKU_PATH_NUM); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req, sizeof(req)); + /* cck and ofdm */ + skb_put_data(skb, &la.cck, sizeof(la.cck)); + skb_put_data(skb, &la.ofdm, sizeof(la.ofdm)); + /* ht20 */ + skb_put_data(skb, &la.mcs[0], 8); + /* ht40 */ + skb_put_data(skb, &la.mcs[1], 9); + + /* vht */ + for (i = 0; i < 4; i++) { + skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i])); + skb_put_zero(skb, 2); /* padding */ + } + + /* he */ + skb_put_data(skb, &la.ru[0], sizeof(la.ru)); + /* eht */ + skb_put_data(skb, &la.eht[0], sizeof(la.eht)); + + /* padding */ + skb_put_zero(skb, MT7996_SKU_PATH_NUM - MT7996_SKU_RATE_NUM); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD(TXPOWER), true); +} + +int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode) +{ + __le32 cp_mode; + + if (mode < mt76_connac_lmac_mapping(IEEE80211_AC_BE) || + mode > mt76_connac_lmac_mapping(IEEE80211_AC_VO)) + return -EINVAL; + + cp_mode = cpu_to_le32(mode); + return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), + &cp_mode, sizeof(cp_mode), true); +} diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.h b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.h index 078f82858621..43468bcaffc6 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mcu.h +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mcu.h @@ -1,700 +1,954 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2022 MediaTek Inc. */ #ifndef __MT7996_MCU_H #define __MT7996_MCU_H #include "../mt76_connac_mcu.h" struct mt7996_mcu_rxd { __le32 rxd[8]; __le16 len; __le16 pkt_type_id; u8 eid; u8 seq; u8 option; u8 __rsv; u8 ext_eid; u8 __rsv1[2]; u8 s2d_index; }; struct mt7996_mcu_uni_event { u8 cid; u8 __rsv[3]; __le32 status; /* 0: success, others: fail */ } __packed; +struct mt7996_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7996_mcu_thermal_enable { + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; +} __packed; + struct mt7996_mcu_csa_notify { struct mt7996_mcu_rxd rxd; u8 omac_idx; u8 csa_count; u8 band_idx; u8 rsv; } __packed; struct mt7996_mcu_rdd_report { struct mt7996_mcu_rxd rxd; u8 __rsv1[4]; __le16 tag; __le16 len; u8 band_idx; u8 long_detected; u8 constant_prf_detected; u8 staggered_prf_detected; u8 radar_type_idx; u8 periodic_pulse_num; u8 long_pulse_num; u8 hw_pulse_num; u8 out_lpn; u8 out_spn; u8 out_crpn; u8 out_crpw; u8 out_crbn; u8 out_stgpn; u8 out_stgpw; u8 __rsv2; __le32 out_pri_const; __le32 out_pri_stg[3]; __le32 out_pri_stg_dmin; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 mdrdy_flag; u8 rsv[3]; } long_pulse[32]; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 mdrdy_flag; u8 rsv[3]; } periodic_pulse[32]; struct { __le32 start; __le16 pulse_width; __le16 pulse_power; u8 sc_pass; u8 sw_reset; u8 mdrdy_flag; u8 tx_active; } hw_pulse[32]; } __packed; struct mt7996_mcu_background_chain_ctrl { u8 _rsv[4]; __le16 tag; __le16 len; u8 chan; /* primary channel */ u8 central_chan; /* central channel */ u8 bw; u8 tx_stream; u8 rx_stream; u8 monitor_chan; /* monitor channel */ u8 monitor_central_chan;/* monitor central channel */ u8 monitor_bw; u8 monitor_tx_stream; u8 monitor_rx_stream; u8 scan_mode; /* 0: ScanStop * 1: ScanStart * 2: ScanRunning */ u8 band_idx; /* DBDC */ u8 monitor_scan_type; u8 band; /* 0: 2.4GHz, 1: 5GHz */ u8 rsv[2]; } __packed; struct mt7996_mcu_eeprom { u8 _rsv[4]; __le16 tag; __le16 len; u8 buffer_mode; u8 format; __le16 buf_len; } __packed; struct mt7996_mcu_phy_rx_info { u8 category; u8 rate; u8 mode; u8 nsts; u8 gi; u8 coding; u8 stbc; u8 bw; }; struct mt7996_mcu_mib { __le16 tag; __le16 len; __le32 offs; __le64 data; } __packed; +struct all_sta_trx_rate { + __le16 wlan_idx; + u8 __rsv1[2]; + u8 tx_mode; + u8 flags; + u8 tx_stbc; + u8 tx_gi; + u8 tx_bw; + u8 tx_ldpc; + u8 tx_mcs; + u8 tx_nss; + u8 rx_rate; + u8 rx_mode; + u8 rx_nsts; + u8 rx_gi; + u8 rx_coding; + u8 rx_stbc; + u8 rx_bw; + u8 __rsv2; +} __packed; + +struct mt7996_mcu_all_sta_info_event { + u8 rsv[4]; + __le16 tag; + __le16 len; + u8 more; + u8 rsv2; + __le16 sta_num; + u8 rsv3[4]; + + union { + DECLARE_FLEX_ARRAY(struct all_sta_trx_rate, rate); + DECLARE_FLEX_ARRAY(struct { + __le16 wlan_idx; + u8 rsv[2]; + __le32 tx_bytes[IEEE80211_NUM_ACS]; + __le32 rx_bytes[IEEE80211_NUM_ACS]; + } __packed, adm_stat); + + DECLARE_FLEX_ARRAY(struct { + __le16 wlan_idx; + u8 rsv[2]; + __le32 tx_msdu_cnt; + __le32 rx_msdu_cnt; + } __packed, msdu_cnt); + } __packed; +} __packed; + +struct mt7996_mcu_wed_rro_event { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; +} __packed; + +struct mt7996_mcu_wed_rro_ba_event { + __le16 tag; + __le16 len; + + __le16 wlan_id; + u8 tid; + u8 __rsv1; + __le32 status; + __le16 id; + u8 __rsv2[2]; +} __packed; + +struct mt7996_mcu_wed_rro_ba_delete_event { + __le16 tag; + __le16 len; + + __le16 session_id; + u8 __rsv2[2]; +} __packed; + +enum { + UNI_WED_RRO_BA_SESSION_STATUS, + UNI_WED_RRO_BA_SESSION_TBL, + UNI_WED_RRO_BA_SESSION_DELETE, +}; + +struct mt7996_mcu_thermal_notify { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + + u8 event_id; + u8 band_idx; + u8 level_idx; + u8 duty_percent; + __le32 restore_temp; + u8 __rsv2[4]; +} __packed; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, UNI_MIB_TX_TIME = 28, UNI_MIB_RX_TIME = 29 }; struct edca { __le16 tag; __le16 len; u8 queue; u8 set; u8 cw_min; u8 cw_max; __le16 txop; u8 aifs; u8 __rsv; }; #define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10)) #define MCU_PKT_ID 0xa0 enum { MCU_FW_LOG_WM, MCU_FW_LOG_WA, MCU_FW_LOG_TO_HOST, MCU_FW_LOG_RELAY = 16 }; enum { MCU_TWT_AGRT_ADD, MCU_TWT_AGRT_MODIFY, MCU_TWT_AGRT_DELETE, MCU_TWT_AGRT_TEARDOWN, MCU_TWT_AGRT_GET_TSF, }; enum { MCU_WA_PARAM_CMD_QUERY, MCU_WA_PARAM_CMD_SET, MCU_WA_PARAM_CMD_CAPABILITY, MCU_WA_PARAM_CMD_DEBUG, }; enum { MCU_WA_PARAM_PDMA_RX = 0x04, MCU_WA_PARAM_CPU_UTIL = 0x0b, MCU_WA_PARAM_RED = 0x0e, MCU_WA_PARAM_HW_PATH_HIF_VER = 0x2f, }; enum mcu_mmps_mode { MCU_MMPS_STATIC, MCU_MMPS_DYNAMIC, MCU_MMPS_RSV, MCU_MMPS_DISABLE, }; struct bss_rate_tlv { __le16 tag; __le16 len; u8 __rsv1[4]; __le16 bc_trans; __le16 mc_trans; u8 short_preamble; u8 bc_fixed_rate; u8 mc_fixed_rate; - u8 __rsv2[1]; + u8 __rsv2[9]; +} __packed; + +enum { + BP_DISABLE, + BP_SW_MODE, + BP_HW_MODE, +}; + +struct mt7996_mcu_bcn_prot_tlv { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 enable; + u8 cipher_id; + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_id; + u8 __rsv[3]; } __packed; struct bss_ra_tlv { __le16 tag; __le16 len; u8 short_preamble; u8 force_sgi; u8 force_gf; u8 ht_mode; u8 se_off; u8 antenna_idx; __le16 max_phyrate; u8 force_tx_streams; u8 __rsv[3]; } __packed; struct bss_rlm_tlv { __le16 tag; __le16 len; u8 control_channel; u8 center_chan; u8 center_chan2; u8 bw; u8 tx_streams; u8 rx_streams; u8 ht_op_info; u8 sco; u8 band; u8 __rsv[3]; } __packed; struct bss_color_tlv { __le16 tag; __le16 len; u8 enable; u8 color; u8 rsv[2]; } __packed; struct bss_inband_discovery_tlv { __le16 tag; __le16 len; u8 tx_type; u8 tx_mode; u8 tx_interval; u8 enable; __le16 wcid; __le16 prob_rsp_len; -#define MAX_INBAND_FRAME_SIZE 512 - u8 pkt[MAX_INBAND_FRAME_SIZE]; } __packed; struct bss_bcn_content_tlv { __le16 tag; __le16 len; __le16 tim_ie_pos; __le16 csa_ie_pos; __le16 bcc_ie_pos; u8 enable; u8 type; __le16 pkt_len; -#define MAX_BEACON_SIZE 512 - u8 pkt[MAX_BEACON_SIZE]; } __packed; struct bss_bcn_cntdwn_tlv { __le16 tag; __le16 len; u8 cnt; u8 rsv[3]; } __packed; struct bss_bcn_mbss_tlv { __le16 tag; __le16 len; __le32 bitmap; #define MAX_BEACON_NUM 32 __le16 offset[MAX_BEACON_NUM]; } __packed __aligned(4); struct bss_txcmd_tlv { __le16 tag; __le16 len; u8 txcmd_mode; u8 __rsv[3]; } __packed; struct bss_sec_tlv { __le16 tag; __le16 len; u8 __rsv1[2]; u8 cipher; u8 __rsv2[1]; } __packed; struct bss_ifs_time_tlv { __le16 tag; __le16 len; u8 slot_valid; u8 sifs_valid; u8 rifs_valid; u8 eifs_valid; __le16 slot_time; __le16 sifs_time; __le16 rifs_time; __le16 eifs_time; u8 eifs_cck_valid; u8 rsv; __le16 eifs_cck_time; } __packed; struct bss_power_save { __le16 tag; __le16 len; u8 profile; u8 _rsv[3]; } __packed; struct bss_mld_tlv { __le16 tag; __le16 len; u8 group_mld_id; u8 own_mld_id; u8 mac_addr[ETH_ALEN]; u8 remap_idx; u8 __rsv[3]; } __packed; +struct sta_rec_ht_uni { + __le16 tag; + __le16 len; + __le16 ht_cap; + __le16 ht_cap_ext; + u8 ampdu_param; + u8 _rsv[3]; +} __packed; + struct sta_rec_ba_uni { __le16 tag; __le16 len; u8 tid; u8 ba_type; u8 amsdu; u8 ba_en; __le16 ssn; __le16 winsize; u8 ba_rdd_rro; u8 __rsv[3]; } __packed; struct sta_rec_eht { __le16 tag; __le16 len; u8 tid_bitmap; u8 _rsv; __le16 mac_cap; __le64 phy_cap; __le64 phy_cap_ext; u8 mcs_map_bw20[4]; u8 mcs_map_bw80[3]; u8 mcs_map_bw160[3]; u8 mcs_map_bw320[3]; u8 _rsv2[3]; } __packed; struct sec_key_uni { __le16 wlan_idx; u8 mgmt_prot; u8 cipher_id; u8 cipher_len; u8 key_id; u8 key_len; u8 need_resp; u8 key[32]; } __packed; struct sta_rec_sec_uni { __le16 tag; __le16 len; u8 add; u8 n_cipher; u8 rsv[2]; struct sec_key_uni key[2]; } __packed; +struct sta_phy_uni { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; + u8 rsv[3]; +}; + +struct sta_rec_ra_uni { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_cap; + + struct sta_phy_uni phy; + u8 rx_rcpi[4]; +} __packed; + +struct sta_rec_ra_fixed_uni { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct sta_phy_uni phy; + + u8 spe_idx; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + struct sta_rec_hdrt { __le16 tag; __le16 len; u8 hdrt_mode; u8 rsv[3]; } __packed; struct sta_rec_hdr_trans { __le16 tag; __le16 len; u8 from_ds; u8 to_ds; u8 dis_rx_hdr_tran; u8 mesh; } __packed; struct hdr_trans_en { __le16 tag; __le16 len; u8 enable; u8 check_bssid; u8 mode; u8 __rsv; } __packed; struct hdr_trans_vlan { __le16 tag; __le16 len; u8 insert_vlan; u8 remove_vlan; u8 tid; u8 __rsv; } __packed; struct hdr_trans_blacklist { __le16 tag; __le16 len; u8 idx; u8 enable; __le16 type; } __packed; struct uni_header { u8 __rsv[4]; } __packed; struct vow_rx_airtime { __le16 tag; __le16 len; u8 enable; u8 band; u8 __rsv[2]; } __packed; struct bf_sounding_on { __le16 tag; __le16 len; u8 snd_mode; u8 sta_num; u8 __rsv[2]; __le16 wlan_id[4]; __le32 snd_period; } __packed; struct bf_hw_en_status_update { __le16 tag; __le16 len; bool ebf; bool ibf; u8 __rsv[2]; } __packed; struct bf_mod_en_ctrl { __le16 tag; __le16 len; u8 bf_num; u8 bf_bitmap; u8 bf_sel[8]; u8 __rsv[2]; } __packed; union bf_tag_tlv { struct bf_sounding_on bf_snd; struct bf_hw_en_status_update bf_hw_en; struct bf_mod_en_ctrl bf_mod_en; }; struct ra_rate { __le16 wlan_idx; u8 mode; u8 stbc; __le16 gi; u8 bw; u8 ldpc; u8 mcs; u8 nss; __le16 ltf; u8 spe; u8 preamble; u8 __rsv[2]; } __packed; struct ra_fixed_rate { __le16 tag; __le16 len; __le16 version; struct ra_rate rate; } __packed; enum { UNI_RA_FIXED_RATE = 0xf, }; #define MT7996_HDR_TRANS_MAX_SIZE (sizeof(struct hdr_trans_en) + \ sizeof(struct hdr_trans_vlan) + \ sizeof(struct hdr_trans_blacklist)) enum { UNI_HDR_TRANS_EN, UNI_HDR_TRANS_VLAN, UNI_HDR_TRANS_BLACKLIST, }; enum { RATE_PARAM_FIXED = 3, RATE_PARAM_MMPS_UPDATE = 5, RATE_PARAM_FIXED_HE_LTF = 7, RATE_PARAM_FIXED_MCS, RATE_PARAM_FIXED_GI = 11, RATE_PARAM_AUTO = 20, }; enum { BF_SOUNDING_ON = 1, BF_HW_EN_UPDATE = 17, BF_MOD_EN_CTRL = 20, }; enum { CMD_BAND_NONE, CMD_BAND_24G, CMD_BAND_5G, CMD_BAND_6G, }; struct bss_req_hdr { u8 bss_idx; u8 __rsv[3]; } __packed; enum { UNI_CHANNEL_SWITCH, UNI_CHANNEL_RX_PATH, }; #define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct mt76_connac_bss_basic_tlv) + \ sizeof(struct bss_rlm_tlv) + \ sizeof(struct bss_ra_tlv) + \ sizeof(struct bss_info_uni_he) + \ sizeof(struct bss_rate_tlv) + \ sizeof(struct bss_txcmd_tlv) + \ sizeof(struct bss_power_save) + \ sizeof(struct bss_sec_tlv) + \ sizeof(struct bss_ifs_time_tlv) + \ sizeof(struct bss_mld_tlv)) #define MT7996_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_ht_uni) + \ sizeof(struct sta_rec_he_v2) + \ sizeof(struct sta_rec_ba_uni) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ - sizeof(struct sta_rec_phy) + \ - sizeof(struct sta_rec_ra) + \ + sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ - sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_ra_fixed_uni) + \ sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_eht) + \ sizeof(struct sta_rec_hdrt) + \ sizeof(struct sta_rec_hdr_trans) + \ sizeof(struct tlv)) +#define MT7996_MAX_BEACON_SIZE 1338 #define MT7996_BEACON_UPDATE_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct bss_bcn_content_tlv) + \ + 4 + MT_TXD_SIZE + \ sizeof(struct bss_bcn_cntdwn_tlv) + \ sizeof(struct bss_bcn_mbss_tlv)) +#define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ + MT7996_BEACON_UPDATE_SIZE) -#define MT7996_INBAND_FRAME_SIZE (sizeof(struct bss_req_hdr) + \ - sizeof(struct bss_inband_discovery_tlv)) +static inline s8 +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower) +{ + struct mt76_phy *mphy = phy->mt76; + int n_chains = hweight16(mphy->chainmask); + + txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); + txpower -= mt76_tx_power_nss_delta(n_chains); + + return txpower; +} enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, }; enum { UNI_WSYS_CONFIG_FW_LOG_CTRL, UNI_WSYS_CONFIG_FW_DBG_CTRL, }; enum { UNI_RDD_CTRL_PARM, UNI_RDD_CTRL_SET_TH = 0x3, }; enum { UNI_EFUSE_ACCESS = 1, UNI_EFUSE_BUFFER_MODE, UNI_EFUSE_FREE_BLOCK, UNI_EFUSE_BUFFER_RD, }; enum { UNI_VOW_DRR_CTRL, UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, UNI_VOW_RX_AT_AIRTIME_CLR_EN = 0x0e, }; enum { UNI_CMD_MIB_DATA, }; enum { UNI_POWER_OFF, }; enum { UNI_CMD_TWT_ARGT_UPDATE = 0x0, UNI_CMD_TWT_MGMT_OFFLOAD, }; enum { UNI_RRO_DEL_ENTRY = 0x1, UNI_RRO_SET_PLATFORM_TYPE, UNI_RRO_GET_BA_SESSION_TABLE, UNI_RRO_SET_BYPASS_MODE, UNI_RRO_SET_TXFREE_PATH, + UNI_RRO_DEL_BA_SESSION, + UNI_RRO_SET_FLUSH_TIMEOUT }; enum{ UNI_CMD_SR_ENABLE = 0x1, UNI_CMD_SR_ENABLE_SD, UNI_CMD_SR_ENABLE_MODE, UNI_CMD_SR_ENABLE_DPD = 0x12, UNI_CMD_SR_ENABLE_TX, UNI_CMD_SR_SET_SRG_BITMAP = 0x80, UNI_CMD_SR_SET_PARAM = 0xc1, UNI_CMD_SR_SET_SIGA = 0xd0, }; +enum { + UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6, + UNI_CMD_THERMAL_PROTECT_DISABLE, + UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, +}; + +enum { + UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, +}; + enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, }; enum { UNI_CMD_SER_QUERY, /* recovery */ UNI_CMD_SER_SET_RECOVER_L1, UNI_CMD_SER_SET_RECOVER_L2, UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT, UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT, UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE, UNI_CMD_SER_SET_RECOVER_L3_BF, UNI_CMD_SER_SET_RECOVER_L4_MDP, UNI_CMD_SER_SET_RECOVER_FULL, UNI_CMD_SER_SET_SYSTEM_ASSERT, /* action */ UNI_CMD_SER_ENABLE = 1, UNI_CMD_SER_SET, UNI_CMD_SER_TRIGGER }; enum { MT7996_SEC_MODE_PLAIN, MT7996_SEC_MODE_AES, MT7996_SEC_MODE_SCRAMBLE, MT7996_SEC_MODE_MAX, }; #define MT7996_PATCH_SEC GENMASK(31, 24) #define MT7996_PATCH_SCRAMBLE_KEY GENMASK(15, 8) #define MT7996_PATCH_AES_KEY GENMASK(7, 0) #define MT7996_SEC_ENCRYPT BIT(0) #define MT7996_SEC_KEY_IDX GENMASK(2, 1) #define MT7996_SEC_IV BIT(3) +struct fixed_rate_table_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 table_idx; + u8 antenna_idx; + __le16 rate_idx; + u8 spe_idx_sel; + u8 spe_idx; + u8 gi; + u8 he_ltf; + bool ldpc; + bool txbf; + bool dynamic_bw; + + u8 _rsv2; +} __packed; + #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mmio.c b/sys/contrib/dev/mediatek/mt76/mt7996/mmio.c index 8107d58d9802..bf21780427b2 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mmio.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mmio.c @@ -1,398 +1,690 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #include #include #include +#include #include "mt7996.h" #include "mac.h" +#include "mcu.h" #include "../trace.h" +#include "../dma.h" + +static bool wed_enable; +module_param(wed_enable, bool, 0644); +#if defined(__FreeBSD__) +MODULE_PARM_DESC(wed_enable, "Enable Wireless Ethernet Dispatch support"); +#endif static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, [WF_ARB_BASE] = { { 0x820e3000, 0x820f3000, 0x830e3000 } }, [WF_TMAC_BASE] = { { 0x820e4000, 0x820f4000, 0x830e4000 } }, [WF_RMAC_BASE] = { { 0x820e5000, 0x820f5000, 0x830e5000 } }, [WF_DMA_BASE] = { { 0x820e7000, 0x820f7000, 0x830e7000 } }, [WF_WTBLOFF_BASE] = { { 0x820e9000, 0x820f9000, 0x830e9000 } }, [WF_ETBF_BASE] = { { 0x820ea000, 0x820fa000, 0x830ea000 } }, [WF_LPON_BASE] = { { 0x820eb000, 0x820fb000, 0x830eb000 } }, [WF_MIB_BASE] = { { 0x820ed000, 0x820fd000, 0x830ed000 } }, [WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } }, }; +static const u32 mt7996_offs[] = { + [MIB_RVSR0] = 0x720, + [MIB_RVSR1] = 0x724, + [MIB_BTSCR5] = 0x788, + [MIB_BTSCR6] = 0x798, + [MIB_RSCR1] = 0x7ac, + [MIB_RSCR27] = 0x954, + [MIB_RSCR28] = 0x958, + [MIB_RSCR29] = 0x95c, + [MIB_RSCR30] = 0x960, + [MIB_RSCR31] = 0x964, + [MIB_RSCR33] = 0x96c, + [MIB_RSCR35] = 0x974, + [MIB_RSCR36] = 0x978, + [MIB_BSCR0] = 0x9cc, + [MIB_BSCR1] = 0x9d0, + [MIB_BSCR2] = 0x9d4, + [MIB_BSCR3] = 0x9d8, + [MIB_BSCR4] = 0x9dc, + [MIB_BSCR5] = 0x9e0, + [MIB_BSCR6] = 0x9e4, + [MIB_BSCR7] = 0x9e8, + [MIB_BSCR17] = 0xa10, + [MIB_TRDR1] = 0xa28, +}; + +static const u32 mt7992_offs[] = { + [MIB_RVSR0] = 0x760, + [MIB_RVSR1] = 0x764, + [MIB_BTSCR5] = 0x7c8, + [MIB_BTSCR6] = 0x7d8, + [MIB_RSCR1] = 0x7f0, + [MIB_RSCR27] = 0x998, + [MIB_RSCR28] = 0x99c, + [MIB_RSCR29] = 0x9a0, + [MIB_RSCR30] = 0x9a4, + [MIB_RSCR31] = 0x9a8, + [MIB_RSCR33] = 0x9b0, + [MIB_RSCR35] = 0x9b8, + [MIB_RSCR36] = 0x9bc, + [MIB_BSCR0] = 0xac8, + [MIB_BSCR1] = 0xacc, + [MIB_BSCR2] = 0xad0, + [MIB_BSCR3] = 0xad4, + [MIB_BSCR4] = 0xad8, + [MIB_BSCR5] = 0xadc, + [MIB_BSCR6] = 0xae0, + [MIB_BSCR7] = 0xae4, + [MIB_BSCR17] = 0xb0c, + [MIB_TRDR1] = 0xb24, +}; + static const struct __map mt7996_reg_map[] = { { 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ { 0x56000000, 0x04000, 0x1000 }, /* WFDMA reserved */ { 0x57000000, 0x05000, 0x1000 }, /* WFDMA MCU wrap CR */ { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */ { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */ { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */ { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */ { 0x820cc000, 0x0e000, 0x1000 }, /* WF_UMAC_TOP (PP) */ { 0x74030000, 0x10000, 0x1000 }, /* PCIe MAC */ { 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) */ { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */ { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */ { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */ { 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) */ { 0x820ca000, 0x26000, 0x2000 }, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */ { 0x40000000, 0x70000, 0x10000 }, /* WF_UMAC_SYSRAM */ { 0x00400000, 0x80000, 0x10000 }, /* WF_MCU_SYSRAM */ { 0x00410000, 0x90000, 0x10000 }, /* WF_MCU_SYSRAM (configure register) */ { 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) */ { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */ { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */ { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */ { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */ { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */ { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */ { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */ { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */ { 0x820cc000, 0xa5000, 0x2000 }, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ { 0x820c4000, 0xa8000, 0x4000 }, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ { 0x820b0000, 0xae000, 0x1000 }, /* [APB2] WFSYS_ON */ { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */ { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */ { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, wfdma */ { 0x7c060000, 0xe0000, 0x10000 }, /* CONN_INFRA, conn_host_csr_top */ { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */ { 0x0, 0x0, 0x0 }, /* imply end of search */ }; static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) { u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); - dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); return MT_HIF_REMAP_BASE_L1 + offset; } static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) { u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); - dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); return MT_HIF_REMAP_BASE_L2 + offset; } -static void mt7996_reg_remap_restore(struct mt7996_dev *dev) -{ - /* remap to ori status */ - if (unlikely(dev->reg_l1_backup)) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup); - dev->reg_l1_backup = 0; - } - - if (dev->reg_l2_backup) { - dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup); - dev->reg_l2_backup = 0; - } -} - static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) { int i; - mt7996_reg_remap_restore(dev); - if (addr < 0x100000) return addr; for (i = 0; i < dev->reg.map_size; i++) { u32 ofs; if (addr < dev->reg.map[i].phys) continue; ofs = addr - dev->reg.map[i].phys; - if (ofs > dev->reg.map[i].size) + if (ofs >= dev->reg.map[i].size) continue; return dev->reg.map[i].mapped + ofs; } + return 0; +} + +static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) +{ if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) || (addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) || (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) return mt7996_reg_map_l1(dev, addr); if (dev_is_pci(dev->mt76.dev) && ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || addr >= MT_CBTOP2_PHY_START)) return mt7996_reg_map_l1(dev, addr); /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ if (addr >= MT_INFRA_MCU_START && addr <= MT_INFRA_MCU_END) { addr = addr - MT_INFRA_MCU_START + MT_INFRA_BASE; return mt7996_reg_map_l1(dev, addr); } return mt7996_reg_map_l2(dev, addr); } void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, size_t len) { u32 addr = __mt7996_reg_addr(dev, offset); + if (addr) { +#if defined(__linux__) + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); +#elif defined(__FreeBSD__) + memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + addr, len); +#endif + return; + } + + spin_lock_bh(&dev->reg_lock); #if defined(__linux__) - memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); + memcpy_fromio(buf, dev->mt76.mmio.regs + #elif defined(__FreeBSD__) - memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + addr, len); + memcpy_fromio(buf, (u8 *)dev->mt76.mmio.regs + #endif + __mt7996_reg_remap_addr(dev, offset), len); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset), val; + + if (addr) + return dev->bus_ops->rr(mdev, addr); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset)); + spin_unlock_bh(&dev->reg_lock); - return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset)); + return val; } static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); + + if (addr) { + dev->bus_ops->wr(mdev, addr, val); + return; + } - dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val); + spin_lock_bh(&dev->reg_lock); + dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val); + spin_unlock_bh(&dev->reg_lock); } static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + u32 addr = __mt7996_reg_addr(dev, offset); + + if (addr) + return dev->bus_ops->rmw(mdev, addr, mask, val); + + spin_lock_bh(&dev->reg_lock); + val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val); + spin_unlock_bh(&dev->reg_lock); + + return val; +} + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed) +{ + struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt76_phy *mphy = &dev->mphy; + int ret; + + ASSERT_RTNL(); + + if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state)) + return -EBUSY; - return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); + ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1, + mphy->band_idx); + if (ret) + goto out; + + rtnl_unlock(); + if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) { + dev_err(mdev->dev, "wed reset timeout\n"); + ret = -ETIMEDOUT; + } + rtnl_lock(); +out: + clear_bit(MT76_STATE_WED_RESET, &mphy->state); + + return ret; +} +#endif + +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct pci_dev *pci_dev = pdev_ptr; + u32 hif1_ofs = 0; + + if (!wed_enable) + return 0; + + dev->has_rro = true; + + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + + if (hif2) + wed = &dev->mt76.mmio.wed_hif2; + + wed->wlan.pci_dev = pci_dev; + wed->wlan.bus_type = MTK_WED_BUS_PCIE; + + wed->wlan.base = devm_ioremap(dev->mt76.dev, + pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); + + if (hif2) { + wed->wlan.wpdma_int = wed->wlan.phy_base + + MT_INT_PCIE1_SOURCE_CSR_EXT; + wed->wlan.wpdma_mask = wed->wlan.phy_base + + MT_INT_PCIE1_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND2 * MT_RING_SIZE; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + } else { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + } + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; + wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.id = 0x7991; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; + } else { + wed->wlan.hw_rro = dev->has_rro; /* default on */ + wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; + wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; + + wed->wlan.wpdma_rx = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; + + wed->wlan.rx_nbuf = 65536; + wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); + + wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + + wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + + wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; + wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; + wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1; + + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; + wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; + } + + wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; + wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + + wed->wlan.amsdu_max_subframes = 8; + wed->wlan.amsdu_max_len = 1536; + + wed->wlan.init_buf = mt7996_wed_init_buf; + wed->wlan.init_rx_buf = mt76_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_wed_offload_enable; + wed->wlan.offload_disable = mt76_wed_offload_disable; + if (!hif2) { + wed->wlan.reset = mt7996_mmio_wed_reset; + wed->wlan.reset_complete = mt76_wed_reset_complete; + } + + if (mtk_wed_device_attach(wed)) + return 0; + + *irq = wed->irq; + dev->mt76.dma_dev = wed->dev; + + return 1; +#else + return 0; +#endif } static int mt7996_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, u32 device_id) { struct mt76_bus_ops *bus_ops; struct mt7996_dev *dev; dev = container_of(mdev, struct mt7996_dev, mt76); mt76_mmio_init(&dev->mt76, mem_base); + spin_lock_init(&dev->reg_lock); switch (device_id) { case 0x7990: dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7996_offs; + dev->reg.map = mt7996_reg_map; + dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); + break; + case 0x7992: + dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7992_offs; dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; default: return -EINVAL; } dev->bus_ops = dev->mt76.bus; bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), GFP_KERNEL); if (!bus_ops) return -ENOMEM; bus_ops->rr = mt7996_rr; bus_ops->wr = mt7996_wr; bus_ops->rmw = mt7996_rmw; dev->mt76.bus = bus_ops; mdev->rev = (device_id << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); return 0; } void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, u32 clear, u32 set) { struct mt76_dev *mdev = &dev->mt76; unsigned long flags; spin_lock_irqsave(&mdev->mmio.irq_lock, flags); mdev->mmio.irqmask &= ~clear; mdev->mmio.irqmask |= set; if (write_reg) { - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); - mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2, + mdev->mmio.irqmask); + } + } else { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + } } spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); } static void mt7996_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q) { struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); mt7996_irq_enable(dev, MT_INT_RX(q)); } /* TODO: support 2/4/6/8 MSI-X vectors */ static void mt7996_irq_tasklet(struct tasklet_struct *t) { struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); - u32 i, intr, mask, intr1; - - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); - - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - intr &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); - - if (dev->hif2) { - intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); - intr1 &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; + u32 i, intr, mask, intr1 = 0; + + if (dev->hif2 && mtk_wed_device_active(wed_hif2)) { + mtk_wed_device_irq_set_mask(wed_hif2, 0); + intr1 = mtk_wed_device_irq_get(wed_hif2, + dev->mt76.mmio.irqmask); + if (intr1 & MT_INT_RX_TXFREE_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); + } - intr |= intr1; + if (mtk_wed_device_active(wed)) { + mtk_wed_device_irq_set_mask(wed, 0); + intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); + intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); + } else { + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + intr &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (dev->hif2) { + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); + intr1 &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + intr |= intr1; + } } trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); mask = intr & MT_INT_RX_DONE_ALL; if (intr & MT_INT_TX_DONE_MCU) mask |= MT_INT_TX_DONE_MCU; mt7996_irq_disable(dev, mask); if (intr & MT_INT_TX_DONE_MCU) napi_schedule(&dev->mt76.tx_napi); for (i = 0; i < __MT_RXQ_MAX; i++) { if ((intr & MT_INT_RX(i))) napi_schedule(&dev->mt76.napi[i]); } if (intr & MT_INT_MCU_CMD) { u32 val = mt76_rr(dev, MT_MCU_CMD); mt76_wr(dev, MT_MCU_CMD, val); if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { dev->recovery.state = val; mt7996_reset(dev); } } } irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0); + else + mt76_wr(dev, MT_INT_MASK_CSR, 0); + + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0); + else + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + } if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; tasklet_schedule(&dev->mt76.irq_tasklet); return IRQ_HANDLED; } struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, void __iomem *mem_base, u32 device_id) { static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), + .link_data_size = sizeof(struct mt7996_vif_link), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_AMSDU_OFFLOAD | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, .token_size = MT7996_TOKEN_SIZE, .tx_prepare_skb = mt7996_tx_prepare_skb, .tx_complete_skb = mt76_connac_tx_complete_skb, .rx_skb = mt7996_queue_rx_skb, .rx_check = mt7996_rx_check, .rx_poll_complete = mt7996_rx_poll_complete, .sta_add = mt7996_mac_sta_add, + .sta_event = mt7996_mac_sta_event, .sta_remove = mt7996_mac_sta_remove, .update_survey = mt7996_update_channel, + .set_channel = mt7996_set_channel, + .vif_link_add = mt7996_vif_link_add, + .vif_link_remove = mt7996_vif_link_remove, }; struct mt7996_dev *dev; struct mt76_dev *mdev; int ret; mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7996_ops, &drv_ops); if (!mdev) return ERR_PTR(-ENOMEM); dev = container_of(mdev, struct mt7996_dev, mt76); ret = mt7996_mmio_init(mdev, mem_base, device_id); if (ret) goto error; tasklet_setup(&mdev->irq_tasklet, mt7996_irq_tasklet); mt76_wr(dev, MT_INT_MASK_CSR, 0); return dev; error: mt76_free_device(&dev->mt76); return ERR_PTR(ret); } static int __init mt7996_init(void) { int ret; ret = pci_register_driver(&mt7996_hif_driver); if (ret) return ret; ret = pci_register_driver(&mt7996_pci_driver); if (ret) pci_unregister_driver(&mt7996_hif_driver); return ret; } static void __exit mt7996_exit(void) { pci_unregister_driver(&mt7996_pci_driver); pci_unregister_driver(&mt7996_hif_driver); } module_init(mt7996_init); module_exit(mt7996_exit); +MODULE_DESCRIPTION("MediaTek MT7996 MMIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/mt7996.h b/sys/contrib/dev/mediatek/mt76/mt7996/mt7996.h index 033b761a5372..f6491cf6005f 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/mt7996.h +++ b/sys/contrib/dev/mediatek/mt76/mt7996/mt7996.h @@ -1,502 +1,755 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2022 MediaTek Inc. */ #ifndef __MT7996_H #define __MT7996_H #include #include #if defined(__FreeBSD__) #include #endif #include "../mt76_connac.h" #include "regs.h" +#define MT7996_MAX_RADIOS 3 #define MT7996_MAX_INTERFACES 19 /* per-band */ #define MT7996_MAX_WMM_SETS 4 +#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64) #define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1) #define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \ mt7996_max_interface_num(dev)) #define MT7996_WATCHDOG_TIME (HZ / 10) #define MT7996_RESET_TIMEOUT (30 * HZ) #define MT7996_TX_RING_SIZE 2048 #define MT7996_TX_MCU_RING_SIZE 256 #define MT7996_TX_FWDL_RING_SIZE 128 #define MT7996_RX_RING_SIZE 1536 #define MT7996_RX_MCU_RING_SIZE 512 #define MT7996_RX_MCU_RING_SIZE_WA 1024 #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin" #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin" #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin" +#define MT7996_FIRMWARE_WA_233 "mediatek/mt7996/mt7996_wa_233.bin" +#define MT7996_FIRMWARE_WM_233 "mediatek/mt7996/mt7996_wm_233.bin" +#define MT7996_FIRMWARE_DSP_233 MT7996_FIRMWARE_DSP +#define MT7996_ROM_PATCH_233 "mediatek/mt7996/mt7996_rom_patch_233.bin" + +#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin" +#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin" +#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin" +#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" + +#define MT7992_FIRMWARE_WA_23 "mediatek/mt7996/mt7992_wa_23.bin" +#define MT7992_FIRMWARE_WM_23 "mediatek/mt7996/mt7992_wm_23.bin" +#define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" +#define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" +#define MT7996_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7996_eeprom_2i5i6i.bin" +#define MT7996_EEPROM_DEFAULT_233 "mediatek/mt7996/mt7996_eeprom_233.bin" +#define MT7996_EEPROM_DEFAULT_233_INT "mediatek/mt7996/mt7996_eeprom_233_2i5i6i.bin" + +#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin" +#define MT7992_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7992_eeprom_2i5i.bin" +#define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" +#define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" +#define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" + #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 +#define MT7996_HW_TOKEN_SIZE 8192 #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7996_IBF_MAX_NC 2 +#define MT7996_IBF_TIMEOUT 0x18 +#define MT7996_IBF_TIMEOUT_LEGACY 0x48 + +#define MT7992_CFEND_RATE_DEFAULT 0x4b /* OFDM 6M */ +#define MT7992_IBF_TIMEOUT 0xff + +#define MT7996_SKU_RATE_NUM 417 +#define MT7996_SKU_PATH_NUM 494 #define MT7996_MAX_TWT_AGRT 16 #define MT7996_MAX_STA_TWT_AGRT 8 +#define MT7996_MIN_TWT_DUR 64 #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ -#define MT7996_BASIC_RATES_TBL 11 +#define MT7996_BASIC_RATES_TBL 31 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_THERMAL_THROTTLE_MAX 100 +#define MT7996_CDEV_THROTTLE_MAX 99 +#define MT7996_CRIT_TEMP_IDX 0 +#define MT7996_MAX_TEMP_IDX 1 +#define MT7996_CRIT_TEMP 110 +#define MT7996_MAX_TEMP 120 + +#define MT7996_RRO_MAX_SESSION 1024 +#define MT7996_RRO_WINDOW_MAX_LEN 1024 +#define MT7996_RRO_ADDR_ELEM_LEN 128 +#define MT7996_RRO_BA_BITMAP_LEN 2 +#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \ + MT7996_RRO_BA_BITMAP_LEN) +#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \ + MT7996_RRO_ADDR_ELEM_LEN) +#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \ + MT7996_RRO_BA_BITMAP_SESSION_SIZE) + +#define MT7996_RX_BUF_SIZE (1800 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + struct mt7996_vif; struct mt7996_sta; struct mt7996_dfs_pulse; struct mt7996_dfs_pattern; enum mt7996_ram_type { MT7996_RAM_TYPE_WM, MT7996_RAM_TYPE_WA, MT7996_RAM_TYPE_DSP, }; +enum mt7996_var_type { + MT7996_VAR_TYPE_444, + MT7996_VAR_TYPE_233, +}; + +enum mt7992_var_type { + MT7992_VAR_TYPE_44, + MT7992_VAR_TYPE_23, +}; + +enum mt7996_fem_type { + MT7996_FEM_EXT, + MT7996_FEM_INT, + MT7996_FEM_MIX, +}; + enum mt7996_txq_id { MT7996_TXQ_FWDL = 16, MT7996_TXQ_MCU_WM, MT7996_TXQ_BAND0, MT7996_TXQ_BAND1, MT7996_TXQ_MCU_WA, MT7996_TXQ_BAND2, }; enum mt7996_rxq_id { MT7996_RXQ_MCU_WM = 0, MT7996_RXQ_MCU_WA, MT7996_RXQ_MCU_WA_MAIN = 2, - MT7996_RXQ_MCU_WA_EXT = 2,/* unused */ + MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */ MT7996_RXQ_MCU_WA_TRI = 3, MT7996_RXQ_BAND0 = 4, - MT7996_RXQ_BAND1 = 4,/* unused */ + MT7996_RXQ_BAND1 = 5, /* for mt7992 */ MT7996_RXQ_BAND2 = 5, + MT7996_RXQ_RRO_BAND0 = 8, + MT7996_RXQ_RRO_BAND1 = 8,/* unused */ + MT7996_RXQ_RRO_BAND2 = 6, + MT7996_RXQ_MSDU_PG_BAND0 = 10, + MT7996_RXQ_MSDU_PG_BAND1 = 11, + MT7996_RXQ_MSDU_PG_BAND2 = 12, + MT7996_RXQ_TXFREE0 = 9, + MT7996_RXQ_TXFREE1 = 9, + MT7996_RXQ_TXFREE2 = 7, + MT7996_RXQ_RRO_IND = 0, }; struct mt7996_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; }; DECLARE_EWMA(avg_signal, 10, 8) struct mt7996_sta { struct mt76_wcid wcid; /* must be first */ struct mt7996_vif *vif; struct list_head rc_list; u32 airtime_ac[8]; int ack_signal; struct ewma_avg_signal avg_ack_signal; unsigned long changed; - unsigned long jiffies; struct mt76_connac_sta_key_conf bip; struct { u8 flowid_mask; struct mt7996_twt_flow flow[MT7996_MAX_STA_TWT_AGRT]; } twt; }; -struct mt7996_vif { - struct mt76_vif mt76; /* must be first */ +struct mt7996_vif_link { + struct mt76_vif_link mt76; /* must be first */ struct mt7996_sta sta; struct mt7996_phy *phy; struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; struct cfg80211_bitrate_mask bitrate_mask; }; +struct mt7996_vif { + struct mt7996_vif_link deflink; /* must be first */ + struct mt76_vif_data mt76; +}; + /* crash-dump */ struct mt7996_crash_data { guid_t guid; struct timespec64 timestamp; u8 *memdump_buf; size_t memdump_buf_len; }; struct mt7996_hif { struct list_head list; struct device *dev; void __iomem *regs; int irq; }; +struct mt7996_wed_rro_addr { + u32 head_low; + u32 head_high : 4; + u32 count: 11; + u32 oor: 1; + u32 rsv : 8; + u32 signature : 8; +}; + +struct mt7996_wed_rro_session_id { + struct list_head list; + u16 id; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; - struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 cdev_state; + u8 throttle_state; + u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ u32 rxfilter; u64 omac_mask; u16 noise; s16 coverage_class; u8 slottime; u8 rdd_state; + u16 beacon_rate; + u32 rx_ampdu_ts; u32 ampdu_ref; + int txpower; struct mt76_mib_stats mib; struct mt76_channel_state state_ts; + + u16 orig_chainmask; + + bool has_aux_rx; + bool counter_reset; }; struct mt7996_dev { union { /* must be first */ struct mt76_dev mt76; struct mt76_phy mphy; }; + struct mt7996_phy *radio_phy[MT7996_MAX_RADIOS]; + struct wiphy_radio radios[MT7996_MAX_RADIOS]; + struct wiphy_radio_freq_range radio_freqs[MT7996_MAX_RADIOS]; + struct mt7996_hif *hif2; struct mt7996_reg_desc reg; u8 q_id[MT7996_MAX_QUEUE]; u32 q_int_mask[MT7996_MAX_QUEUE]; u32 q_wfdma_mask; const struct mt76_bus_ops *bus_ops; struct mt7996_phy phy; /* monitor rx chain configured channel */ struct cfg80211_chan_def rdd2_chandef; struct mt7996_phy *rdd2_phy; u16 chainmask; u8 chainshift[__MT_MAX_BAND]; u32 hif_idx; struct work_struct init_work; struct work_struct rc_work; struct work_struct dump_work; struct work_struct reset_work; wait_queue_head_t reset_wait; struct { u32 state; u32 wa_reset_count; u32 wm_reset_count; bool hw_full_reset:1; bool hw_init_done:1; bool restart:1; } recovery; /* protects coredump data */ struct mutex dump_mutex; #ifdef CONFIG_DEV_COREDUMP struct { struct mt7996_crash_data *crash_data; } coredump; #endif struct list_head sta_rc_list; struct list_head twt_list; u32 hw_pattern; - bool dbdc_support:1; - bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; + bool has_rro:1; + + struct { + struct { + void *ptr; + dma_addr_t phy_addr; + } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } addr_elem[MT7996_RRO_ADDR_ELEM_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } session; + + struct work_struct work; + struct list_head poll_list; + spinlock_t lock; + } wed_rro; bool ibf; u8 fw_debug_wm; u8 fw_debug_wa; u8 fw_debug_bin; u16 fw_debug_seq; struct dentry *debugfs_dir; struct rchan *relay_fwlog; struct { - u8 table_mask; + u16 table_mask; u8 n_agrt; } twt; - u32 reg_l1_backup; - u32 reg_l2_backup; + spinlock_t reg_lock; u8 wtbl_size_group; + struct { + u8 type:4; + u8 fem:4; + } var; }; enum { WFDMA0 = 0x0, WFDMA1, WFDMA_EXT, __MT_WFDMA_MAX, }; enum { MT_RX_SEL0, MT_RX_SEL1, MT_RX_SEL2, /* monitor chain */ }; enum mt7996_rdd_cmd { RDD_STOP, RDD_START, RDD_DET_MODE, RDD_RADAR_EMULATE, RDD_START_TXQ = 20, RDD_CAC_START = 50, RDD_CAC_END, RDD_NORMAL_START, RDD_DISABLE_DFS_CAL, RDD_PULSE_DBG, RDD_READ_PULSE, RDD_RESUME_BF, RDD_IRQ_OFF, }; -static inline struct mt7996_phy * -mt7996_hw_phy(struct ieee80211_hw *hw) -{ - struct mt76_phy *phy = hw->priv; - - return phy->priv; -} - static inline struct mt7996_dev * mt7996_hw_dev(struct ieee80211_hw *hw) { struct mt76_phy *phy = hw->priv; return container_of(phy->dev, struct mt7996_dev, mt76); } static inline struct mt7996_phy * __mt7996_phy(struct mt7996_dev *dev, enum mt76_band_id band) { struct mt76_phy *phy = dev->mt76.phys[band]; if (!phy) return NULL; return phy->priv; } static inline struct mt7996_phy * mt7996_phy2(struct mt7996_dev *dev) { return __mt7996_phy(dev, MT_BAND1); } static inline struct mt7996_phy * mt7996_phy3(struct mt7996_dev *dev) { return __mt7996_phy(dev, MT_BAND2); } +static inline bool +mt7996_band_valid(struct mt7996_dev *dev, u8 band) +{ + if (is_mt7992(&dev->mt76)) + return band <= MT_BAND1; + + return band <= MT_BAND2; +} + +static inline bool +mt7996_has_background_radar(struct mt7996_dev *dev) +{ + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + if (dev->var.type == MT7996_VAR_TYPE_233) + return false; + break; + case 0x7992: + if (dev->var.type == MT7992_VAR_TYPE_23) + return false; + break; + default: + return false; + } + + return true; +} + +static inline struct mt7996_phy * +mt7996_band_phy(struct mt7996_dev *dev, enum nl80211_band band) +{ + struct mt76_phy *mphy; + + mphy = dev->mt76.band_phys[band]; + if (!mphy) + return NULL; + + return mphy->priv; +} + +static inline struct mt7996_vif_link * +mt7996_vif_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, int link_id) +{ + return (struct mt7996_vif_link *)mt76_vif_link(&dev->mt76, vif, link_id); +} + +static inline struct mt7996_phy * +mt7996_vif_link_phy(struct mt7996_vif_link *link) +{ + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); + + if (!mphy) + return NULL; + + return mphy->priv; +} + +static inline struct mt7996_vif_link * +mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + return (struct mt7996_vif_link *)mt76_vif_conf_link(&dev->mt76, vif, + link_conf); +} + +#define mt7996_for_each_phy(dev, phy) \ + for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \ + if (((phy) = (dev)->radio_phy[__i]) != NULL) + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, void __iomem *mem_base, u32 device_id); void mt7996_wfsys_reset(struct mt7996_dev *dev); irqreturn_t mt7996_irq_handler(int irq, void *dev_instance); u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif); int mt7996_register_device(struct mt7996_dev *dev); void mt7996_unregister_device(struct mt7996_dev *dev); +int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); +void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink); int mt7996_eeprom_init(struct mt7996_dev *dev); int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy); int mt7996_eeprom_get_target_power(struct mt7996_dev *dev, struct ieee80211_channel *chan); s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band); int mt7996_dma_init(struct mt7996_dev *dev); void mt7996_dma_reset(struct mt7996_dev *dev, bool force); void mt7996_dma_prefetch(struct mt7996_dev *dev); void mt7996_dma_cleanup(struct mt7996_dev *dev); -void mt7996_dma_start(struct mt7996_dev *dev, bool reset); -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband); +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, + int n_desc, int ring_base, struct mtk_wed_device *wed); +void mt7996_init_txpower(struct mt7996_phy *phy); int mt7996_txbf_init(struct mt7996_dev *dev); void mt7996_reset(struct mt7996_dev *dev); -int mt7996_run(struct ieee80211_hw *hw); +int mt7996_run(struct mt7996_phy *phy); int mt7996_mcu_init(struct mt7996_dev *dev); int mt7996_mcu_init_firmware(struct mt7996_dev *dev); int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, struct mt7996_vif *mvif, struct mt7996_twt_flow *flow, int cmd); -int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, bool enable); -int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, - struct ieee80211_vif *vif, int enable); +int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, bool enable); +int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt76_vif_link *mlink, int enable); int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, bool enable); + struct mt76_vif_link *mlink, + struct ieee80211_sta *sta, int conn_state, bool newly); int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, bool add); int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, bool add); -int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif, +int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, + struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color); int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - int enable); + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, struct ieee80211_vif *vif, u32 changed); int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd); int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed); -int mt7996_set_channel(struct mt7996_phy *phy); +int mt7996_set_channel(struct mt76_phy *mphy); int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag); -int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif); +int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version); +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset); +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len); int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action); int mt7996_mcu_set_fcc5_lpn(struct mt7996_dev *dev, int val); int mt7996_mcu_set_pulse_th(struct mt7996_dev *dev, const struct mt7996_dfs_pulse *pulse); int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index, const struct mt7996_dfs_pattern *pattern); int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); -int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif); +int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); +int mt7996_mcu_get_temperature(struct mt7996_phy *phy); +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val); +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl); int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); void mt7996_mcu_exit(struct mt7996_dev *dev); +int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); +int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support); + return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)), + MT7996_WTBL_BMC_SIZE); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) { - return (dev->wtbl_size_group << 8) + 64; + return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE; } void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, u32 clear, u32 set); static inline void mt7996_irq_enable(struct mt7996_dev *dev, u32 mask) { if (dev->hif2) mt7996_dual_hif_set_irq_mask(dev, false, 0, mask); else mt76_set_irq_mask(&dev->mt76, 0, 0, mask); tasklet_schedule(&dev->mt76.irq_tasklet); } static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask) { if (dev->hif2) mt7996_dual_hif_set_irq_mask(dev, true, mask, 0); else mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, size_t len); +static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) +{ + int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx); + int cur_nss = hweight8(phy->mt76->antenna_mask); + u16 tx_chainmask = phy->mt76->chainmask; + + if (cur_nss != max_nss) + return tx_chainmask; + + return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); void mt7996_mac_reset_counters(struct mt7996_phy *phy); void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy); void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, struct ieee80211_vif *vif, bool enable); -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); void mt7996_mac_set_coverage_class(struct mt7996_phy *phy); int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev); void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7996_mac_work(struct work_struct *work); void mt7996_mac_reset_work(struct work_struct *work); void mt7996_mac_dump_work(struct work_struct *work); void mt7996_mac_sta_rc_work(struct work_struct *work); void mt7996_mac_update_stats(struct mt7996_phy *phy); void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, struct mt7996_sta *msta, u8 flowid); void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_twt_setup *twt); int mt7996_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 mt7996_tx_token_put(struct mt7996_dev *dev); void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7996_stats_work(struct work_struct *work); int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force); int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy); void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy); void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy); void mt7996_update_channel(struct mt76_phy *mphy); -int mt7996_init_debugfs(struct mt7996_phy *phy); +int mt7996_init_debugfs(struct mt7996_dev *dev); void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len); bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len); int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd); +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key); int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode); #ifdef CONFIG_MAC80211_DEBUGFS void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq); +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); + +#ifdef CONFIG_MTK_DEBUG +int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); +#endif + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/pci.c b/sys/contrib/dev/mediatek/mt76/mt7996/pci.c index 001888733bc7..dfb86ba5bedb 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/pci.c +++ b/sys/contrib/dev/mediatek/mt76/mt7996/pci.c @@ -1,245 +1,281 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2022 MediaTek Inc. */ #if defined(__FreeBSD__) #define LINUXKPI_PARAM_PREFIX mt7996_pci_ #endif #include #include #include #include "mt7996.h" #include "mac.h" #include "../trace.h" static LIST_HEAD(hif_list); static DEFINE_SPINLOCK(hif_lock); static u32 hif_idx; static const struct pci_device_id mt7996_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7992) }, { }, }; static const struct pci_device_id mt7996_hif_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) }, { }, }; static struct mt7996_hif *mt7996_pci_get_hif2(u32 idx) { struct mt7996_hif *hif; u32 val; spin_lock_bh(&hif_lock); list_for_each_entry(hif, &hif_list, list) { #if defined(__linux__) val = readl(hif->regs + MT_PCIE_RECOG_ID); #elif defined(__FreeBSD__) val = readl((u8 *)hif->regs + MT_PCIE_RECOG_ID); #endif val &= MT_PCIE_RECOG_ID_MASK; if (val != idx) continue; get_device(hif->dev); goto out; } hif = NULL; out: spin_unlock_bh(&hif_lock); return hif; } static void mt7996_put_hif2(struct mt7996_hif *hif) { if (!hif) return; put_device(hif->dev); } static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { hif_idx++; + #if defined(__linux__) - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL)) + if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) #elif defined(__FreeBSD__) - if (!linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL)) + if (!linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && + !linuxkpi_pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) #endif return NULL; writel(hif_idx | MT_PCIE_RECOG_ID_SEM, #if defined(__linux__) pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); #elif defined(__FreeBSD__) (u8 *)(pcim_iomap_table(pdev)[0]) + MT_PCIE_RECOG_ID); #endif return mt7996_pci_get_hif2(hif_idx); } static int mt7996_pci_hif2_probe(struct pci_dev *pdev) { struct mt7996_hif *hif; hif = devm_kzalloc(&pdev->dev, sizeof(*hif), GFP_KERNEL); if (!hif) return -ENOMEM; hif->dev = &pdev->dev; hif->regs = pcim_iomap_table(pdev)[0]; hif->irq = pdev->irq; spin_lock_bh(&hif_lock); list_add(&hif->list, &hif_list); spin_unlock_bh(&hif_lock); pci_set_drvdata(pdev, hif); return 0; } static int mt7996_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pci_dev *hif2_dev; + struct mt7996_hif *hif2; struct mt7996_dev *dev; + int irq, hif2_irq, ret; struct mt76_dev *mdev; - struct mt7996_hif *hif2; - int irq, ret; ret = pcim_enable_device(pdev); if (ret) return ret; ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); if (ret) return ret; pci_set_master(pdev); - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36)); + if (ret) + return ret; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; mt76_pci_disable_aspm(pdev); - if (id->device == 0x7991) + if (id->device == 0x7991 || id->device == 0x799a) return mt7996_pci_hif2_probe(pdev); dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], id->device); if (IS_ERR(dev)) return PTR_ERR(dev); mdev = &dev->mt76; mt7996_wfsys_reset(dev); hif2 = mt7996_pci_init_hif2(pdev); - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) - goto free_device; + goto free_wed_or_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_device; + + irq = pdev->irq; + } - irq = pdev->irq; ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto free_irq_vector; + goto free_wed_or_irq_vector; mt76_wr(dev, MT_INT_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); if (hif2) { hif2_dev = container_of(hif2->dev, struct pci_dev, dev); dev->hif2 = hif2; - ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq); if (ret < 0) - goto free_hif2; + goto free_hif2_wed_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, + PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_hif2; - dev->hif2->irq = hif2_dev->irq; - ret = devm_request_irq(mdev->dev, dev->hif2->irq, - mt7996_irq_handler, IRQF_SHARED, - KBUILD_MODNAME "-hif", dev); + dev->hif2->irq = hif2_dev->irq; + hif2_irq = dev->hif2->irq; + } + + ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler, + IRQF_SHARED, KBUILD_MODNAME "-hif", + dev); if (ret) - goto free_hif2_irq_vector; + goto free_hif2_wed_irq_vector; mt76_wr(dev, MT_INT1_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); } ret = mt7996_register_device(dev); if (ret) goto free_hif2_irq; return 0; free_hif2_irq: if (dev->hif2) - devm_free_irq(mdev->dev, dev->hif2->irq, dev); -free_hif2_irq_vector: - if (dev->hif2) - pci_free_irq_vectors(hif2_dev); + devm_free_irq(mdev->dev, hif2_irq, dev); +free_hif2_wed_irq_vector: + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2); + else + pci_free_irq_vectors(hif2_dev); + } free_hif2: if (dev->hif2) put_device(dev->hif2->dev); devm_free_irq(mdev->dev, irq, dev); -free_irq_vector: - pci_free_irq_vectors(pdev); +free_wed_or_irq_vector: + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_detach(&dev->mt76.mmio.wed); + else + pci_free_irq_vectors(pdev); free_device: mt76_free_device(&dev->mt76); return ret; } static void mt7996_hif_remove(struct pci_dev *pdev) { struct mt7996_hif *hif = pci_get_drvdata(pdev); list_del(&hif->list); } static void mt7996_pci_remove(struct pci_dev *pdev) { struct mt76_dev *mdev; struct mt7996_dev *dev; mdev = pci_get_drvdata(pdev); dev = container_of(mdev, struct mt7996_dev, mt76); mt7996_put_hif2(dev->hif2); mt7996_unregister_device(dev); } struct pci_driver mt7996_hif_driver = { .name = KBUILD_MODNAME "_hif", .id_table = mt7996_hif_device_table, .probe = mt7996_pci_probe, .remove = mt7996_hif_remove, }; struct pci_driver mt7996_pci_driver = { .name = KBUILD_MODNAME, .id_table = mt7996_pci_device_table, .probe = mt7996_pci_probe, .remove = mt7996_pci_remove, }; MODULE_DEVICE_TABLE(pci, mt7996_pci_device_table); MODULE_DEVICE_TABLE(pci, mt7996_hif_device_table); MODULE_FIRMWARE(MT7996_FIRMWARE_WA); MODULE_FIRMWARE(MT7996_FIRMWARE_WM); MODULE_FIRMWARE(MT7996_FIRMWARE_DSP); MODULE_FIRMWARE(MT7996_ROM_PATCH); +MODULE_FIRMWARE(MT7992_FIRMWARE_WA); +MODULE_FIRMWARE(MT7992_FIRMWARE_WM); +MODULE_FIRMWARE(MT7992_FIRMWARE_DSP); +MODULE_FIRMWARE(MT7992_ROM_PATCH); #if defined(__FreeBSD__) MODULE_VERSION(mt7996_pci, 1); MODULE_DEPEND(mt7996_pci, linuxkpi, 1, 1, 1); MODULE_DEPEND(mt7996_pci, linuxkpi_wlan, 1, 1, 1); MODULE_DEPEND(mt7996_pci, mt76_core, 1, 1, 1); #endif diff --git a/sys/contrib/dev/mediatek/mt76/mt7996/regs.h b/sys/contrib/dev/mediatek/mt76/mt7996/regs.h index 97beab924517..1876a968c92d 100644 --- a/sys/contrib/dev/mediatek/mt76/mt7996/regs.h +++ b/sys/contrib/dev/mediatek/mt76/mt7996/regs.h @@ -1,596 +1,736 @@ /* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2022 MediaTek Inc. */ #ifndef __MT7996_REGS_H #define __MT7996_REGS_H struct __map { u32 phys; u32 mapped; u32 size; }; struct __base { u32 band_base[__MT_MAX_BAND]; }; /* used to differentiate between generations */ struct mt7996_reg_desc { const struct __base *base; + const u32 *offs_rev; const struct __map *map; u32 map_size; }; enum base_rev { WF_AGG_BASE, WF_ARB_BASE, WF_TMAC_BASE, WF_RMAC_BASE, WF_DMA_BASE, WF_WTBLOFF_BASE, WF_ETBF_BASE, WF_LPON_BASE, WF_MIB_BASE, WF_RATE_BASE, __MT_REG_BASE_MAX, }; #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +enum offs_rev { + MIB_RVSR0, + MIB_RVSR1, + MIB_BTSCR5, + MIB_BTSCR6, + MIB_RSCR1, + MIB_RSCR27, + MIB_RSCR28, + MIB_RSCR29, + MIB_RSCR30, + MIB_RSCR31, + MIB_RSCR33, + MIB_RSCR35, + MIB_RSCR36, + MIB_BSCR0, + MIB_BSCR1, + MIB_BSCR2, + MIB_BSCR3, + MIB_BSCR4, + MIB_BSCR5, + MIB_BSCR6, + MIB_BSCR7, + MIB_BSCR17, + MIB_TRDR1, + __MT_OFFS_MAX, +}; + +#define __OFFS(id) (dev->reg.offs_rev[(id)]) + +/* RRO TOP */ +#define MT_RRO_TOP_BASE 0xA000 +#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) + +#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8) +#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) +#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) +#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) +#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) +#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) + +#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C) +#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31) + +#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C) +#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60) +#define MT_RRO_PARTICULAR_CONFG_EN BIT(31) +#define MT_RRO_PARTICULAR_SID GENMASK(30, 16) + +#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70) +#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74) +#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204) +#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0) + +#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) + +#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) +#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) +#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) + +#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0) +#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0) +#define MT_RRO_DBG_RD_EXEC BIT(31) + +#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) #define MT_MCU_INT_EVENT_RESET_DONE BIT(3) /* PLE */ #define MT_PLE_BASE 0x820c0000 #define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) #define MT_FL_Q_EMPTY MT_PLE(0x360) #define MT_FL_Q0_CTRL MT_PLE(0x3e0) #define MT_FL_Q2_CTRL MT_PLE(0x3e8) #define MT_FL_Q3_CTRL MT_PLE(0x3ec) #define MT_PLE_FREEPG_CNT MT_PLE(0x380) #define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x384) #define MT_PLE_PG_HIF_GROUP MT_PLE(0x00c) #define MT_PLE_HIF_PG_INFO MT_PLE(0x388) #define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x600 + 0x80 * (ac) + ((n) << 2)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) /* WF MDP TOP */ #define MT_MDP_BASE 0x820cc000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) #define MT_MDP_DCR2 MT_MDP(0x8e8) #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) /* TMAC: band 0(0x820e4000), band 1(0x820f4000), band 2(0x830e4000) */ #define MT_WF_TMAC_BASE(_band) __BASE(WF_TMAC_BASE, (_band)) #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_CDTR(_band) MT_WF_TMAC(_band, 0x0c8) #define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x0cc) #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) #define MT_TIMEOUT_VAL_CCA GENMASK(31, 16) #define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x014) #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, 0x018) #define MT_IFS_EIFS_CCK GENMASK(8, 0) /* WF DMA TOP: band 0(0x820e7000), band 1(0x820f7000), band 2(0x830e7000) */ #define MT_WF_DMA_BASE(_band) __BASE(WF_DMA_BASE, (_band)) #define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs)) #define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) #define MT_DMA_TCRF1(_band) MT_WF_DMA(_band, 0x054) #define MT_DMA_TCRF1_QIDX GENMASK(15, 13) /* WTBLOFF TOP: band 0(0x820e9000), band 1(0x820f9000), band 2(0x830e9000) */ #define MT_WTBLOFF_BASE(_band) __BASE(WF_WTBLOFF_BASE, (_band)) #define MT_WTBLOFF(_band, ofs) (MT_WTBLOFF_BASE(_band) + (ofs)) #define MT_WTBLOFF_RSCR(_band) MT_WTBLOFF(_band, 0x008) #define MT_WTBLOFF_RSCR_RCPI_MODE GENMASK(31, 30) #define MT_WTBLOFF_RSCR_RCPI_PARAM GENMASK(25, 24) +#define MT_WTBLOFF_ACR(_band) MT_WTBLOFF(_band, 0x010) +#define MT_WTBLOFF_ADM_BACKOFFTIME BIT(29) + /* ETBF: band 0(0x820ea000), band 1(0x820fa000), band 2(0x830ea000) */ #define MT_WF_ETBF_BASE(_band) __BASE(WF_ETBF_BASE, (_band)) #define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs)) #define MT_ETBF_RX_FB_CONT(_band) MT_WF_ETBF(_band, 0x100) #define MT_ETBF_RX_FB_BW GENMASK(10, 8) #define MT_ETBF_RX_FB_NC GENMASK(7, 4) #define MT_ETBF_RX_FB_NR GENMASK(3, 0) /* LPON: band 0(0x820eb000), band 1(0x820fb000), band 2(0x830eb000) */ #define MT_WF_LPON_BASE(_band) __BASE(WF_LPON_BASE, (_band)) #define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs)) #define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, 0x360) #define MT_LPON_UTTR1(_band) MT_WF_LPON(_band, 0x364) #define MT_LPON_FRCR(_band) MT_WF_LPON(_band, 0x37c) #define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + (((n) * 4) << 4)) #define MT_LPON_TCR_SW_MODE GENMASK(1, 0) #define MT_LPON_TCR_SW_WRITE BIT(0) #define MT_LPON_TCR_SW_ADJUST BIT(1) #define MT_LPON_TCR_SW_READ GENMASK(1, 0) /* MIB: band 0(0x820ed000), band 1(0x820fd000), band 2(0x830ed000)*/ /* 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) __BASE(WF_MIB_BASE, (_band)) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) -#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc) -#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0) -#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4) -#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8) -#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc) -#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0) -#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4) -#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8) -#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10) +#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0)) +#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1)) +#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2)) +#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3)) +#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4)) +#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5)) +#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6)) +#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7)) +#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17)) #define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4) #define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8) #define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0) -#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac) +#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1)) /* rx mpdu counter, full 32 bits */ -#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964) -#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c) +#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31)) +#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33)) #define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020) #define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0) -#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720) +#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0)) -#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974) -#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978) +#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35)) +#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36)) /* tx ampdu cnt, full 32 bits */ #define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0) #define MT_MIB_TSCR2(_band) MT_WF_MIB(_band, 0x6b8) /* counts all mpdus in ampdu, regardless of success */ #define MT_MIB_TSCR3(_band) MT_WF_MIB(_band, 0x6bc) /* counts all successfully tx'd mpdus in ampdu */ #define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0) /* rx ampdu count, 32-bit */ -#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954) +#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27)) /* rx ampdu bytes count, 32-bit */ -#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958) +#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28)) /* rx ampdu valid subframe count */ -#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c) +#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29)) /* rx ampdu valid subframe bytes count, 32bits */ -#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960) +#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30)) /* remaining windows protected stats */ #define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080) #define MT_MIB_SDR27_TX_RWP_FAIL_CNT GENMASK(15, 0) #define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084) #define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0) -#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724) +#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1)) /* rx blockack count, 32 bits */ #define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4) #define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0) -#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788) -#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798) +#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5)) +#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6)) #define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0) -#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0)) /* UMIB */ #define MT_WF_UMIB_BASE 0x820cd000 #define MT_WF_UMIB(ofs) (MT_WF_UMIB_BASE + (ofs)) #define MT_UMIB_RPDCR(_band) (MT_WF_UMIB(0x594) + (_band) * 0x164) /* WTBLON TOP */ #define MT_WTBLON_TOP_BASE 0x820d4000 #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) #define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x370) #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(4, 0) #define MT_WTBL_UPDATE MT_WTBLON_TOP(0x380) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(11, 0) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(14) #define MT_WTBL_UPDATE_BUSY BIT(31) #define MT_WTBL_ITCR MT_WTBLON_TOP(0x3b0) #define MT_WTBL_ITCR_WR BIT(16) #define MT_WTBL_ITCR_EXEC BIT(31) #define MT_WTBL_ITDR0 MT_WTBLON_TOP(0x3b8) #define MT_WTBL_ITDR1 MT_WTBLON_TOP(0x3bc) #define MT_WTBL_SPE_IDX_SEL BIT(6) /* WTBL */ #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 | \ FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \ FIELD_PREP(MT_WTBL_LMAC_DW, _dw)) +/* AGG: band 0(0x820e2000), band 1(0x820f2000), band 2(0x830e2000) */ +#define MT_WF_AGG_BASE(_band) __BASE(WF_AGG_BASE, (_band)) +#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs)) + +#define MT_AGG_ACR4(_band) MT_WF_AGG(_band, 0x3c) +#define MT_AGG_ACR_PPDU_TXS2H BIT(1) + /* ARB: band 0(0x820e3000), band 1(0x820f3000), band 2(0x830e3000) */ #define MT_WF_ARB_BASE(_band) __BASE(WF_ARB_BASE, (_band)) #define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs)) #define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x000) #define MT_ARB_SCR_TX_DISABLE BIT(8) #define MT_ARB_SCR_RX_DISABLE BIT(9) /* RMAC: band 0(0x820e5000), band 1(0x820f5000), band 2(0x830e5000), */ #define MT_WF_RMAC_BASE(_band) __BASE(WF_RMAC_BASE, (_band)) #define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs)) #define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000) #define MT_WF_RFCR_DROP_STBC_MULTI BIT(0) #define MT_WF_RFCR_DROP_FCSFAIL BIT(1) #define MT_WF_RFCR_DROP_PROBEREQ BIT(4) #define MT_WF_RFCR_DROP_MCAST BIT(5) #define MT_WF_RFCR_DROP_BCAST BIT(6) #define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7) #define MT_WF_RFCR_DROP_A3_MAC BIT(8) #define MT_WF_RFCR_DROP_A3_BSSID BIT(9) #define MT_WF_RFCR_DROP_A2_BSSID BIT(10) #define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11) #define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12) #define MT_WF_RFCR_DROP_CTL_RSV BIT(13) #define MT_WF_RFCR_DROP_CTS BIT(14) #define MT_WF_RFCR_DROP_RTS BIT(15) #define MT_WF_RFCR_DROP_DUPLICATE BIT(16) #define MT_WF_RFCR_DROP_OTHER_BSS BIT(17) #define MT_WF_RFCR_DROP_OTHER_UC BIT(18) #define MT_WF_RFCR_DROP_OTHER_TIM BIT(19) #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) #define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004) #define MT_WF_RFCR1_DROP_ACK BIT(4) #define MT_WF_RFCR1_DROP_BF_POLL BIT(5) #define MT_WF_RFCR1_DROP_BA BIT(6) #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) #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_ED_OFFSET GENMASK(20, 16) #define MT_WF_RMAC_MIB_OBSS_BACKOFF GENMASK(15, 0) #define MT_WF_RMAC_MIB_AIRTIME1(_band) MT_WF_RMAC(_band, 0x0384) #define MT_WF_RMAC_MIB_NONQOSD_BACKOFF GENMASK(31, 16) #define MT_WF_RMAC_MIB_AIRTIME3(_band) MT_WF_RMAC(_band, 0x038c) #define MT_WF_RMAC_MIB_QOS01_BACKOFF GENMASK(31, 0) #define MT_WF_RMAC_MIB_AIRTIME4(_band) MT_WF_RMAC(_band, 0x0390) #define MT_WF_RMAC_MIB_QOS23_BACKOFF GENMASK(31, 0) #define MT_WF_RMAC_RSVD0(_band) MT_WF_RMAC(_band, 0x03e0) #define MT_WF_RMAC_RSVD0_EIFS_CLR BIT(21) /* RATE: band 0(0x820ee000), band 1(0x820fe000), band 2(0x830ee000) */ #define MT_WF_RATE_BASE(_band) __BASE(WF_RATE_BASE, (_band)) #define MT_WF_RATE(_band, ofs) (MT_WF_RATE_BASE(_band) + (ofs)) #define MT_RATE_HRCR0(_band) MT_WF_RATE(_band, 0x050) #define MT_RATE_HRCR0_CFEND_RATE GENMASK(14, 0) /* WFDMA0 */ #define MT_WFDMA0_BASE 0xd4000 #define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs)) #define MT_WFDMA0_RST MT_WFDMA0(0x100) #define MT_WFDMA0_RST_LOGIC_RST BIT(4) #define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5) #define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c) #define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) +#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) -#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) -#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_GLO_CFG_EXT_EN BIT(26) +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) +#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) + +#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268) +#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c) +#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270) +#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c) #define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18) #define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE BIT(14) #define WF_WFDMA0_GLO_CFG_EXT1 MT_WFDMA0(0x2b4) #define WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE BIT(31) #define WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE BIT(28) #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) #define MT_WFDMA0_PRI_DLY_INT_CFG1 MT_WFDMA0(0x2f4) #define MT_WFDMA0_PRI_DLY_INT_CFG2 MT_WFDMA0(0x2f8) /* WFDMA1 */ #define MT_WFDMA1_BASE 0xd5000 /* WFDMA CSR */ #define MT_WFDMA_EXT_CSR_BASE 0xd7000 #define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs)) #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) +#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) +#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500) +#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0) + #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) /* WFDMA0 PCIE1 */ #define MT_WFDMA0_PCIE1_BASE 0xd8000 #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) +#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118) +#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c) + #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO BIT(2) /* WFDMA COMMON */ #define __RXQ(q) ((q) + __MT_MCUQ_MAX) #define __TXQ(q) (__RXQ(q) + __MT_RXQ_MAX) #define MT_Q_ID(q) (dev->q_id[(q)]) #define MT_Q_BASE(q) ((dev->q_wfdma_mask >> (q)) & 0x1 ? \ MT_WFDMA1_BASE : MT_WFDMA0_BASE) #define MT_MCUQ_ID(q) MT_Q_ID(q) #define MT_TXQ_ID(q) MT_Q_ID(__TXQ(q)) #define MT_RXQ_ID(q) MT_Q_ID(__RXQ(q)) #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) +#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) #define MT_RXQ_BAND1_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ MT_RXQ_ID(q) * 0x4) #define MT_TXQ_EXT_CTRL(q) (MT_Q_BASE(__TXQ(q)) + 0x600 + \ MT_TXQ_ID(q) * 0x4) #define MT_INT_SOURCE_CSR MT_WFDMA0(0x200) #define MT_INT_MASK_CSR MT_WFDMA0(0x204) #define MT_INT1_SOURCE_CSR MT_WFDMA0_PCIE1(0x200) #define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204) #define MT_INT_RX_DONE_BAND0 BIT(12) -#define MT_INT_RX_DONE_BAND1 BIT(12) +#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */ #define MT_INT_RX_DONE_BAND2 BIT(13) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) #define MT_INT_RX_DONE_WA_MAIN BIT(2) -#define MT_INT_RX_DONE_WA_EXT BIT(2) +#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */ #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) +#define MT_INT_RX_DONE_BAND2_EXT BIT(23) +#define MT_INT_RX_TXFREE_EXT BIT(26) #define MT_INT_MCU_CMD BIT(29) +#define MT_INT_RX_DONE_RRO_BAND0 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND2 BIT(14) +#define MT_INT_RX_DONE_RRO_IND BIT(11) +#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) +#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) +#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) + #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) #define MT_INT_RX_DONE_MCU (MT_INT_RX(MT_RXQ_MCU) | \ MT_INT_RX(MT_RXQ_MCU_WA)) #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ MT_INT_RX(MT_RXQ_BAND1_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \ MT_INT_RX(MT_RXQ_BAND2_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) + +#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ + MT_INT_RX(MT_RXQ_RRO_BAND1) | \ + MT_INT_RX(MT_RXQ_RRO_BAND2) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ MT_INT_BAND0_RX_DONE | \ MT_INT_BAND1_RX_DONE | \ - MT_INT_BAND2_RX_DONE) + MT_INT_BAND2_RX_DONE | \ + MT_INT_RRO_RX_DONE) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) #define MT_INT_TX_DONE_MCU_WA BIT(22) #define MT_INT_TX_DONE_BAND0 BIT(30) #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_BAND2 BIT(15) +#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \ + MT_INT_RX_DONE_BAND2_EXT | \ + MT_INT_RX_TXFREE_EXT) + #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ MT_INT_TX_MCU(MT_MCUQ_FWDL)) #define MT_MCU_CMD MT_WFDMA0(0x1f0) #define MT_MCU_CMD_STOP_DMA BIT(2) #define MT_MCU_CMD_RESET_DONE BIT(3) #define MT_MCU_CMD_RECOVERY_DONE BIT(4) #define MT_MCU_CMD_NORMAL_STATE BIT(5) #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) #define MT_MCU_CMD_WA_WDT BIT(31) #define MT_MCU_CMD_WM_WDT BIT(30) #define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) /* l1/l2 remap */ #define MT_HIF_REMAP_L1 0x155024 #define MT_HIF_REMAP_L1_MASK GENMASK(31, 16) #define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) #define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) #define MT_HIF_REMAP_BASE_L1 0x130000 #define MT_HIF_REMAP_L2 0x1b4 #define MT_HIF_REMAP_L2_MASK GENMASK(19, 0) #define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0) #define MT_HIF_REMAP_L2_BASE GENMASK(31, 12) #define MT_HIF_REMAP_BASE_L2 0x1000 #define MT_INFRA_BASE 0x18000000 #define MT_WFSYS0_PHY_START 0x18400000 #define MT_WFSYS1_PHY_START 0x18800000 #define MT_WFSYS1_PHY_END 0x18bfffff #define MT_CBTOP1_PHY_START 0x70000000 #define MT_CBTOP1_PHY_END 0x77ffffff #define MT_CBTOP2_PHY_START 0xf0000000 #define MT_INFRA_MCU_START 0x7c000000 #define MT_INFRA_MCU_END 0x7c3fffff /* FW MODE SYNC */ #define MT_FW_ASSERT_CNT 0x02208274 #define MT_FW_DUMP_STATE 0x02209e90 #define MT_SWDEF_BASE 0x00401400 #define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs)) #define MT_SWDEF_MODE MT_SWDEF(0x3c) #define MT_SWDEF_NORMAL_MODE 0 #define MT_SWDEF_SER_STATS MT_SWDEF(0x040) #define MT_SWDEF_PLE_STATS MT_SWDEF(0x044) #define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048) #define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04c) #define MT_SWDEF_PSE_STATS MT_SWDEF(0x050) #define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054) #define MT_SWDEF_LAMC_WISR6_BN0_STATS MT_SWDEF(0x058) #define MT_SWDEF_LAMC_WISR6_BN1_STATS MT_SWDEF(0x05c) #define MT_SWDEF_LAMC_WISR6_BN2_STATS MT_SWDEF(0x060) #define MT_SWDEF_LAMC_WISR7_BN0_STATS MT_SWDEF(0x064) #define MT_SWDEF_LAMC_WISR7_BN1_STATS MT_SWDEF(0x068) #define MT_SWDEF_LAMC_WISR7_BN2_STATS MT_SWDEF(0x06c) /* LED */ #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_BAND_SEL BIT(4) #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)) /* CONN DBG */ #define MT_CONN_DBG_CTL_BASE 0x18023000 #define MT_CONN_DBG_CTL(ofs) (MT_CONN_DBG_CTL_BASE + (ofs)) #define MT_CONN_DBG_CTL_OUT_SEL MT_CONN_DBG_CTL(0x604) #define MT_CONN_DBG_CTL_PC_LOG_SEL MT_CONN_DBG_CTL(0x60c) #define MT_CONN_DBG_CTL_PC_LOG MT_CONN_DBG_CTL(0x610) #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) /* MT TOP */ #define MT_TOP_BASE 0xe0000 #define MT_TOP(ofs) (MT_TOP_BASE + (ofs)) #define MT_TOP_LPCR_HOST_BAND(_band) MT_TOP(0x10 + ((_band) * 0x10)) #define MT_TOP_LPCR_HOST_FW_OWN BIT(0) #define MT_TOP_LPCR_HOST_DRV_OWN BIT(1) #define MT_TOP_LPCR_HOST_FW_OWN_STAT BIT(2) #define MT_TOP_LPCR_HOST_BAND_IRQ_STAT(_band) MT_TOP(0x14 + ((_band) * 0x10)) #define MT_TOP_LPCR_HOST_BAND_STAT BIT(0) #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +/* ADIE */ +#define MT_ADIE_CHIP_ID(_idx) (0x0f00002c + ((_idx) << 28)) +#define MT_ADIE_VERSION_MASK GENMASK(15, 0) +#define MT_ADIE_CHIP_ID_MASK GENMASK(31, 16) + +#define MT_PAD_GPIO 0x700056f0 +#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15) +#define MT_PAD_GPIO_2ADIE_TBTC BIT(19) +/* for mt7992 */ +#define MT_PAD_GPIO_ADIE_COMB_7992 GENMASK(17, 16) +#define MT_PAD_GPIO_ADIE_SINGLE BIT(15) + #define MT_HW_REV 0x70010204 +#define MT_HW_REV1 0x8a00 + #define MT_WF_SUBSYS_RST 0x70028600 /* PCIE MAC */ #define MT_PCIE_MAC_BASE 0x74030000 #define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) #define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) #define MT_PCIE1_MAC_BASE 0x74090000 #define MT_PCIE1_MAC(ofs) (MT_PCIE1_MAC_BASE + (ofs)) #define MT_PCIE1_MAC_INT_ENABLE MT_PCIE1_MAC(0x188) /* PHYRX CSD */ #define MT_WF_PHYRX_CSD_BASE 0x83000000 #define MT_WF_PHYRX_CSD(_band, _wf, ofs) (MT_WF_PHYRX_CSD_BASE + \ ((_band) << 20) + \ ((_wf) << 16) + (ofs)) #define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000) /* PHYRX CTRL */ #define MT_WF_PHYRX_BAND_BASE 0x83080000 #define MT_WF_PHYRX_BAND(_band, ofs) (MT_WF_PHYRX_BAND_BASE + \ ((_band) << 20) + (ofs)) #define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHYRX_BAND(_band, 0x1054) #define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHYRX_BAND(_band, 0x1058) #define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHYRX_BAND(_band, 0x105c) #define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHYRX_BAND(_band, 0x1060) #define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHYRX_BAND(_band, 0x1064) #define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHYRX_BAND(_band, 0x1068) #define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHYRX_BAND(_band, 0x2004) #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN GENMASK(2, 0) #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN GENMASK(11, 9) /* PHYRX CSD BAND */ #define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHYRX_BAND(_band, 0x8230) #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18) #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR BIT(29) /* CONN MCU EXCP CON */ #define MT_MCU_WM_EXCP_BASE 0x89050000 #define MT_MCU_WM_EXCP(ofs) (MT_MCU_WM_EXCP_BASE + (ofs)) #define MT_MCU_WM_EXCP_PC_CTRL MT_MCU_WM_EXCP(0x100) #define MT_MCU_WM_EXCP_PC_LOG MT_MCU_WM_EXCP(0x104) #define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200) #define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204) +/* CONN AFE CTL CON */ +#define MT_AFE_CTL_BASE 0x18043000 +#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \ + ((_band) * 0x1000) + (ofs)) +#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c) +#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1) + #endif diff --git a/sys/contrib/dev/mediatek/mt76/pci.c b/sys/contrib/dev/mediatek/mt76/pci.c index 4c1c159fbb62..b5031ca7f73f 100644 --- a/sys/contrib/dev/mediatek/mt76/pci.c +++ b/sys/contrib/dev/mediatek/mt76/pci.c @@ -1,47 +1,70 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2019 Lorenzo Bianconi */ #include "mt76.h" #include void mt76_pci_disable_aspm(struct pci_dev *pdev) { struct pci_dev *parent = pdev->bus->self; u16 aspm_conf, parent_aspm_conf = 0; pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); aspm_conf &= PCI_EXP_LNKCTL_ASPMC; if (parent) { pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_aspm_conf); parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; } if (!aspm_conf && (!parent || !parent_aspm_conf)) { /* aspm already disabled */ return; } dev_info(&pdev->dev, "disabling ASPM %s %s\n", (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); if (IS_ENABLED(CONFIG_PCIEASPM)) { int err; err = pci_disable_link_state(pdev, aspm_conf); if (!err) return; } /* both device and parent should have the same ASPM setting. * disable ASPM in downstream component first and then upstream. */ pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf); if (parent) pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, aspm_conf); } EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm); + +bool mt76_pci_aspm_supported(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + u16 aspm_conf, parent_aspm_conf = 0; + bool result = true; + + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); + aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + if (parent) { + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, + &parent_aspm_conf); + parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + } + + if (!aspm_conf && (!parent || !parent_aspm_conf)) { + /* aspm already disabled */ + result = false; + } + + return result; +} +EXPORT_SYMBOL_GPL(mt76_pci_aspm_supported); diff --git a/sys/contrib/dev/mediatek/mt76/scan.c b/sys/contrib/dev/mediatek/mt76/scan.c new file mode 100644 index 000000000000..1c4f9deaaada --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/scan.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2024 Felix Fietkau + */ +#include "mt76.h" + +static void mt76_scan_complete(struct mt76_dev *dev, bool abort) +{ + struct mt76_phy *phy = dev->scan.phy; + struct cfg80211_scan_info info = { + .aborted = abort, + }; + + if (!phy) + return; + + clear_bit(MT76_SCANNING, &phy->state); + + if (dev->scan.chan && phy->main_chandef.chan) + mt76_set_channel(phy, &phy->main_chandef, false); + mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); + memset(&dev->scan, 0, sizeof(dev->scan)); + ieee80211_scan_completed(phy->hw, &info); +} + +void mt76_abort_scan(struct mt76_dev *dev) +{ + cancel_delayed_work_sync(&dev->scan_work); + mt76_scan_complete(dev, true); +} + +static void +mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) +{ + struct cfg80211_scan_request *req = dev->scan.req; + struct ieee80211_vif *vif = dev->scan.vif; + struct mt76_vif_link *mvif = dev->scan.mlink; + enum nl80211_band band = dev->scan.chan->band; + struct mt76_phy *phy = dev->scan.phy; + struct ieee80211_tx_info *info; + struct sk_buff *skb; + + skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid, + ssid->ssid_len, req->ie_len); + if (!skb) + return; + + if (is_unicast_ether_addr(req->bssid)) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + ether_addr_copy(hdr->addr1, req->bssid); + ether_addr_copy(hdr->addr3, req->bssid); + } + + info = IEEE80211_SKB_CB(skb); + if (req->no_cck) + info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; + info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK; + + if (req->ie_len) + skb_put_data(skb, req->ie, req->ie_len); + + skb->priority = 7; + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + + rcu_read_lock(); + if (ieee80211_tx_prepare_skb(phy->hw, vif, skb, band, NULL)) + mt76_tx(phy, NULL, mvif->wcid, skb); + else + ieee80211_free_txskb(phy->hw, skb); + rcu_read_unlock(); +} + +void mt76_scan_work(struct work_struct *work) +{ + struct mt76_dev *dev = container_of(work, struct mt76_dev, + scan_work.work); + struct cfg80211_scan_request *req = dev->scan.req; + struct cfg80211_chan_def chandef = {}; + struct mt76_phy *phy = dev->scan.phy; + int duration = HZ / 9; /* ~110 ms */ + int i; + + if (dev->scan.chan_idx >= req->n_channels) { + mt76_scan_complete(dev, false); + return; + } + + if (dev->scan.chan && phy->num_sta) { + dev->scan.chan = NULL; + mt76_set_channel(phy, &phy->main_chandef, false); + goto out; + } + + dev->scan.chan = req->channels[dev->scan.chan_idx++]; + cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); + mt76_set_channel(phy, &chandef, true); + + if (!req->n_ssids || + chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) + goto out; + + duration = HZ / 16; /* ~60 ms */ + local_bh_disable(); + for (i = 0; i < req->n_ssids; i++) + mt76_scan_send_probe(dev, &req->ssids[i]); + local_bh_enable(); + +out: + if (!duration) + return; + + if (dev->scan.chan) + duration = max_t(int, duration, + msecs_to_jiffies(req->duration + + (req->duration >> 5))); + + ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration); +} + +int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_vif_link *mlink; + int ret = 0; + + if (hw->wiphy->n_radio > 1) { + phy = dev->band_phys[req->req.channels[0]->band]; + if (!phy) + return -EINVAL; + } + + mutex_lock(&dev->mutex); + + if (dev->scan.req || phy->roc_vif) { + ret = -EBUSY; + goto out; + } + + mlink = mt76_get_vif_phy_link(phy, vif); + if (IS_ERR(mlink)) { + ret = PTR_ERR(mlink); + goto out; + } + + memset(&dev->scan, 0, sizeof(dev->scan)); + dev->scan.req = &req->req; + dev->scan.vif = vif; + dev->scan.phy = phy; + dev->scan.mlink = mlink; + ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_hw_scan); + +void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_phy *phy = hw->priv; + + mt76_abort_scan(phy->dev); +} +EXPORT_SYMBOL_GPL(mt76_cancel_hw_scan); diff --git a/sys/contrib/dev/mediatek/mt76/sdio.c b/sys/contrib/dev/mediatek/mt76/sdio.c index 419723118ded..8e9576747052 100644 --- a/sys/contrib/dev/mediatek/mt76/sdio.c +++ b/sys/contrib/dev/mediatek/mt76/sdio.c @@ -1,671 +1,681 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * This file is written based on mt76/usb.c. * * Author: Felix Fietkau * Lorenzo Bianconi * Sean Wang */ #include #include #include #include #include #include #include #include #include "mt76.h" #include "sdio.h" 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]; spin_lock_init(&q->lock); q->entry = devm_kcalloc(dev->dev, MT76S_NUM_RX_ENTRIES, sizeof(*q->entry), GFP_KERNEL); if (!q->entry) return -ENOMEM; q->ndesc = MT76S_NUM_RX_ENTRIES; q->head = q->tail = 0; q->queued = 0; return 0; } EXPORT_SYMBOL_GPL(mt76s_alloc_rx_queue); static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev) { struct mt76_queue *q; q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL); if (!q) return ERR_PTR(-ENOMEM); spin_lock_init(&q->lock); q->entry = devm_kcalloc(dev->dev, MT76S_NUM_TX_ENTRIES, sizeof(*q->entry), GFP_KERNEL); if (!q->entry) return ERR_PTR(-ENOMEM); q->ndesc = MT76S_NUM_TX_ENTRIES; return q; } int mt76s_alloc_tx(struct mt76_dev *dev) { struct mt76_queue *q; int i; for (i = 0; i <= MT_TXQ_PSD; i++) { q = mt76s_alloc_tx_queue(dev); if (IS_ERR(q)) return PTR_ERR(q); dev->phy.q_tx[i] = q; } q = mt76s_alloc_tx_queue(dev); if (IS_ERR(q)) return PTR_ERR(q); dev->q_mcu[MT_MCUQ_WM] = q; return 0; } EXPORT_SYMBOL_GPL(mt76s_alloc_tx); static struct mt76_queue_entry * mt76s_get_next_rx_entry(struct mt76_queue *q) { struct mt76_queue_entry *e = NULL; spin_lock_bh(&q->lock); if (q->queued > 0) { e = &q->entry[q->tail]; q->tail = (q->tail + 1) % q->ndesc; q->queued--; } spin_unlock_bh(&q->lock); return e; } static int mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) { int qid = q - &dev->q_rx[MT_RXQ_MAIN]; int nframes = 0; while (true) { struct mt76_queue_entry *e; if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state)) break; e = mt76s_get_next_rx_entry(q); if (!e || !e->skb) break; dev->drv->rx_skb(dev, MT_RXQ_MAIN, e->skb, NULL); e->skb = NULL; nframes++; } if (qid == MT_RXQ_MAIN) mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL); return nframes; } static void mt76s_net_worker(struct mt76_worker *w) { struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, net_worker); struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); int i, nframes; do { nframes = 0; local_bh_disable(); rcu_read_lock(); mt76_for_each_q_rx(dev, i) nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); local_bh_enable(); } while (nframes > 0); } static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) { struct mt76_queue_entry entry; int nframes = 0; bool mcu; if (!q) return 0; mcu = q == dev->q_mcu[MT_MCUQ_WM]; while (q->queued > 0) { if (!q->entry[q->tail].done) break; entry = q->entry[q->tail]; q->entry[q->tail].done = false; if (mcu) { dev_kfree_skb(entry.skb); entry.skb = NULL; } mt76_queue_tx_complete(dev, q, &entry); nframes++; } if (!q->queued) wake_up(&dev->tx_wait); return nframes; } static void mt76s_status_worker(struct mt76_worker *w) { struct mt76_sdio *sdio = container_of(w, struct mt76_sdio, status_worker); struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); bool resched = false; int i, nframes; do { int ndata_frames = 0; nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]); for (i = 0; i <= MT_TXQ_PSD; i++) ndata_frames += mt76s_process_tx_queue(dev, dev->phy.q_tx[i]); nframes += ndata_frames; if (ndata_frames > 0) resched = true; if (dev->drv->tx_status_data && ndata_frames > 0 && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state) && !test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &dev->sdio.stat_work); + mt76_worker_schedule(&sdio->stat_worker); } while (nframes > 0); if (resched) mt76_worker_schedule(&dev->tx_worker); } -static void mt76s_tx_status_data(struct work_struct *work) +static void mt76s_tx_status_data(struct mt76_worker *worker) { struct mt76_sdio *sdio; struct mt76_dev *dev; u8 update = 1; u16 count = 0; - sdio = container_of(work, struct mt76_sdio, stat_work); + sdio = container_of(worker, struct mt76_sdio, stat_worker); dev = container_of(sdio, struct mt76_dev, sdio); while (true) { - if (test_bit(MT76_REMOVED, &dev->phy.state)) + if (test_bit(MT76_RESET, &dev->phy.state) || + test_bit(MT76_REMOVED, &dev->phy.state)) break; if (!dev->drv->tx_status_data(dev, &update)) break; count++; } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &sdio->stat_work); + mt76_worker_schedule(&sdio->status_worker); else clear_bit(MT76_READING_STATS, &dev->phy.state); } static int -mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, +mt76s_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct mt76_tx_info tx_info = { .skb = skb, }; + struct mt76_dev *dev = phy->dev; int err, len = skb->len; u16 idx = q->head; if (q->queued == q->ndesc) return -ENOSPC; skb->prev = skb->next = NULL; err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) return err; q->entry[q->head].skb = tx_info.skb; q->entry[q->head].buf_sz = len; q->entry[q->head].wcid = 0xffff; smp_wmb(); q->head = (q->head + 1) % q->ndesc; q->queued++; return idx; } static int mt76s_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q, struct sk_buff *skb, u32 tx_info) { - int ret = -ENOSPC, len = skb->len, pad; - - if (q->queued == q->ndesc) - goto error; + int ret, len = skb->len, pad; pad = round_up(skb->len, 4) - skb->len; ret = mt76_skb_adjust_pad(skb, pad); if (ret) goto error; spin_lock_bh(&q->lock); + if (q->queued == q->ndesc) { + ret = -ENOSPC; + spin_unlock_bh(&q->lock); + goto error; + } + q->entry[q->head].buf_sz = len; q->entry[q->head].skb = skb; /* ensure the entry fully updated before bus access */ smp_wmb(); q->head = (q->head + 1) % q->ndesc; q->queued++; spin_unlock_bh(&q->lock); return 0; error: dev_kfree_skb(skb); return ret; } static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) { struct mt76_sdio *sdio = &dev->sdio; mt76_worker_schedule(&sdio->txrx_worker); } static const struct mt76_queue_ops sdio_queue_ops = { .tx_queue_skb = mt76s_tx_queue_skb, .kick = mt76s_tx_kick, .tx_queue_skb_raw = mt76s_tx_queue_skb_raw, }; void mt76s_deinit(struct mt76_dev *dev) { struct mt76_sdio *sdio = &dev->sdio; int i; mt76_worker_teardown(&sdio->txrx_worker); mt76_worker_teardown(&sdio->status_worker); mt76_worker_teardown(&sdio->net_worker); + mt76_worker_teardown(&sdio->stat_worker); - cancel_work_sync(&sdio->stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); mt76_tx_status_check(dev, true); sdio_claim_host(sdio->func); sdio_release_irq(sdio->func); sdio_release_host(sdio->func); mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; int j; for (j = 0; j < q->ndesc; j++) { struct mt76_queue_entry *e = &q->entry[j]; if (!e->skb) continue; dev_kfree_skb(e->skb); e->skb = NULL; } } } EXPORT_SYMBOL_GPL(mt76s_deinit); int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, const struct mt76_bus_ops *bus_ops) { struct mt76_sdio *sdio = &dev->sdio; u32 host_max_cap; int err; err = mt76_worker_setup(dev->hw, &sdio->status_worker, mt76s_status_worker, "sdio-status"); if (err) return err; err = mt76_worker_setup(dev->hw, &sdio->net_worker, mt76s_net_worker, "sdio-net"); if (err) return err; + err = mt76_worker_setup(dev->hw, &sdio->stat_worker, mt76s_tx_status_data, + "sdio-sta"); + if (err) + return err; + sched_set_fifo_low(sdio->status_worker.task); sched_set_fifo_low(sdio->net_worker.task); - - INIT_WORK(&sdio->stat_work, mt76s_tx_status_data); + sched_set_fifo_low(sdio->stat_worker.task); dev->queue_ops = &sdio_queue_ops; dev->bus = bus_ops; dev->sdio.func = func; host_max_cap = min_t(u32, func->card->host->max_req_size, func->cur_blksize * func->card->host->max_blk_count); dev->sdio.xmit_buf_sz = min_t(u32, host_max_cap, MT76S_XMIT_BUF_SZ); dev->sdio.xmit_buf = devm_kmalloc(dev->dev, dev->sdio.xmit_buf_sz, GFP_KERNEL); if (!dev->sdio.xmit_buf) err = -ENOMEM; return err; } EXPORT_SYMBOL_GPL(mt76s_init); MODULE_AUTHOR("Sean Wang "); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT76x SDIO helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/sdio_txrx.c b/sys/contrib/dev/mediatek/mt76/sdio_txrx.c index ddd8c0cc744d..0a927a7313a6 100644 --- a/sys/contrib/dev/mediatek/mt76/sdio_txrx.c +++ b/sys/contrib/dev/mediatek/mt76/sdio_txrx.c @@ -1,384 +1,388 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 MediaTek Inc. * * Author: Felix Fietkau * Lorenzo Bianconi * Sean Wang */ #include #include #include #include #include #include #include "trace.h" #include "sdio.h" #include "mt76.h" 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 */ FIELD_GET(TXQ_CNT_H, data[3]), /* VI */ FIELD_GET(TXQ_CNT_L, data[3]), /* BE */ FIELD_GET(TXQ_CNT_H, data[2]), /* BK */ }; u32 pse_ac_data_quota[] = { FIELD_GET(TXQ_CNT_H, data[1]), /* VO */ FIELD_GET(TXQ_CNT_L, data[1]), /* VI */ FIELD_GET(TXQ_CNT_H, data[0]), /* BE */ FIELD_GET(TXQ_CNT_L, data[0]), /* BK */ }; u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]); u32 pse_data_quota = 0, ple_data_quota = 0; struct mt76_sdio *sdio = &dev->sdio; int i; for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) { pse_data_quota += pse_ac_data_quota[i]; ple_data_quota += ple_ac_data_quota[i]; } if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota) return 0; sdio->sched.pse_mcu_quota += pse_mcu_quota; + if (sdio->pse_mcu_quota_max && + sdio->sched.pse_mcu_quota > sdio->pse_mcu_quota_max) { + sdio->sched.pse_mcu_quota = sdio->pse_mcu_quota_max; + } sdio->sched.pse_data_quota += pse_data_quota; sdio->sched.ple_data_quota += ple_data_quota; return pse_data_quota + ple_data_quota + pse_mcu_quota; } 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; skb = alloc_skb(len, GFP_KERNEL); if (!skb) return NULL; skb_put_data(skb, data, len); if (data_len > len) { struct page *page; data += len; page = virt_to_head_page(data); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, data - page_address(page), data_len - len, buf_len); get_page(page); } return skb; } 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; int len = 0, err, i; struct page *page; u8 *buf, *end; for (i = 0; i < intr->rx.num[qid]; i++) len += round_up(intr->rx.len[qid][i] + 4, 4); if (!len) return 0; if (len > sdio->func->cur_blksize) len = roundup(len, sdio->func->cur_blksize); page = __dev_alloc_pages(GFP_KERNEL, get_order(len)); if (!page) return -ENOMEM; buf = page_address(page); sdio_claim_host(sdio->func); err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); sdio_release_host(sdio->func); if (err < 0) { dev_err(dev->dev, "sdio read data failed:%d\n", err); put_page(page); return err; } end = buf + len; i = 0; while (i < intr->rx.num[qid] && buf < end) { int index = (q->head + i) % q->ndesc; struct mt76_queue_entry *e = &q->entry[index]; __le32 *rxd = (__le32 *)buf; /* parse rxd to get the actual packet length */ len = le32_get_bits(rxd[0], GENMASK(15, 0)); /* Optimized path for TXS */ if (!dev->drv->rx_check || dev->drv->rx_check(dev, buf, len)) { e->skb = mt76s_build_rx_skb(buf, len, round_up(len + 4, 4)); if (!e->skb) break; if (q->queued + i + 1 == q->ndesc) break; i++; } buf += round_up(len + 4, 4); } put_page(page); spin_lock_bh(&q->lock); q->head = (q->head + i) % q->ndesc; q->queued += i; spin_unlock_bh(&q->lock); return i; } static int mt76s_rx_handler(struct mt76_dev *dev) { struct mt76_sdio *sdio = &dev->sdio; struct mt76s_intr intr; int nframes = 0, ret; ret = sdio->parse_irq(dev, &intr); if (ret) return ret; trace_dev_irq(dev, intr.isr, 0); 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 = mt76s_rx_run_queue(dev, 1, &intr); if (ret > 0) { mt76_worker_schedule(&sdio->net_worker); nframes += ret; } } nframes += !!mt76s_refill_sched_quota(dev, intr.tx.wtqcr); return nframes; } 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, 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) return -EBUSY; } else { if (sdio->sched.pse_data_quota < *pse_size + pse_sz || sdio->sched.ple_data_quota < *ple_size + 1) return -EBUSY; *ple_size = *ple_size + 1; } *pse_size = *pse_size + pse_sz; return 0; } 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; } else { sdio->sched.pse_data_quota -= pse_size; sdio->sched.ple_data_quota -= ple_size; } } static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) { struct mt76_sdio *sdio = &dev->sdio; int err; if (len > sdio->func->cur_blksize) len = roundup(len, sdio->func->cur_blksize); sdio_claim_host(sdio->func); err = sdio_writesb(sdio->func, MCR_WTDR1, data, len); sdio_release_host(sdio->func); if (err) dev_err(dev->dev, "sdio write failed: %d\n", err); return err; } static int mt76s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q) { int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0; bool mcu = q == dev->q_mcu[MT_MCUQ_WM]; struct mt76_sdio *sdio = &dev->sdio; u8 pad; while (q->first != q->head) { struct mt76_queue_entry *e = &q->entry[q->first]; struct sk_buff *iter; 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 = __skb_grow(e->skb, roundup(e->skb->len, sdio->func->cur_blksize)); if (err) return err; err = __mt76s_xmit_queue(dev, e->skb->data, e->skb->len); if (err) return err; goto next; } pad = roundup(e->skb->len, 4) - e->skb->len; if (len + e->skb->len + pad + 4 > dev->sdio.xmit_buf_sz) break; if (mt76s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz, &ple_sz)) break; memcpy(sdio->xmit_buf + len, e->skb->data, skb_headlen(e->skb)); len += skb_headlen(e->skb); nframes++; skb_walk_frags(e->skb, iter) { memcpy(sdio->xmit_buf + len, iter->data, iter->len); len += iter->len; nframes++; } if (unlikely(pad)) { memset(sdio->xmit_buf + len, 0, pad); len += pad; } next: q->first = (q->first + 1) % q->ndesc; e->done = true; } if (nframes) { memset(sdio->xmit_buf + len, 0, 4); err = __mt76s_xmit_queue(dev, sdio->xmit_buf, len + 4); if (err) return err; } mt76s_tx_update_quota(sdio, mcu, pse_sz, ple_sz); mt76_worker_schedule(&sdio->status_worker); return nframes; } void mt76s_txrx_worker(struct mt76_sdio *sdio) { struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio); int i, nframes, ret; /* disable interrupt */ sdio_claim_host(sdio->func); sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); sdio_release_host(sdio->func); do { nframes = 0; /* tx */ for (i = 0; i <= MT_TXQ_PSD; i++) { ret = mt76s_tx_run_queue(dev, dev->phy.q_tx[i]); if (ret > 0) nframes += ret; } ret = mt76s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]); if (ret > 0) nframes += ret; /* rx */ ret = mt76s_rx_handler(dev); if (ret > 0) nframes += ret; if (test_bit(MT76_MCU_RESET, &dev->phy.state) || test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) { if (!mt76s_txqs_empty(dev)) continue; else wake_up(&sdio->wait); } } while (nframes > 0); /* enable interrupt */ sdio_claim_host(sdio->func); sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL); sdio_release_host(sdio->func); } EXPORT_SYMBOL_GPL(mt76s_txrx_worker); void mt76s_sdio_irq(struct sdio_func *func) { struct mt76_dev *dev = sdio_get_drvdata(func); struct mt76_sdio *sdio = &dev->sdio; if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state) || test_bit(MT76_MCU_RESET, &dev->phy.state)) return; sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL); 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); diff --git a/sys/contrib/dev/mediatek/mt76/testmode.c b/sys/contrib/dev/mediatek/mt76/testmode.c index 4644dace9bb3..ca4feccf38ca 100644 --- a/sys/contrib/dev/mediatek/mt76/testmode.c +++ b/sys/contrib/dev/mediatek/mt76/testmode.c @@ -1,676 +1,676 @@ // SPDX-License-Identifier: ISC /* Copyright (C) 2020 Felix Fietkau */ #include #include "mt76.h" 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 }, [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 }, [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED }, [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 }, [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 }, [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 }, [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, [MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED }, }; EXPORT_SYMBOL_GPL(mt76_tm_policy); void mt76_testmode_tx_pending(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; struct mt76_dev *dev = phy->dev; struct mt76_wcid *wcid = &dev->global_wcid; struct sk_buff *skb = td->tx_skb; struct mt76_queue *q; u16 tx_queued_limit; int qid; if (!skb || !td->tx_pending) return; qid = skb_get_queue_mapping(skb); q = phy->q_tx[qid]; tx_queued_limit = td->tx_queued_limit ? td->tx_queued_limit : 1000; spin_lock_bh(&q->lock); while (td->tx_pending > 0 && td->tx_queued - td->tx_done < tx_queued_limit && q->queued < q->ndesc / 2) { int ret; - ret = dev->queue_ops->tx_queue_skb(dev, q, qid, skb_get(skb), + ret = dev->queue_ops->tx_queue_skb(phy, q, qid, skb_get(skb), wcid, NULL); if (ret < 0) break; td->tx_pending--; td->tx_queued++; } dev->queue_ops->kick(dev, q); spin_unlock_bh(&q->lock); } static u32 mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode) { switch (tx_rate_mode) { case MT76_TM_TX_MODE_HT: return IEEE80211_MAX_MPDU_LEN_HT_7935; case MT76_TM_TX_MODE_VHT: case MT76_TM_TX_MODE_HE_SU: case MT76_TM_TX_MODE_HE_EXT_SU: case MT76_TM_TX_MODE_HE_TB: case MT76_TM_TX_MODE_HE_MU: if (phy->sband_5g.sband.vht_cap.cap & IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991) return IEEE80211_MAX_MPDU_LEN_VHT_7991; return IEEE80211_MAX_MPDU_LEN_VHT_11454; case MT76_TM_TX_MODE_CCK: case MT76_TM_TX_MODE_OFDM: default: return IEEE80211_MAX_FRAME_LEN; } } static void mt76_testmode_free_skb(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; dev_kfree_skb(td->tx_skb); td->tx_skb = NULL; } int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) { #define MT_TXP_MAX_LEN 4095 u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS; struct mt76_testmode_data *td = &phy->test; struct sk_buff **frag_tail, *head; struct ieee80211_tx_info *info; struct ieee80211_hdr *hdr; u32 max_len, head_len; int nfrags, i; max_len = mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode); if (len > max_len) len = max_len; else if (len < sizeof(struct ieee80211_hdr)) len = sizeof(struct ieee80211_hdr); nfrags = len / MT_TXP_MAX_LEN; head_len = nfrags ? MT_TXP_MAX_LEN : len; if (len > IEEE80211_MAX_FRAME_LEN) fc |= IEEE80211_STYPE_QOS_DATA; head = alloc_skb(head_len, GFP_KERNEL); if (!head) return -ENOMEM; hdr = __skb_put_zero(head, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(fc); memcpy(hdr->addr1, td->addr[0], ETH_ALEN); memcpy(hdr->addr2, td->addr[1], ETH_ALEN); memcpy(hdr->addr3, td->addr[2], ETH_ALEN); skb_set_queue_mapping(head, IEEE80211_AC_BE); get_random_bytes(__skb_put(head, head_len - sizeof(*hdr)), head_len - sizeof(*hdr)); info = IEEE80211_SKB_CB(head); info->flags = IEEE80211_TX_CTL_INJECTED | IEEE80211_TX_CTL_NO_ACK | IEEE80211_TX_CTL_NO_PS_BUFFER; info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); frag_tail = &skb_shinfo(head)->frag_list; for (i = 0; i < nfrags; i++) { struct sk_buff *frag; u16 frag_len; if (i == nfrags - 1) frag_len = len % MT_TXP_MAX_LEN; else frag_len = MT_TXP_MAX_LEN; frag = alloc_skb(frag_len, GFP_KERNEL); if (!frag) { mt76_testmode_free_skb(phy); dev_kfree_skb(head); return -ENOMEM; } get_random_bytes(__skb_put(frag, frag_len), frag_len); head->len += frag->len; head->data_len += frag->len; *frag_tail = frag; frag_tail = &(*frag_tail)->next; } mt76_testmode_free_skb(phy); td->tx_skb = head; return 0; } EXPORT_SYMBOL(mt76_testmode_alloc_skb); static int mt76_testmode_tx_init(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; struct ieee80211_tx_info *info; struct ieee80211_tx_rate *rate; u8 max_nss = hweight8(phy->antenna_mask); int ret; ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len); if (ret) return ret; if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT) goto out; if (td->tx_antenna_mask) max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask)); info = IEEE80211_SKB_CB(td->tx_skb); rate = &info->control.rates[0]; rate->count = 1; rate->idx = td->tx_rate_idx; switch (td->tx_rate_mode) { case MT76_TM_TX_MODE_CCK: if (phy->chandef.chan->band != NL80211_BAND_2GHZ) return -EINVAL; if (rate->idx > 4) return -EINVAL; break; case MT76_TM_TX_MODE_OFDM: if (phy->chandef.chan->band != NL80211_BAND_2GHZ) break; if (rate->idx > 8) return -EINVAL; rate->idx += 4; break; case MT76_TM_TX_MODE_HT: if (rate->idx > 8 * max_nss && !(rate->idx == 32 && phy->chandef.width >= NL80211_CHAN_WIDTH_40)) return -EINVAL; rate->flags |= IEEE80211_TX_RC_MCS; break; case MT76_TM_TX_MODE_VHT: if (rate->idx > 9) return -EINVAL; if (td->tx_rate_nss > max_nss) return -EINVAL; ieee80211_rate_set_vht(rate, td->tx_rate_idx, td->tx_rate_nss); rate->flags |= IEEE80211_TX_RC_VHT_MCS; break; default: break; } if (td->tx_rate_sgi) rate->flags |= IEEE80211_TX_RC_SHORT_GI; if (td->tx_rate_ldpc) info->flags |= IEEE80211_TX_CTL_LDPC; if (td->tx_rate_stbc) info->flags |= IEEE80211_TX_CTL_STBC; if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) { switch (phy->chandef.width) { case NL80211_CHAN_WIDTH_40: rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; break; case NL80211_CHAN_WIDTH_80: rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; break; case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_160: rate->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; break; default: break; } } out: return 0; } static void mt76_testmode_tx_start(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; struct mt76_dev *dev = phy->dev; td->tx_queued = 0; td->tx_done = 0; td->tx_pending = td->tx_count; mt76_worker_schedule(&dev->tx_worker); } static void mt76_testmode_tx_stop(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; struct mt76_dev *dev = phy->dev; mt76_worker_disable(&dev->tx_worker); td->tx_pending = 0; mt76_worker_enable(&dev->tx_worker); wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, MT76_TM_TIMEOUT * HZ); mt76_testmode_free_skb(phy); } static inline void mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx) { td->param_set[idx / 32] |= BIT(idx % 32); } static inline bool mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx) { return td->param_set[idx / 32] & BIT(idx % 32); } static void mt76_testmode_init_defaults(struct mt76_phy *phy) { struct mt76_testmode_data *td = &phy->test; if (td->tx_mpdu_len > 0) return; td->tx_mpdu_len = 1024; td->tx_count = 1; td->tx_rate_mode = MT76_TM_TX_MODE_OFDM; td->tx_rate_nss = 1; memcpy(td->addr[0], phy->macaddr, ETH_ALEN); memcpy(td->addr[1], phy->macaddr, ETH_ALEN); memcpy(td->addr[2], phy->macaddr, ETH_ALEN); } static int __mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state) { enum mt76_testmode_state prev_state = phy->test.state; struct mt76_dev *dev = phy->dev; int err; if (prev_state == MT76_TM_STATE_TX_FRAMES) mt76_testmode_tx_stop(phy); if (state == MT76_TM_STATE_TX_FRAMES) { err = mt76_testmode_tx_init(phy); if (err) return err; } err = dev->test_ops->set_state(phy, state); if (err) { if (state == MT76_TM_STATE_TX_FRAMES) mt76_testmode_tx_stop(phy); return err; } if (state == MT76_TM_STATE_TX_FRAMES) mt76_testmode_tx_start(phy); else if (state == MT76_TM_STATE_RX_FRAMES) { memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats)); } phy->test.state = state; return 0; } int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state) { struct mt76_testmode_data *td = &phy->test; struct ieee80211_hw *hw = phy->hw; if (state == td->state && state == MT76_TM_STATE_OFF) return 0; if (state > MT76_TM_STATE_OFF && (!test_bit(MT76_STATE_RUNNING, &phy->state) || !(hw->conf.flags & IEEE80211_CONF_MONITOR))) return -ENOTCONN; if (state != MT76_TM_STATE_IDLE && td->state != MT76_TM_STATE_IDLE) { int ret; ret = __mt76_testmode_set_state(phy, MT76_TM_STATE_IDLE); if (ret) return ret; } return __mt76_testmode_set_state(phy, state); } EXPORT_SYMBOL(mt76_testmode_set_state); static int mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max) { u8 val; if (!attr) return 0; val = nla_get_u8(attr); if (val < min || val > max) return -EINVAL; *dest = val; return 0; } int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct mt76_testmode_data *td = &phy->test; struct nlattr *tb[NUM_MT76_TM_ATTRS]; u32 state; int err; int i; if (!dev->test_ops) return -EOPNOTSUPP; err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, mt76_tm_policy, NULL); if (err) return err; err = -EINVAL; mutex_lock(&dev->mutex); if (tb[MT76_TM_ATTR_RESET]) { mt76_testmode_set_state(phy, MT76_TM_STATE_OFF); memset(td, 0, sizeof(*td)); } mt76_testmode_init_defaults(phy); if (tb[MT76_TM_ATTR_TX_COUNT]) td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]); if (tb[MT76_TM_ATTR_TX_RATE_IDX]) td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]); if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode, 0, MT76_TM_TX_MODE_MAX) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss, 1, hweight8(phy->antenna_mask)) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 2) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 0, 0xff) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_SPE_IDX], &td->tx_spe_idx, 0, 27) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE], &td->tx_duty_cycle, 0, 99) || mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL], &td->tx_power_control, 0, 1)) goto out; if (tb[MT76_TM_ATTR_TX_LENGTH]) { u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]); if (val > mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode) || val < sizeof(struct ieee80211_hdr)) goto out; td->tx_mpdu_len = val; } if (tb[MT76_TM_ATTR_TX_IPG]) td->tx_ipg = nla_get_u32(tb[MT76_TM_ATTR_TX_IPG]); if (tb[MT76_TM_ATTR_TX_TIME]) td->tx_time = nla_get_u32(tb[MT76_TM_ATTR_TX_TIME]); if (tb[MT76_TM_ATTR_FREQ_OFFSET]) td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]); if (tb[MT76_TM_ATTR_STATE]) { state = nla_get_u32(tb[MT76_TM_ATTR_STATE]); if (state > MT76_TM_STATE_MAX) goto out; } else { state = td->state; } if (tb[MT76_TM_ATTR_TX_POWER]) { struct nlattr *cur; int idx = 0; int rem; nla_for_each_nested(cur, tb[MT76_TM_ATTR_TX_POWER], rem) { if (nla_len(cur) != 1 || idx >= ARRAY_SIZE(td->tx_power)) goto out; td->tx_power[idx++] = nla_get_u8(cur); } } if (tb[MT76_TM_ATTR_MAC_ADDRS]) { struct nlattr *cur; int idx = 0; int rem; nla_for_each_nested(cur, tb[MT76_TM_ATTR_MAC_ADDRS], rem) { if (nla_len(cur) != ETH_ALEN || idx >= 3) goto out; memcpy(td->addr[idx], nla_data(cur), ETH_ALEN); idx++; } } if (dev->test_ops->set_params) { err = dev->test_ops->set_params(phy, tb, state); if (err) goto out; } for (i = MT76_TM_ATTR_STATE; i < ARRAY_SIZE(tb); i++) if (tb[i]) mt76_testmode_param_set(td, i); err = 0; if (tb[MT76_TM_ATTR_STATE]) err = mt76_testmode_set_state(phy, state); out: mutex_unlock(&dev->mutex); return err; } EXPORT_SYMBOL(mt76_testmode_cmd); static int mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) { struct mt76_testmode_data *td = &phy->test; struct mt76_dev *dev = phy->dev; u64 rx_packets = 0; u64 rx_fcs_error = 0; int i; if (dev->test_ops->dump_stats) { int ret; ret = dev->test_ops->dump_stats(phy, msg); if (ret) return ret; } for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) { rx_packets += td->rx_stats.packets[i]; rx_fcs_error += td->rx_stats.fcs_error[i]; } if (nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_PENDING, td->tx_pending) || nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_QUEUED, td->tx_queued) || nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_DONE, td->tx_done) || nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets, MT76_TM_STATS_ATTR_PAD) || nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error, MT76_TM_STATS_ATTR_PAD)) return -EMSGSIZE; return 0; } int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, struct netlink_callback *cb, void *data, int len) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct mt76_testmode_data *td = &phy->test; struct nlattr *tb[NUM_MT76_TM_ATTRS] = {}; int err = 0; void *a; int i; if (!dev->test_ops) return -EOPNOTSUPP; if (cb->args[2]++ > 0) return -ENOENT; if (data) { err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, mt76_tm_policy, NULL); if (err) return err; } mutex_lock(&dev->mutex); if (tb[MT76_TM_ATTR_STATS]) { err = -EINVAL; a = nla_nest_start(msg, MT76_TM_ATTR_STATS); if (a) { err = mt76_testmode_dump_stats(phy, msg); nla_nest_end(msg, a); } goto out; } mt76_testmode_init_defaults(phy); err = -EMSGSIZE; if (nla_put_u32(msg, MT76_TM_ATTR_STATE, td->state)) goto out; if (dev->test_mtd.name && (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) || nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset))) goto out; if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) || nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_mpdu_len) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) || nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) && nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) && nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_SPE_IDX) && nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX, td->tx_spe_idx)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_DUTY_CYCLE) && nla_put_u8(msg, MT76_TM_ATTR_TX_DUTY_CYCLE, td->tx_duty_cycle)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_IPG) && nla_put_u32(msg, MT76_TM_ATTR_TX_IPG, td->tx_ipg)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME) && nla_put_u32(msg, MT76_TM_ATTR_TX_TIME, td->tx_time)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) && nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) || (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) && nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset))) goto out; if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) { a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER); if (!a) goto out; for (i = 0; i < ARRAY_SIZE(td->tx_power); i++) if (nla_put_u8(msg, i, td->tx_power[i])) goto out; nla_nest_end(msg, a); } if (mt76_testmode_param_present(td, MT76_TM_ATTR_MAC_ADDRS)) { a = nla_nest_start(msg, MT76_TM_ATTR_MAC_ADDRS); if (!a) goto out; for (i = 0; i < 3; i++) if (nla_put(msg, i, ETH_ALEN, td->addr[i])) goto out; nla_nest_end(msg, a); } err = 0; out: mutex_unlock(&dev->mutex); return err; } EXPORT_SYMBOL(mt76_testmode_dump); diff --git a/sys/contrib/dev/mediatek/mt76/tx.c b/sys/contrib/dev/mediatek/mt76/tx.c index 6cc26cc6c517..af0c50c983ec 100644 --- a/sys/contrib/dev/mediatek/mt76/tx.c +++ b/sys/contrib/dev/mediatek/mt76/tx.c @@ -1,835 +1,926 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include "mt76.h" static int mt76_txq_get_qid(struct ieee80211_txq *txq) { if (!txq->sta) return MT_TXQ_BE; return txq->ac; } void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_txq *txq; struct mt76_txq *mtxq; u8 tid; if (!sta || !ieee80211_is_data_qos(hdr->frame_control) || !ieee80211_is_data_present(hdr->frame_control)) return; tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; txq = sta->txq[tid]; mtxq = (struct mt76_txq *)txq->drv_priv; if (!mtxq->aggr) return; mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10; } 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_lock) { __skb_queue_head_init(list); 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_lock) { struct ieee80211_hw *hw; struct sk_buff *skb; spin_unlock_bh(&dev->status_lock); rcu_read_lock(); while ((skb = __skb_dequeue(list)) != NULL) { struct ieee80211_tx_status status = { .skb = skb, .info = IEEE80211_SKB_CB(skb), }; struct ieee80211_rate_status rs = {}; struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); struct mt76_wcid *wcid; wcid = rcu_dereference(dev->wcid[cb->wcid]); if (wcid) { status.sta = wcid_to_sta(wcid); if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) { rs.rate_idx = wcid->rate; status.rates = &rs; status.n_rates = 1; } else { status.n_rates = 0; } } hw = mt76_tx_status_get_hw(dev, skb); spin_lock_bh(&dev->rx_lock); ieee80211_tx_status_ext(hw, &status); spin_unlock_bh(&dev->rx_lock); } rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_tx_status_unlock); static void __mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, u8 flags, struct sk_buff_head *list) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); u8 done = MT_TX_CB_DMA_DONE | MT_TX_CB_TXS_DONE; flags |= cb->flags; cb->flags = flags; if ((flags & done) != done) return; /* 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; info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; } __skb_queue_tail(list, skb); } void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb, struct sk_buff_head *list) { __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_DONE, list); } EXPORT_SYMBOL_GPL(mt76_tx_status_skb_done); int mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb); int pid; memset(cb, 0, sizeof(*cb)); if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx])) return MT_PACKET_ID_NO_ACK; if (info->flags & IEEE80211_TX_CTL_NO_ACK) return MT_PACKET_ID_NO_ACK; if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | IEEE80211_TX_CTL_RATE_CTRL_PROBE))) { if (mtk_wed_device_active(&dev->mmio.wed) && ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) || ieee80211_is_data(hdr->frame_control))) return MT_PACKET_ID_WED; return MT_PACKET_ID_NO_SKB; } 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; } cb->wcid = wcid->idx; cb->pktid = pid; if (list_empty(&wcid->list)) list_add_tail(&wcid->list, &dev->wcid_list); out: spin_unlock_bh(&dev->status_lock); return pid; } EXPORT_SYMBOL_GPL(mt76_tx_status_skb_add); 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; int id; 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 (pktid >= 0) { if (!(cb->flags & MT_TX_CB_DMA_DONE)) 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); } 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, bool flush) { struct mt76_wcid *wcid, *tmp; struct sk_buff_head list; mt76_tx_status_lock(dev, &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); static void mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int pending; if (!wcid || info->tx_time_est) return; pending = atomic_dec_return(&wcid->non_aql_packets); if (pending < 0) atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); } 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, }; struct mt76_wcid *wcid = NULL; struct ieee80211_hw *hw; struct sk_buff_head list; rcu_read_lock(); if (wcid_idx < ARRAY_SIZE(dev->wcid)) wcid = rcu_dereference(dev->wcid[wcid_idx]); mt76_tx_check_non_aql(dev, wcid, skb); #ifdef CONFIG_NL80211_TESTMODE if (mt76_is_testmode_skb(dev, skb, &hw)) { struct mt76_phy *phy = hw->priv; if (skb == phy->test.tx_skb) phy->test.tx_done++; if (phy->test.tx_queued == phy->test.tx_done) wake_up(&dev->tx_wait); dev_kfree_skb_any(skb); goto out; } #endif if (cb->pktid < MT_PACKET_ID_FIRST) { struct ieee80211_rate_status rs = {}; hw = mt76_tx_status_get_hw(dev, skb); status.sta = wcid_to_sta(wcid); if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) { rs.rate_idx = wcid->rate; status.rates = &rs; status.n_rates = 1; } spin_lock_bh(&dev->rx_lock); ieee80211_tx_status_ext(hw, &status); spin_unlock_bh(&dev->rx_lock); goto out; } 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); out: rcu_read_unlock(); } EXPORT_SYMBOL_GPL(__mt76_tx_complete_skb); static int __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, bool *stop) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct mt76_queue *q = phy->q_tx[qid]; struct mt76_dev *dev = phy->dev; bool non_aql; int pending; int idx; non_aql = !info->tx_time_est; - idx = dev->queue_ops->tx_queue_skb(dev, q, qid, skb, wcid, sta); + idx = dev->queue_ops->tx_queue_skb(phy, q, qid, skb, wcid, sta); if (idx < 0 || !sta) return idx; wcid = (struct mt76_wcid *)sta->drv_priv; + if (!wcid->sta) + return idx; + q->entry[idx].wcid = wcid->idx; if (!non_aql) return idx; pending = atomic_inc_return(&wcid->non_aql_packets); if (stop && pending >= MT_MAX_NON_AQL_PKT) *stop = true; return idx; } void mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { - struct mt76_dev *dev = phy->dev; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct mt76_queue *q; - int qid = skb_get_queue_mapping(skb); + struct sk_buff_head *head; if (mt76_testmode_enabled(phy)) { ieee80211_free_txskb(phy->hw, skb); return; } - if (WARN_ON(qid >= MT_TXQ_PSD)) { - qid = MT_TXQ_BE; - skb_set_queue_mapping(skb, qid); - } - - if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && - !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && - !ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_bufferable_mmpdu(skb)) { - qid = MT_TXQ_PSD; - } + if (WARN_ON(skb_get_queue_mapping(skb) >= MT_TXQ_PSD)) + skb_set_queue_mapping(skb, MT_TXQ_BE); if (wcid && !(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(info->control.vif, sta, skb, info->control.rates, 1); info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); - q = phy->q_tx[qid]; - spin_lock_bh(&q->lock); - __mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL); - dev->queue_ops->kick(dev, q); - spin_unlock_bh(&q->lock); + if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || + (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) + head = &wcid->tx_offchannel; + else + head = &wcid->tx_pending; + + spin_lock_bh(&head->lock); + __skb_queue_tail(head, skb); + spin_unlock_bh(&head->lock); + + spin_lock_bh(&phy->tx_lock); + if (list_empty(&wcid->tx_list)) + list_add_tail(&wcid->tx_list, &phy->tx_list); + spin_unlock_bh(&phy->tx_lock); + + mt76_worker_schedule(&phy->dev->tx_worker); } EXPORT_SYMBOL_GPL(mt76_tx); static struct sk_buff * mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); struct ieee80211_tx_info *info; struct sk_buff *skb; skb = ieee80211_tx_dequeue(phy->hw, txq); if (!skb) return NULL; info = IEEE80211_SKB_CB(skb); info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); return skb; } static void mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta, struct sk_buff *skb, bool last) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; if (last) info->flags |= IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; mt76_skb_set_moredata(skb, !last); __mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL); } void mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct sk_buff *last_skb = NULL; struct mt76_queue *hwq = phy->q_tx[MT_TXQ_PSD]; int i; spin_lock_bh(&hwq->lock); for (i = 0; tids && nframes; i++, tids >>= 1) { struct ieee80211_txq *txq = sta->txq[i]; struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv; struct sk_buff *skb; if (!(tids & 1)) continue; do { skb = mt76_txq_dequeue(phy, mtxq); if (!skb) break; nframes--; if (last_skb) mt76_queue_ps_skb(phy, sta, last_skb, false); last_skb = skb; } while (nframes); } if (last_skb) { mt76_queue_ps_skb(phy, sta, last_skb, true); dev->queue_ops->kick(dev, hwq); } else { ieee80211_sta_eosp(sta); } spin_unlock_bh(&hwq->lock); } EXPORT_SYMBOL_GPL(mt76_release_buffered_frames); static bool mt76_txq_stopped(struct mt76_queue *q) { return q->stopped || q->blocked || q->queued + MT_TXQ_FREE_THR >= q->ndesc; } static int mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, struct mt76_txq *mtxq, struct mt76_wcid *wcid) { struct mt76_dev *dev = phy->dev; struct ieee80211_txq *txq = mtxq_to_txq(mtxq); enum mt76_txq_id qid = mt76_txq_get_qid(txq); struct ieee80211_tx_info *info; struct sk_buff *skb; int n_frames = 1; bool stop = false; int idx; if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) return 0; if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) return 0; skb = mt76_txq_dequeue(phy, mtxq); if (!skb) return 0; info = IEEE80211_SKB_CB(skb); if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(txq->vif, txq->sta, skb, info->control.rates, 1); spin_lock(&q->lock); idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop); spin_unlock(&q->lock); if (idx < 0) return idx; do { - if (test_bit(MT76_RESET, &phy->state)) - return -EBUSY; + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + break; if (stop || mt76_txq_stopped(q)) break; skb = mt76_txq_dequeue(phy, mtxq); if (!skb) break; info = IEEE80211_SKB_CB(skb); if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) ieee80211_get_tx_rates(txq->vif, txq->sta, skb, info->control.rates, 1); spin_lock(&q->lock); idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop); spin_unlock(&q->lock); if (idx < 0) break; n_frames++; } while (1); spin_lock(&q->lock); dev->queue_ops->kick(dev, q); spin_unlock(&q->lock); return n_frames; } static int mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) { - struct mt76_queue *q = phy->q_tx[qid]; struct mt76_dev *dev = phy->dev; struct ieee80211_txq *txq; struct mt76_txq *mtxq; struct mt76_wcid *wcid; + struct mt76_queue *q; int ret = 0; while (1) { int n_frames = 0; - if (test_bit(MT76_RESET, &phy->state)) - return -EBUSY; - - if (dev->queue_ops->tx_cleanup && - q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { - dev->queue_ops->tx_cleanup(dev, q, false); - } - txq = ieee80211_next_txq(phy->hw, qid); if (!txq) break; mtxq = (struct mt76_txq *)txq->drv_priv; wcid = rcu_dereference(dev->wcid[mtxq->wcid]); if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) continue; + phy = mt76_dev_phy(dev, wcid->phy_idx); + if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) + continue; + + q = phy->q_tx[qid]; + if (dev->queue_ops->tx_cleanup && + q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { + dev->queue_ops->tx_cleanup(dev, q, false); + } + if (mtxq->send_bar && mtxq->aggr) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); struct ieee80211_sta *sta = txq->sta; struct ieee80211_vif *vif = txq->vif; u16 agg_ssn = mtxq->agg_ssn; u8 tid = txq->tid; mtxq->send_bar = false; ieee80211_send_bar(vif, sta->addr, tid, agg_ssn); } if (!mt76_txq_stopped(q)) n_frames = mt76_txq_send_burst(phy, q, mtxq, wcid); ieee80211_return_txq(phy->hw, txq, false); if (unlikely(n_frames < 0)) return n_frames; ret += n_frames; } return ret; } void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid) { int len; if (qid >= 4) return; local_bh_disable(); rcu_read_lock(); do { ieee80211_txq_schedule_start(phy->hw, qid); len = mt76_txq_schedule_list(phy, qid); ieee80211_txq_schedule_end(phy->hw, qid); } while (len > 0); rcu_read_unlock(); local_bh_enable(); } EXPORT_SYMBOL_GPL(mt76_txq_schedule); +static int +mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, + struct sk_buff_head *head) +{ + struct mt76_dev *dev = phy->dev; + struct ieee80211_sta *sta; + struct mt76_queue *q; + struct sk_buff *skb; + int ret = 0; + + spin_lock(&head->lock); + while ((skb = skb_peek(head)) != NULL) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + int qid = skb_get_queue_mapping(skb); + + if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && + !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + !ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_bufferable_mmpdu(skb)) + qid = MT_TXQ_PSD; + + q = phy->q_tx[qid]; + if (mt76_txq_stopped(q) || test_bit(MT76_RESET, &phy->state)) { + ret = -1; + break; + } + + __skb_unlink(skb, head); + spin_unlock(&head->lock); + + sta = wcid_to_sta(wcid); + spin_lock(&q->lock); + __mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL); + dev->queue_ops->kick(dev, q); + spin_unlock(&q->lock); + + spin_lock(&head->lock); + } + spin_unlock(&head->lock); + + return ret; +} + +static void mt76_txq_schedule_pending(struct mt76_phy *phy) +{ + LIST_HEAD(tx_list); + + if (list_empty(&phy->tx_list)) + return; + + local_bh_disable(); + rcu_read_lock(); + + spin_lock(&phy->tx_lock); + list_splice_init(&phy->tx_list, &tx_list); + while (!list_empty(&tx_list)) { + struct mt76_wcid *wcid; + int ret; + + wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list); + list_del_init(&wcid->tx_list); + + spin_unlock(&phy->tx_lock); + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); + if (ret >= 0 && !phy->offchannel) + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); + spin_lock(&phy->tx_lock); + + if (!skb_queue_empty(&wcid->tx_pending) && + !skb_queue_empty(&wcid->tx_offchannel) && + list_empty(&wcid->tx_list)) + list_add_tail(&wcid->tx_list, &phy->tx_list); + + if (ret < 0) + break; + } + spin_unlock(&phy->tx_lock); + + rcu_read_unlock(); + local_bh_enable(); +} + void mt76_txq_schedule_all(struct mt76_phy *phy) { + struct mt76_phy *main_phy = &phy->dev->phy; int i; + mt76_txq_schedule_pending(phy); + + if (phy != main_phy && phy->hw == main_phy->hw) + return; + for (i = 0; i <= MT_TXQ_BK; i++) mt76_txq_schedule(phy, i); } EXPORT_SYMBOL_GPL(mt76_txq_schedule_all); void mt76_tx_worker_run(struct mt76_dev *dev) { struct mt76_phy *phy; int i; + mt76_txq_schedule_all(&dev->phy); for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { phy = dev->phys[i]; if (!phy) continue; mt76_txq_schedule_all(phy); } #ifdef CONFIG_NL80211_TESTMODE for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { phy = dev->phys[i]; if (!phy || !phy->test.tx_pending) continue; mt76_testmode_tx_pending(phy); } #endif } EXPORT_SYMBOL_GPL(mt76_tx_worker_run); void mt76_tx_worker(struct mt76_worker *w) { struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker); mt76_tx_worker_run(dev); } void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, bool send_bar) { int i; for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { struct ieee80211_txq *txq = sta->txq[i]; struct mt76_queue *hwq; struct mt76_txq *mtxq; if (!txq) continue; hwq = phy->q_tx[mt76_txq_get_qid(txq)]; mtxq = (struct mt76_txq *)txq->drv_priv; spin_lock_bh(&hwq->lock); mtxq->send_bar = mtxq->aggr && send_bar; spin_unlock_bh(&hwq->lock); } } EXPORT_SYMBOL_GPL(mt76_stop_tx_queues); void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; - if (!test_bit(MT76_STATE_RUNNING, &phy->state)) - return; - mt76_worker_schedule(&dev->tx_worker); } EXPORT_SYMBOL_GPL(mt76_wake_tx_queue); u8 mt76_ac_to_hwq(u8 ac) { static const u8 wmm_queue_map[] = { [IEEE80211_AC_BE] = 0, [IEEE80211_AC_BK] = 1, [IEEE80211_AC_VI] = 2, [IEEE80211_AC_VO] = 3, }; if (WARN_ON(ac >= IEEE80211_NUM_ACS)) return 0; return wmm_queue_map[ac]; } EXPORT_SYMBOL_GPL(mt76_ac_to_hwq); int mt76_skb_adjust_pad(struct sk_buff *skb, int pad) { struct sk_buff *iter, *last = skb; /* First packet of a A-MSDU burst keeps track of the whole burst * length, need to update length of it and the last packet. */ skb_walk_frags(skb, iter) { last = iter; if (!iter->next) { skb->data_len += pad; skb->len += pad; break; } } if (skb_pad(last, pad)) return -ENOMEM; __skb_put(last, pad); return 0; } EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad); void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *e) { if (e->skb) dev->drv->tx_complete_skb(dev, e); spin_lock_bh(&q->lock); q->tail = (q->tail + 1) % q->ndesc; q->queued--; spin_unlock_bh(&q->lock); } EXPORT_SYMBOL_GPL(mt76_queue_tx_complete); void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked) { struct mt76_phy *phy = &dev->phy; struct mt76_queue *q = phy->q_tx[0]; if (blocked == q->blocked) return; q->blocked = blocked; phy = dev->phys[MT_BAND1]; if (phy) { q = phy->q_tx[0]; q->blocked = blocked; } phy = dev->phys[MT_BAND2]; if (phy) { q = phy->q_tx[0]; q->blocked = blocked; } if (!blocked) mt76_worker_schedule(&dev->tx_worker); } EXPORT_SYMBOL_GPL(__mt76_set_tx_blocked); int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi) { int token; spin_lock_bh(&dev->token_lock); token = idr_alloc(&dev->token, *ptxwi, 0, dev->token_size, GFP_ATOMIC); if (token >= 0) dev->token_count++; #ifdef CONFIG_NET_MEDIATEK_SOC_WED if (mtk_wed_device_active(&dev->mmio.wed) && token >= dev->mmio.wed.wlan.token_start) dev->wed_token_count++; #endif if (dev->token_count >= dev->token_size - MT76_TOKEN_FREE_THR) __mt76_set_tx_blocked(dev, true); spin_unlock_bh(&dev->token_lock); return token; } EXPORT_SYMBOL_GPL(mt76_token_consume); int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr, struct mt76_txwi_cache *t, dma_addr_t phys) { int token; spin_lock_bh(&dev->rx_token_lock); token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size, GFP_ATOMIC); if (token >= 0) { t->ptr = ptr; t->dma_addr = phys; } spin_unlock_bh(&dev->rx_token_lock); return token; } EXPORT_SYMBOL_GPL(mt76_rx_token_consume); struct mt76_txwi_cache * mt76_token_release(struct mt76_dev *dev, int token, bool *wake) { struct mt76_txwi_cache *txwi; spin_lock_bh(&dev->token_lock); txwi = idr_remove(&dev->token, token); if (txwi) { dev->token_count--; #ifdef CONFIG_NET_MEDIATEK_SOC_WED if (mtk_wed_device_active(&dev->mmio.wed) && token >= dev->mmio.wed.wlan.token_start && --dev->wed_token_count == 0) wake_up(&dev->tx_wait); #endif } if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR && dev->phy.q_tx[0]->blocked) *wake = true; spin_unlock_bh(&dev->token_lock); return txwi; } EXPORT_SYMBOL_GPL(mt76_token_release); struct mt76_txwi_cache * mt76_rx_token_release(struct mt76_dev *dev, int token) { struct mt76_txwi_cache *t; spin_lock_bh(&dev->rx_token_lock); t = idr_remove(&dev->rx_token, token); spin_unlock_bh(&dev->rx_token_lock); return t; } EXPORT_SYMBOL_GPL(mt76_rx_token_release); diff --git a/sys/contrib/dev/mediatek/mt76/usb.c b/sys/contrib/dev/mediatek/mt76/usb.c index 5e5c7bf51174..f9e67b8c3b3c 100644 --- a/sys/contrib/dev/mediatek/mt76/usb.c +++ b/sys/contrib/dev/mediatek/mt76/usb.c @@ -1,1132 +1,1139 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi */ #include #include "mt76.h" #include "usb_trace.h" #include "dma.h" #define MT_VEND_REQ_MAX_RETRY 10 #define MT_VEND_REQ_TOUT_MS 300 static bool disable_usb_sg; module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644); MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support"); int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) { struct usb_interface *uintf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; int i, ret; lockdep_assert_held(&dev->usb.usb_ctrl_mtx); pipe = (req_type & USB_DIR_IN) ? usb_rcvctrlpipe(udev, 0) : usb_sndctrlpipe(udev, 0); for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { if (test_bit(MT76_REMOVED, &dev->phy.state)) return -EIO; ret = usb_control_msg(udev, pipe, req, req_type, val, offset, buf, len, MT_VEND_REQ_TOUT_MS); - if (ret == -ENODEV) + if (ret == -ENODEV || ret == -EPROTO) set_bit(MT76_REMOVED, &dev->phy.state); - if (ret >= 0 || ret == -ENODEV) + if (ret >= 0 || ret == -ENODEV || ret == -EPROTO) return ret; usleep_range(5000, 10000); } dev_err(dev->dev, "vendor request req:%02x off:%04x failed:%d\n", req, offset, ret); return ret; } EXPORT_SYMBOL_GPL(__mt76u_vendor_request); int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) { int ret; mutex_lock(&dev->usb.usb_ctrl_mtx); ret = __mt76u_vendor_request(dev, req, req_type, val, offset, buf, len); trace_usb_reg_wr(dev, offset, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); return ret; } EXPORT_SYMBOL_GPL(mt76u_vendor_request); u32 ___mt76u_rr(struct mt76_dev *dev, u8 req, u8 req_type, u32 addr) { struct mt76_usb *usb = &dev->usb; u32 data = ~0; int ret; ret = __mt76u_vendor_request(dev, req, req_type, addr >> 16, addr, usb->data, sizeof(__le32)); if (ret == sizeof(__le32)) data = get_unaligned_le32(usb->data); trace_usb_reg_rr(dev, addr, data); return data; } EXPORT_SYMBOL_GPL(___mt76u_rr); static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr) { u8 req; switch (addr & MT_VEND_TYPE_MASK) { case MT_VEND_TYPE_EEPROM: req = MT_VEND_READ_EEPROM; break; case MT_VEND_TYPE_CFG: req = MT_VEND_READ_CFG; break; default: req = MT_VEND_MULTI_READ; break; } return ___mt76u_rr(dev, req, USB_DIR_IN | USB_TYPE_VENDOR, addr & ~MT_VEND_TYPE_MASK); } static u32 mt76u_rr(struct mt76_dev *dev, u32 addr) { u32 ret; mutex_lock(&dev->usb.usb_ctrl_mtx); ret = __mt76u_rr(dev, addr); mutex_unlock(&dev->usb.usb_ctrl_mtx); return ret; } void ___mt76u_wr(struct mt76_dev *dev, u8 req, u8 req_type, u32 addr, u32 val) { struct mt76_usb *usb = &dev->usb; put_unaligned_le32(val, usb->data); __mt76u_vendor_request(dev, req, req_type, addr >> 16, addr, usb->data, sizeof(__le32)); trace_usb_reg_wr(dev, addr, val); } EXPORT_SYMBOL_GPL(___mt76u_wr); static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) { u8 req; switch (addr & MT_VEND_TYPE_MASK) { case MT_VEND_TYPE_CFG: req = MT_VEND_WRITE_CFG; break; default: req = MT_VEND_MULTI_WRITE; break; } ___mt76u_wr(dev, req, USB_DIR_OUT | USB_TYPE_VENDOR, addr & ~MT_VEND_TYPE_MASK, val); } static void mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); __mt76u_wr(dev, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); } static u32 mt76u_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); val |= __mt76u_rr(dev, addr) & ~mask; __mt76u_wr(dev, addr, val); mutex_unlock(&dev->usb.usb_ctrl_mtx); return val; } static void mt76u_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { struct mt76_usb *usb = &dev->usb; const u8 *val = data; int ret; int current_batch_size; int i = 0; /* Assure that always a multiple of 4 bytes are copied, * otherwise beacons can be corrupted. * See: "mt76: round up length on mt76_wr_copy" * Commit 850e8f6fbd5d0003b0 */ len = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); while (i < len) { current_batch_size = min_t(int, usb->data_len, len - i); memcpy(usb->data, val + i, current_batch_size); ret = __mt76u_vendor_request(dev, MT_VEND_MULTI_WRITE, USB_DIR_OUT | USB_TYPE_VENDOR, 0, offset + i, usb->data, current_batch_size); if (ret < 0) break; i += current_batch_size; } mutex_unlock(&usb->usb_ctrl_mtx); } void mt76u_read_copy(struct mt76_dev *dev, u32 offset, void *data, int len) { struct mt76_usb *usb = &dev->usb; int i = 0, batch_len, ret; u8 *val = data; len = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); while (i < len) { batch_len = min_t(int, usb->data_len, len - i); ret = __mt76u_vendor_request(dev, MT_VEND_READ_EXT, USB_DIR_IN | USB_TYPE_VENDOR, (offset + i) >> 16, offset + i, usb->data, batch_len); if (ret < 0) break; memcpy(val + i, usb->data, batch_len); i += batch_len; } mutex_unlock(&usb->usb_ctrl_mtx); } EXPORT_SYMBOL_GPL(mt76u_read_copy); void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val) { mutex_lock(&dev->usb.usb_ctrl_mtx); __mt76u_vendor_request(dev, req, USB_DIR_OUT | USB_TYPE_VENDOR, val & 0xffff, offset, NULL, 0); __mt76u_vendor_request(dev, req, USB_DIR_OUT | USB_TYPE_VENDOR, val >> 16, offset + 2, NULL, 0); mutex_unlock(&dev->usb.usb_ctrl_mtx); } EXPORT_SYMBOL_GPL(mt76u_single_wr); static int mt76u_req_wr_rp(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *data, int len) { struct mt76_usb *usb = &dev->usb; mutex_lock(&usb->usb_ctrl_mtx); while (len > 0) { __mt76u_wr(dev, base + data->reg, data->value); len--; data++; } mutex_unlock(&usb->usb_ctrl_mtx); return 0; } static int mt76u_wr_rp(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *data, int n) { if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) return dev->mcu_ops->mcu_wr_rp(dev, base, data, n); else return mt76u_req_wr_rp(dev, base, data, n); } static int mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, int len) { struct mt76_usb *usb = &dev->usb; mutex_lock(&usb->usb_ctrl_mtx); while (len > 0) { data->value = __mt76u_rr(dev, base + data->reg); len--; data++; } mutex_unlock(&usb->usb_ctrl_mtx); return 0; } static int mt76u_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data, int n) { if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) return dev->mcu_ops->mcu_rd_rp(dev, base, data, n); else return mt76u_req_rd_rp(dev, base, data, n); } static bool mt76u_check_sg(struct mt76_dev *dev) { struct usb_interface *uintf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(uintf); return (!disable_usb_sg && udev->bus->sg_tablesize > 0 && - (udev->bus->no_sg_constraint || - udev->speed == USB_SPEED_WIRELESS)); + udev->bus->no_sg_constraint); } static int mt76u_set_endpoints(struct usb_interface *intf, struct mt76_usb *usb) { struct usb_host_interface *intf_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *ep_desc; int i, in_ep = 0, out_ep = 0; for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { ep_desc = &intf_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_in(ep_desc) && in_ep < __MT_EP_IN_MAX) { usb->in_ep[in_ep] = usb_endpoint_num(ep_desc); in_ep++; } else if (usb_endpoint_is_bulk_out(ep_desc) && out_ep < __MT_EP_OUT_MAX) { usb->out_ep[out_ep] = usb_endpoint_num(ep_desc); out_ep++; } } if (in_ep != __MT_EP_IN_MAX || out_ep != __MT_EP_OUT_MAX) return -EINVAL; return 0; } static int mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb, int nsgs) { int i; for (i = 0; i < nsgs; i++) { void *data; int offset; data = mt76_get_page_pool_buf(q, &offset, q->buf_size); if (!data) break; sg_set_page(&urb->sg[i], virt_to_head_page(data), q->buf_size, offset); } if (i < nsgs) { int j; for (j = nsgs; j < urb->num_sgs; j++) mt76_put_page_pool_buf(sg_virt(&urb->sg[j]), false); urb->num_sgs = i; } urb->num_sgs = max_t(int, i, urb->num_sgs); urb->transfer_buffer_length = urb->num_sgs * q->buf_size; sg_init_marker(urb->sg, urb->num_sgs); return i ? : -ENOMEM; } static int mt76u_refill_rx(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb, int nsgs) { enum mt76_rxq_id qid = q - &dev->q_rx[MT_RXQ_MAIN]; int offset; if (qid == MT_RXQ_MAIN && dev->usb.sg_en) return mt76u_fill_rx_sg(dev, q, urb, nsgs); urb->transfer_buffer_length = q->buf_size; urb->transfer_buffer = mt76_get_page_pool_buf(q, &offset, q->buf_size); return urb->transfer_buffer ? 0 : -ENOMEM; } static int mt76u_urb_alloc(struct mt76_dev *dev, struct mt76_queue_entry *e, int sg_max_size) { unsigned int size = sizeof(struct urb); if (dev->usb.sg_en) size += sg_max_size * sizeof(struct scatterlist); e->urb = kzalloc(size, GFP_KERNEL); if (!e->urb) return -ENOMEM; usb_init_urb(e->urb); if (dev->usb.sg_en && sg_max_size > 0) e->urb->sg = (struct scatterlist *)(e->urb + 1); return 0; } static int mt76u_rx_urb_alloc(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *e) { enum mt76_rxq_id qid = q - &dev->q_rx[MT_RXQ_MAIN]; int err, sg_size; sg_size = qid == MT_RXQ_MAIN ? MT_RX_SG_MAX_SIZE : 0; err = mt76u_urb_alloc(dev, e, sg_size); if (err) return err; return mt76u_refill_rx(dev, q, e->urb, sg_size); } static void mt76u_urb_free(struct urb *urb) { int i; for (i = 0; i < urb->num_sgs; i++) mt76_put_page_pool_buf(sg_virt(&urb->sg[i]), false); if (urb->transfer_buffer) mt76_put_page_pool_buf(urb->transfer_buffer, false); usb_free_urb(urb); } static void mt76u_fill_bulk_urb(struct mt76_dev *dev, int dir, int index, struct urb *urb, usb_complete_t complete_fn, void *context) { struct usb_interface *uintf = to_usb_interface(dev->dev); struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; if (dir == USB_DIR_IN) pipe = usb_rcvbulkpipe(udev, dev->usb.in_ep[index]); else pipe = usb_sndbulkpipe(udev, dev->usb.out_ep[index]); urb->dev = udev; urb->pipe = pipe; urb->complete = complete_fn; urb->context = context; } static struct urb * mt76u_get_next_rx_entry(struct mt76_queue *q) { struct urb *urb = NULL; unsigned long flags; spin_lock_irqsave(&q->lock, flags); if (q->queued > 0) { urb = q->entry[q->tail].urb; q->tail = (q->tail + 1) % q->ndesc; q->queued--; } spin_unlock_irqrestore(&q->lock, flags); return urb; } static int mt76u_get_rx_entry_len(struct mt76_dev *dev, u8 *data, u32 data_len) { u16 dma_len, min_len; dma_len = get_unaligned_le16(data); if (dev->drv->drv_flags & MT_DRV_RX_DMA_HDR) return dma_len; min_len = MT_DMA_HDR_LEN + MT_RX_RXWI_LEN + MT_FCE_INFO_LEN; if (data_len < min_len || !dma_len || dma_len + MT_DMA_HDR_LEN > data_len || (dma_len & 0x3)) return -EINVAL; return dma_len; } static struct sk_buff * mt76u_build_rx_skb(struct mt76_dev *dev, void *data, int len, int buf_size) { int head_room, drv_flags = dev->drv->drv_flags; struct sk_buff *skb; head_room = drv_flags & MT_DRV_RX_DMA_HDR ? 0 : MT_DMA_HDR_LEN; if (SKB_WITH_OVERHEAD(buf_size) < head_room + len) { struct page *page; /* slow path, not enough space for data and * skb_shared_info */ skb = alloc_skb(MT_SKB_HEAD_LEN, GFP_ATOMIC); if (!skb) return NULL; skb_put_data(skb, data + head_room, MT_SKB_HEAD_LEN); data += head_room + MT_SKB_HEAD_LEN; page = virt_to_head_page(data); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, data - page_address(page), len - MT_SKB_HEAD_LEN, buf_size); return skb; } /* fast path */ skb = build_skb(data, buf_size); if (!skb) return NULL; skb_reserve(skb, head_room); __skb_put(skb, len); return skb; } static int mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb, int buf_size) { u8 *data = urb->num_sgs ? sg_virt(&urb->sg[0]) : urb->transfer_buffer; int data_len = urb->num_sgs ? urb->sg[0].length : urb->actual_length; int len, nsgs = 1, head_room, drv_flags = dev->drv->drv_flags; struct sk_buff *skb; if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state)) return 0; len = mt76u_get_rx_entry_len(dev, data, urb->actual_length); if (len < 0) return 0; head_room = drv_flags & MT_DRV_RX_DMA_HDR ? 0 : MT_DMA_HDR_LEN; data_len = min_t(int, len, data_len - head_room); if (len == data_len && dev->drv->rx_check && !dev->drv->rx_check(dev, data, data_len)) return 0; skb = mt76u_build_rx_skb(dev, data, data_len, buf_size); if (!skb) return 0; len -= data_len; while (len > 0 && nsgs < urb->num_sgs) { data_len = min_t(int, len, urb->sg[nsgs].length); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, sg_page(&urb->sg[nsgs]), urb->sg[nsgs].offset, data_len, buf_size); len -= data_len; nsgs++; } skb_mark_for_recycle(skb); dev->drv->rx_skb(dev, MT_RXQ_MAIN, skb, NULL); return nsgs; } static void mt76u_complete_rx(struct urb *urb) { struct mt76_dev *dev = dev_get_drvdata(&urb->dev->dev); struct mt76_queue *q = urb->context; unsigned long flags; trace_rx_urb(dev, urb); switch (urb->status) { case -ECONNRESET: case -ESHUTDOWN: case -ENOENT: case -EPROTO: return; default: dev_err_ratelimited(dev->dev, "rx urb failed: %d\n", urb->status); fallthrough; case 0: break; } spin_lock_irqsave(&q->lock, flags); if (WARN_ONCE(q->entry[q->head].urb != urb, "rx urb mismatch")) goto out; q->head = (q->head + 1) % q->ndesc; q->queued++; mt76_worker_schedule(&dev->usb.rx_worker); out: spin_unlock_irqrestore(&q->lock, flags); } static int mt76u_submit_rx_buf(struct mt76_dev *dev, enum mt76_rxq_id qid, struct urb *urb) { int ep = qid == MT_RXQ_MAIN ? MT_EP_IN_PKT_RX : MT_EP_IN_CMD_RESP; mt76u_fill_bulk_urb(dev, USB_DIR_IN, ep, urb, mt76u_complete_rx, &dev->q_rx[qid]); trace_submit_urb(dev, urb); return usb_submit_urb(urb, GFP_ATOMIC); } static void mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) { int qid = q - &dev->q_rx[MT_RXQ_MAIN]; struct urb *urb; int err, count; while (true) { urb = mt76u_get_next_rx_entry(q); if (!urb) break; count = mt76u_process_rx_entry(dev, urb, q->buf_size); if (count > 0) { err = mt76u_refill_rx(dev, q, urb, count); if (err < 0) break; } mt76u_submit_rx_buf(dev, qid, urb); } if (qid == MT_RXQ_MAIN) { local_bh_disable(); mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL); local_bh_enable(); } } static void mt76u_rx_worker(struct mt76_worker *w) { struct mt76_usb *usb = container_of(w, struct mt76_usb, rx_worker); struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb); int i; rcu_read_lock(); mt76_for_each_q_rx(dev, i) mt76u_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); } static int mt76u_submit_rx_buffers(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; unsigned long flags; int i, err = 0; spin_lock_irqsave(&q->lock, flags); for (i = 0; i < q->ndesc; i++) { err = mt76u_submit_rx_buf(dev, qid, q->entry[i].urb); if (err < 0) break; } q->head = q->tail = 0; q->queued = 0; spin_unlock_irqrestore(&q->lock, flags); return err; } static int mt76u_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; int i, err; err = mt76_create_page_pool(dev, q); if (err) return err; spin_lock_init(&q->lock); q->entry = devm_kcalloc(dev->dev, MT_NUM_RX_ENTRIES, sizeof(*q->entry), GFP_KERNEL); if (!q->entry) return -ENOMEM; q->ndesc = MT_NUM_RX_ENTRIES; q->buf_size = PAGE_SIZE; for (i = 0; i < q->ndesc; i++) { err = mt76u_rx_urb_alloc(dev, q, &q->entry[i]); if (err < 0) return err; } return mt76u_submit_rx_buffers(dev, qid); } int mt76u_alloc_mcu_queue(struct mt76_dev *dev) { return mt76u_alloc_rx_queue(dev, MT_RXQ_MCU); } EXPORT_SYMBOL_GPL(mt76u_alloc_mcu_queue); static void mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) { int i; for (i = 0; i < q->ndesc; i++) { if (!q->entry[i].urb) continue; mt76u_urb_free(q->entry[i].urb); q->entry[i].urb = NULL; } page_pool_destroy(q->page_pool); q->page_pool = NULL; } static void mt76u_free_rx(struct mt76_dev *dev) { int i; mt76_worker_teardown(&dev->usb.rx_worker); mt76_for_each_q_rx(dev, i) mt76u_free_rx_queue(dev, &dev->q_rx[i]); } void mt76u_stop_rx(struct mt76_dev *dev) { int i; mt76_worker_disable(&dev->usb.rx_worker); mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; int j; for (j = 0; j < q->ndesc; j++) usb_poison_urb(q->entry[j].urb); } } EXPORT_SYMBOL_GPL(mt76u_stop_rx); int mt76u_resume_rx(struct mt76_dev *dev) { int i; mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; int err, j; for (j = 0; j < q->ndesc; j++) usb_unpoison_urb(q->entry[j].urb); err = mt76u_submit_rx_buffers(dev, i); if (err < 0) return err; } mt76_worker_enable(&dev->usb.rx_worker); return 0; } EXPORT_SYMBOL_GPL(mt76u_resume_rx); static void mt76u_status_worker(struct mt76_worker *w) { struct mt76_usb *usb = container_of(w, struct mt76_usb, status_worker); struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb); struct mt76_queue_entry entry; struct mt76_queue *q; int i; if (!test_bit(MT76_STATE_RUNNING, &dev->phy.state)) return; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; while (q->queued > 0) { if (!q->entry[q->tail].done) break; entry = q->entry[q->tail]; q->entry[q->tail].done = false; mt76_queue_tx_complete(dev, q, &entry); } if (!q->queued) wake_up(&dev->tx_wait); mt76_worker_schedule(&dev->tx_worker); } if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) queue_work(dev->wq, &dev->usb.stat_work); } static void mt76u_tx_status_data(struct work_struct *work) { struct mt76_usb *usb; struct mt76_dev *dev; u8 update = 1; u16 count = 0; usb = container_of(work, struct mt76_usb, stat_work); dev = container_of(usb, struct mt76_dev, usb); while (true) { if (test_bit(MT76_REMOVED, &dev->phy.state)) break; if (!dev->drv->tx_status_data(dev, &update)) break; count++; } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) queue_work(dev->wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->phy.state); } static void mt76u_complete_tx(struct urb *urb) { struct mt76_dev *dev = dev_get_drvdata(&urb->dev->dev); struct mt76_queue_entry *e = urb->context; if (mt76u_urb_error(urb)) dev_err(dev->dev, "tx urb failed: %d\n", urb->status); e->done = true; mt76_worker_schedule(&dev->usb.status_worker); } static int mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, struct urb *urb) { urb->transfer_buffer_length = skb->len; if (!dev->usb.sg_en) { urb->transfer_buffer = skb->data; return 0; } sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE); urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len); if (!urb->num_sgs) return -ENOMEM; return urb->num_sgs; } static int -mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q, +mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { struct mt76_tx_info tx_info = { .skb = skb, }; + struct mt76_dev *dev = phy->dev; u16 idx = q->head; int err; if (q->queued == q->ndesc) return -ENOSPC; skb->prev = skb->next = NULL; err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) return err; err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb); if (err < 0) return err; - mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q2ep(q->hw_idx), - q->entry[idx].urb, mt76u_complete_tx, - &q->entry[idx]); + mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb, + mt76u_complete_tx, &q->entry[idx]); q->head = (q->head + 1) % q->ndesc; q->entry[idx].skb = tx_info.skb; q->entry[idx].wcid = 0xffff; q->queued++; return idx; } static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) { struct urb *urb; int err; while (q->first != q->head) { urb = q->entry[q->first].urb; trace_submit_urb(dev, urb); err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { if (err == -ENODEV) set_bit(MT76_REMOVED, &dev->phy.state); else dev_err(dev->dev, "tx urb submit failed:%d\n", err); break; } q->first = (q->first + 1) % q->ndesc; } } -static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac) +static void +mt76u_ac_to_hwq(struct mt76_dev *dev, struct mt76_queue *q, u8 qid) { - if (mt76_chip(dev) == 0x7663) { + u8 ac = qid < IEEE80211_NUM_ACS ? qid : IEEE80211_AC_BE; + + switch (mt76_chip(dev)) { + case 0x7663: { static const u8 lmac_queue_map[] = { /* ac to lmac mapping */ [IEEE80211_AC_BK] = 0, [IEEE80211_AC_BE] = 1, [IEEE80211_AC_VI] = 2, [IEEE80211_AC_VO] = 4, }; - if (WARN_ON(ac >= ARRAY_SIZE(lmac_queue_map))) - return 1; /* BE */ - - return lmac_queue_map[ac]; + q->hw_idx = lmac_queue_map[ac]; + q->ep = q->hw_idx + 1; + break; + } + case 0x7961: + case 0x7925: + q->hw_idx = mt76_ac_to_hwq(ac); + q->ep = qid == MT_TXQ_PSD ? MT_EP_OUT_HCCA : q->hw_idx + 1; + break; + default: + q->hw_idx = mt76_ac_to_hwq(ac); + q->ep = q->hw_idx + 1; + break; } - - return mt76_ac_to_hwq(ac); } static int mt76u_alloc_tx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j, err; + int i; for (i = 0; i <= MT_TXQ_PSD; i++) { - if (i >= IEEE80211_NUM_ACS) { - dev->phy.q_tx[i] = dev->phy.q_tx[0]; - continue; - } + struct mt76_queue *q; + int j, err; q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL); if (!q) return -ENOMEM; spin_lock_init(&q->lock); - q->hw_idx = mt76u_ac_to_hwq(dev, i); - + mt76u_ac_to_hwq(dev, q, i); dev->phy.q_tx[i] = q; q->entry = devm_kcalloc(dev->dev, MT_NUM_TX_ENTRIES, sizeof(*q->entry), GFP_KERNEL); if (!q->entry) return -ENOMEM; q->ndesc = MT_NUM_TX_ENTRIES; for (j = 0; j < q->ndesc; j++) { err = mt76u_urb_alloc(dev, &q->entry[j], MT_TX_SG_MAX_SIZE); if (err < 0) return err; } } return 0; } static void mt76u_free_tx(struct mt76_dev *dev) { int i; mt76_worker_teardown(&dev->usb.status_worker); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { struct mt76_queue *q; int j; q = dev->phy.q_tx[i]; if (!q) continue; for (j = 0; j < q->ndesc; j++) { usb_free_urb(q->entry[j].urb); q->entry[j].urb = NULL; } } } void mt76u_stop_tx(struct mt76_dev *dev) { int ret; mt76_worker_disable(&dev->usb.status_worker); ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy), HZ / 5); if (!ret) { struct mt76_queue_entry entry; struct mt76_queue *q; int i, j; dev_err(dev->dev, "timed out waiting for pending tx\n"); - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; for (j = 0; j < q->ndesc; j++) usb_kill_urb(q->entry[j].urb); } mt76_worker_disable(&dev->tx_worker); /* On device removal we maight queue skb's, but mt76u_tx_kick() * will fail to submit urb, cleanup those skb's manually. */ - for (i = 0; i < IEEE80211_NUM_ACS; i++) { + for (i = 0; i <= MT_TXQ_PSD; i++) { q = dev->phy.q_tx[i]; if (!q) continue; while (q->queued > 0) { entry = q->entry[q->tail]; q->entry[q->tail].done = false; mt76_queue_tx_complete(dev, q, &entry); } } mt76_worker_enable(&dev->tx_worker); } cancel_work_sync(&dev->usb.stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); mt76_worker_enable(&dev->usb.status_worker); mt76_tx_status_check(dev, true); } EXPORT_SYMBOL_GPL(mt76u_stop_tx); void mt76u_queues_deinit(struct mt76_dev *dev) { mt76u_stop_rx(dev); mt76u_stop_tx(dev); mt76u_free_rx(dev); mt76u_free_tx(dev); } EXPORT_SYMBOL_GPL(mt76u_queues_deinit); int mt76u_alloc_queues(struct mt76_dev *dev) { int err; err = mt76u_alloc_rx_queue(dev, MT_RXQ_MAIN); if (err < 0) return err; return mt76u_alloc_tx(dev); } EXPORT_SYMBOL_GPL(mt76u_alloc_queues); static const struct mt76_queue_ops usb_queue_ops = { .tx_queue_skb = mt76u_tx_queue_skb, .kick = mt76u_tx_kick, }; int __mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, struct mt76_bus_ops *ops) { struct usb_device *udev = interface_to_usbdev(intf); struct mt76_usb *usb = &dev->usb; int err; INIT_WORK(&usb->stat_work, mt76u_tx_status_data); usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0)); if (usb->data_len < 32) usb->data_len = 32; usb->data = devm_kmalloc(dev->dev, usb->data_len, GFP_KERNEL); if (!usb->data) return -ENOMEM; mutex_init(&usb->usb_ctrl_mtx); dev->bus = ops; dev->queue_ops = &usb_queue_ops; dev_set_drvdata(&udev->dev, dev); usb->sg_en = mt76u_check_sg(dev); err = mt76u_set_endpoints(intf, usb); if (err < 0) return err; err = mt76_worker_setup(dev->hw, &usb->rx_worker, mt76u_rx_worker, "usb-rx"); if (err) return err; err = mt76_worker_setup(dev->hw, &usb->status_worker, mt76u_status_worker, "usb-status"); if (err) return err; sched_set_fifo_low(usb->rx_worker.task); sched_set_fifo_low(usb->status_worker.task); return 0; } EXPORT_SYMBOL_GPL(__mt76u_init); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf) { static struct mt76_bus_ops bus_ops = { .rr = mt76u_rr, .wr = mt76u_wr, .rmw = mt76u_rmw, .read_copy = mt76u_read_copy, .write_copy = mt76u_copy, .wr_rp = mt76u_wr_rp, .rd_rp = mt76u_rd_rp, .type = MT76_BUS_USB, }; return __mt76u_init(dev, intf, &bus_ops); } EXPORT_SYMBOL_GPL(mt76u_init); MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_DESCRIPTION("MediaTek MT76x USB helpers"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sys/contrib/dev/mediatek/mt76/util.c b/sys/contrib/dev/mediatek/mt76/util.c index fcfc7233242a..9be1cca22ae9 100644 --- a/sys/contrib/dev/mediatek/mt76/util.c +++ b/sys/contrib/dev/mediatek/mt76/util.c @@ -1,150 +1,147 @@ // SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau */ #include #if defined(__FreeBSD__) #include #include #endif #include "mt76.h" bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, int timeout) { u32 cur; timeout /= 10; do { cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; udelay(10); } while (timeout-- > 0); return false; } EXPORT_SYMBOL_GPL(__mt76_poll); bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, int timeout, int tick) { u32 cur; timeout /= tick; do { cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; usleep_range(1000 * tick, 2000 * tick); } while (timeout-- > 0); return false; } EXPORT_SYMBOL_GPL(____mt76_poll_msec); int mt76_wcid_alloc(u32 *mask, int size) { int i, idx = 0, cur; for (i = 0; i < DIV_ROUND_UP(size, 32); i++) { idx = ffs(~mask[i]); if (!idx) continue; idx--; cur = i * 32 + idx; if (cur >= size) break; mask[i] |= BIT(idx); return cur; } return -1; } EXPORT_SYMBOL_GPL(mt76_wcid_alloc); -int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy) +int mt76_get_min_avg_rssi(struct mt76_dev *dev, u8 phy_idx) { struct mt76_wcid *wcid; int i, j, min_rssi = 0; s8 cur_rssi; local_bh_disable(); rcu_read_lock(); for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { u32 mask = dev->wcid_mask[i]; - u32 phy_mask = dev->wcid_phy_mask[i]; if (!mask) continue; - for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) { + for (j = i * 32; mask; j++, mask >>= 1) { if (!(mask & 1)) continue; - if (!!(phy_mask & 1) != ext_phy) - continue; - wcid = rcu_dereference(dev->wcid[j]); - if (!wcid) + if (!wcid || wcid->phy_idx != phy_idx) continue; spin_lock(&dev->rx_lock); if (wcid->inactive_count++ < 5) cur_rssi = -ewma_signal_read(&wcid->rssi); else cur_rssi = 0; spin_unlock(&dev->rx_lock); if (cur_rssi < min_rssi) min_rssi = cur_rssi; } } rcu_read_unlock(); local_bh_enable(); return min_rssi; } EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi); int __mt76_worker_fn(void *ptr) { struct mt76_worker *w = ptr; while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_park()) { kthread_parkme(); continue; } if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) { schedule(); continue; } set_bit(MT76_WORKER_RUNNING, &w->state); set_current_state(TASK_RUNNING); w->fn(w); cond_resched(); clear_bit(MT76_WORKER_RUNNING, &w->state); } return 0; } EXPORT_SYMBOL_GPL(__mt76_worker_fn); +MODULE_DESCRIPTION("MediaTek MT76x helpers"); MODULE_LICENSE("Dual BSD/GPL"); #if defined(__FreeBSD__) MODULE_VERSION(mt76_core, 1); MODULE_DEPEND(mt76_core, linuxkpi, 1, 1, 1); MODULE_DEPEND(mt76_core, linuxkpi_wlan, 1, 1, 1); #endif diff --git a/sys/contrib/dev/mediatek/mt76/wed.c b/sys/contrib/dev/mediatek/mt76/wed.c new file mode 100644 index 000000000000..f89e4537555c --- /dev/null +++ b/sys/contrib/dev/mediatek/mt76/wed.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2023 Lorenzo Bianconi + */ + +#include "mt76.h" +#include "dma.h" + +void mt76_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + int i; + + for (i = 0; i < dev->rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(dev, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->ptr = NULL; + + mt76_put_rxwi(dev, t); + } + + mt76_free_pending_rxwi(dev); +} +EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf); + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + int i, len = SKB_WITH_OVERHEAD(q->buf_size); + struct mt76_txwi_cache *t = NULL; + + for (i = 0; i < size; i++) { + enum dma_data_direction dir; + dma_addr_t addr; + u32 offset; + int token; + void *buf; + + t = mt76_get_rxwi(dev); + if (!t) + goto unmap; + + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!buf) + goto unmap; + + addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; + dir = page_pool_get_dma_dir(q->page_pool); + dma_sync_single_for_device(dev->dma_dev, addr, len, dir); + + desc->buf0 = cpu_to_le32(addr); + token = mt76_rx_token_consume(dev, buf, t, addr); + if (token < 0) { + mt76_put_page_pool_buf(buf, false); + goto unmap; + } + + token = FIELD_PREP(MT_DMA_CTL_TOKEN, token); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32); +#endif + desc->token |= cpu_to_le32(token); + desc++; + } + + return 0; + +unmap: + if (t) + mt76_put_rxwi(dev, t); + mt76_wed_release_rx_buf(wed); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mt76_wed_init_rx_buf); + +int mt76_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->token_lock); + + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); +} +EXPORT_SYMBOL_GPL(mt76_wed_offload_enable); + +int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) +{ + int ret = 0, type, ring; + u16 flags; + + if (!q || !q->ndesc) + return -EINVAL; + + flags = q->flags; + if (!q->wed || !mtk_wed_device_active(q->wed)) + q->flags &= ~MT_QFLAG_WED; + + if (!(q->flags & MT_QFLAG_WED)) + return 0; + + type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags); + ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags); + + switch (type) { + case MT76_WED_Q_TX: + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, + reset); + if (!ret) + q->wed_regs = q->wed->tx_ring[ring].reg_base; + break; + case MT76_WED_Q_TXFREE: + /* WED txfree queue needs ring to be initialized before setup */ + q->flags = 0; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); + if (!ret) + q->wed_regs = q->wed->txfree_ring.reg_base; + break; + case MT76_WED_Q_RX: + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, + reset); + if (!ret) + q->wed_regs = q->wed->rx_ring[ring].reg_base; + break; + case MT76_WED_RRO_Q_DATA: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_MSDU_PG: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_IND: + q->flags &= ~MT_QFLAG_WED; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); + break; + default: + ret = -EINVAL; + break; + } + q->flags = flags; + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_wed_dma_setup); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + +void mt76_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = dev->drv->token_size; + spin_unlock_bh(&dev->token_lock); +} +EXPORT_SYMBOL_GPL(mt76_wed_offload_disable); + +void mt76_wed_reset_complete(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + complete(&dev->mmio.wed_reset_complete); +} +EXPORT_SYMBOL_GPL(mt76_wed_reset_complete); + +int mt76_wed_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + struct mtk_wed_device *wed = &phy->dev->mmio.wed; + + if (!mtk_wed_device_active(wed)) + return -EOPNOTSUPP; + + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); +} +EXPORT_SYMBOL_GPL(mt76_wed_net_setup_tc); + +void mt76_wed_dma_reset(struct mt76_dev *dev) +{ + struct mt76_mmio *mmio = &dev->mmio; + + if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) + return; + + complete(&mmio->wed_reset); + + if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) + dev_err(dev->dev, "wed reset complete timeout\n"); +} +EXPORT_SYMBOL_GPL(mt76_wed_dma_reset); diff --git a/sys/modules/mt76/Makefile b/sys/modules/mt76/Makefile index f75427acf4f5..5abae4c5ad7c 100644 --- a/sys/modules/mt76/Makefile +++ b/sys/modules/mt76/Makefile @@ -1,7 +1,8 @@ SUBDIR= core SUBDIR+= mt7615 SUBDIR+= mt7915 SUBDIR+= mt7921 +SUBDIR+= mt7925 SUBDIR+= mt7996 .include diff --git a/sys/modules/mt76/core/Makefile b/sys/modules/mt76/core/Makefile index 88068b7bb188..c782bf218d93 100644 --- a/sys/modules/mt76/core/Makefile +++ b/sys/modules/mt76/core/Makefile @@ -1,40 +1,43 @@ KMOD= mt76_core # Basic stuff. SRCS= mac80211.c mmio.c util.c dma.c eeprom.c tx.c agg-rx.c mcu.c +SRCS+= channel.c scan.c wed.c #SRCS+= trace.c # Bus stuff. SRCS+= pci.c .if defined(WITH_USB) && ${WITH_USB} > 0 SRCS+= usb.c # usb_trace.c .endif #SRCS+= sdio.c sdio_txrx.c # Connac-Lib stuff. SRCS+= mt76_connac_mac.c mt76_connac_mcu.c mt76_connac3_mac.c # MT76x02-Lib stuff (we don't need; that's for older chipsets not yet supported) # XXX should this be a separate module? # MT792X-LIB stuff. SRCS+= mt792x_core.c mt792x_mac.c mt792x_dma.c #SRCS+= mt792x_trace.c .if defined(WITH_ACPI) && ${WITH_ACPI} > 0 SRCS+= mt792x_acpi_sar.c .endif .if defined(WITH_USB) && ${WITH_USB} > 0 SRCS+= mt792x_usb.c .endif .if defined(WITH_DEBUGFS) && ${WITH_DEBUGFS} > 0 SRCS+= mt792x_debugfs.c .endif .if defined(WITH_DEBUGFS) && ${WITH_DEBUGFS} > 0 SRCS+= debugfs.c .endif CFLAGS+= -DKBUILD_MODNAME='"mt76_core"' CFLAGS+= -DCONFIG_MAC80211_DEBUGFS=${WITH_DEBUGFS} +EXPORT_SYMS= YES + .include diff --git a/sys/modules/mt76/mt7925/Makefile b/sys/modules/mt76/mt7925/Makefile new file mode 100644 index 000000000000..58e23d06a9ad --- /dev/null +++ b/sys/modules/mt76/mt7925/Makefile @@ -0,0 +1,24 @@ +DEVDIR= ${SRCTOP}/sys/contrib/dev/mediatek/mt76/mt7925 + +.PATH: ${DEVDIR} + +KMOD= if_mt7925 + +# Common stuff. +SRCS= init.c main.c mac.c mcu.c + +# PCI stuff. +SRCS+= pci.c pci_mac.c pci_mcu.c + +# USB stuff. +#SRCS+= usb.c + +.if defined(WITH_DEBUGFS) && ${WITH_DEBUGFS} > 0 +SRCS+= debugfs.c +CFLAGS+= -DCONFIG_MT7925_DEBUGFS=${WITH_DEBUGFS} +.endif + +CFLAGS+= -DKBUILD_MODNAME='"mt7925"' +CFLAGS+= -I${DEVDIR} + +.include