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:
Kalle Valo 2020-05-18 15:03:37 +03:00
commit eda31200e6
70 changed files with 14050 additions and 1022 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) },
{ },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */
{ },
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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