mt76 patches for 5.11

* mt7915 fixes
 * mt7615 fixes
 * support for more sta interfaces on mt7615/mt7915
 * mt7915 encap offload
 * performance improvements
 * channel noise report on mt7915
 * usb/sdio support improvements
 * mt7915 testmode support
 * mt7915 DBDC support
 * warning fixes
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - http://gpgtools.org
 
 iEYEABECAAYFAl/KqTkACgkQ130UHQKnbvXb1QCg4DV/w3VNHYPn2Cdckf3FBbPq
 n+wAoN9suskTCA4rv7ieH610laAyLxnP
 =0ZQ4
 -----END PGP SIGNATURE-----

Merge tag 'mt76-for-kvalo-2020-12-04' of https://github.com/nbd168/wireless

mt76 patches for 5.11

* mt7915 fixes
* mt7615 fixes
* support for more sta interfaces on mt7615/mt7915
* mt7915 encap offload
* performance improvements
* channel noise report on mt7915
* usb/sdio support improvements
* mt7915 testmode support
* mt7915 DBDC support
* warning fixes
This commit is contained in:
Kalle Valo 2020-12-08 09:39:43 +02:00
commit d3b6fab909
76 changed files with 3459 additions and 2166 deletions

View File

@ -30,8 +30,8 @@ int mt76_queues_read(struct seq_file *s, void *data)
struct mt76_dev *dev = dev_get_drvdata(s->private);
int i;
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
struct mt76_queue *q = dev->q_tx[i];
for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
struct mt76_queue *q = dev->phy.q_tx[i];
if (!q)
continue;

View File

@ -72,9 +72,11 @@ mt76_free_pending_txwi(struct mt76_dev *dev)
{
struct mt76_txwi_cache *t;
local_bh_disable();
while ((t = __mt76_get_txwi(dev)) != NULL)
dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
local_bh_enable();
}
static int
@ -86,6 +88,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int i;
spin_lock_init(&q->lock);
spin_lock_init(&q->cleanup_lock);
q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
q->ndesc = n_desc;
@ -215,16 +218,15 @@ mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
}
static void
mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_entry entry;
bool wake = false;
int last;
if (!q)
return;
spin_lock_bh(&q->cleanup_lock);
if (flush)
last = -1;
else
@ -237,13 +239,13 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
if (entry.txwi) {
if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
mt76_put_txwi(dev, entry.txwi);
wake = !flush;
}
if (!flush && q->tail == last)
last = readl(&q->regs->dma_idx);
}
spin_unlock_bh(&q->cleanup_lock);
if (flush) {
spin_lock_bh(&q->lock);
@ -252,16 +254,8 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
spin_unlock_bh(&q->lock);
}
wake = wake && q->stopped &&
qid < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8;
if (wake)
q->stopped = false;
if (!q->queued)
wake_up(&dev->tx_wait);
if (wake)
ieee80211_wake_queue(dev->hw, qid);
}
static void *
@ -312,10 +306,9 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
}
static int
mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
@ -343,11 +336,10 @@ error:
}
static int
mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@ -397,7 +389,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info);
ret = dev->drv->tx_prepare_skb(dev, txwi, q->qid, wcid, sta, &tx_info);
dma_sync_single_for_device(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
if (ret < 0)
@ -661,8 +653,15 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_worker_disable(&dev->tx_worker);
netif_napi_del(&dev->tx_napi);
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
mt76_dma_tx_cleanup(dev, i, true);
for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
mt76_dma_tx_cleanup(dev, dev->phy.q_tx[i], true);
if (dev->phy2)
mt76_dma_tx_cleanup(dev, dev->phy2->q_tx[i], true);
}
for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++)
mt76_dma_tx_cleanup(dev, dev->q_mcu[i], true);
mt76_for_each_q_rx(dev, i) {
netif_napi_del(&dev->napi[i]);

View File

@ -88,8 +88,10 @@ out_put_node:
}
void
mt76_eeprom_override(struct mt76_dev *dev)
mt76_eeprom_override(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
#ifdef CONFIG_OF
struct device_node *np = dev->dev->of_node;
const u8 *mac = NULL;
@ -97,14 +99,14 @@ mt76_eeprom_override(struct mt76_dev *dev)
if (np)
mac = of_get_mac_address(np);
if (!IS_ERR_OR_NULL(mac))
ether_addr_copy(dev->macaddr, mac);
ether_addr_copy(phy->macaddr, mac);
#endif
if (!is_valid_ether_addr(dev->macaddr)) {
eth_random_addr(dev->macaddr);
if (!is_valid_ether_addr(phy->macaddr)) {
eth_random_addr(phy->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
dev->macaddr);
phy->macaddr);
}
}
EXPORT_SYMBOL_GPL(mt76_eeprom_override);

View File

@ -159,21 +159,22 @@ static void mt76_init_stream_cap(struct mt76_phy *phy,
void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
{
if (phy->dev->cap.has_2ghz)
if (phy->cap.has_2ghz)
mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
if (phy->dev->cap.has_5ghz)
if (phy->cap.has_5ghz)
mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
}
EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
static int
mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
const struct ieee80211_channel *chan, int n_chan,
struct ieee80211_rate *rates, int n_rates, bool vht)
{
struct ieee80211_supported_band *sband = &msband->sband;
struct ieee80211_sta_ht_cap *ht_cap;
struct ieee80211_sta_vht_cap *vht_cap;
struct ieee80211_sta_ht_cap *ht_cap;
struct mt76_dev *dev = phy->dev;
void *chanlist;
int size;
@ -203,7 +204,7 @@ 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;
mt76_init_stream_cap(&dev->phy, sband, vht);
mt76_init_stream_cap(phy, sband, vht);
if (!vht)
return 0;
@ -221,27 +222,25 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
}
static int
mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
int n_rates)
{
dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
return mt76_init_sband(dev, &dev->phy.sband_2g,
mt76_channels_2ghz,
ARRAY_SIZE(mt76_channels_2ghz),
rates, n_rates, false);
return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
ARRAY_SIZE(mt76_channels_2ghz), rates,
n_rates, false);
}
static int
mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
int n_rates, bool vht)
{
dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
return mt76_init_sband(dev, &dev->phy.sband_5g,
mt76_channels_5ghz,
ARRAY_SIZE(mt76_channels_5ghz),
rates, n_rates, vht);
return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
ARRAY_SIZE(mt76_channels_5ghz), rates,
n_rates, vht);
}
static void
@ -274,12 +273,13 @@ mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
}
static void
mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
{
struct mt76_dev *dev = phy->dev;
struct wiphy *wiphy = hw->wiphy;
SET_IEEE80211_DEV(hw, dev->dev);
SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
@ -305,6 +305,7 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
ieee80211_hw_set(hw, TX_AMSDU);
@ -314,7 +315,6 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, AP_LINK_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
wiphy->interface_modes =
@ -333,65 +333,57 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
const struct ieee80211_ops *ops)
{
struct ieee80211_hw *hw;
unsigned int phy_size;
struct mt76_phy *phy;
unsigned int phy_size, chan_size;
unsigned int size_2g, size_5g;
void *priv;
phy_size = ALIGN(sizeof(*phy), 8);
chan_size = sizeof(dev->phy.sband_2g.chan[0]);
size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
size += phy_size + size_2g + size_5g;
hw = ieee80211_alloc_hw(size, ops);
hw = ieee80211_alloc_hw(size + phy_size, ops);
if (!hw)
return NULL;
phy = hw->priv;
phy->dev = dev;
phy->hw = hw;
mt76_phy_init(dev, hw);
priv = hw->priv + phy_size;
phy->sband_2g = dev->phy.sband_2g;
phy->sband_2g.chan = priv;
priv += size_2g;
phy->sband_5g = dev->phy.sband_5g;
phy->sband_5g.chan = priv;
priv += size_5g;
phy->priv = priv;
hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
phy->priv = hw->priv + phy_size;
return phy;
}
EXPORT_SYMBOL_GPL(mt76_alloc_phy);
int
mt76_register_phy(struct mt76_phy *phy)
int mt76_register_phy(struct mt76_phy *phy, bool vht,
struct ieee80211_rate *rates, int n_rates)
{
int ret;
mt76_phy_init(phy, phy->hw);
if (phy->cap.has_2ghz) {
ret = mt76_init_sband_2g(phy, rates, n_rates);
if (ret)
return ret;
}
if (phy->cap.has_5ghz) {
ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
if (ret)
return ret;
}
wiphy_read_of_freq_limits(phy->hw->wiphy);
mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
ret = ieee80211_register_hw(phy->hw);
if (ret)
return ret;
phy->dev->phy2 = phy;
return 0;
}
EXPORT_SYMBOL_GPL(mt76_register_phy);
void
mt76_unregister_phy(struct mt76_phy *phy)
void mt76_unregister_phy(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
@ -459,16 +451,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
int ret;
dev_set_drvdata(dev->dev, dev);
mt76_phy_init(dev, hw);
mt76_phy_init(phy, hw);
if (dev->cap.has_2ghz) {
ret = mt76_init_sband_2g(dev, rates, n_rates);
if (phy->cap.has_2ghz) {
ret = mt76_init_sband_2g(phy, rates, n_rates);
if (ret)
return ret;
}
if (dev->cap.has_5ghz) {
ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
if (phy->cap.has_5ghz) {
ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
if (ret)
return ret;
}
@ -539,14 +531,11 @@ EXPORT_SYMBOL_GPL(mt76_rx);
bool mt76_has_tx_pending(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
struct mt76_queue *q;
int i, offset;
offset = __MT_TXQ_MAX * (phy != &dev->phy);
int i;
for (i = 0; i < __MT_TXQ_MAX; i++) {
q = dev->q_tx[offset + i];
q = phy->q_tx[i];
if (q && q->queued)
return true;
}
@ -842,7 +831,7 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
return;
if (!wcid || !wcid->sta) {
if (!ether_addr_equal(hdr->addr1, dev->macaddr))
if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
return;
wcid = NULL;
@ -932,7 +921,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
{
struct ieee80211_sta *sta;
struct ieee80211_hw *hw;
struct sk_buff *skb;
struct sk_buff *skb, *tmp;
LIST_HEAD(list);
spin_lock(&dev->rx_lock);
while ((skb = __skb_dequeue(frames)) != NULL) {
@ -942,9 +932,19 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
}
mt76_rx_convert(dev, skb, &hw, &sta);
ieee80211_rx_napi(hw, sta, skb, napi);
ieee80211_rx_list(hw, sta, skb, &list);
}
spin_unlock(&dev->rx_lock);
if (!napi) {
netif_receive_skb_list(&list);
return;
}
list_for_each_entry_safe(skb, tmp, &list, list) {
skb_list_del_init(skb);
napi_gro_receive(napi, skb);
}
}
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
@ -1202,3 +1202,22 @@ int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
EXPORT_SYMBOL_GPL(mt76_get_antenna);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
int ring_base)
{
struct mt76_queue *hwq;
int err;
hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
if (!hwq)
return ERR_PTR(-ENOMEM);
err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
if (err < 0)
return ERR_PTR(err);
return hwq;
}
EXPORT_SYMBOL_GPL(mt76_init_queue);

View File

@ -50,3 +50,83 @@ void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)
wake_up(&dev->mcu.wait);
}
EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
int len, bool wait_resp, struct sk_buff **ret_skb)
{
struct sk_buff *skb;
if (dev->mcu_ops->mcu_send_msg)
return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);
skb = mt76_mcu_msg_alloc(dev, data, len);
if (!skb)
return -ENOMEM;
return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);
}
EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp,
struct sk_buff **ret_skb)
{
unsigned long expires;
int ret, seq;
if (ret_skb)
*ret_skb = NULL;
mutex_lock(&dev->mcu.mutex);
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
if (ret < 0)
goto out;
if (!wait_resp) {
ret = 0;
goto out;
}
expires = jiffies + dev->mcu.timeout;
do {
skb = mt76_mcu_get_response(dev, expires);
ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
if (!ret && ret_skb)
*ret_skb = skb;
else
dev_kfree_skb(skb);
} while (ret == -EAGAIN);
out:
mutex_unlock(&dev->mcu.mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len)
{
int err, cur_len;
while (len > 0) {
cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len);
err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
if (err)
return err;
data += cur_len;
len -= cur_len;
if (dev->queue_ops->tx_cleanup)
dev->queue_ops->tx_cleanup(dev,
dev->q_mcu[MT_MCUQ_FWDL],
false);
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76_mcu_send_firmware);

View File

@ -64,18 +64,23 @@ enum mt76_txq_id {
MT_TXQ_BE = IEEE80211_AC_BE,
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,
__MT_TXQ_MAX
};
enum mt76_mcuq_id {
MT_MCUQ_WM,
MT_MCUQ_WA,
MT_MCUQ_FWDL,
__MT_MCUQ_MAX
};
enum mt76_rxq_id {
MT_RXQ_MAIN,
MT_RXQ_MCU,
MT_RXQ_MCU_WA,
MT_RXQ_EXT,
__MT_RXQ_MAX
};
@ -121,6 +126,7 @@ struct mt76_queue {
struct mt76_queue_regs __iomem *regs;
spinlock_t lock;
spinlock_t cleanup_lock;
struct mt76_queue_entry *entry;
struct mt76_desc *desc;
@ -131,9 +137,11 @@ struct mt76_queue {
int queued;
int buf_size;
bool stopped;
bool blocked;
u8 buf_offset;
u8 hw_idx;
u8 qid;
dma_addr_t desc_dma;
struct sk_buff *rx_head;
@ -147,7 +155,9 @@ struct mt76_mcu_ops {
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,
int cmd, bool wait_resp);
int cmd, int *seq);
int (*mcu_parse_response)(struct mt76_dev *dev, int cmd,
struct sk_buff *skb, int seq);
u32 (*mcu_rr)(struct mt76_dev *dev, u32 offset);
void (*mcu_wr)(struct mt76_dev *dev, u32 offset, u32 val);
int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base,
@ -164,11 +174,11 @@ struct mt76_queue_ops {
int idx, int n_desc, int bufsize,
u32 ring_base);
int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
int (*tx_queue_skb)(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta);
int (*tx_queue_skb_raw)(struct mt76_dev *dev, enum mt76_txq_id qid,
int (*tx_queue_skb_raw)(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info);
void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
@ -176,7 +186,7 @@ struct mt76_queue_ops {
void (*rx_reset)(struct mt76_dev *dev, enum mt76_rxq_id qid);
void (*tx_cleanup)(struct mt76_dev *dev, enum mt76_txq_id qid,
void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q,
bool flush);
void (*kick)(struct mt76_dev *dev, struct mt76_queue *q);
@ -185,6 +195,7 @@ struct mt76_queue_ops {
enum mt76_wcid_flags {
MT_WCID_FLAG_CHECK_PS,
MT_WCID_FLAG_PS,
MT_WCID_FLAG_4ADDR,
};
#define MT76_N_WCIDS 288
@ -411,6 +422,7 @@ enum mt76u_out_ep {
struct mt76_mcu {
struct mutex mutex;
u32 msg_seq;
int timeout;
struct sk_buff_head res_q;
wait_queue_head_t wait;
@ -426,7 +438,9 @@ struct mt76_usb {
u8 *data;
u16 data_len;
struct tasklet_struct rx_tasklet;
struct mt76_worker status_worker;
struct mt76_worker rx_worker;
struct work_struct stat_work;
u8 out_ep[__MT_EP_OUT_MAX];
@ -445,25 +459,18 @@ struct mt76_usb {
#define MT76S_XMIT_BUF_SZ (16 * PAGE_SIZE)
struct mt76_sdio {
struct workqueue_struct *txrx_wq;
struct {
struct work_struct xmit_work;
struct work_struct status_work;
} tx;
struct {
struct work_struct recv_work;
struct work_struct net_work;
} rx;
struct mt76_worker txrx_worker;
struct mt76_worker status_worker;
struct mt76_worker net_worker;
struct work_struct stat_work;
u8 *xmit_buf[MT_TXQ_MCU_WA];
u8 *xmit_buf[IEEE80211_NUM_ACS + 2];
struct sdio_func *func;
void *intr_data;
struct {
struct mutex lock;
int pse_data_quota;
int ple_data_quota;
int pse_mcu_quota;
@ -528,6 +535,8 @@ struct mt76_testmode_data {
u8 tx_rate_nss;
u8 tx_rate_sgi;
u8 tx_rate_ldpc;
u8 tx_rate_stbc;
u8 tx_ltf;
u8 tx_antenna_mask;
@ -555,15 +564,20 @@ struct mt76_phy {
unsigned long state;
struct mt76_queue *q_tx[__MT_TXQ_MAX];
struct cfg80211_chan_def chandef;
struct ieee80211_channel *main_chan;
struct mt76_channel_state *chan_state;
ktime_t survey_time;
struct mt76_hw_cap cap;
struct mt76_sband sband_2g;
struct mt76_sband sband_5g;
u8 macaddr[ETH_ALEN];
u32 vif_mask;
int txpower_cur;
@ -601,7 +615,7 @@ struct mt76_dev {
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
struct list_head txwi_cache;
struct mt76_queue *q_tx[2 * __MT_TXQ_MAX];
struct mt76_queue *q_mcu[__MT_MCUQ_MAX];
struct mt76_queue q_rx[__MT_RXQ_MAX];
const struct mt76_queue_ops *queue_ops;
int tx_dma_idx[4];
@ -619,7 +633,6 @@ struct mt76_dev {
struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
u8 macaddr[ETH_ALEN];
u32 rev;
u32 aggr_stats[32];
@ -630,7 +643,6 @@ struct mt76_dev {
struct debugfs_blob_wrapper eeprom;
struct debugfs_blob_wrapper otp;
struct mt76_hw_cap cap;
struct mt76_rate_power rate_power;
@ -690,10 +702,7 @@ enum mt76_phy_type {
#define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__)
#define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__)
#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__)
#define __mt76_mcu_send_msg(dev, ...) (dev)->mcu_ops->mcu_send_msg((dev), __VA_ARGS__)
#define __mt76_mcu_skb_send_msg(dev, ...) (dev)->mcu_ops->mcu_skb_send_msg((dev), __VA_ARGS__)
#define mt76_mcu_restart(dev, ...) (dev)->mt76.mcu_ops->mcu_restart(&((dev)->mt76))
#define __mt76_mcu_restart(dev, ...) (dev)->mcu_ops->mcu_restart((dev))
@ -752,7 +761,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__)
#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__)
#define mt76_for_each_q_rx(dev, i) \
@ -770,7 +779,8 @@ void mt76_unregister_phy(struct mt76_phy *phy);
struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
const struct ieee80211_ops *ops);
int mt76_register_phy(struct mt76_phy *phy);
int mt76_register_phy(struct mt76_phy *phy, bool vht,
struct ieee80211_rate *rates, int n_rates);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
int mt76_queues_read(struct seq_file *s, void *data);
@ -778,7 +788,40 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len);
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_dev *dev);
void mt76_eeprom_override(struct mt76_phy *phy);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
int ring_base);
static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
int n_desc, int ring_base)
{
struct mt76_queue *q;
q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base);
if (IS_ERR(q))
return PTR_ERR(q);
q->qid = qid;
phy->q_tx[qid] = q;
return 0;
}
static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx,
int n_desc, int ring_base)
{
struct mt76_queue *q;
q = mt76_init_queue(dev, qid, idx, n_desc, ring_base);
if (IS_ERR(q))
return PTR_ERR(q);
q->qid = __MT_TXQ_MAX + qid;
dev->q_mcu[qid] = q;
return 0;
}
static inline struct mt76_phy *
mt76_dev_phy(struct mt76_dev *dev, bool phy_ext)
@ -901,7 +944,7 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb);
void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar);
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
@ -1064,7 +1107,6 @@ void mt76u_queues_deinit(struct mt76_dev *dev);
int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
const struct mt76_bus_ops *bus_ops);
int mt76s_alloc_queues(struct mt76_dev *dev);
void mt76s_stop_txrx(struct mt76_dev *dev);
void mt76s_deinit(struct mt76_dev *dev);
struct sk_buff *
@ -1073,6 +1115,25 @@ mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb);
struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
unsigned long expires);
int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
int len, bool wait_resp, struct sk_buff **ret);
int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp, struct sk_buff **ret);
int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
int len);
static inline int
mt76_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len,
bool wait_resp)
{
return mt76_mcu_send_and_get_msg(dev, cmd, data, len, wait_resp, NULL);
}
static inline int
mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd,
bool wait_resp)
{
return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, NULL);
}
void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set);

View File

@ -13,23 +13,25 @@ static void
mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt7603_dev *dev = (struct mt7603_dev *)priv;
struct mt76_dev *mdev = &dev->mt76;
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct sk_buff *skb = NULL;
if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
if (!(mdev->beacon_mask & BIT(mvif->idx)))
return;
skb = ieee80211_beacon_get(mt76_hw(dev), vif);
if (!skb)
return;
mt76_tx_queue_skb(dev, MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL);
mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], skb,
&mvif->sta.wcid, NULL);
spin_lock_bh(&dev->ps_lock);
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
dev->mt76.q_tx[MT_TXQ_CAB]->hw_idx) |
dev->mphy.q_tx[MT_TXQ_CAB]->hw_idx) |
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
@ -64,9 +66,10 @@ mt7603_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
data->count[mvif->idx]++;
}
void mt7603_pre_tbtt_tasklet(unsigned long arg)
void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
{
struct mt7603_dev *dev = (struct mt7603_dev *)arg;
struct mt7603_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet);
struct mt76_dev *mdev = &dev->mt76;
struct mt76_queue *q;
struct beacon_bc_data data = {};
struct sk_buff *skb;
@ -78,7 +81,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
data.dev = dev;
__skb_queue_head_init(&data.q);
q = dev->mt76.q_tx[MT_TXQ_BEACON];
q = dev->mphy.q_tx[MT_TXQ_BEACON];
spin_lock_bh(&q->lock);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
@ -89,13 +92,13 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
/* Flush all previous CAB queue packets */
mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0));
mt76_queue_tx_cleanup(dev, MT_TXQ_CAB, false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false);
mt76_csa_check(&dev->mt76);
if (dev->mt76.csa_complete)
mt76_csa_check(mdev);
if (mdev->csa_complete)
goto out;
q = dev->mt76.q_tx[MT_TXQ_CAB];
q = dev->mphy.q_tx[MT_TXQ_CAB];
do {
nframes = skb_queue_len(&data.q);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
@ -120,7 +123,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
struct ieee80211_vif *vif = info->control.vif;
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
mt76_tx_queue_skb(dev, MT_TXQ_CAB, skb, &mvif->sta.wcid, NULL);
mt76_tx_queue_skb(dev, q, skb, &mvif->sta.wcid, NULL);
}
mt76_queue_kick(dev, q);
spin_unlock_bh(&q->lock);
@ -135,9 +138,8 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
((1 << (MT7603_MAX_INTERFACES - 1)) - 1)));
out:
mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false);
if (dev->mt76.q_tx[MT_TXQ_BEACON]->queued >
hweight8(dev->mt76.beacon_mask))
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false);
if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > hweight8(mdev->beacon_mask))
dev->beacon_check++;
}

View File

@ -4,27 +4,6 @@
#include "mac.h"
#include "../dma.h"
static int
mt7603_init_tx_queue(struct mt7603_dev *dev, int qid, 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;
dev->mt76.q_tx[qid] = hwq;
mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
return 0;
}
static void
mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
{
@ -152,14 +131,16 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7603_dev, mt76.tx_napi);
dev->tx_dma_check = 0;
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
for (i = MT_TXQ_PSD; i >= 0; i--)
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
if (napi_complete_done(napi, 0))
mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
for (i = MT_TXQ_PSD; i >= 0; i--)
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
mt7603_mac_sta_poll(dev);
@ -191,32 +172,42 @@ int mt7603_dma_init(struct mt7603_dev *dev)
mt7603_pse_client_reset(dev);
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
ret = mt7603_init_tx_queue(dev, i, wmm_queue_map[i],
MT7603_TX_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
MT7603_TX_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
}
ret = mt7603_init_tx_queue(dev, MT_TXQ_PSD,
MT_TX_HW_QUEUE_MGMT, MT7603_PSD_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
MT7603_PSD_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
ret = mt7603_init_tx_queue(dev, MT_TXQ_MCU,
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU,
MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
ret = mt7603_init_tx_queue(dev, MT_TXQ_BEACON,
MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN,
MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
ret = mt7603_init_tx_queue(dev, MT_TXQ_CAB,
MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC,
MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
mt7603_irq_enable(dev,
MT_INT_TX_DONE(IEEE80211_AC_VO) |
MT_INT_TX_DONE(IEEE80211_AC_VI) |
MT_INT_TX_DONE(IEEE80211_AC_BE) |
MT_INT_TX_DONE(IEEE80211_AC_BK) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_BCN) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_BMC));
ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
MT7603_MCU_RX_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)

View File

@ -141,6 +141,7 @@ static int mt7603_check_eeprom(struct mt76_dev *dev)
switch (val) {
case 0x7628:
case 0x7603:
case 0x7600:
return 0;
default:
return -EINVAL;
@ -170,8 +171,8 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
}
eeprom = (u8 *)dev->mt76.eeprom.data;
dev->mt76.cap.has_2ghz = true;
memcpy(dev->mt76.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
dev->mphy.cap.has_2ghz = true;
memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
/* Check for 1SS devices */
dev->mphy.antenna_mask = 3;
@ -180,7 +181,7 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
is_mt7688(dev))
dev->mphy.antenna_mask = 1;
mt76_eeprom_override(&dev->mt76);
mt76_eeprom_override(&dev->mphy);
return 0;
}

View File

@ -533,8 +533,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
spin_lock_init(&dev->ps_lock);
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work);
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet,
(unsigned long)dev);
tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet);
dev->slottime = 9;
dev->sensitivity_limit = 28;
@ -557,6 +556,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
/* init led callbacks */
if (IS_ENABLED(CONFIG_MT76_LEDS)) {

View File

@ -445,7 +445,7 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
for (i = 0; i < 4; i++) {
struct mt76_queue *q = dev->mt76.q_tx[i];
struct mt76_queue *q = dev->mphy.q_tx[i];
u8 qidx = q->hw_idx;
u8 tid = ac_to_tid[i];
u32 txtime = airtime[qidx];
@ -896,7 +896,7 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
struct ieee80211_vif *vif = info->control.vif;
struct mt76_queue *q = dev->mt76.q_tx[qid];
struct mt76_queue *q = dev->mphy.q_tx[qid];
struct mt7603_vif *mvif;
int wlan_idx;
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
@ -1434,8 +1434,9 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
mt7603_pse_client_reset(dev);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
mt76_queue_tx_cleanup(dev, i, true);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@ -1514,7 +1515,7 @@ static bool mt7603_tx_hang(struct mt7603_dev *dev)
int i;
for (i = 0; i < 4; i++) {
q = dev->mt76.q_tx[i];
q = dev->mphy.q_tx[i];
if (!q->queued)
continue;

View File

@ -380,9 +380,11 @@ mt7603_ps_tx_list(struct mt7603_dev *dev, struct sk_buff_head *list)
{
struct sk_buff *skb;
while ((skb = __skb_dequeue(list)) != NULL)
mt76_tx_queue_skb_raw(dev, skb_get_queue_mapping(skb),
skb, 0);
while ((skb = __skb_dequeue(list)) != NULL) {
int qid = skb_get_queue_mapping(skb);
mt76_tx_queue_skb_raw(dev, dev->mphy.q_tx[qid], skb, 0);
}
}
void
@ -392,7 +394,7 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
struct sk_buff_head list;
mt76_stop_tx_queues(&dev->mt76, sta, true);
mt76_stop_tx_queues(&dev->mphy, sta, true);
mt7603_wtbl_set_ps(dev, msta, ps);
if (ps)
return;
@ -512,7 +514,7 @@ mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
u16 cw_max = (1 << 10) - 1;
u32 val;
queue = dev->mt76.q_tx[queue]->hw_idx;
queue = dev->mphy.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = params->cw_min;

View File

@ -14,14 +14,38 @@ struct mt7603_fw_trailer {
} __packed;
static int
__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
int cmd, int *wait_seq)
mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
struct mt7603_mcu_rxd *rxd;
if (!skb) {
dev_err(mdev->dev,
"MCU message %d (seq %d) timed out\n",
cmd, seq);
dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
return -ETIMEDOUT;
}
rxd = (struct mt7603_mcu_rxd *)skb->data;
if (seq != rxd->seq)
return -EAGAIN;
return 0;
}
static int
mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, int *wait_seq)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
struct mt76_dev *mdev = &dev->mt76;
struct mt7603_mcu_txd *txd;
u8 seq;
mdev->mcu.timeout = 3 * HZ;
seq = ++mdev->mcu.msg_seq & 0xf;
if (!seq)
seq = ++mdev->mcu.msg_seq & 0xf;
@ -49,56 +73,7 @@ __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
if (wait_seq)
*wait_seq = seq;
return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
}
static int
mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
int len, bool wait_resp)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
unsigned long expires = jiffies + 3 * HZ;
struct mt7603_mcu_rxd *rxd;
struct sk_buff *skb;
int ret, seq;
skb = mt76_mcu_msg_alloc(mdev, data, len);
if (!skb)
return -ENOMEM;
mutex_lock(&mdev->mcu.mutex);
ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq);
if (ret)
goto out;
while (wait_resp) {
bool check_seq = false;
skb = mt76_mcu_get_response(&dev->mt76, expires);
if (!skb) {
dev_err(mdev->dev,
"MCU message %d (seq %d) timed out\n",
cmd, seq);
dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
ret = -ETIMEDOUT;
break;
}
rxd = (struct mt7603_mcu_rxd *)skb->data;
if (seq == rxd->seq)
check_seq = true;
dev_kfree_skb(skb);
if (check_seq)
break;
}
out:
mutex_unlock(&mdev->mcu.mutex);
return ret;
return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
}
static int
@ -114,29 +89,8 @@ mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
.mode = cpu_to_le32(BIT(31)),
};
return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
&req, sizeof(req), true);
}
static int
mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
{
int cur_len, ret = 0;
while (len > 0) {
cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
len);
ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
data, cur_len, false);
if (ret)
break;
data += cur_len;
len -= cur_len;
}
return ret;
return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
&req, sizeof(req), true);
}
static int
@ -150,15 +104,14 @@ mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
.addr = cpu_to_le32(addr),
};
return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
&req, sizeof(req), true);
return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
sizeof(req), true);
}
static int
mt7603_mcu_restart(struct mt76_dev *dev)
{
return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ,
NULL, 0, true);
return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
}
static int mt7603_load_firmware(struct mt7603_dev *dev)
@ -226,7 +179,8 @@ static int mt7603_load_firmware(struct mt7603_dev *dev)
goto out;
}
ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
fw->data, dl_len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
goto out;
@ -266,7 +220,8 @@ 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_skb_send_msg = mt7603_mcu_skb_send_msg,
.mcu_parse_response = mt7603_mcu_parse_response,
.mcu_restart = mt7603_mcu_restart,
};
@ -377,8 +332,8 @@ int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
data[i].val = eep[req_fields[i]];
}
ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
req, len, true);
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
req, len, true);
kfree(req);
return ret;
@ -424,8 +379,8 @@ static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
sizeof(req.temp_comp_power));
return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
&req, sizeof(req), true);
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
&req, sizeof(req), true);
}
int mt7603_mcu_set_channel(struct mt7603_dev *dev)
@ -470,8 +425,8 @@ int mt7603_mcu_set_channel(struct mt7603_dev *dev)
for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
req.txpower[i] = tx_power;
ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH,
&req, sizeof(req), true);
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
sizeof(req), true);
if (ret)
return ret;

View File

@ -256,7 +256,7 @@ void mt7603_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7603_pre_tbtt_tasklet(unsigned long arg);
void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t);
void mt7603_update_channel(struct mt76_dev *mdev);

View File

@ -57,7 +57,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
mt76_free_device(&dev->mt76);
return ret;
}

View File

@ -55,11 +55,26 @@ static int
mt7615_pm_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
int ret = 0;
if (!mt7615_wait_for_mcu_init(dev))
return 0;
return mt7615_pm_set_enable(dev, val);
if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
return -EOPNOTSUPP;
mt7615_mutex_acquire(dev);
if (dev->phy.n_beacon_vif) {
ret = -EBUSY;
goto out;
}
dev->pm.enable = val;
out:
mt7615_mutex_release(dev);
return ret;
}
static int
@ -172,7 +187,7 @@ mt7615_reset_test_set(void *data, u64 val)
skb_put(skb, 1);
mt7615_mutex_acquire(dev);
mt76_tx_queue_skb_raw(dev, 0, skb, 0);
mt76_tx_queue_skb_raw(dev, dev->mphy.q_tx[0], skb, 0);
mt7615_mutex_release(dev);
return 0;
@ -317,21 +332,18 @@ static int
mt7615_queues_read(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
static const struct {
struct {
struct mt76_queue *q;
char *queue;
int id;
} queue_map[] = {
{ "PDMA0", MT_TXQ_BE },
{ "MCUQ", MT_TXQ_MCU },
{ "MCUFWQ", MT_TXQ_FWDL },
{ dev->mphy.q_tx[MT_TXQ_BE], "PDMA0" },
{ dev->mt76.q_mcu[MT_MCUQ_WM], "MCUQ" },
{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
if (!q)
continue;
struct mt76_queue *q = queue_map[i].q;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
@ -365,6 +377,107 @@ mt7615_rf_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_reg, mt7615_rf_reg_get, mt7615_rf_reg_set,
"0x%08llx\n");
static ssize_t
mt7615_ext_mac_addr_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct mt7615_dev *dev = file->private_data;
char buf[32 * ((ETH_ALEN * 3) + 4) + 1];
u8 addr[ETH_ALEN];
int ofs = 0;
int i;
for (i = 0; i < 32; i++) {
if (!(dev->muar_mask & BIT(i)))
continue;
mt76_wr(dev, MT_WF_RMAC_MAR1,
FIELD_PREP(MT_WF_RMAC_MAR1_IDX, i * 2) |
MT_WF_RMAC_MAR1_START);
put_unaligned_le32(mt76_rr(dev, MT_WF_RMAC_MAR0), addr);
put_unaligned_le16((mt76_rr(dev, MT_WF_RMAC_MAR1) &
MT_WF_RMAC_MAR1_ADDR), addr + 4);
ofs += snprintf(buf + ofs, sizeof(buf) - ofs, "%d=%pM\n", i, addr);
}
return simple_read_from_buffer(userbuf, count, ppos, buf, ofs);
}
static ssize_t
mt7615_ext_mac_addr_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct mt7615_dev *dev = file->private_data;
unsigned long idx = 0;
u8 addr[ETH_ALEN];
char buf[32];
char *p;
if (count > sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, userbuf, count))
return -EFAULT;
buf[sizeof(buf) - 1] = '\0';
p = strchr(buf, '=');
if (p) {
*p = 0;
p++;
if (kstrtoul(buf, 0, &idx) || idx > 31)
return -EINVAL;
} else {
idx = 0;
p = buf;
}
if (!mac_pton(p, addr))
return -EINVAL;
if (is_valid_ether_addr(addr)) {
dev->muar_mask |= BIT(idx);
} else {
memset(addr, 0, sizeof(addr));
dev->muar_mask &= ~BIT(idx);
}
mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, 1);
mt76_wr(dev, MT_WF_RMAC_MAR0, get_unaligned_le32(addr));
mt76_wr(dev, MT_WF_RMAC_MAR1,
get_unaligned_le16(addr + 4) |
FIELD_PREP(MT_WF_RMAC_MAR1_IDX, idx * 2) |
MT_WF_RMAC_MAR1_START |
MT_WF_RMAC_MAR1_WRITE);
mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, !!dev->muar_mask);
return count;
}
static const struct file_operations fops_ext_mac_addr = {
.open = simple_open,
.llseek = generic_file_llseek,
.read = mt7615_ext_mac_addr_read,
.write = mt7615_ext_mac_addr_write,
.owner = THIS_MODULE,
};
static int
mt7663s_sched_quota_read(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
struct mt76_sdio *sdio = &dev->mt76.sdio;
seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota);
seq_printf(s, "ple_data_quota\t%d\n", sdio->sched.ple_data_quota);
seq_printf(s, "pse_mcu_quota\t%d\n", sdio->sched.pse_mcu_quota);
seq_printf(s, "sched_deficit\t%d\n", sdio->sched.deficit);
return 0;
}
int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
@ -406,11 +519,15 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
&fops_reset_test);
debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
mt7615_read_temperature);
debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr);
debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf);
debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg);
debugfs_create_file_unsafe("rf_regval", 0600, dir, dev,
&fops_rf_reg);
if (mt76_is_sdio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir,
mt7663s_sched_quota_read);
return 0;
}

View File

@ -11,25 +11,6 @@
#include "../dma.h"
#include "mac.h"
static int
mt7615_init_tx_queue(struct mt7615_dev *dev, int qid, 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;
dev->mt76.q_tx[qid] = hwq;
return 0;
}
static int
mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
{
@ -43,20 +24,21 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
int i;
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
ret = mt7615_init_tx_queue(dev, i, wmm_queue_map[i],
MT7615_TX_RING_SIZE / 2);
ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
MT7615_TX_RING_SIZE / 2,
MT_TX_RING_BASE);
if (ret)
return ret;
}
ret = mt7615_init_tx_queue(dev, MT_TXQ_PSD,
MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT,
MT7615_TX_MGMT_RING_SIZE,
MT_TX_RING_BASE);
if (ret)
return ret;
ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU,
MT7622_TXQ_MCU, MT7615_TX_MCU_RING_SIZE);
return ret;
return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7622_TXQ_MCU,
MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
}
static int
@ -64,25 +46,24 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
{
int ret, i;
ret = mt7615_init_tx_queue(dev, MT_TXQ_FWDL,
MT7615_TXQ_FWDL,
MT7615_TX_FWDL_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7615_TXQ_FWDL,
MT7615_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
if (!is_mt7615(&dev->mt76))
return mt7622_init_tx_queues_multi(dev);
ret = mt7615_init_tx_queue(dev, 0, 0, MT7615_TX_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, 0, 0, MT7615_TX_RING_SIZE,
MT_TX_RING_BASE);
if (ret)
return ret;
for (i = 1; i < MT_TXQ_MCU; i++)
dev->mt76.q_tx[i] = dev->mt76.q_tx[0];
for (i = 1; i <= MT_TXQ_PSD ; i++)
dev->mphy.q_tx[i] = dev->mphy.q_tx[0];
ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU, MT7615_TXQ_MCU,
MT7615_TX_MCU_RING_SIZE);
return 0;
return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7615_TXQ_MCU,
MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
}
static int mt7615_poll_tx(struct napi_struct *napi, int budget)
@ -91,7 +72,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
if (napi_complete_done(napi, 0))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
@ -202,7 +183,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
int ret;
/* Increase buffer size to receive large VHT MPDUs */
if (dev->mt76.cap.has_5ghz)
if (dev->mphy.cap.has_5ghz)
rx_buf_size *= 2;
mt76_dma_attach(&dev->mt76);

View File

@ -99,20 +99,20 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
if (is_mt7663(&dev->mt76)) {
/* dual band */
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_2ghz = true;
dev->mphy.cap.has_5ghz = true;
return;
}
if (is_mt7622(&dev->mt76)) {
/* 2GHz only */
dev->mt76.cap.has_2ghz = true;
dev->mphy.cap.has_2ghz = true;
return;
}
if (is_mt7611(&dev->mt76)) {
/* 5GHz only */
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_5ghz = true;
return;
}
@ -120,17 +120,17 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
eeprom[MT_EE_WIFI_CONF]);
switch (val) {
case MT_EE_5GHZ:
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
dev->mt76.cap.has_2ghz = true;
dev->mphy.cap.has_2ghz = true;
break;
case MT_EE_DBDC:
dev->dbdc_support = true;
/* fall through */
fallthrough;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_2ghz = true;
dev->mphy.cap.has_5ghz = true;
break;
}
}
@ -342,10 +342,10 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
}
mt7615_eeprom_parse_hw_cap(dev);
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mt76_eeprom_override(&dev->mt76);
mt76_eeprom_override(&dev->mphy);
return 0;
}

View File

@ -221,7 +221,7 @@ static const struct ieee80211_iface_combination if_comb_radar[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
.max_interfaces = 4,
.max_interfaces = MT7615_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
@ -237,7 +237,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
.max_interfaces = 4,
.max_interfaces = MT7615_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
}
@ -385,7 +385,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
{
struct mt7615_phy *phy = mt7615_ext_phy(dev);
struct mt76_phy *mphy;
int ret;
int i, ret;
if (!is_mt7615(&dev->mt76))
return -EOPNOTSUPP;
@ -422,14 +422,21 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
* 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);
memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mphy->macaddr[0] |= 2;
mphy->macaddr[0] ^= BIT(7);
mt76_eeprom_override(mphy);
/* second phy can only handle 5 GHz */
mphy->sband_2g.sband.n_channels = 0;
mphy->hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
mphy->cap.has_5ghz = true;
ret = mt76_register_phy(mphy);
/* mt7615 second phy shares the same hw queues with the primary one */
for (i = 0; i <= MT_TXQ_PSD ; i++)
mphy->q_tx[i] = dev->mphy.q_tx[i];
ret = mt76_register_phy(mphy, true, mt7615_rates,
ARRAY_SIZE(mt7615_rates));
if (ret)
ieee80211_free_hw(mphy->hw);

View File

@ -215,8 +215,8 @@ static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv)
dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4);
dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4);
dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4);
dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
dev->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
dev->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
#endif
}
@ -915,22 +915,20 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct ieee80211_tx_rate *rates)
{
struct mt7615_dev *dev = phy->dev;
struct mt7615_wtbl_desc *wd;
struct mt7615_wtbl_rate_desc *wrd;
if (work_pending(&dev->wtbl_work))
if (work_pending(&dev->rate_work))
return -EBUSY;
wd = kzalloc(sizeof(*wd), GFP_ATOMIC);
if (!wd)
wrd = kzalloc(sizeof(*wrd), GFP_ATOMIC);
if (!wrd)
return -ENOMEM;
wd->type = MT7615_WTBL_RATE_DESC;
wd->sta = sta;
wrd->sta = sta;
mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates,
&wd->rate);
list_add_tail(&wd->node, &dev->wd_head);
queue_work(dev->mt76.wq, &dev->wtbl_work);
&wrd->rate);
list_add_tail(&wrd->node, &dev->wrd_head);
queue_work(dev->mt76.wq, &dev->rate_work);
return 0;
}
@ -1030,31 +1028,33 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
}
EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
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)
static int
mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
enum mt7615_cipher_type cipher,
enum set_key_cmd cmd)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
u8 data[32] = {};
if (keylen > sizeof(data))
if (key->keylen > sizeof(data))
return -EINVAL;
mt76_rr_copy(dev, addr, data, sizeof(data));
if (cmd == SET_KEY) {
if (cipher == MT_CIPHER_TKIP) {
/* Rx/Tx MIC keys are swapped */
memcpy(data + 16, key + 24, 8);
memcpy(data + 24, key + 16, 8);
memcpy(data, key->key, 16);
memcpy(data + 16, key->key + 24, 8);
memcpy(data + 24, key->key + 16, 8);
} else {
if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher)
memmove(data + 16, data, 16);
if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
memcpy(data, key->key, key->keylen);
else if (cipher == MT_CIPHER_BIP_CMAC_128)
memcpy(data + 16, key->key, 16);
}
if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher)
memmove(data + 16, data, 16);
if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
memcpy(data, key, keylen);
else if (cipher == MT_CIPHER_BIP_CMAC_128)
memcpy(data + 16, key, 16);
} else {
if (wcid->cipher & ~BIT(cipher)) {
if (cipher != MT_CIPHER_BIP_CMAC_128)
@ -1068,12 +1068,11 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
return 0;
}
EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_key);
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)
static 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)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
@ -1105,12 +1104,11 @@ int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev,
return 0;
}
EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_pk);
void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
struct mt76_wcid *wcid,
enum mt7615_cipher_type cipher,
enum set_key_cmd cmd)
static void
mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
enum mt7615_cipher_type cipher,
enum set_key_cmd cmd)
{
u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
@ -1128,12 +1126,11 @@ void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE);
}
}
EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_cipher);
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_set_key(struct mt7615_dev *dev,
struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd)
{
enum mt7615_cipher_type cipher;
int err;
@ -1142,25 +1139,32 @@ int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
if (cipher == MT_CIPHER_NONE)
return -EOPNOTSUPP;
spin_lock_bh(&dev->mt76.lock);
mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd);
err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen,
cipher, cmd);
err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cmd);
if (err < 0)
goto out;
return err;
err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
cmd);
err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, cmd);
if (err < 0)
goto out;
return err;
if (cmd == SET_KEY)
wcid->cipher |= BIT(cipher);
else
wcid->cipher &= ~BIT(cipher);
out:
return 0;
}
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 err;
spin_lock_bh(&dev->mt76.lock);
err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
spin_unlock_bh(&dev->mt76.lock);
return err;
@ -1431,12 +1435,12 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
u8 i, count;
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
if (is_mt7615(&dev->mt76)) {
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
} else {
for (i = 0; i < IEEE80211_NUM_ACS; i++)
mt76_queue_tx_cleanup(dev, i, false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
}
count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
@ -1969,49 +1973,6 @@ out:
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
}
static void
mt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt7615_phy *phy = priv;
struct mt7615_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable))
return;
if (dev->pm.enable) {
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
mt76_set(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
} else {
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
mt76_clear(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
}
}
int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable)
{
struct mt76_phy *mphy = dev->phy.mt76;
if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
return -EOPNOTSUPP;
mt7615_mutex_acquire(dev);
if (dev->pm.enable == enable)
goto out;
dev->pm.enable = enable;
ieee80211_iterate_active_interfaces(mphy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7615_pm_interface_iter, mphy->priv);
out:
mt7615_mutex_release(dev);
return 0;
}
void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_phy *phy;
@ -2083,8 +2044,9 @@ void mt7615_dma_reset(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
usleep_range(1000, 2000);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
mt76_queue_tx_cleanup(dev, i, true);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@ -2314,3 +2276,46 @@ stop:
mt7615_dfs_stop_radar_detector(phy);
return 0;
}
int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
struct ieee80211_vif *vif,
bool enable)
{
struct mt7615_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
int err;
if (!mt7615_firmware_offload(dev))
return -EOPNOTSUPP;
switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
return 0;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_AP:
if (enable)
phy->n_beacon_vif++;
else
phy->n_beacon_vif--;
fallthrough;
default:
break;
}
err = mt7615_mcu_set_bss_pm(dev, vif, !phy->n_beacon_vif);
if (err)
return err;
if (phy->n_beacon_vif) {
vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
mt76_clear(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
} else {
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
mt76_set(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
}
return 0;
}

View File

@ -115,29 +115,50 @@ static void mt7615_stop(struct ieee80211_hw *hw)
mt7615_mutex_release(dev);
}
static int get_omac_idx(enum nl80211_iftype type, u32 mask)
static inline int get_free_idx(u32 mask, u8 start, u8 end)
{
return ffs(~mask & GENMASK(end, start));
}
static int get_omac_idx(enum nl80211_iftype type, u64 mask)
{
int i;
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
/* ap use hw bssid 0 and ext bssid */
case NL80211_IFTYPE_STATION:
/* prefer hw bssid slot 1-3 */
i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
if (i)
return i - 1;
if (type != NL80211_IFTYPE_STATION)
break;
/* next, try to find a free repeater entry for the sta */
i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
REPEATER_BSSID_MAX - REPEATER_BSSID_START);
if (i)
return i + 32 - 1;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
if (~mask & BIT(i))
return i;
break;
case NL80211_IFTYPE_STATION:
/* sta use hw bssid other than 0 */
for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
if (~mask & BIT(i))
return i;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP:
/* ap uses hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
break;
default:
@ -187,8 +208,8 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS;
dev->mphy.vif_mask |= BIT(mvif->idx);
dev->omac_mask |= BIT(mvif->omac_idx);
phy->omac_mask |= BIT(mvif->omac_idx);
dev->omac_mask |= BIT_ULL(mvif->omac_idx);
phy->omac_mask |= BIT_ULL(mvif->omac_idx);
mt7615_mcu_set_dbdc(dev);
@ -211,15 +232,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out;
if (dev->pm.enable) {
ret = mt7615_mcu_set_bss_pm(dev, vif, true);
if (ret)
goto out;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
mt76_set(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
}
mt7615_mac_set_beacon_filter(phy, vif, true);
out:
mt7615_mutex_release(dev);
@ -245,20 +258,14 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt7615_free_pending_tx_skbs(dev, msta);
if (dev->pm.enable) {
bool ext_phy = phy != &dev->phy;
mt7615_mcu_set_bss_pm(dev, vif, false);
mt76_clear(dev, MT_WF_RFCR(ext_phy),
MT_WF_RFCR_DROP_OTHER_BEACON);
}
mt7615_mac_set_beacon_filter(phy, vif, false);
mt7615_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
dev->mphy.vif_mask &= ~BIT(mvif->idx);
dev->omac_mask &= ~BIT(mvif->omac_idx);
phy->omac_mask &= ~BIT(mvif->omac_idx);
dev->omac_mask &= ~BIT_ULL(mvif->omac_idx);
phy->omac_mask &= ~BIT_ULL(mvif->omac_idx);
mt7615_mutex_release(dev);
@ -334,39 +341,6 @@ out:
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 = kmemdup(key->key, key->keylen, GFP_KERNEL);
if (!wd->key.key) {
kfree(wd);
return -ENOMEM;
}
wd->key.cipher = key->cipher;
wd->key.keyidx = key->keyidx;
wd->key.keylen = key->keylen;
wd->key.cmd = cmd;
spin_lock_bh(&dev->mt76.lock);
list_add_tail(&wd->node, &dev->wd_head);
spin_unlock_bh(&dev->mt76.lock);
queue_work(dev->mt76.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)
@ -393,8 +367,6 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
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:
@ -402,6 +374,8 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
default:
return -EOPNOTSUPP;
}
@ -420,7 +394,7 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (mt76_is_mmio(&dev->mt76))
err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
else
err = mt7615_queue_key_update(dev, cmd, msta, key);
err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
mt7615_mutex_release(dev);
@ -511,7 +485,6 @@ static void mt7615_configure_filter(struct ieee80211_hw *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 |
@ -522,6 +495,9 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
MT_WF_RFCR_DROP_UNWANTED_CTL |
MT_WF_RFCR_DROP_STBC_MULTI);
if (phy->n_beacon_vif || !mt7615_firmware_offload(dev))
phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_BEACON;
MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
MT_WF_RFCR_DROP_A3_MAC |
MT_WF_RFCR_DROP_A3_BSSID);
@ -1127,7 +1103,6 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
{
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;
cancel_delayed_work_sync(&dev->pm.ps_work);
@ -1139,8 +1114,6 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
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,
@ -1158,7 +1131,7 @@ 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;
bool running;
mt7615_mutex_acquire(dev);
@ -1182,7 +1155,6 @@ static int mt7615_resume(struct ieee80211_hw *hw)
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);
mt7615_mutex_release(dev);

File diff suppressed because it is too large Load Diff

View File

@ -275,6 +275,7 @@ enum {
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_DBDC_CTRL = 0x45,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
@ -477,6 +478,12 @@ struct mt7615_bss_qos_tlv {
u8 pad[3];
} __packed;
enum {
WOW_USB = 1,
WOW_PCIE = 2,
WOW_GPIO = 3,
};
struct mt7615_wow_ctrl_tlv {
__le16 tag;
__le16 len;
@ -501,6 +508,16 @@ struct mt7615_wow_ctrl_tlv {
u8 rsv[4];
} __packed;
struct mt7615_wow_gpio_param_tlv {
__le16 tag;
__le16 len;
u8 gpio_pin;
u8 trigger_lvl;
u8 pad[2];
__le32 gpio_interval;
u8 rsv[4];
} __packed;
#define MT7615_WOW_MASK_MAX_LEN 16
#define MT7615_WOW_PATTEN_MAX_LEN 128
struct mt7615_wow_pattern_tlv {

View File

@ -98,9 +98,9 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
return IRQ_HANDLED;
}
static void mt7615_irq_tasklet(unsigned long data)
static void mt7615_irq_tasklet(struct tasklet_struct *t)
{
struct mt7615_dev *dev = (struct mt7615_dev *)data;
struct mt7615_dev *dev = from_tasklet(dev, t, irq_tasklet);
u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
mt76_wr(dev, MT_INT_MASK_CSR, 0);
@ -203,7 +203,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
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);
tasklet_setup(&dev->irq_tasklet, mt7615_irq_tasklet);
dev->reg_map = map;
dev->ops = ops;
@ -240,7 +240,8 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
mt76_free_device(&dev->mt76);
return ret;
}

View File

@ -11,7 +11,7 @@
#include "../mt76.h"
#include "regs.h"
#define MT7615_MAX_INTERFACES 4
#define MT7615_MAX_INTERFACES 16
#define MT7615_MAX_WMM_SETS 4
#define MT7663_WTBL_SIZE 32
#define MT7615_WTBL_SIZE 128
@ -106,29 +106,11 @@ struct mt7615_rate_desc {
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 mt7615_wtbl_rate_desc {
struct list_head node;
enum mt7615_wtbl_desc_type type;
struct mt7615_rate_desc rate;
struct mt7615_sta *sta;
union {
struct mt7615_rate_desc rate;
struct mt7615_key_desc key;
};
};
struct mt7615_sta {
@ -175,8 +157,10 @@ struct mt7615_phy {
struct ieee80211_vif *monitor_vif;
u8 n_beacon_vif;
u32 rxfilter;
u32 omac_mask;
u64 omac_mask;
u16 noise;
@ -254,7 +238,7 @@ struct mt7615_dev {
struct tasklet_struct irq_tasklet;
struct mt7615_phy phy;
u32 omac_mask;
u64 omac_mask;
u16 chainmask;
@ -289,20 +273,22 @@ struct mt7615_dev {
u8 fw_ver;
struct work_struct wtbl_work;
struct list_head wd_head;
struct work_struct rate_work;
struct list_head wrd_head;
u32 debugfs_rf_wf;
u32 debugfs_rf_reg;
u32 muar_mask;
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
s16 last_freq_offset;
u8 last_rcpi[4];
s8 last_ib_rssi;
s8 last_wb_rssi;
s8 last_ib_rssi[4];
s8 last_wb_rssi[4];
} test;
#endif
@ -344,24 +330,13 @@ enum {
HW_BSSID_1,
HW_BSSID_2,
HW_BSSID_3,
HW_BSSID_MAX,
HW_BSSID_MAX = HW_BSSID_3,
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
EXT_BSSID_15 = 0x1f,
EXT_BSSID_MAX = EXT_BSSID_15,
REPEATER_BSSID_START = 0x20,
REPEATER_BSSID_MAX = 0x3f,
};
enum {
@ -452,7 +427,6 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev);
void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates);
int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable);
void mt7615_pm_wake_work(struct work_struct *work);
int mt7615_pm_wake(struct mt7615_dev *dev);
void mt7615_pm_power_save_sched(struct mt7615_dev *dev);
@ -542,7 +516,7 @@ static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac)
static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev)
{
return MT_INT_TX_DONE(dev->mt76.q_tx[MT_TXQ_MCU]->hw_idx);
return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx);
}
void mt7615_dma_reset(struct mt7615_dev *dev);
@ -568,28 +542,18 @@ 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_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_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);
u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid);
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_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq);
u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg);
int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val);
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
@ -651,6 +615,9 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
int mt7615_init_debugfs(struct mt7615_dev *dev);
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
struct ieee80211_vif *vif,
bool enable);
int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend);
@ -674,14 +641,13 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update);
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
struct mt76_queue_entry *e);
void mt7663_usb_sdio_wtbl_work(struct work_struct *work);
int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
int mt7663u_mcu_init(struct mt7615_dev *dev);
/* sdio */
u32 mt7663s_read_pcr(struct mt7615_dev *dev);
int mt7663s_mcu_init(struct mt7615_dev *dev);
void mt7663s_tx_work(struct work_struct *work);
void mt7663s_txrx_worker(struct mt76_worker *w);
void mt7663s_rx_work(struct work_struct *work);
void mt7663s_sdio_irq(struct sdio_func *func);

View File

@ -16,8 +16,15 @@ static void mt7615_init_work(struct work_struct *work)
{
struct mt7615_dev *dev = container_of(work, struct mt7615_dev,
mcu_work);
int i, ret;
if (mt7615_mcu_init(dev))
ret = mt7615_mcu_init(dev);
for (i = 0; (ret == -EAGAIN) && (i < 10); i++) {
msleep(200);
ret = mt7615_mcu_init(dev);
}
if (ret)
return;
mt7615_mcu_set_eeprom(dev);

View File

@ -333,6 +333,9 @@ enum mt7615_reg_base {
#define MT_WF_RFCR_DROP_NDPA BIT(20)
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
#define MT_WF_RMAC_MORE(_band) MT_WF_RMAC((_band) ? 0x124 : 0x024)
#define MT_WF_RMAC_MORE_MUAR_MODE GENMASK(31, 30)
#define MT_WF_RFCR1(_band) MT_WF_RMAC((_band) ? 0x104 : 0x004)
#define MT_WF_RFCR1_DROP_ACK BIT(4)
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
@ -342,6 +345,14 @@ enum mt7615_reg_base {
#define MT_CHFREQ(_band) MT_WF_RMAC((_band) ? 0x130 : 0x030)
#define MT_WF_RMAC_MAR0 MT_WF_RMAC(0x025c)
#define MT_WF_RMAC_MAR1 MT_WF_RMAC(0x0260)
#define MT_WF_RMAC_MAR1_ADDR GENMASK(15, 0)
#define MT_WF_RMAC_MAR1_START BIT(16)
#define MT_WF_RMAC_MAR1_WRITE BIT(17)
#define MT_WF_RMAC_MAR1_IDX GENMASK(29, 24)
#define MT_WF_RMAC_MAR1_GROUP GENMASK(31, 30)
#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)

View File

@ -294,30 +294,6 @@ release:
return ret;
}
static int mt7663s_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct mt76_sdio *sdio = &mdev->sdio;
u32 pse, ple;
int err;
err = mt7615_mac_sta_add(mdev, vif, sta);
if (err < 0)
return err;
/* init sched data quota */
pse = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
mutex_lock(&sdio->sched.lock);
sdio->sched.pse_data_quota = pse;
sdio->sched.ple_data_quota = ple;
mutex_unlock(&sdio->sched.lock);
return 0;
}
static int mt7663s_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@ -329,7 +305,7 @@ static int mt7663s_probe(struct sdio_func *func,
.tx_status_data = mt7663_usb_sdio_tx_status_data,
.rx_skb = mt7615_queue_rx_skb,
.sta_ps = mt7615_sta_ps,
.sta_add = mt7663s_sta_add,
.sta_add = mt7615_mac_sta_add,
.sta_remove = mt7615_mac_sta_remove,
.update_survey = mt7615_update_channel,
};
@ -366,14 +342,11 @@ static int mt7663s_probe(struct sdio_func *func,
ret = mt76s_init(mdev, func, &mt7663s_ops);
if (ret < 0)
goto err_free;
INIT_WORK(&mdev->sdio.tx.xmit_work, mt7663s_tx_work);
INIT_WORK(&mdev->sdio.rx.recv_work, mt7663s_rx_work);
goto error;
ret = mt7663s_hw_init(dev, func);
if (ret)
goto err_deinit;
goto error;
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
@ -384,7 +357,7 @@ static int mt7663s_probe(struct sdio_func *func,
GFP_KERNEL);
if (!mdev->sdio.intr_data) {
ret = -ENOMEM;
goto err_deinit;
goto error;
}
for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
@ -393,23 +366,29 @@ static int mt7663s_probe(struct sdio_func *func,
GFP_KERNEL);
if (!mdev->sdio.xmit_buf[i]) {
ret = -ENOMEM;
goto err_deinit;
goto error;
}
}
ret = mt76s_alloc_queues(&dev->mt76);
if (ret)
goto err_deinit;
goto error;
ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
mt7663s_txrx_worker, "sdio-txrx");
if (ret)
goto error;
sched_set_fifo_low(mdev->sdio.txrx_worker.task);
ret = mt7663_usb_sdio_register_device(dev);
if (ret)
goto err_deinit;
goto error;
return 0;
err_deinit:
error:
mt76s_deinit(&dev->mt76);
err_free:
mt76_free_device(&dev->mt76);
return ret;
@ -432,6 +411,7 @@ static int mt7663s_suspend(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct mt7615_dev *mdev = sdio_get_drvdata(func);
int err;
if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
mt7615_firmware_offload(mdev)) {
@ -444,9 +424,20 @@ static int mt7663s_suspend(struct device *dev)
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
mt76s_stop_txrx(&mdev->mt76);
err = mt7615_mcu_set_fw_ctrl(mdev);
if (err)
return err;
return mt7615_mcu_set_fw_ctrl(mdev);
mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);
mt76_worker_disable(&mdev->mt76.sdio.status_worker);
mt76_worker_disable(&mdev->mt76.sdio.net_worker);
cancel_work_sync(&mdev->mt76.sdio.stat_work);
clear_bit(MT76_READING_STATS, &mdev->mphy.state);
mt76_tx_status_check(&mdev->mt76, NULL, true);
return 0;
}
static int mt7663s_resume(struct device *dev)
@ -455,6 +446,10 @@ static int mt7663s_resume(struct device *dev)
struct mt7615_dev *mdev = sdio_get_drvdata(func);
int err;
mt76_worker_enable(&mdev->mt76.sdio.txrx_worker);
mt76_worker_enable(&mdev->mt76.sdio.status_worker);
mt76_worker_enable(&mdev->mt76.sdio.net_worker);
err = mt7615_mcu_set_drv_ctrl(mdev);
if (err)
return err;

View File

@ -19,46 +19,34 @@
static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
u32 pse0, ple, pse1, txdwcnt;
u32 txdwcnt;
pse0 = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
pse1 = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, MT_HIF1_MIN_QUOTA);
ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
sdio->sched.pse_data_quota = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP,
MT_HIF0_MIN_QUOTA);
sdio->sched.pse_mcu_quota = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP,
MT_HIF1_MIN_QUOTA);
sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP,
MT_HIF0_MIN_QUOTA);
txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT,
MT_PP_TXDWCNT_TX1_ADD_DW_CNT);
mutex_lock(&sdio->sched.lock);
sdio->sched.pse_data_quota = pse0;
sdio->sched.ple_data_quota = ple;
sdio->sched.pse_mcu_quota = pse1;
sdio->sched.deficit = txdwcnt << 2;
mutex_unlock(&sdio->sched.lock);
return 0;
}
static int
mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, bool wait_resp)
int cmd, int *seq)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
int ret, seq;
int ret;
mutex_lock(&mdev->mcu.mutex);
mt7615_mcu_fill_msg(dev, skb, cmd, &seq);
ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
mt7615_mcu_fill_msg(dev, skb, cmd, seq);
ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
if (ret)
goto out;
return ret;
mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU]);
if (wait_resp)
ret = mt7615_mcu_wait_response(dev, cmd, seq);
out:
mutex_unlock(&mdev->mcu.mutex);
mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]);
return ret;
}
@ -127,7 +115,7 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.headroom = sizeof(struct mt7615_mcu_txd),
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7663s_mcu_send_message,
.mcu_send_msg = mt7615_mcu_msg_send,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
.mcu_rr = mt7615_mcu_reg_rr,
.mcu_wr = mt7615_mcu_reg_wr,

View File

@ -46,11 +46,9 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
return 0;
mutex_lock(&sdio->sched.lock);
sdio->sched.pse_mcu_quota += pse_mcu_quota;
sdio->sched.pse_data_quota += pse_data_quota;
sdio->sched.ple_data_quota += ple_data_quota;
mutex_unlock(&sdio->sched.lock);
return pse_data_quota + ple_data_quota + pse_mcu_quota;
}
@ -105,10 +103,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
buf = page_address(page);
sdio_claim_host(sdio->func);
err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
sdio_release_host(sdio->func);
if (err < 0) {
dev_err(dev->dev, "sdio read data failed:%d\n", err);
__free_pages(page, order);
@ -138,19 +133,52 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
return i;
}
static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
int buf_sz, int *pse_size, int *ple_size)
static int mt7663s_rx_handler(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
struct mt76s_intr *intr = sdio->intr_data;
int nframes = 0, ret;
ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
if (ret < 0)
return ret;
trace_dev_irq(dev, intr->isr, 0);
if (intr->isr & WHIER_RX0_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 0, intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}
if (intr->isr & WHIER_RX1_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 1, intr);
if (ret > 0) {
mt76_worker_schedule(&sdio->net_worker);
nframes += ret;
}
}
nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
return nframes;
}
static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
int *pse_size, int *ple_size)
{
int pse_sz;
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
if (qid == MT_TXQ_MCU) {
if (mcu) {
if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
return -EBUSY;
} else {
if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
sdio->sched.ple_data_quota < *ple_size)
sdio->sched.ple_data_quota < *ple_size + 1)
return -EBUSY;
*ple_size = *ple_size + 1;
@ -160,17 +188,15 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
return 0;
}
static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
int pse_size, int ple_size)
{
mutex_lock(&sdio->sched.lock);
if (qid == MT_TXQ_MCU) {
if (mcu) {
sdio->sched.pse_mcu_quota -= pse_size;
} else {
sdio->sched.pse_data_quota -= pse_size;
sdio->sched.ple_data_quota -= ple_size;
}
mutex_unlock(&sdio->sched.lock);
}
static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
@ -181,22 +207,20 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
if (len > sdio->func->cur_blksize)
len = roundup(len, sdio->func->cur_blksize);
sdio_claim_host(sdio->func);
err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
sdio_release_host(sdio->func);
if (err)
dev_err(dev->dev, "sdio write failed: %d\n", err);
return err;
}
static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
struct mt76_queue *q = dev->q_tx[qid];
int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
struct mt76_sdio *sdio = &dev->sdio;
qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
while (q->first != q->head) {
struct mt76_queue_entry *e = &q->entry[q->first];
struct sk_buff *iter;
@ -214,7 +238,7 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (len + e->skb->len + 4 > MT76S_XMIT_BUF_SZ)
break;
if (mt7663s_tx_pick_quota(sdio, qid, e->buf_sz, &pse_sz,
if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
&ple_sz))
break;
@ -240,78 +264,44 @@ next:
if (err)
return err;
}
mt7663s_tx_update_quota(sdio, qid, pse_sz, ple_sz);
mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
mt76_worker_schedule(&sdio->status_worker);
return nframes;
}
void mt7663s_tx_work(struct work_struct *work)
void mt7663s_txrx_worker(struct mt76_worker *w)
{
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
tx.xmit_work);
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
txrx_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes = 0;
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
int ret;
ret = mt7663s_tx_run_queue(dev, i);
if (ret < 0)
break;
nframes += ret;
}
if (nframes)
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
queue_work(sdio->txrx_wq, &sdio->tx.status_work);
}
void mt7663s_rx_work(struct work_struct *work)
{
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
rx.recv_work);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
struct mt76s_intr *intr = sdio->intr_data;
int nframes = 0, ret;
int i, nframes, ret;
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
sdio_release_host(sdio->func);
if (ret < 0)
goto out;
do {
nframes = 0;
trace_dev_irq(dev, intr->isr, 0);
if (intr->isr & WHIER_RX0_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 0, intr);
if (ret > 0) {
queue_work(sdio->txrx_wq, &sdio->rx.net_work);
nframes += ret;
/* tx */
for (i = 0; i <= MT_TXQ_PSD; i++) {
ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]);
if (ret > 0)
nframes += ret;
}
}
if (intr->isr & WHIER_RX1_DONE_INT_EN) {
ret = mt7663s_rx_run_queue(dev, 1, intr);
if (ret > 0) {
queue_work(sdio->txrx_wq, &sdio->rx.net_work);
ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
if (ret > 0)
nframes += ret;
}
}
if (mt7663s_refill_sched_quota(dev, intr->tx.wtqcr))
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
/* rx */
ret = mt7663s_rx_handler(dev);
if (ret > 0)
nframes += ret;
} while (nframes > 0);
if (nframes) {
queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
return;
}
out:
/* enable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
}
@ -324,5 +314,5 @@ void mt7663s_sdio_irq(struct sdio_func *func)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
return;
queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
mt76_worker_schedule(&sdio->txrx_worker);
}

View File

@ -90,8 +90,8 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
data[ret - MT_EE_NIC_CONF_0] = tx_power[i];
}
return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD_SET_TX_POWER_CTRL, false);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_EXT_CMD_SET_TX_POWER_CTRL, false);
}
static void
@ -335,9 +335,7 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
if (!rx)
return -ENOMEM;
if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset) ||
nla_put_s32(msg, MT76_TM_RX_ATTR_IB_RSSI, dev->test.last_ib_rssi) ||
nla_put_s32(msg, MT76_TM_RX_ATTR_WB_RSSI, dev->test.last_wb_rssi))
if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset))
return -ENOMEM;
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
@ -350,6 +348,26 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
nla_nest_end(msg, rssi);
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
if (!rssi)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++)
if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i]))
return -ENOMEM;
nla_nest_end(msg, rssi);
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
if (!rssi)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++)
if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i]))
return -ENOMEM;
nla_nest_end(msg, rssi);
nla_nest_end(msg, rx);
return 0;

View File

@ -126,21 +126,20 @@ static int mt7663u_probe(struct usb_interface *usb_intf,
alloc_queues:
ret = mt76u_alloc_mcu_queue(&dev->mt76);
if (ret)
goto error_free_q;
goto error;
ret = mt76u_alloc_queues(&dev->mt76);
if (ret)
goto error_free_q;
goto error;
ret = mt7663_usb_sdio_register_device(dev);
if (ret)
goto error_free_q;
goto error;
return 0;
error_free_q:
mt76u_queues_deinit(&dev->mt76);
error:
mt76u_queues_deinit(&dev->mt76);
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));

View File

@ -15,14 +15,12 @@
static int
mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, bool wait_resp)
int cmd, int *seq)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
int ret, seq, ep, len, pad;
int ret, ep, len, pad;
mutex_lock(&mdev->mcu.mutex);
mt7615_mcu_fill_msg(dev, skb, cmd, &seq);
mt7615_mcu_fill_msg(dev, skb, cmd, seq);
if (cmd != MCU_CMD_FW_SCATTER)
ep = MT_EP_OUT_INBAND_CMD;
else
@ -37,14 +35,8 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL,
1000, ep);
if (ret < 0)
goto out;
if (wait_resp)
ret = mt7615_mcu_wait_response(dev, cmd, seq);
out:
mutex_unlock(&mdev->mcu.mutex);
dev_kfree_skb(skb);
return ret;
@ -56,7 +48,7 @@ int mt7663u_mcu_init(struct mt7615_dev *dev)
.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_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
};
int ret;

View File

@ -61,12 +61,11 @@ mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid,
skb_push(skb, MT_USB_TXD_SIZE);
}
static int
mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
struct mt7615_wtbl_desc *wd)
static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
struct mt7615_wtbl_rate_desc *wrd)
{
struct mt7615_rate_desc *rate = &wd->rate;
struct mt7615_sta *sta = wd->sta;
struct mt7615_rate_desc *rate = &wrd->rate;
struct mt7615_sta *sta = wrd->sta;
u32 w5, w27, addr, val;
lockdep_assert_held(&dev->mt76.mutex);
@ -132,86 +131,30 @@ mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
return 0;
}
static int
mt7663_usb_sdio_set_key(struct mt7615_dev *dev,
struct mt7615_wtbl_desc *wd)
static void mt7663_usb_sdio_rate_work(struct work_struct *work)
{
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) {
err = -EINVAL;
goto out;
}
cipher = mt7615_mac_get_cipher(key->cipher);
if (cipher == MT_CIPHER_NONE) {
err = -EOPNOTSUPP;
goto out;
}
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)
goto out;
err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
key->cmd);
if (err < 0)
goto out;
if (key->cmd == SET_KEY)
wcid->cipher |= BIT(cipher);
else
wcid->cipher &= ~BIT(cipher);
out:
kfree(key->key);
return err;
}
void mt7663_usb_sdio_wtbl_work(struct work_struct *work)
{
struct mt7615_wtbl_desc *wd, *wd_next;
struct list_head wd_list;
struct mt7615_wtbl_rate_desc *wrd, *wrd_next;
struct list_head wrd_list;
struct mt7615_dev *dev;
dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
wtbl_work);
rate_work);
INIT_LIST_HEAD(&wd_list);
INIT_LIST_HEAD(&wrd_list);
spin_lock_bh(&dev->mt76.lock);
list_splice_init(&dev->wd_head, &wd_list);
list_splice_init(&dev->wrd_head, &wrd_list);
spin_unlock_bh(&dev->mt76.lock);
list_for_each_entry_safe(wd, wd_next, &wd_list, node) {
list_del(&wd->node);
list_for_each_entry_safe(wrd, wrd_next, &wrd_list, node) {
list_del(&wrd->node);
mt7615_mutex_acquire(dev);
switch (wd->type) {
case MT7615_WTBL_RATE_DESC:
mt7663_usb_sdio_set_rates(dev, wd);
break;
case MT7615_WTBL_KEY_DESC:
mt7663_usb_sdio_set_key(dev, wd);
break;
}
mt7663_usb_sdio_set_rates(dev, wrd);
mt7615_mutex_release(dev);
kfree(wd);
kfree(wrd);
}
}
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_wtbl_work);
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
{
@ -357,8 +300,8 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev)
struct ieee80211_hw *hw = mt76_hw(dev);
int err;
INIT_WORK(&dev->wtbl_work, mt7663_usb_sdio_wtbl_work);
INIT_LIST_HEAD(&dev->wd_head);
INIT_WORK(&dev->rate_work, mt7663_usb_sdio_rate_work);
INIT_LIST_HEAD(&dev->wrd_head);
mt7615_init_device(dev);
err = mt7663_usb_sdio_init_hardware(dev);

View File

@ -52,15 +52,15 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
mt76x02_eeprom_parse_hw_cap(dev);
dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n",
dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
dev->mphy.cap.has_2ghz, dev->mphy.cap.has_5ghz);
if (dev->no_2ghz) {
dev->mt76.cap.has_2ghz = false;
dev->mphy.cap.has_2ghz = false;
dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
}
if (is_mt7630(dev)) {
dev->mt76.cap.has_5ghz = false;
dev->mphy.cap.has_5ghz = false;
dev_dbg(dev->mt76.dev, "mask out 5GHz support\n");
}
@ -342,10 +342,10 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
version, fae);
memcpy(dev->mt76.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mt76_eeprom_override(&dev->mt76);
mt76x02_mac_setaddr(dev, dev->mt76.macaddr);
mt76_eeprom_override(&dev->mphy);
mt76x02_mac_setaddr(dev, dev->mphy.macaddr);
mt76x0_set_chip_cap(dev);
mt76x0_set_freq_offset(dev);

View File

@ -245,7 +245,7 @@ int mt76x0_register_device(struct mt76x02_dev *dev)
if (ret)
return ret;
if (dev->mt76.cap.has_5ghz) {
if (dev->mphy.cap.has_5ghz) {
struct ieee80211_supported_band *sband;
sband = &dev->mphy.sband_5g.sband;
@ -253,7 +253,7 @@ int mt76x0_register_device(struct mt76x02_dev *dev)
mt76x0_init_txpower(dev, sband);
}
if (dev->mt76.cap.has_2ghz)
if (dev->mphy.cap.has_2ghz)
mt76x0_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt76x02_init_debugfs(dev);

View File

@ -194,7 +194,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
mt76_free_device(&dev->mt76);
return ret;
}

View File

@ -117,6 +117,7 @@ int mt76x0e_mcu_init(struct mt76x02_dev *dev)
{
static const struct mt76_mcu_ops mt76x0e_mcu_ops = {
.mcu_send_msg = mt76x02_mcu_msg_send,
.mcu_parse_response = mt76x02_mcu_parse_response,
};
int err;

View File

@ -447,11 +447,11 @@ static void mt76x0_phy_ant_select(struct mt76x02_dev *dev)
else
coex3 |= BIT(4);
coex3 |= BIT(3);
if (dev->mt76.cap.has_2ghz)
if (dev->mphy.cap.has_2ghz)
wlan |= BIT(6);
} else {
/* sigle antenna mode */
if (dev->mt76.cap.has_5ghz) {
if (dev->mphy.cap.has_5ghz) {
coex3 |= BIT(3) | BIT(4);
} else {
wlan |= BIT(6);

View File

@ -277,6 +277,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
err:
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
mt76u_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
return ret;

View File

@ -609,10 +609,11 @@ static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
}
}
static void mt76x02_dfs_tasklet(unsigned long arg)
static void mt76x02_dfs_tasklet(struct tasklet_struct *t)
{
struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t,
dfs_tasklet);
struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd);
u32 engine_mask;
int i;
@ -860,8 +861,7 @@ void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
INIT_LIST_HEAD(&dfs_pd->seq_pool);
dev->mt76.region = NL80211_DFS_UNSET;
dfs_pd->last_sw_check = jiffies;
tasklet_init(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet,
(unsigned long)dev);
tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet);
}
static void

View File

@ -75,14 +75,14 @@ void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev)
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
case BOARD_TYPE_5GHZ:
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
dev->mt76.cap.has_2ghz = true;
dev->mphy.cap.has_2ghz = true;
break;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
dev->mphy.cap.has_2ghz = true;
dev->mphy.cap.has_5ghz = true;
break;
}
}

View File

@ -727,24 +727,24 @@ void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
static const u8 null_addr[ETH_ALEN] = {};
int i;
ether_addr_copy(dev->mt76.macaddr, addr);
ether_addr_copy(dev->mphy.macaddr, addr);
if (!is_valid_ether_addr(dev->mt76.macaddr)) {
eth_random_addr(dev->mt76.macaddr);
if (!is_valid_ether_addr(dev->mphy.macaddr)) {
eth_random_addr(dev->mphy.macaddr);
dev_info(dev->mt76.dev,
"Invalid MAC address, using random address %pM\n",
dev->mt76.macaddr);
dev->mphy.macaddr);
}
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mphy.macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW1,
get_unaligned_le16(dev->mt76.macaddr + 4) |
get_unaligned_le16(dev->mphy.macaddr + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
mt76_wr(dev, MT_MAC_BSSID_DW0,
get_unaligned_le32(dev->mt76.macaddr));
get_unaligned_le32(dev->mphy.macaddr));
mt76_wr(dev, MT_MAC_BSSID_DW1,
get_unaligned_le16(dev->mt76.macaddr + 4) |
get_unaligned_le16(dev->mphy.macaddr + 4) |
FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
/* enable 7 additional beacon slots and control them with bypass mask */

View File

@ -10,6 +10,28 @@
#include "mt76x02_mcu.h"
int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
u32 *rxfce;
if (!skb) {
dev_err(mdev->dev,
"MCU message %d (seq %d) timed out\n", cmd,
seq);
dev->mcu_timeout = 1;
return -ETIMEDOUT;
}
rxfce = (u32 *)skb->cb;
if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
return -EAGAIN;
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response);
int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
int len, bool wait_resp)
{
@ -39,31 +61,15 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, tx_info);
ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info);
if (ret)
goto out;
while (wait_resp) {
u32 *rxfce;
bool check_seq = false;
skb = mt76_mcu_get_response(&dev->mt76, expires);
if (!skb) {
dev_err(mdev->dev,
"MCU message %d (seq %d) timed out\n", cmd,
seq);
ret = -ETIMEDOUT;
dev->mcu_timeout = 1;
break;
}
rxfce = (u32 *)skb->cb;
if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
check_seq = true;
ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq);
dev_kfree_skb(skb);
if (check_seq)
if (ret != -EAGAIN)
break;
}
@ -89,7 +95,8 @@ int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
if (func != Q_SELECT)
wait = true;
return mt76_mcu_send_msg(dev, CMD_FUN_SET_OP, &msg, sizeof(msg), wait);
return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg,
sizeof(msg), wait);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
@ -103,8 +110,8 @@ int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on)
.level = cpu_to_le32(0),
};
return mt76_mcu_send_msg(dev, CMD_POWER_SAVING_OP, &msg, sizeof(msg),
false);
return mt76_mcu_send_msg(&dev->mt76, CMD_POWER_SAVING_OP, &msg,
sizeof(msg), false);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
@ -123,8 +130,8 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
if (is_mt76x2e)
mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
ret = mt76_mcu_send_msg(dev, CMD_CALIBRATION_OP, &msg, sizeof(msg),
true);
ret = mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
sizeof(msg), true);
if (ret)
return ret;

View File

@ -89,6 +89,8 @@ 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,
int len, bool wait_resp);
int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq);
int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
u32 val);
int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on);

View File

@ -11,10 +11,11 @@
#include "mt76x02_mcu.h"
#include "trace.h"
static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t)
{
struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD];
struct mt76x02_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet);
struct mt76_dev *mdev = &dev->mt76;
struct mt76_queue *q = dev->mphy.q_tx[MT_TXQ_PSD];
struct beacon_bc_data data = {};
struct sk_buff *skb;
int i;
@ -35,9 +36,9 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
mt76_wr(dev, MT_BCN_BYPASS_MASK,
0xff00 | ~(0xff00 >> dev->beacon_data_count));
mt76_csa_check(&dev->mt76);
mt76_csa_check(mdev);
if (dev->mt76.csa_complete)
if (mdev->csa_complete)
return;
mt76x02_enqueue_buffered_bc(dev, &data, 8);
@ -58,8 +59,7 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
struct ieee80211_vif *vif = info->control.vif;
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, &mvif->group_wcid,
NULL);
mt76_tx_queue_skb(dev, q, skb, &mvif->group_wcid, NULL);
}
spin_unlock_bh(&q->lock);
}
@ -103,27 +103,6 @@ void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config);
static int
mt76x02_init_tx_queue(struct mt76x02_dev *dev, int qid, 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;
dev->mt76.q_tx[qid] = hwq;
mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
return 0;
}
static int
mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize)
@ -169,14 +148,16 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
mt76x02_mac_poll_tx_status(dev, false);
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
for (i = MT_TXQ_PSD; i >= 0; i--)
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
if (napi_complete_done(napi, 0))
mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL);
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
for (i = MT_TXQ_PSD; i >= 0; i--)
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
mt76_worker_schedule(&dev->mt76.tx_worker);
@ -198,8 +179,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
return -ENOMEM;
dev->mt76.tx_worker.fn = mt76x02_tx_worker;
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
(unsigned long)dev);
tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet);
spin_lock_init(&dev->txstatus_fifo_lock);
kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
@ -209,22 +189,31 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
ret = mt76x02_init_tx_queue(dev, i, mt76_ac_to_hwq(i),
MT76x02_TX_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i),
MT76x02_TX_RING_SIZE,
MT_TX_RING_BASE);
if (ret)
return ret;
}
ret = mt76x02_init_tx_queue(dev, MT_TXQ_PSD,
MT_TX_HW_QUEUE_MGMT, MT76x02_PSD_RING_SIZE);
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
ret = mt76x02_init_tx_queue(dev, MT_TXQ_MCU,
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU,
MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
mt76x02_irq_enable(dev,
MT_INT_TX_DONE(IEEE80211_AC_VO) |
MT_INT_TX_DONE(IEEE80211_AC_VI) |
MT_INT_TX_DONE(IEEE80211_AC_BE) |
MT_INT_TX_DONE(IEEE80211_AC_BK) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) |
MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU));
ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
@ -292,7 +281,7 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
if (dev->mt76.csa_complete)
mt76_csa_finish(&dev->mt76);
else
mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD]);
mt76_queue_kick(dev, dev->mphy.q_tx[MT_TXQ_PSD]);
}
if (intr & MT_INT_TX_STAT)
@ -357,7 +346,7 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
int i;
for (i = 0; i < 4; i++) {
q = dev->mt76.q_tx[i];
q = dev->mphy.q_tx[i];
if (!q->queued)
continue;
@ -475,8 +464,9 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
if (restart)
mt76_mcu_restart(dev);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
mt76_queue_tx_cleanup(dev, i, true);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);

View File

@ -67,7 +67,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct mt76_tx_info *tx_info)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid]->hw_idx);
int pid, len = tx_info->skb->len, ep = q2ep(dev->mphy.q_tx[qid]->hw_idx);
struct mt76x02_txwi *txwi;
bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
enum mt76_qsel qsel;

View File

@ -297,6 +297,7 @@ void mt76x02u_init_mcu(struct mt76_dev *dev)
.headroom = MT_CMD_HDR_LEN,
.tailroom = 8,
.mcu_send_msg = mt76x02u_mcu_send_msg,
.mcu_parse_response = mt76x02_mcu_parse_response,
.mcu_wr_rp = mt76x02u_mcu_wr_rp,
.mcu_rd_rp = mt76x02u_mcu_rd_rp,
};

View File

@ -186,6 +186,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
dev->mt76.global_wcid.idx = 255;
dev->mt76.global_wcid.hw_key_idx = -1;
@ -304,12 +305,12 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
/* Allow to change address in HW if we create first interface. */
if (!dev->mphy.vif_mask &&
(((vif->addr[0] ^ dev->mt76.macaddr[0]) & ~GENMASK(4, 1)) ||
memcmp(vif->addr + 1, dev->mt76.macaddr + 1, ETH_ALEN - 1)))
(((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) ||
memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1)))
mt76x02_mac_setaddr(dev, vif->addr);
if (vif->addr[0] & BIT(1))
idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
/*
* Client mode typically only has one configurable BSSID register,
@ -487,7 +488,7 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 cw_min = 5, cw_max = 10, qid;
u32 val;
qid = dev->mt76.q_tx[queue]->hw_idx;
qid = dev->mphy.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = fls(params->cw_min);
@ -621,7 +622,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
int idx = msta->wcid.idx;
mt76_stop_tx_queues(&dev->mt76, sta, true);
mt76_stop_tx_queues(&dev->mphy, sta, true);
if (mt76_is_mmio(mdev))
mt76x02_mac_wcid_set_drop(dev, idx, ps);
}
@ -677,7 +678,7 @@ void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev)
for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) {
u8 *addr = dev->macaddr_list[i].addr;
memcpy(addr, dev->mt76.macaddr, ETH_ALEN);
memcpy(addr, dev->mphy.macaddr, ETH_ALEN);
if (!i)
continue;

View File

@ -16,7 +16,7 @@ mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
{
void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
memcpy(dev->mt76.macaddr, src, ETH_ALEN);
memcpy(dev->mphy.macaddr, src, ETH_ALEN);
return 0;
}
@ -502,8 +502,8 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev)
mt76x02_eeprom_parse_hw_cap(dev);
mt76x2_eeprom_get_macaddr(dev);
mt76_eeprom_override(&dev->mt76);
dev->mt76.macaddr[0] &= ~BIT(1);
mt76_eeprom_override(&dev->mphy);
dev->mphy.macaddr[0] &= ~BIT(1);
return 0;
}

View File

@ -33,13 +33,14 @@ int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw,
};
/* first set the channel without the extension channel info */
mt76_mcu_send_msg(dev, CMD_SWITCH_CHANNEL_OP, &msg, sizeof(msg), true);
mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg,
sizeof(msg), true);
usleep_range(5000, 10000);
msg.ext_chan = 0xe0 + bw_index;
return mt76_mcu_send_msg(dev, CMD_SWITCH_CHANNEL_OP, &msg, sizeof(msg),
true);
return mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg,
sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
@ -66,7 +67,8 @@ int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */
return mt76_mcu_send_msg(dev, CMD_LOAD_CR, &msg, sizeof(msg), true);
return mt76_mcu_send_msg(&dev->mt76, CMD_LOAD_CR, &msg, sizeof(msg),
true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr);
@ -84,8 +86,8 @@ int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain,
if (force)
msg.channel |= cpu_to_le32(BIT(31));
return mt76_mcu_send_msg(dev, CMD_INIT_GAIN_OP, &msg, sizeof(msg),
true);
return mt76_mcu_send_msg(&dev->mt76, CMD_INIT_GAIN_OP, &msg,
sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain);
@ -100,7 +102,7 @@ int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev,
.data = *tssi_data,
};
return mt76_mcu_send_msg(dev, CMD_CALIBRATION_OP, &msg, sizeof(msg),
true);
return mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp);

View File

@ -90,7 +90,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
mt76_free_device(&dev->mt76);
return ret;
}

View File

@ -69,7 +69,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev)
int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
{
const u8 *macaddr = dev->mt76.macaddr;
const u8 *macaddr = dev->mphy.macaddr;
u32 val;
int i, k;

View File

@ -179,6 +179,7 @@ int mt76x2_mcu_init(struct mt76x02_dev *dev)
static const struct mt76_mcu_ops mt76x2_mcu_ops = {
.mcu_restart = mt76pci_mcu_restart,
.mcu_send_msg = mt76x02_mcu_msg_send,
.mcu_parse_response = mt76x02_mcu_parse_response,
};
int ret;

View File

@ -75,6 +75,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
return 0;
err:
mt76u_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);

View File

@ -4,3 +4,5 @@ obj-$(CONFIG_MT7915E) += mt7915e.o
mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o
mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o

View File

@ -47,32 +47,6 @@ mt7915_radar_trigger(void *data, u64 val)
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)
{
@ -233,6 +207,7 @@ static const struct file_operations fops_tx_stats = {
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int mt7915_read_temperature(struct seq_file *s, void *data)
@ -279,19 +254,23 @@ static int
mt7915_queues_read(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
static const struct {
struct mt76_phy *mphy_ext = dev->mt76.phy2;
struct mt76_queue *ext_q = mphy_ext ? mphy_ext->q_tx[MT_TXQ_BE] : NULL;
struct {
struct mt76_queue *q;
char *queue;
int id;
} queue_map[] = {
{ "WFDMA0", MT_TXQ_BE },
{ "MCUWM", MT_TXQ_MCU },
{ "MCUWA", MT_TXQ_MCU_WA },
{ "MCUFWQ", MT_TXQ_FWDL },
{ dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
{ ext_q, "WFDMA1" },
{ dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
{ dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" },
{ dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" },
{ dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
struct mt76_queue *q = queue_map[i].q;
if (!q)
continue;
@ -375,7 +354,6 @@ int mt7915_init_debugfs(struct mt7915_dev *dev)
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 */
@ -460,6 +438,7 @@ static const struct file_operations fops_sta_stats = {
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

View File

@ -5,42 +5,16 @@
#include "../dma.h"
#include "mac.h"
static int
mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc)
{
struct mt76_queue *hwq;
int err, i;
int i, err;
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);
err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE);
if (err < 0)
return err;
for (i = 0; i < MT_TXQ_MCU; i++)
dev->mt76.q_tx[i] = hwq;
return 0;
}
static int
mt7915_init_mcu_queue(struct mt7915_dev *dev, int qid, 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;
dev->mt76.q_tx[qid] = hwq;
for (i = 0; i <= MT_TXQ_PSD; i++)
phy->mt76->q_tx[i] = phy->mt76->q_tx[0];
return 0;
}
@ -61,6 +35,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
case PKT_TYPE_RX_EVENT:
mt7915_mcu_rx_event(dev, skb);
break;
#ifdef CONFIG_NL80211_TESTMODE
case PKT_TYPE_TXRXV:
mt7915_mac_fill_rx_vector(dev, skb);
break;
#endif
case PKT_TYPE_NORMAL:
if (!mt7915_mac_fill_rx(dev, skb)) {
mt76_rx(&dev->mt76, q, skb);
@ -76,8 +55,8 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
static void
mt7915_tx_cleanup(struct mt7915_dev *dev)
{
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
}
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
@ -257,25 +236,26 @@ int mt7915_dma_init(struct mt7915_dev *dev)
mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0);
/* init tx queue */
ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE);
ret = mt7915_init_tx_queues(&dev->phy, MT7915_TXQ_BAND0,
MT7915_TX_RING_SIZE);
if (ret)
return ret;
/* command to WM */
ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU, MT7915_TXQ_MCU_WM,
MT7915_TX_MCU_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7915_TXQ_MCU_WM,
MT7915_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
/* command to WA */
ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU_WA, MT7915_TXQ_MCU_WA,
MT7915_TX_MCU_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, MT7915_TXQ_MCU_WA,
MT7915_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
/* firmware download */
ret = mt7915_init_mcu_queue(dev, MT_TXQ_FWDL, MT7915_TXQ_FWDL,
MT7915_TX_FWDL_RING_SIZE);
ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7915_TXQ_FWDL,
MT7915_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
@ -293,13 +273,21 @@ int mt7915_dma_init(struct mt7915_dev *dev)
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);
/* rx data queue */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
MT7915_RXQ_BAND0, MT7915_RX_RING_SIZE,
rx_buf_size, MT_RX_DATA_RING_BASE);
if (ret)
return ret;
if (dev->dbdc_support) {
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT],
MT7915_RXQ_BAND1, 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;

View File

@ -4,16 +4,11 @@
#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)
static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
{
u8 *data = dev->mt76.eeprom.data;
if (!mt7915_efuse_valid(data[offset]))
if (data[offset] == 0xff)
mt7915_mcu_get_eeprom(dev, offset);
return data[offset];
@ -34,10 +29,10 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
static int mt7915_check_eeprom(struct mt7915_dev *dev)
{
u16 val;
u8 *eeprom = dev->mt76.eeprom.data;
u16 val;
mt7915_eeprom_read(dev, 0);
mt7915_eeprom_read(dev, MT_EE_CHIP_ID);
val = get_unaligned_le16(eeprom);
switch (val) {
@ -48,35 +43,50 @@ static int mt7915_check_eeprom(struct mt7915_dev *dev)
}
}
static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
{
u8 *eeprom = dev->mt76.eeprom.data;
u8 tx_mask, max_nss = 4;
u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
struct mt7915_dev *dev = phy->dev;
bool ext_phy = phy != &dev->phy;
u32 val;
val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy);
val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
switch (val) {
case MT_EE_5GHZ:
dev->mt76.cap.has_5ghz = true;
phy->mt76->cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
dev->mt76.cap.has_2ghz = true;
phy->mt76->cap.has_2ghz = true;
break;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
phy->mt76->cap.has_2ghz = true;
phy->mt76->cap.has_5ghz = true;
break;
}
}
static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
{
u8 nss, tx_mask[2] = {}, *eeprom = dev->mt76.eeprom.data;
mt7915_eeprom_parse_band_config(&dev->phy);
/* 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;
tx_mask[0] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
eeprom[MT_EE_WIFI_CONF]);
if (dev->dbdc_support)
tx_mask[1] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
eeprom[MT_EE_WIFI_CONF + 1]);
dev->chainmask = BIT(tx_mask) - 1;
dev->mphy.antenna_mask = dev->chainmask;
dev->phy.chainmask = dev->chainmask;
nss = tx_mask[0] + tx_mask[1];
if (!nss || nss > 4) {
tx_mask[0] = 4;
nss = 4;
}
dev->chainmask = BIT(nss) - 1;
dev->mphy.antenna_mask = BIT(tx_mask[0]) - 1;
dev->phy.chainmask = dev->mphy.antenna_mask;
}
int mt7915_eeprom_init(struct mt7915_dev *dev)
@ -92,10 +102,10 @@ int mt7915_eeprom_init(struct mt7915_dev *dev)
return ret;
mt7915_eeprom_parse_hw_cap(dev);
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mt76_eeprom_override(&dev->mt76);
mt76_eeprom_override(&dev->mphy);
return 0;
}

View File

@ -15,6 +15,7 @@ enum mt7915_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_MAC_ADDR2 = 0x00a,
MT_EE_DDIE_FT_VERSION = 0x050,
MT_EE_WIFI_CONF = 0x190,
MT_EE_TX0_POWER_2G = 0x2fc,

View File

@ -6,6 +6,113 @@
#include "mac.h"
#include "eeprom.h"
#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 = 16,
.types = BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT)
#endif
}, {
.max = MT7915_MAX_INTERFACES,
.types = BIT(NL80211_IFTYPE_STATION)
}
};
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
.max_interfaces = MT7915_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160) |
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);
ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
hw->max_tx_fragments = 4;
}
static void
mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
{
@ -35,25 +142,26 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
/* disable rx rate report by default due to hw issues */
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}
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);
for (i = 0; i < 2; i++)
mt7915_mac_init_band(dev, i);
mt7915_mac_init_band(dev, 0);
mt7915_mac_init_band(dev, 1);
mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b);
}
@ -108,6 +216,60 @@ static void mt7915_init_txpower(struct mt7915_dev *dev)
mt7915_eeprom_init_sku(dev);
}
static int mt7915_register_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy;
int ret;
if (!dev->dbdc_support)
return 0;
if (phy)
return 0;
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);
INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
mt7915_eeprom_parse_band_config(phy);
mt7915_set_stream_vht_txbf_caps(phy);
mt7915_set_stream_he_caps(phy);
memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2,
ETH_ALEN);
mt76_eeprom_override(mphy);
/* The second interface does not get any packets unless it has a vif */
ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
ret = mt7915_init_tx_queues(phy, MT7915_TXQ_BAND1,
MT7915_TX_RING_SIZE);
if (ret)
goto error;
ret = mt76_register_phy(mphy, true, mt7915_rates,
ARRAY_SIZE(mt7915_rates));
if (ret)
goto error;
return 0;
error:
ieee80211_free_hw(mphy->hw);
return ret;
}
static void mt7915_init_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
@ -117,6 +279,7 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_mac_init(dev);
mt7915_init_txpower(dev);
mt7915_txbf_init(dev);
mt7915_register_ext_phy(dev);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
@ -129,6 +292,8 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
dev->dbdc_support = !!(mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5));
ret = mt7915_dma_init(dev);
if (ret)
return ret;
@ -162,109 +327,6 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
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);
@ -342,7 +404,7 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
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);
c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3);
elem->phy_cap_info[5] |= c;
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
@ -354,35 +416,24 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
}
static void
mt7915_gen_ppe_thresh(u8 *he_ppet)
mt7915_gen_ppe_thresh(u8 *he_ppet, int nss)
{
int ru, nss, max_nss = 1, max_ru = 3;
u8 bit = 7, ru_bit_mask = 0x7;
u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
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;
he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
ru_bit_mask);
for (nss = 0; nss <= max_nss; nss++) {
for (ru = 0; ru < max_ru; ru++) {
u8 val;
int i;
ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
nss * hweight8(ru_bit_mask) * 2;
ppet_size = DIV_ROUND_UP(ppet_bits, 8);
if (!(ru_bit_mask & BIT(ru)))
continue;
for (i = 0; i < ppet_size - 1; i++)
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
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++;
}
}
}
he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
@ -513,7 +564,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7915_gen_ppe_thresh(he_cap->ppe_thres);
mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
@ -528,10 +579,9 @@ 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) {
if (phy->mt76->cap.has_2ghz) {
data = phy->iftype[NL80211_BAND_2GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
@ -540,7 +590,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
band->n_iftype_data = n;
}
if (mdev->cap.has_5ghz) {
if (phy->mt76->cap.has_5ghz) {
data = phy->iftype[NL80211_BAND_5GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
@ -550,95 +600,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
}
}
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;
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);
INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
/*
* 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)
static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy = dev->mt76.phy2;
@ -646,7 +608,6 @@ void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
if (!phy)
return;
mt7915_cap_dbdc_disable(dev);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
}
@ -683,9 +644,22 @@ int mt7915_register_device(struct mt7915_dev *dev)
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);
if (!dev->dbdc_support)
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
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);
dev->phy.dfs_state = -1;
#ifdef CONFIG_NL80211_TESTMODE
dev->mt76.test_ops = &mt7915_testmode_ops;
#endif
ret = mt76_register_device(&dev->mt76, true, mt7915_rates,
ARRAY_SIZE(mt7915_rates));
if (ret)
@ -716,6 +690,7 @@ void mt7915_unregister_device(struct mt7915_dev *dev)
ieee80211_free_txskb(hw, txwi->skb);
}
mt76_put_txwi(&dev->mt76, txwi);
dev->token_count--;
}
spin_unlock_bh(&dev->token_lock);
idr_destroy(&dev->token);

View File

@ -562,52 +562,197 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
return 0;
}
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)
#ifdef CONFIG_NL80211_TESTMODE
void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
bool multicast = is_multicast_ether_addr(hdr->addr1);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
__le16 fc = hdr->frame_control;
u16 tx_count = 15, seqno = 0;
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
__le32 *rxd = (__le32 *)skb->data;
__le32 *rxv = rxd + 4;
u32 rcpi, ib_rssi, wb_rssi, v20, v21;
s32 foe;
u8 snr;
int i;
rcpi = le32_to_cpu(rxv[6]);
ib_rssi = le32_to_cpu(rxv[7]);
wb_rssi = le32_to_cpu(rxv[8]) >> 5;
for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) {
if (i == 3)
wb_rssi = le32_to_cpu(rxv[9]);
dev->test.last_rcpi[i] = rcpi & 0xff;
dev->test.last_ib_rssi[i] = ib_rssi & 0xff;
dev->test.last_wb_rssi[i] = wb_rssi & 0xff;
}
v20 = le32_to_cpu(rxv[20]);
v21 = le32_to_cpu(rxv[21]);
foe = FIELD_GET(MT_CRXV_FOE_LO, v20) |
(FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT);
snr = FIELD_GET(MT_CRXV_SNR, v20) - 16;
dev->test.last_freq_offset = foe;
dev->test.last_snr = snr;
dev_kfree_skb(skb);
}
#endif
static void
mt7915_mac_write_txwi_tm(struct mt7915_dev *dev, struct mt76_phy *mphy,
__le32 *txwi, struct sk_buff *skb)
{
#ifdef CONFIG_NL80211_TESTMODE
struct mt76_testmode_data *td = &dev->mt76.test;
u8 rate_idx = td->tx_rate_idx;
u8 nss = td->tx_rate_nss;
u8 bw, mode;
u16 rateval = 0;
u32 val;
if (vif) {
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
if (skb != dev->mt76.test.tx_skb)
return;
omac_idx = mvif->omac_idx;
wmm_idx = mvif->wmm_idx;
switch (td->tx_rate_mode) {
case MT76_TM_TX_MODE_CCK:
mode = MT_PHY_TYPE_CCK;
break;
case MT76_TM_TX_MODE_HT:
nss = 1 + (rate_idx >> 3);
mode = MT_PHY_TYPE_HT;
break;
case MT76_TM_TX_MODE_VHT:
mode = MT_PHY_TYPE_VHT;
break;
case MT76_TM_TX_MODE_HE_SU:
mode = MT_PHY_TYPE_HE_SU;
break;
case MT76_TM_TX_MODE_HE_EXT_SU:
mode = MT_PHY_TYPE_HE_EXT_SU;
break;
case MT76_TM_TX_MODE_HE_TB:
mode = MT_PHY_TYPE_HE_TB;
break;
case MT76_TM_TX_MODE_HE_MU:
mode = MT_PHY_TYPE_HE_MU;
break;
case MT76_TM_TX_MODE_OFDM:
default:
mode = MT_PHY_TYPE_OFDM;
break;
}
if (ext_phy && dev->mt76.phy2)
mphy = dev->mt76.phy2;
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
txwi[4] = 0;
txwi[5] = 0;
txwi[6] = 0;
if (beacon) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
p_fmt = MT_TX_TYPE_CT;
q_idx = MT_LMAC_ALTX0;
} else {
p_fmt = MT_TX_TYPE_CT;
q_idx = wmm_idx * MT7915_MAX_WMM_SETS +
mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb));
switch (mphy->chandef.width) {
case NL80211_CHAN_WIDTH_40:
bw = 1;
break;
case NL80211_CHAN_WIDTH_80:
bw = 2;
break;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
bw = 3;
break;
default:
bw = 0;
break;
}
if (td->tx_rate_stbc && nss == 1) {
nss++;
rateval |= MT_TX_RATE_STBC;
}
rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
FIELD_PREP(MT_TX_RATE_MODE, mode) |
FIELD_PREP(MT_TX_RATE_NSS, nss - 1);
txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT);
if (td->tx_rate_mode < MT76_TM_TX_MODE_HT)
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
val = MT_TXD6_FIXED_BW |
FIELD_PREP(MT_TXD6_BW, bw) |
FIELD_PREP(MT_TXD6_TX_RATE, rateval) |
FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi);
/* for HE_SU/HE_EXT_SU PPDU
* - 1x, 2x, 4x LTF + 0.8us GI
* - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
* for HE_MU PPDU
* - 2x, 4x LTF + 0.8us GI
* - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
* for HE_TB PPDU
* - 1x, 2x LTF + 1.6us GI
* - 4x LTF + 3.2us GI
*/
if (mode >= MT_PHY_TYPE_HE_SU)
val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
if (td->tx_rate_ldpc)
val |= MT_TXD6_LDPC;
txwi[6] |= cpu_to_le32(val);
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
dev->test.spe_idx));
#endif
}
static void
mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid)
{
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
u8 fc_type, fc_stype;
bool wmm = false;
u32 val;
if (wcid->sta) {
struct ieee80211_sta *sta;
sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
wmm = sta->wme;
}
val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
FIELD_PREP(MT_TXD1_TID, tid);
if (be16_to_cpu(skb->protocol) >= ETH_P_802_3_MIN)
val |= MT_TXD1_ETH_802_3;
txwi[1] |= cpu_to_le32(val);
fc_type = IEEE80211_FTYPE_DATA >> 2;
fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
txwi[2] |= cpu_to_le32(val);
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
txwi[7] |= cpu_to_le32(val);
}
static void
mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct ieee80211_key_conf *key)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool multicast = is_multicast_ether_addr(hdr->addr1);
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
__le16 fc = hdr->frame_control;
u8 fc_type, fc_stype;
u32 val;
if (ieee80211_is_action(fc) &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
@ -622,6 +767,90 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
}
val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
FIELD_PREP(MT_TXD1_HDR_INFO,
ieee80211_get_hdrlen_from_skb(skb) / 2) |
FIELD_PREP(MT_TXD1_TID, tid);
txwi[1] |= cpu_to_le32(val);
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
FIELD_PREP(MT_TXD2_MULTICAST, multicast);
if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
val |= MT_TXD2_BIP;
txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
}
if (!ieee80211_is_data(fc) || multicast)
val |= MT_TXD2_FIX_RATE;
txwi[2] |= cpu_to_le32(val);
if (ieee80211_is_beacon(fc)) {
txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
}
if (info->flags & IEEE80211_TX_CTL_INJECTED) {
u16 seqno = le16_to_cpu(hdr->seq_ctrl);
if (ieee80211_is_back_req(hdr->frame_control)) {
struct ieee80211_bar *bar;
bar = (struct ieee80211_bar *)skb->data;
seqno = le16_to_cpu(bar->start_seq_num);
}
val = MT_TXD3_SN_VALID |
FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
txwi[3] |= cpu_to_le32(val);
}
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
txwi[7] |= cpu_to_le32(val);
}
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)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
u16 tx_count = 15;
u32 val;
if (vif) {
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
omac_idx = mvif->omac_idx;
wmm_idx = mvif->wmm_idx;
}
if (ext_phy && dev->mt76.phy2)
mphy = dev->mt76.phy2;
if (beacon) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
p_fmt = MT_TX_TYPE_CT;
q_idx = MT_LMAC_ALTX0;
} else {
p_fmt = MT_TX_TYPE_CT;
q_idx = wmm_idx * MT7915_MAX_WMM_SETS +
mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb));
}
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
@ -629,10 +858,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
val = MT_TXD1_LONG_FORMAT |
FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
FIELD_PREP(MT_TXD1_HDR_INFO,
ieee80211_get_hdrlen_from_skb(skb) / 2) |
FIELD_PREP(MT_TXD1_TID, tid) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
@ -640,27 +865,31 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
txwi[1] = cpu_to_le32(val);
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
FIELD_PREP(MT_TXD2_MULTICAST, multicast);
if (key) {
if (multicast && ieee80211_is_robust_mgmt_frame(skb) &&
key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
val |= MT_TXD2_BIP;
txwi[3] = 0;
} else {
txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME);
}
} else {
txwi[3] = 0;
}
txwi[2] = cpu_to_le32(val);
txwi[2] = 0;
if (!ieee80211_is_data(fc) || multicast) {
val = MT_TXD3_SW_POWER_MGMT |
FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
if (key)
val |= MT_TXD3_PROTECT_FRAME;
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
val |= MT_TXD3_NO_ACK;
txwi[3] = cpu_to_le32(val);
txwi[4] = 0;
txwi[5] = 0;
txwi[6] = 0;
txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
if (is_8023)
mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid);
else
mt7915_mac_write_txwi_80211(dev, txwi, skb, key);
if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
u16 rate;
/* hardware won't add HTC for mgmt/ctrl frame */
txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE | MT_TXD2_HTC_VLD);
txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
rate = MT7915_5G_RATE_DEFAULT;
@ -673,35 +902,28 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
if (!ieee80211_is_beacon(fc))
txwi[3] |= cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
else
tx_count = 0x1f;
if (mt76_testmode_enabled(&dev->mt76))
mt7915_mac_write_txwi_tm(dev, mphy, txwi, skb);
}
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
static void
mt7915_set_tx_blocked(struct mt7915_dev *dev, bool blocked)
{
struct mt76_phy *mphy = &dev->mphy, *mphy2 = dev->mt76.phy2;
struct mt76_queue *q, *q2 = NULL;
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
if (wcid->amsdu)
val |= MT_TXD7_HW_AMSDU;
txwi[7] = cpu_to_le32(val);
q = mphy->q_tx[0];
if (blocked == q->blocked)
return;
val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
if (info->flags & IEEE80211_TX_CTL_INJECTED) {
seqno = le16_to_cpu(hdr->seq_ctrl);
if (ieee80211_is_back_req(hdr->frame_control)) {
struct ieee80211_bar *bar;
bar = (struct ieee80211_bar *)skb->data;
seqno = le16_to_cpu(bar->start_seq_num);
}
val |= MT_TXD3_SN_VALID |
FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
q->blocked = blocked;
if (mphy2) {
q2 = mphy2->q_tx[0];
q2->blocked = blocked;
}
txwi[3] |= cpu_to_le32(val);
if (!blocked)
mt76_worker_schedule(&dev->mt76.tx_worker);
}
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@ -723,11 +945,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
cb->wcid = wcid->idx;
mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
false);
cb->wcid = wcid->idx;
txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
@ -740,12 +962,13 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->buf[1].skip_unmap = true;
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST);
if (!key)
txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
if (ieee80211_is_mgmt(hdr->frame_control))
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
ieee80211_is_mgmt(hdr->frame_control))
txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
if (vif) {
@ -759,12 +982,21 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
spin_lock_bh(&dev->token_lock);
id = idr_alloc(&dev->token, t, 0, MT7915_TOKEN_SIZE, GFP_ATOMIC);
if (id >= 0)
dev->token_count++;
if (dev->token_count >= MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR)
mt7915_set_tx_blocked(dev, true);
spin_unlock_bh(&dev->token_lock);
if (id < 0)
return id;
txp->token = cpu_to_le16(id);
txp->rept_wds_wcid = 0xff;
if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
else
txp->rept_wds_wcid = cpu_to_le16(0x3ff);
tx_info->skb = DMA_DUMMY_DATA;
return 0;
@ -795,17 +1027,19 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
ieee80211_start_tx_ba_session(sta, tid, 0);
}
static inline void
mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw,
struct ieee80211_tx_info *info, struct sk_buff *skb)
static void
mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
struct ieee80211_sta *sta, u8 stat,
struct list_head *free_list)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_status status = {
.sta = sta,
.info = info,
.skb = skb,
.free_list = free_list,
};
if (skb)
status.skb = skb;
struct ieee80211_hw *hw;
if (sta) {
struct mt7915_sta *msta;
@ -814,19 +1048,20 @@ mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw,
status.rate = &msta->stats.tx_rate;
}
/* use status_ext to report HE rate */
ieee80211_tx_status_ext(hw, &status);
}
static void
mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
struct ieee80211_sta *sta, u8 stat)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hw *hw;
hw = mt76_tx_status_get_hw(mdev, skb);
#ifdef CONFIG_NL80211_TESTMODE
if (skb == mdev->test.tx_skb) {
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct ieee80211_vif *vif = phy->monitor_vif;
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb);
return;
}
#endif
if (info->flags & IEEE80211_TX_CTL_AMPDU)
info->flags |= IEEE80211_TX_STAT_AMPDU;
@ -837,16 +1072,7 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.tx_time = 0;
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
mt7915_tx_status(sta, hw, info, skb);
return;
}
if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK))
mt7915_tx_status(sta, hw, info, NULL);
ieee80211_free_txskb(hw, skb);
ieee80211_tx_status_ext(hw, &status);
}
void mt7915_txp_skb_unmap(struct mt76_dev *dev,
@ -865,13 +1091,21 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data;
struct mt76_dev *mdev = &dev->mt76;
struct mt76_phy *mphy_ext = mdev->phy2;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
LIST_HEAD(free_list);
struct sk_buff *tmp;
u8 i, count;
bool wake = false;
/* clean DMA queues and unmap buffers first */
mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
if (mphy_ext) {
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
}
/*
* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
@ -908,6 +1142,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
continue;
}
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
@ -915,6 +1150,11 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
spin_lock_bh(&dev->token_lock);
txwi = idr_remove(&dev->token, msdu);
if (txwi)
dev->token_count--;
if (dev->token_count < MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR &&
dev->mphy.q_tx[0]->blocked)
wake = true;
spin_unlock_bh(&dev->token_lock);
if (!txwi)
@ -937,16 +1177,29 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
}
mt7915_tx_complete_status(mdev, txwi->skb, sta, stat);
mt7915_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list);
txwi->skb = NULL;
}
mt76_put_txwi(mdev, txwi);
}
dev_kfree_skb(skb);
mt7915_mac_sta_poll(dev);
if (wake) {
spin_lock_bh(&dev->token_lock);
mt7915_set_tx_blocked(dev, false);
spin_unlock_bh(&dev->token_lock);
}
mt76_worker_schedule(&dev->mt76.tx_worker);
napi_consume_skb(skb, 1);
list_for_each_entry_safe(skb, tmp, &free_list, list) {
skb_list_del_init(skb);
napi_consume_skb(skb, 1);
}
}
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
@ -979,7 +1232,8 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]);
mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0);
mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0,
NULL);
}
}
@ -1081,17 +1335,48 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy)
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
}
/*
* TODO: mib counters are read-clear and there're many HE functionalities need
* such info, hence firmware prepares a task to read the fields out to a shared
* structure. User should switch to use event format to avoid race condition.
*/
void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy)
{
mt7915_l2_set(dev, MT_WF_PHY_RXTD12(ext_phy),
MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY |
MT_WF_PHY_RXTD12_IRPI_SW_CLR);
mt7915_l2_set(dev, MT_WF_PHY_RX_CTRL1(ext_phy),
FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5));
}
static u8
mt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
{
static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
struct mt7915_dev *dev = phy->dev;
u32 val, sum = 0, n = 0;
int nss, i;
for (nss = 0; nss < hweight8(phy->chainmask); nss++) {
u32 reg = MT_WF_IRPI(nss + (idx << dev->dbdc_support));
for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
val = mt7915_l2_rr(dev, reg);
sum += val * nf_power[i];
n += val;
}
}
if (!n)
return 0;
return sum / n;
}
static void
mt7915_phy_update_channel(struct mt76_phy *mphy, int idx)
{
struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76);
struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
struct mt76_channel_state *state;
u64 busy_time, tx_time, rx_time, obss_time;
int nf;
busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
MT_MIB_SDR9_BUSY_MASK);
@ -1102,12 +1387,18 @@ mt7915_phy_update_channel(struct mt76_phy *mphy, int idx)
obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
MT_MIB_OBSSTIME_MASK);
/* TODO: state->noise */
nf = mt7915_phy_get_nf(phy, idx);
if (!phy->noise)
phy->noise = nf << 4;
else if (nf)
phy->noise += nf - (phy->noise >> 4);
state = mphy->chan_state;
state->cc_busy += busy_time;
state->cc_tx += tx_time;
state->cc_rx += rx_time + obss_time;
state->cc_bss_rx += rx_time;
state->noise = -(phy->noise >> 4);
}
void mt7915_update_channel(struct mt76_dev *mdev)
@ -1162,8 +1453,10 @@ mt7915_update_beacons(struct mt7915_dev *dev)
}
static void
mt7915_dma_reset(struct mt7915_dev *dev)
mt7915_dma_reset(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mt76_phy *mphy_ext = dev->mt76.phy2;
int i;
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
@ -1172,8 +1465,12 @@ mt7915_dma_reset(struct mt7915_dev *dev)
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
usleep_range(1000, 2000);
for (i = 0; i < __MT_TXQ_MAX; i++)
mt76_queue_tx_cleanup(dev, i, true);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], true);
for (i = 0; i < __MT_TXQ_MAX; i++) {
mt76_queue_tx_cleanup(dev, phy->mt76->q_tx[i], true);
if (mphy_ext)
mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
}
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@ -1229,7 +1526,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7915_dma_reset(dev);
mt7915_dma_reset(&dev->phy);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
@ -1329,7 +1626,7 @@ mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
spin_unlock_bh(&dev->sta_poll_lock);
/* use MT_TX_FREE_RATE to report Tx rate for further devices */
mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
mt7915_mcu_get_tx_rate(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
spin_lock_bh(&dev->sta_poll_lock);
}

View File

@ -128,6 +128,11 @@ enum rx_pkt_type {
#define MT_CRXV_HE_BEAM_CHNG BIT(13)
#define MT_CRXV_HE_DOPPLER BIT(16)
#define MT_CRXV_SNR GENMASK(18, 13)
#define MT_CRXV_FOE_LO GENMASK(31, 19)
#define MT_CRXV_FOE_HI GENMASK(6, 0)
#define MT_CRXV_FOE_SHIFT 13
enum tx_header_format {
MT_HDR_FORMAT_802_3,
MT_HDR_FORMAT_CMD,
@ -160,6 +165,7 @@ enum tx_mcu_port_q_idx {
#define MT_CT_INFO_MGMT_FRAME BIT(2)
#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3)
#define MT_CT_INFO_HSR2_TX BIT(4)
#define MT_CT_INFO_FROM_HOST BIT(7)
#define MT_TXD_SIZE (8 * 4)
@ -176,6 +182,7 @@ enum tx_mcu_port_q_idx {
#define MT_TXD1_HDR_PAD GENMASK(19, 18)
#define MT_TXD1_HDR_FORMAT GENMASK(17, 16)
#define MT_TXD1_HDR_INFO GENMASK(15, 11)
#define MT_TXD1_ETH_802_3 BIT(15)
#define MT_TXD1_VTA BIT(10)
#define MT_TXD1_WLAN_IDX GENMASK(9, 0)
@ -229,7 +236,7 @@ enum tx_mcu_port_q_idx {
#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_TXD6_BW GENMASK(1, 0)
#define MT_TXD7_TXD_LEN GENMASK(31, 30)
#define MT_TXD7_UDP_TCP_SUM BIT(29)
@ -246,7 +253,9 @@ enum tx_mcu_port_q_idx {
#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_TX_RATE_SU_EXT_TONE BIT(5)
#define MT_TX_RATE_DCM BIT(4)
#define MT_TX_RATE_IDX GENMASK(3, 0)
#define MT_TXP_MAX_BUF_NUM 6
@ -254,8 +263,7 @@ struct mt7915_txp {
__le16 flags;
__le16 token;
u8 bss_idx;
u8 rept_wds_wcid;
u8 rsv;
__le16 rept_wds_wcid;
u8 nbuf;
__le32 buf[MT_TXP_MAX_BUF_NUM];
__le16 len[MT_TXP_MAX_BUF_NUM];

View File

@ -34,21 +34,24 @@ static int mt7915_start(struct ieee80211_hw *hw)
mt7915_mcu_set_pm(dev, 0, 0);
mt7915_mcu_set_mac(dev, 0, true, false);
mt7915_mcu_set_scs(dev, 0, true);
mt7915_mac_enable_nf(dev, 0);
}
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_mac_enable_nf(dev, 1);
}
mt7915_mcu_set_sku_en(phy, true);
mt7915_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76));
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 (!mt76_testmode_enabled(&dev->mt76))
ieee80211_queue_delayed_work(hw, &phy->mac_work,
MT7915_WATCHDOG_TIME);
if (!running)
mt7915_mac_reset_counters(phy);
@ -67,6 +70,8 @@ static void mt7915_stop(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
mt76_testmode_reset(&dev->mt76, true);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
if (phy != &dev->phy) {
@ -82,28 +87,51 @@ static void mt7915_stop(struct ieee80211_hw *hw)
mutex_unlock(&dev->mt76.mutex);
}
static int get_omac_idx(enum nl80211_iftype type, u32 mask)
static inline int get_free_idx(u32 mask, u8 start, u8 end)
{
return ffs(~mask & GENMASK(end, start));
}
static int get_omac_idx(enum nl80211_iftype type, u64 mask)
{
int i;
switch (type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_STATION:
/* prefer hw bssid slot 1-3 */
i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
if (i)
return i - 1;
if (type != NL80211_IFTYPE_STATION)
break;
/* next, try to find a free repeater entry for the sta */
i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
REPEATER_BSSID_MAX - REPEATER_BSSID_START);
if (i)
return i + 32 - 1;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
break;
case NL80211_IFTYPE_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;
i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
if (i)
return i - 1;
break;
default:
WARN_ON(1);
@ -125,6 +153,12 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mutex_lock(&dev->mt76.mutex);
mt76_testmode_reset(&dev->mt76, true);
if (vif->type == NL80211_IFTYPE_MONITOR &&
is_zero_ether_addr(vif->addr))
phy->monitor_vif = vif;
mvif->idx = ffs(~phy->mt76->vif_mask) - 1;
if (mvif->idx >= MT7915_MAX_INTERFACES) {
ret = -ENOSPC;
@ -146,12 +180,12 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
else
mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS;
ret = mt7915_mcu_add_dev_info(dev, vif, true);
ret = mt7915_mcu_add_dev_info(phy, vif, true);
if (ret)
goto out;
phy->mt76->vif_mask |= BIT(mvif->idx);
phy->omac_mask |= BIT(mvif->omac_idx);
phy->omac_mask |= BIT_ULL(mvif->omac_idx);
idx = MT7915_WTBL_RESERVED - mvif->idx;
@ -171,6 +205,11 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mtxq->wcid = &mvif->sta.wcid;
}
if (vif->type != NL80211_IFTYPE_AP &&
(!mvif->omac_idx || mvif->omac_idx > 3))
vif->offload_flags = 0;
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
out:
mutex_unlock(&dev->mt76.mutex);
@ -188,13 +227,20 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
/* TODO: disable beacon for the bss */
mt7915_mcu_add_dev_info(dev, vif, false);
mutex_lock(&dev->mt76.mutex);
mt76_testmode_reset(&dev->mt76, true);
mutex_unlock(&dev->mt76.mutex);
if (vif == phy->monitor_vif)
phy->monitor_vif = NULL;
mt7915_mcu_add_dev_info(phy, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mutex_lock(&dev->mt76.mutex);
phy->mt76->vif_mask &= ~BIT(mvif->idx);
phy->omac_mask &= ~BIT(mvif->omac_idx);
phy->omac_mask &= ~BIT_ULL(mvif->omac_idx);
mutex_unlock(&dev->mt76.mutex);
spin_lock_bh(&dev->sta_poll_lock);
@ -222,7 +268,7 @@ static void mt7915_init_dfs_state(struct mt7915_phy *phy)
phy->dfs_state = -1;
}
static int mt7915_set_channel(struct mt7915_phy *phy)
int mt7915_set_channel(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
int ret;
@ -251,8 +297,10 @@ out:
mutex_unlock(&dev->mt76.mutex);
mt76_txq_schedule_all(phy->mt76);
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
MT7915_WATCHDOG_TIME);
if (!mt76_testmode_enabled(&dev->mt76))
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
MT7915_WATCHDOG_TIME);
return ret;
}
@ -283,8 +331,6 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
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:
@ -292,6 +338,8 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
default:
return -EOPNOTSUPP;
}
@ -316,6 +364,13 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
int ret;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
#ifdef CONFIG_NL80211_TESTMODE
if (dev->mt76.test.state != MT76_TM_STATE_OFF) {
mutex_lock(&dev->mt76.mutex);
mt76_testmode_reset(&dev->mt76, false);
mutex_unlock(&dev->mt76.mutex);
}
#endif
ieee80211_stop_queues(hw);
ret = mt7915_set_channel(phy);
if (ret)
@ -332,11 +387,16 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
if (!enabled)
phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
else
phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN,
enabled);
mt76_testmode_reset(&dev->mt76, true);
mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
}
@ -764,9 +824,13 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct mt7915_sta_stats *stats = &msta->stats;
if (mt7915_mcu_get_rx_rate(phy, vif, sta, &sinfo->rxrate) == 0)
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
return;
@ -802,6 +866,22 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &dev->rc_work);
}
static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
bool enabled)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
if (enabled)
set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
else
clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
mt7915_mcu_sta_update_hdr_trans(dev, vif, sta);
}
const struct ieee80211_ops mt7915_ops = {
.tx = mt7915_tx,
.start = mt7915_start,
@ -833,6 +913,9 @@ const struct ieee80211_ops mt7915_ops = {
.set_antenna = mt7915_set_antenna,
.set_coverage_class = mt7915_set_coverage_class,
.sta_statistics = mt7915_sta_statistics,
.sta_set_4addr = mt7915_sta_set_4addr,
CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = mt7915_sta_add_debugfs,
#endif

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,11 @@ enum {
MCU_EXT_EVENT_RATE_REPORT = 0x87,
};
enum {
MCU_ATE_SET_TRX = 0x1,
MCU_ATE_SET_FREQ_OFFSET = 0xa,
};
struct mt7915_mcu_rxd {
__le32 rxd[6];
@ -153,6 +158,18 @@ struct mt7915_mcu_ra_info {
u8 prob_down_pending;
} __packed;
struct mt7915_mcu_phy_rx_info {
u8 category;
u8 rate;
u8 mode;
u8 nsts;
u8 gi;
u8 coding;
u8 stbc;
u8 bw;
};
#define MT_RA_RATE_NSS GENMASK(8, 6)
#define MT_RA_RATE_MCS GENMASK(3, 0)
#define MT_RA_RATE_TX_MODE GENMASK(12, 9)
@ -201,19 +218,24 @@ enum {
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
MCU_EXT_CMD_WTBL_UPDATE = 0x32,
MCU_EXT_CMD_SET_DRR_CTRL = 0x36,
MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
MCU_EXT_CMD_ATE_CTRL = 0x3d,
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_RX_HDR_TRANS = 0x47,
MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
MCU_EXT_CMD_SET_SER_TRIGGER = 0x81,
MCU_EXT_CMD_SCS_CTRL = 0x82,
MCU_EXT_CMD_RATE_CTRL = 0x87,
MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
MCU_EXT_CMD_SET_SPR = 0xa8,
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
};
enum {
@ -247,6 +269,14 @@ enum {
EE_FORMAT_MULTIPLE,
};
enum {
MCU_PHY_STATE_TX_RATE,
MCU_PHY_STATE_RX_RATE,
MCU_PHY_STATE_RSSI,
MCU_PHY_STATE_CONTENTION_RX_RATE,
MCU_PHY_STATE_OFDMLQ_CNINFO,
};
#define STA_TYPE_STA BIT(0)
#define STA_TYPE_AP BIT(1)
#define STA_TYPE_ADHOC BIT(2)
@ -354,15 +384,6 @@ struct bss_info_ext_bss {
u8 rsv[8];
} __packed;
struct bss_info_sync_mode {
__le16 tag;
__le16 len;
__le16 bcn_interval;
u8 enable;
u8 dtim_period;
u8 rsv[8];
} __packed;
struct bss_info_bmc_rate {
__le16 tag;
__le16 len;
@ -480,7 +501,7 @@ enum {
BSS_INFO_LQ_RM, /* obsoleted */
BSS_INFO_EXT_BSS,
BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */
BSS_INFO_SYNC_MODE,
BSS_INFO_SYNC_MODE, /* obsoleted */
BSS_INFO_RA,
BSS_INFO_HW_AMSDU,
BSS_INFO_BSS_COLOR,
@ -551,6 +572,15 @@ struct wtbl_vht {
u8 rsv[4];
} __packed;
struct wtbl_hdr_trans {
__le16 tag;
__le16 len;
u8 to_ds;
u8 from_ds;
u8 no_rx_trans;
u8 _rsv;
};
enum {
MT_BA_TYPE_INVALID,
MT_BA_TYPE_ORIGINATOR,
@ -972,6 +1002,7 @@ enum {
sizeof(struct wtbl_rx) + \
sizeof(struct wtbl_ht) + \
sizeof(struct wtbl_vht) + \
sizeof(struct wtbl_hdr_trans) +\
sizeof(struct wtbl_ba) + \
sizeof(struct wtbl_smps))
@ -997,8 +1028,7 @@ enum {
sizeof(struct bss_info_hw_amsdu) +\
sizeof(struct bss_info_he) + \
sizeof(struct bss_info_bmc_rate) +\
sizeof(struct bss_info_ext_bss) +\
sizeof(struct bss_info_sync_mode))
sizeof(struct bss_info_ext_bss))
#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct bss_info_bcn_csa) + \

View File

@ -9,7 +9,7 @@
#include "../mt76.h"
#include "regs.h"
#define MT7915_MAX_INTERFACES 4
#define MT7915_MAX_INTERFACES 32
#define MT7915_MAX_WMM_SETS 4
#define MT7915_WTBL_SIZE 288
#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1)
@ -32,6 +32,7 @@
#define MT7915_EEPROM_SIZE 3584
#define MT7915_TOKEN_SIZE 8192
#define MT7915_TOKEN_FREE_THR 64
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
@ -112,8 +113,10 @@ struct mt7915_phy {
struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES];
struct ieee80211_vif *monitor_vif;
u32 rxfilter;
u32 omac_mask;
u64 omac_mask;
u16 noise;
u16 chainmask;
@ -159,11 +162,27 @@ struct mt7915_dev {
u32 hw_pattern;
spinlock_t token_lock;
int token_count;
struct idr token;
s8 **rate_power; /* TODO: use mt76_rate_power */
bool dbdc_support;
bool fw_debug;
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
s32 last_freq_offset;
u8 last_rcpi[4];
s8 last_ib_rssi[4];
s8 last_wb_rssi[4];
u8 last_snr;
u8 spe_idx;
} test;
#endif
};
enum {
@ -171,24 +190,13 @@ enum {
HW_BSSID_1,
HW_BSSID_2,
HW_BSSID_3,
HW_BSSID_MAX,
HW_BSSID_MAX = HW_BSSID_3,
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
EXT_BSSID_15 = 0x1f,
EXT_BSSID_MAX = EXT_BSSID_15,
REPEATER_BSSID_START = 0x20,
REPEATER_BSSID_MAX = 0x3f,
};
enum {
@ -264,15 +272,14 @@ static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac)
extern const struct ieee80211_ops mt7915_ops;
extern struct pci_driver mt7915_pci_driver;
extern const struct mt76_testmode_ops mt7915_testmode_ops;
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);
void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy);
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx);
@ -281,7 +288,7 @@ 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,
int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, bool enable);
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, int enable);
@ -289,6 +296,9 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
struct ieee80211_ampdu_params *params,
bool add);
@ -306,6 +316,7 @@ 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_set_channel(struct mt7915_phy *phy);
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,
@ -314,6 +325,8 @@ 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_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
u8 en);
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);
@ -327,8 +340,10 @@ 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_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
u8 index, u8 rx_sel, u8 val);
int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl);
@ -428,11 +443,13 @@ mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
void mt7915_mac_reset_counters(struct mt7915_phy *phy);
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy);
void mt7915_mac_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_fill_rx_vector(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);
@ -446,6 +463,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc);
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);

View File

@ -21,8 +21,14 @@ 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);
static const u32 rx_irq_mask[] = {
[MT_RXQ_MAIN] = MT_INT_RX_DONE_DATA0,
[MT_RXQ_EXT] = MT_INT_RX_DONE_DATA1,
[MT_RXQ_MCU] = MT_INT_RX_DONE_WM,
[MT_RXQ_MCU_WA] = MT_INT_RX_DONE_WA,
};
mt7915_irq_enable(dev, MT_INT_RX_DONE(q));
mt7915_irq_enable(dev, rx_irq_mask[q]);
}
/* TODO: support 2/4/6/8 MSI-X vectors */
@ -49,14 +55,17 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
if (intr & MT_INT_TX_DONE_MCU)
napi_schedule(&dev->mt76.tx_napi);
if (intr & MT_INT_RX_DONE_DATA)
napi_schedule(&dev->mt76.napi[0]);
if (intr & MT_INT_RX_DONE_DATA0)
napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
if (intr & MT_INT_RX_DONE_DATA1)
napi_schedule(&dev->mt76.napi[MT_RXQ_EXT]);
if (intr & MT_INT_RX_DONE_WM)
napi_schedule(&dev->mt76.napi[1]);
napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]);
if (intr & MT_INT_RX_DONE_WA)
napi_schedule(&dev->mt76.napi[2]);
napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]);
if (intr & MT_INT_MCU_CMD) {
u32 val = mt76_rr(dev, MT_MCU_CMD);
@ -140,7 +149,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
dev = container_of(mdev, struct mt7915_dev, mt76);
ret = mt7915_alloc_device(pdev, dev);
if (ret)
return ret;
goto error;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) |
@ -163,7 +172,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
mt76_free_device(&dev->mt76);
return ret;
}

View File

@ -51,6 +51,9 @@
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25)
#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094)
#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
@ -67,11 +70,13 @@
#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_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
#define MT_DMA_DCR0 MT_WF_DMA(0x000)
#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
@ -166,10 +171,33 @@
#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4)
#define MT_AGG_PCR0_MM_PROT BIT(0)
#define MT_AGG_PCR0_GF_PROT BIT(1)
#define MT_AGG_PCR0_BW20_PROT BIT(2)
#define MT_AGG_PCR0_BW40_PROT BIT(4)
#define MT_AGG_PCR0_BW80_PROT BIT(6)
#define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8)
#define MT_AGG_PCR0_VHT_PROT BIT(13)
#define MT_AGG_PCR0_PTA_WIN_DIS BIT(15)
#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23)
#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0)
#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084)
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)
#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098)
#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
#define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7)
#define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24)
#define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0)
#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
/* ARB: band 0(0x20c00), band 1(0xa0c00) */
#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
@ -178,6 +206,8 @@
#define MT_ARB_SCR_TX_DISABLE BIT(8)
#define MT_ARB_SCR_RX_DISABLE BIT(9)
#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
/* RMAC: band 0(0x21400), band 1(0xa1400) */
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
@ -308,11 +338,11 @@
#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_DATA0 BIT(16)
#define MT_INT_RX_DONE_DATA1 BIT(17)
#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_RX_DONE_ALL (BIT(0) | BIT(1) | GENMASK(17, 16))
#define MT_INT_TX_DONE_MCU_WA BIT(15)
#define MT_INT_TX_DONE_FWDL BIT(26)
#define MT_INT_TX_DONE_MCU_WM BIT(27)
@ -385,11 +415,19 @@
#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs))
#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188)
#define MT_WF_IRPI_BASE 0x83006000
#define MT_WF_IRPI(ofs) (MT_WF_IRPI_BASE + ((ofs) << 16))
/* 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_IPI_EN GENMASK(2, 0)
#define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
#define MT_WF_PHY_RXTD12(_phy) MT_WF_PHY(0x8230 + ((_phy) << 16))
#define MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
#define MT_WF_PHY_RXTD12_IRPI_SW_CLR BIT(29)
#endif

View File

@ -0,0 +1,377 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "testmode.h"
enum {
TM_CHANGED_TXPOWER,
TM_CHANGED_FREQ_OFFSET,
/* must be last */
NUM_TM_CHANGED
};
static const u8 tm_change_map[] = {
[TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,
[TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
};
struct reg_band {
u32 band[2];
};
#define REG_BAND(_reg) \
{ .band[0] = MT_##_reg(0), .band[1] = MT_##_reg(1) }
#define REG_BAND_IDX(_reg, _idx) \
{ .band[0] = MT_##_reg(0, _idx), .band[1] = MT_##_reg(1, _idx) }
static const struct reg_band reg_backup_list[] = {
REG_BAND_IDX(AGG_PCR0, 0),
REG_BAND_IDX(AGG_PCR0, 1),
REG_BAND_IDX(AGG_AWSCR0, 0),
REG_BAND_IDX(AGG_AWSCR0, 1),
REG_BAND_IDX(AGG_AWSCR0, 2),
REG_BAND_IDX(AGG_AWSCR0, 3),
REG_BAND(AGG_MRCR),
REG_BAND(TMAC_TFCR0),
REG_BAND(TMAC_TCR0),
REG_BAND(AGG_ATCR1),
REG_BAND(AGG_ATCR3),
REG_BAND(TMAC_TRCR0),
REG_BAND(TMAC_ICR0),
REG_BAND_IDX(ARB_DRNGR0, 0),
REG_BAND_IDX(ARB_DRNGR0, 1),
REG_BAND(WF_RFCR),
REG_BAND(WF_RFCR1),
};
static int
mt7915_tm_set_tx_power(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mt76_phy *mphy = phy->mt76;
struct cfg80211_chan_def *chandef = &mphy->chandef;
int freq = chandef->center_freq1;
int ret;
struct {
u8 format_id;
u8 dbdc_idx;
s8 tx_power;
u8 ant_idx; /* Only 0 is valid */
u8 center_chan;
u8 rsv[3];
} __packed req = {
.format_id = 0xf,
.dbdc_idx = phy != &dev->phy,
.center_chan = ieee80211_frequency_to_channel(freq),
};
u8 *tx_power = NULL;
if (dev->mt76.test.state != MT76_TM_STATE_OFF)
tx_power = dev->mt76.test.tx_power;
/* Tx power of the other antennas are the same as antenna 0 */
if (tx_power && tx_power[0])
req.tx_power = tx_power[0];
ret = mt76_mcu_send_msg(&dev->mt76,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
&req, sizeof(req), false);
return ret;
}
static int
mt7915_tm_set_freq_offset(struct mt7915_dev *dev, bool en, u32 val)
{
struct mt7915_tm_cmd req = {
.testmode_en = en,
.param_idx = MCU_ATE_SET_FREQ_OFFSET,
.param.freq.freq_offset = cpu_to_le32(val),
};
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
sizeof(req), false);
}
static int
mt7915_tm_mode_ctrl(struct mt7915_dev *dev, bool enable)
{
struct {
u8 format_id;
bool enable;
u8 rsv[2];
} __packed req = {
.format_id = 0x6,
.enable = enable,
};
return mt76_mcu_send_msg(&dev->mt76,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
&req, sizeof(req), false);
}
static int
mt7915_tm_set_trx(struct mt7915_dev *dev, struct mt7915_phy *phy,
int type, bool en)
{
struct mt7915_tm_cmd req = {
.testmode_en = 1,
.param_idx = MCU_ATE_SET_TRX,
.param.trx.type = type,
.param.trx.enable = en,
.param.trx.band = phy != &dev->phy,
};
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
sizeof(req), false);
}
static void
mt7915_tm_reg_backup_restore(struct mt7915_dev *dev, struct mt7915_phy *phy)
{
int n_regs = ARRAY_SIZE(reg_backup_list);
bool ext_phy = phy != &dev->phy;
u32 *b = dev->test.reg_backup;
int i;
if (dev->mt76.test.state == MT76_TM_STATE_OFF) {
for (i = 0; i < n_regs; i++)
mt76_wr(dev, reg_backup_list[i].band[ext_phy], b[i]);
return;
}
if (b)
return;
b = devm_kzalloc(dev->mt76.dev, 4 * n_regs, GFP_KERNEL);
if (!b)
return;
dev->test.reg_backup = b;
for (i = 0; i < n_regs; i++)
b[i] = mt76_rr(dev, reg_backup_list[i].band[ext_phy]);
mt76_clear(dev, MT_AGG_PCR0(ext_phy, 0), MT_AGG_PCR0_MM_PROT |
MT_AGG_PCR0_GF_PROT | MT_AGG_PCR0_ERP_PROT |
MT_AGG_PCR0_VHT_PROT | MT_AGG_PCR0_BW20_PROT |
MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT);
mt76_set(dev, MT_AGG_PCR0(ext_phy, 0), MT_AGG_PCR0_PTA_WIN_DIS);
mt76_wr(dev, MT_AGG_PCR0(ext_phy, 1), MT_AGG_PCR1_RTS0_NUM_THRES |
MT_AGG_PCR1_RTS0_LEN_THRES);
mt76_clear(dev, MT_AGG_MRCR(ext_phy), MT_AGG_MRCR_BAR_CNT_LIMIT |
MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT |
MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT);
mt76_rmw(dev, MT_AGG_MRCR(ext_phy), MT_AGG_MRCR_RTS_FAIL_LIMIT |
MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT,
FIELD_PREP(MT_AGG_MRCR_RTS_FAIL_LIMIT, 1) |
FIELD_PREP(MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 1));
mt76_wr(dev, MT_TMAC_TFCR0(ext_phy), 0);
mt76_clear(dev, MT_TMAC_TCR0(ext_phy), MT_TMAC_TCR0_TBTT_STOP_CTRL);
/* config rx filter for testmode rx */
mt76_wr(dev, MT_WF_RFCR(ext_phy), 0xcf70a);
mt76_wr(dev, MT_WF_RFCR1(ext_phy), 0);
}
static void
mt7915_tm_init(struct mt7915_dev *dev)
{
bool en = !(dev->mt76.test.state == MT76_TM_STATE_OFF);
if (!test_bit(MT76_STATE_RUNNING, &dev->phy.mt76->state))
return;
mt7915_tm_mode_ctrl(dev, en);
mt7915_tm_reg_backup_restore(dev, &dev->phy);
mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TXRX, !en);
}
static void
mt7915_tm_set_tx_frames(struct mt7915_dev *dev, bool en)
{
static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0,
9, 8, 6, 10, 16, 12, 18, 0};
struct sk_buff *skb = dev->mt76.test.tx_skb;
struct ieee80211_tx_info *info;
mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, false);
if (en) {
u8 tx_ant = dev->mt76.test.tx_antenna_mask;
mutex_unlock(&dev->mt76.mutex);
mt7915_set_channel(&dev->phy);
mutex_lock(&dev->mt76.mutex);
mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH);
dev->test.spe_idx = spe_idx_map[tx_ant];
}
mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TX, en);
if (!en || !skb)
return;
info = IEEE80211_SKB_CB(skb);
info->control.vif = dev->phy.monitor_vif;
}
static void
mt7915_tm_set_rx_frames(struct mt7915_dev *dev, bool en)
{
if (en) {
mutex_unlock(&dev->mt76.mutex);
mt7915_set_channel(&dev->phy);
mutex_lock(&dev->mt76.mutex);
mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH);
}
mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, en);
}
static void
mt7915_tm_update_params(struct mt7915_dev *dev, u32 changed)
{
struct mt76_testmode_data *td = &dev->mt76.test;
bool en = dev->mt76.test.state != MT76_TM_STATE_OFF;
if (changed & BIT(TM_CHANGED_FREQ_OFFSET))
mt7915_tm_set_freq_offset(dev, en, en ? td->freq_offset : 0);
if (changed & BIT(TM_CHANGED_TXPOWER))
mt7915_tm_set_tx_power(&dev->phy);
}
static int
mt7915_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt76_testmode_data *td = &mdev->test;
enum mt76_testmode_state prev_state = td->state;
mdev->test.state = state;
if (prev_state == MT76_TM_STATE_TX_FRAMES)
mt7915_tm_set_tx_frames(dev, false);
else if (state == MT76_TM_STATE_TX_FRAMES)
mt7915_tm_set_tx_frames(dev, true);
else if (prev_state == MT76_TM_STATE_RX_FRAMES)
mt7915_tm_set_rx_frames(dev, false);
else if (state == MT76_TM_STATE_RX_FRAMES)
mt7915_tm_set_rx_frames(dev, true);
else if (prev_state == MT76_TM_STATE_OFF || state == MT76_TM_STATE_OFF)
mt7915_tm_init(dev);
if ((state == MT76_TM_STATE_IDLE &&
prev_state == MT76_TM_STATE_OFF) ||
(state == MT76_TM_STATE_OFF &&
prev_state == MT76_TM_STATE_IDLE)) {
u32 changed = 0;
int i;
for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
u16 cur = tm_change_map[i];
if (td->param_set[cur / 32] & BIT(cur % 32))
changed |= BIT(i);
}
mt7915_tm_update_params(dev, changed);
}
return 0;
}
static int
mt7915_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb,
enum mt76_testmode_state new_state)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt76_testmode_data *td = &dev->mt76.test;
u32 changed = 0;
int i;
BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
if (new_state == MT76_TM_STATE_OFF ||
td->state == MT76_TM_STATE_OFF)
return 0;
if (td->tx_antenna_mask & ~dev->phy.chainmask)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
if (tb[tm_change_map[i]])
changed |= BIT(i);
}
mt7915_tm_update_params(dev, changed);
return 0;
}
static int
mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
void *rx, *rssi;
int i;
rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
if (!rx)
return -ENOMEM;
if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset))
return -ENOMEM;
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
if (!rssi)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++)
if (nla_put_u8(msg, i, dev->test.last_rcpi[i]))
return -ENOMEM;
nla_nest_end(msg, rssi);
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
if (!rssi)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++)
if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i]))
return -ENOMEM;
nla_nest_end(msg, rssi);
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
if (!rssi)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++)
if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i]))
return -ENOMEM;
nla_nest_end(msg, rssi);
if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, dev->test.last_snr))
return -ENOMEM;
nla_nest_end(msg, rx);
return 0;
}
const struct mt76_testmode_ops mt7915_testmode_ops = {
.set_state = mt7915_tm_set_state,
.set_params = mt7915_tm_set_params,
.dump_stats = mt7915_tm_dump_stats,
};

View File

@ -0,0 +1,40 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_TESTMODE_H
#define __MT7915_TESTMODE_H
struct mt7915_tm_trx {
u8 type;
u8 enable;
u8 band;
u8 rsv;
};
struct mt7915_tm_freq_offset {
u8 band;
__le32 freq_offset;
};
struct mt7915_tm_cmd {
u8 testmode_en;
u8 param_idx;
u8 _rsv[2];
union {
__le32 data;
struct mt7915_tm_trx trx;
struct mt7915_tm_freq_offset freq;
u8 test[72];
} param;
} __packed;
enum {
TM_MAC_TX = 1,
TM_MAC_RX,
TM_MAC_TXRX,
TM_MAC_TXRX_RXV,
TM_MAC_RXV,
TM_MAC_RX_RXV,
};
#endif

View File

@ -36,47 +36,50 @@ mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
return 0;
}
static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev)
{
struct mt76_queue *q;
q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
if (!q)
return ERR_PTR(-ENOMEM);
spin_lock_init(&q->lock);
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return ERR_PTR(-ENOMEM);
q->ndesc = MT_NUM_TX_ENTRIES;
return q;
}
static int mt76s_alloc_tx(struct mt76_dev *dev)
{
struct mt76_queue *q;
int i;
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
if (!q)
return -ENOMEM;
for (i = 0; i <= MT_TXQ_PSD; i++) {
q = mt76s_alloc_tx_queue(dev);
if (IS_ERR(q))
return PTR_ERR(q);
spin_lock_init(&q->lock);
q->hw_idx = i;
dev->q_tx[i] = q;
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
q->ndesc = MT_NUM_TX_ENTRIES;
q->qid = i;
dev->phy.q_tx[i] = q;
}
q = mt76s_alloc_tx_queue(dev);
if (IS_ERR(q))
return PTR_ERR(q);
q->qid = MT_MCUQ_WM;
dev->q_mcu[MT_MCUQ_WM] = q;
return 0;
}
void mt76s_stop_txrx(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
cancel_work_sync(&sdio->tx.xmit_work);
cancel_work_sync(&sdio->tx.status_work);
cancel_work_sync(&sdio->rx.recv_work);
cancel_work_sync(&sdio->rx.net_work);
cancel_work_sync(&sdio->stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
mt76_tx_status_check(dev, NULL, true);
}
EXPORT_SYMBOL_GPL(mt76s_stop_txrx);
int mt76s_alloc_queues(struct mt76_dev *dev)
{
int err;
@ -131,11 +134,32 @@ mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
return nframes;
}
static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
static void mt76s_net_worker(struct mt76_worker *w)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
net_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes;
do {
nframes = 0;
local_bh_disable();
rcu_read_lock();
mt76_for_each_q_rx(dev, i)
nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]);
rcu_read_unlock();
local_bh_enable();
} while (nframes > 0);
}
static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
bool wake, mcu = q == dev->q_mcu[MT_MCUQ_WM];
struct mt76_queue_entry entry;
bool wake;
int nframes = 0;
while (q->queued > 0) {
if (!q->entry[q->tail].done)
@ -144,12 +168,13 @@ static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
entry = q->entry[q->tail];
q->entry[q->tail].done = false;
if (qid == MT_TXQ_MCU) {
if (mcu) {
dev_kfree_skb(entry.skb);
entry.skb = NULL;
}
mt76_queue_tx_complete(dev, q, &entry);
nframes++;
}
wake = q->stopped && q->queued < q->ndesc - 8;
@ -159,13 +184,35 @@ static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (!q->queued)
wake_up(&dev->tx_wait);
if (qid == MT_TXQ_MCU)
return;
if (mcu)
goto out;
mt76_txq_schedule(&dev->phy, qid);
mt76_txq_schedule(&dev->phy, q->qid);
if (wake)
ieee80211_wake_queue(dev->hw, qid);
ieee80211_wake_queue(dev->hw, q->qid);
out:
return nframes;
}
static void mt76s_status_worker(struct mt76_worker *w)
{
struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
status_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes;
do {
nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
for (i = 0; i <= MT_TXQ_PSD; i++)
nframes += mt76s_process_tx_queue(dev,
dev->phy.q_tx[i]);
if (dev->drv->tx_status_data &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
queue_work(dev->wq, &dev->sdio.stat_work);
} while (nframes > 0);
}
static void mt76s_tx_status_data(struct work_struct *work)
@ -194,11 +241,10 @@ static void mt76s_tx_status_data(struct work_struct *work)
}
static int
mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@ -209,7 +255,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
return -ENOSPC;
skb->prev = skb->next = NULL;
err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info);
if (err < 0)
return err;
@ -222,10 +268,9 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
}
static int
mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
mt76s_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info)
{
struct mt76_queue *q = dev->q_tx[qid];
int ret = -ENOSPC, len = skb->len, pad;
if (q->queued == q->ndesc)
@ -257,7 +302,7 @@ static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
{
struct mt76_sdio *sdio = &dev->sdio;
queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
mt76_worker_schedule(&sdio->txrx_worker);
}
static const struct mt76_queue_ops sdio_queue_ops = {
@ -266,49 +311,19 @@ static const struct mt76_queue_ops sdio_queue_ops = {
.tx_queue_skb_raw = mt76s_tx_queue_skb_raw,
};
static void mt76s_tx_work(struct work_struct *work)
{
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
tx.status_work);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i;
for (i = 0; i < MT_TXQ_MCU_WA; i++)
mt76s_process_tx_queue(dev, i);
if (dev->drv->tx_status_data &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
queue_work(dev->wq, &dev->sdio.stat_work);
}
static void mt76s_rx_work(struct work_struct *work)
{
struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
rx.net_work);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i;
/* rx processing */
local_bh_disable();
rcu_read_lock();
mt76_for_each_q_rx(dev, i)
mt76s_process_rx_queue(dev, &dev->q_rx[i]);
rcu_read_unlock();
local_bh_enable();
}
void mt76s_deinit(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
int i;
mt76s_stop_txrx(dev);
if (sdio->txrx_wq) {
destroy_workqueue(sdio->txrx_wq);
sdio->txrx_wq = NULL;
}
mt76_worker_teardown(&sdio->txrx_worker);
mt76_worker_teardown(&sdio->status_worker);
mt76_worker_teardown(&sdio->net_worker);
cancel_work_sync(&sdio->stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
mt76_tx_status_check(dev, NULL, true);
sdio_claim_host(sdio->func);
sdio_release_irq(sdio->func);
@ -335,18 +350,23 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
const struct mt76_bus_ops *bus_ops)
{
struct mt76_sdio *sdio = &dev->sdio;
int err;
sdio->txrx_wq = alloc_workqueue("mt76s_txrx_wq",
WQ_UNBOUND | WQ_HIGHPRI,
WQ_UNBOUND_MAX_ACTIVE);
if (!sdio->txrx_wq)
return -ENOMEM;
err = mt76_worker_setup(dev->hw, &sdio->status_worker,
mt76s_status_worker, "sdio-status");
if (err)
return err;
err = mt76_worker_setup(dev->hw, &sdio->net_worker, mt76s_net_worker,
"sdio-net");
if (err)
return err;
sched_set_fifo_low(sdio->status_worker.task);
sched_set_fifo_low(sdio->net_worker.task);
INIT_WORK(&sdio->stat_work, mt76s_tx_status_data);
INIT_WORK(&sdio->tx.status_work, mt76s_tx_work);
INIT_WORK(&sdio->rx.net_work, mt76s_rx_work);
mutex_init(&sdio->sched.lock);
dev->queue_ops = &sdio_queue_ops;
dev->bus = bus_ops;
dev->sdio.func = func;

View File

@ -11,6 +11,8 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED },
@ -21,6 +23,7 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
struct mt76_wcid *wcid = &dev->global_wcid;
struct mt76_phy *phy = &dev->phy;
struct sk_buff *skb = td->tx_skb;
struct mt76_queue *q;
int qid;
@ -29,7 +32,7 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
return;
qid = skb_get_queue_mapping(skb);
q = dev->q_tx[qid];
q = phy->q_tx[qid];
spin_lock_bh(&q->lock);
@ -37,7 +40,8 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
q->queued < q->ndesc / 2) {
int ret;
ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL);
ret = dev->queue_ops->tx_queue_skb(dev, q, skb_get(skb), wcid,
NULL);
if (ret < 0)
break;
@ -55,13 +59,14 @@ static int
mt76_testmode_tx_init(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
struct mt76_phy *phy = &dev->phy;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_FROMDS;
struct ieee80211_tx_rate *rate;
u8 max_nss = hweight8(dev->phy.antenna_mask);
u8 max_nss = hweight8(phy->antenna_mask);
if (td->tx_antenna_mask)
max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask));
@ -74,28 +79,32 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
td->tx_skb = skb;
hdr = __skb_put_zero(skb, td->tx_msdu_len);
hdr->frame_control = cpu_to_le16(fc);
memcpy(hdr->addr1, dev->macaddr, sizeof(dev->macaddr));
memcpy(hdr->addr2, dev->macaddr, sizeof(dev->macaddr));
memcpy(hdr->addr3, dev->macaddr, sizeof(dev->macaddr));
memcpy(hdr->addr1, phy->macaddr, sizeof(phy->macaddr));
memcpy(hdr->addr2, phy->macaddr, sizeof(phy->macaddr));
memcpy(hdr->addr3, phy->macaddr, sizeof(phy->macaddr));
info = IEEE80211_SKB_CB(skb);
info->flags = IEEE80211_TX_CTL_INJECTED |
IEEE80211_TX_CTL_NO_ACK |
IEEE80211_TX_CTL_NO_PS_BUFFER;
if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT)
goto out;
rate = &info->control.rates[0];
rate->count = 1;
rate->idx = td->tx_rate_idx;
switch (td->tx_rate_mode) {
case MT76_TM_TX_MODE_CCK:
if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ)
if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
return -EINVAL;
if (rate->idx > 4)
return -EINVAL;
break;
case MT76_TM_TX_MODE_OFDM:
if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ)
if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
break;
if (rate->idx > 8)
@ -106,7 +115,7 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
case MT76_TM_TX_MODE_HT:
if (rate->idx > 8 * max_nss &&
!(rate->idx == 32 &&
dev->phy.chandef.width >= NL80211_CHAN_WIDTH_40))
phy->chandef.width >= NL80211_CHAN_WIDTH_40))
return -EINVAL;
rate->flags |= IEEE80211_TX_RC_MCS;
@ -131,8 +140,11 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
if (td->tx_rate_ldpc)
info->flags |= IEEE80211_TX_CTL_LDPC;
if (td->tx_rate_stbc)
info->flags |= IEEE80211_TX_CTL_STBC;
if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) {
switch (dev->phy.chandef.width) {
switch (phy->chandef.width) {
case NL80211_CHAN_WIDTH_40:
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
break;
@ -147,7 +159,7 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
break;
}
}
out:
skb_set_queue_mapping(skb, IEEE80211_AC_BE);
return 0;
@ -334,8 +346,10 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0, MT76_TM_TX_MODE_MAX) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,
1, hweight8(phy->antenna_mask)) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 1) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 2) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 1,
phy->antenna_mask) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
@ -472,6 +486,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&

View File

@ -25,6 +25,8 @@
* @MT76_TM_ATTR_TX_RATE_IDX: packet tx rate/MCS index (u8)
* @MT76_TM_ATTR_TX_RATE_SGI: packet tx use short guard interval (u8)
* @MT76_TM_ATTR_TX_RATE_LDPC: packet tx enable LDPC (u8)
* @MT76_TM_ATTR_TX_RATE_STBC: packet tx enable STBC (u8)
* @MT76_TM_ATTR_TX_LTF: packet tx LTF, set 0 to 2 for 1x, 2x, and 4x LTF (u8)
*
* @MT76_TM_ATTR_TX_ANTENNA: tx antenna mask (u8)
* @MT76_TM_ATTR_TX_POWER_CONTROL: enable tx power control (u8)
@ -50,6 +52,8 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_TX_RATE_IDX,
MT76_TM_ATTR_TX_RATE_SGI,
MT76_TM_ATTR_TX_RATE_LDPC,
MT76_TM_ATTR_TX_RATE_STBC,
MT76_TM_ATTR_TX_LTF,
MT76_TM_ATTR_TX_ANTENNA,
MT76_TM_ATTR_TX_POWER_CONTROL,
@ -99,8 +103,9 @@ enum mt76_testmode_stats_attr {
*
* @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32)
* @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8)
* @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (s8)
* @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (s8)
* @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (array, s8)
* @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (array, s8)
* @MT76_TM_RX_ATTR_SNR: signal-to-noise ratio (u8)
*/
enum mt76_testmode_rx_attr {
MT76_TM_RX_ATTR_UNSPEC,
@ -109,6 +114,7 @@ enum mt76_testmode_rx_attr {
MT76_TM_RX_ATTR_RCPI,
MT76_TM_RX_ATTR_IB_RSSI,
MT76_TM_RX_ATTR_WB_RSSI,
MT76_TM_RX_ATTR_SNR,
/* keep last */
NUM_MT76_TM_RX_ATTRS,
@ -141,12 +147,20 @@ enum mt76_testmode_state {
* @MT76_TM_TX_MODE_OFDM: legacy OFDM mode
* @MT76_TM_TX_MODE_HT: 802.11n MCS
* @MT76_TM_TX_MODE_VHT: 802.11ac MCS
* @MT76_TM_TX_MODE_HE_SU: 802.11ax single-user MIMO
* @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
* @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
* @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
*/
enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_CCK,
MT76_TM_TX_MODE_OFDM,
MT76_TM_TX_MODE_HT,
MT76_TM_TX_MODE_VHT,
MT76_TM_TX_MODE_HE_SU,
MT76_TM_TX_MODE_HE_EXT_SU,
MT76_TM_TX_MODE_HE_TB,
MT76_TM_TX_MODE_HE_MU,
/* keep last */
NUM_MT76_TM_TX_MODES,

View File

@ -225,23 +225,23 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk
EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
static int
__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb,
__mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
bool *stop)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mt76_queue *q;
struct mt76_queue *q = phy->q_tx[qid];
struct mt76_dev *dev = phy->dev;
bool non_aql;
int pending;
int idx;
non_aql = !info->tx_time_est;
idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta);
if (idx < 0 || !sta || !non_aql)
return idx;
wcid = (struct mt76_wcid *)sta->drv_priv;
q = dev->q_tx[qid];
q->entry[idx].wcid = wcid->idx;
pending = atomic_inc_return(&wcid->non_aql_packets);
if (stop && pending >= MT_MAX_NON_AQL_PKT)
@ -272,6 +272,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
}
if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
qid = MT_TXQ_PSD;
@ -285,17 +286,11 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
if (ext_phy)
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
q = dev->q_tx[qid];
q = phy->q_tx[qid];
spin_lock_bh(&q->lock);
__mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL);
__mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL);
dev->queue_ops->kick(dev, q);
if (q->queued > q->ndesc - 8 && !q->stopped) {
ieee80211_stop_queue(phy->hw, skb_get_queue_mapping(skb));
q->stopped = true;
}
spin_unlock_bh(&q->lock);
}
EXPORT_SYMBOL_GPL(mt76_tx);
@ -320,7 +315,7 @@ mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
}
static void
mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta,
struct sk_buff *skb, bool last)
{
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
@ -332,7 +327,7 @@ mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
IEEE80211_TX_CTL_REQ_TX_STATUS;
mt76_skb_set_moredata(skb, !last);
__mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL);
__mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL);
}
void
@ -344,7 +339,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
struct sk_buff *last_skb = NULL;
struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD];
struct mt76_queue *hwq = phy->q_tx[MT_TXQ_PSD];
int i;
spin_lock_bh(&hwq->lock);
@ -363,14 +358,14 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
nframes--;
if (last_skb)
mt76_queue_ps_skb(dev, sta, last_skb, false);
mt76_queue_ps_skb(phy, sta, last_skb, false);
last_skb = skb;
} while (nframes);
}
if (last_skb) {
mt76_queue_ps_skb(dev, sta, last_skb, true);
mt76_queue_ps_skb(phy, sta, last_skb, true);
dev->queue_ops->kick(dev, hwq);
} else {
ieee80211_sta_eosp(sta);
@ -380,6 +375,13 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
}
EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
static bool
mt76_txq_stopped(struct mt76_queue *q)
{
return q->stopped || q->blocked ||
q->queued + MT_TXQ_FREE_THR >= q->ndesc;
}
static int
mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
struct mt76_txq *mtxq)
@ -409,7 +411,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
info->control.rates, 1);
idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
return idx;
@ -418,10 +420,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
test_bit(MT76_RESET, &phy->state))
return -EBUSY;
if (stop)
break;
if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
if (stop || mt76_txq_stopped(q))
break;
skb = mt76_txq_dequeue(phy, mtxq);
@ -433,7 +432,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
info->control.rates, 1);
idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
break;
@ -448,8 +447,8 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
static int
mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
{
struct mt76_queue *q = phy->q_tx[qid];
struct mt76_dev *dev = phy->dev;
struct mt76_queue *q = dev->q_tx[qid];
struct ieee80211_txq *txq;
struct mt76_txq *mtxq;
struct mt76_wcid *wcid;
@ -463,7 +462,14 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
break;
}
if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
if (dev->queue_ops->tx_cleanup &&
q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) {
spin_unlock_bh(&q->lock);
dev->queue_ops->tx_cleanup(dev, q, false);
spin_lock_bh(&q->lock);
}
if (mt76_txq_stopped(q))
break;
txq = ieee80211_next_txq(phy->hw, qid);
@ -498,11 +504,14 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
{
struct mt76_queue *q;
int len;
if (qid >= 4)
return;
q = phy->q_tx[qid];
rcu_read_lock();
do {
@ -538,7 +547,7 @@ void mt76_tx_worker(struct mt76_worker *w)
#endif
}
void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar)
{
int i;
@ -551,7 +560,7 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
if (!txq)
continue;
hwq = dev->q_tx[mt76_txq_get_qid(txq)];
hwq = phy->q_tx[mt76_txq_get_qid(txq)];
mtxq = (struct mt76_txq *)txq->drv_priv;
spin_lock_bh(&hwq->lock);

View File

@ -627,7 +627,7 @@ static void mt76u_complete_rx(struct urb *urb)
q->head = (q->head + 1) % q->ndesc;
q->queued++;
tasklet_schedule(&dev->usb.rx_tasklet);
mt76_worker_schedule(&dev->usb.rx_worker);
out:
spin_unlock_irqrestore(&q->lock, flags);
}
@ -665,13 +665,17 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
}
mt76u_submit_rx_buf(dev, qid, urb);
}
if (qid == MT_RXQ_MAIN)
if (qid == MT_RXQ_MAIN) {
local_bh_disable();
mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL);
local_bh_enable();
}
}
static void mt76u_rx_tasklet(unsigned long data)
static void mt76u_rx_worker(struct mt76_worker *w)
{
struct mt76_dev *dev = (struct mt76_dev *)data;
struct mt76_usb *usb = container_of(w, struct mt76_usb, rx_worker);
struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb);
int i;
rcu_read_lock();
@ -737,8 +741,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
struct page *page;
int i;
for (i = 0; i < q->ndesc; i++)
for (i = 0; i < q->ndesc; i++) {
if (!q->entry[i].urb)
continue;
mt76u_urb_free(q->entry[i].urb);
q->entry[i].urb = NULL;
}
if (!q->rx_page.va)
return;
@ -752,6 +761,8 @@ static void mt76u_free_rx(struct mt76_dev *dev)
{
int i;
mt76_worker_teardown(&dev->usb.rx_worker);
mt76_for_each_q_rx(dev, i)
mt76u_free_rx_queue(dev, &dev->q_rx[i]);
}
@ -760,6 +771,8 @@ void mt76u_stop_rx(struct mt76_dev *dev)
{
int i;
mt76_worker_disable(&dev->usb.rx_worker);
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
int j;
@ -767,8 +780,6 @@ void mt76u_stop_rx(struct mt76_dev *dev)
for (j = 0; j < q->ndesc; j++)
usb_poison_urb(q->entry[j].urb);
}
tasklet_kill(&dev->usb.rx_tasklet);
}
EXPORT_SYMBOL_GPL(mt76u_stop_rx);
@ -788,20 +799,23 @@ int mt76u_resume_rx(struct mt76_dev *dev)
return err;
}
mt76_worker_enable(&dev->usb.rx_worker);
return 0;
}
EXPORT_SYMBOL_GPL(mt76u_resume_rx);
static void mt76u_tx_worker(struct mt76_worker *w)
static void mt76u_status_worker(struct mt76_worker *w)
{
struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
struct mt76_usb *usb = container_of(w, struct mt76_usb, status_worker);
struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb);
struct mt76_queue_entry entry;
struct mt76_queue *q;
bool wake;
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
q = dev->q_tx[i];
q = dev->phy.q_tx[i];
while (q->queued > 0) {
if (!q->entry[q->tail].done)
@ -820,7 +834,7 @@ static void mt76u_tx_worker(struct mt76_worker *w)
if (!q->queued)
wake_up(&dev->tx_wait);
mt76_txq_schedule(&dev->phy, i);
mt76_worker_schedule(&dev->tx_worker);
if (dev->drv->tx_status_data &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
@ -864,7 +878,7 @@ static void mt76u_complete_tx(struct urb *urb)
dev_err(dev->dev, "tx urb failed: %d\n", urb->status);
e->done = true;
mt76_worker_schedule(&dev->tx_worker);
mt76_worker_schedule(&dev->usb.status_worker);
}
static int
@ -887,11 +901,10 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb,
}
static int
mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@ -902,7 +915,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
return -ENOSPC;
skb->prev = skb->next = NULL;
err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info);
if (err < 0)
return err;
@ -970,7 +983,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
for (i = 0; i <= MT_TXQ_PSD; i++) {
if (i >= IEEE80211_NUM_ACS) {
dev->q_tx[i] = dev->q_tx[0];
dev->phy.q_tx[i] = dev->phy.q_tx[0];
continue;
}
@ -980,7 +993,9 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
spin_lock_init(&q->lock);
q->hw_idx = mt76u_ac_to_hwq(dev, i);
dev->q_tx[i] = q;
q->qid = i;
dev->phy.q_tx[i] = q;
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
@ -1003,16 +1018,20 @@ static void mt76u_free_tx(struct mt76_dev *dev)
{
int i;
mt76_worker_teardown(&dev->usb.status_worker);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
struct mt76_queue *q;
int j;
q = dev->q_tx[i];
q = dev->phy.q_tx[i];
if (!q)
continue;
for (j = 0; j < q->ndesc; j++)
for (j = 0; j < q->ndesc; j++) {
usb_free_urb(q->entry[j].urb);
q->entry[j].urb = NULL;
}
}
}
@ -1020,6 +1039,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
{
int ret;
mt76_worker_disable(&dev->usb.status_worker);
ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy),
HZ / 5);
if (!ret) {
@ -1030,7 +1051,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
dev_err(dev->dev, "timed out waiting for pending tx\n");
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
q = dev->q_tx[i];
q = dev->phy.q_tx[i];
if (!q)
continue;
@ -1044,7 +1065,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
* will fail to submit urb, cleanup those skb's manually.
*/
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
q = dev->q_tx[i];
q = dev->phy.q_tx[i];
if (!q)
continue;
@ -1061,6 +1082,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
cancel_work_sync(&dev->usb.stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
mt76_worker_enable(&dev->usb.status_worker);
mt76_tx_status_check(dev, NULL, true);
}
EXPORT_SYMBOL_GPL(mt76u_stop_tx);
@ -1103,15 +1126,13 @@ int mt76u_init(struct mt76_dev *dev,
};
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
int err = -ENOMEM;
int err;
mt76u_ops.rr = ext ? mt76u_rr_ext : mt76u_rr;
mt76u_ops.wr = ext ? mt76u_wr_ext : mt76u_wr;
mt76u_ops.rmw = ext ? mt76u_rmw_ext : mt76u_rmw;
mt76u_ops.write_copy = ext ? mt76u_copy_ext : mt76u_copy;
dev->tx_worker.fn = mt76u_tx_worker;
tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);
@ -1120,7 +1141,7 @@ int mt76u_init(struct mt76_dev *dev,
usb->data = devm_kmalloc(dev->dev, usb->data_len, GFP_KERNEL);
if (!usb->data)
goto error;
return -ENOMEM;
mutex_init(&usb->usb_ctrl_mtx);
dev->bus = &mt76u_ops;
@ -1132,14 +1153,22 @@ int mt76u_init(struct mt76_dev *dev,
err = mt76u_set_endpoints(intf, usb);
if (err < 0)
goto error;
return err;
err = mt76_worker_setup(dev->hw, &usb->rx_worker, mt76u_rx_worker,
"usb-rx");
if (err)
return err;
err = mt76_worker_setup(dev->hw, &usb->status_worker,
mt76u_status_worker, "usb-status");
if (err)
return err;
sched_set_fifo_low(usb->rx_worker.task);
sched_set_fifo_low(usb->status_worker.task);
return 0;
error:
destroy_workqueue(dev->wq);
return err;
}
EXPORT_SYMBOL_GPL(mt76u_init);