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;
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)
This diff is collapsed.
......@@ -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);
......
......@@ -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);
......@@ -176,7 +176,8 @@ 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));
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); */
if (scan)
mt76x0_vco_cal(dev, channel);
if (scan)
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,51 +41,15 @@ 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;
}
......@@ -148,123 +60,56 @@ void mt76x0_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
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;
while (!test_bit(MT76_REMOVED, &dev->mt76.state)) {
stat = mt76x0_mac_fetch_tx_status(dev);
if (!stat.valid)
break;
struct mt76x0_dev *dev = container_of(mdev, struct mt76x0_dev, mt76);
struct mt76x02_txwi *txwi;
int len = skb->len;
mt76x0_send_tx_status(dev, &stat, &update);
mt76x02_insert_hdr_pad(skb);
txwi = mt76x0_push_txwi(dev, skb, sta, wcid, len);
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)
{
mt76_wr(dev, offset, get_unaligned_le32(addr));
mt76_wr(dev, offset + 4, addr[4] | addr[5] << 8);
return mt76_rr(dev, MT_MCU_COM_REG0) == 1;
}
static int mt76x0_probe(struct usb_interface *usb_intf,
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)
{
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 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);
This diff is collapsed.
......@@ -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
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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