mirror of https://gitee.com/openkylin/linux.git
mt76 patches for 5.8
* new devices for mt76x0/mt76x2 * mt7615 fixes * mt7663 fixes * support for non-offload firmware on mt7663 * hw/sched scan support for mt7663 * mt7615/mt7663 MSI support * TDLS support * mt7603/mt7615 rate control fixes * new driver for mt7915 * wowlan support for mt7663 * suspend/resume support for mt7663 -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org iEYEABECAAYFAl69GP8ACgkQ130UHQKnbvUK1QCguAkkko7P79NpRiqd2MydjmWi 4dIAoIhmr8PEsh1fOsMBMqInupEnDKoZ =biCw -----END PGP SIGNATURE----- Merge tag 'mt76-for-kvalo-2020-05-14' of https://github.com/nbd168/wireless mt76 patches for 5.8 * new devices for mt76x0/mt76x2 * mt7615 fixes * mt7663 fixes * support for non-offload firmware on mt7663 * hw/sched scan support for mt7663 * mt7615/mt7663 MSI support * TDLS support * mt7603/mt7615 rate control fixes * new driver for mt7915 * wowlan support for mt7663 * suspend/resume support for mt7663 # gpg: Signature made Thu 14 May 2020 01:10:07 PM EEST using DSA key ID 02A76EF5 # gpg: Good signature from "Felix Fietkau <nbd@nbd.name>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 75D1 1A7D 91A7 710F 4900 42EF D77D 141D 02A7 6EF5
This commit is contained in:
commit
eda31200e6
|
@ -25,6 +25,9 @@ Optional properties:
|
|||
- mediatek,mtd-eeprom: Specify a MTD partition + offset containing EEPROM data
|
||||
- big-endian: if the radio eeprom partition is written in big-endian, specify
|
||||
this property
|
||||
- mediatek,eeprom-merge-otp: Merge EEPROM data with OTP data. Can be used on
|
||||
boards where the flash calibration data is generic and specific calibration
|
||||
data should be pulled from the OTP ROM
|
||||
|
||||
The MAC address can as well be set with corresponding optional properties
|
||||
defined in net/ethernet.txt.
|
||||
|
|
|
@ -24,3 +24,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
|
|||
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig"
|
||||
source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig"
|
||||
|
|
|
@ -26,4 +26,5 @@ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
|
|||
obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
|
||||
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
|
||||
obj-$(CONFIG_MT7603E) += mt7603/
|
||||
obj-$(CONFIG_MT7615E) += mt7615/
|
||||
obj-$(CONFIG_MT7615_COMMON) += mt7615/
|
||||
obj-$(CONFIG_MT7915E) += mt7915/
|
||||
|
|
|
@ -119,7 +119,7 @@ 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 = (struct ieee80211_bar *)skb->data;
|
||||
struct ieee80211_bar *bar = mt76_skb_get_hdr(skb);
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct mt76_rx_tid *tid;
|
||||
u16 seqno;
|
||||
|
@ -147,13 +147,13 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
|
|||
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 ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct ieee80211_sta *sta;
|
||||
struct mt76_rx_tid *tid;
|
||||
bool sn_less;
|
||||
u16 seqno, head, size;
|
||||
u8 ackp, idx;
|
||||
u16 seqno, head, size, idx;
|
||||
u8 ackp;
|
||||
|
||||
__skb_queue_tail(frames, skb);
|
||||
|
||||
|
@ -239,7 +239,7 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
|
|||
}
|
||||
|
||||
int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno,
|
||||
u16 ssn, u8 size)
|
||||
u16 ssn, u16 size)
|
||||
{
|
||||
struct mt76_rx_tid *tid;
|
||||
|
||||
|
@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(mt76_rx_aggr_start);
|
|||
|
||||
static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid)
|
||||
{
|
||||
u8 size = tid->size;
|
||||
u16 size = tid->size;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&tid->lock);
|
||||
|
|
|
@ -46,6 +46,25 @@ int mt76_queues_read(struct seq_file *s, void *data)
|
|||
}
|
||||
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;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) {
|
||||
struct mt76_queue *q = &dev->q_rx[i];
|
||||
|
||||
if (!q->ndesc)
|
||||
continue;
|
||||
|
||||
queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued;
|
||||
seq_printf(s, "%d: queued=%d head=%d tail=%d\n",
|
||||
i, queued, q->head, q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt76_seq_puts_array(struct seq_file *file, const char *str,
|
||||
s8 *val, int len)
|
||||
{
|
||||
|
@ -92,6 +111,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
|
|||
debugfs_create_blob("otp", 0400, dir, &dev->otp);
|
||||
debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir,
|
||||
mt76_read_rate_txpower);
|
||||
debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir,
|
||||
mt76_rx_queues_read);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
|
|
@ -116,12 +116,12 @@ static void mt76_led_cleanup(struct mt76_dev *dev)
|
|||
led_classdev_unregister(&dev->led_cdev);
|
||||
}
|
||||
|
||||
static void mt76_init_stream_cap(struct mt76_dev *dev,
|
||||
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(dev->phy.antenna_mask);
|
||||
int i, nstream = hweight8(phy->antenna_mask);
|
||||
struct ieee80211_sta_vht_cap *vht_cap;
|
||||
u16 mcs_map = 0;
|
||||
|
||||
|
@ -153,12 +153,12 @@ static void mt76_init_stream_cap(struct mt76_dev *dev,
|
|||
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
|
||||
}
|
||||
|
||||
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
|
||||
void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
|
||||
{
|
||||
if (dev->cap.has_2ghz)
|
||||
mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false);
|
||||
if (dev->cap.has_5ghz)
|
||||
mt76_init_stream_cap(dev, &dev->phy.sband_5g.sband, vht);
|
||||
if (phy->dev->cap.has_2ghz)
|
||||
mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
|
||||
if (phy->dev->cap.has_5ghz)
|
||||
mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
|
||||
|
||||
|
@ -198,9 +198,8 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
|
|||
|
||||
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
|
||||
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
|
||||
ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
|
||||
|
||||
mt76_init_stream_cap(dev, sband, vht);
|
||||
mt76_init_stream_cap(&dev->phy, sband, vht);
|
||||
|
||||
if (!vht)
|
||||
return 0;
|
||||
|
@ -279,7 +278,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
|
|||
SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
|
||||
|
||||
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
|
||||
WIPHY_FLAG_SUPPORTS_TDLS;
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
|
||||
|
@ -294,7 +294,6 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
|
|||
hw->max_tx_fragments = 16;
|
||||
|
||||
ieee80211_hw_set(hw, SIGNAL_DBM);
|
||||
ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
|
||||
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
|
||||
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
|
||||
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
|
||||
|
@ -314,6 +313,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
|
|||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
}
|
||||
|
||||
|
@ -677,7 +678,6 @@ 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 mt76_rx_status mstat;
|
||||
|
||||
|
@ -689,6 +689,9 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
|
|||
status->enc_flags = mstat.enc_flags;
|
||||
status->encoding = mstat.encoding;
|
||||
status->bw = mstat.bw;
|
||||
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;
|
||||
|
@ -725,7 +728,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
|
|||
* Validate the first fragment both here and in mac80211
|
||||
* All further fragments will be validated by mac80211 only.
|
||||
*/
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
hdr = mt76_skb_get_hdr(skb);
|
||||
if (ieee80211_is_frag(hdr) &&
|
||||
!ieee80211_is_first_frag(hdr->frame_control))
|
||||
return 0;
|
||||
|
@ -798,7 +801,7 @@ mt76_airtime_flush_ampdu(struct mt76_dev *dev)
|
|||
static void
|
||||
mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
|
||||
|
@ -835,7 +838,7 @@ 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 = (struct ieee80211_hdr *)skb->data;
|
||||
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_hw *hw;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
#include "mt76.h"
|
||||
|
||||
struct sk_buff *
|
||||
mt76_mcu_msg_alloc(const void *data, int head_len,
|
||||
int data_len, int tail_len)
|
||||
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
|
||||
int data_len)
|
||||
{
|
||||
int length = head_len + data_len + tail_len;
|
||||
const struct mt76_mcu_ops *ops = dev->mcu_ops;
|
||||
int length = ops->headroom + data_len + ops->tailroom;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = alloc_skb(length, GFP_KERNEL);
|
||||
|
@ -17,7 +18,7 @@ mt76_mcu_msg_alloc(const void *data, int head_len,
|
|||
return NULL;
|
||||
|
||||
memset(skb->head, 0, length);
|
||||
skb_reserve(skb, head_len);
|
||||
skb_reserve(skb, ops->headroom);
|
||||
|
||||
if (data && data_len)
|
||||
skb_put_data(skb, data, data_len);
|
||||
|
|
|
@ -73,7 +73,8 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
|
|||
spin_lock_irqsave(&dev->mmio.irq_lock, flags);
|
||||
dev->mmio.irqmask &= ~clear;
|
||||
dev->mmio.irqmask |= set;
|
||||
mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
|
||||
if (addr)
|
||||
mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
|
||||
spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
|
||||
|
|
|
@ -60,6 +60,7 @@ enum mt76_txq_id {
|
|||
MT_TXQ_BK = IEEE80211_AC_BK,
|
||||
MT_TXQ_PSD,
|
||||
MT_TXQ_MCU,
|
||||
MT_TXQ_MCU_WA,
|
||||
MT_TXQ_BEACON,
|
||||
MT_TXQ_CAB,
|
||||
MT_TXQ_FWDL,
|
||||
|
@ -69,6 +70,7 @@ enum mt76_txq_id {
|
|||
enum mt76_rxq_id {
|
||||
MT_RXQ_MAIN,
|
||||
MT_RXQ_MCU,
|
||||
MT_RXQ_MCU_WA,
|
||||
__MT_RXQ_MAX
|
||||
};
|
||||
|
||||
|
@ -137,6 +139,9 @@ struct mt76_sw_queue {
|
|||
};
|
||||
|
||||
struct mt76_mcu_ops {
|
||||
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_send_msg)(struct mt76_dev *dev, struct sk_buff *skb,
|
||||
|
@ -178,7 +183,7 @@ enum mt76_wcid_flags {
|
|||
MT_WCID_FLAG_PS,
|
||||
};
|
||||
|
||||
#define MT76_N_WCIDS 128
|
||||
#define MT76_N_WCIDS 288
|
||||
|
||||
/* stored in ieee80211_tx_info::hw_queue */
|
||||
#define MT_TX_HW_QUEUE_EXT_PHY BIT(3)
|
||||
|
@ -198,7 +203,7 @@ struct mt76_wcid {
|
|||
struct ewma_signal rssi;
|
||||
int inactive_count;
|
||||
|
||||
u8 idx;
|
||||
u16 idx;
|
||||
u8 hw_key_idx;
|
||||
|
||||
u8 sta:1;
|
||||
|
@ -241,8 +246,8 @@ struct mt76_rx_tid {
|
|||
struct delayed_work reorder_work;
|
||||
|
||||
u16 head;
|
||||
u8 size;
|
||||
u8 nframes;
|
||||
u16 size;
|
||||
u16 nframes;
|
||||
|
||||
u8 num;
|
||||
|
||||
|
@ -265,7 +270,7 @@ struct mt76_rx_tid {
|
|||
|
||||
struct mt76_tx_cb {
|
||||
unsigned long jiffies;
|
||||
u8 wcid;
|
||||
u16 wcid;
|
||||
u8 pktid;
|
||||
u8 flags;
|
||||
};
|
||||
|
@ -275,10 +280,16 @@ enum {
|
|||
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_PS,
|
||||
MT76_STATE_SUSPEND,
|
||||
};
|
||||
|
||||
struct mt76_hw_cap {
|
||||
|
@ -372,6 +383,7 @@ enum mt_vendor_req {
|
|||
MT_VEND_READ_CFG = 0x47,
|
||||
MT_VEND_READ_EXT = 0x63,
|
||||
MT_VEND_WRITE_EXT = 0x66,
|
||||
MT_VEND_FEATURE_SET = 0x91,
|
||||
};
|
||||
|
||||
enum mt76u_in_ep {
|
||||
|
@ -435,7 +447,7 @@ struct mt76_mmio {
|
|||
struct mt76_rx_status {
|
||||
union {
|
||||
struct mt76_wcid *wcid;
|
||||
u8 wcid_idx;
|
||||
u16 wcid_idx;
|
||||
};
|
||||
|
||||
unsigned long reorder_time;
|
||||
|
@ -452,7 +464,8 @@ struct mt76_rx_status {
|
|||
u16 freq;
|
||||
u32 flag;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3;
|
||||
u8 encoding:2, bw:3, he_ru:3;
|
||||
u8 he_gi:2, he_dcm:1;
|
||||
u8 rate_idx;
|
||||
u8 nss;
|
||||
u8 band;
|
||||
|
@ -570,6 +583,10 @@ enum mt76_phy_type {
|
|||
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,
|
||||
};
|
||||
|
||||
#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__)
|
||||
|
@ -611,7 +628,7 @@ enum mt76_phy_type {
|
|||
#define mt76_hw(dev) (dev)->mphy.hw
|
||||
|
||||
static inline struct ieee80211_hw *
|
||||
mt76_wcid_hw(struct mt76_dev *dev, u8 wcid)
|
||||
mt76_wcid_hw(struct mt76_dev *dev, u16 wcid)
|
||||
{
|
||||
if (wcid <= MT76_N_WCIDS &&
|
||||
mt76_wcid_mask_test(dev->wcid_phy_mask, wcid))
|
||||
|
@ -735,6 +752,25 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
|
|||
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);
|
||||
|
@ -785,10 +821,10 @@ void mt76_set_channel(struct mt76_phy *phy);
|
|||
void mt76_update_survey(struct mt76_dev *dev);
|
||||
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht);
|
||||
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, u8 size);
|
||||
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,
|
||||
|
@ -911,8 +947,8 @@ int mt76u_resume_rx(struct mt76_dev *dev);
|
|||
void mt76u_queues_deinit(struct mt76_dev *dev);
|
||||
|
||||
struct sk_buff *
|
||||
mt76_mcu_msg_alloc(const void *data, int head_len,
|
||||
int data_len, int tail_len);
|
||||
mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
|
||||
int data_len);
|
||||
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);
|
||||
|
|
|
@ -113,7 +113,7 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
|
|||
return;
|
||||
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
|
||||
debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
|
||||
#include <linux/of.h>
|
||||
#include "mt7603.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
|
@ -100,10 +101,14 @@ mt7603_apply_cal_free_data(struct mt7603_dev *dev, u8 *efuse)
|
|||
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;
|
||||
|
||||
|
|
|
@ -342,6 +342,8 @@ static const struct ieee80211_iface_limit if_limits[] = {
|
|||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
};
|
||||
|
|
|
@ -51,10 +51,11 @@ void mt7603_mac_set_timing(struct mt7603_dev *dev)
|
|||
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 (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
|
||||
if (is_5ghz)
|
||||
sifs = 16;
|
||||
else
|
||||
sifs = 10;
|
||||
|
@ -71,7 +72,7 @@ void mt7603_mac_set_timing(struct mt7603_dev *dev)
|
|||
FIELD_PREP(MT_IFS_SIFS, sifs) |
|
||||
FIELD_PREP(MT_IFS_SLOT, dev->slottime));
|
||||
|
||||
if (dev->slottime < 20)
|
||||
if (dev->slottime < 20 || is_5ghz)
|
||||
val = MT7603_CFEND_RATE_DEFAULT;
|
||||
else
|
||||
val = MT7603_CFEND_RATE_11B;
|
||||
|
@ -318,11 +319,16 @@ 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->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->ht_cap.ampdu_factor) |
|
||||
|
@ -1097,7 +1103,7 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
|||
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);
|
||||
first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY);
|
||||
|
||||
if (fixed_rate && !probe) {
|
||||
info->status.rates[0].count = count;
|
||||
|
|
|
@ -62,7 +62,7 @@ mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
|
|||
struct sk_buff *skb;
|
||||
int ret, seq;
|
||||
|
||||
skb = mt7603_mcu_msg_alloc(data, len);
|
||||
skb = mt76_mcu_msg_alloc(mdev, data, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -265,6 +265,7 @@ static int mt7603_load_firmware(struct mt7603_dev *dev)
|
|||
int mt7603_mcu_init(struct mt7603_dev *dev)
|
||||
{
|
||||
static const struct mt76_mcu_ops mt7603_mcu_ops = {
|
||||
.headroom = sizeof(struct mt7603_mcu_txd),
|
||||
.mcu_send_msg = mt7603_mcu_msg_send,
|
||||
.mcu_restart = mt7603_mcu_restart,
|
||||
};
|
||||
|
|
|
@ -100,11 +100,4 @@ enum {
|
|||
MCU_EXT_EVENT_BCN_UPDATE = 0x31,
|
||||
};
|
||||
|
||||
static inline struct sk_buff *
|
||||
mt7603_mcu_msg_alloc(const void *data, int len)
|
||||
{
|
||||
return mt76_mcu_msg_alloc(data, sizeof(struct mt7603_mcu_txd),
|
||||
len, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,8 @@ mt76_wmac_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
|
||||
mem_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mem_base)) {
|
||||
dev_err(&pdev->dev, "Failed to get memory resource\n");
|
||||
if (IS_ERR(mem_base))
|
||||
return PTR_ERR(mem_base);
|
||||
}
|
||||
|
||||
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7603_ops,
|
||||
&mt7603_drv_ops);
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config MT7615E
|
||||
tristate "MediaTek MT7615E (PCIe) support"
|
||||
|
||||
config MT7615_COMMON
|
||||
tristate
|
||||
select MT76_CORE
|
||||
|
||||
config MT7615E
|
||||
tristate "MediaTek MT7615E and MT7663E (PCIe) support"
|
||||
select MT7615_COMMON
|
||||
depends on MAC80211
|
||||
depends on PCI
|
||||
help
|
||||
|
@ -22,3 +27,14 @@ config MT7622_WMAC
|
|||
This adds support for the built-in WMAC on MT7622 SoC devices
|
||||
which has the same feature set as a MT7615, but limited to
|
||||
2.4 GHz only.
|
||||
|
||||
config MT7663U
|
||||
tristate "MediaTek MT7663U (USB) support"
|
||||
select MT76_USB
|
||||
select MT7615_COMMON
|
||||
depends on MAC80211
|
||||
depends on USB
|
||||
help
|
||||
This adds support for MT7663U 802.11ax 2x2:2 wireless devices.
|
||||
|
||||
To compile this driver as a module, choose M here.
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
#SPDX-License-Identifier: ISC
|
||||
|
||||
obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o
|
||||
obj-$(CONFIG_MT7615E) += mt7615e.o
|
||||
obj-$(CONFIG_MT7663U) += mt7663u.o
|
||||
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o mmio.o \
|
||||
debugfs.o trace.o
|
||||
mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \
|
||||
debugfs.o trace.o
|
||||
|
||||
mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o
|
||||
mt7615e-$(CONFIG_MT7622_WMAC) += soc.o
|
||||
|
||||
mt7663u-y := usb.o usb_mcu.o usb_init.o
|
||||
|
|
|
@ -20,11 +20,15 @@ static int
|
|||
mt7615_scs_set(void *data, u64 val)
|
||||
{
|
||||
struct mt7615_dev *dev = data;
|
||||
struct mt7615_phy *ext_phy;
|
||||
|
||||
if (!mt7615_wait_for_mcu_init(dev))
|
||||
return 0;
|
||||
|
||||
mt7615_mac_set_scs(dev, val);
|
||||
mt7615_mac_set_scs(&dev->phy, val);
|
||||
ext_phy = mt7615_ext_phy(dev);
|
||||
if (ext_phy)
|
||||
mt7615_mac_set_scs(ext_phy, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,7 +38,7 @@ mt7615_scs_get(void *data, u64 *val)
|
|||
{
|
||||
struct mt7615_dev *dev = data;
|
||||
|
||||
*val = dev->scs_en;
|
||||
*val = dev->phy.scs_en;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,28 +124,52 @@ mt7615_reset_test_set(void *data, u64 val)
|
|||
DEFINE_DEBUGFS_ATTRIBUTE(fops_reset_test, NULL,
|
||||
mt7615_reset_test_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
static void
|
||||
mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy,
|
||||
struct seq_file *file)
|
||||
{
|
||||
struct mt7615_dev *dev = file->private;
|
||||
u32 reg = is_mt7663(&dev->mt76) ? MT_MIB_ARNG(0) : MT_AGG_ASRCR0;
|
||||
bool ext_phy = phy != &dev->phy;
|
||||
int bound[7], i, range;
|
||||
|
||||
range = mt76_rr(dev, MT_AGG_ASRCR0);
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
range = mt76_rr(dev, reg);
|
||||
for (i = 0; i < 4; i++)
|
||||
bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
|
||||
range = mt76_rr(dev, MT_AGG_ASRCR1);
|
||||
|
||||
range = mt76_rr(dev, reg + 4);
|
||||
for (i = 0; i < 3; i++)
|
||||
bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1;
|
||||
|
||||
seq_printf(file, "\nPhy %d\n", ext_phy);
|
||||
|
||||
seq_printf(file, "Length: %8d | ", bound[0]);
|
||||
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
|
||||
seq_printf(file, "%3d -%3d | ",
|
||||
bound[i], bound[i + 1]);
|
||||
seq_puts(file, "\nCount: ");
|
||||
|
||||
range = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
|
||||
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + range]);
|
||||
seq_puts(file, "\n");
|
||||
|
||||
seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
|
||||
seq_printf(file, "PER: %ld.%1ld%%\n",
|
||||
phy->mib.aggr_per / 10, phy->mib.aggr_per % 10);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7615_dev *dev = file->private;
|
||||
|
||||
mt7615_ampdu_stat_read_phy(&dev->phy, file);
|
||||
mt7615_ampdu_stat_read_phy(mt7615_ext_phy(dev), file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -265,10 +293,10 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
if (is_mt7615(&dev->mt76))
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
|
||||
mt7615_queues_read);
|
||||
else
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
|
||||
mt7615_queues_acq);
|
||||
|
@ -297,3 +325,4 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_init_debugfs);
|
||||
|
|
|
@ -94,45 +94,6 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
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 = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
|
||||
flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0]));
|
||||
if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
|
||||
type = PKT_TYPE_NORMAL_MCU;
|
||||
|
||||
switch (type) {
|
||||
case PKT_TYPE_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);
|
||||
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;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_tx_cleanup(struct mt7615_dev *dev)
|
||||
{
|
||||
|
@ -160,13 +121,52 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
|
|||
|
||||
mt7615_tx_cleanup(dev);
|
||||
|
||||
rcu_read_lock();
|
||||
mt7615_mac_sta_poll(dev);
|
||||
rcu_read_unlock();
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -229,8 +229,13 @@ static void mt7663_dma_sched_init(struct mt7615_dev *dev)
|
|||
int mt7615_dma_init(struct mt7615_dev *dev)
|
||||
{
|
||||
int rx_ring_size = MT7615_RX_RING_SIZE;
|
||||
int rx_buf_size = MT_RX_BUF_SIZE;
|
||||
int ret;
|
||||
|
||||
/* Increase buffer size to receive large VHT MPDUs */
|
||||
if (dev->mt76.cap.has_5ghz)
|
||||
rx_buf_size *= 2;
|
||||
|
||||
mt76_dma_attach(&dev->mt76);
|
||||
|
||||
mt76_wr(dev, MT_WPDMA_GLO_CFG,
|
||||
|
@ -271,7 +276,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
|
|||
|
||||
/* 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,
|
||||
MT7615_RX_MCU_RING_SIZE, rx_buf_size,
|
||||
MT_RX_RING_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -280,7 +285,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
|
|||
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);
|
||||
rx_ring_size, rx_buf_size, MT_RX_RING_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Felix Fietkau <nbd@nbd.name>
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include "mt7615.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
|
@ -40,11 +41,11 @@ static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt7615_efuse_init(struct mt7615_dev *dev)
|
||||
static int mt7615_efuse_init(struct mt7615_dev *dev, u32 base)
|
||||
{
|
||||
u32 val, base = mt7615_reg_map(dev, MT_EFUSE_BASE);
|
||||
int i, len = MT7615_EEPROM_SIZE;
|
||||
void *buf;
|
||||
u32 val;
|
||||
|
||||
val = mt76_rr(dev, base + MT_EFUSE_BASE_CTRL);
|
||||
if (val & MT_EFUSE_BASE_CTRL_EMPTY)
|
||||
|
@ -67,15 +68,16 @@ static int mt7615_efuse_init(struct mt7615_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt7615_eeprom_load(struct mt7615_dev *dev)
|
||||
static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE);
|
||||
ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE +
|
||||
MT7615_EEPROM_EXTRA_DATA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return mt7615_efuse_init(dev);
|
||||
return mt7615_efuse_init(dev, addr);
|
||||
}
|
||||
|
||||
static int mt7615_check_eeprom(struct mt76_dev *dev)
|
||||
|
@ -128,14 +130,15 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
|
|||
static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
|
||||
{
|
||||
u8 *eeprom = dev->mt76.eeprom.data;
|
||||
u8 tx_mask;
|
||||
u8 tx_mask, max_nss;
|
||||
|
||||
mt7615_eeprom_parse_hw_band_cap(dev);
|
||||
|
||||
if (is_mt7663(&dev->mt76)) {
|
||||
tx_mask = 2;
|
||||
max_nss = 2;
|
||||
tx_mask = FIELD_GET(MT_EE_HW_CONF1_TX_MASK,
|
||||
eeprom[MT7663_EE_HW_CONF1]);
|
||||
} else {
|
||||
u8 max_nss;
|
||||
u32 val;
|
||||
|
||||
/* read tx-rx mask from eeprom */
|
||||
|
@ -144,21 +147,46 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
|
|||
|
||||
tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
|
||||
eeprom[MT_EE_NIC_CONF_0]);
|
||||
if (!tx_mask || tx_mask > max_nss)
|
||||
tx_mask = max_nss;
|
||||
}
|
||||
if (!tx_mask || tx_mask > max_nss)
|
||||
tx_mask = max_nss;
|
||||
|
||||
dev->chainmask = BIT(tx_mask) - 1;
|
||||
dev->mphy.antenna_mask = dev->chainmask;
|
||||
dev->phy.chainmask = dev->chainmask;
|
||||
}
|
||||
|
||||
int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx)
|
||||
static int mt7663_eeprom_get_target_power_index(struct mt7615_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx)
|
||||
{
|
||||
int index, group;
|
||||
|
||||
if (chain_idx > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (chan->band == NL80211_BAND_2GHZ)
|
||||
return MT7663_EE_TX0_2G_TARGET_POWER + (chain_idx << 4);
|
||||
|
||||
group = mt7615_get_channel_group(chan->hw_value);
|
||||
if (chain_idx == 1)
|
||||
index = MT7663_EE_TX1_5G_G0_TARGET_POWER;
|
||||
else
|
||||
index = MT7663_EE_TX0_5G_G0_TARGET_POWER;
|
||||
|
||||
return index + group * 3;
|
||||
}
|
||||
|
||||
int mt7615_eeprom_get_target_power_index(struct mt7615_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (is_mt7663(&dev->mt76))
|
||||
return mt7663_eeprom_get_target_power_index(dev, chan,
|
||||
chain_idx);
|
||||
|
||||
if (chain_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -197,6 +225,23 @@ int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
|
|||
return index;
|
||||
}
|
||||
|
||||
int mt7615_eeprom_get_power_delta_index(struct mt7615_dev *dev,
|
||||
enum nl80211_band band)
|
||||
{
|
||||
/* assume the first rate has the highest power offset */
|
||||
if (is_mt7663(&dev->mt76)) {
|
||||
if (band == NL80211_BAND_2GHZ)
|
||||
return MT_EE_TX0_5G_G0_TARGET_POWER;
|
||||
else
|
||||
return MT7663_EE_5G_RATE_POWER;
|
||||
}
|
||||
|
||||
if (band == NL80211_BAND_2GHZ)
|
||||
return MT_EE_2G_RATE_POWER;
|
||||
else
|
||||
return MT_EE_5G_RATE_POWER;
|
||||
}
|
||||
|
||||
static void mt7615_apply_cal_free_data(struct mt7615_dev *dev)
|
||||
{
|
||||
static const u16 ical[] = {
|
||||
|
@ -255,6 +300,11 @@ static void mt7622_apply_cal_free_data(struct mt7615_dev *dev)
|
|||
|
||||
static void mt7615_cal_free_data(struct mt7615_dev *dev)
|
||||
{
|
||||
struct device_node *np = dev->mt76.dev->of_node;
|
||||
|
||||
if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
|
||||
return;
|
||||
|
||||
switch (mt76_chip(&dev->mt76)) {
|
||||
case 0x7622:
|
||||
mt7622_apply_cal_free_data(dev);
|
||||
|
@ -265,20 +315,22 @@ static void mt7615_cal_free_data(struct mt7615_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
int mt7615_eeprom_init(struct mt7615_dev *dev)
|
||||
int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt7615_eeprom_load(dev);
|
||||
ret = mt7615_eeprom_load(dev, addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt7615_check_eeprom(&dev->mt76);
|
||||
if (ret && dev->mt76.otp.data)
|
||||
if (ret && dev->mt76.otp.data) {
|
||||
memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
|
||||
MT7615_EEPROM_SIZE);
|
||||
else
|
||||
} else {
|
||||
dev->flash_eeprom = true;
|
||||
mt7615_cal_free_data(dev);
|
||||
}
|
||||
|
||||
mt7615_eeprom_parse_hw_cap(dev);
|
||||
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
|
@ -288,3 +340,4 @@ int mt7615_eeprom_init(struct mt7615_dev *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_eeprom_init);
|
||||
|
|
|
@ -6,6 +6,21 @@
|
|||
|
||||
#include "mt7615.h"
|
||||
|
||||
|
||||
#define MT7615_EEPROM_DCOC_OFFSET MT7615_EEPROM_SIZE
|
||||
#define MT7615_EEPROM_DCOC_SIZE 256
|
||||
#define MT7615_EEPROM_DCOC_COUNT 34
|
||||
|
||||
#define MT7615_EEPROM_TXDPD_OFFSET (MT7615_EEPROM_SIZE + \
|
||||
MT7615_EEPROM_DCOC_COUNT * \
|
||||
MT7615_EEPROM_DCOC_SIZE)
|
||||
#define MT7615_EEPROM_TXDPD_SIZE 216
|
||||
#define MT7615_EEPROM_TXDPD_COUNT (44 + 3)
|
||||
|
||||
#define MT7615_EEPROM_EXTRA_DATA (MT7615_EEPROM_TXDPD_OFFSET + \
|
||||
MT7615_EEPROM_TXDPD_COUNT * \
|
||||
MT7615_EEPROM_TXDPD_SIZE)
|
||||
|
||||
enum mt7615_eeprom_field {
|
||||
MT_EE_CHIP_ID = 0x000,
|
||||
MT_EE_VERSION = 0x002,
|
||||
|
@ -13,23 +28,39 @@ enum mt7615_eeprom_field {
|
|||
MT_EE_NIC_CONF_0 = 0x034,
|
||||
MT_EE_NIC_CONF_1 = 0x036,
|
||||
MT_EE_WIFI_CONF = 0x03e,
|
||||
MT_EE_CALDATA_FLASH = 0x052,
|
||||
MT_EE_TX0_2G_TARGET_POWER = 0x058,
|
||||
MT_EE_TX0_5G_G0_TARGET_POWER = 0x070,
|
||||
MT7663_EE_5G_RATE_POWER = 0x089,
|
||||
MT_EE_TX1_5G_G0_TARGET_POWER = 0x098,
|
||||
MT_EE_2G_RATE_POWER = 0x0be,
|
||||
MT_EE_5G_RATE_POWER = 0x0d5,
|
||||
MT7663_EE_TX0_2G_TARGET_POWER = 0x0e3,
|
||||
MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2,
|
||||
MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3,
|
||||
MT7663_EE_TX0_2G_TARGET_POWER = 0x123,
|
||||
MT_EE_TX2_5G_G0_TARGET_POWER = 0x142,
|
||||
MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a,
|
||||
MT7663_EE_HW_CONF1 = 0x1b0,
|
||||
MT7663_EE_TX0_5G_G0_TARGET_POWER = 0x245,
|
||||
MT7663_EE_TX1_5G_G0_TARGET_POWER = 0x2b5,
|
||||
|
||||
MT7615_EE_MAX = 0x3bf,
|
||||
MT7622_EE_MAX = 0x3db,
|
||||
MT7663_EE_MAX = 0x400,
|
||||
};
|
||||
|
||||
#define MT_EE_RATE_POWER_MASK GENMASK(5, 0)
|
||||
#define MT_EE_RATE_POWER_SIGN BIT(6)
|
||||
#define MT_EE_RATE_POWER_EN BIT(7)
|
||||
|
||||
#define MT_EE_CALDATA_FLASH_TX_DPD BIT(0)
|
||||
#define MT_EE_CALDATA_FLASH_RX_CAL BIT(1)
|
||||
|
||||
#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4)
|
||||
#define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0)
|
||||
|
||||
#define MT_EE_HW_CONF1_TX_MASK GENMASK(2, 0)
|
||||
|
||||
#define MT_EE_NIC_CONF_TSSI_2G BIT(5)
|
||||
#define MT_EE_NIC_CONF_TSSI_5G BIT(6)
|
||||
|
||||
|
|
|
@ -12,17 +12,18 @@
|
|||
#include "mac.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
static void mt7615_phy_init(struct mt7615_dev *dev)
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_phy_init);
|
||||
|
||||
static void
|
||||
mt7615_init_mac_chain(struct mt7615_dev *dev, int chain)
|
||||
{
|
||||
u32 val, mask, set;
|
||||
u32 val;
|
||||
|
||||
if (!chain)
|
||||
val = MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN;
|
||||
|
@ -62,18 +63,23 @@ mt7615_init_mac_chain(struct mt7615_dev *dev, int chain)
|
|||
FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) |
|
||||
FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1));
|
||||
|
||||
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);
|
||||
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)
|
||||
void mt7615_mac_init(struct mt7615_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -90,7 +96,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
|
|||
MT_TMAC_CTCR0_INS_DDLMT_EN);
|
||||
|
||||
mt7615_mcu_set_rts_thresh(&dev->phy, 0x92b);
|
||||
mt7615_mac_set_scs(dev, true);
|
||||
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);
|
||||
|
@ -112,15 +118,47 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
|
|||
mt76_wr(dev, MT_DMA_DCR0,
|
||||
FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) |
|
||||
MT_DMA_DCR0_RX_VEC_DROP);
|
||||
/* 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_CSR(0x010), 0x8208);
|
||||
mt76_wr(dev, 0x44064, 0x2000000);
|
||||
mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02);
|
||||
mt76_wr(dev, MT_WF_AGG(0x164), 0x70708040);
|
||||
} else {
|
||||
mt7615_init_mac_chain(dev, 1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_mac_init);
|
||||
|
||||
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->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
|
||||
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_check_offload_capability);
|
||||
|
||||
bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev)
|
||||
{
|
||||
|
@ -128,51 +166,7 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev)
|
|||
|
||||
return test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
|
||||
}
|
||||
|
||||
static void mt7615_init_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(work, struct mt7615_dev, mcu_work);
|
||||
|
||||
if (mt7615_mcu_init(dev))
|
||||
return;
|
||||
|
||||
mt7615_mcu_set_eeprom(dev);
|
||||
mt7615_mac_init(dev);
|
||||
mt7615_phy_init(dev);
|
||||
mt7615_mcu_del_wtbl_all(dev);
|
||||
}
|
||||
|
||||
static int mt7615_init_hardware(struct mt7615_dev *dev)
|
||||
{
|
||||
int ret, idx;
|
||||
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
|
||||
|
||||
INIT_WORK(&dev->mcu_work, mt7615_init_work);
|
||||
spin_lock_init(&dev->token_lock);
|
||||
idr_init(&dev->token);
|
||||
|
||||
ret = mt7615_eeprom_init(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_wait_for_mcu_init);
|
||||
|
||||
#define CCK_RATE(_idx, _rate) { \
|
||||
.bitrate = _rate, \
|
||||
|
@ -187,7 +181,7 @@ static int mt7615_init_hardware(struct mt7615_dev *dev)
|
|||
.hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate mt7615_rates[] = {
|
||||
struct ieee80211_rate mt7615_rates[] = {
|
||||
CCK_RATE(0, 10),
|
||||
CCK_RATE(1, 20),
|
||||
CCK_RATE(2, 55),
|
||||
|
@ -201,6 +195,7 @@ static struct ieee80211_rate mt7615_rates[] = {
|
|||
OFDM_RATE(8, 480),
|
||||
OFDM_RATE(12, 540),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mt7615_rates);
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits[] = {
|
||||
{
|
||||
|
@ -212,6 +207,8 @@ static const struct ieee80211_iface_limit if_limits[] = {
|
|||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_STATION)
|
||||
}
|
||||
};
|
||||
|
@ -226,68 +223,26 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
|||
}
|
||||
};
|
||||
|
||||
static void
|
||||
mt7615_led_set_config(struct led_classdev *led_cdev,
|
||||
u8 delay_on, u8 delay_off)
|
||||
{
|
||||
struct mt7615_dev *dev;
|
||||
struct mt76_dev *mt76;
|
||||
u32 val, addr;
|
||||
|
||||
mt76 = container_of(led_cdev, struct mt76_dev, led_cdev);
|
||||
dev = container_of(mt76, struct mt7615_dev, mt76);
|
||||
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 = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin));
|
||||
mt76_wr(dev, addr, val);
|
||||
addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin));
|
||||
mt76_wr(dev, addr, val);
|
||||
|
||||
val = MT_LED_CTRL_REPLAY(mt76->led_pin) |
|
||||
MT_LED_CTRL_KICK(mt76->led_pin);
|
||||
if (mt76->led_al)
|
||||
val |= MT_LED_CTRL_POLARITY(mt76->led_pin);
|
||||
addr = mt7615_reg_map(dev, MT_LED_CTRL);
|
||||
mt76_wr(dev, addr, val);
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_init_txpower(struct mt7615_dev *dev,
|
||||
struct ieee80211_supported_band *sband)
|
||||
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;
|
||||
int delta = mt76_tx_power_nss_delta(n_chains);
|
||||
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;
|
||||
|
||||
target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
struct ieee80211_channel *chan = &sband->channels[i];
|
||||
u8 target_power = 0;
|
||||
|
@ -296,7 +251,10 @@ mt7615_init_txpower(struct mt7615_dev *dev,
|
|||
for (j = 0; j < target_chains; j++) {
|
||||
int index;
|
||||
|
||||
index = mt7615_eeprom_get_power_index(dev, chan, j);
|
||||
index = mt7615_eeprom_get_target_power_index(dev, chan, j);
|
||||
if (index < 0)
|
||||
continue;
|
||||
|
||||
target_power = max(target_power, eep[index]);
|
||||
}
|
||||
|
||||
|
@ -306,6 +264,7 @@ mt7615_init_txpower(struct mt7615_dev *dev,
|
|||
chan->orig_mpwr = target_power;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_init_txpower);
|
||||
|
||||
static void
|
||||
mt7615_regd_notifier(struct wiphy *wiphy,
|
||||
|
@ -345,8 +304,18 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
|
|||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
wiphy->reg_notifier = mt7615_regd_notifier;
|
||||
|
||||
wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL;
|
||||
wiphy->max_sched_scan_ie_len = IEEE80211_MAX_DATA_LEN;
|
||||
wiphy->max_scan_ie_len = MT7615_SCAN_IE_LEN;
|
||||
wiphy->max_sched_scan_ssids = MT7615_MAX_SCHED_SCAN_SSID;
|
||||
wiphy->max_match_sets = MT7615_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);
|
||||
|
||||
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
|
||||
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
|
||||
|
||||
if (is_mt7615(&phy->dev->mt76))
|
||||
|
@ -368,7 +337,7 @@ mt7615_cap_dbdc_enable(struct mt7615_dev *dev)
|
|||
dev->phy.chainmask = dev->mphy.antenna_mask;
|
||||
dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask;
|
||||
dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
|
||||
mt76_set_stream_caps(&dev->mt76, true);
|
||||
mt76_set_stream_caps(&dev->mphy, true);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -381,7 +350,7 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev)
|
|||
dev->phy.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->mt76, true);
|
||||
mt76_set_stream_caps(&dev->mphy, true);
|
||||
}
|
||||
|
||||
int mt7615_register_ext_phy(struct mt7615_dev *dev)
|
||||
|
@ -399,6 +368,12 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
|
|||
if (phy)
|
||||
return 0;
|
||||
|
||||
INIT_DELAYED_WORK(&phy->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->ps_work, mt7615_ps_work);
|
||||
|
||||
mt7615_cap_dbdc_enable(dev);
|
||||
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops);
|
||||
if (!mphy)
|
||||
|
@ -411,6 +386,8 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
|
|||
mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
|
||||
mt7615_init_wiphy(mphy->hw);
|
||||
|
||||
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
|
||||
|
@ -431,6 +408,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_register_ext_phy);
|
||||
|
||||
void mt7615_unregister_ext_phy(struct mt7615_dev *dev)
|
||||
{
|
||||
|
@ -444,6 +422,7 @@ void mt7615_unregister_ext_phy(struct mt7615_dev *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)
|
||||
{
|
||||
|
@ -452,11 +431,15 @@ void mt7615_init_device(struct mt7615_dev *dev)
|
|||
dev->phy.dev = dev;
|
||||
dev->phy.mt76 = &dev->mt76.phy;
|
||||
dev->mt76.phy.priv = &dev->phy;
|
||||
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
|
||||
INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work);
|
||||
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work);
|
||||
skb_queue_head_init(&dev->phy.scan_event_list);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
spin_lock_init(&dev->sta_poll_lock);
|
||||
init_waitqueue_head(&dev->reset_wait);
|
||||
|
||||
INIT_WORK(&dev->reset_work, mt7615_mac_reset_work);
|
||||
INIT_WORK(&dev->phy.ps_work, mt7615_ps_work);
|
||||
|
||||
mt7615_init_wiphy(hw);
|
||||
dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
|
@ -467,62 +450,4 @@ void mt7615_init_device(struct mt7615_dev *dev)
|
|||
mt7615_cap_dbdc_disable(dev);
|
||||
dev->phy.dfs_state = -1;
|
||||
}
|
||||
|
||||
int mt7615_register_device(struct mt7615_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mt7615_init_device(dev);
|
||||
|
||||
/* init led callbacks */
|
||||
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
|
||||
dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness;
|
||||
dev->mt76.led_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, mt7615_rates,
|
||||
ARRAY_SIZE(mt7615_rates));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
|
||||
return mt7615_init_debugfs(dev);
|
||||
}
|
||||
|
||||
void mt7615_unregister_device(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *txwi;
|
||||
bool mcu_running;
|
||||
int id;
|
||||
|
||||
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_dma_cleanup(dev);
|
||||
|
||||
spin_lock_bh(&dev->token_lock);
|
||||
idr_for_each_entry(&dev->token, txwi, id) {
|
||||
mt7615_txp_skb_unmap(&dev->mt76, txwi);
|
||||
if (txwi->skb)
|
||||
dev_kfree_skb_any(txwi->skb);
|
||||
mt76_put_txwi(&dev->mt76, txwi);
|
||||
}
|
||||
spin_unlock_bh(&dev->token_lock);
|
||||
idr_destroy(&dev->token);
|
||||
|
||||
mt76_free_device(&dev->mt76);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_init_device);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -167,6 +167,10 @@ enum tx_phy_bandwidth {
|
|||
|
||||
#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_TXD0_P_IDX BIT(31)
|
||||
#define MT_TXD0_Q_IDX GENMASK(30, 26)
|
||||
#define MT_TXD0_UDP_TCP_SUM BIT(24)
|
||||
|
@ -252,8 +256,11 @@ enum tx_phy_bandwidth {
|
|||
|
||||
#define MT_MSDU_ID_VALID 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)
|
||||
/* mt7663 */
|
||||
#define MT_TXD_LEN_LAST BIT(15)
|
||||
|
||||
struct mt7615_txp_ptr {
|
||||
__le32 buf0;
|
||||
|
@ -393,6 +400,33 @@ enum mt7615_cipher_type {
|
|||
MT_CIPHER_GCMP_256,
|
||||
};
|
||||
|
||||
static inline enum mt7615_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 inline struct mt7615_txp_common *
|
||||
mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
||||
{
|
||||
|
@ -406,4 +440,9 @@ mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
|
|||
return (struct mt7615_txp_common *)(txwi + MT_TXD_SIZE);
|
||||
}
|
||||
|
||||
static inline u32 mt7615_mac_wtbl_addr(struct mt7615_dev *dev, int wcid)
|
||||
{
|
||||
return MT_WTBL_BASE(dev) + wcid * MT_WTBL_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
* Author: Roy Luo <royluo@google.com>
|
||||
* Ryder Lee <ryder.lee@mediatek.com>
|
||||
* Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include "mt7615.h"
|
||||
#include "mcu.h"
|
||||
|
@ -50,19 +49,17 @@ static int mt7615_start(struct ieee80211_hw *hw)
|
|||
mt7615_mac_enable_nf(dev, 1);
|
||||
}
|
||||
|
||||
mt7615_mcu_set_channel_domain(phy);
|
||||
mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
|
||||
|
||||
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
|
||||
if (running)
|
||||
goto out;
|
||||
|
||||
mt7615_mac_reset_counters(dev);
|
||||
|
||||
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
|
||||
ieee80211_queue_delayed_work(hw, &phy->mac_work,
|
||||
MT7615_WATCHDOG_TIME);
|
||||
|
||||
out:
|
||||
if (!running)
|
||||
mt7615_mac_reset_counters(dev);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
|
@ -73,9 +70,13 @@ static void mt7615_stop(struct ieee80211_hw *hw)
|
|||
struct mt7615_dev *dev = mt7615_hw_dev(hw);
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
cancel_work_sync(&phy->ps_work);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
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);
|
||||
|
@ -83,8 +84,6 @@ static void mt7615_stop(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
if (!mt7615_dev_running(dev)) {
|
||||
cancel_delayed_work_sync(&dev->mt76.mac_work);
|
||||
|
||||
mt7615_mcu_set_pm(dev, 0, 1);
|
||||
mt7615_mcu_set_mac_enable(dev, 0, false);
|
||||
}
|
||||
|
@ -157,10 +156,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
|
|||
else
|
||||
mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS;
|
||||
|
||||
ret = mt7615_mcu_add_dev_info(dev, vif, true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dev->vif_mask |= BIT(mvif->idx);
|
||||
dev->omac_mask |= BIT(mvif->omac_idx);
|
||||
phy->omac_mask |= BIT(mvif->omac_idx);
|
||||
|
@ -183,6 +178,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
|
|||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
}
|
||||
|
||||
ret = mt7615_mcu_add_dev_info(dev, vif, true);
|
||||
out:
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
|
@ -218,20 +214,44 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
|
|||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
static void mt7615_init_dfs_state(struct mt7615_phy *phy)
|
||||
{
|
||||
struct mt76_phy *mphy = phy->mt76;
|
||||
struct ieee80211_hw *hw = mphy->hw;
|
||||
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
|
||||
|
||||
if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
return;
|
||||
|
||||
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return;
|
||||
|
||||
if (mphy->chandef.chan->center_freq == chandef->chan->center_freq &&
|
||||
mphy->chandef.width == chandef->width)
|
||||
return;
|
||||
|
||||
phy->dfs_state = -1;
|
||||
}
|
||||
|
||||
static int mt7615_set_channel(struct mt7615_phy *phy)
|
||||
{
|
||||
struct mt7615_dev *dev = phy->dev;
|
||||
bool ext_phy = phy != &dev->phy;
|
||||
int ret;
|
||||
|
||||
cancel_delayed_work_sync(&dev->mt76.mac_work);
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
set_bit(MT76_RESET, &phy->mt76->state);
|
||||
|
||||
phy->dfs_state = -1;
|
||||
mt7615_init_dfs_state(phy);
|
||||
mt76_set_channel(phy->mt76);
|
||||
|
||||
if (is_mt7615(&dev->mt76) && dev->flash_eeprom) {
|
||||
mt7615_mcu_apply_rx_dcoc(phy);
|
||||
mt7615_mcu_apply_tx_dpd(phy);
|
||||
}
|
||||
|
||||
ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
@ -250,11 +270,42 @@ static int mt7615_set_channel(struct mt7615_phy *phy)
|
|||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
mt76_txq_schedule_all(phy->mt76);
|
||||
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
|
||||
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
|
||||
MT7615_WATCHDOG_TIME);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd,
|
||||
struct mt7615_sta *msta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mt7615_wtbl_desc *wd;
|
||||
|
||||
wd = kzalloc(sizeof(*wd), GFP_KERNEL);
|
||||
if (!wd)
|
||||
return -ENOMEM;
|
||||
|
||||
wd->type = MT7615_WTBL_KEY_DESC;
|
||||
wd->sta = msta;
|
||||
|
||||
wd->key.key = kzalloc(key->keylen, GFP_KERNEL);
|
||||
if (!wd->key.key) {
|
||||
kfree(wd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(wd->key.key, key->key, key->keylen);
|
||||
wd->key.cipher = key->cipher;
|
||||
wd->key.keyidx = key->keyidx;
|
||||
wd->key.keylen = key->keylen;
|
||||
wd->key.cmd = cmd;
|
||||
|
||||
list_add_tail(&wd->node, &dev->wd_head);
|
||||
queue_work(dev->mt76.usb.wq, &dev->wtbl_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -303,9 +354,26 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||
mt76_wcid_key_setup(&dev->mt76, wcid,
|
||||
cmd == SET_KEY ? key : NULL);
|
||||
|
||||
if (mt76_is_usb(&dev->mt76))
|
||||
return mt7615_queue_key_update(dev, cmd, msta, key);
|
||||
|
||||
return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
|
||||
}
|
||||
|
||||
void mt7615_ps_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_phy *phy;
|
||||
|
||||
phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
|
||||
ps_work);
|
||||
|
||||
mutex_lock(&phy->dev->mt76.mutex);
|
||||
ieee80211_iterate_active_interfaces(phy->mt76->hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
m7615_mcu_set_ps_iter, phy);
|
||||
mutex_unlock(&phy->dev->mt76.mutex);
|
||||
}
|
||||
|
||||
static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct mt7615_dev *dev = mt7615_hw_dev(hw);
|
||||
|
@ -331,6 +399,14 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
|
|||
mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_PS) {
|
||||
if (hw->conf.flags & IEEE80211_CONF_PS)
|
||||
set_bit(MT76_STATE_PS, &phy->mt76->state);
|
||||
else
|
||||
clear_bit(MT76_STATE_PS, &phy->mt76->state);
|
||||
ieee80211_queue_work(hw, &phy->ps_work);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return ret;
|
||||
|
@ -408,15 +484,12 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
|
|||
u32 changed)
|
||||
{
|
||||
struct mt7615_dev *dev = mt7615_hw_dev(hw);
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC)
|
||||
mt7615_mcu_add_bss_info(dev, vif, info->assoc);
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
int slottime = info->use_short_slot ? 9 : 20;
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
|
||||
if (slottime != phy->slottime) {
|
||||
phy->slottime = slottime;
|
||||
|
@ -425,8 +498,11 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
mt7615_mcu_add_bss_info(dev, vif, info->enable_beacon);
|
||||
mt7615_mcu_add_bss_info(phy, vif, NULL, info->enable_beacon);
|
||||
mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon);
|
||||
|
||||
if (vif->p2p && info->enable_beacon)
|
||||
mt7615_mcu_set_p2p_oppps(hw, vif);
|
||||
}
|
||||
|
||||
if (changed & (BSS_CHANGED_BEACON |
|
||||
|
@ -466,13 +542,19 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
msta->wcid.idx = idx;
|
||||
msta->wcid.ext_phy = mvif->band_idx;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
|
||||
struct mt7615_phy *phy;
|
||||
|
||||
phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy;
|
||||
mt7615_mcu_add_bss_info(phy, vif, sta, true);
|
||||
}
|
||||
mt7615_mac_wtbl_update(dev, idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
mt7615_mcu_sta_add(dev, vif, sta, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_mac_sta_add);
|
||||
|
||||
void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
|
@ -483,12 +565,20 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
|||
mt7615_mcu_sta_add(dev, 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) {
|
||||
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
|
||||
struct mt7615_phy *phy;
|
||||
|
||||
phy = mvif->band_idx ? mt7615_ext_phy(dev) : &dev->phy;
|
||||
mt7615_mcu_add_bss_info(phy, vif, sta, false);
|
||||
}
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove);
|
||||
|
||||
static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
|
@ -694,13 +784,167 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
|
|||
}
|
||||
phy->chainmask = tx_ant;
|
||||
|
||||
mt76_set_stream_caps(&dev->mt76, true);
|
||||
mt76_set_stream_caps(phy->mt76, true);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 mt76_phy *mphy = hw->priv;
|
||||
|
||||
return mt7615_mcu_hw_scan(mphy->priv, vif, req);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt76_phy *mphy = hw->priv;
|
||||
|
||||
mt7615_mcu_cancel_hw_scan(mphy->priv, vif);
|
||||
}
|
||||
|
||||
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 mt76_phy *mphy = hw->priv;
|
||||
int err;
|
||||
|
||||
err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return mt7615_mcu_sched_scan_enable(mphy->priv, vif, true);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt76_phy *mphy = hw->priv;
|
||||
|
||||
return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mt7615_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct mt7615_dev *dev = mt7615_hw_dev(hw);
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
bool ext_phy = phy != &dev->phy;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
cancel_delayed_work_sync(&phy->scan_work);
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
|
||||
mt76_set(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON);
|
||||
|
||||
set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
|
||||
ieee80211_iterate_active_interfaces(hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7615_mcu_set_suspend_iter, phy);
|
||||
|
||||
if (!mt7615_dev_running(dev))
|
||||
err = mt7615_mcu_set_hif_suspend(dev, true);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mt7615_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7615_dev *dev = mt7615_hw_dev(hw);
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
bool running, ext_phy = phy != &dev->phy;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
running = mt7615_dev_running(dev);
|
||||
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
|
||||
if (!running) {
|
||||
int err;
|
||||
|
||||
err = mt7615_mcu_set_hif_suspend(dev, false);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
clear_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
|
||||
ieee80211_iterate_active_interfaces(hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7615_mcu_set_suspend_iter, phy);
|
||||
|
||||
ieee80211_queue_delayed_work(hw, &phy->mac_work,
|
||||
MT7615_WATCHDOG_TIME);
|
||||
mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
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)
|
||||
{
|
||||
mt7615_mcu_update_gtk_rekey(hw, vif, data);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
const struct ieee80211_ops mt7615_ops = {
|
||||
.tx = mt7615_tx,
|
||||
.start = mt7615_start,
|
||||
|
@ -730,32 +974,17 @@ const struct ieee80211_ops mt7615_ops = {
|
|||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = mt7615_suspend,
|
||||
.resume = mt7615_resume,
|
||||
.set_wakeup = mt7615_set_wakeup,
|
||||
.set_rekey_data = mt7615_set_rekey_data,
|
||||
#endif /* CONFIG_PM */
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(mt7615_ops);
|
||||
|
||||
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_LICENSE("Dual BSD/GPL");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -81,7 +81,11 @@ enum {
|
|||
MCU_EVENT_GENERIC = 0x01,
|
||||
MCU_EVENT_ACCESS_REG = 0x02,
|
||||
MCU_EVENT_MT_PATCH_SEM = 0x04,
|
||||
MCU_EVENT_SCAN_DONE = 0x0d,
|
||||
MCU_EVENT_BSS_ABSENCE = 0x11,
|
||||
MCU_EVENT_BSS_BEACON_LOSS = 0x13,
|
||||
MCU_EVENT_CH_PRIVILEGE = 0x18,
|
||||
MCU_EVENT_SCHED_SCAN_DONE = 0x23,
|
||||
MCU_EVENT_EXT = 0xed,
|
||||
MCU_EVENT_RESTART_DL = 0xef,
|
||||
};
|
||||
|
@ -232,7 +236,9 @@ enum {
|
|||
|
||||
#define MCU_FW_PREFIX BIT(31)
|
||||
#define MCU_UNI_PREFIX BIT(30)
|
||||
#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX)
|
||||
#define MCU_CE_PREFIX BIT(29)
|
||||
#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \
|
||||
MCU_CE_PREFIX)
|
||||
|
||||
enum {
|
||||
MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01,
|
||||
|
@ -265,6 +271,8 @@ enum {
|
|||
MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
|
||||
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
|
||||
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
|
||||
MCU_EXT_CMD_RXDCOC_CAL = 0x59,
|
||||
MCU_EXT_CMD_TXDPD_CAL = 0x60,
|
||||
MCU_EXT_CMD_SET_RDD_TH = 0x7c,
|
||||
MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d,
|
||||
};
|
||||
|
@ -273,6 +281,261 @@ enum {
|
|||
MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01,
|
||||
MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02,
|
||||
MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03,
|
||||
MCU_UNI_CMD_SUSPEND = MCU_UNI_PREFIX | 0x05,
|
||||
MCU_UNI_CMD_OFFLOAD = MCU_UNI_PREFIX | 0x06,
|
||||
MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07,
|
||||
};
|
||||
|
||||
struct mt7615_mcu_uni_event {
|
||||
u8 cid;
|
||||
u8 pad[3];
|
||||
__le32 status; /* 0: success, others: fail */
|
||||
} __packed;
|
||||
|
||||
struct mt7615_beacon_loss_event {
|
||||
u8 bss_idx;
|
||||
u8 reason;
|
||||
u8 pad[2];
|
||||
} __packed;
|
||||
|
||||
struct mt7615_mcu_scan_ssid {
|
||||
__le32 ssid_len;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
} __packed;
|
||||
|
||||
struct mt7615_mcu_scan_channel {
|
||||
u8 band; /* 1: 2.4GHz
|
||||
* 2: 5.0GHz
|
||||
* Others: Reserved
|
||||
*/
|
||||
u8 channel_num;
|
||||
} __packed;
|
||||
|
||||
struct mt7615_mcu_scan_match {
|
||||
__le32 rssi_th;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
u8 rsv[3];
|
||||
} __packed;
|
||||
|
||||
struct mt7615_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
|
||||
*/
|
||||
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 mt7615_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 mt7615_mcu_scan_channel channels[32];
|
||||
__le16 ies_len;
|
||||
u8 ies[MT7615_SCAN_IE_LEN];
|
||||
/* following fields are valid if version > 0 */
|
||||
u8 ext_channels_num;
|
||||
u8 ext_ssids_num;
|
||||
__le16 channel_min_dwell_time;
|
||||
struct mt7615_mcu_scan_channel ext_channels[32];
|
||||
struct mt7615_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[64];
|
||||
} __packed;
|
||||
|
||||
#define SCAN_DONE_EVENT_MAX_CHANNEL_NUM 64
|
||||
struct mt7615_hw_scan_done {
|
||||
u8 seq_num;
|
||||
u8 sparse_channel_num;
|
||||
struct mt7615_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[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[SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
|
||||
/* beacon and probe response count */
|
||||
u8 beacon_probe_num[SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
|
||||
u8 mdrdy_count[SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
|
||||
__le32 beacon_2g_num;
|
||||
__le32 beacon_5g_num;
|
||||
} __packed;
|
||||
|
||||
struct mt7615_sched_scan_req {
|
||||
u8 version;
|
||||
u8 seq_num;
|
||||
u8 stop_on_match;
|
||||
u8 ssids_num;
|
||||
u8 match_num;
|
||||
u8 pad;
|
||||
__le16 ie_len;
|
||||
struct mt7615_mcu_scan_ssid ssids[MT7615_MAX_SCHED_SCAN_SSID];
|
||||
struct mt7615_mcu_scan_match match[MT7615_MAX_SCAN_MATCH];
|
||||
u8 channel_type;
|
||||
u8 channels_num;
|
||||
u8 intervals_num;
|
||||
u8 scan_func; /* BIT(0) eable random mac address */
|
||||
struct mt7615_mcu_scan_channel channels[64];
|
||||
__le16 intervals[MT7615_MAX_SCHED_SCAN_INTERVAL];
|
||||
u8 random_mac[ETH_ALEN]; /* valid when BIT(0) in scan_func is set */
|
||||
u8 pad2[58];
|
||||
} __packed;
|
||||
|
||||
struct nt7615_sched_scan_done {
|
||||
u8 seq_num;
|
||||
u8 status; /* 0: ssid found */
|
||||
__le16 pad;
|
||||
} __packed;
|
||||
|
||||
struct mt7615_mcu_bss_event {
|
||||
u8 bss_idx;
|
||||
u8 is_absent;
|
||||
u8 free_quota;
|
||||
u8 pad;
|
||||
} __packed;
|
||||
|
||||
struct mt7615_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
|
||||
*/
|
||||
__le16 sta_idx;
|
||||
u8 nonht_basic_phy;
|
||||
u8 pad[3];
|
||||
} __packed;
|
||||
|
||||
struct mt7615_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;
|
||||
|
||||
#define MT7615_WOW_MASK_MAX_LEN 16
|
||||
#define MT7615_WOW_PATTEN_MAX_LEN 128
|
||||
struct mt7615_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[MT7615_WOW_MASK_MAX_LEN];
|
||||
u8 pattern[MT7615_WOW_PATTEN_MAX_LEN];
|
||||
u8 rsv[4];
|
||||
} __packed;
|
||||
|
||||
struct mt7615_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;
|
||||
|
||||
struct mt7615_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 pad[2];
|
||||
__le32 proto; /* WPA-RSN-WAPI-OPSN */
|
||||
__le32 pairwise_cipher;
|
||||
__le32 group_cipher;
|
||||
__le32 key_mgmt; /* NONE-PSK-IEEE802.1X */
|
||||
__le32 mgmt_group_cipher;
|
||||
u8 option; /* 1: rekey data update without enabling offload */
|
||||
u8 reserverd[3];
|
||||
} __packed;
|
||||
|
||||
/* offload mcu commands */
|
||||
enum {
|
||||
MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03,
|
||||
MCU_CMD_SET_PS_PROFILE = MCU_CE_PREFIX | 0x05,
|
||||
MCU_CMD_SET_CHAN_DOMAIN = MCU_CE_PREFIX | 0x0f,
|
||||
MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16,
|
||||
MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17,
|
||||
MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b,
|
||||
MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33,
|
||||
MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61,
|
||||
MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62,
|
||||
};
|
||||
|
||||
#define MCU_CMD_ACK BIT(0)
|
||||
|
@ -283,9 +546,25 @@ enum {
|
|||
|
||||
enum {
|
||||
UNI_BSS_INFO_BASIC = 0,
|
||||
UNI_BSS_INFO_RLM = 2,
|
||||
UNI_BSS_INFO_BCN_CONTENT = 7,
|
||||
};
|
||||
|
||||
enum {
|
||||
UNI_SUSPEND_MODE_SETTING,
|
||||
UNI_SUSPEND_WOW_CTRL,
|
||||
UNI_SUSPEND_WOW_GPIO_PARAM,
|
||||
UNI_SUSPEND_WOW_WAKEUP_PORT,
|
||||
UNI_SUSPEND_WOW_PATTERN,
|
||||
};
|
||||
|
||||
enum {
|
||||
UNI_OFFLOAD_OFFLOAD_ARPNS_IPV4,
|
||||
UNI_OFFLOAD_OFFLOAD_ARPNS_IPV6,
|
||||
UNI_OFFLOAD_OFFLOAD_GTK_REKEY,
|
||||
UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT,
|
||||
};
|
||||
|
||||
enum {
|
||||
PATCH_SEM_RELEASE = 0x0,
|
||||
PATCH_SEM_GET = 0x1
|
||||
|
@ -306,6 +585,11 @@ enum {
|
|||
FW_STATE_CR4_RDY = 7
|
||||
};
|
||||
|
||||
enum {
|
||||
FW_STATE_PWR_ON = 1,
|
||||
FW_STATE_N9_RDY = 2,
|
||||
};
|
||||
|
||||
#define STA_TYPE_STA BIT(0)
|
||||
#define STA_TYPE_AP BIT(1)
|
||||
#define STA_TYPE_ADHOC BIT(2)
|
||||
|
@ -704,11 +988,4 @@ enum {
|
|||
CH_SWITCH_SCAN_BYPASS_DPD = 9
|
||||
};
|
||||
|
||||
static inline struct sk_buff *
|
||||
mt7615_mcu_msg_alloc(const void *data, int len)
|
||||
{
|
||||
return mt76_mcu_msg_alloc(data, sizeof(struct mt7615_mcu_txd),
|
||||
len, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "mt7615.h"
|
||||
#include "regs.h"
|
||||
|
@ -13,12 +15,15 @@ const u32 mt7615e_reg_map[] = {
|
|||
[MT_ARB_BASE] = 0x20c00,
|
||||
[MT_HIF_BASE] = 0x04000,
|
||||
[MT_CSR_BASE] = 0x07000,
|
||||
[MT_PLE_BASE] = 0x08000,
|
||||
[MT_PSE_BASE] = 0x0c000,
|
||||
[MT_PHY_BASE] = 0x10000,
|
||||
[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,
|
||||
|
@ -37,12 +42,15 @@ const u32 mt7663e_reg_map[] = {
|
|||
[MT_ARB_BASE] = 0x20c00,
|
||||
[MT_HIF_BASE] = 0x04000,
|
||||
[MT_CSR_BASE] = 0x07000,
|
||||
[MT_PLE_BASE] = 0x08000,
|
||||
[MT_PSE_BASE] = 0x0c000,
|
||||
[MT_PHY_BASE] = 0x10000,
|
||||
[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,
|
||||
|
@ -80,30 +88,42 @@ mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
|
|||
static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
|
||||
{
|
||||
struct mt7615_dev *dev = dev_instance;
|
||||
u32 intr;
|
||||
|
||||
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
|
||||
return IRQ_NONE;
|
||||
|
||||
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
|
||||
tasklet_schedule(&dev->irq_tasklet);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void mt7615_irq_tasklet(unsigned long data)
|
||||
{
|
||||
struct mt7615_dev *dev = (struct mt7615_dev *)data;
|
||||
u32 intr, mask = 0;
|
||||
|
||||
mt76_wr(dev, MT_INT_MASK_CSR, 0);
|
||||
|
||||
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
|
||||
|
||||
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
|
||||
intr &= dev->mt76.mmio.irqmask;
|
||||
|
||||
if (intr & MT_INT_TX_DONE_ALL) {
|
||||
mt7615_irq_disable(dev, MT_INT_TX_DONE_ALL);
|
||||
mask |= MT_INT_TX_DONE_ALL;
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE(0)) {
|
||||
mt7615_irq_disable(dev, MT_INT_RX_DONE(0));
|
||||
mask |= MT_INT_RX_DONE(0);
|
||||
napi_schedule(&dev->mt76.napi[0]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE(1)) {
|
||||
mt7615_irq_disable(dev, MT_INT_RX_DONE(1));
|
||||
mask |= MT_INT_RX_DONE(1);
|
||||
napi_schedule(&dev->mt76.napi[1]);
|
||||
}
|
||||
|
||||
|
@ -117,7 +137,7 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
|
|||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
}
|
||||
|
||||
int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
|
||||
|
@ -139,18 +159,25 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
|
|||
.sta_remove = mt7615_mac_sta_remove,
|
||||
.update_survey = mt7615_update_channel,
|
||||
};
|
||||
struct ieee80211_ops *ops;
|
||||
struct mt7615_dev *dev;
|
||||
struct mt76_dev *mdev;
|
||||
int ret;
|
||||
|
||||
mdev = mt76_alloc_device(pdev, sizeof(*dev), &mt7615_ops, &drv_ops);
|
||||
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_init(&dev->irq_tasklet, mt7615_irq_tasklet, (unsigned long)dev);
|
||||
|
||||
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);
|
||||
|
@ -172,3 +199,31 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
|
|||
ieee80211_free_hw(mt76_hw(dev));
|
||||
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_LICENSE("Dual BSD/GPL");
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
|
||||
#define MT7615_MAX_INTERFACES 4
|
||||
#define MT7615_MAX_WMM_SETS 4
|
||||
#define MT7663_WTBL_SIZE 32
|
||||
#define MT7615_WTBL_SIZE 128
|
||||
#define MT7615_WTBL_RESERVED (MT7615_WTBL_SIZE - 1)
|
||||
#define MT7615_WTBL_RESERVED (mt7615_wtbl_size(dev) - 1)
|
||||
#define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \
|
||||
MT7615_MAX_INTERFACES)
|
||||
|
||||
#define MT7615_WATCHDOG_TIME (HZ / 10)
|
||||
#define MT7615_HW_SCAN_TIMEOUT (HZ / 10)
|
||||
#define MT7615_RESET_TIMEOUT (30 * HZ)
|
||||
#define MT7615_RATE_RETRY 2
|
||||
|
||||
|
@ -40,8 +42,10 @@
|
|||
#define MT7615_FIRMWARE_V2 2
|
||||
#define MT7615_FIRMWARE_V3 3
|
||||
|
||||
#define MT7663_ROM_PATCH "mediatek/mt7663pr2h_v3.bin"
|
||||
#define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin"
|
||||
#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 MT7615_TOKEN_SIZE 4096
|
||||
|
@ -57,10 +61,16 @@
|
|||
#define MT7615_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
|
||||
#define MT7615_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
|
||||
|
||||
#define MT7615_SCAN_IE_LEN 600
|
||||
#define MT7615_MAX_SCHED_SCAN_INTERVAL 10
|
||||
#define MT7615_MAX_SCHED_SCAN_SSID 10
|
||||
#define MT7615_MAX_SCAN_MATCH 16
|
||||
|
||||
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,
|
||||
|
@ -84,6 +94,39 @@ struct mt7615_rate_set {
|
|||
struct ieee80211_tx_rate rates[4];
|
||||
};
|
||||
|
||||
struct mt7615_rate_desc {
|
||||
bool rateset;
|
||||
u16 probe_val;
|
||||
u16 val[4];
|
||||
u8 bw_idx;
|
||||
u8 bw;
|
||||
};
|
||||
|
||||
enum mt7615_wtbl_desc_type {
|
||||
MT7615_WTBL_RATE_DESC,
|
||||
MT7615_WTBL_KEY_DESC
|
||||
};
|
||||
|
||||
struct mt7615_key_desc {
|
||||
enum set_key_cmd cmd;
|
||||
u32 cipher;
|
||||
s8 keyidx;
|
||||
u8 keylen;
|
||||
u8 *key;
|
||||
};
|
||||
|
||||
struct mt7615_wtbl_desc {
|
||||
struct list_head node;
|
||||
|
||||
enum mt7615_wtbl_desc_type type;
|
||||
struct mt7615_sta *sta;
|
||||
|
||||
union {
|
||||
struct mt7615_rate_desc rate;
|
||||
struct mt7615_key_desc key;
|
||||
};
|
||||
};
|
||||
|
||||
struct mt7615_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
|
@ -108,15 +151,18 @@ struct mt7615_vif {
|
|||
u8 omac_idx;
|
||||
u8 band_idx;
|
||||
u8 wmm_idx;
|
||||
u8 scan_seq_num;
|
||||
|
||||
struct mt7615_sta sta;
|
||||
};
|
||||
|
||||
struct mib_stats {
|
||||
u32 ack_fail_cnt;
|
||||
u32 fcs_err_cnt;
|
||||
u32 rts_cnt;
|
||||
u32 rts_retries_cnt;
|
||||
u16 ack_fail_cnt;
|
||||
u16 fcs_err_cnt;
|
||||
u16 rts_cnt;
|
||||
u16 rts_retries_cnt;
|
||||
u16 ba_miss_cnt;
|
||||
unsigned long aggr_per;
|
||||
};
|
||||
|
||||
struct mt7615_phy {
|
||||
|
@ -128,6 +174,8 @@ struct mt7615_phy {
|
|||
|
||||
u16 noise;
|
||||
|
||||
bool scs_en;
|
||||
|
||||
unsigned long last_cca_adj;
|
||||
int false_cca_ofdm, false_cca_cck;
|
||||
s8 ofdm_sensitivity;
|
||||
|
@ -146,13 +194,21 @@ struct mt7615_phy {
|
|||
u32 ampdu_ref;
|
||||
|
||||
struct mib_stats mib;
|
||||
|
||||
struct delayed_work mac_work;
|
||||
u8 mac_work_count;
|
||||
|
||||
struct sk_buff_head scan_event_list;
|
||||
struct delayed_work scan_work;
|
||||
|
||||
struct work_struct ps_work;
|
||||
};
|
||||
|
||||
#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(dev, ...) (dev)->mcu_ops->sta_add((dev), __VA_ARGS__)
|
||||
#define mt7615_mcu_add_dev_info(dev, ...) (dev)->mcu_ops->add_dev_info((dev), __VA_ARGS__)
|
||||
#define mt7615_mcu_add_bss_info(dev, ...) (dev)->mcu_ops->add_bss_info((dev), __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__)
|
||||
struct mt7615_mcu_ops {
|
||||
|
@ -167,8 +223,8 @@ struct mt7615_mcu_ops {
|
|||
struct ieee80211_sta *sta, bool enable);
|
||||
int (*add_dev_info)(struct mt7615_dev *dev,
|
||||
struct ieee80211_vif *vif, bool enable);
|
||||
int (*add_bss_info)(struct mt7615_dev *dev, 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);
|
||||
|
@ -181,12 +237,15 @@ struct mt7615_dev {
|
|||
struct mt76_phy mphy;
|
||||
};
|
||||
|
||||
struct tasklet_struct irq_tasklet;
|
||||
|
||||
struct mt7615_phy phy;
|
||||
u32 vif_mask;
|
||||
u32 omac_mask;
|
||||
|
||||
u16 chainmask;
|
||||
|
||||
struct ieee80211_ops *ops;
|
||||
const struct mt7615_mcu_ops *mcu_ops;
|
||||
struct regmap *infracfg;
|
||||
const u32 *reg_map;
|
||||
|
@ -208,14 +267,16 @@ struct mt7615_dev {
|
|||
} radar_pattern;
|
||||
u32 hw_pattern;
|
||||
|
||||
u8 mac_work_count;
|
||||
bool scs_en;
|
||||
bool fw_debug;
|
||||
bool flash_eeprom;
|
||||
|
||||
spinlock_t token_lock;
|
||||
struct idr token;
|
||||
|
||||
u8 fw_ver;
|
||||
|
||||
struct work_struct wtbl_work;
|
||||
struct list_head wd_head;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -289,6 +350,7 @@ mt7615_ext_phy(struct mt7615_dev *dev)
|
|||
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];
|
||||
|
@ -308,15 +370,19 @@ 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);
|
||||
|
||||
void mt7615_check_offload_capability(struct mt7615_dev *dev);
|
||||
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);
|
||||
int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx);
|
||||
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_cleanup(struct mt7615_dev *dev);
|
||||
int mt7615_mcu_init(struct mt7615_dev *dev);
|
||||
|
@ -355,19 +421,38 @@ static inline bool is_mt7663(struct mt76_dev *dev)
|
|||
|
||||
static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask)
|
||||
{
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
|
||||
mt76_set_irq_mask(&dev->mt76, 0, 0, mask);
|
||||
|
||||
tasklet_schedule(&dev->irq_tasklet);
|
||||
}
|
||||
|
||||
static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
|
||||
static inline bool mt7615_firmware_offload(struct mt7615_dev *dev)
|
||||
{
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
void mt7615_dma_reset(struct mt7615_dev *dev);
|
||||
void mt7615_scan_work(struct work_struct *work);
|
||||
void mt7615_ps_work(struct work_struct *work);
|
||||
void mt7615_init_txpower(struct mt7615_dev *dev,
|
||||
struct ieee80211_supported_band *sband);
|
||||
void mt7615_phy_init(struct mt7615_dev *dev);
|
||||
void mt7615_mac_init(struct mt7615_dev *dev);
|
||||
|
||||
int mt7615_mcu_restart(struct mt76_dev *dev);
|
||||
void mt7615_update_channel(struct mt76_dev *mdev);
|
||||
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask);
|
||||
void mt7615_mac_reset_counters(struct mt7615_dev *dev);
|
||||
void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy);
|
||||
void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable);
|
||||
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_sta_poll(struct mt7615_dev *dev);
|
||||
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
|
||||
|
@ -375,15 +460,27 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
|
|||
struct ieee80211_sta *sta, int pid,
|
||||
struct ieee80211_key_conf *key, bool beacon);
|
||||
void mt7615_mac_set_timing(struct mt7615_phy *phy);
|
||||
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb);
|
||||
void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data);
|
||||
void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb);
|
||||
int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key,
|
||||
enum set_key_cmd cmd);
|
||||
int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev,
|
||||
struct mt76_wcid *wcid,
|
||||
enum mt7615_cipher_type cipher,
|
||||
int keyidx, enum set_key_cmd cmd);
|
||||
void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
|
||||
struct mt76_wcid *wcid,
|
||||
enum mt7615_cipher_type cipher,
|
||||
enum set_key_cmd cmd);
|
||||
int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
|
||||
struct mt76_wcid *wcid,
|
||||
u8 *key, u8 keylen,
|
||||
enum mt7615_cipher_type cipher,
|
||||
enum set_key_cmd cmd);
|
||||
void mt7615_mac_reset_work(struct work_struct *work);
|
||||
|
||||
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
|
||||
int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
|
||||
int len, bool wait_resp);
|
||||
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
|
||||
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
|
||||
int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable);
|
||||
|
@ -392,6 +489,17 @@ int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index);
|
|||
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_mcu_set_channel_domain(struct mt7615_phy *phy);
|
||||
int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif,
|
||||
struct ieee80211_scan_request *scan_req);
|
||||
int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy,
|
||||
struct ieee80211_vif *vif);
|
||||
int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_sched_scan_request *sreq);
|
||||
int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
|
||||
struct ieee80211_vif *vif,
|
||||
bool enable);
|
||||
|
||||
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
enum mt76_txq_id qid, struct mt76_wcid *wcid,
|
||||
|
@ -417,8 +525,31 @@ int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
|
|||
int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
|
||||
const struct mt7615_dfs_pattern *pattern);
|
||||
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);
|
||||
void m7615_mcu_set_ps_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
|
||||
int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy);
|
||||
|
||||
int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
int mt7615_firmware_own(struct mt7615_dev *dev);
|
||||
int mt7615_driver_own(struct mt7615_dev *dev);
|
||||
|
||||
int mt7615_init_debugfs(struct mt7615_dev *dev);
|
||||
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
|
||||
|
||||
int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend);
|
||||
void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac,
|
||||
struct ieee80211_vif *vif);
|
||||
int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_gtk_rekey_data *key);
|
||||
|
||||
int __mt7663_load_firmware(struct mt7615_dev *dev);
|
||||
|
||||
/* usb */
|
||||
void mt7663u_wtbl_work(struct work_struct *work);
|
||||
int mt7663u_mcu_init(struct mt7615_dev *dev);
|
||||
int mt7663u_register_device(struct mt7615_dev *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,13 +33,27 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
mt76_pci_disable_aspm(pdev);
|
||||
|
||||
map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map;
|
||||
return mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
|
||||
pdev->irq, 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)
|
||||
|
@ -48,18 +62,130 @@ static void mt7615_pci_remove(struct pci_dev *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;
|
||||
|
||||
hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
|
||||
mt7615_firmware_offload(dev);
|
||||
if (hif_suspend) {
|
||||
err = mt7615_mcu_set_hif_suspend(dev, true);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
napi_disable(&mdev->tx_napi);
|
||||
tasklet_kill(&mdev->tx_tasklet);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++)
|
||||
napi_disable(&mdev->napi[i]);
|
||||
tasklet_kill(&dev->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_firmware_own(dev);
|
||||
if (err)
|
||||
goto restore;
|
||||
|
||||
return 0;
|
||||
|
||||
restore:
|
||||
for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++)
|
||||
napi_enable(&mdev->napi[i]);
|
||||
napi_enable(&mdev->tx_napi);
|
||||
if (hif_suspend)
|
||||
mt7615_mcu_set_hif_suspend(dev, false);
|
||||
|
||||
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_driver_own(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");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mdev->q_rx); i++) {
|
||||
napi_enable(&mdev->napi[i]);
|
||||
napi_schedule(&mdev->napi[i]);
|
||||
}
|
||||
napi_enable(&mdev->tx_napi);
|
||||
napi_schedule(&mdev->tx_napi);
|
||||
|
||||
if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) &&
|
||||
mt7615_firmware_offload(dev))
|
||||
err = mt7615_mcu_set_hif_suspend(dev, false);
|
||||
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2019 MediaTek Inc.
|
||||
*
|
||||
* Author: Roy Luo <royluo@google.com>
|
||||
* Ryder Lee <ryder.lee@mediatek.com>
|
||||
* Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "mt7615.h"
|
||||
#include "mac.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
static void mt7615_init_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(work, struct mt7615_dev,
|
||||
mcu_work);
|
||||
|
||||
if (mt7615_mcu_init(dev))
|
||||
return;
|
||||
|
||||
mt7615_mcu_set_eeprom(dev);
|
||||
mt7615_mac_init(dev);
|
||||
mt7615_phy_init(dev);
|
||||
mt7615_mcu_del_wtbl_all(dev);
|
||||
mt7615_check_offload_capability(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_init_work);
|
||||
spin_lock_init(&dev->token_lock);
|
||||
idr_init(&dev->token);
|
||||
|
||||
ret = mt7615_eeprom_init(dev, addr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_led_set_config(struct led_classdev *led_cdev,
|
||||
u8 delay_on, u8 delay_off)
|
||||
{
|
||||
struct mt7615_dev *dev;
|
||||
struct mt76_dev *mt76;
|
||||
u32 val, addr;
|
||||
|
||||
mt76 = container_of(led_cdev, struct mt76_dev, led_cdev);
|
||||
dev = container_of(mt76, struct mt7615_dev, mt76);
|
||||
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 = mt7615_reg_map(dev, MT_LED_STATUS_0(mt76->led_pin));
|
||||
mt76_wr(dev, addr, val);
|
||||
addr = mt7615_reg_map(dev, MT_LED_STATUS_1(mt76->led_pin));
|
||||
mt76_wr(dev, addr, val);
|
||||
|
||||
val = MT_LED_CTRL_REPLAY(mt76->led_pin) |
|
||||
MT_LED_CTRL_KICK(mt76->led_pin);
|
||||
if (mt76->led_al)
|
||||
val |= MT_LED_CTRL_POLARITY(mt76->led_pin);
|
||||
addr = mt7615_reg_map(dev, MT_LED_CTRL);
|
||||
mt76_wr(dev, addr, val);
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
int mt7615_register_device(struct mt7615_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mt7615_init_device(dev);
|
||||
|
||||
/* init led callbacks */
|
||||
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
|
||||
dev->mt76.led_cdev.brightness_set = mt7615_led_set_brightness;
|
||||
dev->mt76.led_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, mt7615_rates,
|
||||
ARRAY_SIZE(mt7615_rates));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
|
||||
return mt7615_init_debugfs(dev);
|
||||
}
|
||||
|
||||
void mt7615_unregister_device(struct mt7615_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *txwi;
|
||||
bool mcu_running;
|
||||
int id;
|
||||
|
||||
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_dma_cleanup(dev);
|
||||
|
||||
spin_lock_bh(&dev->token_lock);
|
||||
idr_for_each_entry(&dev->token, txwi, id) {
|
||||
mt7615_txp_skb_unmap(&dev->mt76, txwi);
|
||||
if (txwi->skb)
|
||||
dev_kfree_skb_any(txwi->skb);
|
||||
mt76_put_txwi(&dev->mt76, txwi);
|
||||
}
|
||||
spin_unlock_bh(&dev->token_lock);
|
||||
idr_destroy(&dev->token);
|
||||
|
||||
tasklet_disable(&dev->irq_tasklet);
|
||||
|
||||
mt76_free_device(&dev->mt76);
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc.
|
||||
*
|
||||
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
||||
* Roy Luo <royluo@google.com>
|
||||
* Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/timekeeping.h>
|
||||
|
||||
#include "mt7615.h"
|
||||
#include "../dma.h"
|
||||
#include "mac.h"
|
||||
|
||||
void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
{
|
||||
if (!e->txwi) {
|
||||
dev_kfree_skb_any(e->skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* error path */
|
||||
if (e->skb == DMA_DUMMY_DATA) {
|
||||
struct mt76_txwi_cache *t;
|
||||
struct mt7615_dev *dev;
|
||||
struct mt7615_txp_common *txp;
|
||||
u16 token;
|
||||
|
||||
dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
txp = mt7615_txwi_to_txp(mdev, e->txwi);
|
||||
|
||||
if (is_mt7615(&dev->mt76))
|
||||
token = le16_to_cpu(txp->fw.token);
|
||||
else
|
||||
token = le16_to_cpu(txp->hw.msdu_id[0]) &
|
||||
~MT_MSDU_ID_VALID;
|
||||
|
||||
spin_lock_bh(&dev->token_lock);
|
||||
t = idr_remove(&dev->token, token);
|
||||
spin_unlock_bh(&dev->token_lock);
|
||||
e->skb = t ? t->skb : NULL;
|
||||
}
|
||||
|
||||
if (e->skb)
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info,
|
||||
void *txp_ptr, u32 id)
|
||||
{
|
||||
struct mt7615_hw_txp *txp = txp_ptr;
|
||||
struct mt7615_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->mt76))
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 mt7615_fw_txp *txp = txp_ptr;
|
||||
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->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 mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
|
||||
|
||||
txp->bss_idx = mvif->idx;
|
||||
}
|
||||
|
||||
txp->token = cpu_to_le16(id);
|
||||
txp->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 mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid);
|
||||
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;
|
||||
void *txp;
|
||||
|
||||
if (!wcid)
|
||||
wcid = &dev->mt76.global_wcid;
|
||||
|
||||
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
|
||||
struct mt7615_phy *phy = &dev->phy;
|
||||
|
||||
if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && mdev->phy2)
|
||||
phy = mdev->phy2->priv;
|
||||
|
||||
spin_lock_bh(&dev->mt76.lock);
|
||||
mt7615_mac_set_rates(phy, msta, &info->control.rates[0],
|
||||
msta->rates);
|
||||
msta->rate_probe = true;
|
||||
spin_unlock_bh(&dev->mt76.lock);
|
||||
}
|
||||
|
||||
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
|
||||
t->skb = tx_info->skb;
|
||||
|
||||
spin_lock_bh(&dev->token_lock);
|
||||
id = idr_alloc(&dev->token, t, 0, MT7615_TOKEN_SIZE, GFP_ATOMIC);
|
||||
spin_unlock_bh(&dev->token_lock);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta,
|
||||
pid, key, false);
|
||||
|
||||
txp = txwi + MT_TXD_SIZE;
|
||||
memset(txp, 0, sizeof(struct mt7615_txp_common));
|
||||
if (is_mt7615(&dev->mt76))
|
||||
mt7615_write_fw_txp(dev, tx_info, txp, id);
|
||||
else
|
||||
mt7615_write_hw_txp(dev, tx_info, txp, id);
|
||||
|
||||
tx_info->skb = DMA_DUMMY_DATA;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -12,12 +12,15 @@ enum mt7615_reg_base {
|
|||
MT_ARB_BASE,
|
||||
MT_HIF_BASE,
|
||||
MT_CSR_BASE,
|
||||
MT_PLE_BASE,
|
||||
MT_PSE_BASE,
|
||||
MT_PHY_BASE,
|
||||
MT_CFG_BASE,
|
||||
MT_AGG_BASE,
|
||||
MT_TMAC_BASE,
|
||||
MT_RMAC_BASE,
|
||||
MT_DMA_BASE,
|
||||
MT_PF_BASE,
|
||||
MT_WTBL_BASE_ON,
|
||||
MT_WTBL_BASE_OFF,
|
||||
MT_LPON_BASE,
|
||||
|
@ -43,6 +46,7 @@ enum mt7615_reg_base {
|
|||
#define MT_TOP_MISC2_FW_STATE GENMASK(2, 0)
|
||||
|
||||
#define MT7663_TOP_MISC2_FW_STATE GENMASK(3, 1)
|
||||
#define MT_TOP_MISC2_FW_PWR_ON BIT(1)
|
||||
|
||||
#define MT_MCU_BASE 0x2000
|
||||
#define MT_MCU(ofs) (MT_MCU_BASE + (ofs))
|
||||
|
@ -58,6 +62,19 @@ enum mt7615_reg_base {
|
|||
#define MT_PCIE_REMAP_BASE_2 ((dev)->reg_map[MT_PCIE_REMAP_BASE2])
|
||||
|
||||
#define MT_HIF(ofs) ((dev)->reg_map[MT_HIF_BASE] + (ofs))
|
||||
#define MT_HIF_RST MT_HIF(0x100)
|
||||
#define MT_HIF_LOGIC_RST_N BIT(4)
|
||||
|
||||
#define MT_PDMA_SLP_PROT MT_HIF(0x154)
|
||||
#define MT_PDMA_AXI_SLPPROT_ENABLE BIT(0)
|
||||
#define MT_PDMA_AXI_SLPPROT_RDY BIT(16)
|
||||
|
||||
#define MT_PDMA_BUSY_STATUS MT_HIF(0x168)
|
||||
#define MT_PDMA_TX_IDX_BUSY BIT(2)
|
||||
#define MT_PDMA_BUSY_IDX BIT(31)
|
||||
|
||||
#define MT_WPDMA_TX_RING0_CTRL0 MT_HIF(0x300)
|
||||
#define MT_WPDMA_TX_RING0_CTRL1 MT_HIF(0x304)
|
||||
|
||||
#define MT7663_MCU_PCIE_REMAP_2_OFFSET GENMASK(15, 0)
|
||||
#define MT7663_MCU_PCIE_REMAP_2_BASE GENMASK(31, 16)
|
||||
|
@ -65,6 +82,7 @@ enum mt7615_reg_base {
|
|||
#define MT_HIF2_BASE 0xf0000
|
||||
#define MT_HIF2(ofs) (MT_HIF2_BASE + (ofs))
|
||||
#define MT_PCIE_IRQ_ENABLE MT_HIF2(0x188)
|
||||
#define MT_PCIE_DOORBELL_PUSH MT_HIF2(0x1484)
|
||||
|
||||
#define MT_CFG_LPCR_HOST MT_HIF(0x1f0)
|
||||
#define MT_CFG_LPCR_HOST_FW_OWN BIT(0)
|
||||
|
@ -133,8 +151,7 @@ enum mt7615_reg_base {
|
|||
#define MT_CSR(ofs) ((dev)->reg_map[MT_CSR_BASE] + (ofs))
|
||||
#define MT_CONN_HIF_ON_LPCTL MT_CSR(0x000)
|
||||
|
||||
#define MT_PLE_BASE 0x8000
|
||||
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
|
||||
#define MT_PLE(ofs) ((dev)->reg_map[MT_PLE_BASE] + (ofs))
|
||||
|
||||
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
|
||||
#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
|
||||
|
@ -144,6 +161,14 @@ enum mt7615_reg_base {
|
|||
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
|
||||
((n) << 2))
|
||||
|
||||
#define MT_PSE(ofs) ((dev)->reg_map[MT_PSE_BASE] + (ofs))
|
||||
#define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b4)
|
||||
#define MT_HIF_0_EMPTY_MASK BIT(16)
|
||||
#define MT_HIF_1_EMPTY_MASK BIT(17)
|
||||
#define MT_HIF_ALL_EMPTY_MASK GENMASK(17, 16)
|
||||
#define MT_PSE_PG_INFO MT_PSE(0x194)
|
||||
#define MT_PSE_SRC_CNT GENMASK(27, 16)
|
||||
|
||||
#define MT_WF_PHY_BASE ((dev)->reg_map[MT_PHY_BASE])
|
||||
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
|
||||
|
||||
|
@ -151,29 +176,40 @@ enum mt7615_reg_base {
|
|||
#define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9)
|
||||
|
||||
#define MT_WF_PHY_R0_PHYMUX_5(_phy) MT_WF_PHY(0x0614 + ((_phy) << 9))
|
||||
#define MT7663_WF_PHY_R0_PHYMUX_5 MT_WF_PHY(0x0414)
|
||||
|
||||
#define MT_WF_PHY_R0_PHYCTRL_STS0(_phy) MT_WF_PHY(0x020c + ((_phy) << 9))
|
||||
#define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16)
|
||||
#define MT_WF_PHYCTRL_STAT_PD_CCK GENMASK(15, 0)
|
||||
|
||||
#define MT7663_WF_PHY_R0_PHYCTRL_STS0(_phy) MT_WF_PHY(0x0210 + ((_phy) << 12))
|
||||
|
||||
#define MT_WF_PHY_R0_PHYCTRL_STS5(_phy) MT_WF_PHY(0x0220 + ((_phy) << 9))
|
||||
#define MT_WF_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16)
|
||||
#define MT_WF_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0)
|
||||
|
||||
#define MT7663_WF_PHY_R0_PHYCTRL_STS5(_phy) MT_WF_PHY(0x0224 + ((_phy) << 12))
|
||||
|
||||
#define MT_WF_PHY_MIN_PRI_PWR(_phy) MT_WF_PHY((_phy) ? 0x084 : 0x229c)
|
||||
#define MT_WF_PHY_PD_OFDM_MASK(_phy) ((_phy) ? GENMASK(24, 16) : \
|
||||
GENMASK(28, 20))
|
||||
#define MT_WF_PHY_PD_OFDM(_phy, v) ((v) << ((_phy) ? 16 : 20))
|
||||
#define MT_WF_PHY_PD_BLK(_phy) ((_phy) ? BIT(25) : BIT(19))
|
||||
|
||||
#define MT7663_WF_PHY_MIN_PRI_PWR(_phy) MT_WF_PHY((_phy) ? 0x2aec : 0x22f0)
|
||||
|
||||
#define MT_WF_PHY_RXTD_BASE MT_WF_PHY(0x2200)
|
||||
#define MT_WF_PHY_RXTD(_n) (MT_WF_PHY_RXTD_BASE + ((_n) << 2))
|
||||
|
||||
#define MT7663_WF_PHY_RXTD(_n) (MT_WF_PHY(0x25b0) + ((_n) << 2))
|
||||
|
||||
#define MT_WF_PHY_RXTD_CCK_PD(_phy) MT_WF_PHY((_phy) ? 0x2314 : 0x2310)
|
||||
#define MT_WF_PHY_PD_CCK_MASK(_phy) (_phy) ? GENMASK(31, 24) : \
|
||||
GENMASK(8, 1)
|
||||
#define MT_WF_PHY_PD_CCK(_phy, v) ((v) << ((_phy) ? 24 : 1))
|
||||
|
||||
#define MT7663_WF_PHY_RXTD_CCK_PD(_phy) MT_WF_PHY((_phy) ? 0x2350 : 0x234c)
|
||||
|
||||
#define MT_WF_PHY_RXTD2_BASE MT_WF_PHY(0x2a00)
|
||||
#define MT_WF_PHY_RXTD2(_n) (MT_WF_PHY_RXTD2_BASE + ((_n) << 2))
|
||||
|
||||
|
@ -306,10 +342,17 @@ enum mt7615_reg_base {
|
|||
#define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2)
|
||||
#define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3)
|
||||
#define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4)
|
||||
#define MT_DMA_RCFR0_MCU_RX_TDLS BIT(19)
|
||||
#define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21)
|
||||
#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24)
|
||||
#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26)
|
||||
|
||||
#define MT_WF_PF_BASE ((dev)->reg_map[MT_PF_BASE])
|
||||
#define MT_WF_PF(ofs) (MT_WF_PF_BASE + (ofs))
|
||||
|
||||
#define MT_WF_PFCR MT_WF_PF(0x000)
|
||||
#define MT_WF_PFCR_TDLS_EN BIT(9)
|
||||
|
||||
#define MT_WTBL_BASE(dev) ((dev)->reg_map[MT_WTBL_BASE_ADDR])
|
||||
#define MT_WTBL_ENTRY_SIZE 256
|
||||
|
||||
|
@ -379,34 +422,44 @@ enum mt7615_reg_base {
|
|||
#define MT_LPON_UTTR1 MT_LPON(0x01c)
|
||||
|
||||
#define MT_WF_MIB_BASE (dev->reg_map[MT_MIB_BASE])
|
||||
#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs))
|
||||
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE + (ofs) + (_band) * 0x200)
|
||||
|
||||
#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c)
|
||||
#define MT_WF_MIB_SCR0 MT_WF_MIB(0, 0)
|
||||
#define MT_MIB_SCR0_AGG_CNT_RANGE_EN BIT(21)
|
||||
|
||||
#define MT_MIB_SDR3(n) MT_WF_MIB(0x014 + ((n) << 9))
|
||||
#define MT_MIB_M0_MISC_CR(_band) MT_WF_MIB(_band, 0x00c)
|
||||
|
||||
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014)
|
||||
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9))
|
||||
#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
|
||||
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9))
|
||||
#define MT_MIB_SDR14(_band) MT_WF_MIB(_band, 0x040)
|
||||
#define MT_MIB_AMPDU_MPDU_COUNT GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR15(_band) MT_WF_MIB(_band, 0x044)
|
||||
#define MT_MIB_AMPDU_ACK_COUNT GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
|
||||
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9))
|
||||
#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
|
||||
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
|
||||
#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9))
|
||||
#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
|
||||
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(0x100 + ((_band) << 9) + \
|
||||
((n) << 4))
|
||||
#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_RTS_COUNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(0x104 + ((_band) << 9) + \
|
||||
((n) << 4))
|
||||
#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4))
|
||||
#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0)
|
||||
#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16)
|
||||
|
||||
#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2))
|
||||
#define MT_MIB_ARNG(n) MT_WF_MIB(0, 0x4b8 + ((n) << 2))
|
||||
|
||||
#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa8 + ((n) << 2))
|
||||
|
||||
#define MT_DMA_SHDL(ofs) (dev->reg_map[MT_DMA_SHDL_BASE] + (ofs))
|
||||
|
||||
|
@ -449,6 +502,10 @@ enum mt7615_reg_base {
|
|||
#define MT_LED_STATUS_ON GENMASK(23, 16)
|
||||
#define MT_LED_STATUS_DURATION GENMASK(15, 0)
|
||||
|
||||
#define MT_PDMA_BUSY 0x82000504
|
||||
#define MT_PDMA_TX_BUSY BIT(0)
|
||||
#define MT_PDMA_RX_BUSY BIT(1)
|
||||
|
||||
#define MT_EFUSE_BASE ((dev)->reg_map[MT_EFUSE_ADDR_BASE])
|
||||
#define MT_EFUSE_BASE_CTRL 0x000
|
||||
#define MT_EFUSE_BASE_CTRL_EMPTY BIT(30)
|
||||
|
@ -470,4 +527,27 @@ enum mt7615_reg_base {
|
|||
#define MT_INFRACFG_MISC 0x700
|
||||
#define MT_INFRACFG_MISC_AP2CONN_WAKE BIT(1)
|
||||
|
||||
#define MT_UMAC_BASE 0x7c000000
|
||||
#define MT_UMAC(ofs) (MT_UMAC_BASE + (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)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,10 +36,8 @@ static int mt7622_wmac_probe(struct platform_device *pdev)
|
|||
int irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get device IRQ\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
mem_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mem_base)) {
|
||||
|
|
|
@ -0,0 +1,446 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2019 MediaTek Inc.
|
||||
*
|
||||
* Author: Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
* Sean Wang <sean.wang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "mt7615.h"
|
||||
#include "mac.h"
|
||||
#include "mcu.h"
|
||||
#include "regs.h"
|
||||
|
||||
static const u32 mt7663u_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_PHY_BASE] = 0x82070000,
|
||||
[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,
|
||||
};
|
||||
|
||||
static const struct usb_device_id mt7615_device_table[] = {
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7663, 0xff, 0xff, 0xff) },
|
||||
{ },
|
||||
};
|
||||
|
||||
static void mt7663u_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7615_phy *phy = mt7615_hw_phy(hw);
|
||||
struct mt7615_dev *dev = hw->priv;
|
||||
|
||||
clear_bit(MT76_STATE_RUNNING, &dev->mphy.state);
|
||||
cancel_work_sync(&phy->ps_work);
|
||||
cancel_delayed_work_sync(&phy->scan_work);
|
||||
cancel_delayed_work_sync(&phy->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_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid,
|
||||
enum mt76_txq_id qid, struct ieee80211_sta *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_key_conf *key = info->control.hw_key;
|
||||
__le32 *txwi;
|
||||
int pid;
|
||||
|
||||
if (!wcid)
|
||||
wcid = &dev->mt76.global_wcid;
|
||||
|
||||
pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb);
|
||||
|
||||
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, false);
|
||||
skb_push(skb, MT_USB_TXD_SIZE);
|
||||
}
|
||||
|
||||
static int
|
||||
__mt7663u_mac_set_rates(struct mt7615_dev *dev,
|
||||
struct mt7615_wtbl_desc *wd)
|
||||
{
|
||||
struct mt7615_rate_desc *rate = &wd->rate;
|
||||
struct mt7615_sta *sta = wd->sta;
|
||||
u32 w5, w27, addr, val;
|
||||
|
||||
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);
|
||||
|
||||
mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* 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 int
|
||||
__mt7663u_mac_set_key(struct mt7615_dev *dev,
|
||||
struct mt7615_wtbl_desc *wd)
|
||||
{
|
||||
struct mt7615_key_desc *key = &wd->key;
|
||||
struct mt7615_sta *sta = wd->sta;
|
||||
enum mt7615_cipher_type cipher;
|
||||
struct mt76_wcid *wcid;
|
||||
int err;
|
||||
|
||||
lockdep_assert_held(&dev->mt76.mutex);
|
||||
|
||||
if (!sta)
|
||||
return -EINVAL;
|
||||
|
||||
cipher = mt7615_mac_get_cipher(key->cipher);
|
||||
if (cipher == MT_CIPHER_NONE)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
wcid = &wd->sta->wcid;
|
||||
|
||||
mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd);
|
||||
err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen,
|
||||
cipher, key->cmd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
|
||||
key->cmd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (key->cmd == SET_KEY)
|
||||
wcid->cipher |= BIT(cipher);
|
||||
else
|
||||
wcid->cipher &= ~BIT(cipher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7663u_wtbl_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_wtbl_desc *wd, *wd_next;
|
||||
struct mt7615_dev *dev;
|
||||
|
||||
dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
|
||||
wtbl_work);
|
||||
|
||||
list_for_each_entry_safe(wd, wd_next, &dev->wd_head, node) {
|
||||
spin_lock_bh(&dev->mt76.lock);
|
||||
list_del(&wd->node);
|
||||
spin_unlock_bh(&dev->mt76.lock);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
switch (wd->type) {
|
||||
case MT7615_WTBL_RATE_DESC:
|
||||
__mt7663u_mac_set_rates(dev, wd);
|
||||
break;
|
||||
case MT7615_WTBL_KEY_DESC:
|
||||
__mt7663u_mac_set_key(dev, wd);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
kfree(wd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7663u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e)
|
||||
{
|
||||
skb_pull(e->skb, MT_USB_HDR_SIZE + MT_USB_TXD_SIZE);
|
||||
mt76_tx_complete_skb(mdev, e->skb);
|
||||
}
|
||||
|
||||
static int
|
||||
mt7663u_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);
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
|
||||
struct mt7615_sta *msta;
|
||||
|
||||
msta = container_of(wcid, struct mt7615_sta, wcid);
|
||||
spin_lock_bh(&dev->mt76.lock);
|
||||
mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0],
|
||||
msta->rates);
|
||||
msta->rate_probe = true;
|
||||
spin_unlock_bh(&dev->mt76.lock);
|
||||
}
|
||||
mt7663u_mac_write_txwi(dev, wcid, qid, sta, tx_info->skb);
|
||||
|
||||
return mt76u_skb_dma_info(tx_info->skb, tx_info->skb->len);
|
||||
}
|
||||
|
||||
static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
mt7615_mac_sta_poll(dev);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.tx_prepare_skb = mt7663u_tx_prepare_skb,
|
||||
.tx_complete_skb = mt7663u_tx_complete_skb,
|
||||
.tx_status_data = mt7663u_tx_status_data,
|
||||
.rx_skb = mt7615_queue_rx_skb,
|
||||
.sta_ps = mt7615_sta_ps,
|
||||
.sta_add = mt7615_mac_sta_add,
|
||||
.sta_remove = mt7615_mac_sta_remove,
|
||||
.update_survey = mt7615_update_channel,
|
||||
};
|
||||
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);
|
||||
|
||||
dev->reg_map = mt7663u_reg_map;
|
||||
dev->ops = ops;
|
||||
ret = mt76u_init(mdev, usb_intf, true);
|
||||
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)) {
|
||||
dev_dbg(dev->mt76.dev, "Usb device already powered on\n");
|
||||
set_bit(MT76_STATE_POWER_OFF, &dev->mphy.state);
|
||||
goto alloc_queues;
|
||||
}
|
||||
|
||||
ret = mt76u_vendor_request(&dev->mt76, MT_VEND_POWER_ON,
|
||||
USB_DIR_OUT | USB_TYPE_VENDOR,
|
||||
0x0, 0x1, NULL, 0);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
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");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
alloc_queues:
|
||||
ret = mt76u_alloc_mcu_queue(&dev->mt76);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt76u_alloc_queues(&dev->mt76);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt7663u_register_device(dev);
|
||||
if (ret)
|
||||
goto error_freeq;
|
||||
|
||||
return 0;
|
||||
|
||||
error_freeq:
|
||||
mt76u_queues_deinit(&dev->mt76);
|
||||
error:
|
||||
mt76u_deinit(&dev->mt76);
|
||||
usb_set_intfdata(usb_intf, NULL);
|
||||
usb_put_dev(interface_to_usbdev(usb_intf));
|
||||
|
||||
ieee80211_free_hw(mdev->hw);
|
||||
|
||||
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));
|
||||
|
||||
mt76u_deinit(&dev->mt76);
|
||||
ieee80211_free_hw(dev->mt76.hw);
|
||||
}
|
||||
|
||||
#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 = mt7615_mcu_set_hif_suspend(dev, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
mt76u_stop_rx(&dev->mt76);
|
||||
|
||||
mt76u_stop_tx(&dev->mt76);
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
|
||||
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 = mt7615_mcu_set_hif_suspend(dev, false);
|
||||
|
||||
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 <sean.wang@mediatek.com>");
|
||||
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2019 MediaTek Inc.
|
||||
*
|
||||
* Author: Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
* Sean Wang <sean.wang@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "mt7615.h"
|
||||
#include "mac.h"
|
||||
#include "regs.h"
|
||||
|
||||
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 mt7663u_init_hardware(struct mt7615_dev *dev)
|
||||
{
|
||||
int ret, idx;
|
||||
|
||||
ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_mcu_set_eeprom(dev);
|
||||
mt7615_mac_init(dev);
|
||||
mt7615_phy_init(dev);
|
||||
mt7615_mcu_del_wtbl_all(dev);
|
||||
mt7615_check_offload_capability(dev);
|
||||
}
|
||||
|
||||
int mt7663u_register_device(struct mt7615_dev *dev)
|
||||
{
|
||||
struct ieee80211_hw *hw = mt76_hw(dev);
|
||||
int err;
|
||||
|
||||
INIT_WORK(&dev->wtbl_work, mt7663u_wtbl_work);
|
||||
INIT_WORK(&dev->mcu_work, mt7663u_init_work);
|
||||
INIT_LIST_HEAD(&dev->wd_head);
|
||||
mt7615_init_device(dev);
|
||||
|
||||
err = mt7663u_init_hardware(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE;
|
||||
/* check hw sg support in order to enable AMSDU */
|
||||
hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1;
|
||||
|
||||
err = mt76_register_device(&dev->mt76, true, mt7615_rates,
|
||||
ARRAY_SIZE(mt7615_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);
|
||||
|
||||
return mt7615_init_debugfs(dev);
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (C) 2019 MediaTek Inc.
|
||||
*
|
||||
* Author: Felix Fietkau <nbd@nbd.name>
|
||||
* Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
* Sean Wang <sean.wang@mediatek.com>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#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, bool wait_resp)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
int ret, seq, ep;
|
||||
|
||||
mutex_lock(&mdev->mcu.mutex);
|
||||
|
||||
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;
|
||||
|
||||
ret = mt76u_skb_dma_info(skb, skb->len);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL,
|
||||
1000, ep);
|
||||
dev_kfree_skb(skb);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (wait_resp)
|
||||
ret = mt7615_mcu_wait_response(dev, cmd, seq);
|
||||
|
||||
out:
|
||||
mutex_unlock(&mdev->mcu.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_send_msg = mt7615_mcu_msg_send,
|
||||
.mcu_restart = mt7615_mcu_restart,
|
||||
};
|
||||
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)) {
|
||||
mt7615_mcu_restart(&dev->mt76);
|
||||
if (!mt76_poll_msec(dev, MT_CONN_ON_MISC,
|
||||
MT_TOP_MISC2_FW_PWR_ON, 0, 500))
|
||||
return -EIO;
|
||||
|
||||
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");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
|
@ -12,24 +12,6 @@
|
|||
#include "initvals.h"
|
||||
#include "../mt76x02_phy.h"
|
||||
|
||||
static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
|
||||
{
|
||||
struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
|
||||
u16 mcs_map = 0;
|
||||
int i;
|
||||
|
||||
vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!i)
|
||||
mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (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);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76x0_set_wlan_state(struct mt76x02_dev *dev, u32 val, bool enable)
|
||||
{
|
||||
|
@ -263,9 +245,11 @@ int mt76x0_register_device(struct mt76x02_dev *dev)
|
|||
return ret;
|
||||
|
||||
if (dev->mt76.cap.has_5ghz) {
|
||||
/* overwrite unsupported features */
|
||||
mt76x0_vht_cap_mask(&dev->mphy.sband_5g.sband);
|
||||
mt76x0_init_txpower(dev, &dev->mphy.sband_5g.sband);
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
sband = &dev->mphy.sband_5g.sband;
|
||||
sband->vht_cap.cap &= ~IEEE80211_VHT_CAP_RXLDPC;
|
||||
mt76x0_init_txpower(dev, sband);
|
||||
}
|
||||
|
||||
if (dev->mt76.cap.has_2ghz)
|
||||
|
|
|
@ -29,6 +29,7 @@ static void mt76x0e_stop_hw(struct mt76x02_dev *dev)
|
|||
{
|
||||
cancel_delayed_work_sync(&dev->cal_work);
|
||||
cancel_delayed_work_sync(&dev->mt76.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))
|
||||
|
@ -83,6 +84,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
|
|||
.set_coverage_class = mt76x02_set_coverage_class,
|
||||
.set_rts_threshold = mt76x02_set_rts_threshold,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
.reconfig_complete = mt76x02_reconfig_complete,
|
||||
};
|
||||
|
||||
static int mt76x0e_register_device(struct mt76x02_dev *dev)
|
||||
|
@ -216,6 +218,7 @@ mt76x0e_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
static const struct pci_device_id mt76x0e_device_table[] = {
|
||||
{ PCI_DEVICE(0x14c3, 0x7610) },
|
||||
{ PCI_DEVICE(0x14c3, 0x7630) },
|
||||
{ PCI_DEVICE(0x14c3, 0x7650) },
|
||||
{ },
|
||||
|
|
|
@ -187,6 +187,8 @@ void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps);
|
|||
void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *info, u32 changed);
|
||||
void mt76x02_reconfig_complete(struct ieee80211_hw *hw,
|
||||
enum ieee80211_reconfig_type reconfig_type);
|
||||
|
||||
struct beacon_bc_data {
|
||||
struct mt76x02_dev *dev;
|
||||
|
@ -216,6 +218,7 @@ static inline bool is_mt76x0(struct mt76x02_dev *dev)
|
|||
static inline bool is_mt76x2(struct mt76x02_dev *dev)
|
||||
{
|
||||
return mt76_chip(&dev->mt76) == 0x7612 ||
|
||||
mt76_chip(&dev->mt76) == 0x7632 ||
|
||||
mt76_chip(&dev->mt76) == 0x7662 ||
|
||||
mt76_chip(&dev->mt76) == 0x7602;
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
|
|||
if (!dir)
|
||||
return;
|
||||
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp);
|
||||
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
|
||||
|
|
|
@ -409,6 +409,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
|||
txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
|
||||
if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
|
||||
u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
|
||||
u8 ampdu_density = sta->ht_cap.ampdu_density;
|
||||
|
||||
ba_size <<= sta->ht_cap.ampdu_factor;
|
||||
ba_size = min_t(int, 63, ba_size - 1);
|
||||
|
@ -416,9 +417,11 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
|
|||
ba_size = 0;
|
||||
txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
|
||||
|
||||
if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4)
|
||||
ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
|
||||
|
||||
txwi_flags |= MT_TXWI_FLAGS_AMPDU |
|
||||
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
|
||||
sta->ht_cap.ampdu_density);
|
||||
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, ampdu_density);
|
||||
}
|
||||
|
||||
if (ieee80211_is_probe_resp(hdr->frame_control) ||
|
||||
|
|
|
@ -20,7 +20,10 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
|
|||
int ret;
|
||||
u8 seq;
|
||||
|
||||
skb = mt76x02_mcu_msg_alloc(data, len);
|
||||
if (mt76_is_mmio(&dev->mt76) && dev->mcu_timeout)
|
||||
return -EIO;
|
||||
|
||||
skb = mt76_mcu_msg_alloc(mdev, data, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -85,12 +85,6 @@ struct mt76x02_patch_header {
|
|||
u8 pad[2];
|
||||
};
|
||||
|
||||
static inline struct sk_buff *
|
||||
mt76x02_mcu_msg_alloc(const void *data, int len)
|
||||
{
|
||||
return mt76_mcu_msg_alloc(data, 0, len, 0);
|
||||
}
|
||||
|
||||
int mt76x02_mcu_cleanup(struct mt76x02_dev *dev);
|
||||
int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param);
|
||||
int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
|
||||
|
|
|
@ -520,6 +520,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||
}
|
||||
|
||||
if (restart) {
|
||||
set_bit(MT76_RESTART, &dev->mphy.state);
|
||||
mt76x02_mcu_function_select(dev, Q_SELECT, 1);
|
||||
ieee80211_restart_hw(dev->mt76.hw);
|
||||
} else {
|
||||
|
@ -528,8 +529,23 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
if (++dev->tx_hang_check >= MT_TX_HANG_TH)
|
||||
goto restart;
|
||||
|
|
|
@ -123,7 +123,7 @@ mt76x02u_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data,
|
|||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
skb = mt76_mcu_msg_alloc(data, MT_CMD_HDR_LEN, len, 8);
|
||||
skb = mt76_mcu_msg_alloc(dev, data, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -291,6 +291,8 @@ 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_wr_rp = mt76x02u_mcu_wr_rp,
|
||||
.mcu_rd_rp = mt76x02u_mcu_rd_rp,
|
||||
|
|
|
@ -46,6 +46,8 @@ static const struct ieee80211_iface_limit mt76x02_if_limits[] = {
|
|||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
};
|
||||
|
@ -60,6 +62,8 @@ static const struct ieee80211_iface_limit mt76x02u_if_limits[] = {
|
|||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
||||
BIT(NL80211_IFTYPE_P2P_GO) |
|
||||
BIT(NL80211_IFTYPE_AP)
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "mt76x2.h"
|
||||
#include "eeprom.h"
|
||||
|
@ -76,6 +77,7 @@ mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
|
|||
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],
|
||||
|
@ -86,6 +88,9 @@ mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
|
|||
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;
|
||||
|
||||
|
|
|
@ -256,6 +256,7 @@ void mt76x2_stop_hardware(struct mt76x02_dev *dev)
|
|||
cancel_delayed_work_sync(&dev->cal_work);
|
||||
cancel_delayed_work_sync(&dev->mt76.mac_work);
|
||||
cancel_delayed_work_sync(&dev->wdt_work);
|
||||
clear_bit(MT76_RESTART, &dev->mphy.state);
|
||||
mt76x02_mcu_set_radio_state(dev, false);
|
||||
mt76x2_mac_stop(dev, false);
|
||||
}
|
||||
|
|
|
@ -10,12 +10,9 @@ static int
|
|||
mt76x2_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
int ret;
|
||||
|
||||
mt76x02_mac_start(dev);
|
||||
ret = mt76x2_phy_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mt76x2_phy_start(dev);
|
||||
|
||||
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
|
||||
MT_MAC_WORK_INTERVAL);
|
||||
|
@ -35,11 +32,9 @@ mt76x2_stop(struct ieee80211_hw *hw)
|
|||
mt76x2_stop_hardware(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cancel_delayed_work_sync(&dev->cal_work);
|
||||
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
|
||||
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
|
||||
|
@ -50,7 +45,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
|
|||
mt76_set_channel(&dev->mphy);
|
||||
|
||||
mt76x2_mac_stop(dev, true);
|
||||
ret = mt76x2_phy_set_channel(dev, chandef);
|
||||
mt76x2_phy_set_channel(dev, chandef);
|
||||
|
||||
mt76x02_mac_cc_reset(dev);
|
||||
mt76x02_dfs_init_params(dev);
|
||||
|
@ -64,15 +59,12 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
|
|||
tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
|
||||
|
||||
mt76_txq_schedule_all(&dev->mphy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mt76x2_config(struct ieee80211_hw *hw, u32 changed)
|
||||
{
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
|
@ -101,11 +93,11 @@ mt76x2_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
ieee80211_stop_queues(hw);
|
||||
ret = mt76x2_set_channel(dev, &hw->conf.chandef);
|
||||
mt76x2_set_channel(dev, &hw->conf.chandef);
|
||||
ieee80211_wake_queues(hw);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -127,7 +119,7 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
|
|||
dev->chainmask = (tx_ant == 3) ? 0x202 : 0x101;
|
||||
dev->mphy.antenna_mask = tx_ant;
|
||||
|
||||
mt76_set_stream_caps(&dev->mt76, true);
|
||||
mt76_set_stream_caps(&dev->mphy, true);
|
||||
mt76x2_phy_set_antenna(dev);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
@ -162,5 +154,6 @@ const struct ieee80211_ops mt76x2_ops = {
|
|||
.set_antenna = mt76x2_set_antenna,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
.set_rts_threshold = mt76x02_set_rts_threshold,
|
||||
.reconfig_complete = mt76x02_reconfig_complete,
|
||||
};
|
||||
|
||||
|
|
|
@ -16,8 +16,10 @@ static const struct usb_device_id mt76x2u_device_table[] = {
|
|||
{ 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(0x2c4e, 0x0103) }, /* Mercury UD13 */
|
||||
{ USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */
|
||||
{ USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */
|
||||
{ USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# SPDX-License-Identifier: ISC
|
||||
config MT7915E
|
||||
tristate "MediaTek MT7915E (PCIe) support"
|
||||
select MT76_CORE
|
||||
depends on MAC80211
|
||||
depends on PCI
|
||||
help
|
||||
This adds support for MT7915-based wireless PCIe 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.
|
|
@ -0,0 +1,6 @@
|
|||
#SPDX-License-Identifier: ISC
|
||||
|
||||
obj-$(CONFIG_MT7915E) += mt7915e.o
|
||||
|
||||
mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
|
||||
debugfs.o
|
|
@ -0,0 +1,463 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#include "mt7915.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
/** global debugfs **/
|
||||
|
||||
/* test knob of system layer 1/2 error recovery */
|
||||
static int mt7915_ser_trigger_set(void *data, u64 val)
|
||||
{
|
||||
enum {
|
||||
SER_SET_RECOVER_L1 = 1,
|
||||
SER_SET_RECOVER_L2,
|
||||
SER_ENABLE = 2,
|
||||
SER_RECOVER
|
||||
};
|
||||
struct mt7915_dev *dev = data;
|
||||
int ret = 0;
|
||||
|
||||
switch (val) {
|
||||
case SER_SET_RECOVER_L1:
|
||||
case SER_SET_RECOVER_L2:
|
||||
/* fall through */
|
||||
ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
|
||||
mt7915_ser_trigger_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7915_radar_trigger(void *data, u64 val)
|
||||
{
|
||||
struct mt7915_dev *dev = data;
|
||||
|
||||
return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
|
||||
mt7915_radar_trigger, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7915_dbdc_set(void *data, u64 val)
|
||||
{
|
||||
struct mt7915_dev *dev = data;
|
||||
|
||||
if (val)
|
||||
mt7915_register_ext_phy(dev);
|
||||
else
|
||||
mt7915_unregister_ext_phy(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_dbdc_get(void *data, u64 *val)
|
||||
{
|
||||
struct mt7915_dev *dev = data;
|
||||
|
||||
*val = !!mt7915_ext_phy(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get,
|
||||
mt7915_dbdc_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7915_fw_debug_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;
|
||||
|
||||
dev->fw_debug = !!val;
|
||||
|
||||
mt7915_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0);
|
||||
|
||||
for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++)
|
||||
mt7915_mcu_fw_dbg_ctrl(dev, debug, dev->fw_debug);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_fw_debug_get(void *data, u64 *val)
|
||||
{
|
||||
struct mt7915_dev *dev = data;
|
||||
|
||||
*val = dev->fw_debug;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug, mt7915_fw_debug_get,
|
||||
mt7915_fw_debug_set, "%lld\n");
|
||||
|
||||
static void
|
||||
mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
|
||||
struct seq_file *file)
|
||||
{
|
||||
struct mt7915_dev *dev = file->private;
|
||||
bool ext_phy = phy != &dev->phy;
|
||||
int bound[15], range[4], i, n;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
/* Tx ampdu stat */
|
||||
for (i = 0; i < ARRAY_SIZE(range); i++)
|
||||
range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1;
|
||||
|
||||
seq_printf(file, "\nPhy %d\n", ext_phy);
|
||||
|
||||
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: ");
|
||||
n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]);
|
||||
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 mt7915_dev *dev = s->private;
|
||||
bool ext_phy = phy != &dev->phy;
|
||||
int cnt;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
/* Tx Beamformer monitor */
|
||||
seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
|
||||
|
||||
cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(ext_phy));
|
||||
seq_printf(s, "iBF: %ld, eBF: %ld\n",
|
||||
FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt),
|
||||
FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt));
|
||||
|
||||
/* Tx Beamformer Rx feedback monitor */
|
||||
seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
|
||||
|
||||
cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(ext_phy));
|
||||
seq_printf(s, "All: %ld, HE: %ld, VHT: %ld, HT: %ld\n",
|
||||
FIELD_GET(MT_ETBF_RX_FB_ALL, cnt),
|
||||
FIELD_GET(MT_ETBF_RX_FB_HE, cnt),
|
||||
FIELD_GET(MT_ETBF_RX_FB_VHT, cnt),
|
||||
FIELD_GET(MT_ETBF_RX_FB_HT, cnt));
|
||||
|
||||
/* Tx Beamformee Rx NDPA & Tx feedback report */
|
||||
cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(ext_phy));
|
||||
seq_printf(s, "Tx Beamformee sucessful feedback frames: %ld\n",
|
||||
FIELD_GET(MT_ETBF_TX_FB_CPL, cnt));
|
||||
seq_printf(s, "Tx Beamformee feedback triggerd counts: %ld\n",
|
||||
FIELD_GET(MT_ETBF_TX_FB_TRI, cnt));
|
||||
|
||||
/* Tx SU counters */
|
||||
cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy));
|
||||
seq_printf(s, "Tx single-user sucessful MPDU counts: %d\n", cnt);
|
||||
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_tx_stats_read(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7915_dev *dev = file->private;
|
||||
int stat[8], i, n;
|
||||
|
||||
mt7915_ampdu_stat_read_phy(&dev->phy, file);
|
||||
mt7915_txbf_stat_read_phy(&dev->phy, file);
|
||||
|
||||
mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file);
|
||||
mt7915_txbf_stat_read_phy(mt7915_ext_phy(dev), file);
|
||||
|
||||
/* Tx amsdu info */
|
||||
seq_puts(file, "Tx MSDU stat:\n");
|
||||
for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
|
||||
stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
|
||||
n += stat[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(stat); i++) {
|
||||
seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
|
||||
i + 1, stat[i]);
|
||||
if (n != 0)
|
||||
seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
|
||||
else
|
||||
seq_puts(file, "\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_tx_stats_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7915_tx_stats_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tx_stats = {
|
||||
.open = mt7915_tx_stats_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int mt7915_read_temperature(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7915_dev *dev = dev_get_drvdata(s->private);
|
||||
int temp;
|
||||
|
||||
/* cpu */
|
||||
temp = mt7915_mcu_get_temperature(dev, 0);
|
||||
seq_printf(s, "Temperature: %d\n", temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_queues_acq(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7915_dev *dev = dev_get_drvdata(s->private);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
int j, acs = i / 4, index = i % 4;
|
||||
u32 ctrl, val, qlen = 0;
|
||||
|
||||
val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
|
||||
ctrl = BIT(31) | BIT(15) | (acs << 8);
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (val & BIT(j))
|
||||
continue;
|
||||
|
||||
mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
|
||||
ctrl | (j + (index << 5)));
|
||||
qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
|
||||
GENMASK(11, 0));
|
||||
}
|
||||
seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_queues_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7915_dev *dev = dev_get_drvdata(s->private);
|
||||
static const struct {
|
||||
char *queue;
|
||||
int id;
|
||||
} queue_map[] = {
|
||||
{ "WFDMA0", MT_TXQ_BE },
|
||||
{ "MCUWM", MT_TXQ_MCU },
|
||||
{ "MCUWA", MT_TXQ_MCU_WA },
|
||||
{ "MCUFWQ", MT_TXQ_FWDL },
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
|
||||
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
|
||||
|
||||
if (!q->q)
|
||||
continue;
|
||||
|
||||
seq_printf(s,
|
||||
"%s: queued=%d head=%d tail=%d\n",
|
||||
queue_map[i].queue, q->q->queued, q->q->head,
|
||||
q->q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta,
|
||||
s8 txpower_cur, int band)
|
||||
{
|
||||
static const char * const sku_group_name[] = {
|
||||
"CCK", "OFDM", "HT20", "HT40",
|
||||
"VHT20", "VHT40", "VHT80", "VHT160",
|
||||
"RU26", "RU52", "RU106", "RU242/SU20",
|
||||
"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
|
||||
};
|
||||
s8 txpower[MT7915_SKU_RATE_NUM];
|
||||
int i, idx = 0;
|
||||
|
||||
for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
|
||||
txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2);
|
||||
|
||||
for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) {
|
||||
const struct sku_group *sku = &mt7915_sku_groups[i];
|
||||
u32 offset = sku->offset[band];
|
||||
|
||||
if (!offset) {
|
||||
idx += sku->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
mt76_seq_puts_array(s, sku_group_name[i],
|
||||
txpower + idx, sku->len);
|
||||
idx += sku->len;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_read_rate_txpower(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7915_dev *dev = dev_get_drvdata(s->private);
|
||||
struct mt76_phy *mphy = &dev->mphy;
|
||||
enum nl80211_band band = mphy->chandef.chan->band;
|
||||
s8 *delta = dev->rate_power[band];
|
||||
s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX];
|
||||
|
||||
seq_puts(s, "Band 0:\n");
|
||||
mt7915_puts_rate_txpower(s, delta, txpower_base, band);
|
||||
|
||||
if (dev->mt76.phy2) {
|
||||
mphy = dev->mt76.phy2;
|
||||
band = mphy->chandef.chan->band;
|
||||
delta = dev->rate_power[band];
|
||||
txpower_base = mphy->txpower_cur -
|
||||
delta[MT7915_SKU_MAX_DELTA_IDX];
|
||||
|
||||
seq_puts(s, "Band 1:\n");
|
||||
mt7915_puts_rate_txpower(s, delta, txpower_base, band);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt7915_init_debugfs(struct mt7915_dev *dev)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = mt76_register_debugfs(&dev->mt76);
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
mt7915_queues_read);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
|
||||
mt7915_queues_acq);
|
||||
debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
|
||||
debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
|
||||
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
|
||||
debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
|
||||
/* test knobs */
|
||||
debugfs_create_file("radar_trigger", 0200, dir, dev,
|
||||
&fops_radar_trigger);
|
||||
debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
|
||||
mt7915_read_temperature);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
|
||||
mt7915_read_rate_txpower);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** per-station debugfs **/
|
||||
|
||||
/* usage: <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> */
|
||||
static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
|
||||
{
|
||||
struct ieee80211_sta *sta = data;
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
|
||||
return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate);
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
|
||||
mt7915_sta_fixed_rate_set, "%llx\n");
|
||||
|
||||
static int
|
||||
mt7915_sta_stats_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct ieee80211_sta *sta = s->private;
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
struct mt7915_sta_stats *stats = &msta->stats;
|
||||
struct rate_info *rate = &stats->prob_rate;
|
||||
static const char * const bw[] = {
|
||||
"BW20", "BW5", "BW10", "BW40",
|
||||
"BW80", "BW160", "BW_HE_RU"
|
||||
};
|
||||
|
||||
if (!rate->legacy && !rate->flags)
|
||||
return 0;
|
||||
|
||||
seq_puts(s, "Probing rate - ");
|
||||
if (rate->flags & RATE_INFO_FLAGS_MCS)
|
||||
seq_puts(s, "HT ");
|
||||
else if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
|
||||
seq_puts(s, "VHT ");
|
||||
else if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
|
||||
seq_puts(s, "HE ");
|
||||
else
|
||||
seq_printf(s, "Bitrate %d\n", rate->legacy);
|
||||
|
||||
if (rate->flags) {
|
||||
seq_printf(s, "%s NSS%d MCS%d ",
|
||||
bw[rate->bw], rate->nss, rate->mcs);
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
seq_puts(s, "SGI ");
|
||||
else if (rate->he_gi)
|
||||
seq_puts(s, "HE GI ");
|
||||
|
||||
if (rate->he_dcm)
|
||||
seq_puts(s, "DCM ");
|
||||
}
|
||||
|
||||
seq_printf(s, "\nPPDU PER: %ld.%1ld%%\n",
|
||||
stats->per / 10, stats->per % 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_sta_stats_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7915_sta_stats_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_sta_stats = {
|
||||
.open = mt7915_sta_stats_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir)
|
||||
{
|
||||
debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate);
|
||||
debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats);
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
// 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_dev *dev, int n_desc)
|
||||
{
|
||||
struct mt76_sw_queue *q;
|
||||
struct mt76_queue *hwq;
|
||||
int err, i;
|
||||
|
||||
hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
|
||||
if (!hwq)
|
||||
return -ENOMEM;
|
||||
|
||||
err = mt76_queue_alloc(dev, hwq, MT7915_TXQ_BAND0, n_desc, 0,
|
||||
MT_TX_RING_BASE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < MT_TXQ_MCU; i++) {
|
||||
q = &dev->mt76.q_tx[i];
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
|
||||
int idx, int n_desc)
|
||||
{
|
||||
struct mt76_queue *hwq;
|
||||
int err;
|
||||
|
||||
hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
|
||||
if (!hwq)
|
||||
return -ENOMEM;
|
||||
|
||||
err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_LIST_HEAD(&q->swq);
|
||||
q->q = hwq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
__le32 *rxd = (__le32 *)skb->data;
|
||||
enum rx_pkt_type type;
|
||||
|
||||
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
|
||||
|
||||
switch (type) {
|
||||
case PKT_TYPE_TXRX_NOTIFY:
|
||||
mt7915_mac_tx_free(dev, skb);
|
||||
break;
|
||||
case PKT_TYPE_RX_EVENT:
|
||||
mt7915_mcu_rx_event(dev, skb);
|
||||
break;
|
||||
case PKT_TYPE_NORMAL:
|
||||
if (!mt7915_mac_fill_rx(dev, skb)) {
|
||||
mt76_rx(&dev->mt76, q, skb);
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
|
||||
{
|
||||
static const u8 queue_map[] = {
|
||||
MT_TXQ_MCU,
|
||||
MT_TXQ_MCU_WA,
|
||||
MT_TXQ_BE
|
||||
};
|
||||
struct mt7915_dev *dev;
|
||||
int i;
|
||||
|
||||
dev = container_of(napi, struct mt7915_dev, mt76.tx_napi);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
|
||||
mt76_queue_tx_cleanup(dev, queue_map[i], false);
|
||||
|
||||
if (napi_complete_done(napi, 0))
|
||||
mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
|
||||
mt76_queue_tx_cleanup(dev, queue_map[i], false);
|
||||
|
||||
mt7915_mac_sta_poll(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7915_dma_prefetch(struct mt7915_dev *dev)
|
||||
{
|
||||
#define PREFETCH(base, depth) ((base) << 16 | (depth))
|
||||
|
||||
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x40, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x80, 0x0));
|
||||
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL, PREFETCH(0x80, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL, PREFETCH(0xc0, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL, PREFETCH(0x100, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL, PREFETCH(0x140, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL, PREFETCH(0x180, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL, PREFETCH(0x1c0, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL, PREFETCH(0x200, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL, PREFETCH(0x240, 0x4));
|
||||
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL, PREFETCH(0x280, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL, PREFETCH(0x2c0, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL, PREFETCH(0x300, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL, PREFETCH(0x340, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL, PREFETCH(0x380, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL, PREFETCH(0x3c0, 0x0));
|
||||
|
||||
mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL, PREFETCH(0x3c0, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL, PREFETCH(0x400, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL, PREFETCH(0x440, 0x4));
|
||||
mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0));
|
||||
}
|
||||
|
||||
int mt7915_dma_init(struct mt7915_dev *dev)
|
||||
{
|
||||
/* Increase buffer size to receive large VHT/HE MPDUs */
|
||||
int rx_buf_size = MT_RX_BUF_SIZE * 2;
|
||||
int ret;
|
||||
|
||||
mt76_dma_attach(&dev->mt76);
|
||||
|
||||
/* configure global setting */
|
||||
mt76_set(dev, MT_WFDMA1_GLO_CFG,
|
||||
MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
|
||||
MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
|
||||
|
||||
/* configure perfetch settings */
|
||||
mt7915_dma_prefetch(dev);
|
||||
|
||||
/* reset dma idx */
|
||||
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
|
||||
mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0);
|
||||
|
||||
/* configure delay interrupt */
|
||||
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
|
||||
mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0);
|
||||
|
||||
/* init tx queue */
|
||||
ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* command to WM */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
|
||||
MT7915_TXQ_MCU_WM,
|
||||
MT7915_TX_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* command to WA */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA],
|
||||
MT7915_TXQ_MCU_WA,
|
||||
MT7915_TX_MCU_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* firmware download */
|
||||
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
|
||||
MT7915_TXQ_FWDL,
|
||||
MT7915_TX_FWDL_RING_SIZE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* event from WM */
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
|
||||
MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE,
|
||||
rx_buf_size, MT_RX_EVENT_RING_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* event from WA */
|
||||
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
|
||||
MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE,
|
||||
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], 0,
|
||||
MT7915_RX_RING_SIZE, rx_buf_size,
|
||||
MT_RX_DATA_RING_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt76_init_queues(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
|
||||
mt7915_poll_tx, NAPI_POLL_WEIGHT);
|
||||
napi_enable(&dev->mt76.tx_napi);
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
|
||||
mt76_set(dev, MT_WFDMA0_PCIE1_BUSY_ENA,
|
||||
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 |
|
||||
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 |
|
||||
MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO);
|
||||
|
||||
mt76_set(dev, MT_WFDMA1_PCIE1_BUSY_ENA,
|
||||
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);
|
||||
|
||||
/* set WFDMA Tx/Rx */
|
||||
mt76_set(dev, MT_WFDMA0_GLO_CFG,
|
||||
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
||||
mt76_set(dev, MT_WFDMA1_GLO_CFG,
|
||||
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
|
||||
|
||||
/* enable interrupts for TX/RX rings */
|
||||
mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
|
||||
MT_INT_MCU_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt7915_dma_cleanup(struct mt7915_dev *dev)
|
||||
{
|
||||
/* disable */
|
||||
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
|
||||
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
|
||||
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
||||
mt76_clear(dev, MT_WFDMA1_GLO_CFG,
|
||||
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
|
||||
MT_WFDMA1_GLO_CFG_RX_DMA_EN);
|
||||
|
||||
/* reset */
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
tasklet_kill(&dev->mt76.tx_tasklet);
|
||||
mt76_dma_cleanup(&dev->mt76);
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#include "mt7915.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
static inline bool mt7915_efuse_valid(u8 val)
|
||||
{
|
||||
return !(val == 0xff);
|
||||
}
|
||||
|
||||
u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
|
||||
{
|
||||
u8 *data = dev->mt76.eeprom.data;
|
||||
|
||||
if (!mt7915_efuse_valid(data[offset]))
|
||||
mt7915_mcu_get_eeprom(dev, offset);
|
||||
|
||||
return data[offset];
|
||||
}
|
||||
|
||||
static int mt7915_eeprom_load(struct mt7915_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7915_check_eeprom(struct mt7915_dev *dev)
|
||||
{
|
||||
u16 val;
|
||||
u8 *eeprom = dev->mt76.eeprom.data;
|
||||
|
||||
mt7915_eeprom_read(dev, 0);
|
||||
val = get_unaligned_le16(eeprom);
|
||||
|
||||
switch (val) {
|
||||
case 0x7915:
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
|
||||
{
|
||||
u8 *eeprom = dev->mt76.eeprom.data;
|
||||
u8 tx_mask, max_nss = 4;
|
||||
u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
|
||||
|
||||
val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
|
||||
switch (val) {
|
||||
case MT_EE_5GHZ:
|
||||
dev->mt76.cap.has_5ghz = true;
|
||||
break;
|
||||
case MT_EE_2GHZ:
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
break;
|
||||
default:
|
||||
dev->mt76.cap.has_2ghz = true;
|
||||
dev->mt76.cap.has_5ghz = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read tx mask from eeprom */
|
||||
tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
|
||||
eeprom[MT_EE_WIFI_CONF]);
|
||||
if (!tx_mask || tx_mask > max_nss)
|
||||
tx_mask = max_nss;
|
||||
|
||||
dev->chainmask = BIT(tx_mask) - 1;
|
||||
dev->mphy.antenna_mask = dev->chainmask;
|
||||
dev->phy.chainmask = dev->chainmask;
|
||||
}
|
||||
|
||||
int mt7915_eeprom_init(struct mt7915_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mt7915_eeprom_load(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mt7915_check_eeprom(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt7915_eeprom_parse_hw_cap(dev);
|
||||
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
|
||||
ETH_ALEN);
|
||||
|
||||
mt76_eeprom_override(&dev->mt76);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx)
|
||||
{
|
||||
int index;
|
||||
bool tssi_on;
|
||||
|
||||
if (chain_idx > 3)
|
||||
return -EINVAL;
|
||||
|
||||
tssi_on = mt7915_tssi_enabled(dev, chan->band);
|
||||
|
||||
if (chan->band == NL80211_BAND_2GHZ) {
|
||||
index = MT_EE_TX0_POWER_2G + chain_idx * 3 + !tssi_on;
|
||||
} else {
|
||||
int group = tssi_on ?
|
||||
mt7915_get_channel_group(chan->hw_value) : 8;
|
||||
|
||||
index = MT_EE_TX0_POWER_5G + chain_idx * 12 + group;
|
||||
}
|
||||
|
||||
return mt7915_eeprom_read(dev, index);
|
||||
}
|
||||
|
||||
static const u8 sku_cck_delta_map[] = {
|
||||
SKU_CCK_GROUP0,
|
||||
SKU_CCK_GROUP0,
|
||||
SKU_CCK_GROUP1,
|
||||
SKU_CCK_GROUP1,
|
||||
};
|
||||
|
||||
static const u8 sku_ofdm_delta_map[] = {
|
||||
SKU_OFDM_GROUP0,
|
||||
SKU_OFDM_GROUP0,
|
||||
SKU_OFDM_GROUP1,
|
||||
SKU_OFDM_GROUP1,
|
||||
SKU_OFDM_GROUP2,
|
||||
SKU_OFDM_GROUP2,
|
||||
SKU_OFDM_GROUP3,
|
||||
SKU_OFDM_GROUP4,
|
||||
};
|
||||
|
||||
static const u8 sku_mcs_delta_map[] = {
|
||||
SKU_MCS_GROUP0,
|
||||
SKU_MCS_GROUP1,
|
||||
SKU_MCS_GROUP1,
|
||||
SKU_MCS_GROUP2,
|
||||
SKU_MCS_GROUP2,
|
||||
SKU_MCS_GROUP3,
|
||||
SKU_MCS_GROUP4,
|
||||
SKU_MCS_GROUP5,
|
||||
SKU_MCS_GROUP6,
|
||||
SKU_MCS_GROUP7,
|
||||
SKU_MCS_GROUP8,
|
||||
SKU_MCS_GROUP9,
|
||||
};
|
||||
|
||||
#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map) \
|
||||
[_mode] = { \
|
||||
.len = _len, \
|
||||
.offset = { \
|
||||
_ofs_2g, \
|
||||
_ofs_5g, \
|
||||
}, \
|
||||
.delta_map = _map \
|
||||
}
|
||||
|
||||
const struct sku_group mt7915_sku_groups[] = {
|
||||
SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map),
|
||||
SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map),
|
||||
|
||||
SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map),
|
||||
|
||||
SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map),
|
||||
SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map),
|
||||
};
|
||||
|
||||
static s8
|
||||
mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr)
|
||||
{
|
||||
u32 val = mt7915_eeprom_read(dev, addr);
|
||||
s8 delta = FIELD_GET(SKU_DELTA_VAL, val);
|
||||
|
||||
if (!(val & SKU_DELTA_EN))
|
||||
return 0;
|
||||
|
||||
return val & SKU_DELTA_ADD ? delta : -delta;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_eeprom_init_sku_band(struct mt7915_dev *dev,
|
||||
struct ieee80211_supported_band *sband)
|
||||
{
|
||||
int i, band = sband->band;
|
||||
s8 *rate_power = dev->rate_power[band], max_delta = 0;
|
||||
u8 idx = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) {
|
||||
const struct sku_group *sku = &mt7915_sku_groups[i];
|
||||
u32 offset = sku->offset[band];
|
||||
int j;
|
||||
|
||||
if (!offset) {
|
||||
idx += sku->len;
|
||||
continue;
|
||||
}
|
||||
|
||||
rate_power[idx++] = mt7915_get_sku_delta(dev, offset);
|
||||
if (rate_power[idx - 1] > max_delta)
|
||||
max_delta = rate_power[idx - 1];
|
||||
|
||||
if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
|
||||
offset += 1;
|
||||
|
||||
for (j = 1; j < sku->len; j++) {
|
||||
u32 addr = offset + sku->delta_map[j];
|
||||
|
||||
rate_power[idx++] = mt7915_get_sku_delta(dev, addr);
|
||||
if (rate_power[idx - 1] > max_delta)
|
||||
max_delta = rate_power[idx - 1];
|
||||
}
|
||||
}
|
||||
|
||||
rate_power[idx] = max_delta;
|
||||
}
|
||||
|
||||
void mt7915_eeprom_init_sku(struct mt7915_dev *dev)
|
||||
{
|
||||
mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband);
|
||||
mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband);
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/* 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_DDIE_FT_VERSION = 0x050,
|
||||
MT_EE_WIFI_CONF = 0x190,
|
||||
MT_EE_TX0_POWER_2G = 0x2fc,
|
||||
MT_EE_TX0_POWER_5G = 0x34b,
|
||||
MT_EE_ADIE_FT_VERSION = 0x9a0,
|
||||
|
||||
__MT_EE_MAX = 0xe00
|
||||
};
|
||||
|
||||
#define MT_EE_WIFI_CONF_TX_MASK GENMASK(2, 0)
|
||||
#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(7, 6)
|
||||
#define MT_EE_WIFI_CONF_TSSI0_2G BIT(0)
|
||||
#define MT_EE_WIFI_CONF_TSSI0_5G BIT(2)
|
||||
#define MT_EE_WIFI_CONF_TSSI1_5G BIT(4)
|
||||
|
||||
enum mt7915_eeprom_band {
|
||||
MT_EE_DUAL_BAND,
|
||||
MT_EE_5GHZ,
|
||||
MT_EE_2GHZ,
|
||||
MT_EE_DBDC,
|
||||
};
|
||||
|
||||
#define SKU_DELTA_VAL GENMASK(5, 0)
|
||||
#define SKU_DELTA_ADD BIT(6)
|
||||
#define SKU_DELTA_EN BIT(7)
|
||||
|
||||
enum mt7915_sku_delta_group {
|
||||
SKU_CCK_GROUP0,
|
||||
SKU_CCK_GROUP1,
|
||||
|
||||
SKU_OFDM_GROUP0 = 0,
|
||||
SKU_OFDM_GROUP1,
|
||||
SKU_OFDM_GROUP2,
|
||||
SKU_OFDM_GROUP3,
|
||||
SKU_OFDM_GROUP4,
|
||||
|
||||
SKU_MCS_GROUP0 = 0,
|
||||
SKU_MCS_GROUP1,
|
||||
SKU_MCS_GROUP2,
|
||||
SKU_MCS_GROUP3,
|
||||
SKU_MCS_GROUP4,
|
||||
SKU_MCS_GROUP5,
|
||||
SKU_MCS_GROUP6,
|
||||
SKU_MCS_GROUP7,
|
||||
SKU_MCS_GROUP8,
|
||||
SKU_MCS_GROUP9,
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
struct sku_group {
|
||||
u8 len;
|
||||
u16 offset[2];
|
||||
const u8 *delta_map;
|
||||
};
|
||||
|
||||
static inline int
|
||||
mt7915_get_channel_group(int channel)
|
||||
{
|
||||
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 bool
|
||||
mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
|
||||
{
|
||||
u8 *eep = dev->mt76.eeprom.data;
|
||||
|
||||
/* TODO: DBDC */
|
||||
if (band == NL80211_BAND_5GHZ)
|
||||
return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_5G;
|
||||
else
|
||||
return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G;
|
||||
}
|
||||
|
||||
extern const struct sku_group mt7915_sku_groups[];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,701 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include "mt7915.h"
|
||||
#include "mac.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
static void mt7915_mac_init(struct mt7915_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536);
|
||||
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
|
||||
/* enable rx rate report */
|
||||
mt76_set(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN);
|
||||
/* disable hardware de-agg */
|
||||
mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
|
||||
|
||||
for (i = 0; i < MT7915_WTBL_SIZE; i++)
|
||||
mt7915_mac_wtbl_update(dev, i,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
mt7915_mac_init_band(dev, 0);
|
||||
mt7915_mac_init_band(dev, 1);
|
||||
mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b);
|
||||
}
|
||||
|
||||
static int mt7915_txbf_init(struct mt7915_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* TODO: DBDC & check whether iBF phase calibration data has
|
||||
* been stored in eeprom offset 0x651~0x7b8, then write down
|
||||
* 0x1111 into 0x651 and 0x651 to trigger iBF.
|
||||
*/
|
||||
|
||||
/* trigger sounding packets */
|
||||
ret = mt7915_mcu_set_txbf_sounding(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* enable iBF & eBF */
|
||||
return mt7915_mcu_set_txbf_type(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_init_txpower_band(struct mt7915_dev *dev,
|
||||
struct ieee80211_supported_band *sband)
|
||||
{
|
||||
int i, n_chains = hweight8(dev->mphy.antenna_mask);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
chan->max_power = min_t(int, chan->max_reg_power,
|
||||
target_power / 2);
|
||||
chan->orig_mpwr = target_power / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void mt7915_init_txpower(struct mt7915_dev *dev)
|
||||
{
|
||||
mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband);
|
||||
mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband);
|
||||
|
||||
mt7915_eeprom_init_sku(dev);
|
||||
}
|
||||
|
||||
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);
|
||||
mt7915_txbf_init(dev);
|
||||
}
|
||||
|
||||
static int mt7915_init_hardware(struct mt7915_dev *dev)
|
||||
{
|
||||
int ret, idx;
|
||||
|
||||
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
|
||||
|
||||
INIT_WORK(&dev->init_work, mt7915_init_work);
|
||||
spin_lock_init(&dev->token_lock);
|
||||
idr_init(&dev->token);
|
||||
|
||||
ret = mt7915_dma_init(dev);
|
||||
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;
|
||||
|
||||
/* Beacon and mgmt frames should occupy wcid 0 */
|
||||
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_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;
|
||||
}
|
||||
|
||||
#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), \
|
||||
}
|
||||
|
||||
static struct ieee80211_rate mt7915_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),
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits[] = {
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_ADHOC)
|
||||
}, {
|
||||
.max = MT7915_MAX_INTERFACES,
|
||||
.types = BIT(NL80211_IFTYPE_AP) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_STATION)
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
.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 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;
|
||||
struct cfg80211_chan_def *chandef = &mphy->chandef;
|
||||
|
||||
dev->mt76.region = request->dfs_region;
|
||||
|
||||
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return;
|
||||
|
||||
mt7915_dfs_init_radar_detector(phy);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_init_wiphy(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
|
||||
|
||||
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_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
|
||||
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
|
||||
|
||||
hw->max_tx_fragments = 4;
|
||||
}
|
||||
|
||||
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy)
|
||||
{
|
||||
int nss = hweight8(phy->chainmask);
|
||||
u32 *cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
|
||||
|
||||
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
|
||||
(3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
|
||||
|
||||
*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
|
||||
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
|
||||
|
||||
if (nss < 2)
|
||||
return;
|
||||
|
||||
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
||||
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE |
|
||||
FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
|
||||
nss - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
|
||||
int vif, int nss)
|
||||
{
|
||||
struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
|
||||
struct ieee80211_he_mcs_nss_supp *mcs = &he_cap->he_mcs_nss_supp;
|
||||
u8 c;
|
||||
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
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_BEAMFORMER_FB |
|
||||
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_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;
|
||||
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 (nss < 2)
|
||||
return;
|
||||
|
||||
if (vif != NL80211_IFTYPE_AP)
|
||||
return;
|
||||
|
||||
elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
|
||||
elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
|
||||
|
||||
/* num_snd_dim */
|
||||
c = (nss - 1) | (max_t(int, mcs->tx_mcs_160, 1) << 3);
|
||||
elem->phy_cap_info[5] |= c;
|
||||
|
||||
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
|
||||
IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB;
|
||||
elem->phy_cap_info[6] |= c;
|
||||
|
||||
/* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */
|
||||
elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3;
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_gen_ppe_thresh(u8 *he_ppet)
|
||||
{
|
||||
int ru, nss, max_nss = 1, max_ru = 3;
|
||||
u8 bit = 7, ru_bit_mask = 0x7;
|
||||
u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
|
||||
|
||||
he_ppet[0] = max_nss & IEEE80211_PPE_THRES_NSS_MASK;
|
||||
he_ppet[0] |= (ru_bit_mask <<
|
||||
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) &
|
||||
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK;
|
||||
|
||||
for (nss = 0; nss <= max_nss; nss++) {
|
||||
for (ru = 0; ru < max_ru; ru++) {
|
||||
u8 val;
|
||||
int i;
|
||||
|
||||
if (!(ru_bit_mask & BIT(ru)))
|
||||
continue;
|
||||
|
||||
val = (ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) &
|
||||
0x3f;
|
||||
val = ((val >> 3) & 0x7) | ((val & 0x7) << 3);
|
||||
for (i = 5; i >= 0; i--) {
|
||||
he_ppet[bit / 8] |=
|
||||
((val >> i) & 0x1) << ((bit % 8));
|
||||
bit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
|
||||
struct ieee80211_sband_iftype_data *data)
|
||||
{
|
||||
int i, idx = 0;
|
||||
int nss = hweight8(phy->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:
|
||||
#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[1] =
|
||||
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US |
|
||||
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1;
|
||||
he_cap_elem->mac_cap_info[2] =
|
||||
IEEE80211_HE_MAC_CAP2_BSR;
|
||||
he_cap_elem->mac_cap_info[3] =
|
||||
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
|
||||
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED;
|
||||
he_cap_elem->mac_cap_info[4] =
|
||||
IEEE80211_HE_MAC_CAP4_AMDSU_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 (band == NL80211_BAND_5GHZ)
|
||||
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 |
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_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;
|
||||
|
||||
/* TODO: OFDMA */
|
||||
|
||||
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[4] |=
|
||||
IEEE80211_HE_MAC_CAP4_BQR;
|
||||
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_PPE_THRESHOLD_PRESENT;
|
||||
he_cap_elem->phy_cap_info[9] |=
|
||||
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
he_cap_elem->mac_cap_info[0] |=
|
||||
IEEE80211_HE_MAC_CAP0_TWT_REQ;
|
||||
he_cap_elem->mac_cap_info[3] |=
|
||||
IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED;
|
||||
|
||||
if (band == NL80211_BAND_2GHZ)
|
||||
he_cap_elem->phy_cap_info[0] |=
|
||||
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
|
||||
else if (band == NL80211_BAND_5GHZ)
|
||||
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;
|
||||
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;
|
||||
he_cap_elem->phy_cap_info[9] |=
|
||||
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
|
||||
break;
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
|
||||
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
|
||||
he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
|
||||
he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
|
||||
he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map);
|
||||
he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map);
|
||||
|
||||
mt7915_set_stream_he_txbf_caps(he_cap, i, nss);
|
||||
|
||||
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) {
|
||||
mt7915_gen_ppe_thresh(he_cap->ppe_thres);
|
||||
} else {
|
||||
he_cap_elem->phy_cap_info[9] |=
|
||||
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
|
||||
{
|
||||
struct ieee80211_sband_iftype_data *data;
|
||||
struct ieee80211_supported_band *band;
|
||||
struct mt76_dev *mdev = &phy->dev->mt76;
|
||||
int n;
|
||||
|
||||
if (mdev->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;
|
||||
}
|
||||
|
||||
if (mdev->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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_cap_dbdc_enable(struct mt7915_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->phy.chainmask = dev->mphy.antenna_mask;
|
||||
dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask;
|
||||
dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
|
||||
|
||||
mt76_set_stream_caps(&dev->mphy, true);
|
||||
mt7915_set_stream_vht_txbf_caps(&dev->phy);
|
||||
mt7915_set_stream_he_caps(&dev->phy);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_cap_dbdc_disable(struct mt7915_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->phy.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);
|
||||
mt7915_set_stream_vht_txbf_caps(&dev->phy);
|
||||
mt7915_set_stream_he_caps(&dev->phy);
|
||||
}
|
||||
|
||||
int mt7915_register_ext_phy(struct mt7915_dev *dev)
|
||||
{
|
||||
struct mt7915_phy *phy = mt7915_ext_phy(dev);
|
||||
struct mt76_phy *mphy;
|
||||
int ret;
|
||||
bool bound;
|
||||
|
||||
/* TODO: enble DBDC */
|
||||
bound = mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5);
|
||||
if (!bound)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
|
||||
return -EINVAL;
|
||||
|
||||
if (phy)
|
||||
return 0;
|
||||
|
||||
INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
|
||||
mt7915_cap_dbdc_enable(dev);
|
||||
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops);
|
||||
if (!mphy)
|
||||
return -ENOMEM;
|
||||
|
||||
phy = mphy->priv;
|
||||
phy->dev = dev;
|
||||
phy->mt76 = mphy;
|
||||
phy->chainmask = dev->chainmask & ~dev->phy.chainmask;
|
||||
mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
|
||||
mt7915_init_wiphy(mphy->hw);
|
||||
|
||||
/*
|
||||
* Make the secondary PHY MAC address local without overlapping with
|
||||
* the usual MAC address allocation scheme on multiple virtual interfaces
|
||||
*/
|
||||
mphy->hw->wiphy->perm_addr[0] |= 2;
|
||||
mphy->hw->wiphy->perm_addr[0] ^= BIT(7);
|
||||
|
||||
/* The second interface does not get any packets unless it has a vif */
|
||||
ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
|
||||
|
||||
ret = mt76_register_phy(mphy);
|
||||
if (ret)
|
||||
ieee80211_free_hw(mphy->hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
|
||||
{
|
||||
struct mt7915_phy *phy = mt7915_ext_phy(dev);
|
||||
struct mt76_phy *mphy = dev->mt76.phy2;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mt7915_cap_dbdc_disable(dev);
|
||||
mt76_unregister_phy(mphy);
|
||||
ieee80211_free_hw(mphy->hw);
|
||||
}
|
||||
|
||||
int mt7915_register_device(struct mt7915_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;
|
||||
INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
spin_lock_init(&dev->sta_poll_lock);
|
||||
|
||||
init_waitqueue_head(&dev->reset_wait);
|
||||
INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
|
||||
|
||||
ret = mt7915_init_hardware(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt7915_init_wiphy(hw);
|
||||
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_7991 |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
|
||||
mt7915_cap_dbdc_disable(dev);
|
||||
dev->phy.dfs_state = -1;
|
||||
|
||||
ret = mt76_register_device(&dev->mt76, true, mt7915_rates,
|
||||
ARRAY_SIZE(mt7915_rates));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
|
||||
|
||||
return mt7915_init_debugfs(dev);
|
||||
}
|
||||
|
||||
void mt7915_unregister_device(struct mt7915_dev *dev)
|
||||
{
|
||||
struct mt76_txwi_cache *txwi;
|
||||
int id;
|
||||
|
||||
mt7915_unregister_ext_phy(dev);
|
||||
mt76_unregister_device(&dev->mt76);
|
||||
mt7915_mcu_exit(dev);
|
||||
mt7915_dma_cleanup(dev);
|
||||
|
||||
spin_lock_bh(&dev->token_lock);
|
||||
idr_for_each_entry(&dev->token, txwi, id) {
|
||||
mt7915_txp_skb_unmap(&dev->mt76, txwi);
|
||||
if (txwi->skb)
|
||||
dev_kfree_skb_any(txwi->skb);
|
||||
mt76_put_txwi(&dev->mt76, txwi);
|
||||
}
|
||||
spin_unlock_bh(&dev->token_lock);
|
||||
idr_destroy(&dev->token);
|
||||
|
||||
mt76_free_device(&dev->mt76);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,346 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#ifndef __MT7915_MAC_H
|
||||
#define __MT7915_MAC_H
|
||||
|
||||
#define MT_CT_PARSE_LEN 72
|
||||
#define MT_CT_DMA_BUF_NUM 2
|
||||
|
||||
#define MT_RXD0_LENGTH GENMASK(15, 0)
|
||||
#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)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
/* 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 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 DW4 */
|
||||
#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 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)
|
||||
|
||||
/* 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(9, 7)
|
||||
#define MT_PRXV_HT_AD_CODE BIT(11)
|
||||
#define MT_PRXV_HE_RU_ALLOC_L GENMASK(31, 28)
|
||||
#define MT_PRXV_HE_RU_ALLOC_H GENMASK(3, 0)
|
||||
#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)
|
||||
|
||||
/* 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_UPLINK BIT(31)
|
||||
|
||||
#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)
|
||||
|
||||
struct mt7915_rxv {
|
||||
u32 phy;
|
||||
|
||||
/* P-RXV: bit 0~1, C-RXV: bit 2~19 */
|
||||
__le32 v[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_pkt_queue_idx {
|
||||
MT_LMAC_AC00,
|
||||
MT_LMAC_AC01,
|
||||
MT_LMAC_AC02,
|
||||
MT_LMAC_AC03,
|
||||
MT_LMAC_ALTX0 = 0x10,
|
||||
MT_LMAC_BMC0 = 0x10,
|
||||
MT_LMAC_BCN0 = 0x12,
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
#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_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_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_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(2, 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_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_IDX GENMASK(5, 0)
|
||||
|
||||
#define MT_TXP_MAX_BUF_NUM 6
|
||||
|
||||
struct mt7915_txp {
|
||||
__le16 flags;
|
||||
__le16 token;
|
||||
u8 bss_idx;
|
||||
u8 rept_wds_wcid;
|
||||
u8 rsv;
|
||||
u8 nbuf;
|
||||
__le32 buf[MT_TXP_MAX_BUF_NUM];
|
||||
__le16 len[MT_TXP_MAX_BUF_NUM];
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct mt7915_tx_free {
|
||||
__le16 rx_byte_cnt;
|
||||
__le16 ctrl;
|
||||
u8 txd_cnt;
|
||||
u8 rsv[3];
|
||||
__le32 info[];
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
|
||||
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
|
||||
#define MT_TX_FREE_LATENCY 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)
|
||||
|
||||
struct mt7915_dfs_pulse {
|
||||
u32 max_width; /* us */
|
||||
int max_pwr; /* dbm */
|
||||
int min_pwr; /* dbm */
|
||||
u32 min_stgr_pri; /* us */
|
||||
u32 max_stgr_pri; /* us */
|
||||
u32 min_cr_pri; /* us */
|
||||
u32 max_cr_pri; /* us */
|
||||
};
|
||||
|
||||
struct mt7915_dfs_pattern {
|
||||
u8 enb;
|
||||
u8 stgr;
|
||||
u8 min_crpn;
|
||||
u8 max_crpn;
|
||||
u8 min_crpr;
|
||||
u8 min_pw;
|
||||
u32 min_pri;
|
||||
u32 max_pri;
|
||||
u8 max_pw;
|
||||
u8 min_crbn;
|
||||
u8 max_crbn;
|
||||
u8 min_stgpn;
|
||||
u8 max_stgpn;
|
||||
u8 min_stgpr;
|
||||
u8 rsv[2];
|
||||
u32 min_stgpr_diff;
|
||||
} __packed;
|
||||
|
||||
struct mt7915_dfs_radar_spec {
|
||||
struct mt7915_dfs_pulse pulse_th;
|
||||
struct mt7915_dfs_pattern radar_pattern[16];
|
||||
};
|
||||
|
||||
static inline struct mt7915_txp *
|
||||
mt7915_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 (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,833 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
static int mt7915_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
bool running;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
running = mt7915_dev_running(dev);
|
||||
|
||||
if (!running) {
|
||||
mt7915_mcu_set_pm(dev, 0, 0);
|
||||
mt7915_mcu_set_mac(dev, 0, true, false);
|
||||
mt7915_mcu_set_scs(dev, 0, true);
|
||||
}
|
||||
|
||||
if (phy != &dev->phy) {
|
||||
mt7915_mcu_set_pm(dev, 1, 0);
|
||||
mt7915_mcu_set_mac(dev, 1, true, false);
|
||||
mt7915_mcu_set_scs(dev, 1, true);
|
||||
}
|
||||
|
||||
mt7915_mcu_set_sku_en(phy, true);
|
||||
mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
|
||||
|
||||
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
|
||||
ieee80211_queue_delayed_work(hw, &phy->mac_work,
|
||||
MT7915_WATCHDOG_TIME);
|
||||
|
||||
if (!running)
|
||||
mt7915_mac_reset_counters(phy);
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7915_stop(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
|
||||
|
||||
if (phy != &dev->phy) {
|
||||
mt7915_mcu_set_pm(dev, 1, 1);
|
||||
mt7915_mcu_set_mac(dev, 1, false, false);
|
||||
}
|
||||
|
||||
if (!mt7915_dev_running(dev)) {
|
||||
mt7915_mcu_set_pm(dev, 0, 1);
|
||||
mt7915_mcu_set_mac(dev, 0, false, false);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
}
|
||||
|
||||
static int get_omac_idx(enum nl80211_iftype type, u32 mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (type) {
|
||||
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;
|
||||
|
||||
for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
|
||||
if (~mask & BIT(i))
|
||||
return i;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* station uses hw bssid other than 0 */
|
||||
for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
|
||||
if (~mask & BIT(i))
|
||||
return i;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
mvif->idx = ffs(~phy->vif_mask) - 1;
|
||||
if (mvif->idx >= MT7915_MAX_INTERFACES) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
idx = get_omac_idx(vif->type, phy->omac_mask);
|
||||
if (idx < 0) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
mvif->omac_idx = idx;
|
||||
mvif->dev = dev;
|
||||
mvif->band_idx = ext_phy;
|
||||
|
||||
if (ext_phy)
|
||||
mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) +
|
||||
mvif->idx % (MT7915_MAX_WMM_SETS / 2);
|
||||
else
|
||||
mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS;
|
||||
|
||||
ret = mt7915_mcu_add_dev_info(dev, vif, true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
phy->vif_mask |= BIT(mvif->idx);
|
||||
phy->omac_mask |= BIT(mvif->omac_idx);
|
||||
|
||||
idx = MT7915_WTBL_RESERVED - mvif->idx;
|
||||
|
||||
INIT_LIST_HEAD(&mvif->sta.poll_list);
|
||||
mvif->sta.wcid.idx = idx;
|
||||
mvif->sta.wcid.ext_phy = mvif->band_idx;
|
||||
mvif->sta.wcid.hw_key_idx = -1;
|
||||
mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
|
||||
mt7915_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 = &mvif->sta.wcid;
|
||||
mt76_txq_init(&dev->mt76, vif->txq);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* TODO: disable beacon for the bss */
|
||||
|
||||
mt7915_mcu_add_dev_info(dev, vif, false);
|
||||
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
|
||||
if (vif->txq)
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
phy->vif_mask &= ~BIT(mvif->idx);
|
||||
phy->omac_mask &= ~BIT(mvif->omac_idx);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
static void mt7915_init_dfs_state(struct mt7915_phy *phy)
|
||||
{
|
||||
struct mt76_phy *mphy = phy->mt76;
|
||||
struct ieee80211_hw *hw = mphy->hw;
|
||||
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
|
||||
|
||||
if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
return;
|
||||
|
||||
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return;
|
||||
|
||||
if (mphy->chandef.chan->center_freq == chandef->chan->center_freq &&
|
||||
mphy->chandef.width == chandef->width)
|
||||
return;
|
||||
|
||||
phy->dfs_state = -1;
|
||||
}
|
||||
|
||||
static int mt7915_set_channel(struct mt7915_phy *phy)
|
||||
{
|
||||
struct mt7915_dev *dev = phy->dev;
|
||||
int ret;
|
||||
|
||||
cancel_delayed_work_sync(&phy->mac_work);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
set_bit(MT76_RESET, &phy->mt76->state);
|
||||
|
||||
mt7915_init_dfs_state(phy);
|
||||
mt76_set_channel(phy->mt76);
|
||||
|
||||
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);
|
||||
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->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_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;
|
||||
int idx = key->keyidx;
|
||||
|
||||
/* 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;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
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) {
|
||||
key->hw_key_idx = wcid->idx;
|
||||
wcid->hw_key_idx = idx;
|
||||
} else if (idx == wcid->hw_key_idx) {
|
||||
wcid->hw_key_idx = -1;
|
||||
}
|
||||
mt76_wcid_key_setup(&dev->mt76, wcid,
|
||||
cmd == SET_KEY ? key : NULL);
|
||||
|
||||
return mt7915_mcu_add_key(dev, vif, msta, key, cmd);
|
||||
}
|
||||
|
||||
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);
|
||||
bool band = phy != &dev->phy;
|
||||
int ret;
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||
ieee80211_stop_queues(hw);
|
||||
ret = mt7915_set_channel(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
ieee80211_wake_queues(hw);
|
||||
}
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
||||
ret = mt7915_mcu_set_sku(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
|
||||
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);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 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 */
|
||||
mvif->wmm[queue].cw_min = params->cw_min;
|
||||
mvif->wmm[queue].cw_max = params->cw_max;
|
||||
mvif->wmm[queue].aifs = params->aifs;
|
||||
mvif->wmm[queue].txop = params->txop;
|
||||
|
||||
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 != &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;
|
||||
|
||||
#define MT76_FILTER(_flag, _hw) do { \
|
||||
flags |= *total_flags & FIF_##_flag; \
|
||||
phy->rxfilter &= ~(_hw); \
|
||||
phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
|
||||
} while (0)
|
||||
|
||||
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);
|
||||
|
||||
*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);
|
||||
}
|
||||
|
||||
static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *info,
|
||||
u32 changed)
|
||||
{
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
struct mt7915_dev *dev = mt7915_hw_dev(hw);
|
||||
|
||||
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) {
|
||||
bool join = !is_zero_ether_addr(info->bssid);
|
||||
|
||||
mt7915_mcu_add_bss_info(phy, vif, join);
|
||||
mt7915_mcu_add_sta(dev, vif, NULL, join);
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_ASSOC)
|
||||
mt7915_mcu_add_bss_info(phy, vif, info->assoc);
|
||||
|
||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||
int slottime = info->use_short_slot ? 9 : 20;
|
||||
|
||||
if (slottime != phy->slottime) {
|
||||
phy->slottime = slottime;
|
||||
mt7915_mac_set_timing(phy);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & BSS_CHANGED_BEACON_ENABLED) {
|
||||
mt7915_mcu_add_bss_info(phy, vif, info->enable_beacon);
|
||||
mt7915_mcu_add_sta(dev, vif, NULL, info->enable_beacon);
|
||||
}
|
||||
|
||||
/* 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_BEACON |
|
||||
BSS_CHANGED_BEACON_ENABLED))
|
||||
mt7915_mcu_add_beacon(hw, vif, info->enable_beacon);
|
||||
|
||||
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);
|
||||
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;
|
||||
int ret, idx;
|
||||
|
||||
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
INIT_LIST_HEAD(&msta->poll_list);
|
||||
INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work);
|
||||
spin_lock_init(&msta->ampdu_lock);
|
||||
msta->vif = mvif;
|
||||
msta->wcid.sta = 1;
|
||||
msta->wcid.idx = idx;
|
||||
msta->wcid.ext_phy = mvif->band_idx;
|
||||
msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
|
||||
msta->stats.jiffies = jiffies;
|
||||
|
||||
mt7915_mac_wtbl_update(dev, idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
ret = mt7915_mcu_add_sta(dev, vif, sta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7915_mcu_add_sta_adv(dev, vif, sta, true);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
mt7915_mcu_add_sta_adv(dev, vif, sta, false);
|
||||
mt7915_mcu_add_sta(dev, vif, sta, false);
|
||||
|
||||
mt7915_mac_wtbl_update(dev, msta->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->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);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
mt7915_mcu_set_rts_thresh(phy, val);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
mt7915_mcu_add_rx_ba(dev, params, true);
|
||||
break;
|
||||
case IEEE80211_AMPDU_RX_STOP:
|
||||
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
|
||||
mt7915_mcu_add_rx_ba(dev, params, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_OPERATIONAL:
|
||||
mtxq->aggr = true;
|
||||
mtxq->send_bar = false;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL);
|
||||
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;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
|
||||
mt7915_mcu_add_tx_ba(dev, params, false);
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START);
|
||||
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
|
||||
break;
|
||||
case IEEE80211_AMPDU_TX_STOP_CONT:
|
||||
mtxq->aggr = false;
|
||||
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
|
||||
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 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
struct mt7915_phy *phy = mt7915_hw_phy(hw);
|
||||
bool band = phy != &dev->phy;
|
||||
union {
|
||||
u64 t64;
|
||||
u32 t32[2];
|
||||
} tsf;
|
||||
u16 n;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->omac_idx;
|
||||
/* TSF software read */
|
||||
mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE);
|
||||
tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band));
|
||||
tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band));
|
||||
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return tsf.t64;
|
||||
}
|
||||
|
||||
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 != &dev->phy;
|
||||
union {
|
||||
u64 t64;
|
||||
u32 t32[2];
|
||||
} tsf = { .t64 = timestamp, };
|
||||
u16 n;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
n = mvif->omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->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 */
|
||||
mt76_set(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_WRITE);
|
||||
|
||||
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);
|
||||
|
||||
phy->coverage_class = max_t(s16, coverage_class, 0);
|
||||
mt7915_mac_set_timing(phy);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
phy->mt76->antenna_mask = tx_ant;
|
||||
|
||||
if (ext_phy) {
|
||||
if (dev->chainmask == 0xf)
|
||||
tx_ant <<= 2;
|
||||
else
|
||||
tx_ant <<= 1;
|
||||
}
|
||||
phy->chainmask = tx_ant;
|
||||
|
||||
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_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
struct mt7915_sta_stats *stats = &msta->stats;
|
||||
|
||||
if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
|
||||
return;
|
||||
|
||||
if (stats->tx_rate.legacy) {
|
||||
sinfo->txrate.legacy = stats->tx_rate.legacy;
|
||||
} else {
|
||||
sinfo->txrate.mcs = stats->tx_rate.mcs;
|
||||
sinfo->txrate.nss = stats->tx_rate.nss;
|
||||
sinfo->txrate.bw = stats->tx_rate.bw;
|
||||
sinfo->txrate.he_gi = stats->tx_rate.he_gi;
|
||||
sinfo->txrate.he_dcm = stats->tx_rate.he_dcm;
|
||||
sinfo->txrate.he_ru_alloc = stats->tx_rate.he_ru_alloc;
|
||||
}
|
||||
sinfo->txrate.flags = stats->tx_rate.flags;
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7915_sta_rc_update(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
u32 changed)
|
||||
{
|
||||
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
|
||||
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, sta->addr);
|
||||
if (!sta) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_lock();
|
||||
|
||||
set_bit(changed, &msta->stats.changed);
|
||||
ieee80211_queue_work(hw, &msta->stats_work);
|
||||
}
|
||||
|
||||
const struct ieee80211_ops mt7915_ops = {
|
||||
.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,
|
||||
.sta_add = mt7915_sta_add,
|
||||
.sta_remove = mt7915_sta_remove,
|
||||
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
|
||||
.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,
|
||||
.channel_switch_beacon = mt7915_channel_switch_beacon,
|
||||
.get_stats = mt7915_get_stats,
|
||||
.get_tsf = mt7915_get_tsf,
|
||||
.set_tsf = mt7915_set_tsf,
|
||||
.get_survey = mt76_get_survey,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
.set_antenna = mt7915_set_antenna,
|
||||
.set_coverage_class = mt7915_set_coverage_class,
|
||||
.sta_statistics = mt7915_sta_statistics,
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
.sta_add_debugfs = mt7915_sta_add_debugfs,
|
||||
#endif
|
||||
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,467 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#ifndef __MT7915_H
|
||||
#define __MT7915_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ktime.h>
|
||||
#include "../mt76.h"
|
||||
#include "regs.h"
|
||||
|
||||
#define MT7915_MAX_INTERFACES 4
|
||||
#define MT7915_MAX_WMM_SETS 4
|
||||
#define MT7915_WTBL_SIZE 288
|
||||
#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 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 MT7915_EEPROM_SIZE 3584
|
||||
#define MT7915_TOKEN_SIZE 8192
|
||||
|
||||
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
|
||||
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
|
||||
#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
|
||||
#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */
|
||||
|
||||
#define MT7915_SKU_RATE_NUM 161
|
||||
#define MT7915_SKU_MAX_DELTA_IDX MT7915_SKU_RATE_NUM
|
||||
#define MT7915_SKU_TABLE_SIZE (MT7915_SKU_RATE_NUM + 1)
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
enum mt7915_ampdu_state {
|
||||
MT7915_AGGR_STOP,
|
||||
MT7915_AGGR_PROGRESS,
|
||||
MT7915_AGGR_START,
|
||||
MT7915_AGGR_OPERATIONAL
|
||||
};
|
||||
|
||||
struct mt7915_sta_stats {
|
||||
struct rate_info prob_rate;
|
||||
struct rate_info tx_rate;
|
||||
|
||||
unsigned long per;
|
||||
unsigned long changed;
|
||||
unsigned long jiffies;
|
||||
};
|
||||
|
||||
struct mt7915_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
struct mt7915_vif *vif;
|
||||
|
||||
struct list_head poll_list;
|
||||
u32 airtime_ac[8];
|
||||
|
||||
struct mt7915_sta_stats stats;
|
||||
struct work_struct stats_work;
|
||||
|
||||
spinlock_t ampdu_lock;
|
||||
enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS];
|
||||
};
|
||||
|
||||
struct mt7915_vif {
|
||||
u16 idx;
|
||||
u8 omac_idx;
|
||||
u8 band_idx;
|
||||
u8 wmm_idx;
|
||||
|
||||
struct {
|
||||
u16 cw_min;
|
||||
u16 cw_max;
|
||||
u16 txop;
|
||||
u8 aifs;
|
||||
} wmm[IEEE80211_NUM_ACS];
|
||||
|
||||
struct mt7915_sta sta;
|
||||
struct mt7915_dev *dev;
|
||||
};
|
||||
|
||||
struct mib_stats {
|
||||
u16 ack_fail_cnt;
|
||||
u16 fcs_err_cnt;
|
||||
u16 rts_cnt;
|
||||
u16 rts_retries_cnt;
|
||||
u16 ba_miss_cnt;
|
||||
};
|
||||
|
||||
struct mt7915_phy {
|
||||
struct mt76_phy *mt76;
|
||||
struct mt7915_dev *dev;
|
||||
|
||||
struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES];
|
||||
|
||||
u32 rxfilter;
|
||||
u32 vif_mask;
|
||||
u32 omac_mask;
|
||||
|
||||
u16 noise;
|
||||
u16 chainmask;
|
||||
|
||||
s16 coverage_class;
|
||||
u8 slottime;
|
||||
|
||||
u8 rdd_state;
|
||||
int dfs_state;
|
||||
|
||||
__le32 rx_ampdu_ts;
|
||||
u32 ampdu_ref;
|
||||
|
||||
struct mib_stats mib;
|
||||
|
||||
struct delayed_work mac_work;
|
||||
u8 mac_work_count;
|
||||
};
|
||||
|
||||
struct mt7915_dev {
|
||||
union { /* must be first */
|
||||
struct mt76_dev mt76;
|
||||
struct mt76_phy mphy;
|
||||
};
|
||||
|
||||
struct mt7915_phy phy;
|
||||
|
||||
u16 chainmask;
|
||||
|
||||
struct work_struct init_work;
|
||||
struct work_struct reset_work;
|
||||
wait_queue_head_t reset_wait;
|
||||
u32 reset_state;
|
||||
|
||||
struct list_head sta_poll_list;
|
||||
spinlock_t sta_poll_lock;
|
||||
|
||||
u32 hw_pattern;
|
||||
|
||||
spinlock_t token_lock;
|
||||
struct idr token;
|
||||
|
||||
s8 **rate_power; /* TODO: use mt76_rate_power */
|
||||
|
||||
bool fw_debug;
|
||||
};
|
||||
|
||||
enum {
|
||||
HW_BSSID_0 = 0x0,
|
||||
HW_BSSID_1,
|
||||
HW_BSSID_2,
|
||||
HW_BSSID_3,
|
||||
HW_BSSID_MAX,
|
||||
EXT_BSSID_START = 0x10,
|
||||
EXT_BSSID_1,
|
||||
EXT_BSSID_2,
|
||||
EXT_BSSID_3,
|
||||
EXT_BSSID_4,
|
||||
EXT_BSSID_5,
|
||||
EXT_BSSID_6,
|
||||
EXT_BSSID_7,
|
||||
EXT_BSSID_8,
|
||||
EXT_BSSID_9,
|
||||
EXT_BSSID_10,
|
||||
EXT_BSSID_11,
|
||||
EXT_BSSID_12,
|
||||
EXT_BSSID_13,
|
||||
EXT_BSSID_14,
|
||||
EXT_BSSID_15,
|
||||
EXT_BSSID_END
|
||||
};
|
||||
|
||||
enum {
|
||||
MT_RX_SEL0,
|
||||
MT_RX_SEL1,
|
||||
};
|
||||
|
||||
enum mt7915_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,
|
||||
};
|
||||
|
||||
enum {
|
||||
RATE_CTRL_RU_INFO,
|
||||
RATE_CTRL_FIXED_RATE_INFO,
|
||||
RATE_CTRL_DUMP_INFO,
|
||||
RATE_CTRL_MU_INFO,
|
||||
};
|
||||
|
||||
static inline struct mt7915_phy *
|
||||
mt7915_hw_phy(struct ieee80211_hw *hw)
|
||||
{
|
||||
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.phy2;
|
||||
|
||||
if (!phy)
|
||||
return NULL;
|
||||
|
||||
return phy->priv;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid,
|
||||
enum mt7915_ampdu_state state)
|
||||
{
|
||||
spin_lock_bh(&msta->ampdu_lock);
|
||||
msta->ampdu_state[tid] = state;
|
||||
spin_unlock_bh(&msta->ampdu_lock);
|
||||
}
|
||||
|
||||
extern const struct ieee80211_ops mt7915_ops;
|
||||
extern struct pci_driver mt7915_pci_driver;
|
||||
|
||||
u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr);
|
||||
|
||||
int mt7915_register_device(struct mt7915_dev *dev);
|
||||
void mt7915_unregister_device(struct mt7915_dev *dev);
|
||||
int mt7915_register_ext_phy(struct mt7915_dev *dev);
|
||||
void mt7915_unregister_ext_phy(struct mt7915_dev *dev);
|
||||
int mt7915_eeprom_init(struct mt7915_dev *dev);
|
||||
u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset);
|
||||
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
|
||||
struct ieee80211_channel *chan,
|
||||
u8 chain_idx);
|
||||
void mt7915_eeprom_init_sku(struct mt7915_dev *dev);
|
||||
int mt7915_dma_init(struct mt7915_dev *dev);
|
||||
void mt7915_dma_prefetch(struct mt7915_dev *dev);
|
||||
void mt7915_dma_cleanup(struct mt7915_dev *dev);
|
||||
int mt7915_mcu_init(struct mt7915_dev *dev);
|
||||
int mt7915_mcu_add_dev_info(struct mt7915_dev *dev,
|
||||
struct ieee80211_vif *vif, bool enable);
|
||||
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
|
||||
struct ieee80211_vif *vif, int enable);
|
||||
int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, bool enable);
|
||||
int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, bool enable);
|
||||
int mt7915_mcu_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_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
||||
struct mt7915_sta *msta, struct ieee80211_key_conf *key,
|
||||
enum set_key_cmd cmd);
|
||||
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
int enable);
|
||||
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
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_set_fixed_rate(struct mt7915_dev *dev,
|
||||
struct ieee80211_sta *sta, u32 rate);
|
||||
int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
|
||||
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
|
||||
int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
|
||||
bool hdr_trans);
|
||||
int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable);
|
||||
int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
|
||||
int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val);
|
||||
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter);
|
||||
int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
|
||||
int mt7915_mcu_set_sku(struct mt7915_phy *phy);
|
||||
int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev);
|
||||
int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev);
|
||||
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_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
|
||||
int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index);
|
||||
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
|
||||
u8 index, u8 rx_sel, u8 val);
|
||||
int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, 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 bool is_mt7915(struct mt76_dev *dev)
|
||||
{
|
||||
return mt76_chip(dev) == 0x7915;
|
||||
}
|
||||
|
||||
static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask)
|
||||
{
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
|
||||
}
|
||||
|
||||
static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
|
||||
{
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
}
|
||||
|
||||
static inline 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);
|
||||
|
||||
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
|
||||
mt7915_l1_rr(struct mt7915_dev *dev, u32 addr)
|
||||
{
|
||||
return mt76_rr(dev, mt7915_reg_map_l1(dev, addr));
|
||||
}
|
||||
|
||||
static inline void
|
||||
mt7915_l1_wr(struct mt7915_dev *dev, u32 addr, u32 val)
|
||||
{
|
||||
mt76_wr(dev, mt7915_reg_map_l1(dev, addr), val);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
mt7915_l1_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
|
||||
{
|
||||
val |= mt7915_l1_rr(dev, addr) & ~mask;
|
||||
mt7915_l1_wr(dev, addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#define mt7915_l1_set(dev, addr, val) mt7915_l1_rmw(dev, addr, 0, val)
|
||||
#define mt7915_l1_clear(dev, addr, val) mt7915_l1_rmw(dev, addr, val, 0)
|
||||
|
||||
static inline u32
|
||||
mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr)
|
||||
{
|
||||
u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr);
|
||||
u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr);
|
||||
|
||||
mt76_rmw_field(dev, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, base);
|
||||
/* use read to push write */
|
||||
mt76_rr(dev, MT_HIF_REMAP_L2);
|
||||
|
||||
return MT_HIF_REMAP_BASE_L2 + offset;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
mt7915_l2_rr(struct mt7915_dev *dev, u32 addr)
|
||||
{
|
||||
return mt76_rr(dev, mt7915_reg_map_l2(dev, addr));
|
||||
}
|
||||
|
||||
static inline void
|
||||
mt7915_l2_wr(struct mt7915_dev *dev, u32 addr, u32 val)
|
||||
{
|
||||
mt76_wr(dev, mt7915_reg_map_l2(dev, addr), val);
|
||||
}
|
||||
|
||||
static inline u32
|
||||
mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
|
||||
{
|
||||
val |= mt7915_l2_rr(dev, addr) & ~mask;
|
||||
mt7915_l2_wr(dev, addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#define mt7915_l2_set(dev, addr, val) mt7915_l2_rmw(dev, addr, 0, val)
|
||||
#define mt7915_l2_clear(dev, addr, val) mt7915_l2_rmw(dev, addr, val, 0)
|
||||
|
||||
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_sta_poll(struct mt7915_dev *dev);
|
||||
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key, bool beacon);
|
||||
void mt7915_mac_set_timing(struct mt7915_phy *phy);
|
||||
int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb);
|
||||
void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb);
|
||||
int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
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_sta_stats_work(struct work_struct *work);
|
||||
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_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
struct mt76_queue_entry *e);
|
||||
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
|
||||
struct sk_buff *skb);
|
||||
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
|
||||
void mt7915_stats_work(struct work_struct *work);
|
||||
void mt7915_txp_skb_unmap(struct mt76_dev *dev,
|
||||
struct mt76_txwi_cache *txwi);
|
||||
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_dev *mdev);
|
||||
int mt7915_init_debugfs(struct mt7915_dev *dev);
|
||||
#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
|
||||
|
||||
#endif
|
|
@ -0,0 +1,191 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/* Copyright (C) 2020 MediaTek Inc.
|
||||
*
|
||||
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "mt7915.h"
|
||||
#include "mac.h"
|
||||
#include "../trace.h"
|
||||
|
||||
static const struct pci_device_id mt7915_pci_device_table[] = {
|
||||
{ PCI_DEVICE(0x14c3, 0x7915) },
|
||||
{ },
|
||||
};
|
||||
|
||||
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_DONE(q));
|
||||
}
|
||||
|
||||
/* TODO: support 2/4/6/8 MSI-X vectors */
|
||||
static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
|
||||
{
|
||||
struct mt7915_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_TX_DONE_ALL) {
|
||||
mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL);
|
||||
napi_schedule(&dev->mt76.tx_napi);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_DATA) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA);
|
||||
napi_schedule(&dev->mt76.napi[0]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_WM) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_WM);
|
||||
napi_schedule(&dev->mt76.napi[1]);
|
||||
}
|
||||
|
||||
if (intr & MT_INT_RX_DONE_WA) {
|
||||
mt7915_irq_disable(dev, MT_INT_RX_DONE_WA);
|
||||
napi_schedule(&dev->mt76.napi[2]);
|
||||
}
|
||||
|
||||
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) {
|
||||
dev->reset_state = val;
|
||||
ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
|
||||
wake_up(&dev->reset_wait);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev)
|
||||
{
|
||||
#define NUM_BANDS 2
|
||||
int i;
|
||||
s8 **sku;
|
||||
|
||||
sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL);
|
||||
if (!sku)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < NUM_BANDS; i++) {
|
||||
sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE *
|
||||
sizeof(**sku), GFP_KERNEL);
|
||||
if (!sku[i])
|
||||
return -ENOMEM;
|
||||
}
|
||||
dev->rate_power = sku;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7915_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 mt7915_txp),
|
||||
.drv_flags = MT_DRV_TXWI_NO_FREE,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_BSS_RX,
|
||||
.tx_prepare_skb = mt7915_tx_prepare_skb,
|
||||
.tx_complete_skb = mt7915_tx_complete_skb,
|
||||
.rx_skb = mt7915_queue_rx_skb,
|
||||
.rx_poll_complete = mt7915_rx_poll_complete,
|
||||
.sta_ps = mt7915_sta_ps,
|
||||
.sta_add = mt7915_mac_sta_add,
|
||||
.sta_remove = mt7915_mac_sta_remove,
|
||||
.update_survey = mt7915_update_channel,
|
||||
};
|
||||
struct mt7915_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 = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops,
|
||||
&drv_ops);
|
||||
if (!mdev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
ret = mt7915_alloc_device(pdev, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
|
||||
mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) |
|
||||
(mt7915_l1_rr(dev, MT_HW_REV) & 0xff);
|
||||
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
|
||||
|
||||
/* master switch of PCIe tnterrupt enable */
|
||||
mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
|
||||
|
||||
ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt7915_register_device(dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mt7915_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct mt76_dev *mdev = pci_get_drvdata(pdev);
|
||||
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
|
||||
|
||||
mt7915_unregister_device(dev);
|
||||
}
|
||||
|
||||
struct pci_driver mt7915_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = mt7915_pci_device_table,
|
||||
.probe = mt7915_pci_probe,
|
||||
.remove = mt7915_pci_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(mt7915_pci_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table);
|
||||
MODULE_FIRMWARE(MT7915_FIRMWARE_WA);
|
||||
MODULE_FIRMWARE(MT7915_FIRMWARE_WM);
|
||||
MODULE_FIRMWARE(MT7915_ROM_PATCH);
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -0,0 +1,375 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (C) 2020 MediaTek Inc. */
|
||||
|
||||
#ifndef __MT7915_REGS_H
|
||||
#define __MT7915_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 0x8000
|
||||
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
|
||||
|
||||
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
|
||||
#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
|
||||
#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8)
|
||||
#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc)
|
||||
|
||||
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
|
||||
((n) << 2))
|
||||
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
|
||||
|
||||
#define MT_MDP_BASE 0xf000
|
||||
#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_DCR1 MT_MDP(0x004)
|
||||
#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3)
|
||||
|
||||
#define MT_MDP_BNRCFR0(_band) MT_MDP(0x070 + ((_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(0x074 + ((_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
|
||||
|
||||
/* TMAC: band 0(0x21000), band 1(0xa1000) */
|
||||
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
|
||||
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
|
||||
|
||||
#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)
|
||||
|
||||
/* DMA Band 0 */
|
||||
#define MT_WF_DMA_BASE 0x21e00
|
||||
#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, 3)
|
||||
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
|
||||
|
||||
/* ETBF: band 0(0x24000), band 1(0xa4000) */
|
||||
#define MT_WF_ETBF_BASE(_band) ((_band) ? 0xa4000 : 0x24000)
|
||||
#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_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(0x24200), band 1(0xa4200) */
|
||||
#define MT_WF_LPON_BASE(_band) ((_band) ? 0xa4200 : 0x24200)
|
||||
#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)
|
||||
|
||||
/* MIB: band 0(0x24800), band 1(0xa4800) */
|
||||
#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
|
||||
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
|
||||
|
||||
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014)
|
||||
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
|
||||
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
|
||||
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
|
||||
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
|
||||
#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
|
||||
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
|
||||
|
||||
#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_RTS_COUNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4))
|
||||
#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, 0x108 + ((n) << 4))
|
||||
#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2))
|
||||
#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2))
|
||||
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2))
|
||||
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
|
||||
|
||||
#define MT_WTBLON_TOP_BASE 0x34000
|
||||
#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
|
||||
#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x0)
|
||||
#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
|
||||
|
||||
#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x030)
|
||||
#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)
|
||||
|
||||
#define MT_WTBL_BASE 0x38000
|
||||
#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) ? 0xa0800 : 0x20800)
|
||||
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
|
||||
|
||||
#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)
|
||||
|
||||
/* ARB: band 0(0x20c00), band 1(0xa0c00) */
|
||||
#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
|
||||
#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)
|
||||
|
||||
/* RMAC: band 0(0x21400), band 1(0xa1400) */
|
||||
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
|
||||
#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_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_RST_DTX_PTR MT_WFDMA0(0x20c)
|
||||
#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0)
|
||||
|
||||
#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x500)
|
||||
|
||||
#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)
|
||||
|
||||
/* 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_MCU_CMD MT_WFDMA1(0x1f0)
|
||||
#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_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_RST_DTX_PTR MT_WFDMA1(0x20c)
|
||||
#define MT_WFDMA1_PRI_DLY_INT_CFG0 MT_WFDMA1(0x2f0)
|
||||
|
||||
#define MT_TX_RING_BASE MT_WFDMA1(0x300)
|
||||
#define MT_RX_EVENT_RING_BASE MT_WFDMA1(0x500)
|
||||
|
||||
#define MT_WFDMA1_TX_RING0_EXT_CTRL MT_WFDMA1(0x600)
|
||||
#define MT_WFDMA1_TX_RING1_EXT_CTRL MT_WFDMA1(0x604)
|
||||
#define MT_WFDMA1_TX_RING2_EXT_CTRL MT_WFDMA1(0x608)
|
||||
#define MT_WFDMA1_TX_RING3_EXT_CTRL MT_WFDMA1(0x60c)
|
||||
#define MT_WFDMA1_TX_RING4_EXT_CTRL MT_WFDMA1(0x610)
|
||||
#define MT_WFDMA1_TX_RING5_EXT_CTRL MT_WFDMA1(0x614)
|
||||
#define MT_WFDMA1_TX_RING6_EXT_CTRL MT_WFDMA1(0x618)
|
||||
#define MT_WFDMA1_TX_RING7_EXT_CTRL MT_WFDMA1(0x61c)
|
||||
|
||||
#define MT_WFDMA1_TX_RING16_EXT_CTRL MT_WFDMA1(0x640)
|
||||
#define MT_WFDMA1_TX_RING17_EXT_CTRL MT_WFDMA1(0x644)
|
||||
#define MT_WFDMA1_TX_RING18_EXT_CTRL MT_WFDMA1(0x648)
|
||||
#define MT_WFDMA1_TX_RING19_EXT_CTRL MT_WFDMA1(0x64c)
|
||||
#define MT_WFDMA1_TX_RING20_EXT_CTRL MT_WFDMA1(0x650)
|
||||
#define MT_WFDMA1_TX_RING21_EXT_CTRL MT_WFDMA1(0x654)
|
||||
#define MT_WFDMA1_TX_RING22_EXT_CTRL MT_WFDMA1(0x658)
|
||||
#define MT_WFDMA1_TX_RING23_EXT_CTRL MT_WFDMA1(0x65c)
|
||||
|
||||
#define MT_WFDMA1_RX_RING0_EXT_CTRL MT_WFDMA1(0x680)
|
||||
#define MT_WFDMA1_RX_RING1_EXT_CTRL MT_WFDMA1(0x684)
|
||||
#define MT_WFDMA1_RX_RING2_EXT_CTRL MT_WFDMA1(0x688)
|
||||
#define MT_WFDMA1_RX_RING3_EXT_CTRL MT_WFDMA1(0x68c)
|
||||
|
||||
/* WFDMA CSR */
|
||||
#define MT_WFDMA_EXT_CSR_BASE 0xd7000
|
||||
#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs))
|
||||
|
||||
#define MT_INT_SOURCE_CSR MT_WFDMA_EXT_CSR(0x10)
|
||||
#define MT_INT_MASK_CSR MT_WFDMA_EXT_CSR(0x14)
|
||||
#define MT_INT_RX_DONE_DATA BIT(16)
|
||||
#define MT_INT_RX_DONE_WM BIT(0)
|
||||
#define MT_INT_RX_DONE_WA BIT(1)
|
||||
#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16))
|
||||
#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16))
|
||||
#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30))
|
||||
#define MT_INT_MCU_CMD BIT(29)
|
||||
|
||||
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
|
||||
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
|
||||
|
||||
/* WFDMA0 PCIE1 */
|
||||
#define MT_WFDMA0_PCIE1_BASE 0xd8000
|
||||
#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_WFDMA0_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)
|
||||
|
||||
#define MT_INFRA_CFG_BASE 0xf1000
|
||||
#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs))
|
||||
|
||||
#define MT_HIF_REMAP_L1 MT_INFRA(0x1ac)
|
||||
#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 MT_INFRA(0x1b0)
|
||||
#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 0x00000
|
||||
|
||||
#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_HW_BOUND 0x70010020
|
||||
#define MT_HW_CHIPID 0x70010200
|
||||
#define MT_HW_REV 0x70010204
|
||||
|
||||
#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)
|
||||
|
||||
/* PHY: band 0(0x83080000), band 1(0x83090000) */
|
||||
#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_STSCNT_EN GENMASK(11, 9)
|
||||
|
||||
#endif
|
|
@ -101,19 +101,17 @@ mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
|
|||
{
|
||||
__skb_queue_head_init(list);
|
||||
spin_lock_bh(&dev->status_list.lock);
|
||||
__acquire(&dev->status_list.lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_tx_status_lock);
|
||||
|
||||
void
|
||||
mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
|
||||
__releases(&dev->status_list.unlock)
|
||||
__releases(&dev->status_list.lock)
|
||||
{
|
||||
struct ieee80211_hw *hw;
|
||||
struct sk_buff *skb;
|
||||
|
||||
spin_unlock_bh(&dev->status_list.lock);
|
||||
__release(&dev->status_list.unlock);
|
||||
|
||||
while ((skb = __skb_dequeue(list)) != NULL) {
|
||||
hw = mt76_tx_status_get_hw(dev, skb);
|
||||
|
|
|
@ -1009,8 +1009,19 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
|
|||
|
||||
static u8 mt76u_ac_to_hwq(struct mt76_dev *dev, u8 ac)
|
||||
{
|
||||
if (mt76_chip(dev) == 0x7663)
|
||||
return ac ^ 0x3;
|
||||
if (mt76_chip(dev) == 0x7663) {
|
||||
static const u8 wmm_queue_map[] = {
|
||||
[IEEE80211_AC_VO] = 0,
|
||||
[IEEE80211_AC_VI] = 1,
|
||||
[IEEE80211_AC_BE] = 2,
|
||||
[IEEE80211_AC_BK] = 4,
|
||||
};
|
||||
|
||||
if (WARN_ON(ac >= ARRAY_SIZE(wmm_queue_map)))
|
||||
return 2; /* BE */
|
||||
|
||||
return wmm_queue_map[ac];
|
||||
}
|
||||
|
||||
return mt76_ac_to_hwq(ac);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ int mt76_wcid_alloc(unsigned long *mask, int size)
|
|||
{
|
||||
int i, idx = 0, cur;
|
||||
|
||||
for (i = 0; i < size / BITS_PER_LONG; i++) {
|
||||
for (i = 0; i < DIV_ROUND_UP(size, BITS_PER_LONG); i++) {
|
||||
idx = ffs(~mask[i]);
|
||||
if (!idx)
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue