Commit d18afb2a authored by Kalle Valo's avatar Kalle Valo

Merge tag 'mt76-for-kvalo-2018-09-19' of https://github.com/nbd168/wireless

mt76 patches for 4.20

* lots of mt76x0 cleanups / fixes
* mt76x2u fixes
* unify code between mt76x0, mt76x2e and mt76x2u
* rename mt76x0 to mt76x0u
* improve rx buffer allocation for all variants
* prepare for adding mt76x0e (pci-e variant) support
  add CONFIG_MT76x0E kconfig symbol
parents 43e2f290 bf3741ad
......@@ -7,25 +7,39 @@ config MT76_USB
config MT76x02_LIB
tristate
depends on MT76_CORE
select MT76_CORE
config MT76x02_USB
tristate
select MT76_USB
config MT76x0_COMMON
tristate
select MT76x02_LIB
config MT76x2_COMMON
tristate
select MT76x02_LIB
depends on MT76_CORE
config MT76x0U
tristate "MediaTek MT76x0U (USB) support"
select MT76_CORE
select MT76x0_COMMON
select MT76x02_USB
depends on MAC80211
depends on USB
select MT76x02_LIB
help
This adds support for MT7610U-based wireless USB dongles.
config MT76x0E
tristate "MediaTek MT76x0E (PCIe) support"
select MT76x0_COMMON
depends on MAC80211
depends on PCI
help
This adds support for MT7610/MT7630-based wireless PCIe devices.
config MT76x2E
tristate "MediaTek MT76x2E (PCIe) support"
select MT76_CORE
select MT76x2_COMMON
depends on MAC80211
depends on PCI
......@@ -34,9 +48,8 @@ config MT76x2E
config MT76x2U
tristate "MediaTek MT76x2U (USB) support"
select MT76_CORE
select MT76_USB
select MT76x2_COMMON
select MT76x02_USB
depends on MAC80211
depends on USB
help
......
obj-$(CONFIG_MT76_CORE) += mt76.o
obj-$(CONFIG_MT76_USB) += mt76-usb.o
obj-$(CONFIG_MT76x0U) += mt76x0/
obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o
obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o
obj-$(CONFIG_MT76x2_COMMON) += mt76x2-common.o
obj-$(CONFIG_MT76x2E) += mt76x2e.o
obj-$(CONFIG_MT76x2U) += mt76x2u.o
......@@ -14,12 +15,14 @@ mt76-usb-y := usb.o usb_trace.o usb_mcu.o
CFLAGS_trace.o := -I$(src)
CFLAGS_usb_trace.o := -I$(src)
mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o
mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o
mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
mt76x2-common-y := \
mt76x2_eeprom.o mt76x2_tx_common.o mt76x2_mac_common.o \
mt76x2_init_common.o mt76x2_common.o mt76x2_phy_common.o \
mt76x2_debugfs.o
mt76x2_debugfs.o mt76x2_mcu_common.o
mt76x2e-y := \
mt76x2_pci.o mt76x2_dma.o \
......
......@@ -322,19 +322,13 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
int len = SKB_WITH_OVERHEAD(q->buf_size);
int offset = q->buf_offset;
int idx;
void *(*alloc)(unsigned int fragsz);
if (napi)
alloc = napi_alloc_frag;
else
alloc = netdev_alloc_frag;
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
struct mt76_queue_buf qbuf;
buf = alloc(q->buf_size);
buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
if (!buf)
break;
......@@ -361,6 +355,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
struct page *page;
void *buf;
bool more;
......@@ -373,6 +368,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
skb_free_frag(buf);
} while (1);
spin_unlock_bh(&q->lock);
if (!q->rx_page.va)
return;
page = virt_to_page(q->rx_page.va);
__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
memset(&q->rx_page, 0, sizeof(q->rx_page));
}
static void
......
......@@ -25,34 +25,6 @@
#define MT_DMA_CTL_LAST_SEC0 BIT(30)
#define MT_DMA_CTL_DMA_DONE BIT(31)
#define MT_TXD_INFO_LEN GENMASK(15, 0)
#define MT_TXD_INFO_NEXT_VLD BIT(16)
#define MT_TXD_INFO_TX_BURST BIT(17)
#define MT_TXD_INFO_80211 BIT(19)
#define MT_TXD_INFO_TSO BIT(20)
#define MT_TXD_INFO_CSO BIT(21)
#define MT_TXD_INFO_WIV BIT(24)
#define MT_TXD_INFO_QSEL GENMASK(26, 25)
#define MT_TXD_INFO_DPORT GENMASK(29, 27)
#define MT_TXD_INFO_TYPE GENMASK(31, 30)
#define MT_RX_FCE_INFO_LEN GENMASK(13, 0)
#define MT_RX_FCE_INFO_SELF_GEN BIT(15)
#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16)
#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20)
#define MT_RX_FCE_INFO_PCIE_INTR BIT(24)
#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25)
#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27)
#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30)
/* MCU request message header */
#define MT_MCU_MSG_LEN GENMASK(15, 0)
#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16)
#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20)
#define MT_MCU_MSG_PORT GENMASK(29, 27)
#define MT_MCU_MSG_TYPE GENMASK(31, 30)
#define MT_MCU_MSG_TYPE_CMD BIT(30)
#define MT_DMA_HDR_LEN 4
#define MT_RX_INFO_LEN 4
#define MT_FCE_INFO_LEN 4
......@@ -65,14 +37,11 @@ struct mt76_desc {
__le32 info;
} __packed __aligned(4);
enum dma_msg_port {
WLAN_PORT,
CPU_RX_PORT,
CPU_TX_PORT,
HOST_PORT,
VIRTUAL_CPU_RX_PORT,
VIRTUAL_CPU_TX_PORT,
DISCARD,
enum mt76_qsel {
MT_QSEL_MGMT,
MT_QSEL_HCCA,
MT_QSEL_EDCA,
MT_QSEL_EDCA_2,
};
enum mt76_mcu_evt_type {
......
......@@ -475,7 +475,7 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
}
EXPORT_SYMBOL(mt76_wcid_key_setup);
static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct mt76_rx_status mstat;
......@@ -500,6 +500,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
return wcid_to_sta(mstat.wcid);
}
EXPORT_SYMBOL(mt76_rx_convert);
static int
mt76_check_ccmp_pn(struct sk_buff *skb)
......
......@@ -21,7 +21,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
{
u32 val;
val = ioread32(dev->regs + offset);
val = ioread32(dev->mmio.regs + offset);
trace_reg_rr(dev, offset, val);
return val;
......@@ -30,7 +30,7 @@ static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
static void mt76_mmio_wr(struct mt76_dev *dev, u32 offset, u32 val)
{
trace_reg_wr(dev, offset, val);
iowrite32(val, dev->regs + offset);
iowrite32(val, dev->mmio.regs + offset);
}
static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
......@@ -43,7 +43,7 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val)
static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data,
int len)
{
__iowrite32_copy(dev->regs + offset, data, len >> 2);
__iowrite32_copy(dev->mmio.regs + offset, data, len >> 2);
}
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
......@@ -56,6 +56,10 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
};
dev->bus = &mt76_mmio_ops;
dev->regs = regs;
dev->mmio.regs = regs;
skb_queue_head_init(&dev->mmio.mcu.res_q);
init_waitqueue_head(&dev->mmio.mcu.wait);
mutex_init(&dev->mmio.mcu.mutex);
}
EXPORT_SYMBOL_GPL(mt76_mmio_init);
......@@ -33,12 +33,21 @@
struct mt76_dev;
struct mt76_wcid;
struct mt76_reg_pair {
u32 reg;
u32 value;
};
struct mt76_bus_ops {
u32 (*rr)(struct mt76_dev *dev, u32 offset);
void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val);
void (*copy)(struct mt76_dev *dev, u32 offset, const void *data,
int len);
int (*wr_rp)(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *rp, int len);
int (*rd_rp)(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *rp, int len);
};
enum mt76_txq_id {
......@@ -53,11 +62,6 @@ enum mt76_txq_id {
__MT_TXQ_MAX
};
struct mt76_reg_pair {
u32 reg;
u32 value;
};
enum mt76_rxq_id {
MT_RXQ_MAIN,
MT_RXQ_MCU,
......@@ -117,6 +121,17 @@ struct mt76_queue {
dma_addr_t desc_dma;
struct sk_buff *rx_head;
struct page_frag_cache rx_page;
};
struct mt76_mcu_ops {
struct sk_buff *(*mcu_msg_alloc)(const void *data, int len);
int (*mcu_send_msg)(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp);
int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *rp, int len);
int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *rp, int len);
};
struct mt76_queue_ops {
......@@ -148,6 +163,8 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_PS,
};
#define MT76_N_WCIDS 128
struct mt76_wcid {
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
......@@ -215,7 +232,6 @@ enum {
MT76_OFFCHANNEL,
MT76_REMOVED,
MT76_READING_STATS,
MT76_MORE_STATS,
};
struct mt76_hw_cap {
......@@ -245,6 +261,8 @@ struct mt76_driver_ops {
void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta,
bool ps);
s8 (*get_max_txpwr_adj)(struct mt76_dev *dev,
const struct ieee80211_tx_rate *rate);
};
struct mt76_channel_state {
......@@ -321,6 +339,18 @@ struct mt76_usb {
} mcu;
};
struct mt76_mmio {
struct mt76e_mcu {
struct mutex mutex;
wait_queue_head_t wait;
struct sk_buff_head res_q;
u32 msg_seq;
} mcu;
void __iomem *regs;
};
struct mt76_dev {
struct ieee80211_hw *hw;
struct cfg80211_chan_def chandef;
......@@ -333,7 +363,7 @@ struct mt76_dev {
const struct mt76_bus_ops *bus;
const struct mt76_driver_ops *drv;
void __iomem *regs;
const struct mt76_mcu_ops *mcu_ops;
struct device *dev;
struct net_device napi_dev;
......@@ -348,6 +378,11 @@ struct mt76_dev {
wait_queue_head_t tx_wait;
unsigned long wcid_mask[MT76_N_WCIDS / BITS_PER_LONG];
struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
u8 macaddr[ETH_ALEN];
u32 rev;
unsigned long state;
......@@ -369,7 +404,10 @@ struct mt76_dev {
u32 rxfilter;
struct mt76_usb usb;
union {
struct mt76_mmio mmio;
struct mt76_usb usb;
};
};
enum mt76_phy_type {
......@@ -420,10 +458,18 @@ struct mt76_rx_status {
#define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__)
#define __mt76_wr_copy(dev, ...) (dev)->bus->copy((dev), __VA_ARGS__)
#define __mt76_set(dev, offset, val) __mt76_rmw(dev, offset, 0, val)
#define __mt76_clear(dev, offset, val) __mt76_rmw(dev, offset, val, 0)
#define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__)
#define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__)
#define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__)
#define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__)
#define mt76_mcu_msg_alloc(dev, ...) (dev)->mt76.mcu_ops->mcu_msg_alloc(__VA_ARGS__)
#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__)
#define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val)
#define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0)
......@@ -509,13 +555,7 @@ static inline int mt76_decr(int val, int size)
return (val - 1) & (size - 1);
}
/* Hardware uses mirrored order of queues with Q3
* having the highest priority
*/
static inline u8 q2hwq(u8 q)
{
return q ^ 0x3;
}
u8 mt76_ac_to_hwq(u8 ac);
static inline struct ieee80211_txq *
mtxq_to_txq(struct mt76_txq *mtxq)
......@@ -567,6 +607,8 @@ void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tid);
void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key);
struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb);
/* internal */
void mt76_tx_free(struct mt76_dev *dev);
struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
......@@ -623,17 +665,8 @@ int mt76u_alloc_queues(struct mt76_dev *dev);
void mt76u_stop_queues(struct mt76_dev *dev);
void mt76u_stop_stat_wk(struct mt76_dev *dev);
void mt76u_queues_deinit(struct mt76_dev *dev);
int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags);
int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
int data_len, u32 max_payload, u32 offset);
void mt76u_mcu_complete_urb(struct urb *urb);
struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len);
int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp);
int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp);
void mt76u_mcu_fw_reset(struct mt76_dev *dev);
int mt76u_mcu_init_rx(struct mt76_dev *dev);
void mt76u_mcu_deinit(struct mt76_dev *dev);
......
obj-$(CONFIG_MT76x0U) += mt76x0.o
obj-$(CONFIG_MT76x0U) += mt76x0u.o
obj-$(CONFIG_MT76x0E) += mt76x0e.o
obj-$(CONFIG_MT76x0_COMMON) += mt76x0-common.o
mt76x0-common-y := \
init.o main.o trace.o eeprom.o phy.o \
mac.o debugfs.o tx.o
mt76x0u-y := usb.o
mt76x0e-y := pci.o
mt76x0-objs = \
usb.o init.o main.o mcu.o trace.o dma.o eeprom.o phy.o \
mac.o util.o debugfs.o tx.o
# ccflags-y := -DDEBUG
CFLAGS_trace.o := -I$(src)
/*
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "mt76x0.h"
#include "dma.h"
#include "usb.h"
#include "trace.h"
static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev,
struct mt76x0_dma_buf_rx *e, gfp_t gfp);
static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len)
{
const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data;
unsigned int hdrlen;
if (unlikely(len < 10))
return 0;
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (unlikely(hdrlen > len))
return 0;
return hdrlen;
}
static struct sk_buff *
mt76x0_rx_skb_from_seg(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi,
void *data, u32 seg_len, u32 truesize, struct page *p)
{
struct sk_buff *skb;
u32 true_len, hdr_len = 0, copy, frag;
skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC);
if (!skb)
return NULL;
true_len = mt76x0_mac_process_rx(dev, skb, data, rxwi);
if (!true_len || true_len > seg_len)
goto bad_frame;
hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len);
if (!hdr_len)
goto bad_frame;
if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) {
memcpy(skb_put(skb, hdr_len), data, hdr_len);
data += hdr_len + 2;
true_len -= hdr_len;
hdr_len = 0;
}
/* If not doing paged RX allocated skb will always have enough space */
copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8;
frag = true_len - copy;
memcpy(skb_put(skb, copy), data, copy);
data += copy;
if (frag) {
skb_add_rx_frag(skb, 0, p, data - page_address(p),
frag, truesize);
get_page(p);
}
return skb;
bad_frame:
dev_err_ratelimited(dev->mt76.dev, "Error: incorrect frame len:%u hdr:%u\n",
true_len, hdr_len);
dev_kfree_skb(skb);
return NULL;
}
static void mt76x0_rx_process_seg(struct mt76x0_dev *dev, u8 *data,
u32 seg_len, struct page *p)
{
struct sk_buff *skb;
struct mt76x0_rxwi *rxwi;
u32 fce_info, truesize = seg_len;
/* DMA_INFO field at the beginning of the segment contains only some of
* the information, we need to read the FCE descriptor from the end.
*/
fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN);
seg_len -= MT_FCE_INFO_LEN;
data += MT_DMA_HDR_LEN;
seg_len -= MT_DMA_HDR_LEN;
rxwi = (struct mt76x0_rxwi *) data;
data += sizeof(struct mt76x0_rxwi);
seg_len -= sizeof(struct mt76x0_rxwi);
if (unlikely(FIELD_GET(MT_RXD_INFO_TYPE, fce_info)))
dev_err_once(dev->mt76.dev, "Error: RX path seen a non-pkt urb\n");
trace_mt76x0_rx(&dev->mt76, rxwi, fce_info);
skb = mt76x0_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p);
if (!skb)
return;
spin_lock(&dev->mac_lock);
ieee80211_rx(dev->mt76.hw, skb);
spin_unlock(&dev->mac_lock);
}
static u16 mt76x0_rx_next_seg_len(u8 *data, u32 data_len)
{
u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN +
sizeof(struct mt76x0_rxwi) + MT_FCE_INFO_LEN;
u16 dma_len = get_unaligned_le16(data);
if (data_len < min_seg_len ||
WARN_ON(!dma_len) ||
WARN_ON(dma_len + MT_DMA_HDRS > data_len) ||
WARN_ON(dma_len & 0x3))
return 0;
return MT_DMA_HDRS + dma_len;
}
static void
mt76x0_rx_process_entry(struct mt76x0_dev *dev, struct mt76x0_dma_buf_rx *e)
{
u32 seg_len, data_len = e->urb->actual_length;
u8 *data = page_address(e->p);
struct page *new_p = NULL;
int cnt = 0;
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
return;
/* Copy if there is very little data in the buffer. */
if (data_len > 512)
new_p = dev_alloc_pages(MT_RX_ORDER);
while ((seg_len = mt76x0_rx_next_seg_len(data, data_len))) {
mt76x0_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL);
data_len -= seg_len;
data += seg_len;
cnt++;
}
if (cnt > 1)
trace_mt76x0_rx_dma_aggr(&dev->mt76, cnt, !!new_p);
if (new_p) {
/* we have one extra ref from the allocator */
__free_pages(e->p, MT_RX_ORDER);
e->p = new_p;
}
}
static struct mt76x0_dma_buf_rx *
mt76x0_rx_get_pending_entry(struct mt76x0_dev *dev)
{
struct mt76x0_rx_queue *q = &dev->rx_q;
struct mt76x0_dma_buf_rx *buf = NULL;
unsigned long flags;
spin_lock_irqsave(&dev->rx_lock, flags);
if (!q->pending)
goto out;
buf = &q->e[q->start];
q->pending--;
q->start = (q->start + 1) % q->entries;
out:
spin_unlock_irqrestore(&dev->rx_lock, flags);
return buf;
}
static void mt76x0_complete_rx(struct urb *urb)
{
struct mt76x0_dev *dev = urb->context;
struct mt76x0_rx_queue *q = &dev->rx_q;
unsigned long flags;
spin_lock_irqsave(&dev->rx_lock, flags);
if (mt76x0_urb_has_error(urb))
dev_err(dev->mt76.dev, "Error: RX urb failed:%d\n", urb->status);
if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
goto out;
q->end = (q->end + 1) % q->entries;
q->pending++;
tasklet_schedule(&dev->rx_tasklet);
out:
spin_unlock_irqrestore(&dev->rx_lock, flags);
}
static void mt76x0_rx_tasklet(unsigned long data)
{
struct mt76x0_dev *dev = (struct mt76x0_dev *) data;
struct mt76x0_dma_buf_rx *e;
while ((e = mt76x0_rx_get_pending_entry(dev))) {
if (e->urb->status)
continue;
mt76x0_rx_process_entry(dev, e);
mt76x0_submit_rx_buf(dev, e, GFP_ATOMIC);
}
}
static void mt76x0_complete_tx(struct urb *urb)
{
struct mt76x0_tx_queue *q = urb->context;
struct mt76x0_dev *dev = q->dev;
struct sk_buff *skb;
unsigned long flags;
spin_lock_irqsave(&dev->tx_lock, flags);
if (mt76x0_urb_has_error(urb))
dev_err(dev->mt76.dev, "Error: TX urb failed:%d\n", urb->status);
if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
goto out;
skb = q->e[q->start].skb;
trace_mt76x0_tx_dma_done(&dev->mt76, skb);
__skb_queue_tail(&dev->tx_skb_done, skb);
tasklet_schedule(&dev->tx_tasklet);
if (q->used == q->entries - q->entries / 8)
ieee80211_wake_queue(dev->mt76.hw, skb_get_queue_mapping(skb));
q->start = (q->start + 1) % q->entries;
q->used--;
out:
spin_unlock_irqrestore(&dev->tx_lock, flags);
}
static void mt76x0_tx_tasklet(unsigned long data)
{
struct mt76x0_dev *dev = (struct mt76x0_dev *) data;
struct sk_buff_head skbs;
unsigned long flags;
__skb_queue_head_init(&skbs);
spin_lock_irqsave(&dev->tx_lock, flags);
set_bit(MT76_MORE_STATS, &dev->mt76.state);
if (!test_and_set_bit(MT76_READING_STATS, &dev->mt76.state))
queue_delayed_work(dev->stat_wq, &dev->stat_work,
msecs_to_jiffies(10));
skb_queue_splice_init(&dev->tx_skb_done, &skbs);
spin_unlock_irqrestore(&dev->tx_lock, flags);
while (!skb_queue_empty(&skbs)) {
struct sk_buff *skb = __skb_dequeue(&skbs);
mt76x0_tx_status(dev, skb);
}
}
static int mt76x0_dma_submit_tx(struct mt76x0_dev *dev,
struct sk_buff *skb, u8 ep)
{
struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
struct mt76_usb *usb = &dev->mt76.usb;
unsigned snd_pipe = usb_sndbulkpipe(usb_dev, usb->out_ep[ep]);
struct mt76x0_dma_buf_tx *e;
struct mt76x0_tx_queue *q = &dev->tx_q[ep];
unsigned long flags;
int ret;
spin_lock_irqsave(&dev->tx_lock, flags);
if (WARN_ON_ONCE(q->entries <= q->used)) {
ret = -ENOSPC;
goto out;
}
e = &q->e[q->end];
e->skb = skb;
usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len,
mt76x0_complete_tx, q);
ret = usb_submit_urb(e->urb, GFP_ATOMIC);
if (ret) {
/* Special-handle ENODEV from TX urb submission because it will
* often be the first ENODEV we see after device is removed.
*/
if (ret == -ENODEV)
set_bit(MT76_REMOVED, &dev->mt76.state);
else
dev_err(dev->mt76.dev, "Error: TX urb submit failed:%d\n",
ret);
goto out;
}
q->end = (q->end + 1) % q->entries;
q->used++;
if (q->used >= q->entries)
ieee80211_stop_queue(dev->mt76.hw, skb_get_queue_mapping(skb));
out:
spin_unlock_irqrestore(&dev->tx_lock, flags);
return ret;
}
/* Map USB endpoint number to Q id in the DMA engine */
static enum mt76_qsel ep2dmaq(u8 ep)
{
if (ep == 5)
return MT_QSEL_MGMT;
return MT_QSEL_EDCA;
}
int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb,
struct mt76_wcid *wcid, int hw_q)
{
u8 ep = q2ep(hw_q);
u32 dma_flags;
int ret;
dma_flags = MT_TXD_PKT_INFO_80211;
if (wcid->hw_key_idx == 0xff)
dma_flags |= MT_TXD_PKT_INFO_WIV;
ret = mt76x0_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags);
if (ret)
return ret;
ret = mt76x0_dma_submit_tx(dev, skb, ep);
if (ret) {
ieee80211_free_txskb(dev->mt76.hw, skb);
return ret;
}
return 0;
}
static void mt76x0_kill_rx(struct mt76x0_dev *dev)
{
int i;
unsigned long flags;
spin_lock_irqsave(&dev->rx_lock, flags);
for (i = 0; i < dev->rx_q.entries; i++) {
int next = dev->rx_q.end;
spin_unlock_irqrestore(&dev->rx_lock, flags);
usb_poison_urb(dev->rx_q.e[next].urb);
spin_lock_irqsave(&dev->rx_lock, flags);
}
spin_unlock_irqrestore(&dev->rx_lock, flags);
}
static int mt76x0_submit_rx_buf(struct mt76x0_dev *dev,
struct mt76x0_dma_buf_rx *e, gfp_t gfp)
{
struct usb_device *usb_dev = mt76x0_to_usb_dev(dev);
struct mt76_usb *usb = &dev->mt76.usb;
u8 *buf = page_address(e->p);
unsigned pipe;
int ret;
pipe = usb_rcvbulkpipe(usb_dev, usb->in_ep[MT_EP_IN_PKT_RX]);
usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE,
mt76x0_complete_rx, dev);
trace_mt76x0_submit_urb(&dev->mt76, e->urb);
ret = usb_submit_urb(e->urb, gfp);
if (ret)
dev_err(dev->mt76.dev, "Error: submit RX URB failed:%d\n", ret);
return ret;
}
static int mt76x0_submit_rx(struct mt76x0_dev *dev)
{
int i, ret;
for (i = 0; i < dev->rx_q.entries; i++) {
ret = mt76x0_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL);
if (ret)
return ret;
}
return 0;
}
static void mt76x0_free_rx(struct mt76x0_dev *dev)
{
int i;
for (i = 0; i < dev->rx_q.entries; i++) {
__free_pages(dev->rx_q.e[i].p, MT_RX_ORDER);
usb_free_urb(dev->rx_q.e[i].urb);
}
}
static int mt76x0_alloc_rx(struct mt76x0_dev *dev)
{
int i;
memset(&dev->rx_q, 0, sizeof(dev->rx_q));
dev->rx_q.dev = dev;
dev->rx_q.entries = N_RX_ENTRIES;
for (i = 0; i < N_RX_ENTRIES; i++) {
dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER);
if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p)
return -ENOMEM;
}
return 0;
}
static void mt76x0_free_tx_queue(struct mt76x0_tx_queue *q)
{
int i;
WARN_ON(q->used);
for (i = 0; i < q->entries; i++) {
usb_poison_urb(q->e[i].urb);
usb_free_urb(q->e[i].urb);
}
}
static void mt76x0_free_tx(struct mt76x0_dev *dev)
{
int i;
for (i = 0; i < __MT_EP_OUT_MAX; i++)
mt76x0_free_tx_queue(&dev->tx_q[i]);
}
static int mt76x0_alloc_tx_queue(struct mt76x0_dev *dev,
struct mt76x0_tx_queue *q)
{
int i;
q->dev = dev;
q->entries = N_TX_ENTRIES;
for (i = 0; i < N_TX_ENTRIES; i++) {
q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (!q->e[i].urb)
return -ENOMEM;
}
return 0;
}
static int mt76x0_alloc_tx(struct mt76x0_dev *dev)
{
int i;
dev->tx_q = devm_kcalloc(dev->mt76.dev, __MT_EP_OUT_MAX,
sizeof(*dev->tx_q), GFP_KERNEL);
for (i = 0; i < __MT_EP_OUT_MAX; i++)
if (mt76x0_alloc_tx_queue(dev, &dev->tx_q[i]))
return -ENOMEM;
return 0;
}
int mt76x0_dma_init(struct mt76x0_dev *dev)
{
int ret = -ENOMEM;
tasklet_init(&dev->tx_tasklet, mt76x0_tx_tasklet, (unsigned long) dev);
tasklet_init(&dev->rx_tasklet, mt76x0_rx_tasklet, (unsigned long) dev);
ret = mt76x0_alloc_tx(dev);
if (ret)
goto err;
ret = mt76x0_alloc_rx(dev);
if (ret)
goto err;
ret = mt76x0_submit_rx(dev);
if (ret)
goto err;
return 0;
err:
mt76x0_dma_cleanup(dev);
return ret;
}
void mt76x0_dma_cleanup(struct mt76x0_dev *dev)
{
mt76x0_kill_rx(dev);
tasklet_kill(&dev->rx_tasklet);
mt76x0_free_rx(dev);
mt76x0_free_tx(dev);
tasklet_kill(&dev->tx_tasklet);
}
......@@ -123,18 +123,19 @@ mt76x0_set_chip_cap(struct mt76x0_dev *dev, u8 *eeprom)
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, nic_conf0)) {
case BOARD_TYPE_5GHZ:
dev->ee->has_5ghz = true;
dev->mt76.cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
dev->ee->has_2ghz = true;
dev->mt76.cap.has_2ghz = true;
break;
default:
dev->ee->has_2ghz = true;
dev->ee->has_5ghz = true;
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
break;
}
dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n", dev->ee->has_2ghz, dev->ee->has_5ghz);
dev_dbg(dev->mt76.dev, "Has 2GHZ %d 5GHZ %d\n",
dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
if (!field_valid(nic_conf1 & 0xff))
nic_conf1 &= 0xff00;
......@@ -159,18 +160,19 @@ static int
mt76x0_set_macaddr(struct mt76x0_dev *dev, const u8 *eeprom)
{
const void *src = eeprom + MT_EE_MAC_ADDR;
u8 *dst = dev->mt76.macaddr;
ether_addr_copy(dev->macaddr, src);
ether_addr_copy(dev->mt76.macaddr, src);
if (!is_valid_ether_addr(dev->macaddr)) {
eth_random_addr(dev->macaddr);
if (!is_valid_ether_addr(dst)) {
eth_random_addr(dst);
dev_info(dev->mt76.dev,
"Invalid MAC address, using random address %pM\n",
dev->macaddr);
dst);
}
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dst));
mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dst + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
return 0;
......@@ -443,3 +445,5 @@ mt76x0_eeprom_init(struct mt76x0_dev *dev)
kfree(eeprom);
return ret;
}
MODULE_LICENSE("Dual BSD/GPL");
......@@ -112,9 +112,6 @@ struct mt76x0_eeprom_params {
u8 tx_pwr_per_chan[58];
struct reg_channel_bounds reg;
bool has_2ghz;
bool has_5ghz;
};
int mt76x0_eeprom_init(struct mt76x0_dev *dev);
......
......@@ -18,10 +18,28 @@
#include "eeprom.h"
#include "trace.h"
#include "mcu.h"
#include "usb.h"
#include "../mt76x02_util.h"
#include "initvals.h"
static void mt76x0_vht_cap_mask(struct ieee80211_supported_band *sband)
{
struct ieee80211_sta_vht_cap *vht_cap = &sband->vht_cap;
u16 mcs_map = 0;
int i;
vht_cap->cap &= ~IEEE80211_VHT_CAP_RXLDPC;
for (i = 0; i < 8; i++) {
if (!i)
mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_7 << (i * 2));
else
mcs_map |=
(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
}
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
}
static void
mt76x0_set_wlan_state(struct mt76x0_dev *dev, u32 val, bool enable)
{
......@@ -92,6 +110,7 @@ void mt76x0_chip_onoff(struct mt76x0_dev *dev, bool enable, bool reset)
mutex_unlock(&dev->hw_atomic_mutex);
}
EXPORT_SYMBOL_GPL(mt76x0_chip_onoff);
static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
{
......@@ -109,17 +128,17 @@ static void mt76x0_reset_csr_bbp(struct mt76x0_dev *dev)
static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
{
struct mt76_usb *usb = &dev->mt76.usb;
u32 val;
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) |
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) |
MT_USB_DMA_CFG_RX_BULK_EN |
val |= MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN;
if (usb->in_max_packet == 512)
val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN;
/* disable AGGR_BULK_RX in order to receive one
* frame in each rx urb and avoid copies
*/
val &= ~MT_USB_DMA_CFG_RX_BULK_AGG_EN;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val = mt76_rr(dev, MT_COM_REG0);
......@@ -134,8 +153,9 @@ static void mt76x0_init_usb_dma(struct mt76x0_dev *dev)
mt76_wr(dev, MT_USB_DMA_CFG, val);
}
#define RANDOM_WRITE(dev, tab) \
mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, tab, ARRAY_SIZE(tab));
#define RANDOM_WRITE(dev, tab) \
mt76_wr_rp(dev, MT_MCU_MEMMAP_WLAN, \
tab, ARRAY_SIZE(tab))
static int mt76x0_init_bbp(struct mt76x0_dev *dev)
{
......@@ -228,49 +248,44 @@ static void mt76x0_init_mac_registers(struct mt76x0_dev *dev)
static int mt76x0_init_wcid_mem(struct mt76x0_dev *dev)
{
u32 *vals;
int i, ret;
int i;
vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
if (!vals)
return -ENOMEM;
for (i = 0; i < N_WCIDS; i++) {
for (i = 0; i < MT76_N_WCIDS; i++) {
vals[i * 2] = 0xffffffff;
vals[i * 2 + 1] = 0x00ffffff;
}
ret = mt76x0_burst_write_regs(dev, MT_WCID_ADDR_BASE,
vals, N_WCIDS * 2);
mt76_wr_copy(dev, MT_WCID_ADDR_BASE, vals, MT76_N_WCIDS * 2);
kfree(vals);
return ret;
return 0;
}
static int mt76x0_init_key_mem(struct mt76x0_dev *dev)
static void mt76x0_init_key_mem(struct mt76x0_dev *dev)
{
u32 vals[4] = {};
return mt76x0_burst_write_regs(dev, MT_SKEY_MODE_BASE_0,
vals, ARRAY_SIZE(vals));
mt76_wr_copy(dev, MT_SKEY_MODE_BASE_0, vals, ARRAY_SIZE(vals));
}
static int mt76x0_init_wcid_attr_mem(struct mt76x0_dev *dev)
{
u32 *vals;
int i, ret;
int i;
vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL);
vals = kmalloc(sizeof(*vals) * MT76_N_WCIDS * 2, GFP_KERNEL);
if (!vals)
return -ENOMEM;
for (i = 0; i < N_WCIDS * 2; i++)
for (i = 0; i < MT76_N_WCIDS * 2; i++)
vals[i] = 1;
ret = mt76x0_burst_write_regs(dev, MT_WCID_ATTR_BASE,
vals, N_WCIDS * 2);
mt76_wr_copy(dev, MT_WCID_ATTR_BASE, vals, MT76_N_WCIDS * 2);
kfree(vals);
return ret;
return 0;
}
static void mt76x0_reset_counters(struct mt76x0_dev *dev)
......@@ -360,15 +375,12 @@ static void mt76x0_mac_stop_hw(struct mt76x0_dev *dev)
void mt76x0_mac_stop(struct mt76x0_dev *dev)
{
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
mt76u_stop_stat_wk(&dev->mt76);
mt76x0_mac_stop_hw(dev);
flush_delayed_work(&dev->stat_work);
cancel_delayed_work_sync(&dev->stat_work);
}
static void mt76x0_stop_hardware(struct mt76x0_dev *dev)
{
mt76x0_chip_onoff(dev, false, false);
}
EXPORT_SYMBOL_GPL(mt76x0_mac_stop);
int mt76x0_init_hardware(struct mt76x0_dev *dev)
{
......@@ -383,29 +395,14 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
dev->beacon_offsets = beacon_offsets;
mt76x0_chip_onoff(dev, true, true);
if (!mt76x02_wait_for_mac(&dev->mt76)) {
ret = -ETIMEDOUT;
goto err;
}
ret = mt76x0_mcu_init(dev);
if (ret)
goto err;
if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) {
ret = -EIO;
goto err;
}
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100))
return -EIO;
/* Wait for ASIC ready after FW load. */
if (!mt76x02_wait_for_mac(&dev->mt76)) {
ret = -ETIMEDOUT;
goto err;
}
if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
mt76x0_reset_csr_bbp(dev);
mt76x0_init_usb_dma(dev);
......@@ -413,34 +410,29 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
mt76_wr(dev, MT_HEADER_TRANS_CTRL_REG, 0x0);
mt76_wr(dev, MT_TSO_CTRL, 0x0);
ret = mt76x0_mcu_cmd_init(dev);
if (ret)
goto err;
ret = mt76x0_dma_init(dev);
ret = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, false);
if (ret)
goto err_mcu;
return ret;
mt76x0_init_mac_registers(dev);
if (!mt76_poll_msec(dev, MT_MAC_STATUS,
MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000)) {
ret = -EIO;
goto err_rx;
}
MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 1000))
return -EIO;
ret = mt76x0_init_bbp(dev);
if (ret)
goto err_rx;
return ret;
ret = mt76x0_init_wcid_mem(dev);
if (ret)
goto err_rx;
ret = mt76x0_init_key_mem(dev);
if (ret)
goto err_rx;
return ret;
mt76x0_init_key_mem(dev);
ret = mt76x0_init_wcid_attr_mem(dev);
if (ret)
goto err_rx;
return ret;
mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
MT_BEACON_TIME_CFG_SYNC_MODE |
......@@ -457,268 +449,100 @@ int mt76x0_init_hardware(struct mt76x0_dev *dev)
ret = mt76x0_eeprom_init(dev);
if (ret)
goto err_rx;
return ret;
mt76x0_phy_init(dev);
return 0;
err_rx:
mt76x0_dma_cleanup(dev);
err_mcu:
mt76u_mcu_deinit(&dev->mt76);
err:
mt76x0_chip_onoff(dev, false, false);
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(mt76x0_init_hardware);
void mt76x0_cleanup(struct mt76x0_dev *dev)
{
if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
return;
mt76x0_stop_hardware(dev);
mt76x0_dma_cleanup(dev);
clear_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
mt76x0_chip_onoff(dev, false, false);
mt76u_queues_deinit(&dev->mt76);
mt76u_mcu_deinit(&dev->mt76);
}
EXPORT_SYMBOL_GPL(mt76x0_cleanup);
struct mt76x0_dev *mt76x0_alloc_device(struct device *pdev)
struct mt76x0_dev *
mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops)
{
struct ieee80211_hw *hw;
struct mt76x0_dev *dev;
struct mt76_dev *mdev;
hw = ieee80211_alloc_hw(sizeof(*dev), &mt76x0_ops);
if (!hw)
mdev = mt76_alloc_device(sizeof(*dev), &mt76x0_ops);
if (!mdev)
return NULL;
dev = hw->priv;
dev->mt76.dev = pdev;
dev->mt76.hw = hw;
mutex_init(&dev->usb_ctrl_mtx);
mdev->dev = pdev;
mdev->drv = drv_ops;
dev = container_of(mdev, struct mt76x0_dev, mt76);
mutex_init(&dev->reg_atomic_mutex);
mutex_init(&dev->hw_atomic_mutex);
mutex_init(&dev->mt76.mutex);
spin_lock_init(&dev->tx_lock);
spin_lock_init(&dev->rx_lock);
spin_lock_init(&dev->mt76.lock);
spin_lock_init(&dev->mac_lock);
spin_lock_init(&dev->con_mon_lock);
atomic_set(&dev->avg_ampdu_len, 1);
skb_queue_head_init(&dev->tx_skb_done);
dev->stat_wq = alloc_workqueue("mt76x0", WQ_UNBOUND, 0);
if (!dev->stat_wq) {
ieee80211_free_hw(hw);
return NULL;
}
return dev;
}
#define CHAN2G(_idx, _freq) { \
.band = NL80211_BAND_2GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 30, \
}
static const struct ieee80211_channel mt76_channels_2ghz[] = {
CHAN2G(1, 2412),
CHAN2G(2, 2417),
CHAN2G(3, 2422),
CHAN2G(4, 2427),
CHAN2G(5, 2432),
CHAN2G(6, 2437),
CHAN2G(7, 2442),
CHAN2G(8, 2447),
CHAN2G(9, 2452),
CHAN2G(10, 2457),
CHAN2G(11, 2462),
CHAN2G(12, 2467),
CHAN2G(13, 2472),
CHAN2G(14, 2484),
};
#define CHAN5G(_idx, _freq) { \
.band = NL80211_BAND_5GHZ, \
.center_freq = (_freq), \
.hw_value = (_idx), \
.max_power = 30, \
}
static const struct ieee80211_channel mt76_channels_5ghz[] = {
CHAN5G(36, 5180),
CHAN5G(40, 5200),
CHAN5G(44, 5220),
CHAN5G(46, 5230),
CHAN5G(48, 5240),
CHAN5G(52, 5260),
CHAN5G(56, 5280),
CHAN5G(60, 5300),
CHAN5G(64, 5320),
CHAN5G(100, 5500),
CHAN5G(104, 5520),
CHAN5G(108, 5540),
CHAN5G(112, 5560),
CHAN5G(116, 5580),
CHAN5G(120, 5600),
CHAN5G(124, 5620),
CHAN5G(128, 5640),
CHAN5G(132, 5660),
CHAN5G(136, 5680),
CHAN5G(140, 5700),
};
#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) | (8 + _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 mt76_rates[] = {
CCK_RATE(0, 10),
CCK_RATE(1, 20),
CCK_RATE(2, 55),
CCK_RATE(3, 110),
OFDM_RATE(0, 60),
OFDM_RATE(1, 90),
OFDM_RATE(2, 120),
OFDM_RATE(3, 180),
OFDM_RATE(4, 240),
OFDM_RATE(5, 360),
OFDM_RATE(6, 480),
OFDM_RATE(7, 540),
};
static int
mt76_init_sband(struct mt76x0_dev *dev, struct ieee80211_supported_band *sband,
const struct ieee80211_channel *chan, int n_chan,
struct ieee80211_rate *rates, int n_rates)
{
struct ieee80211_sta_ht_cap *ht_cap;
void *chanlist;
int size;
size = n_chan * sizeof(*chan);
chanlist = devm_kmemdup(dev->mt76.dev, chan, size, GFP_KERNEL);
if (!chanlist)
return -ENOMEM;
sband->channels = chanlist;
sband->n_channels = n_chan;
sband->bitrates = rates;
sband->n_bitrates = n_rates;
ht_cap = &sband->ht_cap;
ht_cap->ht_supported = true;
ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
(1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
ht_cap->mcs.rx_mask[0] = 0xff;
ht_cap->mcs.rx_mask[4] = 0x1;
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2;
return 0;
}
static int
mt76_init_sband_2g(struct mt76x0_dev *dev)
{
dev->mt76.hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->mt76.sband_2g.sband;
WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num >
ARRAY_SIZE(mt76_channels_2ghz));
return mt76_init_sband(dev, &dev->mt76.sband_2g.sband,
mt76_channels_2ghz, ARRAY_SIZE(mt76_channels_2ghz),
mt76_rates, ARRAY_SIZE(mt76_rates));
}
static int
mt76_init_sband_5g(struct mt76x0_dev *dev)
{
dev->mt76.hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->mt76.sband_5g.sband;
return mt76_init_sband(dev, &dev->mt76.sband_5g.sband,
mt76_channels_5ghz, ARRAY_SIZE(mt76_channels_5ghz),
mt76_rates + 4, ARRAY_SIZE(mt76_rates) - 4);
}
EXPORT_SYMBOL_GPL(mt76x0_alloc_device);
int mt76x0_register_device(struct mt76x0_dev *dev)
{
struct ieee80211_hw *hw = dev->mt76.hw;
struct mt76_dev *mdev = &dev->mt76;
struct ieee80211_hw *hw = mdev->hw;
struct wiphy *wiphy = hw->wiphy;
int ret;
ret = mt76x0_init_hardware(dev);
if (ret)
return ret;
/* Reserve WCID 0 for mcast - thanks to this APs WCID will go to
* entry no. 1 like it does in the vendor driver.
*/
dev->wcid_mask[0] |= 1;
mdev->wcid_mask[0] |= 1;
/* init fake wcid for monitor interfaces */
dev->mon_wcid = devm_kmalloc(dev->mt76.dev, sizeof(*dev->mon_wcid),
GFP_KERNEL);
if (!dev->mon_wcid)
return -ENOMEM;
dev->mon_wcid->idx = 0xff;
dev->mon_wcid->hw_key_idx = -1;
mdev->global_wcid.idx = 0xff;
mdev->global_wcid.hw_key_idx = -1;
SET_IEEE80211_DEV(hw, dev->mt76.dev);
/* init antenna configuration */
mdev->antenna_mask = 1;
hw->queues = 4;
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
hw->max_rates = 1;
hw->max_report_rates = 7;
hw->max_rate_tries = 1;
hw->extra_tx_headroom = sizeof(struct mt76x02_txwi) + 4 + 2;
hw->sta_data_size = sizeof(struct mt76x02_sta);
hw->vif_data_size = sizeof(struct mt76x02_vif);
SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
if (dev->ee->has_2ghz) {
ret = mt76_init_sband_2g(dev);
if (ret)
return ret;
}
if (dev->ee->has_5ghz) {
ret = mt76_init_sband_5g(dev);
if (ret)
return ret;
}
dev->mt76.chandef.chan = &dev->mt76.sband_2g.sband.channels[0];
INIT_DELAYED_WORK(&dev->mac_work, mt76x0_mac_work);
INIT_DELAYED_WORK(&dev->stat_work, mt76x0_tx_stat);
ret = ieee80211_register_hw(hw);
ret = mt76_register_device(mdev, true, mt76x02_rates,
ARRAY_SIZE(mt76x02_rates));
if (ret)
return ret;
/* overwrite unsupported features */
if (mdev->cap.has_5ghz)
mt76x0_vht_cap_mask(&dev->mt76.sband_5g.sband);
/* check hw sg support in order to enable AMSDU */
if (mt76u_check_sg(mdev))
hw->max_tx_fragments = MT_SG_MAX_SIZE;
else
hw->max_tx_fragments = 1;
mt76x0_init_debugfs(dev);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x0_register_device);
......@@ -15,237 +15,9 @@
#include "mt76x0.h"
#include "trace.h"
#include "../mt76x02_util.h"
#include <linux/etherdevice.h>
static void
mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
enum nl80211_band band)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
txrate->idx = 0;
txrate->flags = 0;
txrate->count = 1;
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (band == NL80211_BAND_2GHZ)
idx += 4;
txrate->idx = idx;
return;
case MT_PHY_TYPE_CCK:
if (idx >= 8)
idx -= 8;
txrate->idx = idx;
return;
case MT_PHY_TYPE_HT_GF:
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
/* fall through */
case MT_PHY_TYPE_HT:
txrate->flags |= IEEE80211_TX_RC_MCS;
txrate->idx = idx;
break;
case MT_PHY_TYPE_VHT:
txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
txrate->idx = idx;
break;
default:
WARN_ON(1);
return;
}
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
break;
case MT_PHY_BW_80:
txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
break;
default:
WARN_ON(1);
return;
}
if (rate & MT_RXWI_RATE_SGI)
txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
}
static void
mt76_mac_fill_tx_status(struct mt76x0_dev *dev, struct ieee80211_tx_info *info,
struct mt76x02_tx_status *st, int n_frames)
{
struct ieee80211_tx_rate *rate = info->status.rates;
int cur_idx, last_rate;
int i;
if (!n_frames)
return;
last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
mt76_mac_process_tx_rate(&rate[last_rate], st->rate,
dev->mt76.chandef.chan->band);
if (last_rate < IEEE80211_TX_MAX_RATES - 1)
rate[last_rate + 1].idx = -1;
cur_idx = rate[last_rate].idx + last_rate;
for (i = 0; i <= last_rate; i++) {
rate[i].flags = rate[last_rate].flags;
rate[i].idx = max_t(int, 0, cur_idx - i);
rate[i].count = 1;
}
rate[last_rate - 1].count = st->retry + 1 - last_rate;
info->status.ampdu_len = n_frames;
info->status.ampdu_ack_len = st->success ? n_frames : 0;
if (st->pktid & MT_TXWI_PKTID_PROBE)
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
if (st->aggr)
info->flags |= IEEE80211_TX_CTL_AMPDU |
IEEE80211_TX_STAT_AMPDU;
if (!st->ack_req)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
else if (st->success)
info->flags |= IEEE80211_TX_STAT_ACK;
}
u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val)
{
u16 rateval;
u8 phy, rate_idx;
u8 nss = 1;
u8 bw = 0;
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 4);
phy = MT_PHY_TYPE_VHT;
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
bw = 2;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 3);
phy = MT_PHY_TYPE_HT;
if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
phy = MT_PHY_TYPE_HT_GF;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else {
const struct ieee80211_rate *r;
int band = dev->mt76.chandef.chan->band;
u16 val;
r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
val = r->hw_value_short;
else
val = r->hw_value;
phy = val >> 8;
rate_idx = val & 0xff;
bw = 0;
}
rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rateval |= MT_RXWI_RATE_SGI;
*nss_val = nss;
return cpu_to_le16(rateval);
}
void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate)
{
unsigned long flags;
spin_lock_irqsave(&dev->mt76.lock, flags);
wcid->tx_rate = mt76x0_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
wcid->tx_rate_set = true;
spin_unlock_irqrestore(&dev->mt76.lock, flags);
}
struct mt76x02_tx_status mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev)
{
struct mt76x02_tx_status stat = {};
u32 stat2, stat1;
stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
stat.valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
stat.success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
stat.aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
stat.ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
stat.retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
return stat;
}
void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update)
{
struct ieee80211_tx_info info = {};
struct ieee80211_sta *sta = NULL;
struct mt76_wcid *wcid = NULL;
struct mt76x02_sta *msta = NULL;
rcu_read_lock();
if (stat->wcid < ARRAY_SIZE(dev->wcid))
wcid = rcu_dereference(dev->wcid[stat->wcid]);
if (wcid) {
void *priv;
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
sta = container_of(priv, struct ieee80211_sta, drv_priv);
}
if (msta && stat->aggr) {
u32 stat_val, stat_cache;
stat_val = stat->rate;
stat_val |= ((u32) stat->retry) << 16;
stat_cache = msta->status.rate;
stat_cache |= ((u32) msta->status.retry) << 16;
if (*update == 0 && stat_val == stat_cache &&
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
msta->n_frames++;
goto out;
}
mt76_mac_fill_tx_status(dev, &info, &msta->status,
msta->n_frames);
msta->status = *stat;
msta->n_frames = 1;
*update = 0;
} else {
mt76_mac_fill_tx_status(dev, &info, stat, 1);
*update = 1;
}
spin_lock_bh(&dev->mac_lock);
ieee80211_tx_status_noskb(dev->mt76.hw, sta, &info);
spin_unlock_bh(&dev->mac_lock);
out:
rcu_read_unlock();
}
void mt76x0_mac_set_protection(struct mt76x0_dev *dev, bool legacy_prot,
int ht_mode)
{
......@@ -408,8 +180,8 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev)
int i;
rcu_read_lock();
for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
wcid = rcu_dereference(dev->wcid[i]);
for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
wcid = rcu_dereference(dev->mt76.wcid[i]);
if (!wcid)
continue;
......@@ -425,74 +197,7 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev)
}
static void
mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (idx >= 8)
idx = 0;
if (status->band == NL80211_BAND_2GHZ)
idx += 4;
status->rate_idx = idx;
return;
case MT_PHY_TYPE_CCK:
if (idx >= 8) {
idx -= 8;
status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
}
if (idx >= 4)
idx = 0;
status->rate_idx = idx;
return;
case MT_PHY_TYPE_HT_GF:
status->enc_flags |= RX_ENC_FLAG_HT_GF;
/* fall through */
case MT_PHY_TYPE_HT:
status->encoding = RX_ENC_HT;
status->rate_idx = idx;
break;
case MT_PHY_TYPE_VHT:
status->encoding = RX_ENC_VHT;
status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1;
break;
default:
WARN_ON(1);
return;
}
if (rate & MT_RXWI_RATE_LDPC)
status->enc_flags |= RX_ENC_FLAG_LDPC;
if (rate & MT_RXWI_RATE_SGI)
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
if (rate & MT_RXWI_RATE_STBC)
status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
status->bw = RATE_INFO_BW_40;
break;
case MT_PHY_BW_80:
status->bw = RATE_INFO_BW_80;
break;
default:
WARN_ON(1);
break;
}
}
static void
mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi,
mt76x0_rx_monitor_beacon(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi,
u16 rate, int rssi)
{
dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate);
......@@ -509,13 +214,13 @@ mt76x0_rx_is_our_beacon(struct mt76x0_dev *dev, u8 *data)
}
u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb,
u8 *data, void *rxi)
void *rxi)
{
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct mt76x0_rxwi *rxwi = rxi;
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
struct mt76x02_rxwi *rxwi = rxi;
u32 len, ctl = le32_to_cpu(rxwi->ctl);
u16 rate = le16_to_cpu(rxwi->rate);
int rssi;
int rssi, pad_len = 0;
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
if (WARN_ON(len < 10))
......@@ -526,18 +231,24 @@ u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb,
status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
}
if (rxwi->rxinfo & MT_RXINFO_L2PAD)
pad_len += 2;
mt76x02_remove_hdr_pad(skb, pad_len);
pskb_trim(skb, len);
status->chains = BIT(0);
rssi = mt76x0_phy_get_rssi(dev, rxwi);
status->chain_signal[0] = status->signal = rssi;
status->freq = dev->mt76.chandef.chan->center_freq;
status->band = dev->mt76.chandef.chan->band;
mt76_mac_process_rate(status, rate);
mt76x02_mac_process_rate(status, rate);
spin_lock_bh(&dev->con_mon_lock);
if (mt76x0_rx_is_our_beacon(dev, data)) {
if (mt76x0_rx_is_our_beacon(dev, skb->data)) {
mt76x0_rx_monitor_beacon(dev, rxwi, rate, rssi);
} else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) {
} else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST)) {
if (dev->avg_rssi == 0)
dev->avg_rssi = rssi;
else
......
......@@ -15,136 +15,6 @@
#ifndef __MT76_MAC_H
#define __MT76_MAC_H
/* Note: values in original "RSSI" and "SNR" fields are not actually what they
* are called for MT76X0U, names used by this driver are educated guesses
* (see vendor mac/ral_omac.c).
*/
struct mt76x0_rxwi {
__le32 rxinfo;
__le32 ctl;
__le16 tid_sn;
__le16 rate;
s8 rssi[4];
__le32 bbp_rxinfo[4];
} __packed __aligned(4);
#define MT_RXINFO_BA BIT(0)
#define MT_RXINFO_DATA BIT(1)
#define MT_RXINFO_NULL BIT(2)
#define MT_RXINFO_FRAG BIT(3)
#define MT_RXINFO_U2M BIT(4)
#define MT_RXINFO_MULTICAST BIT(5)
#define MT_RXINFO_BROADCAST BIT(6)
#define MT_RXINFO_MYBSS BIT(7)
#define MT_RXINFO_CRCERR BIT(8)
#define MT_RXINFO_ICVERR BIT(9)
#define MT_RXINFO_MICERR BIT(10)
#define MT_RXINFO_AMSDU BIT(11)
#define MT_RXINFO_HTC BIT(12)
#define MT_RXINFO_RSSI BIT(13)
#define MT_RXINFO_L2PAD BIT(14)
#define MT_RXINFO_AMPDU BIT(15)
#define MT_RXINFO_DECRYPT BIT(16)
#define MT_RXINFO_BSSIDX3 BIT(17)
#define MT_RXINFO_WAPI_KEY BIT(18)
#define MT_RXINFO_PN_LEN GENMASK(21, 19)
#define MT_RXINFO_SW_PKT_80211 BIT(22)
#define MT_RXINFO_TCP_SUM_BYPASS BIT(28)
#define MT_RXINFO_IP_SUM_BYPASS BIT(29)
#define MT_RXINFO_TCP_SUM_ERR BIT(30)
#define MT_RXINFO_IP_SUM_ERR BIT(31)
#define MT_RXWI_CTL_WCID GENMASK(7, 0)
#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
#define MT_RXWI_CTL_UDF GENMASK(15, 13)
#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16)
#define MT_RXWI_CTL_TID GENMASK(31, 28)
#define MT_RXWI_FRAG GENMASK(3, 0)
#define MT_RXWI_SN GENMASK(15, 4)
#define MT_RXWI_RATE_INDEX GENMASK(5, 0)
#define MT_RXWI_RATE_LDPC BIT(6)
#define MT_RXWI_RATE_BW GENMASK(8, 7)
#define MT_RXWI_RATE_SGI BIT(9)
#define MT_RXWI_RATE_STBC BIT(10)
#define MT_RXWI_RATE_LDPC_ETXBF BIT(11)
#define MT_RXWI_RATE_SND BIT(12)
#define MT_RXWI_RATE_PHY GENMASK(15, 13)
#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0)
#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4)
#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0)
#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6)
#define MT_RXWI_ANT_AUX_LNA BIT(7)
#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0)
enum mt76_phy_bandwidth {
MT_PHY_BW_20,
MT_PHY_BW_40,
MT_PHY_BW_80,
};
struct mt76_txwi {
__le16 flags;
__le16 rate_ctl;
u8 ack_ctl;
u8 wcid;
__le16 len_ctl;
__le32 iv;
__le32 eiv;
u8 aid;
u8 txstream;
u8 ctl2;
u8 pktid;
} __packed __aligned(4);
#define MT_TXWI_FLAGS_FRAG BIT(0)
#define MT_TXWI_FLAGS_MMPS BIT(1)
#define MT_TXWI_FLAGS_CFACK BIT(2)
#define MT_TXWI_FLAGS_TS BIT(3)
#define MT_TXWI_FLAGS_AMPDU BIT(4)
#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10)
#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13)
#define MT_TXWI_FLAGS_TX_RPT BIT(14)
#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
#define MT_TXWI_RATE_MCS GENMASK(6, 0)
#define MT_TXWI_RATE_BW BIT(7)
#define MT_TXWI_RATE_SGI BIT(8)
#define MT_TXWI_RATE_STBC GENMASK(10, 9)
#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14)
#define MT_TXWI_ACK_CTL_REQ BIT(0)
#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0)
#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0)
#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4)
#define MT_TXWI_CTL_PIFS_REV BIT(6)
#define MT_TXWI_PKTID_PROBE BIT(7)
u32 mt76x0_mac_process_rx(struct mt76x0_dev *dev, struct sk_buff *skb,
u8 *data, void *rxi);
void mt76x0_mac_wcid_set_rate(struct mt76x0_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate);
u16 mt76x0_mac_tx_rate_val(struct mt76x0_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val);
struct mt76x02_tx_status
mt76x0_mac_fetch_tx_status(struct mt76x0_dev *dev);
void mt76x0_send_tx_status(struct mt76x0_dev *dev, struct mt76x02_tx_status *stat, u8 *update);
void *rxi);
#endif
......@@ -33,6 +33,9 @@ static int mt76x0_start(struct ieee80211_hw *hw)
MT_CALIBRATE_INTERVAL);
ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work,
MT_CALIBRATE_INTERVAL);
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
......@@ -44,46 +47,12 @@ static void mt76x0_stop(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
mt76x0_mac_stop(dev);
mutex_unlock(&dev->mt76.mutex);
}
static int mt76x0_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
unsigned int idx;
idx = ffs(~dev->vif_mask);
if (!idx || idx > 8)
return -ENOSPC;
idx--;
dev->vif_mask |= BIT(idx);
mvif->idx = idx;
mvif->group_wcid.idx = GROUP_WCID(idx);
mvif->group_wcid.hw_key_idx = -1;
mt76x02_txq_init(&dev->mt76, vif->txq);
return 0;
}
static void mt76x0_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
dev->vif_mask &= ~BIT(mvif->idx);
mt76_txq_remove(&dev->mt76, vif->txq);
}
static int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
{
struct mt76x0_dev *dev = hw->priv;
......@@ -102,6 +71,13 @@ static int mt76x0_config(struct ieee80211_hw *hw, u32 changed)
return ret;
}
static void
mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr)
{
mt76_wr(dev, offset, get_unaligned_le32(addr));
mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
}
static void
mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
......@@ -155,69 +131,6 @@ mt76x0_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_unlock(&dev->mt76.mutex);
}
static int
mt76x0_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
int ret = 0;
int idx = 0;
int i;
mutex_lock(&dev->mt76.mutex);
idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid));
if (idx < 0) {
ret = -ENOSPC;
goto out;
}
msta->wcid.idx = idx;
msta->wcid.hw_key_idx = -1;
mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr);
mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false);
mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76x02_txq_init(&dev->mt76, sta->txq[i]);
mt76x0_mac_set_ampdu_factor(dev);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static int
mt76x0_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
int idx = msta->wcid.idx;
int i;
mutex_lock(&dev->mt76.mutex);
rcu_assign_pointer(dev->wcid[idx], NULL);
mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true);
mt76_wcid_free(dev->wcid_mask, idx);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76_txq_remove(&dev->mt76, sta->txq[i]);
mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL);
mt76x0_mac_set_ampdu_factor(dev);
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static void
mt76x0_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
{
}
static void
mt76x0_sw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
......@@ -243,41 +156,6 @@ mt76x0_sw_scan_complete(struct ieee80211_hw *hw,
MT_CALIBRATE_INTERVAL);
}
static int
mt76x0_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
struct mt76x02_sta *msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL;
struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;
int idx = key->keyidx;
int ret;
if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = idx;
} else {
if (idx == wcid->hw_key_idx)
wcid->hw_key_idx = -1;
key = NULL;
}
if (!msta) {
if (key || wcid->hw_key_idx == idx) {
ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key);
if (ret)
return ret;
}
return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key);
}
return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key);
}
static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
struct mt76x0_dev *dev = hw->priv;
......@@ -287,89 +165,23 @@ static int mt76x0_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return 0;
}
static int
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
struct mt76x0_dev *dev = hw->priv;
struct ieee80211_sta *sta = params->sta;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
enum ieee80211_ampdu_mlme_action action = params->action;
struct ieee80211_txq *txq = sta->txq[params->tid];
u16 tid = params->tid;
u16 *ssn = &params->ssn;
struct mt76_txq *mtxq;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = *ssn << 4;
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
return 0;
}
static void
mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x0_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct ieee80211_sta_rates *rates;
struct ieee80211_tx_rate rate = {};
rcu_read_lock();
rates = rcu_dereference(sta->rates);
if (!rates)
goto out;
rate.idx = rates->rate[0].idx;
rate.flags = rates->rate[0].flags;
mt76x0_mac_wcid_set_rate(dev, &msta->wcid, &rate);
out:
rcu_read_unlock();
}
const struct ieee80211_ops mt76x0_ops = {
.tx = mt76x0_tx,
.start = mt76x0_start,
.stop = mt76x0_stop,
.add_interface = mt76x0_add_interface,
.remove_interface = mt76x0_remove_interface,
.add_interface = mt76x02_add_interface,
.remove_interface = mt76x02_remove_interface,
.config = mt76x0_config,
.configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x0_bss_info_changed,
.sta_add = mt76x0_sta_add,
.sta_remove = mt76x0_sta_remove,
.sta_notify = mt76x0_sta_notify,
.set_key = mt76x0_set_key,
.conf_tx = mt76x0_conf_tx,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
.set_key = mt76x02_set_key,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x0_sw_scan,
.sw_scan_complete = mt76x0_sw_scan_complete,
.ampdu_action = mt76_ampdu_action,
.sta_rate_tbl_update = mt76_sta_rate_tbl_update,
.ampdu_action = mt76x02_ampdu_action,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.set_rts_threshold = mt76x0_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
};
/*
* (c) Copyright 2002-2010, Ralink Technology, Inc.
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
* Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/usb.h>
#include <linux/skbuff.h>
#include "mt76x0.h"
#include "dma.h"
#include "mcu.h"
#include "usb.h"
#include "trace.h"
#define MCU_FW_URB_MAX_PAYLOAD 0x38f8
#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
#define MCU_RESP_URB_SIZE 1024
static inline int firmware_running(struct mt76x0_dev *dev)
{
return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
}
static inline void skb_put_le32(struct sk_buff *skb, u32 val)
{
put_unaligned_le32(val, skb_put(skb, 4));
}
int mt76x0_mcu_function_select(struct mt76x0_dev *dev,
enum mcu_function func, u32 val)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(func),
.value = cpu_to_le32(val),
};
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP,
func == 5);
}
int
mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(cal),
.value = cpu_to_le32(val),
};
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP,
true);
}
int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
const struct mt76_reg_pair *data, int n)
{
const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
struct sk_buff *skb;
int cnt, i, ret;
if (!n)
return 0;
cnt = min(max_vals_per_cmd, n);
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
for (i = 0; i < cnt; i++) {
skb_put_le32(skb, base + data[i].reg);
skb_put_le32(skb, data[i].value);
}
ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_WRITE,
cnt == n);
if (ret)
return ret;
return mt76x0_write_reg_pairs(dev, base, data + cnt, n - cnt);
}
int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
struct mt76_reg_pair *data, int n)
{
const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8;
struct mt76_usb *usb = &dev->mt76.usb;
struct sk_buff *skb;
int cnt, i, ret;
if (!n)
return 0;
cnt = min(max_vals_per_cmd, n);
if (cnt != n)
return -EINVAL;
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
for (i = 0; i < cnt; i++) {
skb_put_le32(skb, base + data[i].reg);
skb_put_le32(skb, data[i].value);
}
mutex_lock(&usb->mcu.mutex);
usb->mcu.rp = data;
usb->mcu.rp_len = n;
usb->mcu.base = base;
usb->mcu.burst = false;
ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_RANDOM_READ,
true);
usb->mcu.rp = NULL;
mutex_unlock(&usb->mcu.mutex);
return ret;
}
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
const u32 *data, int n)
{
const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
struct sk_buff *skb;
int cnt, i, ret;
if (!n)
return 0;
cnt = min(max_regs_per_cmd, n);
skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset);
for (i = 0; i < cnt; i++)
skb_put_le32(skb, data[i]);
ret = mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_WRITE,
cnt == n);
if (ret)
return ret;
return mt76x0_burst_write_regs(dev, offset + cnt * 4,
data + cnt, n - cnt);
}
#if 0
static int mt76x0_burst_read_regs(struct mt76x0_dev *dev, u32 base,
struct mt76_reg_pair *data, int n)
{
const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1;
struct mt76_usb *usb = &dev->mt76.usb;
struct sk_buff *skb;
int cnt, ret;
if (!n)
return 0;
cnt = min(max_vals_per_cmd, n);
if (cnt != n)
return -EINVAL;
skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
skb_put_le32(skb, base + data[0].reg);
skb_put_le32(skb, n);
mutex_lock(&usb->mcu.mutex);
usb->mcu.rp = data;
usb->mcu.rp_len = n;
usb->mcu.base = base;
usb->mcu.burst = false;
ret = __mt76u_mcu_send_msg(&dev->mt76, skb, CMD_BURST_READ, true);
usb->mcu.rp = NULL;
mutex_unlock(&usb->mcu.mutex);
consume_skb(skb);
return ret;
}
#endif
struct mt76_fw_header {
__le32 ilm_len;
__le32 dlm_len;
__le16 build_ver;
__le16 fw_ver;
u8 pad[4];
char build_time[16];
};
struct mt76_fw {
struct mt76_fw_header hdr;
u8 ivb[MT_MCU_IVB_SIZE];
u8 ilm[];
};
static int
mt76x0_upload_firmware(struct mt76x0_dev *dev, const struct mt76_fw *fw)
{
void *ivb;
u32 ilm_len, dlm_len;
int i, ret;
ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL);
if (!ivb)
return -ENOMEM;
ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb);
dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %zu\n",
ilm_len, sizeof(fw->ivb));
ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm, ilm_len,
MCU_FW_URB_MAX_PAYLOAD,
sizeof(fw->ivb));
if (ret)
goto error;
dlm_len = le32_to_cpu(fw->hdr.dlm_len);
dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
ret = mt76u_mcu_fw_send_data(&dev->mt76, fw->ilm + ilm_len,
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_DLM_OFFSET);
if (ret)
goto error;
ret = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x12, 0, ivb, sizeof(fw->ivb));
if (ret < 0)
goto error;
ret = 0;
for (i = 100; i && !firmware_running(dev); i--)
msleep(10);
if (!i) {
ret = -ETIMEDOUT;
goto error;
}
dev_dbg(dev->mt76.dev, "Firmware running!\n");
error:
kfree(ivb);
return ret;
}
static int mt76x0_load_firmware(struct mt76x0_dev *dev)
{
const struct firmware *fw;
const struct mt76_fw_header *hdr;
int len, ret;
u32 val;
mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN));
if (firmware_running(dev))
return 0;
ret = request_firmware(&fw, MT7610_FIRMWARE, dev->mt76.dev);
if (ret)
return ret;
if (!fw || !fw->data || fw->size < sizeof(*hdr))
goto err_inv_fw;
hdr = (const struct mt76_fw_header *) fw->data;
if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
goto err_inv_fw;
len = sizeof(*hdr);
len += le32_to_cpu(hdr->ilm_len);
len += le32_to_cpu(hdr->dlm_len);
if (fw->size != len)
goto err_inv_fw;
val = le16_to_cpu(hdr->fw_ver);
dev_dbg(dev->mt76.dev,
"Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
le16_to_cpu(hdr->build_ver), hdr->build_time);
len = le32_to_cpu(hdr->ilm_len);
mt76_wr(dev, 0x1004, 0x2c);
mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN) |
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20));
mt76u_mcu_fw_reset(&dev->mt76);
msleep(5);
/*
mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
MT_PBF_CFG_TX1Q_EN |
MT_PBF_CFG_TX2Q_EN |
MT_PBF_CFG_TX3Q_EN));
*/
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
/* FCE tx_fs_base_ptr */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
/* FCE tx_fs_max_cnt */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
/* FCE pdma enable */
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 3);
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
ret = mt76x0_upload_firmware(dev, (const struct mt76_fw *)fw->data);
release_firmware(fw);
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
return ret;
err_inv_fw:
dev_err(dev->mt76.dev, "Invalid firmware image\n");
release_firmware(fw);
return -ENOENT;
}
int mt76x0_mcu_init(struct mt76x0_dev *dev)
{
int ret;
ret = mt76x0_load_firmware(dev);
if (ret)
return ret;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
return 0;
}
int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev)
{
int ret = mt76x0_mcu_function_select(dev, Q_SELECT, 1);
if (ret)
return ret;
return mt76u_mcu_init_rx(&dev->mt76);
}
......@@ -15,65 +15,18 @@
#ifndef __MT76X0U_MCU_H
#define __MT76X0U_MCU_H
struct mt76x0_dev;
#include "../mt76x02_mcu.h"
/* Register definitions */
#define MT_MCU_RESET_CTL 0x070C
#define MT_MCU_INT_LEVEL 0x0718
#define MT_MCU_COM_REG0 0x0730
#define MT_MCU_COM_REG1 0x0734
#define MT_MCU_COM_REG2 0x0738
#define MT_MCU_COM_REG3 0x073C
struct mt76x0_dev;
#define MT_MCU_IVB_SIZE 0x40
#define MT_MCU_DLM_OFFSET 0x80000
#define MT_MCU_MEMMAP_WLAN 0x00410000
/* We use same space for BBP as for MAC regs
* #define MT_MCU_MEMMAP_BBP 0x40000000
*/
#define MT_MCU_MEMMAP_RF 0x80000000
#define INBAND_PACKET_MAX_LEN 192
enum mcu_cmd {
CMD_FUN_SET_OP = 1,
CMD_LOAD_CR = 2,
CMD_INIT_GAIN_OP = 3,
CMD_DYNC_VGA_OP = 6,
CMD_TDLS_CH_SW = 7,
CMD_BURST_WRITE = 8,
CMD_READ_MODIFY_WRITE = 9,
CMD_RANDOM_READ = 10,
CMD_BURST_READ = 11,
CMD_RANDOM_WRITE = 12,
CMD_LED_MODE_OP = 16,
CMD_POWER_SAVING_OP = 20,
CMD_WOW_CONFIG = 21,
CMD_WOW_QUERY = 22,
CMD_WOW_FEATURE = 24,
CMD_CARRIER_DETECT_OP = 28,
CMD_RADOR_DETECT_OP = 29,
CMD_SWITCH_CHANNEL_OP = 30,
CMD_CALIBRATION_OP = 31,
CMD_BEACON_OP = 32,
CMD_ANTENNA_OP = 33,
};
enum mcu_function {
Q_SELECT = 1,
BW_SETTING = 2,
ATOMIC_TSSI_SETTING = 5,
};
enum mcu_power_mode {
RADIO_OFF = 0x30,
RADIO_ON = 0x31,
RADIO_OFF_AUTO_WAKEUP = 0x32,
RADIO_OFF_ADVANCE = 0x33,
RADIO_ON_ADVANCE = 0x34,
};
enum mcu_calibrate {
MCU_CAL_R = 1,
MCU_CAL_RXDCOC,
......@@ -88,13 +41,4 @@ enum mcu_calibrate {
MCU_CAL_TX_GROUP_DELAY,
};
int mt76x0_mcu_init(struct mt76x0_dev *dev);
int mt76x0_mcu_cmd_init(struct mt76x0_dev *dev);
int
mt76x0_mcu_calibrate(struct mt76x0_dev *dev, enum mcu_calibrate cal, u32 val);
int
mt76x0_mcu_function_select(struct mt76x0_dev *dev, enum mcu_function func, u32 val);
#endif
......@@ -39,15 +39,6 @@
#define MT_USB_AGGR_SIZE_LIMIT 21 /* * 1024B */
#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */
#define MT_RX_ORDER 3
#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER)
struct mt76x0_dma_buf {
struct urb *urb;
void *buf;
dma_addr_t dma;
size_t len;
};
struct mac_stats {
u64 rx_stat[6];
......@@ -57,48 +48,6 @@ struct mac_stats {
u64 zero_len_del[2];
};
#define N_RX_ENTRIES 16
struct mt76x0_rx_queue {
struct mt76x0_dev *dev;
struct mt76x0_dma_buf_rx {
struct urb *urb;
struct page *p;
} e[N_RX_ENTRIES];
unsigned int start;
unsigned int end;
unsigned int entries;
unsigned int pending;
};
#define N_TX_ENTRIES 64
struct mt76x0_tx_queue {
struct mt76x0_dev *dev;
struct mt76x0_dma_buf_tx {
struct urb *urb;
struct sk_buff *skb;
} e[N_TX_ENTRIES];
unsigned int start;
unsigned int end;
unsigned int entries;
unsigned int used;
unsigned int fifo_seq;
};
/* WCID allocation:
* 0: mcast wcid
* 1: bssid wcid
* 1...: STAs
* ...7e: group wcids
* 7f: reserved
*/
#define N_WCIDS 128
#define GROUP_WCID(idx) (254 - idx)
struct mt76x0_eeprom_params;
#define MT_EE_TEMPERATURE_SLOPE 39
......@@ -120,9 +69,6 @@ enum mt_bw {
* struct mt76x0_dev - adapter structure
* @lock: protects @wcid->tx_rate.
* @mac_lock: locks out mac80211's tx status and rx paths.
* @tx_lock: protects @tx_q and changes of MT76_STATE_*_STATS
* flags in @state.
* @rx_lock: protects @rx_q.
* @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi.
* @mutex: ensures exclusive access from mac80211 callbacks.
* @reg_atomic_mutex: ensures atomicity of indirect register accesses
......@@ -133,34 +79,15 @@ enum mt_bw {
struct mt76x0_dev {
struct mt76_dev mt76; /* must be first */
struct mutex usb_ctrl_mtx;
u8 data[32];
struct tasklet_struct rx_tasklet;
struct tasklet_struct tx_tasklet;
u8 out_ep[__MT_EP_OUT_MAX];
u16 out_max_packet;
u8 in_ep[__MT_EP_IN_MAX];
u16 in_max_packet;
unsigned long wcid_mask[DIV_ROUND_UP(N_WCIDS, BITS_PER_LONG)];
unsigned long vif_mask;
struct delayed_work cal_work;
struct delayed_work mac_work;
struct workqueue_struct *stat_wq;
struct delayed_work stat_work;
struct mt76_wcid *mon_wcid;
struct mt76_wcid __rcu *wcid[N_WCIDS];
spinlock_t mac_lock;
const u16 *beacon_offsets;
u8 macaddr[ETH_ALEN];
struct mt76x0_eeprom_params *ee;
struct mutex reg_atomic_mutex;
......@@ -168,17 +95,8 @@ struct mt76x0_dev {
u32 debugfs_reg;
/* TX */
spinlock_t tx_lock;
struct mt76x0_tx_queue *tx_q;
struct sk_buff_head tx_skb_done;
atomic_t avg_ampdu_len;
/* RX */
spinlock_t rx_lock;
struct mt76x0_rx_queue rx_q;
/* Connection monitoring things */
spinlock_t con_mon_lock;
u8 ap_bssid[ETH_ALEN];
......@@ -194,17 +112,6 @@ struct mt76x0_dev {
struct mac_stats stats;
};
struct mt76x0_wcid {
u8 idx;
u8 hw_key_idx;
u16 tx_rate;
bool tx_rate_set;
u8 tx_rate_nss;
};
struct mt76x0_rxwi;
extern const struct ieee80211_ops mt76x0_ops;
static inline bool is_mt7610e(struct mt76x0_dev *dev)
......@@ -219,16 +126,9 @@ void mt76x0_init_debugfs(struct mt76x0_dev *dev);
#define mt76_rmw_field(_dev, _reg, _field, _val) \
mt76_rmw(_dev, _reg, _field, FIELD_PREP(_field, _val))
int mt76x0_write_reg_pairs(struct mt76x0_dev *dev, u32 base,
const struct mt76_reg_pair *data, int len);
int mt76x0_read_reg_pairs(struct mt76x0_dev *dev, u32 base,
struct mt76_reg_pair *data, int len);
int mt76x0_burst_write_regs(struct mt76x0_dev *dev, u32 offset,
const u32 *data, int n);
void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr);
/* Init */
struct mt76x0_dev *mt76x0_alloc_device(struct device *dev);
struct mt76x0_dev *
mt76x0_alloc_device(struct device *pdev, const struct mt76_driver_ops *drv_ops);
int mt76x0_init_hardware(struct mt76x0_dev *dev);
int mt76x0_register_device(struct mt76x0_dev *dev);
void mt76x0_cleanup(struct mt76x0_dev *dev);
......@@ -245,7 +145,7 @@ void mt76x0_agc_restore(struct mt76x0_dev *dev);
int mt76x0_phy_set_channel(struct mt76x0_dev *dev,
struct cfg80211_chan_def *chandef);
void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev);
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi);
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi);
void mt76x0_phy_con_cal_onoff(struct mt76x0_dev *dev,
struct ieee80211_bss_conf *info);
......@@ -260,19 +160,12 @@ void mt76x0_mac_set_ampdu_factor(struct mt76x0_dev *dev);
/* TX */
void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb);
int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params);
void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb);
void mt76x0_tx_stat(struct work_struct *work);
/* util */
void mt76x0_remove_hdr_pad(struct sk_buff *skb);
int mt76x0_insert_hdr_pad(struct sk_buff *skb);
int mt76x0_dma_init(struct mt76x0_dev *dev);
void mt76x0_dma_cleanup(struct mt76x0_dev *dev);
int mt76x0_dma_enqueue_tx(struct mt76x0_dev *dev, struct sk_buff *skb,
struct mt76_wcid *wcid, int hw_q);
void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info);
#endif
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "mt76x0.h"
static int
mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct mt76x0_dev *dev;
int ret = -ENODEV;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
if (ret)
return ret;
pci_set_master(pdev);
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
dev = mt76x0_alloc_device(&pdev->dev, NULL);
if (!dev)
return -ENOMEM;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
dev->mt76.rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(dev->mt76.dev, "ASIC revision: %08x\n", dev->mt76.rev);
/* error: */
ieee80211_free_hw(mt76_hw(dev));
return ret;
}
static void
mt76x0e_remove(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
mt76_unregister_device(mdev);
ieee80211_free_hw(mdev->hw);
}
static const struct pci_device_id mt76x0e_device_table[] = {
{ PCI_DEVICE(0x14c3, 0x7630) },
{ },
};
MODULE_DEVICE_TABLE(pci, mt76x0e_device_table);
MODULE_LICENSE("Dual BSD/GPL");
static struct pci_driver mt76x0e_driver = {
.name = KBUILD_MODNAME,
.id_table = mt76x0e_device_table,
.probe = mt76x0e_probe,
.remove = mt76x0e_remove,
};
module_pci_driver(mt76x0e_driver);
......@@ -117,7 +117,7 @@ rf_wr(struct mt76x0_dev *dev, u32 offset, u8 val)
.value = val,
};
return mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1);
} else {
WARN_ON_ONCE(1);
return mt76x0_rf_csr_wr(dev, offset, val);
......@@ -135,7 +135,7 @@ rf_rr(struct mt76x0_dev *dev, u32 offset)
.reg = offset,
};
ret = mt76x0_read_reg_pairs(dev, MT_MCU_MEMMAP_RF, &pair, 1);
ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1);
val = pair.value;
} else {
WARN_ON_ONCE(1);
......@@ -175,8 +175,9 @@ rf_clear(struct mt76x0_dev *dev, u32 offset, u8 mask)
}
#endif
#define RF_RANDOM_WRITE(dev, tab) \
mt76x0_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));
#define RF_RANDOM_WRITE(dev, tab) \
mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, \
tab, ARRAY_SIZE(tab))
int mt76x0_wait_bbp_ready(struct mt76x0_dev *dev)
{
......@@ -225,7 +226,7 @@ mt76x0_bbp_set_ctrlch(struct mt76x0_dev *dev, enum nl80211_chan_width width,
mt76_rmw_field(dev, MT_BBP(TXBE, 0), MT_BBP_TXBE_R0_CTRL_CHAN, ctrl);
}
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x0_rxwi *rxwi)
int mt76x0_phy_get_rssi(struct mt76x0_dev *dev, struct mt76x02_rxwi *rxwi)
{
s8 lna_gain, rssi_offset;
int val;
......@@ -640,7 +641,7 @@ mt76x0_bbp_set_bw(struct mt76x0_dev *dev, enum nl80211_chan_width width)
return ;
}
mt76x0_mcu_function_select(dev, BW_SETTING, bw);
mt76x02_mcu_function_select(&dev->mt76, BW_SETTING, bw, false);
}
static void
......@@ -757,10 +758,10 @@ __mt76x0_phy_set_channel(struct mt76x0_dev *dev,
/* Vendor driver don't do it */
/* mt76x0_phy_set_tx_power(dev, channel, rf_bw_band); */
mt76x0_vco_cal(dev, channel);
if (scan)
mt76x0_vco_cal(dev, channel);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false);
mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1);
mt76x0_phy_set_chan_pwr(dev, channel);
dev->mt76.chandef = *chandef;
......@@ -785,7 +786,7 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev)
u8 channel = dev->mt76.chandef.chan->hw_value;
int is_5ghz = (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ) ? 1 : 0;
mt76x0_mcu_calibrate(dev, MCU_CAL_R, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, false);
mt76x0_vco_cal(dev, channel);
......@@ -797,20 +798,22 @@ void mt76x0_phy_recalibrate_after_assoc(struct mt76x0_dev *dev)
reg_val &= 0xffffff7e;
mt76_wr(dev, 0x2124, reg_val);
mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 0, false);
mt76x0_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz);
mt76x0_mcu_calibrate(dev, MCU_CAL_LOFT, is_5ghz);
mt76x0_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
mt76x0_mcu_calibrate(dev, MCU_CAL_TX_GROUP_DELAY, is_5ghz);
mt76x0_mcu_calibrate(dev, MCU_CAL_RXIQ, is_5ghz);
mt76x0_mcu_calibrate(dev, MCU_CAL_RX_GROUP_DELAY, is_5ghz);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LOFT, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_GROUP_DELAY,
is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQ, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RX_GROUP_DELAY,
is_5ghz, false);
mt76_wr(dev, 0x2124, reg_val);
mt76_wr(dev, MT_TX_ALC_CFG_0, tx_alc);
msleep(100);
mt76x0_mcu_calibrate(dev, MCU_CAL_RXDCOC, 1);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, 1, false);
}
void mt76x0_agc_save(struct mt76x0_dev *dev)
......
......@@ -178,11 +178,11 @@ DECLARE_EVENT_CLASS(dev_simple_evt,
);
TRACE_EVENT(mt76x0_rx,
TP_PROTO(struct mt76_dev *dev, struct mt76x0_rxwi *rxwi, u32 f),
TP_PROTO(struct mt76_dev *dev, struct mt76x02_rxwi *rxwi, u32 f),
TP_ARGS(dev, rxwi, f),
TP_STRUCT__entry(
DEV_ENTRY
__field_struct(struct mt76x0_rxwi, rxwi)
__field_struct(struct mt76x02_rxwi, rxwi)
__field(u32, fce_info)
),
TP_fast_assign(
......@@ -197,11 +197,11 @@ TRACE_EVENT(mt76x0_rx,
TRACE_EVENT(mt76x0_tx,
TP_PROTO(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76x02_sta *sta, struct mt76_txwi *h),
struct mt76x02_sta *sta, struct mt76x02_txwi *h),
TP_ARGS(dev, skb, sta, h),
TP_STRUCT__entry(
DEV_ENTRY
__field_struct(struct mt76_txwi, h)
__field_struct(struct mt76x02_txwi, h)
__field(struct sk_buff *, skb)
__field(struct mt76x02_sta *, sta)
),
......@@ -211,11 +211,11 @@ TRACE_EVENT(mt76x0_tx,
__entry->skb = skb;
__entry->sta = sta;
),
TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx "
TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate:%04hx "
"ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG,
__entry->skb, __entry->sta,
le16_to_cpu(__entry->h.flags),
le16_to_cpu(__entry->h.rate_ctl),
le16_to_cpu(__entry->h.rate),
__entry->h.ack_ctl, __entry->h.wcid,
le16_to_cpu(__entry->h.len_ctl))
);
......
......@@ -14,74 +14,22 @@
#include "mt76x0.h"
#include "trace.h"
#include "../mt76x02_util.h"
#include "../mt76x02_usb.h"
/* Take mac80211 Q id from the skb and translate it to hardware Q id */
static u8 skb2q(struct sk_buff *skb)
{
int qid = skb_get_queue_mapping(skb);
if (WARN_ON(qid >= MT_TXQ_PSD)) {
qid = MT_TXQ_BE;
skb_set_queue_mapping(skb, qid);
}
return q2hwq(qid);
}
static void mt76x0_tx_skb_remove_dma_overhead(struct sk_buff *skb,
struct ieee80211_tx_info *info)
{
int pkt_len = (unsigned long)info->status.status_driver_data[0];
skb_pull(skb, sizeof(struct mt76_txwi) + 4);
if (ieee80211_get_hdrlen_from_skb(skb) % 4)
mt76x0_remove_hdr_pad(skb);
skb_trim(skb, pkt_len);
}
void mt76x0_tx_status(struct mt76x0_dev *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
mt76x0_tx_skb_remove_dma_overhead(skb, info);
ieee80211_tx_info_clear_status(info);
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
spin_lock(&dev->mac_lock);
ieee80211_tx_status(dev->mt76.hw, skb);
spin_unlock(&dev->mac_lock);
}
static int mt76x0_skb_rooms(struct mt76x0_dev *dev, struct sk_buff *skb)
{
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
u32 need_head;
need_head = sizeof(struct mt76_txwi) + 4;
if (hdr_len % 4)
need_head += 2;
return skb_cow(skb, need_head);
}
static struct mt76_txwi *
static struct mt76x02_txwi *
mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta, struct mt76_wcid *wcid,
int pkt_len)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0];
struct mt76_txwi *txwi;
struct mt76x02_txwi *txwi;
unsigned long flags;
u16 txwi_flags = 0;
u32 pkt_id;
u16 rate_ctl;
u8 nss;
txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi));
txwi = (struct mt76x02_txwi *)skb_push(skb, sizeof(struct mt76x02_txwi));
memset(txwi, 0, sizeof(*txwi));
if (!wcid->tx_rate_set)
......@@ -93,178 +41,75 @@ mt76x0_push_txwi(struct mt76x0_dev *dev, struct sk_buff *skb,
rate_ctl = wcid->tx_rate;
nss = wcid->tx_rate_nss;
} else {
rate_ctl = mt76x0_mac_tx_rate_val(dev, rate, &nss);
rate_ctl = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss);
}
spin_unlock_irqrestore(&dev->mt76.lock, flags);
txwi->rate_ctl = cpu_to_le16(rate_ctl);
if (info->flags & IEEE80211_TX_CTL_LDPC)
txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_LDPC);
if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
txwi->rate_ctl |= cpu_to_le16(MT_RXWI_RATE_STBC);
if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
txwi_flags |= MT_TXWI_FLAGS_MMPS;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
pkt_id = 1;
} else {
pkt_id = 0;
}
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
pkt_id |= MT_TXWI_PKTID_PROBE;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
ba_size <<= sta->ht_cap.ampdu_factor;
ba_size = min_t(int, 7, ba_size - 1);
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
ba_size = 0;
} else {
txwi_flags |= MT_TXWI_FLAGS_AMPDU;
txwi_flags |= FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
sta->ht_cap.ampdu_density);
}
txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
}
txwi->wcid = wcid->idx;
txwi->flags |= cpu_to_le16(txwi_flags);
txwi->len_ctl = cpu_to_le16(pkt_len);
txwi->pktid = pkt_id;
txwi->rate = cpu_to_le16(rate_ctl);
txwi->pktid = (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) ? 1 : 0;
mt76x02_mac_fill_txwi(txwi, skb, sta, pkt_len, nss);
return txwi;
}
void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb)
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mt76x0_dev *dev = hw->priv;
struct ieee80211_vif *vif = info->control.vif;
struct ieee80211_sta *sta = control->sta;
struct mt76x02_sta *msta = NULL;
struct mt76_wcid *wcid = dev->mon_wcid;
struct mt76_txwi *txwi;
int pkt_len = skb->len;
int hw_q = skb2q(skb);
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len;
if (control->sta) {
struct mt76x02_sta *msta;
if (mt76x0_skb_rooms(dev, skb) || mt76x0_insert_hdr_pad(skb)) {
ieee80211_free_txskb(dev->mt76.hw, skb);
return;
msta = (struct mt76x02_sta *)control->sta->drv_priv;
wcid = &msta->wcid;
/* sw encrypted frames */
if (!info->control.hw_key && wcid->hw_key_idx != 0xff)
control->sta = NULL;
}
if (sta) {
msta = (struct mt76x02_sta *) sta->drv_priv;
wcid = &msta->wcid;
} else if (vif && (!info->control.hw_key && wcid->hw_key_idx != 0xff)) {
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
if (vif && !control->sta) {
struct mt76x02_vif *mvif;
mvif = (struct mt76x02_vif *)vif->drv_priv;
wcid = &mvif->group_wcid;
}
txwi = mt76x0_push_txwi(dev, skb, sta, wcid, pkt_len);
if (mt76x0_dma_enqueue_tx(dev, skb, wcid, hw_q))
return;
trace_mt76x0_tx(&dev->mt76, skb, msta, txwi);
mt76_tx(&dev->mt76, control->sta, wcid, skb);
}
void mt76x0_tx_stat(struct work_struct *work)
int mt76x0_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info)
{
struct mt76x0_dev *dev = container_of(work, struct mt76x0_dev,
stat_work.work);
struct mt76x02_tx_status stat;
unsigned long flags;
int cleaned = 0;
u8 update = 1;
struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76);
struct mt76x02_txwi *txwi;
int len = skb->len;
while (!test_bit(MT76_REMOVED, &dev->mt76.state)) {
stat = mt76x0_mac_fetch_tx_status(dev);
if (!stat.valid)
break;
mt76x02_insert_hdr_pad(skb);
txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len);
mt76x0_send_tx_status(dev, &stat, &update);
cleaned++;
}
trace_mt76x0_tx_status_cleaned(&dev->mt76, cleaned);
spin_lock_irqsave(&dev->tx_lock, flags);
if (cleaned)
queue_delayed_work(dev->stat_wq, &dev->stat_work,
msecs_to_jiffies(10));
else if (test_and_clear_bit(MT76_MORE_STATS, &dev->mt76.state))
queue_delayed_work(dev->stat_wq, &dev->stat_work,
msecs_to_jiffies(20));
else
clear_bit(MT76_READING_STATS, &dev->mt76.state);
spin_unlock_irqrestore(&dev->tx_lock, flags);
return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
}
EXPORT_SYMBOL_GPL(mt76x0_tx_prepare_skb);
int mt76x0_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params)
void mt76x0_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb)
{
struct mt76x0_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue);
u32 val;
/* TODO: should we do funny things with the parameters?
* See what mt76x0_set_default_edca() used to do in init.c.
*/
if (params->cw_min)
cw_min = fls(params->cw_min);
if (params->cw_max)
cw_max = fls(params->cw_max);
WARN_ON(params->txop > 0xff);
WARN_ON(params->aifs > 0xf);
WARN_ON(cw_min > 0xf);
WARN_ON(cw_max > 0xf);
struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76);
void *rxwi = skb->data;
val = FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
/* TODO: based on user-controlled EnableTxBurst var vendor drv sets
* a really long txop on AC0 (see connect.c:2009) but only on
* connect? When not connected should be 0.
*/
if (!hw_q)
val |= 0x60;
else
val |= FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop);
mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val);
val = mt76_rr(dev, MT_WMM_TXOP(hw_q));
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q));
val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q);
mt76_wr(dev, MT_WMM_TXOP(hw_q), val);
val = mt76_rr(dev, MT_WMM_AIFSN);
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q));
val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q);
mt76_wr(dev, MT_WMM_AIFSN, val);
val = mt76_rr(dev, MT_WMM_CWMIN);
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q));
val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q);
mt76_wr(dev, MT_WMM_CWMIN, val);
val = mt76_rr(dev, MT_WMM_CWMAX);
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q));
val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q);
mt76_wr(dev, MT_WMM_CWMAX, val);
skb_pull(skb, sizeof(struct mt76x02_rxwi));
if (!mt76x0_mac_process_rx(dev, skb, rxwi)) {
dev_kfree_skb(skb);
return;
}
return 0;
mt76_rx(&dev->mt76, q, skb);
}
EXPORT_SYMBOL_GPL(mt76x0_queue_rx_skb);
......@@ -13,11 +13,16 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/usb.h>
#include "mt76x0.h"
#include "usb.h"
#include "mcu.h"
#include "trace.h"
#include "../mt76x02_util.h"
#include "../mt76x02_usb.h"
#define MT7610U_FIRMWARE "mediatek/mt7610u.bin"
static struct usb_device_id mt76x0_device_table[] = {
{ USB_DEVICE(0x148F, 0x7610) }, /* MT7610U */
......@@ -46,21 +51,178 @@ static struct usb_device_id mt76x0_device_table[] = {
{ 0, }
};
void mt76x0_addr_wr(struct mt76x0_dev *dev, const u32 offset, const u8 *addr)
#define MCU_FW_URB_MAX_PAYLOAD 0x38f8
#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12)
static inline int mt76x0_firmware_running(struct mt76x0_dev *dev)
{
return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
}
static int
mt76x0u_upload_firmware(struct mt76x0_dev *dev,
const struct mt76x02_fw_header *hdr)
{
u8 *fw_payload = (u8 *)(hdr + 1);
u32 ilm_len, dlm_len;
void *ivb;
int err;
ivb = kmemdup(fw_payload, MT_MCU_IVB_SIZE, GFP_KERNEL);
if (!ivb)
return -ENOMEM;
ilm_len = le32_to_cpu(hdr->ilm_len) - MT_MCU_IVB_SIZE;
dev_dbg(dev->mt76.dev, "loading FW - ILM %u + IVB %u\n",
ilm_len, MT_MCU_IVB_SIZE);
err = mt76x02u_mcu_fw_send_data(&dev->mt76,
fw_payload + MT_MCU_IVB_SIZE,
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_IVB_SIZE);
if (err)
goto out;
dlm_len = le32_to_cpu(hdr->dlm_len);
dev_dbg(dev->mt76.dev, "loading FW - DLM %u\n", dlm_len);
err = mt76x02u_mcu_fw_send_data(&dev->mt76,
fw_payload + le32_to_cpu(hdr->ilm_len),
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
MT_MCU_DLM_OFFSET);
if (err)
goto out;
err = mt76u_vendor_request(&dev->mt76, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x12, 0, ivb, MT_MCU_IVB_SIZE);
if (err < 0)
goto out;
if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 1000)) {
dev_err(dev->mt76.dev, "Firmware failed to start\n");
err = -ETIMEDOUT;
goto out;
}
dev_dbg(dev->mt76.dev, "Firmware running!\n");
out:
kfree(ivb);
return err;
}
static int mt76x0u_load_firmware(struct mt76x0_dev *dev)
{
const struct firmware *fw;
const struct mt76x02_fw_header *hdr;
int len, ret;
u32 val;
mt76_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN));
if (mt76x0_firmware_running(dev))
return 0;
ret = request_firmware(&fw, MT7610U_FIRMWARE, dev->mt76.dev);
if (ret)
return ret;
if (!fw || !fw->data || fw->size < sizeof(*hdr))
goto err_inv_fw;
hdr = (const struct mt76x02_fw_header *)fw->data;
if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE)
goto err_inv_fw;
len = sizeof(*hdr);
len += le32_to_cpu(hdr->ilm_len);
len += le32_to_cpu(hdr->dlm_len);
if (fw->size != len)
goto err_inv_fw;
val = le16_to_cpu(hdr->fw_ver);
dev_dbg(dev->mt76.dev,
"Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n",
(val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf,
le16_to_cpu(hdr->build_ver), hdr->build_time);
len = le32_to_cpu(hdr->ilm_len);
mt76_wr(dev, 0x1004, 0x2c);
mt76_set(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN |
MT_USB_DMA_CFG_TX_BULK_EN) |
FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, 0x20));
mt76x02u_mcu_fw_reset(&dev->mt76);
msleep(5);
/*
mt76x0_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN |
MT_PBF_CFG_TX1Q_EN |
MT_PBF_CFG_TX2Q_EN |
MT_PBF_CFG_TX3Q_EN));
*/
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
/* FCE tx_fs_base_ptr */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230);
/* FCE tx_fs_max_cnt */
mt76_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1);
/* FCE pdma enable */
mt76_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44);
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 3);
val = mt76_rr(dev, MT_USB_DMA_CFG);
val |= MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
val &= ~MT_USB_DMA_CFG_UDMA_TX_WL_DROP;
mt76_wr(dev, MT_USB_DMA_CFG, val);
ret = mt76x0u_upload_firmware(dev, hdr);
release_firmware(fw);
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
return ret;
err_inv_fw:
dev_err(dev->mt76.dev, "Invalid firmware image\n");
release_firmware(fw);
return -ENOENT;
}
static int mt76x0u_mcu_init(struct mt76x0_dev *dev)
{
mt76_wr(dev, offset, get_unaligned_le32(addr));
mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
int ret;
ret = mt76x0u_load_firmware(dev);
if (ret < 0)
return ret;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
return 0;
}
static int mt76x0_probe(struct usb_interface *usb_intf,
static int mt76x0u_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
.tx_prepare_skb = mt76x0_tx_prepare_skb,
.tx_complete_skb = mt76x02_tx_complete_skb,
.tx_status_data = mt76x02_tx_status_data,
.rx_skb = mt76x0_queue_rx_skb,
};
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
struct mt76x0_dev *dev;
u32 asic_rev, mac_rev;
int ret;
dev = mt76x0_alloc_device(&usb_intf->dev);
dev = mt76x0_alloc_device(&usb_intf->dev, &drv_ops);
if (!dev)
return -ENOMEM;
......@@ -69,6 +231,7 @@ static int mt76x0_probe(struct usb_interface *usb_intf,
usb_set_intfdata(usb_intf, dev);
mt76x02u_init_mcu(&dev->mt76);
ret = mt76u_init(&dev->mt76, usb_intf);
if (ret)
goto err;
......@@ -90,10 +253,23 @@ static int mt76x0_probe(struct usb_interface *usb_intf,
if (!(mt76_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL))
dev_warn(dev->mt76.dev, "Warning: eFUSE not present\n");
ret = mt76x0_init_hardware(dev);
if (ret)
ret = mt76u_mcu_init_rx(&dev->mt76);
if (ret < 0)
goto err;
ret = mt76u_alloc_queues(&dev->mt76);
if (ret < 0)
goto err;
mt76x0_chip_onoff(dev, true, true);
if (!mt76x02_wait_for_mac(&dev->mt76))
return -ETIMEDOUT;
ret = mt76x0u_mcu_init(dev);
if (ret)
goto err_hw;
ret = mt76x0_register_device(dev);
if (ret)
goto err_hw;
......@@ -107,7 +283,6 @@ static int mt76x0_probe(struct usb_interface *usb_intf,
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->mt76.hw);
return ret;
}
......@@ -126,41 +301,62 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf)
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->mt76.hw);
}
static int mt76x0_suspend(struct usb_interface *usb_intf, pm_message_t state)
static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf,
pm_message_t state)
{
struct mt76x0_dev *dev = usb_get_intfdata(usb_intf);
struct mt76_usb *usb = &dev->mt76.usb;
mt76x0_cleanup(dev);
mt76u_stop_queues(&dev->mt76);
mt76x0_mac_stop(dev);
usb_kill_urb(usb->mcu.res.urb);
return 0;
}
static int mt76x0_resume(struct usb_interface *usb_intf)
static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf)
{
struct mt76x0_dev *dev = usb_get_intfdata(usb_intf);
struct mt76_usb *usb = &dev->mt76.usb;
int ret;
reinit_completion(&usb->mcu.cmpl);
ret = mt76u_submit_buf(&dev->mt76, USB_DIR_IN,
MT_EP_IN_CMD_RESP,
&usb->mcu.res, GFP_KERNEL,
mt76u_mcu_complete_urb,
&usb->mcu.cmpl);
if (ret < 0)
goto err;
ret = mt76u_submit_rx_buffers(&dev->mt76);
if (ret < 0)
goto err;
tasklet_enable(&usb->rx_tasklet);
tasklet_enable(&usb->tx_tasklet);
ret = mt76x0_init_hardware(dev);
if (ret)
return ret;
set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
goto err;
return 0;
err:
mt76x0_cleanup(dev);
return ret;
}
MODULE_DEVICE_TABLE(usb, mt76x0_device_table);
MODULE_FIRMWARE(MT7610_FIRMWARE);
MODULE_FIRMWARE(MT7610U_FIRMWARE);
MODULE_LICENSE("GPL");
static struct usb_driver mt76x0_driver = {
.name = KBUILD_MODNAME,
.id_table = mt76x0_device_table,
.probe = mt76x0_probe,
.probe = mt76x0u_probe,
.disconnect = mt76x0_disconnect,
.suspend = mt76x0_suspend,
.resume = mt76x0_resume,
......
/*
* Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __MT76X0U_USB_H
#define __MT76X0U_USB_H
#include "mt76x0.h"
#define MT7610_FIRMWARE "mediatek/mt7610u.bin"
#define MT_VEND_REQ_MAX_RETRY 10
#define MT_VEND_REQ_TOUT_MS 300
#define MT_VEND_DEV_MODE_RESET 1
#define MT_VEND_BUF sizeof(__le32)
static inline struct usb_device *mt76x0_to_usb_dev(struct mt76x0_dev *mt76x0)
{
return interface_to_usbdev(to_usb_interface(mt76x0->mt76.dev));
}
static inline struct usb_device *mt76_to_usb_dev(struct mt76_dev *mt76)
{
return interface_to_usbdev(to_usb_interface(mt76->dev));
}
static inline bool mt76x0_urb_has_error(struct urb *urb)
{
return urb->status &&
urb->status != -ENOENT &&
urb->status != -ECONNRESET &&
urb->status != -ESHUTDOWN;
}
#endif
/*
* Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "mt76x0.h"
void mt76x0_remove_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + 2, skb->data, len);
skb_pull(skb, 2);
}
int mt76x0_insert_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
int ret;
if (len % 4 == 0)
return 0;
ret = skb_cow(skb, 2);
if (ret)
return ret;
skb_push(skb, 2);
memmove(skb->data, skb->data + 2, len);
skb->data[len] = 0;
skb->data[len + 1] = 0;
return 0;
}
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __MT76x02_DMA_H
#define __MT76x02_DMA_H
#include "dma.h"
#define MT_TXD_INFO_LEN GENMASK(15, 0)
#define MT_TXD_INFO_NEXT_VLD BIT(16)
#define MT_TXD_INFO_TX_BURST BIT(17)
#define MT_TXD_INFO_80211 BIT(19)
#define MT_TXD_INFO_TSO BIT(20)
#define MT_TXD_INFO_CSO BIT(21)
#define MT_TXD_INFO_WIV BIT(24)
#define MT_TXD_INFO_QSEL GENMASK(26, 25)
#define MT_TXD_INFO_DPORT GENMASK(29, 27)
#define MT_TXD_INFO_TYPE GENMASK(31, 30)
#define MT_RX_FCE_INFO_LEN GENMASK(13, 0)
#define MT_RX_FCE_INFO_SELF_GEN BIT(15)
#define MT_RX_FCE_INFO_CMD_SEQ GENMASK(19, 16)
#define MT_RX_FCE_INFO_EVT_TYPE GENMASK(23, 20)
#define MT_RX_FCE_INFO_PCIE_INTR BIT(24)
#define MT_RX_FCE_INFO_QSEL GENMASK(26, 25)
#define MT_RX_FCE_INFO_D_PORT GENMASK(29, 27)
#define MT_RX_FCE_INFO_TYPE GENMASK(31, 30)
/* MCU request message header */
#define MT_MCU_MSG_LEN GENMASK(15, 0)
#define MT_MCU_MSG_CMD_SEQ GENMASK(19, 16)
#define MT_MCU_MSG_CMD_TYPE GENMASK(26, 20)
#define MT_MCU_MSG_PORT GENMASK(29, 27)
#define MT_MCU_MSG_TYPE GENMASK(31, 30)
#define MT_MCU_MSG_TYPE_CMD BIT(30)
enum dma_msg_port {
WLAN_PORT,
CPU_RX_PORT,
CPU_TX_PORT,
HOST_PORT,
VIRTUAL_CPU_RX_PORT,
VIRTUAL_CPU_TX_PORT,
DISCARD,
};
#endif /* __MT76x02_DMA_H */
......@@ -155,3 +155,350 @@ void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
mt76_txq_init(dev, txq);
}
EXPORT_SYMBOL_GPL(mt76x02_txq_init);
void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb,
struct ieee80211_sta *sta, int len, u8 nss)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 txwi_flags = 0;
if (info->flags & IEEE80211_TX_CTL_LDPC)
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC);
if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC);
if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
txwi_flags |= MT_TXWI_FLAGS_MMPS;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
txwi->pktid |= MT_TXWI_PKTID_PROBE;
if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
ba_size <<= sta->ht_cap.ampdu_factor;
ba_size = min_t(int, 63, ba_size - 1);
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
ba_size = 0;
txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
txwi_flags |= MT_TXWI_FLAGS_AMPDU |
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
sta->ht_cap.ampdu_density);
}
if (ieee80211_is_probe_resp(hdr->frame_control) ||
ieee80211_is_beacon(hdr->frame_control))
txwi_flags |= MT_TXWI_FLAGS_TS;
txwi->flags |= cpu_to_le16(txwi_flags);
txwi->len_ctl = cpu_to_le16(len);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_fill_txwi);
__le16
mt76x02_mac_tx_rate_val(struct mt76_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val)
{
u16 rateval;
u8 phy, rate_idx;
u8 nss = 1;
u8 bw = 0;
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 4);
phy = MT_PHY_TYPE_VHT;
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
bw = 2;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 3);
phy = MT_PHY_TYPE_HT;
if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
phy = MT_PHY_TYPE_HT_GF;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else {
const struct ieee80211_rate *r;
int band = dev->chandef.chan->band;
u16 val;
r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
val = r->hw_value_short;
else
val = r->hw_value;
phy = val >> 8;
rate_idx = val & 0xff;
bw = 0;
}
rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rateval |= MT_RXWI_RATE_SGI;
*nss_val = nss;
return cpu_to_le16(rateval);
}
EXPORT_SYMBOL_GPL(mt76x02_mac_tx_rate_val);
void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate)
{
spin_lock_bh(&dev->lock);
wcid->tx_rate = mt76x02_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
wcid->tx_rate_set = true;
spin_unlock_bh(&dev->lock);
}
bool mt76x02_mac_load_tx_status(struct mt76_dev *dev,
struct mt76x02_tx_status *stat)
{
u32 stat1, stat2;
stat2 = __mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
stat1 = __mt76_rr(dev, MT_TX_STAT_FIFO);
stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
if (!stat->valid)
return false;
stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
return true;
}
EXPORT_SYMBOL_GPL(mt76x02_mac_load_tx_status);
static int
mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
enum nl80211_band band)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
txrate->idx = 0;
txrate->flags = 0;
txrate->count = 1;
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (band == NL80211_BAND_2GHZ)
idx += 4;
txrate->idx = idx;
return 0;
case MT_PHY_TYPE_CCK:
if (idx >= 8)
idx -= 8;
txrate->idx = idx;
return 0;
case MT_PHY_TYPE_HT_GF:
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
/* fall through */
case MT_PHY_TYPE_HT:
txrate->flags |= IEEE80211_TX_RC_MCS;
txrate->idx = idx;
break;
case MT_PHY_TYPE_VHT:
txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
txrate->idx = idx;
break;
default:
return -EINVAL;
}
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
break;
case MT_PHY_BW_80:
txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
break;
default:
return -EINVAL;
}
if (rate & MT_RXWI_RATE_SGI)
txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
return 0;
}
static void
mt76x02_mac_fill_tx_status(struct mt76_dev *dev,
struct ieee80211_tx_info *info,
struct mt76x02_tx_status *st, int n_frames)
{
struct ieee80211_tx_rate *rate = info->status.rates;
int cur_idx, last_rate;
int i;
if (!n_frames)
return;
last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate,
dev->chandef.chan->band);
if (last_rate < IEEE80211_TX_MAX_RATES - 1)
rate[last_rate + 1].idx = -1;
cur_idx = rate[last_rate].idx + last_rate;
for (i = 0; i <= last_rate; i++) {
rate[i].flags = rate[last_rate].flags;
rate[i].idx = max_t(int, 0, cur_idx - i);
rate[i].count = 1;
}
rate[last_rate].count = st->retry + 1 - last_rate;
info->status.ampdu_len = n_frames;
info->status.ampdu_ack_len = st->success ? n_frames : 0;
if (st->pktid & MT_TXWI_PKTID_PROBE)
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
if (st->aggr)
info->flags |= IEEE80211_TX_CTL_AMPDU |
IEEE80211_TX_STAT_AMPDU;
if (!st->ack_req)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
else if (st->success)
info->flags |= IEEE80211_TX_STAT_ACK;
}
void mt76x02_send_tx_status(struct mt76_dev *dev,
struct mt76x02_tx_status *stat, u8 *update)
{
struct ieee80211_tx_info info = {};
struct ieee80211_sta *sta = NULL;
struct mt76_wcid *wcid = NULL;
struct mt76x02_sta *msta = NULL;
rcu_read_lock();
if (stat->wcid < ARRAY_SIZE(dev->wcid))
wcid = rcu_dereference(dev->wcid[stat->wcid]);
if (wcid) {
void *priv;
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
sta = container_of(priv, struct ieee80211_sta,
drv_priv);
}
if (msta && stat->aggr) {
u32 stat_val, stat_cache;
stat_val = stat->rate;
stat_val |= ((u32) stat->retry) << 16;
stat_cache = msta->status.rate;
stat_cache |= ((u32) msta->status.retry) << 16;
if (*update == 0 && stat_val == stat_cache &&
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
msta->n_frames++;
goto out;
}
mt76x02_mac_fill_tx_status(dev, &info, &msta->status,
msta->n_frames);
msta->status = *stat;
msta->n_frames = 1;
*update = 0;
} else {
mt76x02_mac_fill_tx_status(dev, &info, stat, 1);
*update = 1;
}
ieee80211_tx_status_noskb(dev->hw, sta, &info);
out:
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(mt76x02_send_tx_status);
int
mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (idx >= 8)
idx = 0;
if (status->band == NL80211_BAND_2GHZ)
idx += 4;
status->rate_idx = idx;
return 0;
case MT_PHY_TYPE_CCK:
if (idx >= 8) {
idx -= 8;
status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
}
if (idx >= 4)
idx = 0;
status->rate_idx = idx;
return 0;
case MT_PHY_TYPE_HT_GF:
status->enc_flags |= RX_ENC_FLAG_HT_GF;
/* fall through */
case MT_PHY_TYPE_HT:
status->encoding = RX_ENC_HT;
status->rate_idx = idx;
break;
case MT_PHY_TYPE_VHT:
status->encoding = RX_ENC_VHT;
status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1;
break;
default:
return -EINVAL;
}
if (rate & MT_RXWI_RATE_LDPC)
status->enc_flags |= RX_ENC_FLAG_LDPC;
if (rate & MT_RXWI_RATE_SGI)
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
if (rate & MT_RXWI_RATE_STBC)
status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
status->bw = RATE_INFO_BW_40;
break;
case MT_PHY_BW_80:
status->bw = RATE_INFO_BW_80;
break;
default:
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mac_process_rate);
......@@ -31,6 +31,9 @@ struct mt76x02_tx_status {
u16 rate;
} __packed __aligned(2);
#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
#define MT_MAX_VIFS 8
struct mt76x02_vif {
u8 idx;
......@@ -50,6 +53,111 @@ struct mt76x02_sta {
int inactive_count;
};
#define MT_RXINFO_BA BIT(0)
#define MT_RXINFO_DATA BIT(1)
#define MT_RXINFO_NULL BIT(2)
#define MT_RXINFO_FRAG BIT(3)
#define MT_RXINFO_UNICAST BIT(4)
#define MT_RXINFO_MULTICAST BIT(5)
#define MT_RXINFO_BROADCAST BIT(6)
#define MT_RXINFO_MYBSS BIT(7)
#define MT_RXINFO_CRCERR BIT(8)
#define MT_RXINFO_ICVERR BIT(9)
#define MT_RXINFO_MICERR BIT(10)
#define MT_RXINFO_AMSDU BIT(11)
#define MT_RXINFO_HTC BIT(12)
#define MT_RXINFO_RSSI BIT(13)
#define MT_RXINFO_L2PAD BIT(14)
#define MT_RXINFO_AMPDU BIT(15)
#define MT_RXINFO_DECRYPT BIT(16)
#define MT_RXINFO_BSSIDX3 BIT(17)
#define MT_RXINFO_WAPI_KEY BIT(18)
#define MT_RXINFO_PN_LEN GENMASK(21, 19)
#define MT_RXINFO_SW_FTYPE0 BIT(22)
#define MT_RXINFO_SW_FTYPE1 BIT(23)
#define MT_RXINFO_PROBE_RESP BIT(24)
#define MT_RXINFO_BEACON BIT(25)
#define MT_RXINFO_DISASSOC BIT(26)
#define MT_RXINFO_DEAUTH BIT(27)
#define MT_RXINFO_ACTION BIT(28)
#define MT_RXINFO_TCP_SUM_ERR BIT(30)
#define MT_RXINFO_IP_SUM_ERR BIT(31)
#define MT_RXWI_CTL_WCID GENMASK(7, 0)
#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
#define MT_RXWI_CTL_UDF GENMASK(15, 13)
#define MT_RXWI_CTL_MPDU_LEN GENMASK(29, 16)
#define MT_RXWI_CTL_EOF BIT(31)
#define MT_RXWI_TID GENMASK(3, 0)
#define MT_RXWI_SN GENMASK(15, 4)
#define MT_RXWI_RATE_INDEX GENMASK(5, 0)
#define MT_RXWI_RATE_LDPC BIT(6)
#define MT_RXWI_RATE_BW GENMASK(8, 7)
#define MT_RXWI_RATE_SGI BIT(9)
#define MT_RXWI_RATE_STBC BIT(10)
#define MT_RXWI_RATE_LDPC_EXSYM BIT(11)
#define MT_RXWI_RATE_PHY GENMASK(15, 13)
#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0)
#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4)
struct mt76x02_rxwi {
__le32 rxinfo;
__le32 ctl;
__le16 tid_sn;
__le16 rate;
u8 rssi[4];
__le32 bbp_rxinfo[4];
};
#define MT_TX_PWR_ADJ GENMASK(3, 0)
enum mt76x2_phy_bandwidth {
MT_PHY_BW_20,
MT_PHY_BW_40,
MT_PHY_BW_80,
};
#define MT_TXWI_FLAGS_FRAG BIT(0)
#define MT_TXWI_FLAGS_MMPS BIT(1)
#define MT_TXWI_FLAGS_CFACK BIT(2)
#define MT_TXWI_FLAGS_TS BIT(3)
#define MT_TXWI_FLAGS_AMPDU BIT(4)
#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
#define MT_TXWI_FLAGS_NDPS BIT(10)
#define MT_TXWI_FLAGS_RTSBWSIG BIT(11)
#define MT_TXWI_FLAGS_NDP_BW GENMASK(13, 12)
#define MT_TXWI_FLAGS_SOUND BIT(14)
#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
#define MT_TXWI_ACK_CTL_REQ BIT(0)
#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
#define MT_TXWI_PKTID_PROBE BIT(7)
struct mt76x02_txwi {
__le16 flags;
__le16 rate;
u8 ack_ctl;
u8 wcid;
__le16 len_ctl;
__le32 iv;
__le32 eiv;
u8 aid;
u8 txstream;
u8 ctl2;
u8 pktid;
} __packed __aligned(4);
static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
{
const u32 MAC_CSR0 = 0x1000;
......@@ -72,7 +180,8 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
}
void mt76x02_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq);
void mt76x02_mac_fill_txwi(struct mt76x02_txwi *txwi, struct sk_buff *skb,
struct ieee80211_sta *sta, int len, u8 nss);
enum mt76x02_cipher_type
mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data);
......@@ -82,4 +191,15 @@ int mt76x02_mac_wcid_set_key(struct mt76_dev *dev, u8 idx,
struct ieee80211_key_conf *key);
void mt76x02_mac_wcid_setup(struct mt76_dev *dev, u8 idx, u8 vif_idx, u8 *mac);
void mt76x02_mac_wcid_set_drop(struct mt76_dev *dev, u8 idx, bool drop);
void mt76x02_mac_wcid_set_rate(struct mt76_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate);
__le16
mt76x02_mac_tx_rate_val(struct mt76_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val);
bool mt76x02_mac_load_tx_status(struct mt76_dev *dev,
struct mt76x02_tx_status *stat);
void mt76x02_send_tx_status(struct mt76_dev *dev,
struct mt76x02_tx_status *stat, u8 *update);
int
mt76x02_mac_process_rate(struct mt76_rx_status *status, u16 rate);
#endif
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include "mt76.h"
#include "mt76x02_mcu.h"
#include "mt76x02_dma.h"
struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len)
{
struct sk_buff *skb;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
memcpy(skb_put(skb, len), data, len);
return skb;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_alloc);
static struct sk_buff *
mt76x02_mcu_get_response(struct mt76_dev *dev, unsigned long expires)
{
unsigned long timeout;
if (!time_is_after_jiffies(expires))
return NULL;
timeout = expires - jiffies;
wait_event_timeout(dev->mmio.mcu.wait,
!skb_queue_empty(&dev->mmio.mcu.res_q),
timeout);
return skb_dequeue(&dev->mmio.mcu.res_q);
}
static int
mt76x02_tx_queue_mcu(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, int cmd, int seq)
{
struct mt76_queue *q = &dev->q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
u32 tx_info;
tx_info = MT_MCU_MSG_TYPE_CMD |
FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
addr = dma_map_single(dev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev->dev, addr))
return -ENOMEM;
buf.addr = addr;
buf.len = skb->len;
spin_lock_bh(&q->lock);
dev->queue_ops->add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
dev->queue_ops->kick(dev, q);
spin_unlock_bh(&q->lock);
return 0;
}
int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
unsigned long expires = jiffies + HZ;
int ret;
u8 seq;
if (!skb)
return -EINVAL;
mutex_lock(&dev->mmio.mcu.mutex);
seq = ++dev->mmio.mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mmio.mcu.msg_seq & 0xf;
ret = mt76x02_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq);
if (ret)
goto out;
while (wait_resp) {
u32 *rxfce;
bool check_seq = false;
skb = mt76x02_mcu_get_response(dev, expires);
if (!skb) {
dev_err(dev->dev,
"MCU message %d (seq %d) timed out\n", cmd,
seq);
ret = -ETIMEDOUT;
break;
}
rxfce = (u32 *) skb->cb;
if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
check_seq = true;
dev_kfree_skb(skb);
if (check_seq)
break;
}
out:
mutex_unlock(&dev->mmio.mcu.mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_msg_send);
int mt76x02_mcu_function_select(struct mt76_dev *dev,
enum mcu_function func,
u32 val, bool wait_resp)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(func),
.value = cpu_to_le32(val),
};
skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg));
return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_FUN_SET_OP,
wait_resp);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on,
bool wait_resp)
{
struct sk_buff *skb;
struct {
__le32 mode;
__le32 level;
} __packed __aligned(4) msg = {
.mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
.level = cpu_to_le32(0),
};
skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg));
return dev->mcu_ops->mcu_send_msg(dev, skb, CMD_POWER_SAVING_OP,
wait_resp);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type,
u32 param, bool wait)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(type),
.value = cpu_to_le32(param),
};
int ret;
if (wait)
dev->bus->rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
skb = dev->mcu_ops->mcu_msg_alloc(&msg, sizeof(msg));
ret = dev->mcu_ops->mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true);
if (ret)
return ret;
if (wait &&
WARN_ON(!__mt76_poll_msec(dev, MT_MCU_COM_REG0,
BIT(31), BIT(31), 100)))
return -ETIMEDOUT;
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_calibrate);
int mt76x02_mcu_cleanup(struct mt76_dev *dev)
{
struct sk_buff *skb;
dev->bus->wr(dev, MT_MCU_INT_LEVEL, 1);
usleep_range(20000, 30000);
while ((skb = skb_dequeue(&dev->mmio.mcu.res_q)) != NULL)
dev_kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_cleanup);
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __MT76x02_MCU_H
#define __MT76x0x_MCU_H
#define MT_MCU_RESET_CTL 0x070C
#define MT_MCU_INT_LEVEL 0x0718
#define MT_MCU_COM_REG0 0x0730
#define MT_MCU_COM_REG1 0x0734
#define MT_MCU_COM_REG2 0x0738
#define MT_MCU_COM_REG3 0x073C
#define MT_INBAND_PACKET_MAX_LEN 192
#define MT_MCU_MEMMAP_WLAN 0x410000
enum mcu_cmd {
CMD_FUN_SET_OP = 1,
CMD_LOAD_CR = 2,
CMD_INIT_GAIN_OP = 3,
CMD_DYNC_VGA_OP = 6,
CMD_TDLS_CH_SW = 7,
CMD_BURST_WRITE = 8,
CMD_READ_MODIFY_WRITE = 9,
CMD_RANDOM_READ = 10,
CMD_BURST_READ = 11,
CMD_RANDOM_WRITE = 12,
CMD_LED_MODE_OP = 16,
CMD_POWER_SAVING_OP = 20,
CMD_WOW_CONFIG = 21,
CMD_WOW_QUERY = 22,
CMD_WOW_FEATURE = 24,
CMD_CARRIER_DETECT_OP = 28,
CMD_RADOR_DETECT_OP = 29,
CMD_SWITCH_CHANNEL_OP = 30,
CMD_CALIBRATION_OP = 31,
CMD_BEACON_OP = 32,
CMD_ANTENNA_OP = 33,
};
enum mcu_power_mode {
RADIO_OFF = 0x30,
RADIO_ON = 0x31,
RADIO_OFF_AUTO_WAKEUP = 0x32,
RADIO_OFF_ADVANCE = 0x33,
RADIO_ON_ADVANCE = 0x34,
};
enum mcu_function {
Q_SELECT = 1,
BW_SETTING = 2,
USB2_SW_DISCONNECT = 2,
USB3_SW_DISCONNECT = 3,
LOG_FW_DEBUG_MSG = 4,
GET_FW_VERSION = 5,
};
struct mt76x02_fw_header {
__le32 ilm_len;
__le32 dlm_len;
__le16 build_ver;
__le16 fw_ver;
u8 pad[4];
char build_time[16];
};
struct mt76x02_patch_header {
char build_time[16];
char platform[4];
char hw_version[4];
char patch_version[4];
u8 pad[2];
};
int mt76x02_mcu_cleanup(struct mt76_dev *dev);
int mt76x02_mcu_calibrate(struct mt76_dev *dev, int type,
u32 param, bool wait);
struct sk_buff *mt76x02_mcu_msg_alloc(const void *data, int len);
int mt76x02_mcu_msg_send(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp);
int mt76x02_mcu_function_select(struct mt76_dev *dev,
enum mcu_function func,
u32 val, bool wait_resp);
int mt76x02_mcu_set_radio_state(struct mt76_dev *dev, bool on,
bool wait_resp);
#endif /* __MT76x02_MCU_H */
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -14,16 +14,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __MT76x2_DMA_H
#define __MT76x2_DMA_H
#ifndef __MT76x02_USB_H
#define __MT76x0x_USB_H
#include "dma.h"
#include "mt76.h"
enum mt76x2_qsel {
MT_QSEL_MGMT,
MT_QSEL_HCCA,
MT_QSEL_EDCA,
MT_QSEL_EDCA_2,
};
void mt76x02u_init_mcu(struct mt76_dev *dev);
void mt76x02u_mcu_fw_reset(struct mt76_dev *dev);
int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
int data_len, u32 max_payload, u32 offset);
#endif
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags);
int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep);
#endif /* __MT76x02_USB_H */
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "mt76.h"
#include "mt76x02_dma.h"
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
{
struct sk_buff *iter, *last = skb;
u32 info, pad;
/* Buffer layout:
* | 4B | xfer len | pad | 4B |
* | TXINFO | pkt/cmd | zero pad to 4B | zero |
*
* length field of TXINFO should be set to 'xfer len'.
*/
info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
put_unaligned_le32(info, skb_push(skb, sizeof(info)));
pad = round_up(skb->len, 4) + 4 - skb->len;
skb_walk_frags(skb, iter) {
last = iter;
if (!iter->next) {
skb->data_len += pad;
skb->len += pad;
break;
}
}
if (unlikely(pad)) {
if (__skb_pad(last, pad, true))
return -ENOMEM;
__skb_put(last, pad);
}
return 0;
}
int mt76x02u_set_txinfo(struct sk_buff *skb, struct mt76_wcid *wcid, u8 ep)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
enum mt76_qsel qsel;
u32 flags;
if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
ep == MT_EP_OUT_HCCA)
qsel = MT_QSEL_MGMT;
else
qsel = MT_QSEL_EDCA;
flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
MT_TXD_INFO_80211;
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
flags |= MT_TXD_INFO_WIV;
return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags);
}
EXPORT_SYMBOL_GPL(mt76x02u_set_txinfo);
/*
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/firmware.h>
#include "mt76.h"
#include "mt76x02_dma.h"
#include "mt76x02_mcu.h"
#include "mt76x02_usb.h"
#define MT_CMD_HDR_LEN 4
#define MT_FCE_DMA_ADDR 0x0230
#define MT_FCE_DMA_LEN 0x0234
#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
static struct sk_buff *
mt76x02u_mcu_msg_alloc(const void *data, int len)
{
struct sk_buff *skb;
skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL);
if (!skb)
return NULL;
skb_reserve(skb, MT_CMD_HDR_LEN);
skb_put_data(skb, data, len);
return skb;
}
static void
mt76x02u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data, int len)
{
struct mt76_usb *usb = &dev->usb;
u32 reg, val;
int i;
if (usb->mcu.burst) {
WARN_ON_ONCE(len / 4 != usb->mcu.rp_len);
reg = usb->mcu.rp[0].reg - usb->mcu.base;
for (i = 0; i < usb->mcu.rp_len; i++) {
val = get_unaligned_le32(data + 4 * i);
usb->mcu.rp[i].reg = reg++;
usb->mcu.rp[i].value = val;
}
} else {
WARN_ON_ONCE(len / 8 != usb->mcu.rp_len);
for (i = 0; i < usb->mcu.rp_len; i++) {
reg = get_unaligned_le32(data + 8 * i) -
usb->mcu.base;
val = get_unaligned_le32(data + 8 * i + 4);
WARN_ON_ONCE(usb->mcu.rp[i].reg != reg);
usb->mcu.rp[i].value = val;
}
}
}
static int mt76x02u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
{
struct mt76_usb *usb = &dev->usb;
struct mt76u_buf *buf = &usb->mcu.res;
struct urb *urb = buf->urb;
int i, ret;
u32 rxfce;
u8 *data;
for (i = 0; i < 5; i++) {
if (!wait_for_completion_timeout(&usb->mcu.cmpl,
msecs_to_jiffies(300)))
continue;
if (urb->status)
return -EIO;
data = sg_virt(&urb->sg[0]);
if (usb->mcu.rp)
mt76x02u_multiple_mcu_reads(dev, data + 4,
urb->actual_length - 8);
rxfce = get_unaligned_le32(data);
ret = mt76u_submit_buf(dev, USB_DIR_IN,
MT_EP_IN_CMD_RESP,
buf, GFP_KERNEL,
mt76u_mcu_complete_urb,
&usb->mcu.cmpl);
if (ret)
return ret;
if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) &&
FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE)
return 0;
dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
}
dev_err(dev->dev, "error: %s timed out\n", __func__);
return -ETIMEDOUT;
}
static int
__mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
struct usb_interface *intf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
unsigned int pipe;
int ret, sent;
u8 seq = 0;
u32 info;
if (!skb)
return -EINVAL;
if (test_bit(MT76_REMOVED, &dev->state))
return 0;
pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]);
if (wait_resp) {
seq = ++usb->mcu.msg_seq & 0xf;
if (!seq)
seq = ++usb->mcu.msg_seq & 0xf;
}
info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
MT_MCU_MSG_TYPE_CMD;
ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info);
if (ret)
return ret;
ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500);
if (ret)
return ret;
if (wait_resp)
ret = mt76x02u_mcu_wait_resp(dev, seq);
consume_skb(skb);
return ret;
}
static int
mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
struct mt76_usb *usb = &dev->usb;
int err;
mutex_lock(&usb->mcu.mutex);
err = __mt76x02u_mcu_send_msg(dev, skb, cmd, wait_resp);
mutex_unlock(&usb->mcu.mutex);
return err;
}
static inline void skb_put_le32(struct sk_buff *skb, u32 val)
{
put_unaligned_le32(val, skb_put(skb, 4));
}
static int
mt76x02u_mcu_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data, int n)
{
const int CMD_RANDOM_WRITE = 12;
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
struct sk_buff *skb;
int cnt, i, ret;
if (!n)
return 0;
cnt = min(max_vals_per_cmd, n);
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
for (i = 0; i < cnt; i++) {
skb_put_le32(skb, base + data[i].reg);
skb_put_le32(skb, data[i].value);
}
ret = mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_WRITE, cnt == n);
if (ret)
return ret;
return mt76x02u_mcu_wr_rp(dev, base, data + cnt, n - cnt);
}
static int
mt76x02u_mcu_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data, int n)
{
const int CMD_RANDOM_READ = 10;
const int max_vals_per_cmd = MT_INBAND_PACKET_MAX_LEN / 8;
struct mt76_usb *usb = &dev->usb;
struct sk_buff *skb;
int cnt, i, ret;
if (!n)
return 0;
cnt = min(max_vals_per_cmd, n);
if (cnt != n)
return -EINVAL;
skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_reserve(skb, MT_DMA_HDR_LEN);
for (i = 0; i < cnt; i++) {
skb_put_le32(skb, base + data[i].reg);
skb_put_le32(skb, data[i].value);
}
mutex_lock(&usb->mcu.mutex);
usb->mcu.rp = data;
usb->mcu.rp_len = n;
usb->mcu.base = base;
usb->mcu.burst = false;
ret = __mt76x02u_mcu_send_msg(dev, skb, CMD_RANDOM_READ, true);
usb->mcu.rp = NULL;
mutex_unlock(&usb->mcu.mutex);
return ret;
}
void mt76x02u_mcu_fw_reset(struct mt76_dev *dev)
{
mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x1, 0, NULL, 0);
}
EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_reset);
static int
__mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf,
const void *fw_data, int len, u32 dst_addr)
{
u8 *data = sg_virt(&buf->urb->sg[0]);
DECLARE_COMPLETION_ONSTACK(cmpl);
__le32 info;
u32 val;
int err;
info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, len) |
MT_MCU_MSG_TYPE_CMD);
memcpy(data, &info, sizeof(info));
memcpy(data + sizeof(info), fw_data, len);
memset(data + sizeof(info) + len, 0, 4);
mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
MT_FCE_DMA_ADDR, dst_addr);
len = roundup(len, 4);
mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
MT_FCE_DMA_LEN, len << 16);
buf->len = MT_CMD_HDR_LEN + len + sizeof(info);
err = mt76u_submit_buf(dev, USB_DIR_OUT,
MT_EP_OUT_INBAND_CMD,
buf, GFP_KERNEL,
mt76u_mcu_complete_urb, &cmpl);
if (err < 0)
return err;
if (!wait_for_completion_timeout(&cmpl,
msecs_to_jiffies(1000))) {
dev_err(dev->dev, "firmware upload timed out\n");
usb_kill_urb(buf->urb);
return -ETIMEDOUT;
}
if (mt76u_urb_error(buf->urb)) {
dev_err(dev->dev, "firmware upload failed: %d\n",
buf->urb->status);
return buf->urb->status;
}
val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
val++;
mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
return 0;
}
int mt76x02u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
int data_len, u32 max_payload, u32 offset)
{
int err, len, pos = 0, max_len = max_payload - 8;
struct mt76u_buf buf;
err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload,
GFP_KERNEL);
if (err < 0)
return err;
while (data_len > 0) {
len = min_t(int, data_len, max_len);
err = __mt76x02u_mcu_fw_send_data(dev, &buf, data + pos,
len, offset + pos);
if (err < 0)
break;
data_len -= len;
pos += len;
usleep_range(5000, 10000);
}
mt76u_buf_free(&buf);
return err;
}
EXPORT_SYMBOL_GPL(mt76x02u_mcu_fw_send_data);
void mt76x02u_init_mcu(struct mt76_dev *dev)
{
static const struct mt76_mcu_ops mt76x02u_mcu_ops = {
.mcu_msg_alloc = mt76x02u_mcu_msg_alloc,
.mcu_send_msg = mt76x02u_mcu_send_msg,
.mcu_wr_rp = mt76x02u_mcu_wr_rp,
.mcu_rd_rp = mt76x02u_mcu_rd_rp,
};
dev->mcu_ops = &mt76x02u_mcu_ops;
}
EXPORT_SYMBOL_GPL(mt76x02u_init_mcu);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");
......@@ -16,7 +16,38 @@
*/
#include "mt76.h"
#include "mt76x02_dma.h"
#include "mt76x02_regs.h"
#include "mt76x02_mac.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) | (8 + _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, \
}
struct ieee80211_rate mt76x02_rates[] = {
CCK_RATE(0, 10),
CCK_RATE(1, 20),
CCK_RATE(2, 55),
CCK_RATE(3, 110),
OFDM_RATE(0, 60),
OFDM_RATE(1, 90),
OFDM_RATE(2, 120),
OFDM_RATE(3, 180),
OFDM_RATE(4, 240),
OFDM_RATE(5, 360),
OFDM_RATE(6, 480),
OFDM_RATE(7, 540),
};
EXPORT_SYMBOL_GPL(mt76x02_rates);
void mt76x02_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
......@@ -52,4 +83,374 @@ void mt76x02_configure_filter(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL_GPL(mt76x02_configure_filter);
int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
int ret = 0;
int idx = 0;
int i;
mutex_lock(&dev->mutex);
idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid));
if (idx < 0) {
ret = -ENOSPC;
goto out;
}
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
msta->wcid.hw_key_idx = -1;
mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
mt76x02_mac_wcid_set_drop(dev, idx, false);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76x02_txq_init(dev, sta->txq[i]);
if (vif->type == NL80211_IFTYPE_AP)
set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
ewma_signal_init(&msta->rssi);
rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
out:
mutex_unlock(&dev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mt76x02_sta_add);
int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
int idx = msta->wcid.idx;
int i;
mutex_lock(&dev->mutex);
rcu_assign_pointer(dev->wcid[idx], NULL);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76_txq_remove(dev, sta->txq[i]);
mt76x02_mac_wcid_set_drop(dev, idx, true);
mt76_wcid_free(dev->wcid_mask, idx);
mt76x02_mac_wcid_setup(dev, idx, 0, NULL);
mutex_unlock(&dev->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_sta_remove);
void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif,
unsigned int idx)
{
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
mvif->idx = idx;
mvif->group_wcid.idx = MT_VIF_WCID(idx);
mvif->group_wcid.hw_key_idx = -1;
mt76x02_txq_init(dev, vif->txq);
}
EXPORT_SYMBOL_GPL(mt76x02_vif_init);
int
mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct mt76_dev *dev = hw->priv;
unsigned int idx = 0;
if (vif->addr[0] & BIT(1))
idx = 1 + (((dev->macaddr[0] ^ vif->addr[0]) >> 2) & 7);
/*
* Client mode typically only has one configurable BSSID register,
* which is used for bssidx=0. This is linked to the MAC address.
* Since mac80211 allows changing interface types, and we cannot
* force the use of the primary MAC address for a station mode
* interface, we need some other way of configuring a per-interface
* remote BSSID.
* The hardware provides an AP-Client feature, where bssidx 0-7 are
* used for AP mode and bssidx 8-15 for client mode.
* We shift the station interface bss index by 8 to force the
* hardware to recognize the BSSID.
* The resulting bssidx mismatch for unicast frames is ignored by hw.
*/
if (vif->type == NL80211_IFTYPE_STATION)
idx += 8;
mt76x02_vif_init(dev, vif, idx);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_add_interface);
void mt76x02_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76_dev *dev = hw->priv;
mt76_txq_remove(dev, vif->txq);
}
EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
enum ieee80211_ampdu_mlme_action action = params->action;
struct ieee80211_sta *sta = params->sta;
struct mt76_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct ieee80211_txq *txq = sta->txq[params->tid];
u16 tid = params->tid;
u16 *ssn = &params->ssn;
struct mt76_txq *mtxq;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(dev, &msta->wcid, tid, *ssn, params->buf_size);
__mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(dev, &msta->wcid, tid);
__mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = *ssn << 4;
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_ampdu_action);
int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct mt76_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
struct mt76x02_sta *msta;
struct mt76_wcid *wcid;
int idx = key->keyidx;
int ret;
/* fall back to sw encryption for unsupported ciphers */
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
break;
default:
return -EOPNOTSUPP;
}
/*
* The hardware does not support per-STA RX GTK, fall back
* to software mode for these.
*/
if ((vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
(key->cipher == WLAN_CIPHER_SUITE_TKIP ||
key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL;
wcid = msta ? &msta->wcid : &mvif->group_wcid;
if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = idx;
if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
wcid->sw_iv = true;
}
} else {
if (idx == wcid->hw_key_idx) {
wcid->hw_key_idx = -1;
wcid->sw_iv = true;
}
key = NULL;
}
mt76_wcid_key_setup(dev, wcid, key);
if (!msta) {
if (key || wcid->hw_key_idx == idx) {
ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key);
if (ret)
return ret;
}
return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key);
}
return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key);
}
EXPORT_SYMBOL_GPL(mt76x02_set_key);
int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params)
{
struct mt76_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10, qid;
u32 val;
qid = dev->q_tx[queue].hw_idx;
if (params->cw_min)
cw_min = fls(params->cw_min);
if (params->cw_max)
cw_max = fls(params->cw_max);
val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
__mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
val = __mt76_rr(dev, MT_WMM_TXOP(qid));
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
__mt76_wr(dev, MT_WMM_TXOP(qid), val);
val = __mt76_rr(dev, MT_WMM_AIFSN);
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
__mt76_wr(dev, MT_WMM_AIFSN, val);
val = __mt76_rr(dev, MT_WMM_CWMIN);
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
__mt76_wr(dev, MT_WMM_CWMIN, val);
val = __mt76_rr(dev, MT_WMM_CWMAX);
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
__mt76_wr(dev, MT_WMM_CWMAX, val);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x02_conf_tx);
void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
struct ieee80211_tx_rate rate = {};
if (!rates)
return;
rate.idx = rates->rate[0].idx;
rate.flags = rates->rate[0].flags;
mt76x02_mac_wcid_set_rate(dev, &msta->wcid, &rate);
if (dev->drv && dev->drv->get_max_txpwr_adj)
msta->wcid.max_txpwr_adj = dev->drv->get_max_txpwr_adj(dev, &rate);
}
EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update);
int mt76x02_insert_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
if (len % 4 == 0)
return 0;
skb_push(skb, 2);
memmove(skb->data, skb->data + 2, len);
skb->data[len] = 0;
skb->data[len + 1] = 0;
return 2;
}
EXPORT_SYMBOL_GPL(mt76x02_insert_hdr_pad);
void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len)
{
int hdrlen;
if (!len)
return;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + len, skb->data, hdrlen);
skb_pull(skb, len);
}
EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad);
static void mt76x02_remove_dma_hdr(struct sk_buff *skb)
{
int hdr_len;
skb_pull(skb, sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN);
hdr_len = ieee80211_get_hdrlen_from_skb(skb);
if (hdr_len % 4)
mt76x02_remove_hdr_pad(skb, 2);
}
void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
ieee80211_free_txskb(dev->hw, skb);
} else {
ieee80211_tx_info_clear_status(info);
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status(dev->hw, skb);
}
}
EXPORT_SYMBOL_GPL(mt76x02_tx_complete);
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush)
{
mt76x02_remove_dma_hdr(e->skb);
mt76x02_tx_complete(mdev, e->skb);
}
EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update)
{
struct mt76x02_tx_status stat;
if (!mt76x02_mac_load_tx_status(dev, &stat))
return false;
mt76x02_send_tx_status(dev, &stat, update);
return true;
}
EXPORT_SYMBOL_GPL(mt76x02_tx_status_data);
MODULE_LICENSE("Dual BSD/GPL");
......@@ -18,8 +18,37 @@
#ifndef __MT76X02_UTIL_H
#define __MT76X02_UTIL_H
extern struct ieee80211_rate mt76x02_rates[12];
void mt76x02_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags, u64 multicast);
int mt76x02_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt76x02_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt76x02_vif_init(struct mt76_dev *dev, struct ieee80211_vif *vif,
unsigned int idx);
int mt76x02_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void mt76x02_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params);
void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt76x02_insert_hdr_pad(struct sk_buff *skb);
void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len);
void mt76x02_tx_complete(struct mt76_dev *dev, struct sk_buff *skb);
void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush);
bool mt76x02_tx_status_data(struct mt76_dev *dev, u8 *update);
#endif
......@@ -42,24 +42,11 @@
#define MT_CALIBRATE_INTERVAL HZ
#define MT_MAX_VIFS 8
#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
#include "mt76.h"
#include "mt76x02_regs.h"
#include "mt76x2_mac.h"
#include "mt76x2_dfs.h"
struct mt76x2_mcu {
struct mutex mutex;
wait_queue_head_t wait;
struct sk_buff_head res_q;
struct mt76u_buf res_u;
u32 msg_seq;
};
struct mt76x2_rx_freq_cal {
s8 high_gain[MT_MAX_CHAINS];
s8 rssi_offset[MT_MAX_CHAINS];
......@@ -95,15 +82,12 @@ struct mt76x2_dev {
struct mutex mutex;
const u16 *beacon_offsets;
unsigned long wcid_mask[128 / BITS_PER_LONG];
int txpower_conf;
int txpower_cur;
u8 txdone_seq;
DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
struct mt76x2_mcu mcu;
struct sk_buff *rx_head;
struct tasklet_struct tx_tasklet;
......@@ -113,9 +97,6 @@ struct mt76x2_dev {
u32 aggr_stats[32];
struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[128];
spinlock_t irq_lock;
u32 irqmask;
......@@ -183,8 +164,6 @@ static inline bool wait_for_wpdma(struct mt76x2_dev *dev)
extern const struct ieee80211_ops mt76x2_ops;
extern struct ieee80211_rate mt76x2_rates[12];
struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev);
int mt76x2_register_device(struct mt76x2_dev *dev);
void mt76x2_init_debugfs(struct mt76x2_dev *dev);
......@@ -209,21 +188,16 @@ void mt76x2_phy_set_txpower(struct mt76x2_dev *dev);
int mt76x2_mcu_init(struct mt76x2_dev *dev);
int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
u8 bw_index, bool scan);
int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on);
int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel);
int mt76x2_mcu_cleanup(struct mt76x2_dev *dev);
int mt76x2_dma_init(struct mt76x2_dev *dev);
void mt76x2_dma_cleanup(struct mt76x2_dev *dev);
void mt76x2_cleanup(struct mt76x2_dev *dev);
int mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, int cmd, int seq);
void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb);
void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb);
int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
......@@ -242,40 +216,28 @@ void mt76x2_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps);
void mt76x2_update_channel(struct mt76_dev *mdev);
s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev,
s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *dev,
const struct ieee80211_tx_rate *rate);
s8 mt76x2_tx_get_txpwr_adj(struct mt76x2_dev *dev, s8 txpwr, s8 max_txpwr_adj);
void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr);
int mt76x2_insert_hdr_pad(struct sk_buff *skb);
bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev,
struct mt76x02_tx_status *stat);
void mt76x2_send_tx_status(struct mt76x2_dev *dev,
struct mt76x02_tx_status *stat, u8 *update);
void mt76x2_reset_wlan(struct mt76x2_dev *dev, bool enable);
void mt76x2_init_txpower(struct mt76x2_dev *dev,
struct ieee80211_supported_band *sband);
void mt76_write_mac_initvals(struct mt76x2_dev *dev);
int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt76x2_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params);
void mt76x2_txq_init(struct mt76x2_dev *dev, struct ieee80211_txq *txq);
void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait);
void mt76x2_phy_set_txpower_regs(struct mt76x2_dev *dev,
enum nl80211_band band);
void mt76x2_configure_tx_delay(struct mt76x2_dev *dev,
......
......@@ -18,258 +18,6 @@
#include "mt76x2.h"
#include "mt76x02_mac.h"
int mt76x2_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
enum ieee80211_ampdu_mlme_action action = params->action;
struct ieee80211_sta *sta = params->sta;
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct ieee80211_txq *txq = sta->txq[params->tid];
u16 tid = params->tid;
u16 *ssn = &params->ssn;
struct mt76_txq *mtxq;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn, params->buf_size);
mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
BIT(16 + tid));
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = *ssn << 4;
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76x2_ampdu_action);
int mt76x2_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
int ret = 0;
int idx = 0;
int i;
mutex_lock(&dev->mt76.mutex);
idx = mt76_wcid_alloc(dev->wcid_mask, ARRAY_SIZE(dev->wcid));
if (idx < 0) {
ret = -ENOSPC;
goto out;
}
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
msta->wcid.hw_key_idx = -1;
mt76x02_mac_wcid_setup(&dev->mt76, idx, mvif->idx, sta->addr);
mt76x02_mac_wcid_set_drop(&dev->mt76, idx, false);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76x02_txq_init(&dev->mt76, sta->txq[i]);
if (vif->type == NL80211_IFTYPE_AP)
set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
ewma_signal_init(&msta->rssi);
rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
EXPORT_SYMBOL_GPL(mt76x2_sta_add);
int mt76x2_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
int idx = msta->wcid.idx;
int i;
mutex_lock(&dev->mt76.mutex);
rcu_assign_pointer(dev->wcid[idx], NULL);
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
mt76_txq_remove(&dev->mt76, sta->txq[i]);
mt76x02_mac_wcid_set_drop(&dev->mt76, idx, true);
mt76_wcid_free(dev->wcid_mask, idx);
mt76x02_mac_wcid_setup(&dev->mt76, idx, 0, NULL);
mutex_unlock(&dev->mt76.mutex);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x2_sta_remove);
void mt76x2_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76x2_dev *dev = hw->priv;
mt76_txq_remove(&dev->mt76, vif->txq);
}
EXPORT_SYMBOL_GPL(mt76x2_remove_interface);
int mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
struct mt76x02_sta *msta;
struct mt76_wcid *wcid;
int idx = key->keyidx;
int ret;
/* fall back to sw encryption for unsupported ciphers */
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
break;
default:
return -EOPNOTSUPP;
}
/*
* The hardware does not support per-STA RX GTK, fall back
* to software mode for these.
*/
if ((vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
(key->cipher == WLAN_CIPHER_SUITE_TKIP ||
key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL;
wcid = msta ? &msta->wcid : &mvif->group_wcid;
if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = idx;
if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
wcid->sw_iv = true;
}
} else {
if (idx == wcid->hw_key_idx) {
wcid->hw_key_idx = -1;
wcid->sw_iv = true;
}
key = NULL;
}
mt76_wcid_key_setup(&dev->mt76, wcid, key);
if (!msta) {
if (key || wcid->hw_key_idx == idx) {
ret = mt76x02_mac_wcid_set_key(&dev->mt76, wcid->idx, key);
if (ret)
return ret;
}
return mt76x02_mac_shared_key_setup(&dev->mt76, mvif->idx, idx, key);
}
return mt76x02_mac_wcid_set_key(&dev->mt76, msta->wcid.idx, key);
}
EXPORT_SYMBOL_GPL(mt76x2_set_key);
int mt76x2_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u16 queue, const struct ieee80211_tx_queue_params *params)
{
struct mt76x2_dev *dev = hw->priv;
u8 cw_min = 5, cw_max = 10, qid;
u32 val;
qid = dev->mt76.q_tx[queue].hw_idx;
if (params->cw_min)
cw_min = fls(params->cw_min);
if (params->cw_max)
cw_max = fls(params->cw_max);
val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) |
FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) |
FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) |
FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max);
mt76_wr(dev, MT_EDCA_CFG_AC(qid), val);
val = mt76_rr(dev, MT_WMM_TXOP(qid));
val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid));
val |= params->txop << MT_WMM_TXOP_SHIFT(qid);
mt76_wr(dev, MT_WMM_TXOP(qid), val);
val = mt76_rr(dev, MT_WMM_AIFSN);
val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid));
val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid);
mt76_wr(dev, MT_WMM_AIFSN, val);
val = mt76_rr(dev, MT_WMM_CWMIN);
val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid));
val |= cw_min << MT_WMM_CWMIN_SHIFT(qid);
mt76_wr(dev, MT_WMM_CWMIN, val);
val = mt76_rr(dev, MT_WMM_CWMAX);
val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid));
val |= cw_max << MT_WMM_CWMAX_SHIFT(qid);
mt76_wr(dev, MT_WMM_CWMAX, val);
return 0;
}
EXPORT_SYMBOL_GPL(mt76x2_conf_tx);
void mt76x2_sta_rate_tbl_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv;
struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates);
struct ieee80211_tx_rate rate = {};
if (!rates)
return;
rate.idx = rates->rate[0].idx;
rate.flags = rates->rate[0].flags;
mt76x2_mac_wcid_set_rate(dev, &msta->wcid, &rate);
msta->wcid.max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, &rate);
}
EXPORT_SYMBOL_GPL(mt76x2_sta_rate_tbl_update);
void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb)
{
......@@ -277,12 +25,13 @@ void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
void *rxwi = skb->data;
if (q == MT_RXQ_MCU) {
skb_queue_tail(&dev->mcu.res_q, skb);
wake_up(&dev->mcu.wait);
/* this is used just by mmio code */
skb_queue_tail(&mdev->mmio.mcu.res_q, skb);
wake_up(&mdev->mmio.mcu.wait);
return;
}
skb_pull(skb, sizeof(struct mt76x2_rxwi));
skb_pull(skb, sizeof(struct mt76x02_rxwi));
if (mt76x2_mac_process_rx(dev, skb, rxwi)) {
dev_kfree_skb(skb);
return;
......
......@@ -15,37 +15,7 @@
*/
#include "mt76x2.h"
#include "mt76x2_dma.h"
int
mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, int cmd, int seq)
{
struct mt76_queue *q = &dev->mt76.q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
u32 tx_info;
tx_info = MT_MCU_MSG_TYPE_CMD |
FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
addr = dma_map_single(dev->mt76.dev, skb->data, skb->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev->mt76.dev, addr))
return -ENOMEM;
buf.addr = addr;
buf.len = skb->len;
spin_lock_bh(&q->lock);
mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
mt76_queue_kick(dev, q);
spin_unlock_bh(&q->lock);
return 0;
}
#include "mt76x02_dma.h"
static int
mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
......@@ -53,7 +23,7 @@ mt76x2_init_tx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
{
int ret;
q->regs = dev->mt76.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
q->regs = dev->mt76.mmio.regs + MT_TX_RING_BASE + idx * MT_RING_SIZE;
q->ndesc = n_desc;
q->hw_idx = idx;
......@@ -72,7 +42,7 @@ mt76x2_init_rx_queue(struct mt76x2_dev *dev, struct mt76_queue *q,
{
int ret;
q->regs = dev->mt76.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE;
q->regs = dev->mt76.mmio.regs + MT_RX_RING_BASE + idx * MT_RING_SIZE;
q->ndesc = n_desc;
q->buf_size = bufsize;
......@@ -102,32 +72,23 @@ mt76x2_tx_tasklet(unsigned long data)
int mt76x2_dma_init(struct mt76x2_dev *dev)
{
static const u8 wmm_queue_map[] = {
[IEEE80211_AC_BE] = 0,
[IEEE80211_AC_BK] = 1,
[IEEE80211_AC_VI] = 2,
[IEEE80211_AC_VO] = 3,
};
int ret;
int i;
struct mt76_txwi_cache __maybe_unused *t;
struct mt76_queue *q;
BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x2_txwi));
BUILD_BUG_ON(sizeof(struct mt76x2_rxwi) > MT_RX_HEADROOM);
BUILD_BUG_ON(sizeof(t->txwi) < sizeof(struct mt76x02_txwi));
BUILD_BUG_ON(sizeof(struct mt76x02_rxwi) > MT_RX_HEADROOM);
mt76_dma_attach(&dev->mt76);
init_waitqueue_head(&dev->mcu.wait);
skb_queue_head_init(&dev->mcu.res_q);
tasklet_init(&dev->tx_tasklet, mt76x2_tx_tasklet, (unsigned long) dev);
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
ret = mt76x2_init_tx_queue(dev, &dev->mt76.q_tx[i],
wmm_queue_map[i], MT_TX_RING_SIZE);
mt76_ac_to_hwq(i), MT_TX_RING_SIZE);
if (ret)
return ret;
}
......@@ -148,7 +109,7 @@ int mt76x2_dma_init(struct mt76x2_dev *dev)
return ret;
q = &dev->mt76.q_rx[MT_RXQ_MAIN];
q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x2_rxwi);
q->buf_offset = MT_RX_HEADROOM - sizeof(struct mt76x02_rxwi);
ret = mt76x2_init_rx_queue(dev, q, 0, MT76x2_RX_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
return ret;
......
......@@ -18,6 +18,7 @@
#include "mt76x2.h"
#include "mt76x2_eeprom.h"
#include "mt76x2_mcu.h"
#include "mt76x02_util.h"
static void
mt76x2_mac_pbf_init(struct mt76x2_dev *dev)
......@@ -401,7 +402,7 @@ void mt76x2_stop_hardware(struct mt76x2_dev *dev)
{
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
mt76x2_mcu_set_radio_state(dev, false);
mt76x02_mcu_set_radio_state(&dev->mt76, false, true);
mt76x2_mac_stop(dev, false);
}
......@@ -411,19 +412,20 @@ void mt76x2_cleanup(struct mt76x2_dev *dev)
tasklet_disable(&dev->pre_tbtt_tasklet);
mt76x2_stop_hardware(dev);
mt76x2_dma_cleanup(dev);
mt76x2_mcu_cleanup(dev);
mt76x02_mcu_cleanup(&dev->mt76);
}
struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev)
{
static const struct mt76_driver_ops drv_ops = {
.txwi_size = sizeof(struct mt76x2_txwi),
.txwi_size = sizeof(struct mt76x02_txwi),
.update_survey = mt76x2_update_channel,
.tx_prepare_skb = mt76x2_tx_prepare_skb,
.tx_complete_skb = mt76x2_tx_complete_skb,
.rx_skb = mt76x2_queue_rx_skb,
.rx_poll_complete = mt76x2_rx_poll_complete,
.sta_ps = mt76x2_sta_ps,
.get_max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj,
};
struct mt76x2_dev *dev;
struct mt76_dev *mdev;
......@@ -583,8 +585,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev)
dev->mt76.led_cdev.brightness_set = mt76x2_led_set_brightness;
dev->mt76.led_cdev.blink_set = mt76x2_led_set_blink;
ret = mt76_register_device(&dev->mt76, true, mt76x2_rates,
ARRAY_SIZE(mt76x2_rates));
ret = mt76_register_device(&dev->mt76, true, mt76x02_rates,
ARRAY_SIZE(mt76x02_rates));
if (ret)
goto fail;
......
......@@ -18,35 +18,6 @@
#include "mt76x2.h"
#include "mt76x2_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) | (8 + _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, \
}
struct ieee80211_rate mt76x2_rates[] = {
CCK_RATE(0, 10),
CCK_RATE(1, 20),
CCK_RATE(2, 55),
CCK_RATE(3, 110),
OFDM_RATE(0, 60),
OFDM_RATE(1, 90),
OFDM_RATE(2, 120),
OFDM_RATE(3, 180),
OFDM_RATE(4, 240),
OFDM_RATE(5, 360),
OFDM_RATE(6, 480),
OFDM_RATE(7, 540),
};
EXPORT_SYMBOL_GPL(mt76x2_rates);
static void
mt76x2_set_wlan_state(struct mt76x2_dev *dev, bool enable)
{
......@@ -213,8 +184,8 @@ void mt76x2_init_device(struct mt76x2_dev *dev)
dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
dev->chainmask = 0x202;
dev->global_wcid.idx = 255;
dev->global_wcid.hw_key_idx = -1;
dev->mt76.global_wcid.idx = 255;
dev->mt76.global_wcid.hw_key_idx = -1;
dev->slottime = 9;
/* init antenna configuration */
......
......@@ -19,6 +19,7 @@
#include "mt76x2_mcu.h"
#include "mt76x2_eeprom.h"
#include "mt76x2_trace.h"
#include "mt76x02_util.h"
void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr)
{
......@@ -42,7 +43,7 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq)
while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
spin_lock_irqsave(&dev->irq_lock, flags);
ret = mt76x2_mac_load_tx_status(dev, &stat);
ret = mt76x02_mac_load_tx_status(&dev->mt76, &stat);
spin_unlock_irqrestore(&dev->irq_lock, flags);
if (!ret)
......@@ -51,7 +52,7 @@ void mt76x2_mac_poll_tx_status(struct mt76x2_dev *dev, bool irq)
trace_mac_txstat_fetch(dev, &stat);
if (!irq) {
mt76x2_send_tx_status(dev, &stat, &update);
mt76x02_send_tx_status(&dev->mt76, &stat, &update);
continue;
}
......@@ -64,7 +65,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb,
void *txwi_ptr)
{
struct mt76x2_tx_info *txi = mt76x2_skb_tx_info(skb);
struct mt76x2_txwi *txwi = txwi_ptr;
struct mt76x02_txwi *txwi = txwi_ptr;
mt76x2_mac_poll_tx_status(dev, false);
......@@ -73,7 +74,7 @@ mt76x2_mac_queue_txdone(struct mt76x2_dev *dev, struct sk_buff *skb,
txi->wcid = txwi->wcid;
txi->pktid = txwi->pktid;
trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid);
mt76x2_tx_complete(dev, skb);
mt76x02_tx_complete(&dev->mt76, skb);
}
void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev)
......@@ -82,7 +83,7 @@ void mt76x2_mac_process_tx_status_fifo(struct mt76x2_dev *dev)
u8 update = 1;
while (kfifo_get(&dev->txstatus_fifo, &stat))
mt76x2_send_tx_status(dev, &stat, &update);
mt76x02_send_tx_status(&dev->mt76, &stat, &update);
}
void mt76x2_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
......@@ -100,9 +101,9 @@ static int
mt76_write_beacon(struct mt76x2_dev *dev, int offset, struct sk_buff *skb)
{
int beacon_len = dev->beacon_offsets[1] - dev->beacon_offsets[0];
struct mt76x2_txwi txwi;
struct mt76x02_txwi txwi;
if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x2_txwi)))
if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
return -ENOSPC;
mt76x2_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
......
......@@ -23,7 +23,6 @@
struct mt76x2_dev;
struct mt76x2_sta;
struct mt76x02_vif;
struct mt76x2_txwi;
struct mt76x2_tx_info {
unsigned long jiffies;
......@@ -34,111 +33,6 @@ struct mt76x2_tx_info {
u8 retry;
};
struct mt76x2_rxwi {
__le32 rxinfo;
__le32 ctl;
__le16 tid_sn;
__le16 rate;
u8 rssi[4];
__le32 bbp_rxinfo[4];
};
#define MT_RXINFO_BA BIT(0)
#define MT_RXINFO_DATA BIT(1)
#define MT_RXINFO_NULL BIT(2)
#define MT_RXINFO_FRAG BIT(3)
#define MT_RXINFO_UNICAST BIT(4)
#define MT_RXINFO_MULTICAST BIT(5)
#define MT_RXINFO_BROADCAST BIT(6)
#define MT_RXINFO_MYBSS BIT(7)
#define MT_RXINFO_CRCERR BIT(8)
#define MT_RXINFO_ICVERR BIT(9)
#define MT_RXINFO_MICERR BIT(10)
#define MT_RXINFO_AMSDU BIT(11)
#define MT_RXINFO_HTC BIT(12)
#define MT_RXINFO_RSSI BIT(13)
#define MT_RXINFO_L2PAD BIT(14)
#define MT_RXINFO_AMPDU BIT(15)
#define MT_RXINFO_DECRYPT BIT(16)
#define MT_RXINFO_BSSIDX3 BIT(17)
#define MT_RXINFO_WAPI_KEY BIT(18)
#define MT_RXINFO_PN_LEN GENMASK(21, 19)
#define MT_RXINFO_SW_FTYPE0 BIT(22)
#define MT_RXINFO_SW_FTYPE1 BIT(23)
#define MT_RXINFO_PROBE_RESP BIT(24)
#define MT_RXINFO_BEACON BIT(25)
#define MT_RXINFO_DISASSOC BIT(26)
#define MT_RXINFO_DEAUTH BIT(27)
#define MT_RXINFO_ACTION BIT(28)
#define MT_RXINFO_TCP_SUM_ERR BIT(30)
#define MT_RXINFO_IP_SUM_ERR BIT(31)
#define MT_RXWI_CTL_WCID GENMASK(7, 0)
#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8)
#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10)
#define MT_RXWI_CTL_UDF GENMASK(15, 13)
#define MT_RXWI_CTL_MPDU_LEN GENMASK(29, 16)
#define MT_RXWI_CTL_EOF BIT(31)
#define MT_RXWI_TID GENMASK(3, 0)
#define MT_RXWI_SN GENMASK(15, 4)
#define MT_RXWI_RATE_INDEX GENMASK(5, 0)
#define MT_RXWI_RATE_LDPC BIT(6)
#define MT_RXWI_RATE_BW GENMASK(8, 7)
#define MT_RXWI_RATE_SGI BIT(9)
#define MT_RXWI_RATE_STBC BIT(10)
#define MT_RXWI_RATE_LDPC_EXSYM BIT(11)
#define MT_RXWI_RATE_PHY GENMASK(15, 13)
#define MT_RATE_INDEX_VHT_IDX GENMASK(3, 0)
#define MT_RATE_INDEX_VHT_NSS GENMASK(5, 4)
#define MT_TX_PWR_ADJ GENMASK(3, 0)
enum mt76x2_phy_bandwidth {
MT_PHY_BW_20,
MT_PHY_BW_40,
MT_PHY_BW_80,
};
#define MT_TXWI_FLAGS_FRAG BIT(0)
#define MT_TXWI_FLAGS_MMPS BIT(1)
#define MT_TXWI_FLAGS_CFACK BIT(2)
#define MT_TXWI_FLAGS_TS BIT(3)
#define MT_TXWI_FLAGS_AMPDU BIT(4)
#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5)
#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8)
#define MT_TXWI_FLAGS_NDPS BIT(10)
#define MT_TXWI_FLAGS_RTSBWSIG BIT(11)
#define MT_TXWI_FLAGS_NDP_BW GENMASK(13, 12)
#define MT_TXWI_FLAGS_SOUND BIT(14)
#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15)
#define MT_TXWI_ACK_CTL_REQ BIT(0)
#define MT_TXWI_ACK_CTL_NSEQ BIT(1)
#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2)
#define MT_TXWI_PKTID_PROBE BIT(7)
struct mt76x2_txwi {
__le16 flags;
__le16 rate;
u8 ack_ctl;
u8 wcid;
__le16 len_ctl;
__le32 iv;
__le32 eiv;
u8 aid;
u8 txstream;
u8 ctl2;
u8 pktid;
} __packed __aligned(4);
static inline struct mt76x2_tx_info *
mt76x2_skb_tx_info(struct sk_buff *skb)
{
......@@ -154,11 +48,9 @@ void mt76x2_mac_set_bssid(struct mt76x2_dev *dev, u8 idx, const u8 *addr);
int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
void *rxi);
void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int len);
void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate);
int mt76x2_mac_set_beacon(struct mt76x2_dev *dev, u8 vif_idx,
struct sk_buff *skb);
......
......@@ -16,6 +16,7 @@
*/
#include "mt76x2.h"
#include "mt76x02_util.h"
void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force)
{
......@@ -53,253 +54,14 @@ void mt76x2_mac_stop(struct mt76x2_dev *dev, bool force)
}
EXPORT_SYMBOL_GPL(mt76x2_mac_stop);
bool mt76x2_mac_load_tx_status(struct mt76x2_dev *dev,
struct mt76x02_tx_status *stat)
{
u32 stat1, stat2;
stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
if (!stat->valid)
return false;
stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
return true;
}
EXPORT_SYMBOL_GPL(mt76x2_mac_load_tx_status);
static int
mt76x2_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
enum nl80211_band band)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
txrate->idx = 0;
txrate->flags = 0;
txrate->count = 1;
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (band == NL80211_BAND_2GHZ)
idx += 4;
txrate->idx = idx;
return 0;
case MT_PHY_TYPE_CCK:
if (idx >= 8)
idx -= 8;
txrate->idx = idx;
return 0;
case MT_PHY_TYPE_HT_GF:
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
/* fall through */
case MT_PHY_TYPE_HT:
txrate->flags |= IEEE80211_TX_RC_MCS;
txrate->idx = idx;
break;
case MT_PHY_TYPE_VHT:
txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
txrate->idx = idx;
break;
default:
return -EINVAL;
}
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
break;
case MT_PHY_BW_80:
txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
break;
default:
return -EINVAL;
}
if (rate & MT_RXWI_RATE_SGI)
txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
return 0;
}
static void
mt76x2_mac_fill_tx_status(struct mt76x2_dev *dev,
struct ieee80211_tx_info *info,
struct mt76x02_tx_status *st, int n_frames)
{
struct ieee80211_tx_rate *rate = info->status.rates;
int cur_idx, last_rate;
int i;
if (!n_frames)
return;
last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
mt76x2_mac_process_tx_rate(&rate[last_rate], st->rate,
dev->mt76.chandef.chan->band);
if (last_rate < IEEE80211_TX_MAX_RATES - 1)
rate[last_rate + 1].idx = -1;
cur_idx = rate[last_rate].idx + last_rate;
for (i = 0; i <= last_rate; i++) {
rate[i].flags = rate[last_rate].flags;
rate[i].idx = max_t(int, 0, cur_idx - i);
rate[i].count = 1;
}
rate[last_rate].count = st->retry + 1 - last_rate;
info->status.ampdu_len = n_frames;
info->status.ampdu_ack_len = st->success ? n_frames : 0;
if (st->pktid & MT_TXWI_PKTID_PROBE)
info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
if (st->aggr)
info->flags |= IEEE80211_TX_CTL_AMPDU |
IEEE80211_TX_STAT_AMPDU;
if (!st->ack_req)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
else if (st->success)
info->flags |= IEEE80211_TX_STAT_ACK;
}
void mt76x2_send_tx_status(struct mt76x2_dev *dev,
struct mt76x02_tx_status *stat, u8 *update)
{
struct ieee80211_tx_info info = {};
struct ieee80211_sta *sta = NULL;
struct mt76_wcid *wcid = NULL;
struct mt76x02_sta *msta = NULL;
rcu_read_lock();
if (stat->wcid < ARRAY_SIZE(dev->wcid))
wcid = rcu_dereference(dev->wcid[stat->wcid]);
if (wcid) {
void *priv;
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
sta = container_of(priv, struct ieee80211_sta,
drv_priv);
}
if (msta && stat->aggr) {
u32 stat_val, stat_cache;
stat_val = stat->rate;
stat_val |= ((u32) stat->retry) << 16;
stat_cache = msta->status.rate;
stat_cache |= ((u32) msta->status.retry) << 16;
if (*update == 0 && stat_val == stat_cache &&
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
msta->n_frames++;
goto out;
}
mt76x2_mac_fill_tx_status(dev, &info, &msta->status,
msta->n_frames);
msta->status = *stat;
msta->n_frames = 1;
*update = 0;
} else {
mt76x2_mac_fill_tx_status(dev, &info, stat, 1);
*update = 1;
}
ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
out:
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(mt76x2_send_tx_status);
static __le16
mt76x2_mac_tx_rate_val(struct mt76x2_dev *dev,
const struct ieee80211_tx_rate *rate, u8 *nss_val)
{
u16 rateval;
u8 phy, rate_idx;
u8 nss = 1;
u8 bw = 0;
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 4);
phy = MT_PHY_TYPE_VHT;
if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
bw = 2;
else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else if (rate->flags & IEEE80211_TX_RC_MCS) {
rate_idx = rate->idx;
nss = 1 + (rate->idx >> 3);
phy = MT_PHY_TYPE_HT;
if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
phy = MT_PHY_TYPE_HT_GF;
if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = 1;
} else {
const struct ieee80211_rate *r;
int band = dev->mt76.chandef.chan->band;
u16 val;
r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx];
if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
val = r->hw_value_short;
else
val = r->hw_value;
phy = val >> 8;
rate_idx = val & 0xff;
bw = 0;
}
rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rateval |= MT_RXWI_RATE_SGI;
*nss_val = nss;
return cpu_to_le16(rateval);
}
void mt76x2_mac_wcid_set_rate(struct mt76x2_dev *dev, struct mt76_wcid *wcid,
const struct ieee80211_tx_rate *rate)
{
spin_lock_bh(&dev->mt76.lock);
wcid->tx_rate = mt76x2_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
wcid->tx_rate_set = true;
spin_unlock_bh(&dev->mt76.lock);
}
EXPORT_SYMBOL_GPL(mt76x2_mac_wcid_set_rate);
void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x02_txwi *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int len)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0];
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
u16 txwi_flags = 0;
u8 nss;
s8 txpwr_adj, max_txpwr_adj;
u8 ccmp_pn[8];
......@@ -333,8 +95,8 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
max_txpwr_adj = wcid->max_txpwr_adj;
nss = wcid->tx_rate_nss;
} else {
txwi->rate = mt76x2_mac_tx_rate_val(dev, rate, &nss);
max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(dev, rate);
txwi->rate = mt76x02_mac_tx_rate_val(&dev->mt76, rate, &nss);
max_txpwr_adj = mt76x2_tx_get_max_txpwr_adj(&dev->mt76, rate);
}
spin_unlock_bh(&dev->mt76.lock);
......@@ -348,120 +110,10 @@ void mt76x2_mac_write_txwi(struct mt76x2_dev *dev, struct mt76x2_txwi *txwi,
!(txwi->rate & cpu_to_le16(rate_ht_mask)))
txwi->txstream = 0x93;
if (info->flags & IEEE80211_TX_CTL_LDPC)
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC);
if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC);
if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
txwi_flags |= MT_TXWI_FLAGS_MMPS;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
txwi->pktid |= MT_TXWI_PKTID_PROBE;
if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
ba_size <<= sta->ht_cap.ampdu_factor;
ba_size = min_t(int, 63, ba_size - 1);
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
ba_size = 0;
txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
txwi_flags |= MT_TXWI_FLAGS_AMPDU |
FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY,
sta->ht_cap.ampdu_density);
}
if (ieee80211_is_probe_resp(hdr->frame_control) ||
ieee80211_is_beacon(hdr->frame_control))
txwi_flags |= MT_TXWI_FLAGS_TS;
txwi->flags |= cpu_to_le16(txwi_flags);
txwi->len_ctl = cpu_to_le16(len);
mt76x02_mac_fill_txwi(txwi, skb, sta, len, nss);
}
EXPORT_SYMBOL_GPL(mt76x2_mac_write_txwi);
static int
mt76x2_mac_process_rate(struct mt76_rx_status *status, u16 rate)
{
u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
case MT_PHY_TYPE_OFDM:
if (idx >= 8)
idx = 0;
if (status->band == NL80211_BAND_2GHZ)
idx += 4;
status->rate_idx = idx;
return 0;
case MT_PHY_TYPE_CCK:
if (idx >= 8) {
idx -= 8;
status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
}
if (idx >= 4)
idx = 0;
status->rate_idx = idx;
return 0;
case MT_PHY_TYPE_HT_GF:
status->enc_flags |= RX_ENC_FLAG_HT_GF;
/* fall through */
case MT_PHY_TYPE_HT:
status->encoding = RX_ENC_HT;
status->rate_idx = idx;
break;
case MT_PHY_TYPE_VHT:
status->encoding = RX_ENC_VHT;
status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
status->nss = FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1;
break;
default:
return -EINVAL;
}
if (rate & MT_RXWI_RATE_LDPC)
status->enc_flags |= RX_ENC_FLAG_LDPC;
if (rate & MT_RXWI_RATE_SGI)
status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
if (rate & MT_RXWI_RATE_STBC)
status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
case MT_PHY_BW_20:
break;
case MT_PHY_BW_40:
status->bw = RATE_INFO_BW_40;
break;
case MT_PHY_BW_80:
status->bw = RATE_INFO_BW_80;
break;
default:
break;
}
return 0;
}
static void mt76x2_remove_hdr_pad(struct sk_buff *skb, int len)
{
int hdrlen;
if (!len)
return;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
memmove(skb->data + len, skb->data, hdrlen);
skb_pull(skb, len);
}
int mt76x2_mac_get_rssi(struct mt76x2_dev *dev, s8 rssi, int chain)
{
struct mt76x2_rx_freq_cal *cal = &dev->cal.rx;
......@@ -477,10 +129,10 @@ mt76x2_rx_get_sta(struct mt76x2_dev *dev, u8 idx)
{
struct mt76_wcid *wcid;
if (idx >= ARRAY_SIZE(dev->wcid))
if (idx >= ARRAY_SIZE(dev->mt76.wcid))
return NULL;
wcid = rcu_dereference(dev->wcid[idx]);
wcid = rcu_dereference(dev->mt76.wcid[idx]);
if (!wcid)
return NULL;
......@@ -504,7 +156,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
void *rxi)
{
struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
struct mt76x2_rxwi *rxwi = rxi;
struct mt76x02_rxwi *rxwi = rxi;
struct mt76x02_sta *sta;
u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
u32 ctl = le32_to_cpu(rxwi->ctl);
......@@ -558,7 +210,7 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
}
}
mt76x2_remove_hdr_pad(skb, pad_len);
mt76x02_remove_hdr_pad(skb, pad_len);
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
status->aggr = true;
......@@ -582,6 +234,6 @@ int mt76x2_mac_process_rx(struct mt76x2_dev *dev, struct sk_buff *skb,
sta->inactive_count = 0;
}
return mt76x2_mac_process_rate(status, rate);
return mt76x02_mac_process_rate(status, rate);
}
EXPORT_SYMBOL_GPL(mt76x2_mac_process_rx);
......@@ -54,40 +54,6 @@ mt76x2_stop(struct ieee80211_hw *hw)
mutex_unlock(&dev->mt76.mutex);
}
static int
mt76x2_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *) vif->drv_priv;
unsigned int idx = 0;
if (vif->addr[0] & BIT(1))
idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
/*
* Client mode typically only has one configurable BSSID register,
* which is used for bssidx=0. This is linked to the MAC address.
* Since mac80211 allows changing interface types, and we cannot
* force the use of the primary MAC address for a station mode
* interface, we need some other way of configuring a per-interface
* remote BSSID.
* The hardware provides an AP-Client feature, where bssidx 0-7 are
* used for AP mode and bssidx 8-15 for client mode.
* We shift the station interface bss index by 8 to force the
* hardware to recognize the BSSID.
* The resulting bssidx mismatch for unicast frames is ignored by hw.
*/
if (vif->type == NL80211_IFTYPE_STATION)
idx += 8;
mvif->idx = idx;
mvif->group_wcid.idx = MT_VIF_WCID(idx);
mvif->group_wcid.hw_key_idx = -1;
mt76x02_txq_init(&dev->mt76, vif->txq);
return 0;
}
static int
mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef)
{
......@@ -318,22 +284,22 @@ const struct ieee80211_ops mt76x2_ops = {
.tx = mt76x2_tx,
.start = mt76x2_start,
.stop = mt76x2_stop,
.add_interface = mt76x2_add_interface,
.remove_interface = mt76x2_remove_interface,
.add_interface = mt76x02_add_interface,
.remove_interface = mt76x02_remove_interface,
.config = mt76x2_config,
.configure_filter = mt76x02_configure_filter,
.bss_info_changed = mt76x2_bss_info_changed,
.sta_add = mt76x2_sta_add,
.sta_remove = mt76x2_sta_remove,
.set_key = mt76x2_set_key,
.conf_tx = mt76x2_conf_tx,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
.set_key = mt76x02_set_key,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x2_sw_scan,
.sw_scan_complete = mt76x2_sw_scan_complete,
.flush = mt76x2_flush,
.ampdu_action = mt76x2_ampdu_action,
.ampdu_action = mt76x02_ampdu_action,
.get_txpower = mt76x2_get_txpower,
.wake_tx_queue = mt76_wake_tx_queue,
.sta_rate_tbl_update = mt76x2_sta_rate_tbl_update,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.release_buffered_frames = mt76_release_buffered_frames,
.set_coverage_class = mt76x2_set_coverage_class,
.get_survey = mt76_get_survey,
......
......@@ -20,90 +20,14 @@
#include "mt76x2.h"
#include "mt76x2_mcu.h"
#include "mt76x2_dma.h"
#include "mt76x2_eeprom.h"
static struct sk_buff *mt76x2_mcu_msg_alloc(const void *data, int len)
{
struct sk_buff *skb;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
return NULL;
memcpy(skb_put(skb, len), data, len);
return skb;
}
static struct sk_buff *
mt76x2_mcu_get_response(struct mt76x2_dev *dev, unsigned long expires)
{
unsigned long timeout;
if (!time_is_after_jiffies(expires))
return NULL;
timeout = expires - jiffies;
wait_event_timeout(dev->mcu.wait, !skb_queue_empty(&dev->mcu.res_q),
timeout);
return skb_dequeue(&dev->mcu.res_q);
}
static int
mt76x2_mcu_msg_send(struct mt76x2_dev *dev, struct sk_buff *skb,
enum mcu_cmd cmd)
{
unsigned long expires = jiffies + HZ;
int ret;
u8 seq;
if (!skb)
return -EINVAL;
mutex_lock(&dev->mcu.mutex);
seq = ++dev->mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mcu.msg_seq & 0xf;
ret = mt76x2_tx_queue_mcu(dev, MT_TXQ_MCU, skb, cmd, seq);
if (ret)
goto out;
while (1) {
u32 *rxfce;
bool check_seq = false;
skb = mt76x2_mcu_get_response(dev, expires);
if (!skb) {
dev_err(dev->mt76.dev,
"MCU message %d (seq %d) timed out\n", cmd,
seq);
ret = -ETIMEDOUT;
break;
}
rxfce = (u32 *) skb->cb;
if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
check_seq = true;
dev_kfree_skb(skb);
if (check_seq)
break;
}
out:
mutex_unlock(&dev->mcu.mutex);
return ret;
}
#include "mt76x02_dma.h"
static int
mt76pci_load_rom_patch(struct mt76x2_dev *dev)
{
const struct firmware *fw = NULL;
struct mt76x2_patch_header *hdr;
struct mt76x02_patch_header *hdr;
bool rom_protect = !is_mt7612(dev);
int len, ret = 0;
__le32 *cur;
......@@ -138,7 +62,7 @@ mt76pci_load_rom_patch(struct mt76x2_dev *dev)
goto out;
}
hdr = (struct mt76x2_patch_header *) fw->data;
hdr = (struct mt76x02_patch_header *)fw->data;
dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET);
......@@ -169,7 +93,7 @@ static int
mt76pci_load_firmware(struct mt76x2_dev *dev)
{
const struct firmware *fw;
const struct mt76x2_fw_header *hdr;
const struct mt76x02_fw_header *hdr;
int len, ret;
__le32 *cur;
u32 offset, val;
......@@ -181,7 +105,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
if (!fw || !fw->data || fw->size < sizeof(*hdr))
goto error;
hdr = (const struct mt76x2_fw_header *) fw->data;
hdr = (const struct mt76x02_fw_header *)fw->data;
len = sizeof(*hdr);
len += le32_to_cpu(hdr->ilm_len);
......@@ -241,165 +165,15 @@ mt76pci_load_firmware(struct mt76x2_dev *dev)
return -ENOENT;
}
static int
mt76x2_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func,
u32 val)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(func),
.value = cpu_to_le32(val),
};
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_FUN_SET_OP);
}
int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel)
{
struct sk_buff *skb;
struct {
u8 cr_mode;
u8 temp;
u8 ch;
u8 _pad0;
__le32 cfg;
} __packed __aligned(4) msg = {
.cr_mode = type,
.temp = temp_level,
.ch = channel,
};
u32 val;
val = BIT(31);
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_LOAD_CR);
}
int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
u8 bw_index, bool scan)
{
struct sk_buff *skb;
struct {
u8 idx;
u8 scan;
u8 bw;
u8 _pad0;
__le16 chainmask;
u8 ext_chan;
u8 _pad1;
} __packed __aligned(4) msg = {
.idx = channel,
.scan = scan,
.bw = bw,
.chainmask = cpu_to_le16(dev->chainmask),
};
/* first set the channel without the extension channel info */
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP);
usleep_range(5000, 10000);
msg.ext_chan = 0xe0 + bw_index;
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_SWITCH_CHANNEL_OP);
}
int mt76x2_mcu_set_radio_state(struct mt76x2_dev *dev, bool on)
{
struct sk_buff *skb;
struct {
__le32 mode;
__le32 level;
} __packed __aligned(4) msg = {
.mode = cpu_to_le32(on ? RADIO_ON : RADIO_OFF),
.level = cpu_to_le32(0),
};
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_POWER_SAVING_OP);
}
int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
u32 param)
{
struct sk_buff *skb;
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(type),
.value = cpu_to_le32(param),
};
int ret;
mt76_clear(dev, MT_MCU_COM_REG0, BIT(31));
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
ret = mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP);
if (ret)
return ret;
if (WARN_ON(!mt76_poll_msec(dev, MT_MCU_COM_REG0,
BIT(31), BIT(31), 100)))
return -ETIMEDOUT;
return 0;
}
int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev,
struct mt76x2_tssi_comp *tssi_data)
{
struct sk_buff *skb;
struct {
__le32 id;
struct mt76x2_tssi_comp data;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(MCU_CAL_TSSI_COMP),
.data = *tssi_data,
};
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP);
}
int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
bool force)
{
struct sk_buff *skb;
struct {
__le32 channel;
__le32 gain_val;
} __packed __aligned(4) msg = {
.channel = cpu_to_le32(channel),
.gain_val = cpu_to_le32(gain),
};
if (force)
msg.channel |= cpu_to_le32(BIT(31));
skb = mt76x2_mcu_msg_alloc(&msg, sizeof(msg));
return mt76x2_mcu_msg_send(dev, skb, CMD_INIT_GAIN_OP);
}
int mt76x2_mcu_init(struct mt76x2_dev *dev)
{
static const struct mt76_mcu_ops mt76x2_mcu_ops = {
.mcu_msg_alloc = mt76x02_mcu_msg_alloc,
.mcu_send_msg = mt76x02_mcu_msg_send,
};
int ret;
mutex_init(&dev->mcu.mutex);
dev->mt76.mcu_ops = &mt76x2_mcu_ops;
ret = mt76pci_load_rom_patch(dev);
if (ret)
......@@ -409,19 +183,6 @@ int mt76x2_mcu_init(struct mt76x2_dev *dev)
if (ret)
return ret;
mt76x2_mcu_function_select(dev, Q_SELECT, 1);
return 0;
}
int mt76x2_mcu_cleanup(struct mt76x2_dev *dev)
{
struct sk_buff *skb;
mt76_wr(dev, MT_MCU_INT_LEVEL, 1);
usleep_range(20000, 30000);
while ((skb = skb_dequeue(&dev->mcu.res_q)) != NULL)
dev_kfree_skb(skb);
mt76x02_mcu_function_select(&dev->mt76, Q_SELECT, 1, true);
return 0;
}
......@@ -17,15 +17,11 @@
#ifndef __MT76x2_MCU_H
#define __MT76x2_MCU_H
#include "mt76x02_mcu.h"
/* Register definitions */
#define MT_MCU_CPU_CTL 0x0704
#define MT_MCU_CLOCK_CTL 0x0708
#define MT_MCU_RESET_CTL 0x070C
#define MT_MCU_INT_LEVEL 0x0718
#define MT_MCU_COM_REG0 0x0730
#define MT_MCU_COM_REG1 0x0734
#define MT_MCU_COM_REG2 0x0738
#define MT_MCU_COM_REG3 0x073C
#define MT_MCU_PCIE_REMAP_BASE1 0x0740
#define MT_MCU_PCIE_REMAP_BASE2 0x0744
#define MT_MCU_PCIE_REMAP_BASE3 0x0748
......@@ -69,47 +65,6 @@
#define MT_MCU_DLM_ADDR 0x90000
#define MT_MCU_DLM_ADDR_E3 0x90800
enum mcu_cmd {
CMD_FUN_SET_OP = 1,
CMD_LOAD_CR = 2,
CMD_INIT_GAIN_OP = 3,
CMD_DYNC_VGA_OP = 6,
CMD_TDLS_CH_SW = 7,
CMD_BURST_WRITE = 8,
CMD_READ_MODIFY_WRITE = 9,
CMD_RANDOM_READ = 10,
CMD_BURST_READ = 11,
CMD_RANDOM_WRITE = 12,
CMD_LED_MODE_OP = 16,
CMD_POWER_SAVING_OP = 20,
CMD_WOW_CONFIG = 21,
CMD_WOW_QUERY = 22,
CMD_WOW_FEATURE = 24,
CMD_CARRIER_DETECT_OP = 28,
CMD_RADOR_DETECT_OP = 29,
CMD_SWITCH_CHANNEL_OP = 30,
CMD_CALIBRATION_OP = 31,
CMD_BEACON_OP = 32,
CMD_ANTENNA_OP = 33,
};
enum mcu_function {
Q_SELECT = 1,
BW_SETTING = 2,
USB2_SW_DISCONNECT = 2,
USB3_SW_DISCONNECT = 3,
LOG_FW_DEBUG_MSG = 4,
GET_FW_VERSION = 5,
};
enum mcu_power_mode {
RADIO_OFF = 0x30,
RADIO_ON = 0x31,
RADIO_OFF_AUTO_WAKEUP = 0x32,
RADIO_OFF_ADVANCE = 0x33,
RADIO_ON_ADVANCE = 0x34,
};
enum mcu_calibration {
MCU_CAL_R = 1,
MCU_CAL_TEMP_SENSOR,
......@@ -146,25 +101,6 @@ struct mt76x2_tssi_comp {
u8 offset1;
} __packed __aligned(4);
struct mt76x2_fw_header {
__le32 ilm_len;
__le32 dlm_len;
__le16 build_ver;
__le16 fw_ver;
u8 pad[4];
char build_time[16];
};
struct mt76x2_patch_header {
char build_time[16];
char platform[4];
char hw_version[4];
char patch_version[4];
u8 pad[2];
};
int mt76x2_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
u32 param);
int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev, struct mt76x2_tssi_comp *tssi_data);
int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
bool force);
......
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include "mt76x2.h"
#include "mt76x2_mcu.h"
#include "mt76x2_eeprom.h"
#include "mt76x02_dma.h"
int mt76x2_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
u8 bw_index, bool scan)
{
struct sk_buff *skb;
struct {
u8 idx;
u8 scan;
u8 bw;
u8 _pad0;
__le16 chainmask;
u8 ext_chan;
u8 _pad1;
} __packed __aligned(4) msg = {
.idx = channel,
.scan = scan,
.bw = bw,
.chainmask = cpu_to_le16(dev->chainmask),
};
/* first set the channel without the extension channel info */
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
usleep_range(5000, 10000);
msg.ext_chan = 0xe0 + bw_index;
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
return mt76_mcu_send_msg(dev, skb, CMD_SWITCH_CHANNEL_OP, true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
int mt76x2_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel)
{
struct sk_buff *skb;
struct {
u8 cr_mode;
u8 temp;
u8 ch;
u8 _pad0;
__le32 cfg;
} __packed __aligned(4) msg = {
.cr_mode = type,
.temp = temp_level,
.ch = channel,
};
u32 val;
val = BIT(31);
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
return mt76_mcu_send_msg(dev, skb, CMD_LOAD_CR, true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr);
int mt76x2_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
bool force)
{
struct sk_buff *skb;
struct {
__le32 channel;
__le32 gain_val;
} __packed __aligned(4) msg = {
.channel = cpu_to_le32(channel),
.gain_val = cpu_to_le32(gain),
};
if (force)
msg.channel |= cpu_to_le32(BIT(31));
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
return mt76_mcu_send_msg(dev, skb, CMD_INIT_GAIN_OP, true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain);
int mt76x2_mcu_tssi_comp(struct mt76x2_dev *dev,
struct mt76x2_tssi_comp *tssi_data)
{
struct sk_buff *skb;
struct {
__le32 id;
struct mt76x2_tssi_comp data;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(MCU_CAL_TSSI_COMP),
.data = *tssi_data,
};
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
return mt76_mcu_send_msg(dev, skb, CMD_CALIBRATION_OP, true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp);
......@@ -37,7 +37,7 @@ mt76x2_phy_tssi_init_cal(struct mt76x2_dev *dev)
if (mt76x2_ext_pa_enabled(dev, chan->band))
flag |= BIT(8);
mt76x2_mcu_calibrate(dev, MCU_CAL_TSSI, flag);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI, flag, true);
dev->cal.tssi_cal_done = true;
return true;
}
......@@ -61,13 +61,13 @@ mt76x2_phy_channel_calibrate(struct mt76x2_dev *dev, bool mac_stopped)
mt76x2_mac_stop(dev, false);
if (is_5ghz)
mt76x2_mcu_calibrate(dev, MCU_CAL_LC, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, true);
mt76x2_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz);
mt76x2_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
mt76x2_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz);
mt76x2_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0);
mt76x2_mcu_calibrate(dev, MCU_CAL_TX_SHAPING, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, true);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, true);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, true);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, true);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_SHAPING, 0, true);
if (!mac_stopped)
mt76x2_mac_resume(dev);
......@@ -363,14 +363,14 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
if (val != 0xff)
mt76x2_mcu_calibrate(dev, MCU_CAL_R, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R, 0, true);
}
mt76x2_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, true);
/* Rx LPF calibration */
if (!dev->cal.init_cal_done)
mt76x2_mcu_calibrate(dev, MCU_CAL_RC, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, true);
dev->cal.init_cal_done = true;
......@@ -403,47 +403,6 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev,
return 0;
}
static void
mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
struct mt76x2_tx_power_info txp;
struct mt76x2_tssi_comp t = {};
if (!dev->cal.tssi_cal_done)
return;
if (!dev->cal.tssi_comp_pending) {
/* TSSI trigger */
t.cal_mode = BIT(0);
mt76x2_mcu_tssi_comp(dev, &t);
dev->cal.tssi_comp_pending = true;
} else {
if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
return;
dev->cal.tssi_comp_pending = false;
mt76x2_get_power_info(dev, &txp, chan);
if (mt76x2_ext_pa_enabled(dev, chan->band))
t.pa_mode = 1;
t.cal_mode = BIT(1);
t.slope0 = txp.chain[0].tssi_slope;
t.offset0 = txp.chain[0].tssi_offset;
t.slope1 = txp.chain[1].tssi_slope;
t.offset1 = txp.chain[1].tssi_offset;
mt76x2_mcu_tssi_comp(dev, &t);
if (t.pa_mode || dev->cal.dpd_cal_done)
return;
usleep_range(10000, 20000);
mt76x2_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
dev->cal.dpd_cal_done = true;
}
}
static void
mt76x2_phy_temp_compensate(struct mt76x2_dev *dev)
{
......@@ -478,7 +437,7 @@ void mt76x2_phy_calibrate(struct work_struct *work)
dev = container_of(work, struct mt76x2_dev, cal_work.work);
mt76x2_phy_channel_calibrate(dev, false);
mt76x2_phy_tssi_compensate(dev);
mt76x2_phy_tssi_compensate(dev, true);
mt76x2_phy_temp_compensate(dev);
mt76x2_phy_update_channel_gain(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
......@@ -489,7 +448,7 @@ int mt76x2_phy_start(struct mt76x2_dev *dev)
{
int ret;
ret = mt76x2_mcu_set_radio_state(dev, true);
ret = mt76x02_mcu_set_radio_state(&dev->mt76, true, true);
if (ret)
return ret;
......
......@@ -17,6 +17,7 @@
#include "mt76x2.h"
#include "mt76x2_eeprom.h"
#include "mt76x2_mcu.h"
static void
mt76x2_adjust_high_lna_gain(struct mt76x2_dev *dev, int reg, s8 offset)
......@@ -311,8 +312,8 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev)
local_bh_disable();
rcu_read_lock();
for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
unsigned long mask = dev->wcid_mask[i];
for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid_mask); i++) {
unsigned long mask = dev->mt76.wcid_mask[i];
if (!mask)
continue;
......@@ -321,7 +322,7 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev)
if (!(mask & 1))
continue;
wcid = rcu_dereference(dev->wcid[j]);
wcid = rcu_dereference(dev->mt76.wcid[j]);
if (!wcid)
continue;
......@@ -347,3 +348,45 @@ int mt76x2_phy_get_min_avg_rssi(struct mt76x2_dev *dev)
return min_rssi;
}
EXPORT_SYMBOL_GPL(mt76x2_phy_get_min_avg_rssi);
void mt76x2_phy_tssi_compensate(struct mt76x2_dev *dev, bool wait)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
struct mt76x2_tx_power_info txp;
struct mt76x2_tssi_comp t = {};
if (!dev->cal.tssi_cal_done)
return;
if (!dev->cal.tssi_comp_pending) {
/* TSSI trigger */
t.cal_mode = BIT(0);
mt76x2_mcu_tssi_comp(dev, &t);
dev->cal.tssi_comp_pending = true;
} else {
if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
return;
dev->cal.tssi_comp_pending = false;
mt76x2_get_power_info(dev, &txp, chan);
if (mt76x2_ext_pa_enabled(dev, chan->band))
t.pa_mode = 1;
t.cal_mode = BIT(1);
t.slope0 = txp.chain[0].tssi_slope;
t.offset0 = txp.chain[0].tssi_offset;
t.slope1 = txp.chain[1].tssi_slope;
t.offset1 = txp.chain[1].tssi_offset;
mt76x2_mcu_tssi_comp(dev, &t);
if (t.pa_mode || dev->cal.dpd_cal_done)
return;
usleep_range(10000, 20000);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_DPD,
chan->hw_value, wait);
dev->cal.dpd_cal_done = true;
}
}
EXPORT_SYMBOL_GPL(mt76x2_phy_tssi_compensate);
......@@ -15,7 +15,8 @@
*/
#include "mt76x2.h"
#include "mt76x2_dma.h"
#include "mt76x02_util.h"
#include "mt76x02_dma.h"
struct beacon_bc_data {
struct mt76x2_dev *dev;
......@@ -38,7 +39,7 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, skb->len);
ret = mt76x2_insert_hdr_pad(skb);
ret = mt76x02_insert_hdr_pad(skb);
if (ret < 0)
return ret;
......
......@@ -16,7 +16,7 @@
*/
#include "mt76x2.h"
#include "mt76x2_dma.h"
#include "dma.h"
void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct sk_buff *skb)
......@@ -24,7 +24,7 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct mt76x2_dev *dev = hw->priv;
struct ieee80211_vif *vif = info->control.vif;
struct mt76_wcid *wcid = &dev->global_wcid;
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
if (control->sta) {
struct mt76x02_sta *msta;
......@@ -47,25 +47,10 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
}
EXPORT_SYMBOL_GPL(mt76x2_tx);
int mt76x2_insert_hdr_pad(struct sk_buff *skb)
{
int len = ieee80211_get_hdrlen_from_skb(skb);
if (len % 4 == 0)
return 0;
skb_push(skb, 2);
memmove(skb->data, skb->data + 2, len);
skb->data[len] = 0;
skb->data[len + 1] = 0;
return 2;
}
EXPORT_SYMBOL_GPL(mt76x2_insert_hdr_pad);
s8 mt76x2_tx_get_max_txpwr_adj(struct mt76x2_dev *dev,
s8 mt76x2_tx_get_max_txpwr_adj(struct mt76_dev *mdev,
const struct ieee80211_tx_rate *rate)
{
struct mt76x2_dev *dev = (struct mt76x2_dev *) mdev;
s8 max_txpwr;
if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
......@@ -131,19 +116,3 @@ void mt76x2_tx_set_txpwr_auto(struct mt76x2_dev *dev, s8 txpwr)
MT_PROT_AUTO_TX_CFG_AUTO_PADJ, txpwr_adj);
}
EXPORT_SYMBOL_GPL(mt76x2_tx_set_txpwr_auto);
void mt76x2_tx_complete(struct mt76x2_dev *dev, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
ieee80211_free_txskb(mt76_hw(dev), skb);
} else {
ieee80211_tx_info_clear_status(info);
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status(mt76_hw(dev), skb);
}
}
EXPORT_SYMBOL_GPL(mt76x2_tx_complete);
......@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include "mt76x02_usb.h"
#include "mt76x2u.h"
static const struct usb_device_id mt76x2u_device_table[] = {
......@@ -46,6 +47,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
udev = usb_get_dev(udev);
usb_reset_device(udev);
mt76x02u_init_mcu(&dev->mt76);
err = mt76u_init(&dev->mt76, intf);
if (err < 0)
goto err;
......
......@@ -20,8 +20,8 @@
#include <linux/device.h>
#include "mt76x2.h"
#include "mt76x2_dma.h"
#include "mt76x2_mcu.h"
#include "mt76x02_dma.h"
#define MT7612U_EEPROM_SIZE 512
......@@ -50,32 +50,18 @@ void mt76x2u_phy_set_txdac(struct mt76x2_dev *dev);
void mt76x2u_phy_set_rxpath(struct mt76x2_dev *dev);
void mt76x2u_mcu_complete_urb(struct urb *urb);
int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
u8 bw_index, bool scan);
int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
u32 val);
int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev,
struct mt76x2_tssi_comp *tssi_data);
int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
bool force);
int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
bool ext, int rssi, u32 false_cca);
int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val);
int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type,
u8 temp_level, u8 channel);
int mt76x2u_mcu_init(struct mt76x2_dev *dev);
int mt76x2u_mcu_fw_init(struct mt76x2_dev *dev);
int mt76x2u_alloc_queues(struct mt76x2_dev *dev);
void mt76x2u_queues_deinit(struct mt76x2_dev *dev);
void mt76x2u_stop_queues(struct mt76x2_dev *dev);
bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update);
int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info);
void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush);
int mt76x2u_skb_dma_info(struct sk_buff *skb, enum dma_msg_port port,
u32 flags);
......
......@@ -16,18 +16,8 @@
#include "mt76x2u.h"
#include "dma.h"
static void mt76x2u_remove_dma_hdr(struct sk_buff *skb)
{
int hdr_len;
skb_pull(skb, sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN);
hdr_len = ieee80211_get_hdrlen_from_skb(skb);
if (hdr_len % 4) {
memmove(skb->data + 2, skb->data, hdr_len);
skb_pull(skb, 2);
}
}
#include "mt76x02_util.h"
#include "mt76x02_usb.h"
static int
mt76x2u_check_skb_rooms(struct sk_buff *skb)
......@@ -35,74 +25,29 @@ mt76x2u_check_skb_rooms(struct sk_buff *skb)
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
u32 need_head;
need_head = sizeof(struct mt76x2_txwi) + MT_DMA_HDR_LEN;
need_head = sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN;
if (hdr_len % 4)
need_head += 2;
return skb_cow(skb, need_head);
}
static int
mt76x2u_set_txinfo(struct sk_buff *skb,
struct mt76_wcid *wcid, u8 ep)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
enum mt76x2_qsel qsel;
u32 flags;
if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
ep == MT_EP_OUT_HCCA)
qsel = MT_QSEL_MGMT;
else
qsel = MT_QSEL_EDCA;
flags = FIELD_PREP(MT_TXD_INFO_QSEL, qsel) |
MT_TXD_INFO_80211;
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
flags |= MT_TXD_INFO_WIV;
return mt76u_skb_dma_info(skb, WLAN_PORT, flags);
}
bool mt76x2u_tx_status_data(struct mt76_dev *mdev, u8 *update)
{
struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
struct mt76x02_tx_status stat;
if (!mt76x2_mac_load_tx_status(dev, &stat))
return false;
mt76x2_send_tx_status(dev, &stat, update);
return true;
}
int mt76x2u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct sk_buff *skb, struct mt76_queue *q,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
u32 *tx_info)
{
struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
struct mt76x2_txwi *txwi;
struct mt76x02_txwi *txwi;
int err, len = skb->len;
err = mt76x2u_check_skb_rooms(skb);
if (err < 0)
return -ENOMEM;
mt76x2_insert_hdr_pad(skb);
mt76x02_insert_hdr_pad(skb);
txwi = skb_push(skb, sizeof(struct mt76x2_txwi));
txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
return mt76x2u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
return mt76x02u_set_txinfo(skb, wcid, q2ep(q->hw_idx));
}
void mt76x2u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush)
{
struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
mt76x2u_remove_dma_hdr(e->skb);
mt76x2_tx_complete(dev, e->skb);
}
......@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include "mt76x2u.h"
#include "mt76x02_util.h"
#include "mt76x2_eeprom.h"
static void mt76x2u_init_dma(struct mt76x2_dev *dev)
......@@ -136,8 +137,8 @@ struct mt76x2_dev *mt76x2u_alloc_device(struct device *pdev)
{
static const struct mt76_driver_ops drv_ops = {
.tx_prepare_skb = mt76x2u_tx_prepare_skb,
.tx_complete_skb = mt76x2u_tx_complete_skb,
.tx_status_data = mt76x2u_tx_status_data,
.tx_complete_skb = mt76x02_tx_complete_skb,
.tx_status_data = mt76x02_tx_status_data,
.rx_skb = mt76x2_queue_rx_skb,
};
struct mt76x2_dev *dev;
......@@ -239,7 +240,7 @@ int mt76x2u_init_hardware(struct mt76x2_dev *dev)
mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f);
err = mt76x2u_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0);
err = mt76x2_mcu_load_cr(dev, MT_RF_BBP_CR, 0, 0);
if (err < 0)
return err;
......@@ -276,8 +277,8 @@ int mt76x2u_register_device(struct mt76x2_dev *dev)
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
err = mt76_register_device(&dev->mt76, true, mt76x2_rates,
ARRAY_SIZE(mt76x2_rates));
err = mt76_register_device(&dev->mt76, true, mt76x02_rates,
ARRAY_SIZE(mt76x02_rates));
if (err)
goto fail;
......@@ -309,7 +310,7 @@ void mt76x2u_stop_hw(struct mt76x2_dev *dev)
void mt76x2u_cleanup(struct mt76x2_dev *dev)
{
mt76x2u_mcu_set_radio_state(dev, false);
mt76x02_mcu_set_radio_state(&dev->mt76, false, false);
mt76x2u_stop_hw(dev);
mt76u_queues_deinit(&dev->mt76);
mt76u_mcu_deinit(&dev->mt76);
......
......@@ -49,17 +49,11 @@ static int mt76x2u_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt76x2_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
unsigned int idx = 0;
if (!ether_addr_equal(dev->mt76.macaddr, vif->addr))
mt76x2u_mac_setaddr(dev, vif->addr);
mvif->idx = idx;
mvif->group_wcid.idx = MT_VIF_WCID(idx);
mvif->group_wcid.hw_key_idx = -1;
mt76x02_txq_init(&dev->mt76, vif->txq);
mt76x02_vif_init(&dev->mt76, vif, 0);
return 0;
}
......@@ -170,17 +164,17 @@ const struct ieee80211_ops mt76x2u_ops = {
.start = mt76x2u_start,
.stop = mt76x2u_stop,
.add_interface = mt76x2u_add_interface,
.remove_interface = mt76x2_remove_interface,
.sta_add = mt76x2_sta_add,
.sta_remove = mt76x2_sta_remove,
.set_key = mt76x2_set_key,
.ampdu_action = mt76x2_ampdu_action,
.remove_interface = mt76x02_remove_interface,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
.set_key = mt76x02_set_key,
.ampdu_action = mt76x02_ampdu_action,
.config = mt76x2u_config,
.wake_tx_queue = mt76_wake_tx_queue,
.bss_info_changed = mt76x2u_bss_info_changed,
.configure_filter = mt76x02_configure_filter,
.conf_tx = mt76x2_conf_tx,
.conf_tx = mt76x02_conf_tx,
.sw_scan_start = mt76x2u_sw_scan,
.sw_scan_complete = mt76x2u_sw_scan_complete,
.sta_rate_tbl_update = mt76x2_sta_rate_tbl_update,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
};
......@@ -18,10 +18,9 @@
#include "mt76x2u.h"
#include "mt76x2_eeprom.h"
#include "mt76x02_usb.h"
#define MT_CMD_HDR_LEN 4
#define MT_INBAND_PACKET_MAX_LEN 192
#define MT_MCU_MEMMAP_WLAN 0x410000
#define MCU_FW_URB_MAX_PAYLOAD 0x3900
#define MCU_ROM_PATCH_MAX_PAYLOAD 2048
......@@ -30,150 +29,6 @@
#define MT76U_MCU_DLM_OFFSET 0x110000
#define MT76U_MCU_ROM_PATCH_OFFSET 0x90000
static int
mt76x2u_mcu_function_select(struct mt76x2_dev *dev, enum mcu_function func,
u32 val)
{
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(func),
.value = cpu_to_le32(val),
};
struct sk_buff *skb;
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_FUN_SET_OP,
func != Q_SELECT);
}
int mt76x2u_mcu_set_radio_state(struct mt76x2_dev *dev, bool val)
{
struct {
__le32 mode;
__le32 level;
} __packed __aligned(4) msg = {
.mode = cpu_to_le32(val ? RADIO_ON : RADIO_OFF),
.level = cpu_to_le32(0),
};
struct sk_buff *skb;
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_POWER_SAVING_OP,
false);
}
int mt76x2u_mcu_load_cr(struct mt76x2_dev *dev, u8 type, u8 temp_level,
u8 channel)
{
struct {
u8 cr_mode;
u8 temp;
u8 ch;
u8 _pad0;
__le32 cfg;
} __packed __aligned(4) msg = {
.cr_mode = type,
.temp = temp_level,
.ch = channel,
};
struct sk_buff *skb;
u32 val;
val = BIT(31);
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0) >> 8) & 0x00ff;
val |= (mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1) << 8) & 0xff00;
msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_LOAD_CR, true);
}
int mt76x2u_mcu_set_channel(struct mt76x2_dev *dev, u8 channel, u8 bw,
u8 bw_index, bool scan)
{
struct {
u8 idx;
u8 scan;
u8 bw;
u8 _pad0;
__le16 chainmask;
u8 ext_chan;
u8 _pad1;
} __packed __aligned(4) msg = {
.idx = channel,
.scan = scan,
.bw = bw,
.chainmask = cpu_to_le16(dev->chainmask),
};
struct sk_buff *skb;
/* first set the channel without the extension channel info */
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true);
usleep_range(5000, 10000);
msg.ext_chan = 0xe0 + bw_index;
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_SWITCH_CHANNEL_OP, true);
}
int mt76x2u_mcu_calibrate(struct mt76x2_dev *dev, enum mcu_calibration type,
u32 val)
{
struct {
__le32 id;
__le32 value;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(type),
.value = cpu_to_le32(val),
};
struct sk_buff *skb;
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true);
}
int mt76x2u_mcu_init_gain(struct mt76x2_dev *dev, u8 channel, u32 gain,
bool force)
{
struct {
__le32 channel;
__le32 gain_val;
} __packed __aligned(4) msg = {
.channel = cpu_to_le32(channel),
.gain_val = cpu_to_le32(gain),
};
struct sk_buff *skb;
if (force)
msg.channel |= cpu_to_le32(BIT(31));
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_INIT_GAIN_OP, true);
}
int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
bool ext, int rssi, u32 false_cca)
{
......@@ -194,28 +49,8 @@ int mt76x2u_mcu_set_dynamic_vga(struct mt76x2_dev *dev, u8 channel, bool ap,
val |= BIT(30);
msg.channel = cpu_to_le32(val);
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_DYNC_VGA_OP, true);
}
int mt76x2u_mcu_tssi_comp(struct mt76x2_dev *dev,
struct mt76x2_tssi_comp *tssi_data)
{
struct {
__le32 id;
struct mt76x2_tssi_comp data;
} __packed __aligned(4) msg = {
.id = cpu_to_le32(MCU_CAL_TSSI_COMP),
.data = *tssi_data,
};
struct sk_buff *skb;
skb = mt76u_mcu_msg_alloc(&msg, sizeof(msg));
if (!skb)
return -ENOMEM;
return mt76u_mcu_send_msg(&dev->mt76, skb, CMD_CALIBRATION_OP, true);
skb = mt76_mcu_msg_alloc(dev, &msg, sizeof(msg));
return mt76_mcu_send_msg(dev, skb, CMD_DYNC_VGA_OP, true);
}
static void mt76x2u_mcu_load_ivb(struct mt76x2_dev *dev)
......@@ -257,7 +92,7 @@ static void mt76x2u_mcu_reset_wmt(struct mt76x2_dev *dev)
static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
{
bool rom_protect = !is_mt7612(dev);
struct mt76x2_patch_header *hdr;
struct mt76x02_patch_header *hdr;
u32 val, patch_mask, patch_reg;
const struct firmware *fw;
int err;
......@@ -292,7 +127,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
goto out;
}
hdr = (struct mt76x2_patch_header *)fw->data;
hdr = (struct mt76x02_patch_header *)fw->data;
dev_info(dev->mt76.dev, "ROM patch build: %.15s\n", hdr->build_time);
/* enable USB_DMA_CFG */
......@@ -302,7 +137,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
mt76_wr(dev, MT_VEND_ADDR(CFG, MT_USB_U3DMA_CFG), val);
/* vendor reset */
mt76u_mcu_fw_reset(&dev->mt76);
mt76x02u_mcu_fw_reset(&dev->mt76);
usleep_range(5000, 10000);
/* enable FCE to send in-band cmd */
......@@ -316,10 +151,10 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
/* FCE skip_fs_en */
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
fw->size - sizeof(*hdr),
MCU_ROM_PATCH_MAX_PAYLOAD,
MT76U_MCU_ROM_PATCH_OFFSET);
err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
fw->size - sizeof(*hdr),
MCU_ROM_PATCH_MAX_PAYLOAD,
MT76U_MCU_ROM_PATCH_OFFSET);
if (err < 0) {
err = -EIO;
goto out;
......@@ -344,7 +179,7 @@ static int mt76x2u_mcu_load_rom_patch(struct mt76x2_dev *dev)
static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
{
u32 val, dlm_offset = MT76U_MCU_DLM_OFFSET;
const struct mt76x2_fw_header *hdr;
const struct mt76x02_fw_header *hdr;
int err, len, ilm_len, dlm_len;
const struct firmware *fw;
......@@ -357,7 +192,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
goto out;
}
hdr = (const struct mt76x2_fw_header *)fw->data;
hdr = (const struct mt76x02_fw_header *)fw->data;
ilm_len = le32_to_cpu(hdr->ilm_len);
dlm_len = le32_to_cpu(hdr->dlm_len);
len = sizeof(*hdr) + ilm_len + dlm_len;
......@@ -375,7 +210,7 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time);
/* vendor reset */
mt76u_mcu_fw_reset(&dev->mt76);
mt76x02u_mcu_fw_reset(&dev->mt76);
usleep_range(5000, 10000);
/* enable USB_DMA_CFG */
......@@ -395,9 +230,9 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
mt76_wr(dev, MT_FCE_SKIP_FS, 0x3);
/* load ILM */
err = mt76u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
MT76U_MCU_ILM_OFFSET);
err = mt76x02u_mcu_fw_send_data(&dev->mt76, fw->data + sizeof(*hdr),
ilm_len, MCU_FW_URB_MAX_PAYLOAD,
MT76U_MCU_ILM_OFFSET);
if (err < 0) {
err = -EIO;
goto out;
......@@ -406,10 +241,10 @@ static int mt76x2u_mcu_load_firmware(struct mt76x2_dev *dev)
/* load DLM */
if (mt76xx_rev(dev) >= MT76XX_REV_E3)
dlm_offset += 0x800;
err = mt76u_mcu_fw_send_data(&dev->mt76,
fw->data + sizeof(*hdr) + ilm_len,
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
dlm_offset);
err = mt76x02u_mcu_fw_send_data(&dev->mt76,
fw->data + sizeof(*hdr) + ilm_len,
dlm_len, MCU_FW_URB_MAX_PAYLOAD,
dlm_offset);
if (err < 0) {
err = -EIO;
goto out;
......@@ -447,9 +282,10 @@ int mt76x2u_mcu_init(struct mt76x2_dev *dev)
{
int err;
err = mt76x2u_mcu_function_select(dev, Q_SELECT, 1);
err = mt76x02_mcu_function_select(&dev->mt76, Q_SELECT,
1, false);
if (err < 0)
return err;
return mt76x2u_mcu_set_radio_state(dev, true);
return mt76x02_mcu_set_radio_state(&dev->mt76, true, false);
}
......@@ -61,57 +61,16 @@ void mt76x2u_phy_channel_calibrate(struct mt76x2_dev *dev)
mt76x2u_mac_stop(dev);
if (is_5ghz)
mt76x2u_mcu_calibrate(dev, MCU_CAL_LC, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_LC, 0, false);
mt76x2u_mcu_calibrate(dev, MCU_CAL_TX_LOFT, is_5ghz);
mt76x2u_mcu_calibrate(dev, MCU_CAL_TXIQ, is_5ghz);
mt76x2u_mcu_calibrate(dev, MCU_CAL_RXIQC_FI, is_5ghz);
mt76x2u_mcu_calibrate(dev, MCU_CAL_TEMP_SENSOR, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TX_LOFT, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TXIQ, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXIQC_FI, is_5ghz, false);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TEMP_SENSOR, 0, false);
mt76x2u_mac_resume(dev);
}
static void
mt76x2u_phy_tssi_compensate(struct mt76x2_dev *dev)
{
struct ieee80211_channel *chan = dev->mt76.chandef.chan;
struct mt76x2_tx_power_info txp;
struct mt76x2_tssi_comp t = {};
if (!dev->cal.tssi_cal_done)
return;
if (!dev->cal.tssi_comp_pending) {
/* TSSI trigger */
t.cal_mode = BIT(0);
mt76x2u_mcu_tssi_comp(dev, &t);
dev->cal.tssi_comp_pending = true;
} else {
if (mt76_rr(dev, MT_BBP(CORE, 34)) & BIT(4))
return;
dev->cal.tssi_comp_pending = false;
mt76x2_get_power_info(dev, &txp, chan);
if (mt76x2_ext_pa_enabled(dev, chan->band))
t.pa_mode = 1;
t.cal_mode = BIT(1);
t.slope0 = txp.chain[0].tssi_slope;
t.offset0 = txp.chain[0].tssi_offset;
t.slope1 = txp.chain[1].tssi_slope;
t.offset1 = txp.chain[1].tssi_offset;
mt76x2u_mcu_tssi_comp(dev, &t);
if (t.pa_mode || dev->cal.dpd_cal_done)
return;
usleep_range(10000, 20000);
mt76x2u_mcu_calibrate(dev, MCU_CAL_DPD, chan->hw_value);
dev->cal.dpd_cal_done = true;
}
}
static void
mt76x2u_phy_update_channel_gain(struct mt76x2_dev *dev)
{
......@@ -155,7 +114,7 @@ void mt76x2u_phy_calibrate(struct work_struct *work)
struct mt76x2_dev *dev;
dev = container_of(work, struct mt76x2_dev, cal_work.work);
mt76x2u_phy_tssi_compensate(dev);
mt76x2_phy_tssi_compensate(dev, false);
mt76x2u_phy_update_channel_gain(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->cal_work,
......@@ -239,11 +198,11 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
MT_EXT_CCA_CFG_CCA_MASK),
ext_cca_chan[ch_group_index]);
ret = mt76x2u_mcu_set_channel(dev, channel, bw, bw_index, scan);
ret = mt76x2_mcu_set_channel(dev, channel, bw, bw_index, scan);
if (ret)
return ret;
mt76x2u_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true);
mt76x2_mcu_init_gain(dev, channel, dev->cal.rx.mcu_gain, true);
/* Enable LDPC Rx */
if (mt76xx_rev(dev) >= MT76XX_REV_E3)
......@@ -253,14 +212,15 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
u8 val = mt76x2_eeprom_get(dev, MT_EE_BT_RCAL_RESULT);
if (val != 0xff)
mt76x2u_mcu_calibrate(dev, MCU_CAL_R, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_R,
0, false);
}
mt76x2u_mcu_calibrate(dev, MCU_CAL_RXDCOC, channel);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RXDCOC, channel, false);
/* Rx LPF calibration */
if (!dev->cal.init_cal_done)
mt76x2u_mcu_calibrate(dev, MCU_CAL_RC, 0);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_RC, 0, false);
dev->cal.init_cal_done = true;
mt76_wr(dev, MT_BBP(AGC, 61), 0xff64a4e2);
......@@ -292,7 +252,8 @@ int mt76x2u_phy_set_channel(struct mt76x2_dev *dev,
flag |= BIT(0);
if (mt76x2_ext_pa_enabled(dev, chan->band))
flag |= BIT(8);
mt76x2u_mcu_calibrate(dev, MCU_CAL_TSSI, flag);
mt76x02_mcu_calibrate(&dev->mt76, MCU_CAL_TSSI,
flag, false);
dev->cal.tssi_cal_done = true;
}
}
......
......@@ -442,3 +442,19 @@ void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
mtxq->hwq = &dev->q_tx[mt76_txq_get_qid(txq)];
}
EXPORT_SYMBOL_GPL(mt76_txq_init);
u8 mt76_ac_to_hwq(u8 ac)
{
static const u8 wmm_queue_map[] = {
[IEEE80211_AC_BE] = 0,
[IEEE80211_AC_BK] = 1,
[IEEE80211_AC_VI] = 2,
[IEEE80211_AC_VO] = 3,
};
if (WARN_ON(ac >= IEEE80211_NUM_ACS))
return 0;
return wmm_queue_map[ac];
}
EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
......@@ -109,6 +109,7 @@ u32 mt76u_rr(struct mt76_dev *dev, u32 addr)
return ret;
}
EXPORT_SYMBOL_GPL(mt76u_rr);
/* should be called with usb_ctrl_mtx locked */
static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
......@@ -140,6 +141,7 @@ void mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
__mt76u_wr(dev, addr, val);
mutex_unlock(&dev->usb.usb_ctrl_mtx);
}
EXPORT_SYMBOL_GPL(mt76u_wr);
static u32 mt76u_rmw(struct mt76_dev *dev, u32 addr,
u32 mask, u32 val)
......@@ -186,6 +188,60 @@ void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
}
EXPORT_SYMBOL_GPL(mt76u_single_wr);
static int
mt76u_req_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data, int len)
{
struct mt76_usb *usb = &dev->usb;
mutex_lock(&usb->usb_ctrl_mtx);
while (len > 0) {
__mt76u_wr(dev, base + data->reg, data->value);
len--;
data++;
}
mutex_unlock(&usb->usb_ctrl_mtx);
return 0;
}
static int
mt76u_wr_rp(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *data, int n)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
return dev->mcu_ops->mcu_wr_rp(dev, base, data, n);
else
return mt76u_req_wr_rp(dev, base, data, n);
}
static int
mt76u_req_rd_rp(struct mt76_dev *dev, u32 base, struct mt76_reg_pair *data,
int len)
{
struct mt76_usb *usb = &dev->usb;
mutex_lock(&usb->usb_ctrl_mtx);
while (len > 0) {
data->value = __mt76u_rr(dev, base + data->reg);
len--;
data++;
}
mutex_unlock(&usb->usb_ctrl_mtx);
return 0;
}
static int
mt76u_rd_rp(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *data, int n)
{
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->state))
return dev->mcu_ops->mcu_rd_rp(dev, base, data, n);
else
return mt76u_req_rd_rp(dev, base, data, n);
}
static int
mt76u_set_endpoints(struct usb_interface *intf,
struct mt76_usb *usb)
......@@ -219,6 +275,7 @@ static int
mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
int nsgs, int len, int sglen)
{
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
struct urb *urb = buf->urb;
int i;
......@@ -227,7 +284,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76u_buf *buf,
void *data;
int offset;
data = netdev_alloc_frag(len);
data = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
if (!data)
break;
......@@ -494,10 +551,18 @@ static int mt76u_alloc_rx(struct mt76_dev *dev)
static void mt76u_free_rx(struct mt76_dev *dev)
{
struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
struct page *page;
int i;
for (i = 0; i < q->ndesc; i++)
mt76u_buf_free(&q->entry[i].ubuf);
if (!q->rx_page.va)
return;
page = virt_to_page(q->rx_page.va);
__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
memset(&q->rx_page, 0, sizeof(q->rx_page));
}
static void mt76u_stop_rx(struct mt76_dev *dev)
......@@ -509,40 +574,6 @@ static void mt76u_stop_rx(struct mt76_dev *dev)
usb_kill_urb(q->entry[i].ubuf.urb);
}
int mt76u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
{
struct sk_buff *iter, *last = skb;
u32 info, pad;
/* Buffer layout:
* | 4B | xfer len | pad | 4B |
* | TXINFO | pkt/cmd | zero pad to 4B | zero |
*
* length field of TXINFO should be set to 'xfer len'.
*/
info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) |
FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
put_unaligned_le32(info, skb_push(skb, sizeof(info)));
pad = round_up(skb->len, 4) + 4 - skb->len;
skb_walk_frags(skb, iter) {
last = iter;
if (!iter->next) {
skb->data_len += pad;
skb->len += pad;
break;
}
}
if (unlikely(pad)) {
if (__skb_pad(last, pad, true))
return -ENOMEM;
__skb_put(last, pad);
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76u_skb_dma_info);
static void mt76u_tx_tasklet(unsigned long data)
{
struct mt76_dev *dev = (struct mt76_dev *)data;
......@@ -715,7 +746,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
q = &dev->q_tx[i];
spin_lock_init(&q->lock);
INIT_LIST_HEAD(&q->swq);
q->hw_idx = q2hwq(i);
q->hw_idx = mt76_ac_to_hwq(i);
q->entry = devm_kzalloc(dev->dev,
MT_NUM_TX_ENTRIES * sizeof(*q->entry),
......@@ -822,6 +853,8 @@ int mt76u_init(struct mt76_dev *dev,
.wr = mt76u_wr,
.rmw = mt76u_rmw,
.copy = mt76u_copy,
.wr_rp = mt76u_wr_rp,
.rd_rp = mt76u_rd_rp,
};
struct mt76_usb *usb = &dev->usb;
......
......@@ -14,32 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/firmware.h>
#include "mt76.h"
#include "dma.h"
#define MT_CMD_HDR_LEN 4
#define MT_FCE_DMA_ADDR 0x0230
#define MT_FCE_DMA_LEN 0x0234
#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8
struct sk_buff *mt76u_mcu_msg_alloc(const void *data, int len)
{
struct sk_buff *skb;
skb = alloc_skb(MT_CMD_HDR_LEN + len + 8, GFP_KERNEL);
if (!skb)
return NULL;
skb_reserve(skb, MT_CMD_HDR_LEN);
skb_put_data(skb, data, len);
return skb;
}
EXPORT_SYMBOL_GPL(mt76u_mcu_msg_alloc);
void mt76u_mcu_complete_urb(struct urb *urb)
{
......@@ -49,223 +24,6 @@ void mt76u_mcu_complete_urb(struct urb *urb)
}
EXPORT_SYMBOL_GPL(mt76u_mcu_complete_urb);
static void
mt76u_multiple_mcu_reads(struct mt76_dev *dev, u8 *data,
int len)
{
struct mt76_usb *usb = &dev->usb;
u32 reg, val;
int i;
if (usb->mcu.burst) {
WARN_ON_ONCE(len / 4 != usb->mcu.rp_len);
reg = usb->mcu.rp[0].reg - usb->mcu.base;
for (i = 0; i < usb->mcu.rp_len; i++) {
val = get_unaligned_le32(data + 4 * i);
usb->mcu.rp[i].reg = reg++;
usb->mcu.rp[i].value = val;
}
} else {
WARN_ON_ONCE(len / 8 != usb->mcu.rp_len);
for (i = 0; i < usb->mcu.rp_len; i++) {
reg = get_unaligned_le32(data + 8 * i) -
usb->mcu.base;
val = get_unaligned_le32(data + 8 * i + 4);
WARN_ON_ONCE(usb->mcu.rp[i].reg != reg);
usb->mcu.rp[i].value = val;
}
}
}
static int mt76u_mcu_wait_resp(struct mt76_dev *dev, u8 seq)
{
struct mt76_usb *usb = &dev->usb;
struct mt76u_buf *buf = &usb->mcu.res;
int i, ret;
u32 rxfce;
u8 *data;
for (i = 0; i < 5; i++) {
if (!wait_for_completion_timeout(&usb->mcu.cmpl,
msecs_to_jiffies(300)))
continue;
if (buf->urb->status)
return -EIO;
data = sg_virt(&buf->urb->sg[0]);
if (usb->mcu.rp)
mt76u_multiple_mcu_reads(dev, data + 4,
buf->urb->actual_length - 8);
rxfce = get_unaligned_le32(data);
ret = mt76u_submit_buf(dev, USB_DIR_IN,
MT_EP_IN_CMD_RESP,
buf, GFP_KERNEL,
mt76u_mcu_complete_urb,
&usb->mcu.cmpl);
if (ret)
return ret;
if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce) &&
FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce) == EVT_CMD_DONE)
return 0;
dev_err(dev->dev, "error: MCU resp evt:%lx seq:%hhx-%lx\n",
FIELD_GET(MT_RX_FCE_INFO_EVT_TYPE, rxfce),
seq, FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, rxfce));
}
dev_err(dev->dev, "error: %s timed out\n", __func__);
return -ETIMEDOUT;
}
int __mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
struct usb_interface *intf = to_usb_interface(dev->dev);
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
unsigned int pipe;
int ret, sent;
u8 seq = 0;
u32 info;
if (test_bit(MT76_REMOVED, &dev->state))
return 0;
pipe = usb_sndbulkpipe(udev, usb->out_ep[MT_EP_OUT_INBAND_CMD]);
if (wait_resp) {
seq = ++usb->mcu.msg_seq & 0xf;
if (!seq)
seq = ++usb->mcu.msg_seq & 0xf;
}
info = FIELD_PREP(MT_MCU_MSG_CMD_SEQ, seq) |
FIELD_PREP(MT_MCU_MSG_CMD_TYPE, cmd) |
MT_MCU_MSG_TYPE_CMD;
ret = mt76u_skb_dma_info(skb, CPU_TX_PORT, info);
if (ret)
return ret;
ret = usb_bulk_msg(udev, pipe, skb->data, skb->len, &sent, 500);
if (ret)
return ret;
if (wait_resp)
ret = mt76u_mcu_wait_resp(dev, seq);
consume_skb(skb);
return ret;
}
EXPORT_SYMBOL_GPL(__mt76u_mcu_send_msg);
int mt76u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
struct mt76_usb *usb = &dev->usb;
int err;
mutex_lock(&usb->mcu.mutex);
err = __mt76u_mcu_send_msg(dev, skb, cmd, wait_resp);
mutex_unlock(&usb->mcu.mutex);
return err;
}
EXPORT_SYMBOL_GPL(mt76u_mcu_send_msg);
void mt76u_mcu_fw_reset(struct mt76_dev *dev)
{
mt76u_vendor_request(dev, MT_VEND_DEV_MODE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0x1, 0, NULL, 0);
}
EXPORT_SYMBOL_GPL(mt76u_mcu_fw_reset);
static int
__mt76u_mcu_fw_send_data(struct mt76_dev *dev, struct mt76u_buf *buf,
const void *fw_data, int len, u32 dst_addr)
{
u8 *data = sg_virt(&buf->urb->sg[0]);
DECLARE_COMPLETION_ONSTACK(cmpl);
__le32 info;
u32 val;
int err;
info = cpu_to_le32(FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, len) |
MT_MCU_MSG_TYPE_CMD);
memcpy(data, &info, sizeof(info));
memcpy(data + sizeof(info), fw_data, len);
memset(data + sizeof(info) + len, 0, 4);
mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
MT_FCE_DMA_ADDR, dst_addr);
len = roundup(len, 4);
mt76u_single_wr(dev, MT_VEND_WRITE_FCE,
MT_FCE_DMA_LEN, len << 16);
buf->len = MT_CMD_HDR_LEN + len + sizeof(info);
err = mt76u_submit_buf(dev, USB_DIR_OUT,
MT_EP_OUT_INBAND_CMD,
buf, GFP_KERNEL,
mt76u_mcu_complete_urb, &cmpl);
if (err < 0)
return err;
if (!wait_for_completion_timeout(&cmpl,
msecs_to_jiffies(1000))) {
dev_err(dev->dev, "firmware upload timed out\n");
usb_kill_urb(buf->urb);
return -ETIMEDOUT;
}
if (mt76u_urb_error(buf->urb)) {
dev_err(dev->dev, "firmware upload failed: %d\n",
buf->urb->status);
return buf->urb->status;
}
val = mt76u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX);
val++;
mt76u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val);
return 0;
}
int mt76u_mcu_fw_send_data(struct mt76_dev *dev, const void *data,
int data_len, u32 max_payload, u32 offset)
{
int err, len, pos = 0, max_len = max_payload - 8;
struct mt76u_buf buf;
err = mt76u_buf_alloc(dev, &buf, 1, max_payload, max_payload,
GFP_KERNEL);
if (err < 0)
return err;
while (data_len > 0) {
len = min_t(int, data_len, max_len);
err = __mt76u_mcu_fw_send_data(dev, &buf, data + pos,
len, offset + pos);
if (err < 0)
break;
data_len -= len;
pos += len;
usleep_range(5000, 10000);
}
mt76u_buf_free(&buf);
return err;
}
EXPORT_SYMBOL_GPL(mt76u_mcu_fw_send_data);
int mt76u_mcu_init_rx(struct mt76_dev *dev)
{
struct mt76_usb *usb = &dev->usb;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment