Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Add support for MediaTek MT7615 wireless chipsets
From: Ryder Lee @ 2019-04-01  7:16 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="y", Size: 3612 bytes --]

This adds support for MediaTek MT7615E 4x4 802.11ac PCIe-based chipsets.

The series is based on the Lorenzo's patches:
https://patchwork.kernel.org/project/linux-wireless/list/?series=95969

In the legacy tx arch, we move and store the whole skb content to the
on-device memory when we send packets via high speed interface. (e.g. PCIe)

However, MT7615 and the following generation use a new tx arch called
“cut-through”, which only passes the physical address to the hardware,
and the packet engine will fetch the packets before transmission.

It saves on-chip memory for high throughput devices, and the token mechanism
is used to manage the release of skb under this arch.

And there might be other (existing or future) chips that use the same driver
(e.g. mt7622/mt7663...), this is a starting point to unify MTK wireless chipsets.

Detailed hardware information for this chip could be found on 
https://wikidevi.com/wiki/MediaTek_MT7615

Ryder Lee (4):
  mt76: add mac80211 driver for MT7615 PCIe-based chipsets
  mt76: add unlikely() for dma_mapping_error() check
  mt76: use macro for sn and seq_ctrl conversion
  MAINTAINERS : update entry for mt76 wireless driver

 MAINTAINERS                                        |    2 +
 drivers/net/wireless/mediatek/mt76/Kconfig         |    1 +
 drivers/net/wireless/mediatek/mt76/Makefile        |    1 +
 drivers/net/wireless/mediatek/mt76/agg-rx.c        |    2 +-
 drivers/net/wireless/mediatek/mt76/dma.c           |    8 +-
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c    |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/main.c   |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig  |    7 +
 drivers/net/wireless/mediatek/mt76/mt7615/Makefile |    5 +
 drivers/net/wireless/mediatek/mt76/mt7615/dma.c    |  205 +++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c |   98 ++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h |   18 +
 drivers/net/wireless/mediatek/mt76/mt7615/init.c   |  229 +++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    |  775 +++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.h    |  300 ++++
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |  499 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c    | 1656 ++++++++++++++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h    |  520 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |  195 +++
 drivers/net/wireless/mediatek/mt76/mt7615/pci.c    |  150 ++
 drivers/net/wireless/mediatek/mt76/mt7615/regs.h   |  203 +++
 drivers/net/wireless/mediatek/mt76/mt76x02_util.c  |    2 +-
 22 files changed, 4872 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Makefile
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/dma.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/init.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/main.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/pci.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/regs.h

-- 
1.9.1


^ permalink raw reply

* [PATCH v3 3/4] mt76: use macro for sn and seq_ctrl conversion
From: Ryder Lee @ 2019-04-01  7:16 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554102584.git.ryder.lee@mediatek.com>

Use macro to convert sn and seq_ctrl for better readability.

Signed-off-by: Roy Luo <royluo@google.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/agg-rx.c       | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c   | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/main.c  | 2 +-
 drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c
index 73c8b28..27e3ff0 100644
--- a/drivers/net/wireless/mediatek/mt76/agg-rx.c
+++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c
@@ -135,7 +135,7 @@
 		return;
 
 	status->tid = le16_to_cpu(bar->control) >> 12;
-	seqno = le16_to_cpu(bar->start_seq_num) >> 4;
+	seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
 	tid = rcu_dereference(wcid->aggr[status->tid]);
 	if (!tid)
 		return;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index e498169..2f2961e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -627,7 +627,7 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ssn,
 	status->aggr = unicast &&
 		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
 	status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
-	status->seqno = hdr->seq_ctrl >> 4;
+	status->seqno = IEEE80211_SEQ_TO_SN(hdr->seq_ctrl);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 5d38392..0c78044 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -594,7 +594,7 @@
 		mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, *ssn, -1);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		mtxq->agg_ssn = *ssn << 4;
+		mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index b137ce8..f0e1e12 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -378,7 +378,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		mtxq->agg_ssn = *ssn << 4;
+		mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
-- 
1.9.1


^ permalink raw reply related

* [PATCH v3 4/4] MAINTAINERS : update entry for mt76 wireless driver
From: Ryder Lee @ 2019-04-01  7:16 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554102584.git.ryder.lee@mediatek.com>

Roy and I actively join the development and review.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e17ebf7..7d92a87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9768,6 +9768,8 @@ F:	Documentation/devicetree/bindings/media/mediatek-vpu.txt
 MEDIATEK MT76 WIRELESS LAN DRIVER
 M:	Felix Fietkau <nbd@nbd.name>
 M:	Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+R:	Ryder Lee <ryder.lee@mediatek.com>
+R:	Roy Luo <royluo@google.com>
 L:	linux-wireless@vger.kernel.org
 S:	Maintained
 F:	drivers/net/wireless/mediatek/mt76/
-- 
1.9.1


^ permalink raw reply related

* [PATCH v3 2/4] mt76: add unlikely() for dma_mapping_error() check
From: Ryder Lee @ 2019-04-01  7:16 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554102584.git.ryder.lee@mediatek.com>

In the tx/rx fastpath, the funciton dma_map_single() rarely fails.
This adds unlikely() optimization to this error check conditional.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/dma.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 8a4b935..6f3ef09 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -272,7 +272,7 @@
 
 	addr = dma_map_single(dev->dev, skb->data, skb->len,
 			      DMA_TO_DEVICE);
-	if (dma_mapping_error(dev->dev, addr))
+	if (unlikely(dma_mapping_error(dev->dev, addr)))
 		return -ENOMEM;
 
 	buf.addr = addr;
@@ -315,7 +315,7 @@
 
 	len = skb_headlen(skb);
 	addr = dma_map_single(dev->dev, skb->data, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(dev->dev, addr))
+	if (unlikely(dma_mapping_error(dev->dev, addr)))
 		goto free;
 
 	tx_info.buf[n].addr = t->dma_addr;
@@ -329,7 +329,7 @@
 
 		addr = dma_map_single(dev->dev, iter->data, iter->len,
 				      DMA_TO_DEVICE);
-		if (dma_mapping_error(dev->dev, addr))
+		if (unlikely(dma_mapping_error(dev->dev, addr)))
 			goto unmap;
 
 		tx_info.buf[n].addr = addr;
@@ -386,7 +386,7 @@
 			break;
 
 		addr = dma_map_single(dev->dev, buf, len, DMA_FROM_DEVICE);
-		if (dma_mapping_error(dev->dev, addr)) {
+		if (unlikely(dma_mapping_error(dev->dev, addr))) {
 			skb_free_frag(buf);
 			break;
 		}
-- 
1.9.1


^ permalink raw reply related

* [PATCH v2 1/4] mt76: add mac80211 driver for MT7615 PCIe-based chipsets
From: Ryder Lee @ 2019-04-01  6:56 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee,
	Lorenzo Bianconi
In-Reply-To: <cover.1554100584.git.ryder.lee@mediatek.com>

This driver is for a newer generation of MediaTek MT7615 4x4 802.11ac
PCIe-based chipsets, which support wave2 MU-MIMO up to 4 users/group
and also support up to 160MHz bandwidth.

The driver fully supports AP, station and monitor mode.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Roy Luo <royluo@google.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
Changes since v2:
-switch to use ISC license
-use sw assign sequence number
-add missing hw rate setting
---
 drivers/net/wireless/mediatek/mt76/Kconfig         |    1 +
 drivers/net/wireless/mediatek/mt76/Makefile        |    1 +
 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig  |    7 +
 drivers/net/wireless/mediatek/mt76/mt7615/Makefile |    5 +
 drivers/net/wireless/mediatek/mt76/mt7615/dma.c    |  205 +++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c |   98 ++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h |   18 +
 drivers/net/wireless/mediatek/mt76/mt7615/init.c   |  229 +++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    |  774 +++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.h    |  300 ++++
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |  499 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c    | 1656 ++++++++++++++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h    |  520 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |  195 +++
 drivers/net/wireless/mediatek/mt76/mt7615/pci.c    |  150 ++
 drivers/net/wireless/mediatek/mt76/mt7615/regs.h   |  203 +++
 16 files changed, 4861 insertions(+)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Makefile
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/dma.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/init.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/main.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/pci.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/regs.h

diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig
index dbe8c70..30e44e4 100644
--- a/drivers/net/wireless/mediatek/mt76/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/Kconfig
@@ -22,3 +22,4 @@ config MT76x02_USB
 source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
 source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
 source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
+source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig"
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index cad4fed..7beae23 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -23,3 +23,4 @@ mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
 obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
 obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
 obj-$(CONFIG_MT7603E) += mt7603/
+obj-$(CONFIG_MT7615E) += mt7615/
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
new file mode 100644
index 0000000..3b8aba0
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -0,0 +1,7 @@
+config MT7615E
+	tristate "MediaTek MT7615E (PCIe) support"
+	select MT76_CORE
+	depends on MAC80211
+	depends on PCI
+	help
+	  This adds support for MT7615-based wireless PCIe devices.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
new file mode 100644
index 0000000..6397552
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
@@ -0,0 +1,5 @@
+#SPDX-License-Identifier: ISC
+
+obj-$(CONFIG_MT7615E) += mt7615e.o
+
+mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
new file mode 100644
index 0000000..3ec6582
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *         Roy Luo <royluo@google.com>
+ *         Lorenzo Bianconi <lorenzo@kernel.org>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include "mt7615.h"
+#include "../dma.h"
+#include "mac.h"
+
+static int
+mt7615_init_tx_queues(struct mt7615_dev *dev, int n_desc)
+{
+	struct mt76_sw_queue *q;
+	struct mt76_queue *hwq;
+	int err, i;
+
+	hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
+	if (!hwq)
+		return -ENOMEM;
+
+	err = mt76_queue_alloc(dev, hwq, 0, n_desc, 0, MT_TX_RING_BASE);
+	if (err < 0)
+		return err;
+
+	for (i = 0; i < MT_TXQ_MCU; i++) {
+		q = &dev->mt76.q_tx[i];
+		INIT_LIST_HEAD(&q->swq);
+		q->q = hwq;
+	}
+
+	return 0;
+}
+
+static int
+mt7615_init_mcu_queue(struct mt7615_dev *dev, struct mt76_sw_queue *q,
+		      int idx, int n_desc)
+{
+	struct mt76_queue *hwq;
+	int err;
+
+	hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
+	if (!hwq)
+		return -ENOMEM;
+
+	err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
+	if (err < 0)
+		return err;
+
+	INIT_LIST_HEAD(&q->swq);
+	q->q = hwq;
+
+	return 0;
+}
+
+void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+			 struct sk_buff *skb)
+{
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+	__le32 *rxd = (__le32 *)skb->data;
+	__le32 *end = (__le32 *)&skb->data[skb->len];
+	enum rx_pkt_type type;
+
+	type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
+
+	switch (type) {
+	case PKT_TYPE_TXS:
+		for (rxd++; rxd + 7 <= end; rxd += 7)
+			mt7615_mac_add_txs(dev, rxd);
+		dev_kfree_skb(skb);
+		break;
+	case PKT_TYPE_TXRX_NOTIFY:
+		mt7615_mac_tx_free(dev, skb);
+		break;
+	case PKT_TYPE_RX_EVENT:
+		mt76_mcu_rx_event(&dev->mt76, skb);
+		break;
+	case PKT_TYPE_NORMAL:
+		if (!mt7615_mac_fill_rx(dev, skb)) {
+			mt76_rx(&dev->mt76, q, skb);
+			return;
+		}
+		/* fall through */
+	default:
+		dev_kfree_skb(skb);
+		break;
+	}
+}
+
+static void mt7615_tx_tasklet(unsigned long data)
+{
+	struct mt7615_dev *dev = (struct mt7615_dev *)data;
+	static const u8 queue_map[] = {
+		MT_TXQ_MCU,
+		MT_TXQ_BE
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(queue_map); i++)
+		mt76_queue_tx_cleanup(dev, queue_map[i], false);
+
+	mt76_txq_schedule_all(&dev->mt76);
+
+	mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
+}
+
+int mt7615_dma_init(struct mt7615_dev *dev)
+{
+	int ret;
+
+	mt76_dma_attach(&dev->mt76);
+
+	tasklet_init(&dev->mt76.tx_tasklet, mt7615_tx_tasklet,
+		     (unsigned long)dev);
+
+	mt76_wr(dev, MT_WPDMA_GLO_CFG,
+		MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE |
+		MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN |
+		MT_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY |
+		MT_WPDMA_GLO_CFG_OMIT_TX_INFO);
+
+	mt76_rmw_field(dev, MT_WPDMA_GLO_CFG,
+		       MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT0, 0x1);
+
+	mt76_rmw_field(dev, MT_WPDMA_GLO_CFG,
+		       MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT21, 0x1);
+
+	mt76_rmw_field(dev, MT_WPDMA_GLO_CFG,
+		       MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 0x3);
+
+	mt76_rmw_field(dev, MT_WPDMA_GLO_CFG,
+		       MT_WPDMA_GLO_CFG_MULTI_DMA_EN, 0x3);
+
+	mt76_wr(dev, MT_WPDMA_GLO_CFG1, 0x1);
+	mt76_wr(dev, MT_WPDMA_TX_PRE_CFG, 0xf0000);
+	mt76_wr(dev, MT_WPDMA_RX_PRE_CFG, 0xf7f0000);
+	mt76_wr(dev, MT_WPDMA_ABT_CFG, 0x4000026);
+	mt76_wr(dev, MT_WPDMA_ABT_CFG1, 0x18811881);
+	mt76_set(dev, 0x7158, BIT(16));
+	mt76_clear(dev, 0x7000, BIT(23));
+	mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
+
+	ret = mt7615_init_tx_queues(dev, MT7615_TX_RING_SIZE);
+	if (ret)
+		return ret;
+
+	ret = mt7615_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
+				    MT7615_TXQ_MCU,
+				    MT7615_TX_MCU_RING_SIZE);
+	if (ret)
+		return ret;
+
+	ret = mt7615_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
+				    MT7615_TXQ_FWDL,
+				    MT7615_TX_FWDL_RING_SIZE);
+	if (ret)
+		return ret;
+
+	/* init rx queues */
+	ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
+			       MT7615_RX_MCU_RING_SIZE, MT_RX_BUF_SIZE,
+			       MT_RX_RING_BASE);
+	if (ret)
+		return ret;
+
+	ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
+			       MT7615_RX_RING_SIZE, MT_RX_BUF_SIZE,
+			       MT_RX_RING_BASE);
+	if (ret)
+		return ret;
+
+	mt76_wr(dev, MT_DELAY_INT_CFG, 0);
+
+	ret = mt76_init_queues(dev);
+	if (ret < 0)
+		return ret;
+
+	mt76_poll(dev, MT_WPDMA_GLO_CFG,
+		  MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
+		  MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000);
+
+	/* start dma engine */
+	mt76_set(dev, MT_WPDMA_GLO_CFG,
+		 MT_WPDMA_GLO_CFG_TX_DMA_EN |
+		 MT_WPDMA_GLO_CFG_RX_DMA_EN);
+
+	/* enable interrupts for TX/RX rings */
+	mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL);
+
+	return 0;
+}
+
+void mt7615_dma_cleanup(struct mt7615_dev *dev)
+{
+	mt76_clear(dev, MT_WPDMA_GLO_CFG,
+		   MT_WPDMA_GLO_CFG_TX_DMA_EN |
+		   MT_WPDMA_GLO_CFG_RX_DMA_EN);
+	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
+
+	tasklet_kill(&dev->mt76.tx_tasklet);
+	mt76_dma_cleanup(&dev->mt76);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
new file mode 100644
index 0000000..dd5ab46
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include "mt7615.h"
+#include "eeprom.h"
+
+static int mt7615_efuse_read(struct mt7615_dev *dev, u32 base,
+			     u16 addr, u8 *data)
+{
+	u32 val;
+	int i;
+
+	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
+	val &= ~(MT_EFUSE_CTRL_AIN | MT_EFUSE_CTRL_MODE);
+	val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf);
+	val |= MT_EFUSE_CTRL_KICK;
+	mt76_wr(dev, base + MT_EFUSE_CTRL, val);
+
+	if (!mt76_poll(dev, base + MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000))
+		return -ETIMEDOUT;
+
+	udelay(2);
+
+	val = mt76_rr(dev, base + MT_EFUSE_CTRL);
+	if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT ||
+	    WARN_ON_ONCE(!(val & MT_EFUSE_CTRL_VALID))) {
+		memset(data, 0x0, 16);
+		return 0;
+	}
+
+	for (i = 0; i < 4; i++) {
+		val = mt76_rr(dev, base + MT_EFUSE_RDATA(i));
+		put_unaligned_le32(val, data + 4 * i);
+	}
+
+	return 0;
+}
+
+static int mt7615_efuse_init(struct mt7615_dev *dev)
+{
+	u32 base = mt7615_reg_map(dev, MT_EFUSE_BASE);
+	int len = MT7615_EEPROM_SIZE;
+	int ret, i;
+	void *buf;
+
+	if (mt76_rr(dev, base + MT_EFUSE_BASE_CTRL) & MT_EFUSE_BASE_CTRL_EMPTY)
+		return -EINVAL;
+
+	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, len, GFP_KERNEL);
+	dev->mt76.otp.size = len;
+	if (!dev->mt76.otp.data)
+		return -ENOMEM;
+
+	buf = dev->mt76.otp.data;
+	for (i = 0; i + 16 <= len; i += 16) {
+		ret = mt7615_efuse_read(dev, base, i, buf + i);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mt7615_eeprom_load(struct mt7615_dev *dev)
+{
+	int ret;
+
+	ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE);
+	if (ret < 0)
+		return ret;
+
+	return mt7615_efuse_init(dev);
+}
+
+int mt7615_eeprom_init(struct mt7615_dev *dev)
+{
+	int ret;
+
+	ret = mt7615_eeprom_load(dev);
+	if (ret < 0)
+		return ret;
+
+	memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, MT7615_EEPROM_SIZE);
+
+	dev->mt76.cap.has_2ghz = true;
+	dev->mt76.cap.has_5ghz = true;
+
+	memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+	       ETH_ALEN);
+
+	mt76_eeprom_override(&dev->mt76);
+
+	return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
new file mode 100644
index 0000000..a4cf166
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2019 MediaTek Inc. */
+
+#ifndef __MT7615_EEPROM_H
+#define __MT7615_EEPROM_H
+
+#include "mt7615.h"
+
+enum mt7615_eeprom_field {
+	MT_EE_CHIP_ID =				0x000,
+	MT_EE_VERSION =				0x002,
+	MT_EE_MAC_ADDR =			0x004,
+	MT_EE_NIC_CONF_0 =			0x034,
+
+	__MT_EE_MAX =				0x3bf
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
new file mode 100644
index 0000000..19412df
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Roy Luo <royluo@google.com>
+ *         Ryder Lee <ryder.lee@mediatek.com>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <linux/etherdevice.h>
+#include "mt7615.h"
+#include "mac.h"
+
+static void mt7615_phy_init(struct mt7615_dev *dev)
+{
+	/* disable band 0 rf low power beacon mode */
+	mt76_rmw(dev, MT_WF_PHY_WF2_RFCTRL0, MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN,
+		 MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN);
+}
+
+static void mt7615_mac_init(struct mt7615_dev *dev)
+{
+	/* enable band 0 clk */
+	mt76_rmw(dev, MT_CFG_CCR,
+		 MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN,
+		 MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN);
+
+	mt76_rmw_field(dev, MT_TMAC_CTCR0,
+		       MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
+	mt76_rmw_field(dev, MT_TMAC_CTCR0,
+		       MT_TMAC_CTCR0_INS_DDLMT_DENSITY, 0x3);
+	mt76_rmw(dev, MT_TMAC_CTCR0,
+		 MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
+		 MT_TMAC_CTCR0_INS_DDLMT_EN,
+		 MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
+		 MT_TMAC_CTCR0_INS_DDLMT_EN);
+
+	mt7615_mcu_set_rts_thresh(dev, 0x92b);
+
+	mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
+		 MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
+
+	mt7615_mcu_init_mac(dev);
+
+	mt76_wr(dev, MT_DMA_DCR0, MT_DMA_DCR0_RX_VEC_DROP |
+		FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072));
+
+	mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7));
+	mt76_wr(dev, MT_AGG_ARDCR,
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 0) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(1),
+			   max_t(int, 0, MT7615_RATE_RETRY - 2)) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7615_RATE_RETRY - 1) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7615_RATE_RETRY - 1) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7615_RATE_RETRY - 1) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7615_RATE_RETRY - 1) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) |
+		FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1));
+
+	mt76_wr(dev, MT_AGG_ARCR,
+		(MT_AGG_ARCR_INIT_RATE1 |
+		 FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) |
+		 MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
+		 FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
+		 FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)));
+
+	dev->mt76.global_wcid.idx = MT7615_WTBL_RESERVED;
+	dev->mt76.global_wcid.hw_key_idx = -1;
+	rcu_assign_pointer(dev->mt76.wcid[MT7615_WTBL_RESERVED],
+			   &dev->mt76.global_wcid);
+}
+
+static int mt7615_init_hardware(struct mt7615_dev *dev)
+{
+	int ret;
+
+	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
+
+	spin_lock_init(&dev->token_lock);
+	idr_init(&dev->token);
+
+	ret = mt7615_eeprom_init(dev);
+	if (ret < 0)
+		return ret;
+
+	ret = mt7615_dma_init(dev);
+	if (ret)
+		return ret;
+
+	set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
+
+	ret = mt7615_mcu_init(dev);
+	if (ret)
+		return ret;
+
+	mt7615_mcu_set_eeprom(dev);
+	mt7615_mac_init(dev);
+	mt7615_phy_init(dev);
+	mt7615_mcu_ctrl_pm_state(dev, 0);
+	mt7615_mcu_del_wtbl_all(dev);
+
+	return 0;
+}
+
+#define CCK_RATE(_idx, _rate) {						\
+	.bitrate = _rate,						\
+	.flags = IEEE80211_RATE_SHORT_PREAMBLE,				\
+	.hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx),			\
+	.hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)),	\
+}
+
+#define OFDM_RATE(_idx, _rate) {					\
+	.bitrate = _rate,						\
+	.hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx),			\
+	.hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx),		\
+}
+
+static struct ieee80211_rate mt7615_rates[] = {
+	CCK_RATE(0, 10),
+	CCK_RATE(1, 20),
+	CCK_RATE(2, 55),
+	CCK_RATE(3, 110),
+	OFDM_RATE(11, 60),
+	OFDM_RATE(15, 90),
+	OFDM_RATE(10, 120),
+	OFDM_RATE(14, 180),
+	OFDM_RATE(9,  240),
+	OFDM_RATE(13, 360),
+	OFDM_RATE(8,  480),
+	OFDM_RATE(12, 540),
+};
+
+static const struct ieee80211_iface_limit if_limits[] = {
+	{
+		.max = MT7615_MAX_INTERFACES,
+		.types = BIT(NL80211_IFTYPE_AP) |
+			 BIT(NL80211_IFTYPE_STATION);
+	}
+};
+
+static const struct ieee80211_iface_combination if_comb[] = {
+	{
+		.limits = if_limits,
+		.n_limits = ARRAY_SIZE(if_limits),
+		.max_interfaces = 4,
+		.num_different_channels = 1,
+		.beacon_int_infra_match = true,
+	}
+};
+
+static int mt7615_init_debugfs(struct mt7615_dev *dev)
+{
+	struct dentry *dir;
+
+	dir = mt76_register_debugfs(&dev->mt76);
+	if (!dir)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int mt7615_register_device(struct mt7615_dev *dev)
+{
+	struct ieee80211_hw *hw = mt76_hw(dev);
+	struct wiphy *wiphy = hw->wiphy;
+	int ret;
+
+	ret = mt7615_init_hardware(dev);
+	if (ret)
+		return ret;
+
+	INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
+
+	hw->queues = 4;
+	hw->max_rates = 3;
+	hw->max_report_rates = 7;
+	hw->max_rate_tries = 11;
+
+	hw->sta_data_size = sizeof(struct mt7615_sta);
+	hw->vif_data_size = sizeof(struct mt7615_vif);
+
+	wiphy->iface_combinations = if_comb;
+	wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+
+	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
+	ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
+
+	dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
+	dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
+	dev->mt76.sband_5g.sband.vht_cap.cap |=
+			IEEE80211_VHT_CAP_SHORT_GI_160 |
+			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+	dev->mt76.chainmask = 0x404;
+	dev->mt76.antenna_mask = 0xf;
+
+	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+				 BIT(NL80211_IFTYPE_AP);
+
+	ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
+				   ARRAY_SIZE(mt7615_rates));
+	if (ret)
+		return ret;
+
+	hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM;
+
+	return mt7615_init_debugfs(dev);
+}
+
+void mt7615_unregister_device(struct mt7615_dev *dev)
+{
+	struct mt76_txwi_cache *txwi;
+	int id;
+
+	spin_lock_bh(&dev->token_lock);
+	idr_for_each_entry(&dev->token, txwi, id) {
+		mt7615_txp_skb_unmap(&dev->mt76, txwi);
+		if (txwi->skb)
+			dev_kfree_skb_any(txwi->skb);
+		mt76_put_txwi(&dev->mt76, txwi);
+	}
+	spin_unlock_bh(&dev->token_lock);
+	idr_destroy(&dev->token);
+	mt76_unregister_device(&dev->mt76);
+	mt7615_mcu_exit(dev);
+	mt7615_dma_cleanup(dev);
+
+	ieee80211_free_hw(mt76_hw(dev));
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
new file mode 100644
index 0000000..b855ad8
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -0,0 +1,774 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *         Roy Luo <royluo@google.com>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/timekeeping.h>
+#include "mt7615.h"
+#include "../dma.h"
+#include "mac.h"
+
+static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
+					    u8 idx, bool unicast)
+{
+	struct mt7615_sta *sta;
+	struct mt76_wcid *wcid;
+
+	if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+		return NULL;
+
+	wcid = rcu_dereference(dev->mt76.wcid[idx]);
+	if (unicast || !wcid)
+		return wcid;
+
+	if (!wcid->sta)
+		return NULL;
+
+	sta = container_of(wcid, struct mt7615_sta, wcid);
+	if (!sta->vif)
+		return NULL;
+
+	return &sta->vif->sta.wcid;
+}
+
+static int mt7615_get_rate(struct mt7615_dev *dev,
+			   struct ieee80211_supported_band *sband,
+			   int idx, bool cck)
+{
+	int offset = 0;
+	int len = sband->n_bitrates;
+	int i;
+
+	if (cck) {
+		if (sband == &dev->mt76.sband_5g.sband)
+			return 0;
+
+		idx &= ~BIT(2); /* short preamble */
+	} else if (sband == &dev->mt76.sband_2g.sband) {
+		offset = 4;
+	}
+
+	for (i = offset; i < len; i++) {
+		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
+			return i;
+	}
+
+	return 0;
+}
+
+static void mt7615_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
+	u8 *pn = status->iv;
+	u8 *hdr;
+
+	__skb_push(skb, 8);
+	memmove(skb->data, skb->data + 8, hdr_len);
+	hdr = skb->data + hdr_len;
+
+	hdr[0] = pn[5];
+	hdr[1] = pn[4];
+	hdr[2] = 0;
+	hdr[3] = 0x20 | (key_id << 6);
+	hdr[4] = pn[3];
+	hdr[5] = pn[2];
+	hdr[6] = pn[1];
+	hdr[7] = pn[0];
+
+	status->flag &= ~RX_FLAG_IV_STRIPPED;
+}
+
+int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_hdr *hdr;
+	__le32 *rxd = (__le32 *)skb->data;
+	u32 rxd0 = le32_to_cpu(rxd[0]);
+	u32 rxd1 = le32_to_cpu(rxd[1]);
+	u32 rxd2 = le32_to_cpu(rxd[2]);
+	bool unicast, remove_pad, insert_ccmp_hdr = false;
+	int i, idx;
+
+	memset(status, 0, sizeof(*status));
+
+	unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
+	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
+	status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
+
+	/* TODO: properly support DBDC */
+	status->freq = dev->mt76.chandef.chan->center_freq;
+	status->band = dev->mt76.chandef.chan->band;
+	if (status->band == NL80211_BAND_5GHZ)
+		sband = &dev->mt76.sband_5g.sband;
+	else
+		sband = &dev->mt76.sband_2g.sband;
+
+	if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
+		status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+	if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR)
+		status->flag |= RX_FLAG_MMIC_ERROR;
+
+	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
+	    !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
+		status->flag |= RX_FLAG_DECRYPTED;
+		status->flag |= RX_FLAG_IV_STRIPPED;
+		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
+	}
+
+	remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
+
+	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
+		return -EINVAL;
+
+	if (!sband->channels)
+		return -EINVAL;
+
+	rxd += 4;
+	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
+		rxd += 4;
+		if ((u8 *)rxd - skb->data >= skb->len)
+			return -EINVAL;
+	}
+
+	if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
+		u8 *data = (u8 *)rxd;
+
+		if (status->flag & RX_FLAG_DECRYPTED) {
+			status->iv[0] = data[5];
+			status->iv[1] = data[4];
+			status->iv[2] = data[3];
+			status->iv[3] = data[2];
+			status->iv[4] = data[1];
+			status->iv[5] = data[0];
+
+			insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
+		}
+		rxd += 4;
+		if ((u8 *)rxd - skb->data >= skb->len)
+			return -EINVAL;
+	}
+
+	if (rxd0 & MT_RXD0_NORMAL_GROUP_2) {
+		rxd += 2;
+		if ((u8 *)rxd - skb->data >= skb->len)
+			return -EINVAL;
+	}
+
+	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
+		u32 rxdg0 = le32_to_cpu(rxd[0]);
+		u32 rxdg1 = le32_to_cpu(rxd[1]);
+		u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
+		bool cck = false;
+
+		i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0);
+		switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
+		case MT_PHY_TYPE_CCK:
+			cck = true;
+			/* fall through */
+		case MT_PHY_TYPE_OFDM:
+			i = mt7615_get_rate(dev, sband, i, cck);
+			break;
+		case MT_PHY_TYPE_HT_GF:
+		case MT_PHY_TYPE_HT:
+			status->encoding = RX_ENC_HT;
+			if (i > 31)
+				return -EINVAL;
+			break;
+		case MT_PHY_TYPE_VHT:
+			status->nss = FIELD_GET(MT_RXV2_NSTS, rxdg1) + 1;
+			status->encoding = RX_ENC_VHT;
+			break;
+		default:
+			return -EINVAL;
+		}
+		status->rate_idx = i;
+
+		switch (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0)) {
+		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;
+		case MT_PHY_BW_160:
+			status->bw = RATE_INFO_BW_160;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (rxdg0 & MT_RXV1_HT_SHORT_GI)
+			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
+		if (rxdg0 & MT_RXV1_HT_AD_CODE)
+			status->enc_flags |= RX_ENC_FLAG_LDPC;
+
+		status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
+
+		/* TODO: RSSI */
+		rxd += 6;
+		if ((u8 *)rxd - skb->data >= skb->len)
+			return -EINVAL;
+	}
+
+	skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad);
+
+	if (insert_ccmp_hdr) {
+		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
+
+		mt7615_insert_ccmp_hdr(skb, key_id);
+	}
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
+		return 0;
+
+	status->aggr = unicast &&
+		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
+	status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+	status->seqno = IEEE80211_SEQ_TO_SN(hdr->seq_ctrl);
+
+	return 0;
+}
+
+void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
+{
+}
+
+void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
+			    struct mt76_queue_entry *e)
+{
+	if (!e->txwi) {
+		dev_kfree_skb_any(e->skb);
+		return;
+	}
+
+	/* error path */
+	if (e->skb == DMA_DUMMY_DATA) {
+		struct mt76_txwi_cache *t;
+		struct mt7615_dev *dev;
+		struct mt7615_txp *txp;
+		u8 *txwi_ptr;
+
+		txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
+		txp = (struct mt7615_txp *)(txwi_ptr + MT_TXD_SIZE);
+		dev = container_of(mdev, struct mt7615_dev, mt76);
+
+		spin_lock_bh(&dev->token_lock);
+		t = idr_remove(&dev->token, le16_to_cpu(txp->token));
+		spin_unlock_bh(&dev->token_lock);
+		e->skb = t ? t->skb : NULL;
+	}
+
+	if (e->skb)
+		mt76_tx_complete_skb(mdev, e->skb);
+}
+
+u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
+			   const struct ieee80211_tx_rate *rate,
+			   bool stbc, u8 *bw)
+{
+	u8 phy, nss, rate_idx;
+	u16 rateval;
+
+	*bw = 0;
+
+	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+		rate_idx = ieee80211_rate_get_vht_mcs(rate);
+		nss = ieee80211_rate_get_vht_nss(rate);
+		phy = MT_PHY_TYPE_VHT;
+		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+			*bw = 1;
+		else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+			*bw = 2;
+		else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+			*bw = 3;
+	} 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;
+
+		nss = 1;
+		r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx];
+		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+			val = r->hw_value_short;
+		else
+			val = r->hw_value;
+
+		phy = val >> 8;
+		rate_idx = val & 0xff;
+	}
+
+	rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
+		   FIELD_PREP(MT_TX_RATE_MODE, phy) |
+		   FIELD_PREP(MT_TX_RATE_NSS, nss - 1));
+
+	if (stbc && nss == 1)
+		rateval |= MT_TX_RATE_STBC;
+
+	return rateval;
+}
+
+int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
+			  struct sk_buff *skb, struct mt76_wcid *wcid,
+			  struct ieee80211_sta *sta, int pid,
+			  struct ieee80211_key_conf *key)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_tx_rate *rate = &info->control.rates[0];
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_vif *vif = info->control.vif;
+	int tx_count = 8;
+	u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	u16 seqno = 0;
+	u32 val;
+
+	if (vif) {
+		struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+
+		omac_idx = mvif->omac_idx;
+	}
+
+	if (sta) {
+		struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+
+		tx_count = msta->rate_count;
+	}
+
+	fc_type = (fc & IEEE80211_FCTL_FTYPE) >> 2;
+	fc_stype = (fc & IEEE80211_FCTL_STYPE) >> 4;
+
+	if (ieee80211_is_data(fc)) {
+		q_idx = skb_get_queue_mapping(skb);
+		p_fmt = MT_TX_TYPE_CT;
+	} else if (ieee80211_is_beacon(fc)) {
+		q_idx = MT_LMAC_BCN0;
+		p_fmt = MT_TX_TYPE_FW;
+	} else {
+		q_idx = MT_LMAC_ALTX0;
+		p_fmt = MT_TX_TYPE_CT;
+	}
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
+	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txwi[0] = cpu_to_le32(val);
+
+	val = MT_TXD1_LONG_FORMAT |
+	      FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
+	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+	      FIELD_PREP(MT_TXD1_HDR_INFO,
+			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
+	      FIELD_PREP(MT_TXD1_TID,
+			 skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
+	      FIELD_PREP(MT_TXD1_PKT_FMT, p_fmt) |
+	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
+	txwi[1] = cpu_to_le32(val);
+
+	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
+	      FIELD_PREP(MT_TXD2_MULTICAST,
+			 is_multicast_ether_addr(hdr->addr1));
+	txwi[2] = cpu_to_le32(val);
+
+	if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
+		txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
+
+	txwi[4] = 0;
+	txwi[6] = 0;
+
+	if (rate->idx >= 0 && rate->count &&
+	    !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
+		bool stbc = info->flags & IEEE80211_TX_CTL_STBC;
+		u8 bw;
+		u16 rateval = mt7615_mac_tx_rate_val(dev, rate, stbc, &bw);
+
+		txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
+
+		val = MT_TXD6_FIXED_BW |
+		      FIELD_PREP(MT_TXD6_BW, bw) |
+		      FIELD_PREP(MT_TXD6_TX_RATE, rateval);
+		txwi[6] |= cpu_to_le32(val);
+
+		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+			txwi[6] |= cpu_to_le32(MT_TXD6_SGI);
+
+		if (info->flags & IEEE80211_TX_CTL_LDPC)
+			txwi[6] |= cpu_to_le32(MT_TXD6_LDPC);
+
+		if (!(rate->flags & (IEEE80211_TX_RC_MCS |
+				     IEEE80211_TX_RC_VHT_MCS)))
+			txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
+
+		tx_count = rate->count;
+	}
+
+	if (!ieee80211_is_beacon(fc)) {
+		val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT |
+		      FIELD_PREP(MT_TXD5_PID, pid);
+		txwi[5] = cpu_to_le32(val);
+	} else {
+		txwi[5] = 0;
+		/* use maximum tx count for beacons */
+		tx_count = 0x1f;
+	}
+
+	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+	if (ieee80211_is_data_qos(hdr->frame_control)) {
+		seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+		val |= MT_TXD3_SN_VALID;
+	} else if (ieee80211_is_back_req(hdr->frame_control)) {
+		struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
+
+		seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
+		val |= MT_TXD3_SN_VALID;
+	}
+	val |= FIELD_PREP(MT_TXD3_SEQ, seqno);
+
+	txwi[3] = cpu_to_le32(val);
+
+	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+		txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
+
+	if (key)
+		txwi[3] |= cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+
+	txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
+		  FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
+
+	return 0;
+}
+
+void mt7615_txp_skb_unmap(struct mt76_dev *dev,
+			  struct mt76_txwi_cache *t)
+{
+	struct mt7615_txp *txp;
+	u8 *txwi;
+	int i;
+
+	txwi = mt76_get_txwi_ptr(dev, t);
+	txp = (struct mt7615_txp *)(txwi + MT_TXD_SIZE);
+	for (i = 1; i < txp->nbuf; i++)
+		dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
+				 le32_to_cpu(txp->len[i]), DMA_TO_DEVICE);
+}
+
+int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
+			  struct ieee80211_sta *sta,
+			  struct mt76_tx_info *tx_info)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+	struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+	struct ieee80211_key_conf *key = info->control.hw_key;
+	struct ieee80211_vif *vif = info->control.vif;
+	int i, pid, id, nbuf = tx_info->nbuf - 1;
+	u8 *txwi = (u8 *)txwi_ptr;
+	struct mt76_txwi_cache *t;
+	struct mt7615_txp *txp;
+
+	if (!wcid)
+		wcid = &dev->mt76.global_wcid;
+
+	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+
+	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+		spin_lock_bh(&dev->mt76.lock);
+		msta->rate_probe = true;
+		mt7615_mcu_set_rates(dev, msta, &info->control.rates[0],
+				     msta->rates);
+		spin_unlock_bh(&dev->mt76.lock);
+	}
+
+	mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta,
+			      pid, key);
+
+	txp = (struct mt7615_txp *)(txwi + MT_TXD_SIZE);
+	for (i = 0; i < nbuf; i++) {
+		txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
+		txp->len[i] = cpu_to_le32(tx_info->buf[i + 1].len);
+	}
+	txp->nbuf = nbuf;
+
+	/* pass partial skb header to fw */
+	tx_info->buf[1].len = MT_CT_PARSE_LEN;
+	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
+
+	txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
+
+	if (!key)
+		txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
+
+	if (ieee80211_is_mgmt(hdr->frame_control))
+		txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
+
+	if (vif) {
+		struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+
+		txp->bss_idx = mvif->idx;
+	}
+
+	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
+	t->skb = tx_info->skb;
+
+	spin_lock_bh(&dev->token_lock);
+	id = idr_alloc(&dev->token, t, 0, MT7615_TOKEN_SIZE, GFP_ATOMIC);
+	spin_unlock_bh(&dev->token_lock);
+	if (id < 0)
+		return id;
+
+	txp->token = cpu_to_le16(id);
+	txp->rept_wds_wcid = 0xff;
+	tx_info->skb = DMA_DUMMY_DATA;
+
+	return 0;
+}
+
+static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
+			    struct ieee80211_tx_info *info, __le32 *txs_data)
+{
+	struct ieee80211_supported_band *sband;
+	int i, idx, count, final_idx = 0;
+	bool fixed_rate, final_mpdu, ack_timeout;
+	bool probe, ampdu, cck = false;
+	u32 final_rate, final_rate_flags, final_nss, txs;
+	u8 pid;
+
+	fixed_rate = info->status.rates[0].count;
+	probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+
+	txs = le32_to_cpu(txs_data[1]);
+	final_mpdu = txs & MT_TXS1_ACKED_MPDU;
+	ampdu = !fixed_rate && (txs & MT_TXS1_AMPDU);
+
+	txs = le32_to_cpu(txs_data[3]);
+	count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
+
+	txs = le32_to_cpu(txs_data[0]);
+	pid = FIELD_GET(MT_TXS0_PID, txs);
+	final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
+	ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
+
+	if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT))
+		return false;
+
+	if (txs & MT_TXS0_QUEUE_TIMEOUT)
+		return false;
+
+	if (!ack_timeout)
+		info->flags |= IEEE80211_TX_STAT_ACK;
+
+	info->status.ampdu_len = 1;
+	info->status.ampdu_ack_len = !!(info->flags &
+					IEEE80211_TX_STAT_ACK);
+
+	if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
+		info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
+
+	if (fixed_rate && !probe) {
+		info->status.rates[0].count = count;
+		goto out;
+	}
+
+	for (i = 0, idx = 0; i < ARRAY_SIZE(info->status.rates); i++) {
+		int cur_count = min_t(int, count, 2 * MT7615_RATE_RETRY);
+
+		if (!i && probe) {
+			cur_count = 1;
+		} else {
+			info->status.rates[i] = sta->rates[idx];
+			idx++;
+		}
+
+		if (i && info->status.rates[i].idx < 0) {
+			info->status.rates[i - 1].count += count;
+			break;
+		}
+
+		if (!count) {
+			info->status.rates[i].idx = -1;
+			break;
+		}
+
+		info->status.rates[i].count = cur_count;
+		final_idx = i;
+		count -= cur_count;
+	}
+
+out:
+	final_rate_flags = info->status.rates[final_idx].flags;
+
+	switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
+	case MT_PHY_TYPE_CCK:
+		cck = true;
+		/* fall through */
+	case MT_PHY_TYPE_OFDM:
+		if (dev->mt76.chandef.chan->band == NL80211_BAND_5GHZ)
+			sband = &dev->mt76.sband_5g.sband;
+		else
+			sband = &dev->mt76.sband_2g.sband;
+		final_rate &= MT_TX_RATE_IDX;
+		final_rate = mt7615_get_rate(dev, sband, final_rate, cck);
+		final_rate_flags = 0;
+		break;
+	case MT_PHY_TYPE_HT_GF:
+	case MT_PHY_TYPE_HT:
+		final_rate_flags |= IEEE80211_TX_RC_MCS;
+		final_rate &= MT_TX_RATE_IDX;
+		if (final_rate > 31)
+			return false;
+		break;
+	case MT_PHY_TYPE_VHT:
+		final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate);
+		final_rate_flags |= IEEE80211_TX_RC_VHT_MCS;
+		final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4);
+		break;
+	default:
+		return false;
+	}
+
+	info->status.rates[final_idx].idx = final_rate;
+	info->status.rates[final_idx].flags = final_rate_flags;
+
+	return true;
+}
+
+static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev,
+				   struct mt7615_sta *sta, int pid,
+				   __le32 *txs_data)
+{
+	struct mt76_dev *mdev = &dev->mt76;
+	struct sk_buff_head list;
+	struct sk_buff *skb;
+
+	if (pid < MT_PACKET_ID_FIRST)
+		return false;
+
+	mt76_tx_status_lock(mdev, &list);
+	skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list);
+	if (skb) {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+		if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+			spin_lock_bh(&dev->mt76.lock);
+			if (sta->rate_probe) {
+				mt7615_mcu_set_rates(dev, sta, NULL,
+						     sta->rates);
+				sta->rate_probe = false;
+			}
+			spin_unlock_bh(&dev->mt76.lock);
+		}
+
+		if (!mt7615_fill_txs(dev, sta, info, txs_data)) {
+			ieee80211_tx_info_clear_status(info);
+			info->status.rates[0].idx = -1;
+		}
+
+		mt76_tx_status_skb_done(mdev, skb, &list);
+	}
+	mt76_tx_status_unlock(mdev, &list);
+
+	return !!skb;
+}
+
+void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
+{
+	struct ieee80211_tx_info info = {};
+	struct ieee80211_sta *sta = NULL;
+	struct mt7615_sta *msta = NULL;
+	struct mt76_wcid *wcid;
+	__le32 *txs_data = data;
+	u32 txs;
+	u8 wcidx;
+	u8 pid;
+
+	txs = le32_to_cpu(txs_data[0]);
+	pid = FIELD_GET(MT_TXS0_PID, txs);
+	txs = le32_to_cpu(txs_data[2]);
+	wcidx = FIELD_GET(MT_TXS2_WCID, txs);
+
+	if (pid == MT_PACKET_ID_NO_ACK)
+		return;
+
+	if (wcidx >= ARRAY_SIZE(dev->mt76.wcid))
+		return;
+
+	rcu_read_lock();
+
+	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
+	if (!wcid)
+		goto out;
+
+	msta = container_of(wcid, struct mt7615_sta, wcid);
+	sta = wcid_to_sta(wcid);
+
+	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
+		goto out;
+
+	if (wcidx >= MT7615_WTBL_STA || !sta)
+		goto out;
+
+	if (mt7615_fill_txs(dev, msta, &info, txs_data))
+		ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
+
+out:
+	rcu_read_unlock();
+}
+
+void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
+{
+	struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
+	struct mt76_dev *mdev = &dev->mt76;
+	struct mt76_txwi_cache *txwi;
+	u8 i, count;
+
+	count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
+	for (i = 0; i < count; i++) {
+		spin_lock_bh(&dev->token_lock);
+		txwi = idr_remove(&dev->token, le16_to_cpu(free->token[i]));
+		spin_unlock_bh(&dev->token_lock);
+
+		if (!txwi)
+			continue;
+
+		mt7615_txp_skb_unmap(mdev, txwi);
+		if (txwi->skb) {
+			mt76_tx_complete_skb(mdev, txwi->skb);
+			txwi->skb = NULL;
+		}
+
+		mt76_put_txwi(mdev, txwi);
+	}
+	dev_kfree_skb(skb);
+}
+
+void mt7615_mac_work(struct work_struct *work)
+{
+	struct mt7615_dev *dev;
+
+	dev = (struct mt7615_dev *)container_of(work, struct mt76_dev,
+						mac_work.work);
+
+	mt76_tx_status_check(&dev->mt76, NULL, false);
+	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
+				     MT7615_WATCHDOG_TIME);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
new file mode 100644
index 0000000..18ad4b8
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
@@ -0,0 +1,300 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2019 MediaTek Inc. */
+
+#ifndef __MT7615_MAC_H
+#define __MT7615_MAC_H
+
+#define MT_CT_PARSE_LEN			72
+#define MT_CT_DMA_BUF_NUM		2
+
+#define MT_RXD0_LENGTH			GENMASK(15, 0)
+#define MT_RXD0_PKT_TYPE		GENMASK(31, 29)
+
+#define MT_RXD0_NORMAL_ETH_TYPE_OFS	GENMASK(22, 16)
+#define MT_RXD0_NORMAL_IP_SUM		BIT(23)
+#define MT_RXD0_NORMAL_UDP_TCP_SUM	BIT(24)
+#define MT_RXD0_NORMAL_GROUP_1		BIT(25)
+#define MT_RXD0_NORMAL_GROUP_2		BIT(26)
+#define MT_RXD0_NORMAL_GROUP_3		BIT(27)
+#define MT_RXD0_NORMAL_GROUP_4		BIT(28)
+
+enum rx_pkt_type {
+	PKT_TYPE_TXS,
+	PKT_TYPE_TXRXV,
+	PKT_TYPE_NORMAL,
+	PKT_TYPE_RX_DUP_RFB,
+	PKT_TYPE_RX_TMR,
+	PKT_TYPE_RETRIEVE,
+	PKT_TYPE_TXRX_NOTIFY,
+	PKT_TYPE_RX_EVENT
+};
+
+#define MT_RXD1_NORMAL_BSSID		GENMASK(31, 26)
+#define MT_RXD1_NORMAL_PAYLOAD_FORMAT	GENMASK(25, 24)
+#define MT_RXD1_NORMAL_HDR_TRANS	BIT(23)
+#define MT_RXD1_NORMAL_HDR_OFFSET	BIT(22)
+#define MT_RXD1_NORMAL_MAC_HDR_LEN	GENMASK(21, 16)
+#define MT_RXD1_NORMAL_CH_FREQ		GENMASK(15, 8)
+#define MT_RXD1_NORMAL_KEY_ID		GENMASK(7, 6)
+#define MT_RXD1_NORMAL_BEACON_UC	BIT(5)
+#define MT_RXD1_NORMAL_BEACON_MC	BIT(4)
+#define MT_RXD1_NORMAL_BF_REPORT	BIT(3)
+#define MT_RXD1_NORMAL_ADDR_TYPE	GENMASK(2, 1)
+#define MT_RXD1_NORMAL_BCAST		GENMASK(2, 1)
+#define MT_RXD1_NORMAL_MCAST		BIT(2)
+#define MT_RXD1_NORMAL_U2M		BIT(1)
+#define MT_RXD1_NORMAL_HTC_VLD		BIT(0)
+
+#define MT_RXD2_NORMAL_NON_AMPDU	BIT(31)
+#define MT_RXD2_NORMAL_NON_AMPDU_SUB	BIT(30)
+#define MT_RXD2_NORMAL_NDATA		BIT(29)
+#define MT_RXD2_NORMAL_NULL_FRAME	BIT(28)
+#define MT_RXD2_NORMAL_FRAG		BIT(27)
+#define MT_RXD2_NORMAL_INT_FRAME	BIT(26)
+#define MT_RXD2_NORMAL_HDR_TRANS_ERROR	BIT(25)
+#define MT_RXD2_NORMAL_MAX_LEN_ERROR	BIT(24)
+#define MT_RXD2_NORMAL_AMSDU_ERR	BIT(23)
+#define MT_RXD2_NORMAL_LEN_MISMATCH	BIT(22)
+#define MT_RXD2_NORMAL_TKIP_MIC_ERR	BIT(21)
+#define MT_RXD2_NORMAL_ICV_ERR		BIT(20)
+#define MT_RXD2_NORMAL_CLM		BIT(19)
+#define MT_RXD2_NORMAL_CM		BIT(18)
+#define MT_RXD2_NORMAL_FCS_ERR		BIT(17)
+#define MT_RXD2_NORMAL_SW_BIT		BIT(16)
+#define MT_RXD2_NORMAL_SEC_MODE		GENMASK(15, 12)
+#define MT_RXD2_NORMAL_TID		GENMASK(11, 8)
+#define MT_RXD2_NORMAL_WLAN_IDX		GENMASK(7, 0)
+
+#define MT_RXD3_NORMAL_PF_STS		GENMASK(31, 30)
+#define MT_RXD3_NORMAL_PF_MODE		BIT(29)
+#define MT_RXD3_NORMAL_CLS_BITMAP	GENMASK(28, 19)
+#define MT_RXD3_NORMAL_WOL		GENMASK(18, 14)
+#define MT_RXD3_NORMAL_MAGIC_PKT	BIT(13)
+#define MT_RXD3_NORMAL_OFLD		GENMASK(12, 11)
+#define MT_RXD3_NORMAL_CLS		BIT(10)
+#define MT_RXD3_NORMAL_PATTERN_DROP	BIT(9)
+#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS	BIT(8)
+#define MT_RXD3_NORMAL_RXV_SEQ		GENMASK(7, 0)
+
+#define MT_RXV1_ACID_DET_H		BIT(31)
+#define MT_RXV1_ACID_DET_L		BIT(30)
+#define MT_RXV1_VHTA2_B8_B3		GENMASK(29, 24)
+#define MT_RXV1_NUM_RX			GENMASK(23, 22)
+#define MT_RXV1_HT_NO_SOUND		BIT(21)
+#define MT_RXV1_HT_SMOOTH		BIT(20)
+#define MT_RXV1_HT_SHORT_GI		BIT(19)
+#define MT_RXV1_HT_AGGR			BIT(18)
+#define MT_RXV1_VHTA1_B22		BIT(17)
+#define MT_RXV1_FRAME_MODE		GENMASK(16, 15)
+#define MT_RXV1_TX_MODE			GENMASK(14, 12)
+#define MT_RXV1_HT_EXT_LTF		GENMASK(11, 10)
+#define MT_RXV1_HT_AD_CODE		BIT(9)
+#define MT_RXV1_HT_STBC			GENMASK(8, 7)
+#define MT_RXV1_TX_RATE			GENMASK(6, 0)
+
+#define MT_RXV2_SEL_ANT			BIT(31)
+#define MT_RXV2_VALID_BIT		BIT(30)
+#define MT_RXV2_NSTS			GENMASK(29, 27)
+#define MT_RXV2_GROUP_ID		GENMASK(26, 21)
+#define MT_RXV2_LENGTH			GENMASK(20, 0)
+
+enum tx_header_format {
+	MT_HDR_FORMAT_802_3,
+	MT_HDR_FORMAT_CMD,
+	MT_HDR_FORMAT_802_11,
+	MT_HDR_FORMAT_802_11_EXT,
+};
+
+enum tx_pkt_type {
+	MT_TX_TYPE_CT,
+	MT_TX_TYPE_SF,
+	MT_TX_TYPE_CMD,
+	MT_TX_TYPE_FW,
+};
+
+enum tx_pkt_queue_idx {
+	MT_LMAC_AC00,
+	MT_LMAC_AC01,
+	MT_LMAC_AC02,
+	MT_LMAC_AC03,
+	MT_LMAC_ALTX0 = 0x10,
+	MT_LMAC_BMC0,
+	MT_LMAC_BCN0,
+	MT_LMAC_PSMP0,
+};
+
+enum tx_port_idx {
+	MT_TX_PORT_IDX_LMAC,
+	MT_TX_PORT_IDX_MCU
+};
+
+enum tx_mcu_port_q_idx {
+	MT_TX_MCU_PORT_RX_Q0 = 0,
+	MT_TX_MCU_PORT_RX_Q1,
+	MT_TX_MCU_PORT_RX_Q2,
+	MT_TX_MCU_PORT_RX_Q3,
+	MT_TX_MCU_PORT_RX_FWDL = 0x1e
+};
+
+enum tx_phy_bandwidth {
+	MT_PHY_BW_20,
+	MT_PHY_BW_40,
+	MT_PHY_BW_80,
+	MT_PHY_BW_160,
+};
+
+#define MT_CT_INFO_APPLY_TXD		BIT(0)
+#define MT_CT_INFO_COPY_HOST_TXD_ALL	BIT(1)
+#define MT_CT_INFO_MGMT_FRAME		BIT(2)
+#define MT_CT_INFO_NONE_CIPHER_FRAME	BIT(3)
+#define MT_CT_INFO_HSR2_TX		BIT(4)
+
+#define MT_TXD_SIZE			(8 * 4)
+
+#define MT_TXD0_P_IDX			BIT(31)
+#define MT_TXD0_Q_IDX			GENMASK(30, 26)
+#define MT_TXD0_UDP_TCP_SUM		BIT(24)
+#define MT_TXD0_IP_SUM			BIT(23)
+#define MT_TXD0_ETH_TYPE_OFFSET		GENMASK(22, 16)
+#define MT_TXD0_TX_BYTES		GENMASK(15, 0)
+
+#define MT_TXD1_OWN_MAC			GENMASK(31, 26)
+#define MT_TXD1_PKT_FMT			GENMASK(25, 24)
+#define MT_TXD1_TID			GENMASK(23, 21)
+#define MT_TXD1_AMSDU			BIT(20)
+#define MT_TXD1_UNXV			BIT(19)
+#define MT_TXD1_HDR_PAD			GENMASK(18, 17)
+#define MT_TXD1_TXD_LEN			BIT(16)
+#define MT_TXD1_LONG_FORMAT		BIT(15)
+#define MT_TXD1_HDR_FORMAT		GENMASK(14, 13)
+#define MT_TXD1_HDR_INFO		GENMASK(12, 8)
+#define MT_TXD1_WLAN_IDX		GENMASK(7, 0)
+
+#define MT_TXD2_FIX_RATE		BIT(31)
+#define MT_TXD2_TIMING_MEASURE		BIT(30)
+#define MT_TXD2_BA_DISABLE		BIT(29)
+#define MT_TXD2_POWER_OFFSET		GENMASK(28, 24)
+#define MT_TXD2_MAX_TX_TIME		GENMASK(23, 16)
+#define MT_TXD2_FRAG			GENMASK(15, 14)
+#define MT_TXD2_HTC_VLD			BIT(13)
+#define MT_TXD2_DURATION		BIT(12)
+#define MT_TXD2_BIP			BIT(11)
+#define MT_TXD2_MULTICAST		BIT(10)
+#define MT_TXD2_RTS			BIT(9)
+#define MT_TXD2_SOUNDING		BIT(8)
+#define MT_TXD2_NDPA			BIT(7)
+#define MT_TXD2_NDP			BIT(6)
+#define MT_TXD2_FRAME_TYPE		GENMASK(5, 4)
+#define MT_TXD2_SUB_TYPE		GENMASK(3, 0)
+
+#define MT_TXD3_SN_VALID		BIT(31)
+#define MT_TXD3_PN_VALID		BIT(30)
+#define MT_TXD3_SEQ			GENMASK(27, 16)
+#define MT_TXD3_REM_TX_COUNT		GENMASK(15, 11)
+#define MT_TXD3_TX_COUNT		GENMASK(10, 6)
+#define MT_TXD3_PROTECT_FRAME		BIT(1)
+#define MT_TXD3_NO_ACK			BIT(0)
+
+#define MT_TXD4_PN_LOW			GENMASK(31, 0)
+
+#define MT_TXD5_PN_HIGH			GENMASK(31, 16)
+#define MT_TXD5_SW_POWER_MGMT		BIT(13)
+#define MT_TXD5_DA_SELECT		BIT(11)
+#define MT_TXD5_TX_STATUS_HOST		BIT(10)
+#define MT_TXD5_TX_STATUS_MCU		BIT(9)
+#define MT_TXD5_TX_STATUS_FMT		BIT(8)
+#define MT_TXD5_PID			GENMASK(7, 0)
+
+#define MT_TXD6_FIXED_RATE		BIT(31)
+#define MT_TXD6_SGI			BIT(30)
+#define MT_TXD6_LDPC			BIT(29)
+#define MT_TXD6_TX_BF			BIT(28)
+#define MT_TXD6_TX_RATE			GENMASK(27, 16)
+#define MT_TXD6_ANT_ID			GENMASK(15, 4)
+#define MT_TXD6_DYN_BW			BIT(3)
+#define MT_TXD6_FIXED_BW		BIT(2)
+#define MT_TXD6_BW			GENMASK(1, 0)
+
+#define MT_TXD7_TYPE			GENMASK(21, 20)
+#define MT_TXD7_SUB_TYPE		GENMASK(19, 16)
+
+#define MT_TX_RATE_STBC			BIT(11)
+#define MT_TX_RATE_NSS			GENMASK(10, 9)
+#define MT_TX_RATE_MODE			GENMASK(8, 6)
+#define MT_TX_RATE_IDX			GENMASK(5, 0)
+
+#define MT_TXP_MAX_BUF_NUM		6
+
+struct mt7615_txp {
+	__le16 flags;
+	__le16 token;
+	u8 bss_idx;
+	u8 rept_wds_wcid;
+	u8 rsv;
+	u8 nbuf;
+	__le32 buf[MT_TXP_MAX_BUF_NUM];
+	__le16 len[MT_TXP_MAX_BUF_NUM];
+} __packed;
+
+struct mt7615_tx_free {
+	__le16 rx_byte_cnt;
+	__le16 ctrl;
+	u8 txd_cnt;
+	u8 rsv[3];
+	__le16 token[];
+} __packed;
+
+#define MT_TX_FREE_MSDU_ID_CNT		GENMASK(6, 0)
+
+#define MT_TXS0_PID			GENMASK(31, 24)
+#define MT_TXS0_BA_ERROR		BIT(22)
+#define MT_TXS0_PS_FLAG			BIT(21)
+#define MT_TXS0_TXOP_TIMEOUT		BIT(20)
+#define MT_TXS0_BIP_ERROR		BIT(19)
+
+#define MT_TXS0_QUEUE_TIMEOUT		BIT(18)
+#define MT_TXS0_RTS_TIMEOUT		BIT(17)
+#define MT_TXS0_ACK_TIMEOUT		BIT(16)
+#define MT_TXS0_ACK_ERROR_MASK		GENMASK(18, 16)
+
+#define MT_TXS0_TX_STATUS_HOST		BIT(15)
+#define MT_TXS0_TX_STATUS_MCU		BIT(14)
+#define MT_TXS0_TXS_FORMAT		BIT(13)
+#define MT_TXS0_FIXED_RATE		BIT(12)
+#define MT_TXS0_TX_RATE			GENMASK(11, 0)
+
+#define MT_TXS1_ANT_ID			GENMASK(31, 20)
+#define MT_TXS1_RESP_RATE		GENMASK(19, 16)
+#define MT_TXS1_BW			GENMASK(15, 14)
+#define MT_TXS1_I_TXBF			BIT(13)
+#define MT_TXS1_E_TXBF			BIT(12)
+#define MT_TXS1_TID			GENMASK(11, 9)
+#define MT_TXS1_AMPDU			BIT(8)
+#define MT_TXS1_ACKED_MPDU		BIT(7)
+#define MT_TXS1_TX_POWER_DBM		GENMASK(6, 0)
+
+#define MT_TXS2_WCID			GENMASK(31, 24)
+#define MT_TXS2_RXV_SEQNO		GENMASK(23, 16)
+#define MT_TXS2_TX_DELAY		GENMASK(15, 0)
+
+#define MT_TXS3_LAST_TX_RATE		GENMASK(31, 29)
+#define MT_TXS3_TX_COUNT		GENMASK(28, 24)
+#define MT_TXS3_F1_TSSI1		GENMASK(23, 12)
+#define MT_TXS3_F1_TSSI0		GENMASK(11, 0)
+#define MT_TXS3_F0_SEQNO		GENMASK(11, 0)
+
+#define MT_TXS4_F0_TIMESTAMP		GENMASK(31, 0)
+#define MT_TXS4_F1_TSSI3		GENMASK(23, 12)
+#define MT_TXS4_F1_TSSI2		GENMASK(11, 0)
+
+#define MT_TXS5_F0_FRONT_TIME		GENMASK(24, 0)
+#define MT_TXS5_F1_NOISE_2		GENMASK(23, 16)
+#define MT_TXS5_F1_NOISE_1		GENMASK(15, 8)
+#define MT_TXS5_F1_NOISE_0		GENMASK(7, 0)
+
+#define MT_TXS6_F1_RCPI_3		GENMASK(31, 24)
+#define MT_TXS6_F1_RCPI_2		GENMASK(23, 16)
+#define MT_TXS6_F1_RCPI_1		GENMASK(15, 8)
+#define MT_TXS6_F1_RCPI_0		GENMASK(7, 0)
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
new file mode 100644
index 0000000..80e6b21
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Roy Luo <royluo@google.com>
+ *         Ryder Lee <ryder.lee@mediatek.com>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include "mt7615.h"
+
+static int mt7615_start(struct ieee80211_hw *hw)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
+				     MT7615_WATCHDOG_TIME);
+
+	return 0;
+}
+
+static void mt7615_stop(struct ieee80211_hw *hw)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	clear_bit(MT76_STATE_RUNNING, &dev->mt76.state);
+	cancel_delayed_work_sync(&dev->mt76.mac_work);
+}
+
+static int get_omac_idx(enum nl80211_iftype type, u32 mask)
+{
+	int i;
+
+	switch (type) {
+	case NL80211_IFTYPE_AP:
+		/* ap use hw bssid 0 and ext bssid */
+		if (~mask & BIT(HW_BSSID_0))
+			return HW_BSSID_0;
+
+		for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
+			if (~mask & BIT(i))
+				return i;
+
+		break;
+	case NL80211_IFTYPE_STATION:
+		/* sta use hw bssid other than 0 */
+		for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
+			if (~mask & BIT(i))
+				return i;
+
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	};
+
+	return -1;
+}
+
+static int mt7615_add_interface(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt7615_dev *dev = hw->priv;
+	struct mt76_txq *mtxq;
+	int idx, ret = 0;
+
+	mutex_lock(&dev->mt76.mutex);
+
+	mvif->idx = ffs(~dev->vif_mask) - 1;
+	if (mvif->idx >= MT7615_MAX_INTERFACES) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	mvif->omac_idx = get_omac_idx(vif->type, dev->omac_mask);
+	if (mvif->omac_idx < 0) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	/* TODO: DBDC support. Use band 0 and wmm 0 for now */
+	mvif->band_idx = 0;
+	mvif->wmm_idx = 0;
+
+	ret = mt7615_mcu_set_dev_info(dev, vif, 1);
+	if (ret)
+		goto out;
+
+	dev->vif_mask |= BIT(mvif->idx);
+	dev->omac_mask |= BIT(mvif->omac_idx);
+	idx = MT7615_WTBL_RESERVED - 1 - mvif->idx;
+	mvif->sta.wcid.idx = idx;
+	mvif->sta.wcid.hw_key_idx = -1;
+
+	rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
+	mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+	mtxq->wcid = &mvif->sta.wcid;
+	mt76_txq_init(&dev->mt76, vif->txq);
+
+out:
+	mutex_unlock(&dev->mt76.mutex);
+
+	return ret;
+}
+
+static void mt7615_remove_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt7615_dev *dev = hw->priv;
+	int idx = mvif->sta.wcid.idx;
+
+	/* TODO: disable beacon for the bss */
+
+	mt7615_mcu_set_dev_info(dev, vif, 0);
+
+	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+	mt76_txq_remove(&dev->mt76, vif->txq);
+
+	mutex_lock(&dev->mt76.mutex);
+	dev->vif_mask &= ~BIT(mvif->idx);
+	dev->omac_mask &= ~BIT(mvif->omac_idx);
+	mutex_unlock(&dev->mt76.mutex);
+}
+
+static int mt7615_set_channel(struct mt7615_dev *dev,
+			      struct cfg80211_chan_def *def)
+{
+	int ret;
+
+	cancel_delayed_work_sync(&dev->mt76.mac_work);
+	set_bit(MT76_RESET, &dev->mt76.state);
+
+	mt76_set_channel(&dev->mt76);
+
+	ret = mt7615_mcu_set_channel(dev);
+	if (ret)
+		return ret;
+
+	clear_bit(MT76_RESET, &dev->mt76.state);
+
+	mt76_txq_schedule_all(&dev->mt76);
+	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
+				     MT7615_WATCHDOG_TIME);
+	return 0;
+}
+
+static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			  struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+			  struct ieee80211_key_conf *key)
+{
+	struct mt7615_dev *dev = hw->priv;
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv :
+				  &mvif->sta;
+	struct mt76_wcid *wcid = &msta->wcid;
+	int idx = key->keyidx;
+
+	/* The hardware does not support per-STA RX GTK, fallback
+	 * to software mode for these.
+	 */
+	if ((vif->type == NL80211_IFTYPE_ADHOC ||
+	     vif->type == NL80211_IFTYPE_MESH_POINT) &&
+	    (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+	     key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+		return -EOPNOTSUPP;
+
+	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;
+	}
+	mt76_wcid_key_setup(&dev->mt76, wcid, key);
+
+	return mt7615_mcu_set_wtbl_key(dev, wcid->idx, key, cmd);
+}
+
+static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct mt7615_dev *dev = hw->priv;
+	int ret = 0;
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		mutex_lock(&dev->mt76.mutex);
+
+		ieee80211_stop_queues(hw);
+		ret = mt7615_set_channel(dev, &hw->conf.chandef);
+		ieee80211_wake_queues(hw);
+
+		mutex_unlock(&dev->mt76.mutex);
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+		mutex_lock(&dev->mt76.mutex);
+
+		if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
+			dev->mt76.rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
+		else
+			dev->mt76.rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
+
+		mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
+
+		mutex_unlock(&dev->mt76.mutex);
+	}
+	return ret;
+}
+
+static int
+mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+	       const struct ieee80211_tx_queue_params *params)
+{
+	struct mt7615_dev *dev = hw->priv;
+	static const u8 wmm_queue_map[] = {
+		[IEEE80211_AC_BK] = 0,
+		[IEEE80211_AC_BE] = 1,
+		[IEEE80211_AC_VI] = 2,
+		[IEEE80211_AC_VO] = 3,
+	};
+
+	/* TODO: hw wmm_set 1~3 */
+	return mt7615_mcu_set_wmm(dev, wmm_queue_map[queue], params);
+}
+
+static void mt7615_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed_flags,
+				    unsigned int *total_flags,
+				    u64 multicast)
+{
+	struct mt7615_dev *dev = hw->priv;
+	u32 flags = 0;
+
+#define MT76_FILTER(_flag, _hw) do { \
+		flags |= *total_flags & FIF_##_flag;			\
+		dev->mt76.rxfilter &= ~(_hw);				\
+		dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw);	\
+	} while (0)
+
+	dev->mt76.rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS |
+				MT_WF_RFCR_DROP_OTHER_BEACON |
+				MT_WF_RFCR_DROP_FRAME_REPORT |
+				MT_WF_RFCR_DROP_PROBEREQ |
+				MT_WF_RFCR_DROP_MCAST_FILTERED |
+				MT_WF_RFCR_DROP_MCAST |
+				MT_WF_RFCR_DROP_BCAST |
+				MT_WF_RFCR_DROP_DUPLICATE |
+				MT_WF_RFCR_DROP_A2_BSSID |
+				MT_WF_RFCR_DROP_UNWANTED_CTL |
+				MT_WF_RFCR_DROP_STBC_MULTI);
+
+	MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
+			       MT_WF_RFCR_DROP_A3_MAC |
+			       MT_WF_RFCR_DROP_A3_BSSID);
+
+	MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL);
+
+	MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS |
+			     MT_WF_RFCR_DROP_RTS |
+			     MT_WF_RFCR_DROP_CTL_RSV |
+			     MT_WF_RFCR_DROP_NDPA);
+
+	*total_flags = flags;
+	mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
+}
+
+static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_bss_conf *info,
+				    u32 changed)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	mutex_lock(&dev->mt76.mutex);
+
+	/* TODO: sta mode connect/disconnect
+	 * BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID
+	 */
+
+	/* TODO: update beacon content
+	 * BSS_CHANGED_BEACON
+	 */
+
+	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+		if (info->enable_beacon) {
+			mt7615_mcu_set_bss_info(dev, vif, 1);
+			mt7615_mcu_add_wtbl_bmc(dev, vif);
+			mt7615_mcu_set_sta_rec_bmc(dev, vif, 1);
+			mt7615_mcu_set_bcn(dev, vif, 1);
+		} else {
+			mt7615_mcu_set_sta_rec_bmc(dev, vif, 0);
+			mt7615_mcu_del_wtbl_bmc(dev, vif);
+			mt7615_mcu_set_bss_info(dev, vif, 0);
+			mt7615_mcu_set_bcn(dev, vif, 0);
+		}
+	}
+
+	mutex_unlock(&dev->mt76.mutex);
+}
+
+int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta)
+{
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	int idx;
+
+	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1);
+	if (idx < 0)
+		return -ENOSPC;
+
+	msta->vif = mvif;
+	msta->wcid.sta = 1;
+	msta->wcid.idx = idx;
+
+	mt7615_mcu_add_wtbl(dev, vif, sta);
+	mt7615_mcu_set_sta_rec(dev, vif, sta, 1);
+
+	return 0;
+}
+
+void mt7615_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		      struct ieee80211_sta *sta)
+{
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+
+	if (sta->ht_cap.ht_supported)
+		mt7615_mcu_set_ht_cap(dev, vif, sta);
+}
+
+void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta)
+{
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+
+	mt7615_mcu_set_sta_rec(dev, vif, sta, 0);
+	mt7615_mcu_del_wtbl(dev, vif, sta);
+}
+
+static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif,
+				       struct ieee80211_sta *sta)
+{
+	struct mt7615_dev *dev = hw->priv;
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates);
+	int i;
+
+	spin_lock_bh(&dev->mt76.lock);
+	for (i = 0; i < ARRAY_SIZE(msta->rates); i++) {
+		msta->rates[i].idx = sta_rates->rate[i].idx;
+		msta->rates[i].count = sta_rates->rate[i].count;
+		msta->rates[i].flags = sta_rates->rate[i].flags;
+
+		if (msta->rates[i].idx < 0 || !msta->rates[i].count)
+			break;
+	}
+	msta->n_rates = i;
+	mt7615_mcu_set_rates(dev, msta, NULL, msta->rates);
+	msta->rate_probe = false;
+	spin_unlock_bh(&dev->mt76.lock);
+}
+
+static void mt7615_tx(struct ieee80211_hw *hw,
+		      struct ieee80211_tx_control *control,
+		      struct sk_buff *skb)
+{
+	struct mt7615_dev *dev = hw->priv;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_vif *vif = info->control.vif;
+	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+
+	if (control->sta) {
+		struct mt7615_sta *sta;
+
+		sta = (struct mt7615_sta *)control->sta->drv_priv;
+		wcid = &sta->wcid;
+	}
+
+	if (vif && !control->sta) {
+		struct mt7615_vif *mvif;
+
+		mvif = (struct mt7615_vif *)vif->drv_priv;
+		wcid = &mvif->sta.wcid;
+	}
+
+	mt76_tx(&dev->mt76, control->sta, wcid, skb);
+}
+
+static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	mutex_lock(&dev->mt76.mutex);
+	mt7615_mcu_set_rts_thresh(dev, val);
+	mutex_unlock(&dev->mt76.mutex);
+
+	return 0;
+}
+
+static int
+mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		    struct ieee80211_ampdu_params *params)
+{
+	enum ieee80211_ampdu_mlme_action action = params->action;
+	struct mt7615_dev *dev = hw->priv;
+	struct ieee80211_sta *sta = params->sta;
+	struct ieee80211_txq *txq = sta->txq[params->tid];
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	u16 tid = params->tid;
+	u16 *ssn = &params->ssn;
+	struct mt76_txq *mtxq;
+
+	if (!txq)
+		return -EINVAL;
+
+	mtxq = (struct mt76_txq *)txq->drv_priv;
+
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+		mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn,
+				   params->buf_size);
+		mt7615_mcu_set_rx_ba(dev, params, 1);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
+		mt7615_mcu_set_rx_ba(dev, params, 0);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		mtxq->aggr = true;
+		mtxq->send_bar = false;
+		mt7615_mcu_set_tx_ba(dev, params, 1);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		mtxq->aggr = false;
+		ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
+		mt7615_mcu_set_tx_ba(dev, params, 0);
+		break;
+	case IEEE80211_AMPDU_TX_START:
+		mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
+		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
+		mtxq->aggr = false;
+		mt7615_mcu_set_tx_ba(dev, params, 0);
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	}
+
+	return 0;
+}
+
+static void
+mt7615_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+	       const u8 *mac)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	set_bit(MT76_SCANNING, &dev->mt76.state);
+}
+
+static void
+mt7615_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+	struct mt7615_dev *dev = hw->priv;
+
+	clear_bit(MT76_SCANNING, &dev->mt76.state);
+}
+
+const struct ieee80211_ops mt7615_ops = {
+	.tx = mt7615_tx,
+	.start = mt7615_start,
+	.stop = mt7615_stop,
+	.add_interface = mt7615_add_interface,
+	.remove_interface = mt7615_remove_interface,
+	.config = mt7615_config,
+	.conf_tx = mt7615_conf_tx,
+	.configure_filter = mt7615_configure_filter,
+	.bss_info_changed = mt7615_bss_info_changed,
+	.sta_state = mt76_sta_state,
+	.set_key = mt7615_set_key,
+	.ampdu_action = mt7615_ampdu_action,
+	.set_rts_threshold = mt7615_set_rts_threshold,
+	.wake_tx_queue = mt76_wake_tx_queue,
+	.sta_rate_tbl_update = mt7615_sta_rate_tbl_update,
+	.sw_scan_start = mt7615_sw_scan,
+	.sw_scan_complete = mt7615_sw_scan_complete,
+	.release_buffered_frames = mt76_release_buffered_frames,
+};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
new file mode 100644
index 0000000..b095406
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -0,0 +1,1656 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Roy Luo <royluo@google.com>
+ *         Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <linux/firmware.h>
+#include "mt7615.h"
+#include "mcu.h"
+#include "mac.h"
+#include "eeprom.h"
+
+struct mt7615_patch_hdr {
+	char build_date[16];
+	char platform[4];
+	__be32 hw_sw_ver;
+	__be32 patch_ver;
+	__be16 checksum;
+} __packed;
+
+struct mt7615_fw_trailer {
+	__le32 addr;
+	u8 chip_id;
+	u8 feature_set;
+	u8 eco_code;
+	char fw_ver[10];
+	char build_date[15];
+	__le32 len;
+} __packed;
+
+#define MCU_PATCH_ADDRESS		0x80000
+
+#define N9_REGION_NUM			2
+#define CR4_REGION_NUM			1
+
+#define IMG_CRC_LEN			4
+
+#define FW_FEATURE_SET_ENCRYPT		BIT(0)
+#define FW_FEATURE_SET_KEY_IDX		GENMASK(2, 1)
+
+#define DL_MODE_ENCRYPT			BIT(0)
+#define DL_MODE_KEY_IDX			GENMASK(2, 1)
+#define DL_MODE_RESET_SEC_IV		BIT(3)
+#define DL_MODE_WORKING_PDA_CR4		BIT(4)
+#define DL_MODE_NEED_RSP		BIT(31)
+
+#define FW_START_OVERRIDE		BIT(0)
+#define FW_START_WORKING_PDA_CR4	BIT(2)
+
+static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
+				 int cmd, int query, int dest, int *wait_seq)
+{
+	struct mt7615_mcu_txd *mcu_txd;
+	u8 seq, q_idx, pkt_fmt;
+	enum mt76_txq_id qid;
+	u32 val;
+	__le32 *txd;
+
+	if (!skb)
+		return -EINVAL;
+
+	seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf;
+	if (!seq)
+		seq = ++dev->mt76.mmio.mcu.msg_seq & 0xf;
+
+	mcu_txd = (struct mt7615_mcu_txd *)skb_push(skb,
+		   sizeof(struct mt7615_mcu_txd));
+	memset(mcu_txd, 0, sizeof(struct mt7615_mcu_txd));
+
+	if (cmd != -MCU_CMD_FW_SCATTER) {
+		q_idx = MT_TX_MCU_PORT_RX_Q0;
+		pkt_fmt = MT_TX_TYPE_CMD;
+	} else {
+		q_idx = MT_TX_MCU_PORT_RX_FWDL;
+		pkt_fmt = MT_TX_TYPE_FW;
+	}
+
+	txd = mcu_txd->txd;
+
+	val = FIELD_PREP(MT_TXD0_TX_BYTES, cpu_to_le16(skb->len)) |
+	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
+	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
+	txd[0] = cpu_to_le32(val);
+
+	val = MT_TXD1_LONG_FORMAT |
+	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD) |
+	      FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
+	txd[1] = cpu_to_le32(val);
+
+	mcu_txd->len = cpu_to_le16(skb->len -
+				   sizeof_field(struct mt7615_mcu_txd, txd));
+	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
+	mcu_txd->pkt_type = MCU_PKT_ID;
+	mcu_txd->seq = seq;
+
+	if (cmd < 0) {
+		mcu_txd->cid = -cmd;
+	} else {
+		mcu_txd->cid = MCU_CMD_EXT_CID;
+		mcu_txd->ext_cid = cmd;
+		if (query != MCU_Q_NA)
+			mcu_txd->ext_cid_ack = 1;
+	}
+
+	mcu_txd->set_query = query;
+	mcu_txd->s2d_index = dest;
+
+	if (wait_seq)
+		*wait_seq = seq;
+
+	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state))
+		qid = MT_TXQ_MCU;
+	else
+		qid = MT_TXQ_FWDL;
+
+	return mt76_tx_queue_skb_raw(dev, qid, skb, 0);
+}
+
+static int mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
+			       int cmd, int query, int dest,
+			       struct sk_buff **skb_ret)
+{
+	unsigned long expires = jiffies + 10 * HZ;
+	struct mt7615_mcu_rxd *rxd;
+	int ret, seq;
+
+	mutex_lock(&dev->mt76.mmio.mcu.mutex);
+
+	ret = __mt7615_mcu_msg_send(dev, skb, cmd, query, dest, &seq);
+	if (ret)
+		goto out;
+
+	while (1) {
+		skb = mt76_mcu_get_response(&dev->mt76, expires);
+		if (!skb) {
+			dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n",
+				cmd, seq);
+			ret = -ETIMEDOUT;
+			break;
+		}
+
+		rxd = (struct mt7615_mcu_rxd *)skb->data;
+		if (seq != rxd->seq)
+			continue;
+
+		if (skb_ret) {
+			int hdr_len = sizeof(*rxd);
+
+			if (!test_bit(MT76_STATE_MCU_RUNNING,
+				      &dev->mt76.state))
+				hdr_len -= 4;
+			skb_pull(skb, hdr_len);
+			*skb_ret = skb;
+		} else {
+			dev_kfree_skb(skb);
+		}
+
+		break;
+	}
+
+out:
+	mutex_unlock(&dev->mt76.mmio.mcu.mutex);
+
+	return ret;
+}
+
+static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
+				    u32 len, u32 mode)
+{
+	struct {
+		__le32 addr;
+		__le32 len;
+		__le32 mode;
+	} req = {
+		.addr = cpu_to_le32(addr),
+		.len = cpu_to_le32(len),
+		.mode = cpu_to_le32(mode),
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+				   MCU_Q_NA, MCU_S2D_H2N, NULL);
+}
+
+static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
+				    int len)
+{
+	struct sk_buff *skb;
+	int ret = 0;
+
+	while (len > 0) {
+		int cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd),
+				    len);
+
+		skb = mt7615_mcu_msg_alloc(data, cur_len);
+		if (!skb)
+			return -ENOMEM;
+
+		ret = __mt7615_mcu_msg_send(dev, skb, -MCU_CMD_FW_SCATTER,
+					    MCU_Q_NA, MCU_S2D_H2N, NULL);
+		if (ret)
+			break;
+
+		data += cur_len;
+		len -= cur_len;
+	}
+
+	return ret;
+}
+
+static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr,
+				     u32 option)
+{
+	struct {
+		__le32 option;
+		__le32 addr;
+	} req = {
+		.option = cpu_to_le32(option),
+		.addr = cpu_to_le32(addr),
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_FW_START_REQ,
+				   MCU_Q_NA, MCU_S2D_H2N, NULL);
+}
+
+static int mt7615_mcu_restart(struct mt7615_dev *dev)
+{
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(NULL, 0);
+
+	return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_RESTART_DL_REQ,
+				   MCU_Q_NA, MCU_S2D_H2N, NULL);
+}
+
+static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get)
+{
+	struct {
+		__le32 operation;
+	} req = {
+		.operation = cpu_to_le32(get ? PATCH_SEM_GET :
+					 PATCH_SEM_RELEASE),
+	};
+	struct event {
+		u8 status;
+		u8 reserved[3];
+	} *resp;
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+	struct sk_buff *skb_ret;
+	int ret;
+
+	ret = mt7615_mcu_msg_send(dev, skb, -MCU_CMD_PATCH_SEM_CONTROL,
+				  MCU_Q_NA, MCU_S2D_H2N, &skb_ret);
+	if (ret)
+		goto out;
+
+	resp = (struct event *)(skb_ret->data);
+	ret = resp->status;
+	dev_kfree_skb(skb_ret);
+
+out:
+	return ret;
+}
+
+static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
+{
+	struct {
+		u8 check_crc;
+		u8 reserved[3];
+	} req = {
+		.check_crc = 0,
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, -MCU_CMD_PATCH_FINISH_REQ,
+				   MCU_Q_NA, MCU_S2D_H2N, NULL);
+}
+
+static int mt7615_driver_own(struct mt7615_dev *dev)
+{
+	mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_DRV_OWN);
+	if (!mt76_poll_msec(dev, MT_CFG_LPCR_HOST,
+			    MT_CFG_LPCR_HOST_FW_OWN, 0, 500)) {
+		dev_err(dev->mt76.dev, "Timeout for driver own\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mt7615_load_patch(struct mt7615_dev *dev)
+{
+	const struct firmware *fw;
+	const struct mt7615_patch_hdr *hdr;
+	const char *firmware = MT7615_ROM_PATCH;
+	int len, ret, sem;
+
+	sem = mt7615_mcu_patch_sem_ctrl(dev, 1);
+	switch (sem) {
+	case PATCH_IS_DL:
+		return 0;
+	case PATCH_NOT_DL_SEM_SUCCESS:
+		break;
+	default:
+		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
+		return -EAGAIN;
+	}
+
+	ret = request_firmware(&fw, firmware, dev->mt76.dev);
+	if (ret)
+		return ret;
+
+	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+		dev_err(dev->mt76.dev, "Invalid firmware\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	hdr = (const struct mt7615_patch_hdr *)(fw->data);
+
+	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
+		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
+
+	len = fw->size - sizeof(*hdr);
+
+	ret = mt7615_mcu_init_download(dev, MCU_PATCH_ADDRESS, len,
+				       DL_MODE_NEED_RSP);
+	if (ret) {
+		dev_err(dev->mt76.dev, "Download request failed\n");
+		goto out;
+	}
+
+	ret = mt7615_mcu_send_firmware(dev, fw->data + sizeof(*hdr), len);
+	if (ret) {
+		dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
+		goto out;
+	}
+
+	ret = mt7615_mcu_start_patch(dev);
+	if (ret)
+		dev_err(dev->mt76.dev, "Failed to start patch\n");
+
+out:
+	release_firmware(fw);
+
+	sem = mt7615_mcu_patch_sem_ctrl(dev, 0);
+	switch (sem) {
+	case PATCH_REL_SEM_SUCCESS:
+		break;
+	default:
+		ret = -EAGAIN;
+		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
+		break;
+	}
+
+	return ret;
+}
+
+static u32 gen_dl_mode(u8 feature_set, bool is_cr4)
+{
+	u32 ret = 0;
+
+	ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ?
+	       (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0;
+	ret |= FIELD_PREP(DL_MODE_KEY_IDX,
+			  FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set));
+	ret |= DL_MODE_NEED_RSP;
+	ret |= is_cr4 ? DL_MODE_WORKING_PDA_CR4 : 0;
+
+	return ret;
+}
+
+static int mt7615_load_ram(struct mt7615_dev *dev)
+{
+	const struct firmware *fw;
+	const struct mt7615_fw_trailer *hdr;
+	const char *n9_firmware = MT7615_FIRMWARE_N9;
+	const char *cr4_firmware = MT7615_FIRMWARE_CR4;
+	u32 n9_ilm_addr, offset;
+	int i, ret;
+
+	ret = request_firmware(&fw, n9_firmware, dev->mt76.dev);
+	if (ret)
+		return ret;
+
+	if (!fw || !fw->data || fw->size < N9_REGION_NUM * sizeof(*hdr)) {
+		dev_err(dev->mt76.dev, "Invalid firmware\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
+					N9_REGION_NUM * sizeof(*hdr));
+
+	dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
+		 hdr->fw_ver, hdr->build_date);
+
+	n9_ilm_addr = le32_to_cpu(hdr->addr);
+
+	for (offset = 0, i = 0; i < N9_REGION_NUM; i++) {
+		u32 len, addr, mode;
+
+		len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
+		addr = le32_to_cpu(hdr[i].addr);
+		mode = gen_dl_mode(hdr[i].feature_set, false);
+
+		ret = mt7615_mcu_init_download(dev, addr, len, mode);
+		if (ret) {
+			dev_err(dev->mt76.dev, "Download request failed\n");
+			goto out;
+		}
+
+		ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len);
+		if (ret) {
+			dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
+			goto out;
+		}
+
+		offset += len;
+	}
+
+	ret = mt7615_mcu_start_firmware(dev, n9_ilm_addr, FW_START_OVERRIDE);
+	if (ret) {
+		dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
+		goto out;
+	}
+
+	release_firmware(fw);
+
+	ret = request_firmware(&fw, cr4_firmware, dev->mt76.dev);
+	if (ret)
+		return ret;
+
+	if (!fw || !fw->data || fw->size < CR4_REGION_NUM * sizeof(*hdr)) {
+		dev_err(dev->mt76.dev, "Invalid firmware\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	hdr = (const struct mt7615_fw_trailer *)(fw->data + fw->size -
+					CR4_REGION_NUM * sizeof(*hdr));
+
+	dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
+		 hdr->fw_ver, hdr->build_date);
+
+	for (offset = 0, i = 0; i < CR4_REGION_NUM; i++) {
+		u32 len, addr, mode;
+
+		len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
+		addr = le32_to_cpu(hdr[i].addr);
+		mode = gen_dl_mode(hdr[i].feature_set, true);
+
+		ret = mt7615_mcu_init_download(dev, addr, len, mode);
+		if (ret) {
+			dev_err(dev->mt76.dev, "Download request failed\n");
+			goto out;
+		}
+
+		ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len);
+		if (ret) {
+			dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
+			goto out;
+		}
+
+		offset += len;
+	}
+
+	ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4);
+	if (ret)
+		dev_err(dev->mt76.dev, "Failed to start CR4 firmware\n");
+
+out:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int mt7615_load_firmware(struct mt7615_dev *dev)
+{
+	int ret;
+	u32 val;
+
+	val = mt76_get_field(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE);
+
+	if (val != FW_STATE_FW_DOWNLOAD) {
+		dev_err(dev->mt76.dev, "Firmware is not ready for download\n");
+		return -EIO;
+	}
+
+	ret = mt7615_load_patch(dev);
+	if (ret)
+		return ret;
+
+	ret = mt7615_load_ram(dev);
+	if (ret)
+		return ret;
+
+	if (!mt76_poll_msec(dev, MT_TOP_MISC2, MT_TOP_MISC2_FW_STATE,
+			    FIELD_PREP(MT_TOP_MISC2_FW_STATE,
+				       FW_STATE_CR4_RDY), 500)) {
+		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
+		return -EIO;
+	}
+
+	dev_dbg(dev->mt76.dev, "Firmware init done\n");
+
+	return 0;
+}
+
+int mt7615_mcu_init(struct mt7615_dev *dev)
+{
+	int ret;
+
+	ret = mt7615_driver_own(dev);
+	if (ret)
+		return ret;
+
+	ret = mt7615_load_firmware(dev);
+	if (ret)
+		return ret;
+
+	set_bit(MT76_STATE_MCU_RUNNING, &dev->mt76.state);
+
+	return 0;
+}
+
+void mt7615_mcu_exit(struct mt7615_dev *dev)
+{
+	mt7615_mcu_restart(dev);
+	mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_FW_OWN);
+	skb_queue_purge(&dev->mt76.mmio.mcu.res_q);
+}
+
+int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
+{
+	struct req_data {
+		u8 val;
+	} __packed;
+	struct {
+		u8 buffer_mode;
+		u8 pad;
+		u16 len;
+	} __packed req_hdr = {
+		.buffer_mode = 1,
+		.len = __MT_EE_MAX - MT_EE_NIC_CONF_0,
+	};
+	struct sk_buff *skb;
+	struct req_data *data;
+	const int size = (__MT_EE_MAX - MT_EE_NIC_CONF_0) *
+			 sizeof(struct req_data);
+	u8 *eep = (u8 *)dev->mt76.eeprom.data;
+	u16 off;
+
+	skb = mt7615_mcu_msg_alloc(NULL, size + sizeof(req_hdr));
+	memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
+	data = (struct req_data *)skb_put(skb, size);
+	memset(data, 0, size);
+
+	for (off = MT_EE_NIC_CONF_0; off < __MT_EE_MAX; off++)
+		data[off - MT_EE_NIC_CONF_0].val = eep[off];
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_init_mac(struct mt7615_dev *dev)
+{
+	struct {
+		u8 enable;
+		u8 band;
+		u8 rsv[2];
+	} __packed req = {
+		.enable = 1,
+		.band = 0,
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_MAC_INIT_CTRL,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val)
+{
+	struct {
+		u8 prot_idx;
+		u8 band;
+		u8 rsv[2];
+		__le32 len_thresh;
+		__le32 pkt_thresh;
+	} __packed req = {
+		.prot_idx = 1,
+		.band = 0,
+		.len_thresh = cpu_to_le32(val),
+		.pkt_thresh = cpu_to_le32(0x2),
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_PROTECT_CTRL,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
+		       const struct ieee80211_tx_queue_params *params)
+{
+#define WMM_AIFS_SET	BIT(0)
+#define WMM_CW_MIN_SET	BIT(1)
+#define WMM_CW_MAX_SET	BIT(2)
+#define WMM_TXOP_SET	BIT(3)
+	struct req_data {
+		u8 number;
+		u8 rsv[3];
+		u8 queue;
+		u8 valid;
+		u8 aifs;
+		u8 cw_min;
+		__le16 cw_max;
+		__le16 txop;
+	} __packed req = {
+		.number = 1,
+		.queue = queue,
+		.valid = WMM_AIFS_SET | WMM_TXOP_SET,
+		.aifs = params->aifs,
+		.txop = cpu_to_le16(params->txop),
+	};
+	struct sk_buff *skb;
+
+	if (params->cw_min) {
+		req.valid |= WMM_CW_MIN_SET;
+		req.cw_min = params->cw_min;
+	}
+	if (params->cw_max) {
+		req.valid |= WMM_CW_MAX_SET;
+		req.cw_max = cpu_to_le16(params->cw_max);
+	}
+
+	skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_EDCA_UPDATE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter)
+{
+#define ENTER_PM_STATE	1
+#define EXIT_PM_STATE	2
+	struct {
+		u8 pm_number;
+		u8 pm_state;
+		u8 bssid[ETH_ALEN];
+		u8 dtim_period;
+		u8 wlan_idx;
+		__le16 bcn_interval;
+		__le32 aid;
+		__le32 rx_filter;
+		u8 band_idx;
+		u8 rsv[3];
+		__le32 feature;
+		u8 omac_idx;
+		u8 wmm_idx;
+		u8 bcn_loss_cnt;
+		u8 bcn_sp_duration;
+	} __packed req = {
+		.pm_number = 5,
+		.pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE,
+		.band_idx = 0,
+	};
+	struct sk_buff *skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_PM_STATE_CTRL,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+static int __mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
+				     struct dev_info *dev_info)
+{
+	struct req_hdr {
+		u8 omac_idx;
+		u8 band_idx;
+		__le16 tlv_num;
+		u8 is_tlv_append;
+		u8 rsv[3];
+	} __packed req_hdr = {0};
+	struct req_tlv {
+		__le16 tag;
+		__le16 len;
+		u8 active;
+		u8 band_idx;
+		u8 omac_addr[ETH_ALEN];
+	} __packed;
+	struct sk_buff *skb;
+	u16 tlv_num = 0;
+
+	skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) +
+				   sizeof(struct req_tlv));
+	skb_reserve(skb, sizeof(req_hdr));
+
+	if (dev_info->feature & BIT(DEV_INFO_ACTIVE)) {
+		struct req_tlv req_tlv = {
+			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
+			.len = cpu_to_le16(sizeof(req_tlv)),
+			.active = dev_info->enable,
+			.band_idx = dev_info->band_idx,
+		};
+		memcpy(req_tlv.omac_addr, dev_info->omac_addr, ETH_ALEN);
+		memcpy(skb_put(skb, sizeof(req_tlv)), &req_tlv,
+		       sizeof(req_tlv));
+		tlv_num++;
+	}
+
+	req_hdr.omac_idx = dev_info->omac_idx;
+	req_hdr.band_idx = dev_info->band_idx;
+	req_hdr.tlv_num = cpu_to_le16(tlv_num);
+	req_hdr.is_tlv_append = tlv_num ? 1 : 0;
+
+	memcpy(skb_push(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_DEV_INFO_UPDATE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			    int en)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct dev_info dev_info = {0};
+
+	dev_info.omac_idx = mvif->omac_idx;
+	memcpy(dev_info.omac_addr, vif->addr, ETH_ALEN);
+	dev_info.band_idx = mvif->band_idx;
+	dev_info.enable = en;
+	dev_info.feature = BIT(DEV_INFO_ACTIVE);
+
+	return __mt7615_mcu_set_dev_info(dev, &dev_info);
+}
+
+static void bss_info_omac_handler (struct mt7615_dev *dev,
+				   struct bss_info *bss_info,
+				   struct sk_buff *skb)
+{
+	struct bss_info_omac tlv = {0};
+
+	tlv.tag = cpu_to_le16(BSS_INFO_OMAC);
+	tlv.len = cpu_to_le16(sizeof(tlv));
+	tlv.hw_bss_idx = (bss_info->omac_idx > EXT_BSSID_START) ?
+			 HW_BSSID_0 : bss_info->omac_idx;
+	tlv.omac_idx = bss_info->omac_idx;
+	tlv.band_idx = bss_info->band_idx;
+	tlv.conn_type = cpu_to_le32(bss_info->conn_type);
+
+	memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+}
+
+static void bss_info_basic_handler (struct mt7615_dev *dev,
+				    struct bss_info *bss_info,
+				    struct sk_buff *skb)
+{
+	struct bss_info_basic tlv = {0};
+
+	tlv.tag = cpu_to_le16(BSS_INFO_BASIC);
+	tlv.len = cpu_to_le16(sizeof(tlv));
+	tlv.network_type = cpu_to_le32(bss_info->network_type);
+	tlv.active = bss_info->enable;
+	tlv.bcn_interval = cpu_to_le16(bss_info->bcn_interval);
+	memcpy(tlv.bssid, bss_info->bssid, ETH_ALEN);
+	tlv.wmm_idx = bss_info->wmm_idx;
+	tlv.dtim_period = bss_info->dtim_period;
+	tlv.bmc_tx_wlan_idx = bss_info->bmc_tx_wlan_idx;
+
+	memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+}
+
+static void bss_info_ext_bss_handler (struct mt7615_dev *dev,
+				      struct bss_info *bss_info,
+				      struct sk_buff *skb)
+{
+/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */
+#define BCN_TX_ESTIMATE_TIME (4096 + 20)
+	struct bss_info_ext_bss tlv = {0};
+	int ext_bss_idx;
+
+	ext_bss_idx = bss_info->omac_idx - EXT_BSSID_START;
+
+	if (ext_bss_idx < 0)
+		return;
+
+	tlv.tag = cpu_to_le16(BSS_INFO_EXT_BSS);
+	tlv.len = cpu_to_le16(sizeof(tlv));
+	tlv.mbss_tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;
+
+	memcpy(skb_put(skb, sizeof(tlv)), &tlv, sizeof(tlv));
+}
+
+static struct bss_info_tag_handler bss_info_tag_handler[] = {
+	{BSS_INFO_OMAC, sizeof(struct bss_info_omac), bss_info_omac_handler},
+	{BSS_INFO_BASIC, sizeof(struct bss_info_basic), bss_info_basic_handler},
+	{BSS_INFO_RF_CH, sizeof(struct bss_info_rf_ch), NULL},
+	{BSS_INFO_PM, 0, NULL},
+	{BSS_INFO_UAPSD, 0, NULL},
+	{BSS_INFO_ROAM_DETECTION, 0, NULL},
+	{BSS_INFO_LQ_RM, 0, NULL},
+	{BSS_INFO_EXT_BSS, sizeof(struct bss_info_ext_bss), bss_info_ext_bss_handler},
+	{BSS_INFO_BMC_INFO, 0, NULL},
+	{BSS_INFO_SYNC_MODE, 0, NULL},
+	{BSS_INFO_RA, 0, NULL},
+	{BSS_INFO_MAX_NUM, 0, NULL},
+};
+
+static int __mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
+				     struct bss_info *bss_info)
+{
+	struct req_hdr {
+		u8 bss_idx;
+		u8 rsv0;
+		__le16 tlv_num;
+		u8 is_tlv_append;
+		u8 rsv1[3];
+	} __packed req_hdr = {0};
+	struct sk_buff *skb;
+	u16 tlv_num = 0;
+	u32 size = 0;
+	int i;
+
+	for (i = 0; i < BSS_INFO_MAX_NUM; i++)
+		if ((BIT(bss_info_tag_handler[i].tag) & bss_info->feature) &&
+		    bss_info_tag_handler[i].handler) {
+			tlv_num++;
+			size += bss_info_tag_handler[i].len;
+		}
+
+	skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + size);
+
+	req_hdr.bss_idx = bss_info->bss_idx;
+	req_hdr.tlv_num = cpu_to_le16(tlv_num);
+	req_hdr.is_tlv_append = tlv_num ? 1 : 0;
+
+	memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
+
+	for (i = 0; i < BSS_INFO_MAX_NUM; i++)
+		if ((BIT(bss_info_tag_handler[i].tag) & bss_info->feature) &&
+		    bss_info_tag_handler[i].handler)
+			bss_info_tag_handler[i].handler(dev, bss_info, skb);
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_BSS_INFO_UPDATE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+static void bss_info_convert_vif_type(enum nl80211_iftype type,
+				      u32 *network_type, u32 *conn_type)
+{
+	switch (type) {
+	case NL80211_IFTYPE_AP:
+		if (network_type)
+			*network_type = NETWORK_INFRA;
+		if (conn_type)
+			*conn_type = CONNECTION_INFRA_AP;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (network_type)
+			*network_type = NETWORK_INFRA;
+		if (conn_type)
+			*conn_type = CONNECTION_INFRA_STA;
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	};
+}
+
+int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			    int en)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct bss_info bss_info = {0};
+	u8 bmc_tx_wlan_idx = 0;
+	u32 network_type = 0, conn_type = 0;
+
+	if (vif->type == NL80211_IFTYPE_AP) {
+		bmc_tx_wlan_idx = mvif->sta.wcid.idx;
+	} else if (vif->type == NL80211_IFTYPE_STATION) {
+		/* find the unicast entry for sta mode bmc tx */
+		struct ieee80211_sta *ap_sta;
+		struct mt7615_sta *msta;
+
+		rcu_read_lock();
+
+		ap_sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+		if (!ap_sta) {
+			rcu_read_unlock();
+			return -EINVAL;
+		}
+
+		msta = (struct mt7615_sta *)ap_sta->drv_priv;
+		bmc_tx_wlan_idx = msta->wcid.idx;
+
+		rcu_read_unlock();
+	} else {
+		WARN_ON(1);
+	}
+
+	bss_info_convert_vif_type(vif->type, &network_type, &conn_type);
+
+	bss_info.bss_idx = mvif->idx;
+	memcpy(bss_info.bssid, vif->bss_conf.bssid, ETH_ALEN);
+	bss_info.omac_idx = mvif->omac_idx;
+	bss_info.band_idx = mvif->band_idx;
+	bss_info.bmc_tx_wlan_idx = bmc_tx_wlan_idx;
+	bss_info.wmm_idx = mvif->wmm_idx;
+	bss_info.network_type = network_type;
+	bss_info.conn_type = conn_type;
+	bss_info.bcn_interval = vif->bss_conf.beacon_int;
+	bss_info.dtim_period = vif->bss_conf.dtim_period;
+	bss_info.enable = en;
+	bss_info.feature = BIT(BSS_INFO_BASIC);
+	if (en) {
+		bss_info.feature |= BIT(BSS_INFO_OMAC);
+		if (mvif->omac_idx > EXT_BSSID_START)
+			bss_info.feature |= BIT(BSS_INFO_EXT_BSS);
+	}
+
+	return __mt7615_mcu_set_bss_info(dev, &bss_info);
+}
+
+static int __mt7615_mcu_set_wtbl(struct mt7615_dev *dev, int wlan_idx,
+				 int operation, void *buf, int buf_len)
+{
+	struct req_hdr {
+		u8 wlan_idx;
+		u8 operation;
+		__le16 tlv_num;
+		u8 rsv[4];
+	} __packed req_hdr = {0};
+	struct tlv {
+		__le16 tag;
+		__le16 len;
+		u8 buf[0];
+	} __packed;
+	struct sk_buff *skb;
+	u16 tlv_num = 0;
+	int offset = 0;
+
+	while (offset < buf_len) {
+		struct tlv *tlv = (struct tlv *)((u8 *)buf + offset);
+
+		tlv_num++;
+		offset += tlv->len;
+	}
+
+	skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + buf_len);
+
+	req_hdr.wlan_idx = wlan_idx;
+	req_hdr.operation = operation;
+	req_hdr.tlv_num = cpu_to_le16(tlv_num);
+
+	memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
+
+	if (buf && buf_len)
+		memcpy(skb_put(skb, buf_len), buf, buf_len);
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_WTBL_UPDATE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+static enum mt7615_cipher_type
+mt7615_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
+{
+	if (!key || key->keylen > 32)
+		return MT_CIPHER_NONE;
+
+	memcpy(key_data, key->key, key->keylen);
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+		return MT_CIPHER_WEP40;
+	case WLAN_CIPHER_SUITE_WEP104:
+		return MT_CIPHER_WEP104;
+	case WLAN_CIPHER_SUITE_TKIP:
+		/* Rx/Tx MIC keys are swapped */
+		memcpy(key_data + 16, key->key + 24, 8);
+		memcpy(key_data + 24, key->key + 16, 8);
+		return MT_CIPHER_TKIP;
+	case WLAN_CIPHER_SUITE_CCMP:
+		return MT_CIPHER_AES_CCMP;
+	case WLAN_CIPHER_SUITE_CCMP_256:
+		return MT_CIPHER_CCMP_256;
+	case WLAN_CIPHER_SUITE_GCMP:
+		return MT_CIPHER_GCMP;
+	case WLAN_CIPHER_SUITE_GCMP_256:
+		return MT_CIPHER_GCMP_256;
+	case WLAN_CIPHER_SUITE_SMS4:
+		return MT_CIPHER_WAPI;
+	default:
+		return MT_CIPHER_NONE;
+	}
+}
+
+int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
+			    struct ieee80211_key_conf *key,
+			    enum set_key_cmd cmd)
+{
+	struct wtbl_sec_key wtbl_sec_key = {0};
+	int buf_len = sizeof(struct wtbl_sec_key);
+	u8 cipher;
+
+	wtbl_sec_key.tag = cpu_to_le16(WTBL_SEC_KEY);
+	wtbl_sec_key.len = cpu_to_le16(buf_len);
+	wtbl_sec_key.add = cmd;
+
+	if (cmd == SET_KEY) {
+		cipher = mt7615_get_key_info(key, wtbl_sec_key.key_material);
+		if (cipher == MT_CIPHER_NONE && key)
+			return -EOPNOTSUPP;
+
+		wtbl_sec_key.cipher_id = cipher;
+		wtbl_sec_key.key_id = key->keyidx;
+		wtbl_sec_key.key_len = key->keylen;
+	} else {
+		wtbl_sec_key.key_len = sizeof(wtbl_sec_key.key_material);
+	}
+
+	return __mt7615_mcu_set_wtbl(dev, wcid, WTBL_SET, &wtbl_sec_key,
+				     buf_len);
+}
+
+int mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct wtbl_generic *wtbl_generic;
+	struct wtbl_rx *wtbl_rx;
+	int buf_len, ret;
+	u8 *buf;
+
+	buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	wtbl_generic = (struct wtbl_generic *)buf;
+	buf_len = sizeof(*wtbl_generic);
+	wtbl_generic->tag = cpu_to_le16(WTBL_GENERIC);
+	wtbl_generic->len = cpu_to_le16(buf_len);
+	eth_broadcast_addr(wtbl_generic->peer_addr);
+	wtbl_generic->muar_idx = 0xe;
+
+	wtbl_rx = (struct wtbl_rx *)(buf + buf_len);
+	buf_len += sizeof(*wtbl_rx);
+	wtbl_rx->tag = cpu_to_le16(WTBL_RX);
+	wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
+	wtbl_rx->rca1 = 1;
+	wtbl_rx->rca2 = 1;
+	wtbl_rx->rv = 1;
+
+	ret = __mt7615_mcu_set_wtbl(dev, mvif->sta.wcid.idx,
+				    WTBL_RESET_AND_SET, buf, buf_len);
+
+	kfree(buf);
+	return ret;
+}
+
+int mt7615_mcu_del_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+
+	return __mt7615_mcu_set_wtbl(dev, mvif->sta.wcid.idx,
+				     WTBL_RESET_AND_SET, NULL, 0);
+}
+
+int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct wtbl_generic *wtbl_generic;
+	struct wtbl_rx *wtbl_rx;
+	int buf_len, ret;
+	u8 *buf;
+
+	buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	wtbl_generic = (struct wtbl_generic *)buf;
+	buf_len = sizeof(*wtbl_generic);
+	wtbl_generic->tag = cpu_to_le16(WTBL_GENERIC);
+	wtbl_generic->len = cpu_to_le16(buf_len);
+	memcpy(wtbl_generic->peer_addr, sta->addr, ETH_ALEN);
+	wtbl_generic->muar_idx = mvif->omac_idx;
+	wtbl_generic->qos = sta->wme;
+	wtbl_generic->partial_aid = cpu_to_le16(sta->aid);
+
+	wtbl_rx = (struct wtbl_rx *)(buf + buf_len);
+	buf_len += sizeof(*wtbl_rx);
+	wtbl_rx->tag = cpu_to_le16(WTBL_RX);
+	wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
+	wtbl_rx->rca1 = (vif->type == NL80211_IFTYPE_AP) ? 0 : 1;
+	wtbl_rx->rca2 = 1;
+	wtbl_rx->rv = 1;
+
+	ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx,
+				    WTBL_RESET_AND_SET, buf, buf_len);
+
+	kfree(buf);
+	return ret;
+}
+
+int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta)
+{
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+
+	return __mt7615_mcu_set_wtbl(dev, msta->wcid.idx,
+				     WTBL_RESET_AND_SET, NULL, 0);
+}
+
+int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
+{
+	return __mt7615_mcu_set_wtbl(dev, 0, WTBL_RESET_ALL, NULL, 0);
+}
+
+static int __mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, int bss_idx,
+				    int wlan_idx, int muar_idx, void *buf,
+				    int buf_len)
+{
+	struct req_hdr {
+		u8 bss_idx;
+		u8 wlan_idx;
+		__le16 tlv_num;
+		u8 is_tlv_append;
+		u8 muar_idx;
+		u8 rsv[2];
+	} __packed req_hdr = {0};
+	struct tlv {
+		__le16 tag;
+		__le16 len;
+		u8 buf[0];
+	} __packed;
+	struct sk_buff *skb;
+	u16 tlv_num = 0;
+	int offset = 0;
+
+	while (offset < buf_len) {
+		struct tlv *tlv = (struct tlv *)((u8 *)buf + offset);
+
+		tlv_num++;
+		offset += tlv->len;
+	}
+
+	skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + buf_len);
+
+	req_hdr.bss_idx = bss_idx;
+	req_hdr.wlan_idx = wlan_idx;
+	req_hdr.tlv_num = cpu_to_le16(tlv_num);
+	req_hdr.is_tlv_append = tlv_num ? 1 : 0;
+	req_hdr.muar_idx = muar_idx;
+
+	memcpy(skb_put(skb, sizeof(req_hdr)), &req_hdr, sizeof(req_hdr));
+
+	if (buf && buf_len)
+		memcpy(skb_put(skb, buf_len), buf, buf_len);
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_STA_REC_UPDATE,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_sta_rec_bmc(struct mt7615_dev *dev,
+			       struct ieee80211_vif *vif, bool en)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct sta_rec_basic sta_rec_basic = {0};
+	int buf_len = sizeof(struct sta_rec_basic);
+
+	sta_rec_basic.tag = cpu_to_le16(STA_REC_BASIC);
+	sta_rec_basic.len = cpu_to_le16(buf_len);
+	sta_rec_basic.conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
+	eth_broadcast_addr(sta_rec_basic.peer_addr);
+	if (en) {
+		sta_rec_basic.conn_state = CONN_STATE_PORT_SECURE;
+		sta_rec_basic.extra_info =
+			cpu_to_le16(EXTRA_INFO_VER | EXTRA_INFO_NEW);
+	} else {
+		sta_rec_basic.conn_state = CONN_STATE_DISCONNECT;
+		sta_rec_basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
+	}
+
+	return __mt7615_mcu_set_sta_rec(dev, mvif->idx, mvif->sta.wcid.idx,
+					mvif->omac_idx, &sta_rec_basic,
+					buf_len);
+}
+
+static void sta_rec_convert_vif_type(enum nl80211_iftype type, u32 *conn_type)
+{
+	switch (type) {
+	case NL80211_IFTYPE_AP:
+		if (conn_type)
+			*conn_type = CONNECTION_INFRA_STA;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (conn_type)
+			*conn_type = CONNECTION_INFRA_AP;
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	};
+}
+
+int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta, bool en)
+{
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct sta_rec_basic sta_rec_basic = {0};
+	int buf_len = sizeof(struct sta_rec_basic);
+	u32 conn_type = 0;
+
+	sta_rec_convert_vif_type(vif->type, &conn_type);
+
+	sta_rec_basic.tag = cpu_to_le16(STA_REC_BASIC);
+	sta_rec_basic.len = cpu_to_le16(buf_len);
+	sta_rec_basic.conn_type = cpu_to_le32(conn_type);
+	sta_rec_basic.qos = sta->wme;
+	sta_rec_basic.aid = cpu_to_le16(sta->aid);
+	memcpy(sta_rec_basic.peer_addr, sta->addr, ETH_ALEN);
+
+	if (en) {
+		sta_rec_basic.conn_state = CONN_STATE_PORT_SECURE;
+		sta_rec_basic.extra_info =
+			cpu_to_le16(EXTRA_INFO_VER | EXTRA_INFO_NEW);
+	} else {
+		sta_rec_basic.conn_state = CONN_STATE_DISCONNECT;
+		sta_rec_basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
+	}
+
+	return __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
+					mvif->omac_idx, &sta_rec_basic,
+					buf_len);
+}
+
+int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+		       int en)
+{
+	struct req {
+		u8 omac_idx;
+		u8 enable;
+		u8 wlan_idx;
+		u8 band_idx;
+		u8 pkt_type;
+		u8 need_pre_tbtt_int;
+		__le16 csa_ie_pos;
+		__le16 pkt_len;
+		__le16 tim_ie_pos;
+		u8 pkt[512];
+		u8 csa_cnt;
+		/* bss color change */
+		u8 bcc_cnt;
+		__le16 bcc_ie_pos;
+	} __packed req = {0};
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+	struct sk_buff *skb;
+	u16 tim_off, tim_len;
+
+	skb = ieee80211_beacon_get_tim(mt76_hw(dev), vif, &tim_off, &tim_len);
+
+	if (!skb)
+		return -EINVAL;
+
+	if (skb->len > 512 - MT_TXD_SIZE) {
+		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
+		dev_kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
+			      0, NULL);
+	memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
+	dev_kfree_skb(skb);
+
+	req.omac_idx = mvif->omac_idx;
+	req.enable = en;
+	req.wlan_idx = wcid->idx;
+	req.band_idx = mvif->band_idx;
+	/* pky_type: 0 for bcn, 1 for tim */
+	req.pkt_type = 0;
+	req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+	req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + tim_off);
+
+	skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_BCN_OFFLOAD,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_channel(struct mt7615_dev *dev)
+{
+	struct cfg80211_chan_def *chdef = &dev->mt76.chandef;
+	struct {
+		u8 control_chan;
+		u8 center_chan;
+		u8 bw;
+		u8 tx_streams;
+		u8 rx_streams_mask;
+		u8 switch_reason;
+		u8 band_idx;
+		/* for 80+80 only */
+		u8 center_chan2;
+		__le16 cac_case;
+		u8 channel_band;
+		u8 rsv0;
+		__le32 outband_freq;
+		u8 txpower_drop;
+		u8 rsv1[3];
+		u8 txpower_sku[53];
+		u8 rsv2[3];
+	} req = {0};
+	struct sk_buff *skb;
+	int ret;
+
+	req.control_chan = chdef->chan->hw_value;
+	req.center_chan = ieee80211_frequency_to_channel(chdef->center_freq1);
+	req.tx_streams = (dev->mt76.chainmask >> 8) & 0xf;
+	req.rx_streams_mask = dev->mt76.antenna_mask;
+	req.switch_reason = CH_SWITCH_NORMAL;
+	req.band_idx = 0;
+	req.center_chan2 = ieee80211_frequency_to_channel(chdef->center_freq2);
+	req.txpower_drop = 0;
+
+	switch (dev->mt76.chandef.width) {
+	case NL80211_CHAN_WIDTH_40:
+		req.bw = CMD_CBW_40MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_80:
+		req.bw = CMD_CBW_80MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_80P80:
+		req.bw = CMD_CBW_8080MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_160:
+		req.bw = CMD_CBW_160MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_5:
+		req.bw = CMD_CBW_5MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_10:
+		req.bw = CMD_CBW_10MHZ;
+		break;
+	case NL80211_CHAN_WIDTH_20_NOHT:
+	case NL80211_CHAN_WIDTH_20:
+	default:
+		req.bw = CMD_CBW_20MHZ;
+	}
+
+	memset(req.txpower_sku, 0x3f, 49);
+
+	skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+	ret = mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_CHANNEL_SWITCH,
+				  MCU_Q_SET, MCU_S2D_H2N, NULL);
+	if (ret)
+		return ret;
+
+	skb = mt7615_mcu_msg_alloc(&req, sizeof(req));
+	return mt7615_mcu_msg_send(dev, skb, MCU_EXT_CMD_SET_RX_PATH,
+				   MCU_Q_SET, MCU_S2D_H2N, NULL);
+}
+
+int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta)
+{
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+	struct wtbl_ht *wtbl_ht;
+	struct wtbl_raw *wtbl_raw;
+	struct sta_rec_ht *sta_rec_ht;
+	int buf_len, ret;
+	u32 msk, val = 0;
+	u8 *buf;
+
+	buf = kzalloc(MT7615_WTBL_UPDATE_MAX_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* ht basic */
+	buf_len = sizeof(*wtbl_ht);
+	wtbl_ht = (struct wtbl_ht *)buf;
+	wtbl_ht->tag = cpu_to_le16(WTBL_HT);
+	wtbl_ht->len = cpu_to_le16(sizeof(*wtbl_ht));
+	wtbl_ht->ht = 1;
+	wtbl_ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
+	wtbl_ht->af = sta->ht_cap.ampdu_factor;
+	wtbl_ht->mm = sta->ht_cap.ampdu_density;
+
+	if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
+		val |= MT_WTBL_W5_SHORT_GI_20;
+	if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+		val |= MT_WTBL_W5_SHORT_GI_40;
+
+	/* vht basic */
+	if (sta->vht_cap.vht_supported) {
+		struct wtbl_vht *wtbl_vht;
+
+		wtbl_vht = (struct wtbl_vht *)(buf + buf_len);
+		buf_len += sizeof(*wtbl_vht);
+		wtbl_vht->tag = cpu_to_le16(WTBL_VHT);
+		wtbl_vht->len = cpu_to_le16(sizeof(*wtbl_vht));
+		wtbl_vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC;
+		wtbl_vht->vht = 1;
+
+		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
+			val |= MT_WTBL_W5_SHORT_GI_80;
+		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
+			val |= MT_WTBL_W5_SHORT_GI_160;
+	}
+
+	/* smps */
+	if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
+		struct wtbl_smps *wtbl_smps;
+
+		wtbl_smps = (struct wtbl_smps *)(buf + buf_len);
+		buf_len += sizeof(*wtbl_smps);
+		wtbl_smps->tag = cpu_to_le16(WTBL_SMPS);
+		wtbl_smps->len = cpu_to_le16(sizeof(*wtbl_smps));
+		wtbl_smps->smps = 1;
+	}
+
+	/* sgi */
+	msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 |
+	      MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160;
+
+	wtbl_raw = (struct wtbl_raw *)(buf + buf_len);
+	buf_len += sizeof(*wtbl_raw);
+	wtbl_raw->tag = cpu_to_le16(WTBL_RAW_DATA);
+	wtbl_raw->len = cpu_to_le16(sizeof(*wtbl_raw));
+	wtbl_raw->wtbl_idx = 1;
+	wtbl_raw->dw = 5;
+	wtbl_raw->msk = cpu_to_le32(~msk);
+	wtbl_raw->val = cpu_to_le32(val);
+
+	ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET, buf,
+				    buf_len);
+	if (ret) {
+		kfree(buf);
+		return ret;
+	}
+
+	memset(buf, 0, MT7615_WTBL_UPDATE_MAX_SIZE);
+
+	buf_len = sizeof(*sta_rec_ht);
+	sta_rec_ht = (struct sta_rec_ht *)buf;
+	sta_rec_ht->tag = cpu_to_le16(STA_REC_HT);
+	sta_rec_ht->len = cpu_to_le16(sizeof(*sta_rec_ht));
+	sta_rec_ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+
+	if (sta->vht_cap.vht_supported) {
+		struct sta_rec_vht *sta_rec_vht;
+
+		sta_rec_vht = (struct sta_rec_vht *)(buf + buf_len);
+		buf_len += sizeof(*sta_rec_vht);
+		sta_rec_vht->tag = cpu_to_le16(STA_REC_VHT);
+		sta_rec_vht->len = cpu_to_le16(sizeof(*sta_rec_vht));
+		sta_rec_vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
+		sta_rec_vht->vht_rx_mcs_map =
+			cpu_to_le16(sta->vht_cap.vht_mcs.rx_mcs_map);
+		sta_rec_vht->vht_tx_mcs_map =
+			cpu_to_le16(sta->vht_cap.vht_mcs.tx_mcs_map);
+	}
+
+	ret = __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
+				       mvif->omac_idx, buf, buf_len);
+	kfree(buf);
+	return ret;
+}
+
+int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev,
+			 struct ieee80211_ampdu_params *params,
+			 bool add)
+{
+	struct ieee80211_sta *sta = params->sta;
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct mt7615_vif *mvif = msta->vif;
+	u8 ba_range[8] = {4, 8, 12, 24, 36, 48, 54, 64};
+	u16 tid = params->tid;
+	u16 ba_size = params->buf_size;
+	u16 ssn = params->ssn;
+	struct wtbl_ba wtbl_ba = {0};
+	struct sta_rec_ba sta_rec_ba = {0};
+	int ret, buf_len;
+
+	buf_len = sizeof(struct wtbl_ba);
+
+	wtbl_ba.tag = cpu_to_le16(WTBL_BA);
+	wtbl_ba.len = cpu_to_le16(buf_len);
+	wtbl_ba.tid = tid;
+	wtbl_ba.ba_type = MT_BA_TYPE_ORIGINATOR;
+
+	if (add) {
+		u8 idx;
+
+		for (idx = 7; idx > 0; idx--) {
+			if (ba_size >= ba_range[idx])
+				break;
+		}
+
+		wtbl_ba.sn = cpu_to_le16(ssn);
+		wtbl_ba.ba_en = 1;
+		wtbl_ba.ba_winsize_idx = idx;
+	}
+
+	ret = __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET, &wtbl_ba,
+				    buf_len);
+	if (ret)
+		return ret;
+
+	buf_len = sizeof(struct sta_rec_ba);
+
+	sta_rec_ba.tag = cpu_to_le16(STA_REC_BA);
+	sta_rec_ba.len = cpu_to_le16(buf_len);
+	sta_rec_ba.tid = tid;
+	sta_rec_ba.ba_type = MT_BA_TYPE_ORIGINATOR;
+	sta_rec_ba.amsdu = params->amsdu;
+	sta_rec_ba.ba_en = add << tid;
+	sta_rec_ba.ssn = cpu_to_le16(ssn);
+	sta_rec_ba.winsize = cpu_to_le16(ba_size);
+
+	return __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
+					mvif->omac_idx, &sta_rec_ba, buf_len);
+}
+
+int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
+			 struct ieee80211_ampdu_params *params,
+			 bool add)
+{
+	struct ieee80211_sta *sta = params->sta;
+	struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
+	struct mt7615_vif *mvif = msta->vif;
+	u16 tid = params->tid;
+	struct wtbl_ba wtbl_ba = {0};
+	struct sta_rec_ba sta_rec_ba = {0};
+	int ret, buf_len;
+
+	buf_len = sizeof(struct sta_rec_ba);
+
+	sta_rec_ba.tag = cpu_to_le16(STA_REC_BA);
+	sta_rec_ba.len = cpu_to_le16(buf_len);
+	sta_rec_ba.tid = tid;
+	sta_rec_ba.ba_type = MT_BA_TYPE_RECIPIENT;
+	sta_rec_ba.amsdu = params->amsdu;
+	sta_rec_ba.ba_en = add << tid;
+	sta_rec_ba.ssn = cpu_to_le16(params->ssn);
+	sta_rec_ba.winsize = cpu_to_le16(params->buf_size);
+
+	ret = __mt7615_mcu_set_sta_rec(dev, mvif->idx, msta->wcid.idx,
+				       mvif->omac_idx, &sta_rec_ba, buf_len);
+	if (ret || !add)
+		return ret;
+
+	buf_len = sizeof(struct wtbl_ba);
+
+	wtbl_ba.tag = cpu_to_le16(WTBL_BA);
+	wtbl_ba.len = cpu_to_le16(buf_len);
+	wtbl_ba.tid = tid;
+	wtbl_ba.ba_type = MT_BA_TYPE_RECIPIENT;
+	memcpy(wtbl_ba.peer_addr, sta->addr, ETH_ALEN);
+	wtbl_ba.rst_ba_tid = tid;
+	wtbl_ba.rst_ba_sel = RST_BA_MAC_TID_MATCH;
+	wtbl_ba.rst_ba_sb = 1;
+
+	return  __mt7615_mcu_set_wtbl(dev, msta->wcid.idx, WTBL_SET,
+				      &wtbl_ba, buf_len);
+}
+
+void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
+			  struct ieee80211_tx_rate *probe_rate,
+			  struct ieee80211_tx_rate *rates)
+{
+	int wcid = sta->wcid.idx;
+	u32 addr = MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
+	bool stbc = false;
+	int n_rates = sta->n_rates;
+	u8 bw, bw_prev, bw_idx = 0;
+	u16 val[4];
+	u16 probe_val;
+	u32 w5, w27;
+	int i;
+
+	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
+		return;
+
+	for (i = n_rates; i < 4; i++)
+		rates[i] = rates[n_rates - 1];
+
+	val[0] = mt7615_mac_tx_rate_val(dev, &rates[0], stbc, &bw);
+	bw_prev = bw;
+
+	if (probe_rate) {
+		probe_val = mt7615_mac_tx_rate_val(dev, probe_rate, stbc, &bw);
+		if (bw)
+			bw_idx = 1;
+		else
+			bw_prev = 0;
+	} else {
+		probe_val = val[0];
+	}
+
+	val[1] = mt7615_mac_tx_rate_val(dev, &rates[1], stbc, &bw);
+	if (bw_prev) {
+		bw_idx = 3;
+		bw_prev = bw;
+	}
+
+	val[2] = mt7615_mac_tx_rate_val(dev, &rates[2], stbc, &bw);
+	if (bw_prev) {
+		bw_idx = 5;
+		bw_prev = bw;
+	}
+
+	val[3] = mt7615_mac_tx_rate_val(dev, &rates[3], stbc, &bw);
+	if (bw_prev)
+		bw_idx = 7;
+
+	w27 = mt76_rr(dev, addr + 27 * 4);
+	w27 &= ~MT_WTBL_W27_CC_BW_SEL;
+	w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw);
+
+	w5 = mt76_rr(dev, addr + 5 * 4);
+	w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE);
+	w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) |
+	      FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7);
+
+	mt76_wr(dev, MT_WTBL_RIUCR0, w5);
+
+	mt76_wr(dev, MT_WTBL_RIUCR1,
+		FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
+		FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
+		FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[0]));
+
+	mt76_wr(dev, MT_WTBL_RIUCR2,
+		FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[0] >> 8) |
+		FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
+		FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[1]) |
+		FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
+
+	mt76_wr(dev, MT_WTBL_RIUCR3,
+		FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
+		FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[2]) |
+		FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
+
+	mt76_wr(dev, MT_WTBL_UPDATE,
+		FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
+		MT_WTBL_UPDATE_RATE_UPDATE |
+		MT_WTBL_UPDATE_TX_COUNT_CLEAR);
+
+	mt76_wr(dev, addr + 27 * 4, w27);
+
+	if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
+		mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
+
+	sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates;
+	sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
new file mode 100644
index 0000000..9455f8f
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -0,0 +1,520 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2019 MediaTek Inc. */
+
+#ifndef __MT7615_MCU_H
+#define __MT7615_MCU_H
+
+struct mt7615_mcu_txd {
+	__le32 txd[8];
+
+	__le16 len;
+	__le16 pq_id;
+
+	u8 cid;
+	u8 pkt_type;
+	u8 set_query; /* FW don't care */
+	u8 seq;
+
+	u8 uc_d2b0_rev;
+	u8 ext_cid;
+	u8 s2d_index;
+	u8 ext_cid_ack;
+
+	u32 reserved[5];
+} __packed __aligned(4);
+
+struct mt7615_mcu_rxd {
+	__le32 rxd[4];
+
+	__le16 len;
+	__le16 pkt_type_id;
+
+	u8 eid;
+	u8 seq;
+	__le16 __rsv;
+
+	u8 ext_eid;
+	u8 __rsv1[2];
+	u8 s2d_index;
+};
+
+#define MCU_PQ_ID(p, q)		(((p) << 15) | ((q) << 10))
+#define MCU_PKT_ID		0xa0
+
+enum {
+	MCU_Q_QUERY,
+	MCU_Q_SET,
+	MCU_Q_RESERVED,
+	MCU_Q_NA
+};
+
+enum {
+	MCU_S2D_H2N,
+	MCU_S2D_C2N,
+	MCU_S2D_H2C,
+	MCU_S2D_H2CN
+};
+
+enum {
+	MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01,
+	MCU_CMD_FW_START_REQ = 0x02,
+	MCU_CMD_INIT_ACCESS_REG = 0x3,
+	MCU_CMD_PATCH_START_REQ = 0x05,
+	MCU_CMD_PATCH_FINISH_REQ = 0x07,
+	MCU_CMD_PATCH_SEM_CONTROL = 0x10,
+	MCU_CMD_EXT_CID = 0xED,
+	MCU_CMD_FW_SCATTER = 0xEE,
+	MCU_CMD_RESTART_DL_REQ = 0xEF,
+};
+
+enum {
+	MCU_EXT_CMD_PM_STATE_CTRL = 0x07,
+	MCU_EXT_CMD_CHANNEL_SWITCH = 0x08,
+	MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
+	MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
+	MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
+	MCU_EXT_CMD_EDCA_UPDATE = 0x27,
+	MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
+	MCU_EXT_CMD_WTBL_UPDATE = 0x32,
+	MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
+	MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
+	MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
+	MCU_EXT_CMD_SET_RX_PATH = 0x4e,
+};
+
+enum {
+	PATCH_SEM_RELEASE = 0x0,
+	PATCH_SEM_GET	  = 0x1
+};
+
+enum {
+	PATCH_NOT_DL_SEM_FAIL	 = 0x0,
+	PATCH_IS_DL		 = 0x1,
+	PATCH_NOT_DL_SEM_SUCCESS = 0x2,
+	PATCH_REL_SEM_SUCCESS	 = 0x3
+};
+
+enum {
+	FW_STATE_INITIAL          = 0,
+	FW_STATE_FW_DOWNLOAD      = 1,
+	FW_STATE_NORMAL_OPERATION = 2,
+	FW_STATE_NORMAL_TRX       = 3,
+	FW_STATE_CR4_RDY          = 7
+};
+
+#define STA_TYPE_STA		BIT(0)
+#define STA_TYPE_AP		BIT(1)
+#define STA_TYPE_ADHOC		BIT(2)
+#define STA_TYPE_TDLS		BIT(3)
+#define STA_TYPE_WDS		BIT(4)
+#define STA_TYPE_BC		BIT(5)
+
+#define NETWORK_INFRA		BIT(16)
+#define NETWORK_P2P		BIT(17)
+#define NETWORK_IBSS		BIT(18)
+#define NETWORK_MESH		BIT(19)
+#define NETWORK_BOW		BIT(20)
+#define NETWORK_WDS		BIT(21)
+
+#define CONNECTION_INFRA_STA	(STA_TYPE_STA | NETWORK_INFRA)
+#define CONNECTION_INFRA_AP	(STA_TYPE_AP | NETWORK_INFRA)
+#define CONNECTION_P2P_GC	(STA_TYPE_STA | NETWORK_P2P)
+#define CONNECTION_P2P_GO	(STA_TYPE_AP | NETWORK_P2P)
+#define CONNECTION_MESH_STA	(STA_TYPE_STA | NETWORK_MESH)
+#define CONNECTION_MESH_AP	(STA_TYPE_AP | NETWORK_MESH)
+#define CONNECTION_IBSS_ADHOC	(STA_TYPE_ADHOC | NETWORK_IBSS)
+#define CONNECTION_TDLS		(STA_TYPE_STA | NETWORK_INFRA | STA_TYPE_TDLS)
+#define CONNECTION_WDS		(STA_TYPE_WDS | NETWORK_WDS)
+#define CONNECTION_INFRA_BC	(STA_TYPE_BC | NETWORK_INFRA)
+
+#define CONN_STATE_DISCONNECT	0
+#define CONN_STATE_CONNECT	1
+#define CONN_STATE_PORT_SECURE	2
+
+struct dev_info {
+	u8 omac_idx;
+	u8 omac_addr[ETH_ALEN];
+	u8 band_idx;
+	u8 enable;
+	u32 feature;
+};
+
+enum {
+	DEV_INFO_ACTIVE,
+	DEV_INFO_MAX_NUM
+};
+
+struct bss_info {
+	u8 bss_idx;
+	u8 bssid[ETH_ALEN];
+	u8 omac_idx;
+	u8 band_idx;
+	u8 bmc_tx_wlan_idx; /* for bmc tx (sta mode use uc entry) */
+	u8 wmm_idx;
+	u32 network_type;
+	u32 conn_type;
+	u16 bcn_interval;
+	u8 dtim_period;
+	u8 enable;
+	u32 feature;
+};
+
+struct bss_info_tag_handler {
+	u32 tag;
+	u32 len;
+	void (*handler)(struct mt7615_dev *dev,
+			struct bss_info *bss_info, struct sk_buff *skb);
+};
+
+struct bss_info_omac {
+	__le16 tag;
+	__le16 len;
+	u8 hw_bss_idx;
+	u8 omac_idx;
+	u8 band_idx;
+	u8 rsv0;
+	__le32 conn_type;
+	u32 rsv1;
+} __packed;
+
+struct bss_info_basic {
+	__le16 tag;
+	__le16 len;
+	__le32 network_type;
+	u8 active;
+	u8 rsv0;
+	__le16 bcn_interval;
+	u8 bssid[ETH_ALEN];
+	u8 wmm_idx;
+	u8 dtim_period;
+	u8 bmc_tx_wlan_idx;
+	u8 cipher; /* not used */
+	u8 phymode; /* not used */
+	u8 rsv1[5];
+} __packed;
+
+struct bss_info_rf_ch {
+	__le16 tag;
+	__le16 len;
+	u8 pri_ch;
+	u8 central_ch0;
+	u8 central_ch1;
+	u8 bw;
+} __packed;
+
+struct bss_info_ext_bss {
+	__le16 tag;
+	__le16 len;
+	__le32 mbss_tsf_offset; /* in unit of us */
+	u8 rsv[8];
+} __packed;
+
+enum {
+	BSS_INFO_OMAC,
+	BSS_INFO_BASIC,
+	BSS_INFO_RF_CH, /* optional, for BT/LTE coex */
+	BSS_INFO_PM, /* sta only */
+	BSS_INFO_UAPSD, /* sta only */
+	BSS_INFO_ROAM_DETECTION, /* obsoleted */
+	BSS_INFO_LQ_RM, /* obsoleted */
+	BSS_INFO_EXT_BSS,
+	BSS_INFO_BMC_INFO, /* for bmc rate control in CR4 */
+	BSS_INFO_SYNC_MODE, /* obsoleted */
+	BSS_INFO_RA,
+	BSS_INFO_MAX_NUM
+};
+
+enum {
+	WTBL_RESET_AND_SET = 1,
+	WTBL_SET,
+	WTBL_QUERY,
+	WTBL_RESET_ALL
+};
+
+struct wtbl_generic {
+	__le16 tag;
+	__le16 len;
+	u8 peer_addr[ETH_ALEN];
+	u8 muar_idx;
+	u8 skip_tx;
+	u8 cf_ack;
+	u8 qos;
+	u8 mesh;
+	u8 adm;
+	__le16 partial_aid;
+	u8 baf_en;
+	u8 aad_om;
+} __packed;
+
+struct wtbl_rx {
+	__le16 tag;
+	__le16 len;
+	u8 rcid;
+	u8 rca1;
+	u8 rca2;
+	u8 rv;
+	u8 rsv[4];
+} __packed;
+
+struct wtbl_ht {
+	__le16 tag;
+	__le16 len;
+	u8 ht;
+	u8 ldpc;
+	u8 af;
+	u8 mm;
+	u8 rsv[4];
+} __packed;
+
+struct wtbl_vht {
+	__le16 tag;
+	__le16 len;
+	u8 ldpc;
+	u8 dyn_bw;
+	u8 vht;
+	u8 txop_ps;
+	u8 rsv[4];
+} __packed;
+
+struct wtbl_tx_ps {
+	__le16 tag;
+	__le16 len;
+	u8 txps;
+	u8 rsv[3];
+} __packed;
+
+struct wtbl_hdr_trans {
+	__le16 tag;
+	__le16 len;
+	u8 to_ds;
+	u8 from_ds;
+	u8 disable_rx_trans;
+	u8 rsv;
+} __packed;
+
+enum mt7615_cipher_type {
+	MT_CIPHER_NONE,
+	MT_CIPHER_WEP40,
+	MT_CIPHER_TKIP,
+	MT_CIPHER_TKIP_NO_MIC,
+	MT_CIPHER_AES_CCMP,
+	MT_CIPHER_WEP104,
+	MT_CIPHER_BIP_CMAC_128,
+	MT_CIPHER_WEP128,
+	MT_CIPHER_WAPI,
+	MT_CIPHER_CCMP_256 = 10,
+	MT_CIPHER_GCMP,
+	MT_CIPHER_GCMP_256,
+};
+
+struct wtbl_sec_key {
+	__le16 tag;
+	__le16 len;
+	u8 add; /* 0: add, 1: remove */
+	u8 rkv;
+	u8 ikv;
+	u8 cipher_id;
+	u8 key_id;
+	u8 key_len;
+	u8 rsv[2];
+	u8 key_material[32];
+} __packed;
+
+enum {
+	MT_BA_TYPE_INVALID,
+	MT_BA_TYPE_ORIGINATOR,
+	MT_BA_TYPE_RECIPIENT
+};
+
+enum {
+	RST_BA_MAC_TID_MATCH,
+	RST_BA_MAC_MATCH,
+	RST_BA_NO_MATCH
+};
+
+struct wtbl_ba {
+	__le16 tag;
+	__le16 len;
+	/* common */
+	u8 tid;
+	u8 ba_type;
+	u8 rsv0[2];
+	/* originator only */
+	__le16 sn;
+	u8 ba_en;
+	u8 ba_winsize_idx;
+	__le16 ba_winsize;
+	/* recipient only */
+	u8 peer_addr[ETH_ALEN];
+	u8 rst_ba_tid;
+	u8 rst_ba_sel;
+	u8 rst_ba_sb;
+	u8 band_idx;
+	u8 rsv1[4];
+} __packed;
+
+struct wtbl_bf {
+	__le16 tag;
+	__le16 len;
+	u8 ibf;
+	u8 ebf;
+	u8 ibf_vht;
+	u8 ebf_vht;
+	u8 gid;
+	u8 pfmu_idx;
+	u8 rsv[2];
+} __packed;
+
+struct wtbl_smps {
+	__le16 tag;
+	__le16 len;
+	u8 smps;
+	u8 rsv[3];
+} __packed;
+
+struct wtbl_pn {
+	__le16 tag;
+	__le16 len;
+	u8 pn[6];
+	u8 rsv[2];
+} __packed;
+
+struct wtbl_spe {
+	__le16 tag;
+	__le16 len;
+	u8 spe_idx;
+	u8 rsv[3];
+} __packed;
+
+struct wtbl_raw {
+	__le16 tag;
+	__le16 len;
+	u8 wtbl_idx;
+	u8 dw;
+	u8 rsv[2];
+	__le32 msk;
+	__le32 val;
+} __packed;
+
+#define MT7615_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_generic) + \
+				     sizeof(struct wtbl_rx) + \
+				     sizeof(struct wtbl_ht) + \
+				     sizeof(struct wtbl_vht) + \
+				     sizeof(struct wtbl_tx_ps) + \
+				     sizeof(struct wtbl_hdr_trans) + \
+				     sizeof(struct wtbl_sec_key) + \
+				     sizeof(struct wtbl_ba) + \
+				     sizeof(struct wtbl_bf) + \
+				     sizeof(struct wtbl_smps) + \
+				     sizeof(struct wtbl_pn) + \
+				     sizeof(struct wtbl_spe))
+
+enum {
+	WTBL_GENERIC,
+	WTBL_RX,
+	WTBL_HT,
+	WTBL_VHT,
+	WTBL_PEER_PS, /* not used */
+	WTBL_TX_PS,
+	WTBL_HDR_TRANS,
+	WTBL_SEC_KEY,
+	WTBL_BA,
+	WTBL_RDG, /* obsoleted */
+	WTBL_PROTECT, /* not used */
+	WTBL_CLEAR, /* not used */
+	WTBL_BF,
+	WTBL_SMPS,
+	WTBL_RAW_DATA, /* debug only */
+	WTBL_PN,
+	WTBL_SPE,
+	WTBL_MAX_NUM
+};
+
+struct sta_rec_basic {
+	__le16 tag;
+	__le16 len;
+	__le32 conn_type;
+	u8 conn_state;
+	u8 qos;
+	__le16 aid;
+	u8 peer_addr[ETH_ALEN];
+#define EXTRA_INFO_VER	BIT(0)
+#define EXTRA_INFO_NEW	BIT(1)
+	__le16 extra_info;
+} __packed;
+
+struct sta_rec_ht {
+	__le16 tag;
+	__le16 len;
+	__le16 ht_cap;
+	u16 rsv;
+} __packed;
+
+struct sta_rec_vht {
+	__le16 tag;
+	__le16 len;
+	__le32 vht_cap;
+	__le16 vht_rx_mcs_map;
+	__le16 vht_tx_mcs_map;
+} __packed;
+
+struct sta_rec_ba {
+	__le16 tag;
+	__le16 len;
+	u8 tid;
+	u8 ba_type;
+	u8 amsdu;
+	u8 ba_en;
+	__le16 ssn;
+	__le16 winsize;
+} __packed;
+
+#define MT7615_STA_REC_UPDATE_MAX_SIZE (sizeof(struct sta_rec_basic) + \
+					sizeof(struct sta_rec_ht) + \
+					sizeof(struct sta_rec_vht))
+
+enum {
+	STA_REC_BASIC,
+	STA_REC_RA,
+	STA_REC_RA_CMM_INFO,
+	STA_REC_RA_UPDATE,
+	STA_REC_BF,
+	STA_REC_AMSDU, /* for CR4 */
+	STA_REC_BA,
+	STA_REC_RED, /* not used */
+	STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */
+	STA_REC_HT,
+	STA_REC_VHT,
+	STA_REC_APPS,
+	STA_REC_MAX_NUM
+};
+
+enum {
+	CMD_CBW_20MHZ,
+	CMD_CBW_40MHZ,
+	CMD_CBW_80MHZ,
+	CMD_CBW_160MHZ,
+	CMD_CBW_10MHZ,
+	CMD_CBW_5MHZ,
+	CMD_CBW_8080MHZ
+};
+
+enum {
+	CH_SWITCH_NORMAL = 0,
+	CH_SWITCH_SCAN = 3,
+	CH_SWITCH_MCC = 4,
+	CH_SWITCH_DFS = 5,
+	CH_SWITCH_BACKGROUND_SCAN_START = 6,
+	CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7,
+	CH_SWITCH_BACKGROUND_SCAN_STOP = 8,
+	CH_SWITCH_SCAN_BYPASS_DPD = 9
+};
+
+static inline struct sk_buff *
+mt7615_mcu_msg_alloc(const void *data, int len)
+{
+	return mt76_mcu_msg_alloc(data, sizeof(struct mt7615_mcu_txd),
+				  len, 0);
+}
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
new file mode 100644
index 0000000..895c290
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2019 MediaTek Inc. */
+
+#ifndef __MT7615_H
+#define __MT7615_H
+
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include "../mt76.h"
+#include "regs.h"
+
+#define MT7615_MAX_INTERFACES		4
+#define MT7615_WTBL_SIZE		128
+#define MT7615_WTBL_RESERVED		(MT7615_WTBL_SIZE - 1)
+#define MT7615_WTBL_STA			(MT7615_WTBL_RESERVED - \
+					 MT7615_MAX_INTERFACES)
+
+#define MT7615_WATCHDOG_TIME		100 /* ms */
+#define MT7615_RATE_RETRY		2
+
+#define MT7615_TX_RING_SIZE		1024
+#define MT7615_TX_MCU_RING_SIZE		128
+#define MT7615_TX_FWDL_RING_SIZE	128
+
+#define MT7615_RX_RING_SIZE		1024
+#define MT7615_RX_MCU_RING_SIZE		512
+
+#define MT7615_FIRMWARE_CR4		"mt7615_cr4.bin"
+#define MT7615_FIRMWARE_N9		"mt7615_n9.bin"
+#define MT7615_ROM_PATCH		"mt7615_rom_patch.bin"
+
+#define MT7615_EEPROM_SIZE		1024
+#define MT7615_TOKEN_SIZE		4096
+
+struct mt7615_vif;
+struct mt7615_sta;
+
+enum mt7615_hw_txq_id {
+	MT7615_TXQ_MAIN,
+	MT7615_TXQ_EXT,
+	MT7615_TXQ_MCU,
+	MT7615_TXQ_FWDL,
+};
+
+struct mt7615_sta {
+	struct mt76_wcid wcid; /* must be first */
+
+	struct mt7615_vif *vif;
+
+	struct ieee80211_tx_rate rates[8];
+	u8 rate_count;
+	u8 n_rates;
+
+	u8 rate_probe;
+};
+
+struct mt7615_vif {
+	u8 idx;
+	u8 omac_idx;
+	u8 band_idx;
+	u8 wmm_idx;
+
+	struct mt7615_sta sta;
+};
+
+struct mt7615_dev {
+	struct mt76_dev mt76; /* must be first */
+	u32 vif_mask;
+	u32 omac_mask;
+
+	spinlock_t token_lock;
+	struct idr token;
+};
+
+enum {
+	HW_BSSID_0 = 0x0,
+	HW_BSSID_1,
+	HW_BSSID_2,
+	HW_BSSID_3,
+	HW_BSSID_MAX,
+	EXT_BSSID_START = 0x10,
+	EXT_BSSID_1,
+	EXT_BSSID_2,
+	EXT_BSSID_3,
+	EXT_BSSID_4,
+	EXT_BSSID_5,
+	EXT_BSSID_6,
+	EXT_BSSID_7,
+	EXT_BSSID_8,
+	EXT_BSSID_9,
+	EXT_BSSID_10,
+	EXT_BSSID_11,
+	EXT_BSSID_12,
+	EXT_BSSID_13,
+	EXT_BSSID_14,
+	EXT_BSSID_15,
+	EXT_BSSID_END
+};
+
+extern const struct ieee80211_ops mt7615_ops;
+extern struct pci_driver mt7615_pci_driver;
+
+u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr);
+
+int mt7615_register_device(struct mt7615_dev *dev);
+void mt7615_unregister_device(struct mt7615_dev *dev);
+int mt7615_eeprom_init(struct mt7615_dev *dev);
+int mt7615_dma_init(struct mt7615_dev *dev);
+void mt7615_dma_cleanup(struct mt7615_dev *dev);
+int mt7615_mcu_init(struct mt7615_dev *dev);
+int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			    int en);
+int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			    int en);
+int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
+			    struct ieee80211_key_conf *key,
+			    enum set_key_cmd cmd);
+void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
+			  struct ieee80211_tx_rate *probe_rate,
+			  struct ieee80211_tx_rate *rates);
+int mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif);
+int mt7615_mcu_del_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif);
+int mt7615_mcu_add_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta);
+int mt7615_mcu_del_wtbl(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			struct ieee80211_sta *sta);
+int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev);
+int mt7615_mcu_set_sta_rec_bmc(struct mt7615_dev *dev,
+			       struct ieee80211_vif *vif, bool en);
+int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			   struct ieee80211_sta *sta, bool en);
+int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+		       int en);
+int mt7615_mcu_set_channel(struct mt7615_dev *dev);
+int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
+		       const struct ieee80211_tx_queue_params *params);
+int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev,
+			 struct ieee80211_ampdu_params *params,
+			 bool add);
+int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
+			 struct ieee80211_ampdu_params *params,
+			 bool add);
+int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+			  struct ieee80211_sta *sta);
+
+static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask)
+{
+	mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
+}
+
+static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
+{
+	mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
+}
+
+u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
+			   const struct ieee80211_tx_rate *rate,
+			   bool stbc, u8 *bw);
+int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
+			  struct sk_buff *skb, struct mt76_wcid *wcid,
+			  struct ieee80211_sta *sta, int pid,
+			  struct ieee80211_key_conf *key);
+int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb);
+void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data);
+void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb);
+
+int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
+int mt7615_mcu_init_mac(struct mt7615_dev *dev);
+int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val);
+int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter);
+void mt7615_mcu_exit(struct mt7615_dev *dev);
+
+int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
+			  struct ieee80211_sta *sta,
+			  struct mt76_tx_info *tx_info);
+
+void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
+			    struct mt76_queue_entry *e);
+
+void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+			 struct sk_buff *skb);
+void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q);
+void mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
+int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		   struct ieee80211_sta *sta);
+void mt7615_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		      struct ieee80211_sta *sta);
+void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+		       struct ieee80211_sta *sta);
+void mt7615_mac_work(struct work_struct *work);
+void mt7615_txp_skb_unmap(struct mt76_dev *dev,
+			  struct mt76_txwi_cache *txwi);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
new file mode 100644
index 0000000..11122bd
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2019 MediaTek Inc.
+ *
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *         Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "mt7615.h"
+#include "mac.h"
+
+static const struct pci_device_id mt7615_pci_device_table[] = {
+	{ PCI_DEVICE(0x14c3, 0x7615) },
+	{ },
+};
+
+u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr)
+{
+	u32 base = addr & MT_MCU_PCIE_REMAP_2_BASE;
+	u32 offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET;
+
+	mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base);
+
+	return MT_PCIE_REMAP_BASE_2 + offset;
+}
+
+void mt7615_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
+{
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+
+	mt7615_irq_enable(dev, MT_INT_RX_DONE(q));
+}
+
+irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
+{
+	struct mt7615_dev *dev = dev_instance;
+	u32 intr;
+
+	intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+	mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+
+	if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state))
+		return IRQ_NONE;
+
+	intr &= dev->mt76.mmio.irqmask;
+
+	if (intr & MT_INT_TX_DONE_ALL) {
+		mt7615_irq_disable(dev, MT_INT_TX_DONE_ALL);
+		tasklet_schedule(&dev->mt76.tx_tasklet);
+	}
+
+	if (intr & MT_INT_RX_DONE(0)) {
+		mt7615_irq_disable(dev, MT_INT_RX_DONE(0));
+		napi_schedule(&dev->mt76.napi[0]);
+	}
+
+	if (intr & MT_INT_RX_DONE(1)) {
+		mt7615_irq_disable(dev, MT_INT_RX_DONE(1));
+		napi_schedule(&dev->mt76.napi[1]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mt7615_pci_probe(struct pci_dev *pdev,
+			    const struct pci_device_id *id)
+{
+	static const struct mt76_driver_ops drv_ops = {
+		/* txwi_size = txd size + txp size */
+		.txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp),
+		.txwi_flags = MT_TXWI_NO_FREE,
+		.tx_prepare_skb = mt7615_tx_prepare_skb,
+		.tx_complete_skb = mt7615_tx_complete_skb,
+		.rx_skb = mt7615_queue_rx_skb,
+		.rx_poll_complete = mt7615_rx_poll_complete,
+		.sta_ps = mt7615_sta_ps,
+		.sta_add = mt7615_sta_add,
+		.sta_assoc = mt7615_sta_assoc,
+		.sta_remove = mt7615_sta_remove,
+	};
+	struct mt7615_dev *dev;
+	struct mt76_dev *mdev;
+	int ret;
+
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
+	if (ret)
+		return ret;
+
+	pci_set_master(pdev);
+
+	ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7615_ops,
+				 &drv_ops);
+	if (!mdev)
+		return -ENOMEM;
+
+	dev = container_of(mdev, struct mt7615_dev, mt76);
+	mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
+
+	mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
+		    (mt76_rr(dev, MT_HW_REV) & 0xff);
+	dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+
+	ret = devm_request_irq(mdev->dev, pdev->irq, mt7615_irq_handler,
+			       IRQF_SHARED, KBUILD_MODNAME, dev);
+	if (ret)
+		goto error;
+
+	ret = mt7615_register_device(dev);
+	if (ret)
+		goto error;
+
+	return 0;
+error:
+	ieee80211_free_hw(mt76_hw(dev));
+	return ret;
+}
+
+static void mt7615_pci_remove(struct pci_dev *pdev)
+{
+	struct mt76_dev *mdev = pci_get_drvdata(pdev);
+	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+
+	mt7615_unregister_device(dev);
+}
+
+struct pci_driver mt7615_pci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= mt7615_pci_device_table,
+	.probe		= mt7615_pci_probe,
+	.remove		= mt7615_pci_remove,
+};
+
+module_pci_driver(mt7615_pci_driver);
+
+MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table);
+MODULE_FIRMWARE(MT7615_FIRMWARE_CR4);
+MODULE_FIRMWARE(MT7615_FIRMWARE_N9);
+MODULE_FIRMWARE(MT7615_ROM_PATCH);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
new file mode 100644
index 0000000..70e5ace
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: ISC */
+/* Copyright (C) 2019 MediaTek Inc. */
+
+#ifndef __MT7615_REGS_H
+#define __MT7615_REGS_H
+
+#define MT_HW_REV			0x1000
+#define MT_HW_CHIPID			0x1008
+#define MT_TOP_MISC2			0x1134
+#define MT_TOP_MISC2_FW_STATE		GENMASK(2, 0)
+
+#define MT_MCU_BASE			0x2000
+#define MT_MCU(ofs)			(MT_MCU_BASE + (ofs))
+
+#define MT_MCU_PCIE_REMAP_1		MT_MCU(0x500)
+#define MT_MCU_PCIE_REMAP_1_OFFSET	GENMASK(17, 0)
+#define MT_MCU_PCIE_REMAP_1_BASE	GENMASK(31, 18)
+#define MT_PCIE_REMAP_BASE_1		0x40000
+
+#define MT_MCU_PCIE_REMAP_2		MT_MCU(0x504)
+#define MT_MCU_PCIE_REMAP_2_OFFSET	GENMASK(18, 0)
+#define MT_MCU_PCIE_REMAP_2_BASE	GENMASK(31, 19)
+#define MT_PCIE_REMAP_BASE_2		0x80000
+
+#define MT_HIF_BASE			0x4000
+#define MT_HIF(ofs)			(MT_HIF_BASE + (ofs))
+
+#define MT_CFG_LPCR_HOST		MT_HIF(0x1f0)
+#define MT_CFG_LPCR_HOST_FW_OWN		BIT(0)
+#define MT_CFG_LPCR_HOST_DRV_OWN	BIT(1)
+
+#define MT_INT_SOURCE_CSR		MT_HIF(0x200)
+#define MT_INT_MASK_CSR			MT_HIF(0x204)
+#define MT_DELAY_INT_CFG		MT_HIF(0x210)
+
+#define MT_INT_RX_DONE(_n)		BIT(_n)
+#define MT_INT_RX_DONE_ALL		GENMASK(1, 0)
+#define MT_INT_TX_DONE_ALL		GENMASK(7, 4)
+#define MT_INT_TX_DONE(_n)		BIT((_n) + 4)
+
+#define MT_WPDMA_GLO_CFG		MT_HIF(0x208)
+#define MT_WPDMA_GLO_CFG_TX_DMA_EN	BIT(0)
+#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY	BIT(1)
+#define MT_WPDMA_GLO_CFG_RX_DMA_EN	BIT(2)
+#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY	BIT(3)
+#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE	GENMASK(5, 4)
+#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE	BIT(6)
+#define MT_WPDMA_GLO_CFG_BIG_ENDIAN	BIT(7)
+#define MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT0	BIT(9)
+#define MT_WPDMA_GLO_CFG_MULTI_DMA_EN	GENMASK(11, 10)
+#define MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN	BIT(12)
+#define MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT21	GENMASK(23, 22)
+#define MT_WPDMA_GLO_CFG_SW_RESET	BIT(24)
+#define MT_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY	BIT(26)
+#define MT_WPDMA_GLO_CFG_OMIT_TX_INFO	BIT(28)
+
+#define MT_WPDMA_RST_IDX		MT_HIF(0x20c)
+
+#define MT_TX_RING_BASE			MT_HIF(0x300)
+#define MT_RX_RING_BASE			MT_HIF(0x400)
+
+#define MT_WPDMA_GLO_CFG1		MT_HIF(0x500)
+#define MT_WPDMA_TX_PRE_CFG		MT_HIF(0x510)
+#define MT_WPDMA_RX_PRE_CFG		MT_HIF(0x520)
+#define MT_WPDMA_ABT_CFG		MT_HIF(0x530)
+#define MT_WPDMA_ABT_CFG1		MT_HIF(0x534)
+
+#define MT_WF_PHY_BASE			0x10000
+#define MT_WF_PHY(ofs)			(MT_WF_PHY_BASE + (ofs))
+
+#define MT_WF_PHY_WF2_RFCTRL0		MT_WF_PHY(0x1900)
+#define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN	BIT(9)
+
+#define MT_WF_CFG_BASE			0x20200
+#define MT_WF_CFG(ofs)			(MT_WF_CFG_BASE + (ofs))
+
+#define MT_CFG_CCR			MT_WF_CFG(0x000)
+#define MT_CFG_CCR_MAC_D1_1X_GC_EN	BIT(24)
+#define MT_CFG_CCR_MAC_D0_1X_GC_EN	BIT(25)
+#define MT_CFG_CCR_MAC_D1_2X_GC_EN	BIT(30)
+#define MT_CFG_CCR_MAC_D0_2X_GC_EN	BIT(31)
+
+#define MT_WF_AGG_BASE			0x20a00
+#define MT_WF_AGG(ofs)			(MT_WF_AGG_BASE + (ofs))
+
+#define MT_AGG_ARCR			MT_WF_AGG(0x010)
+#define MT_AGG_ARCR_INIT_RATE1		BIT(0)
+#define MT_AGG_ARCR_RTS_RATE_THR	GENMASK(12, 8)
+#define MT_AGG_ARCR_RATE_DOWN_RATIO	GENMASK(17, 16)
+#define MT_AGG_ARCR_RATE_DOWN_RATIO_EN	BIT(19)
+#define MT_AGG_ARCR_RATE_UP_EXTRA_TH	GENMASK(22, 20)
+
+#define MT_AGG_ARUCR			MT_WF_AGG(0x018)
+#define MT_AGG_ARDCR			MT_WF_AGG(0x01c)
+#define MT_AGG_ARxCR_LIMIT_SHIFT(_n)	(4 * (_n))
+#define MT_AGG_ARxCR_LIMIT(_n)		GENMASK(2 + \
+					MT_AGG_ARxCR_LIMIT_SHIFT(_n), \
+					MT_AGG_ARxCR_LIMIT_SHIFT(_n))
+
+#define MT_AGG_SCR			MT_WF_AGG(0x0fc)
+#define MT_AGG_SCR_NLNAV_MID_PTEC_DIS	BIT(3)
+
+#define MT_WF_TMAC_BASE			0x21000
+#define MT_WF_TMAC(ofs)			(MT_WF_TMAC_BASE + (ofs))
+
+#define MT_TMAC_CTCR0			MT_WF_TMAC(0x0f4)
+#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME	GENMASK(5, 0)
+#define MT_TMAC_CTCR0_INS_DDLMT_DENSITY	GENMASK(15, 12)
+#define MT_TMAC_CTCR0_INS_DDLMT_EN	BIT(17)
+#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN	BIT(18)
+
+#define MT_WF_RMAC_BASE			0x21200
+#define MT_WF_RMAC(ofs)			(MT_WF_RMAC_BASE + (ofs))
+
+#define MT_WF_RFCR			MT_WF_RMAC(0x000)
+#define MT_WF_RFCR_DROP_STBC_MULTI	BIT(0)
+#define MT_WF_RFCR_DROP_FCSFAIL		BIT(1)
+#define MT_WF_RFCR_DROP_VERSION		BIT(3)
+#define MT_WF_RFCR_DROP_PROBEREQ	BIT(4)
+#define MT_WF_RFCR_DROP_MCAST		BIT(5)
+#define MT_WF_RFCR_DROP_BCAST		BIT(6)
+#define MT_WF_RFCR_DROP_MCAST_FILTERED	BIT(7)
+#define MT_WF_RFCR_DROP_A3_MAC		BIT(8)
+#define MT_WF_RFCR_DROP_A3_BSSID	BIT(9)
+#define MT_WF_RFCR_DROP_A2_BSSID	BIT(10)
+#define MT_WF_RFCR_DROP_OTHER_BEACON	BIT(11)
+#define MT_WF_RFCR_DROP_FRAME_REPORT	BIT(12)
+#define MT_WF_RFCR_DROP_CTL_RSV		BIT(13)
+#define MT_WF_RFCR_DROP_CTS		BIT(14)
+#define MT_WF_RFCR_DROP_RTS		BIT(15)
+#define MT_WF_RFCR_DROP_DUPLICATE	BIT(16)
+#define MT_WF_RFCR_DROP_OTHER_BSS	BIT(17)
+#define MT_WF_RFCR_DROP_OTHER_UC	BIT(18)
+#define MT_WF_RFCR_DROP_OTHER_TIM	BIT(19)
+#define MT_WF_RFCR_DROP_NDPA		BIT(20)
+#define MT_WF_RFCR_DROP_UNWANTED_CTL	BIT(21)
+
+#define MT_WF_DMA_BASE			0x21800
+#define MT_WF_DMA(ofs)			(MT_WF_DMA_BASE + (ofs))
+
+#define MT_DMA_DCR0			MT_WF_DMA(0x000)
+#define MT_DMA_DCR0_MAX_RX_LEN		GENMASK(15, 2)
+#define MT_DMA_DCR0_RX_VEC_DROP		BIT(17)
+
+#define MT_WTBL_BASE			0x30000
+#define MT_WTBL_ENTRY_SIZE		256
+
+#define MT_WTBL_OFF_BASE		0x23400
+#define MT_WTBL_OFF(n)			(MT_WTBL_OFF_BASE + (n))
+
+#define MT_WTBL_UPDATE			MT_WTBL_OFF(0x030)
+#define MT_WTBL_UPDATE_WLAN_IDX		GENMASK(7, 0)
+#define MT_WTBL_UPDATE_RATE_UPDATE	BIT(13)
+#define MT_WTBL_UPDATE_TX_COUNT_CLEAR	BIT(14)
+#define MT_WTBL_UPDATE_BUSY		BIT(31)
+
+#define MT_WTBL_ON_BASE			0x23000
+#define MT_WTBL_ON(_n)			(MT_WTBL_ON_BASE + (_n))
+
+#define MT_WTBL_RIUCR0			MT_WTBL_ON(0x020)
+
+#define MT_WTBL_RIUCR1			MT_WTBL_ON(0x024)
+#define MT_WTBL_RIUCR1_RATE0		GENMASK(11, 0)
+#define MT_WTBL_RIUCR1_RATE1		GENMASK(23, 12)
+#define MT_WTBL_RIUCR1_RATE2_LO		GENMASK(31, 24)
+
+#define MT_WTBL_RIUCR2			MT_WTBL_ON(0x028)
+#define MT_WTBL_RIUCR2_RATE2_HI		GENMASK(3, 0)
+#define MT_WTBL_RIUCR2_RATE3		GENMASK(15, 4)
+#define MT_WTBL_RIUCR2_RATE4		GENMASK(27, 16)
+#define MT_WTBL_RIUCR2_RATE5_LO		GENMASK(31, 28)
+
+#define MT_WTBL_RIUCR3			MT_WTBL_ON(0x02c)
+#define MT_WTBL_RIUCR3_RATE5_HI		GENMASK(7, 0)
+#define MT_WTBL_RIUCR3_RATE6		GENMASK(19, 8)
+#define MT_WTBL_RIUCR3_RATE7		GENMASK(31, 20)
+
+#define MT_WTBL_W5_CHANGE_BW_RATE	GENMASK(7, 5)
+#define MT_WTBL_W5_SHORT_GI_20		BIT(8)
+#define MT_WTBL_W5_SHORT_GI_40		BIT(9)
+#define MT_WTBL_W5_SHORT_GI_80		BIT(10)
+#define MT_WTBL_W5_SHORT_GI_160		BIT(11)
+#define MT_WTBL_W5_BW_CAP		GENMASK(13, 12)
+#define MT_WTBL_W27_CC_BW_SEL		GENMASK(6, 5)
+
+#define MT_EFUSE_BASE			0x81070000
+#define MT_EFUSE_BASE_CTRL		0x000
+#define MT_EFUSE_BASE_CTRL_EMPTY	BIT(30)
+
+#define MT_EFUSE_CTRL			0x008
+#define MT_EFUSE_CTRL_AOUT		GENMASK(5, 0)
+#define MT_EFUSE_CTRL_MODE		GENMASK(7, 6)
+#define MT_EFUSE_CTRL_LDO_OFF_TIME	GENMASK(13, 8)
+#define MT_EFUSE_CTRL_LDO_ON_TIME	GENMASK(15, 14)
+#define MT_EFUSE_CTRL_AIN		GENMASK(25, 16)
+#define MT_EFUSE_CTRL_VALID		BIT(29)
+#define MT_EFUSE_CTRL_KICK		BIT(30)
+#define MT_EFUSE_CTRL_SEL		BIT(31)
+
+#define MT_EFUSE_WDATA(_i)		(0x010 + ((_i) * 4))
+#define MT_EFUSE_RDATA(_i)		(0x030 + ((_i) * 4))
+
+#endif
-- 
1.9.1


^ permalink raw reply related

* [PATCH v2 0/4] Add support for MediaTek MT7615 wireless chipsets
From: Ryder Lee @ 2019-04-01  6:56 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="y", Size: 3494 bytes --]

This adds support for MediaTek MT7615E 4x4 802.11ac PCIe-based chipsets.

In the legacy tx arch, we move and store the whole skb content to the
on-device memory when we send packets via high speed interface. (e.g. PCIe)

However, MT7615 and the following generation use a new tx arch called
“cut-through”, which only passes the physical address to the hardware,
and the packet engine will fetch the packets before transmission.

It saves on-chip memory for high throughput devices, and the token mechanism
is used to manage the release of skb under this arch.

And there might be other (existing or future) chips that use the same driver
(e.g. mt7622/mt7663...), this is a starting point to unify MTK wireless chipsets.

Detailed hardware information for this chip could be found on 
https://wikidevi.com/wiki/MediaTek_MT7615

Ryder Lee (4):
  mt76: add mac80211 driver for MT7615 PCIe-based chipsets
  mt76: add unlikely() for dma_mapping_error() check
  mt76: use macro for sn and seq_ctrl conversion
  MAINTAINERS : update entry for mt76 wireless driver

 MAINTAINERS                                        |    2 +
 drivers/net/wireless/mediatek/mt76/Kconfig         |    1 +
 drivers/net/wireless/mediatek/mt76/Makefile        |    1 +
 drivers/net/wireless/mediatek/mt76/agg-rx.c        |    2 +-
 drivers/net/wireless/mediatek/mt76/dma.c           |    8 +-
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c    |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/main.c   |    2 +-
 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig  |    7 +
 drivers/net/wireless/mediatek/mt76/mt7615/Makefile |    5 +
 drivers/net/wireless/mediatek/mt76/mt7615/dma.c    |  205 +++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c |   98 ++
 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h |   18 +
 drivers/net/wireless/mediatek/mt76/mt7615/init.c   |  229 +++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.c    |  774 +++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mac.h    |  300 ++++
 drivers/net/wireless/mediatek/mt76/mt7615/main.c   |  499 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c    | 1656 ++++++++++++++++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h    |  520 ++++++
 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h |  195 +++
 drivers/net/wireless/mediatek/mt76/mt7615/pci.c    |  150 ++
 drivers/net/wireless/mediatek/mt76/mt7615/regs.h   |  203 +++
 drivers/net/wireless/mediatek/mt76/mt76x02_util.c  |    2 +-
 22 files changed, 4871 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/Makefile
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/dma.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/init.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mac.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/main.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/pci.c
 create mode 100644 drivers/net/wireless/mediatek/mt76/mt7615/regs.h

-- 
1.9.1


^ permalink raw reply

* [PATCH v2 3/4] mt76: use macro for sn and seq_ctrl conversion
From: Ryder Lee @ 2019-04-01  6:56 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554100584.git.ryder.lee@mediatek.com>

Use macro to convert sn and seq_ctrl for better readability.

Signed-off-by: Roy Luo <royluo@google.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/agg-rx.c       | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/mac.c   | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7603/main.c  | 2 +-
 drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c
index 73c8b28..27e3ff0 100644
--- a/drivers/net/wireless/mediatek/mt76/agg-rx.c
+++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c
@@ -135,7 +135,7 @@
 		return;
 
 	status->tid = le16_to_cpu(bar->control) >> 12;
-	seqno = le16_to_cpu(bar->start_seq_num) >> 4;
+	seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
 	tid = rcu_dereference(wcid->aggr[status->tid]);
 	if (!tid)
 		return;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index e498169..2f2961e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -627,7 +627,7 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ssn,
 	status->aggr = unicast &&
 		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
 	status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
-	status->seqno = hdr->seq_ctrl >> 4;
+	status->seqno = IEEE80211_SEQ_TO_SN(hdr->seq_ctrl);
 
 	return 0;
 }
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 5d38392..0c78044 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -594,7 +594,7 @@
 		mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, *ssn, -1);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		mtxq->agg_ssn = *ssn << 4;
+		mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index b137ce8..f0e1e12 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -378,7 +378,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
 		break;
 	case IEEE80211_AMPDU_TX_START:
-		mtxq->agg_ssn = *ssn << 4;
+		mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 		break;
 	case IEEE80211_AMPDU_TX_STOP_CONT:
-- 
1.9.1


^ permalink raw reply related

* [PATCH v2 4/4] MAINTAINERS : update entry for mt76 wireless driver
From: Ryder Lee @ 2019-04-01  6:56 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554100584.git.ryder.lee@mediatek.com>

Roy and I actively join the development and review.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e17ebf7..7d92a87 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9768,6 +9768,8 @@ F:	Documentation/devicetree/bindings/media/mediatek-vpu.txt
 MEDIATEK MT76 WIRELESS LAN DRIVER
 M:	Felix Fietkau <nbd@nbd.name>
 M:	Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+R:	Ryder Lee <ryder.lee@mediatek.com>
+R:	Roy Luo <royluo@google.com>
 L:	linux-wireless@vger.kernel.org
 S:	Maintained
 F:	drivers/net/wireless/mediatek/mt76/
-- 
1.9.1


^ permalink raw reply related

* [PATCH v2 2/4] mt76: add unlikely() for dma_mapping_error() check
From: Ryder Lee @ 2019-04-01  6:56 UTC (permalink / raw)
  To: Lorenzo Bianconi, Felix Fietkau
  Cc: Roy Luo, Sean Wang, Nelson Chang, YF Luo, Kai Lin, Rorscha Yang,
	Kyle Lee, Miller Shen, Haipin Liang, KL Huang, YH chen,
	linux-wireless, linux-mediatek, linux-kernel, Ryder Lee
In-Reply-To: <cover.1554100584.git.ryder.lee@mediatek.com>

In the tx/rx fastpath, the funciton dma_map_single() rarely fails.
This adds unlikely() optimization to this error check conditional.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/dma.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 8a4b935..6f3ef09 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -272,7 +272,7 @@
 
 	addr = dma_map_single(dev->dev, skb->data, skb->len,
 			      DMA_TO_DEVICE);
-	if (dma_mapping_error(dev->dev, addr))
+	if (unlikely(dma_mapping_error(dev->dev, addr)))
 		return -ENOMEM;
 
 	buf.addr = addr;
@@ -315,7 +315,7 @@
 
 	len = skb_headlen(skb);
 	addr = dma_map_single(dev->dev, skb->data, len, DMA_TO_DEVICE);
-	if (dma_mapping_error(dev->dev, addr))
+	if (unlikely(dma_mapping_error(dev->dev, addr)))
 		goto free;
 
 	tx_info.buf[n].addr = t->dma_addr;
@@ -329,7 +329,7 @@
 
 		addr = dma_map_single(dev->dev, iter->data, iter->len,
 				      DMA_TO_DEVICE);
-		if (dma_mapping_error(dev->dev, addr))
+		if (unlikely(dma_mapping_error(dev->dev, addr)))
 			goto unmap;
 
 		tx_info.buf[n].addr = addr;
@@ -386,7 +386,7 @@
 			break;
 
 		addr = dma_map_single(dev->dev, buf, len, DMA_FROM_DEVICE);
-		if (dma_mapping_error(dev->dev, addr)) {
+		if (unlikely(dma_mapping_error(dev->dev, addr))) {
 			skb_free_frag(buf);
 			break;
 		}
-- 
1.9.1


^ permalink raw reply related

* RE: [PATCH] ath10k: Remove ATH10K_STATE_RESTARTED in simulate fw crash
From: Wen Gong @ 2019-04-01  6:11 UTC (permalink / raw)
  To: Michał Kazior; +Cc: Wen Gong, linux-wireless, ath10k@lists.infradead.org
In-Reply-To: <CABvG-CWAfB8jjCDW4ggjJ8_YC++CjttJOMOt4s24F3mymvNR9A@mail.gmail.com>

> -----Original Message-----
> From: Michał Kazior <kazikcz@gmail.com>
> Sent: Monday, January 7, 2019 4:36 PM
> To: Wen Gong <wgong@qti.qualcomm.com>
> Cc: Wen Gong <wgong@codeaurora.org>; linux-wireless <linux-
> wireless@vger.kernel.org>; ath10k@lists.infradead.org
> Subject: [EXT] Re: [PATCH] ath10k: Remove ATH10K_STATE_RESTARTED in
> simulate fw crash
> That's actually a feature, not a bug. If firmware crashes while driver
> is restarting after a crash then its likely going to fail again and
> again causing a crash-restart loop which can affect system performance
> and responsiveness. It's better to give up and let the system admin
> take over.
> 
> If it's still bothering you then please consider a crash counter
> threshold so that, e.g. after 5 crash-while-restarting it's going to
> give up. However I doubt it's worth the effort. My experience tells me
> firmware crashes during recovery are rarely, if at all, transient.
> 
> The simulated fw crash is not representative here. It's a mere tool to
> test driver code.
> 
Hi Michal,
There have a stress test case for the simulate fw crash, it will simulate fw crash
in a very short time for each test, this will trigger the stress test fail.
The simulate fw crash process should not be run parallel, after this patch, the
Stress test case will pass.
> 
> Michał

^ permalink raw reply

* Re: wil6210 new features support
From: Sebastian Gottschall @ 2019-03-31 12:23 UTC (permalink / raw)
  To: meneghello, linux-wireless
In-Reply-To: <20190329142607.Horde.d3GknYZ2mQFG07_UafOtL62@mail.dei.unipd.it>

radar detection on a 60 ghz card?  there is no requirement for it. radar 
is not operating at that frequencies

Am 29.03.2019 um 14:26 schrieb meneghello@dei.unipd.it:
>
> Good morning,
>
> we are working on OpenWrt support for wil6210 driver.
> We are interest in support for new features like radar.
> Is there any chance that this feature will be implemented in the next 
> version of the firmware?
> In case it is, can you share with us a beta version to do some testing?
>
> Thank you.
>
> Francesca Meneghello & Jacopo Pegoraro
>
>

^ permalink raw reply

* Re: [PATCH 1/4] mt76: add mac80211 driver for MT7615 PCIe-based chipsets
From: Ryder Lee @ 2019-03-31  8:52 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Sean Wang, Miller Shen, Nelson Chang, YF Luo, linux-wireless,
	linux-kernel, Haipin Liang, linux-mediatek, Roy Luo, Kyle Lee,
	Rorscha Yang, Lorenzo Bianconi, Kai Lin, Lorenzo Bianconi,
	Felix Fietkau
In-Reply-To: <87lg0wyjvj.fsf@purkki.adurom.net>

On Sat, 2019-03-30 at 08:08 +0200, Kalle Valo wrote:
> Ryder Lee <ryder.lee@mediatek.com> writes:
> 
> > This driver is for a newer generation of MediaTek MT7615 4x4 802.11ac
> > PCIe-based chipsets, which support wave2 MU-MIMO up to 4 users/group
> > and also support up to 160MHz bandwidth.
> >
> > The driver fully supports AP, station and monitor mode.
> >
> > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> > Signed-off-by: Roy Luo <royluo@google.com>
> > Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> 
> [...]
> 
> > --- /dev/null
> > +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
> > @@ -0,0 +1,204 @@
> > +// SPDX-License-Identifier: GPL-2.0
> 
> mt76 is under ISC so why did you choose GPLv2 here? I don't think it's a
> good idea to use different licenses within the same driver.
> 
> Also mt76 does not use SPDX tags yet. I would prefer that the whole
> driver is converted in one go to have consistent licensing information.
> 

OK. I will modify it.


^ permalink raw reply

* Re: [PATCH v4 2/3] mac80211: store tx power value from user to station
From: kbuild test robot @ 2019-03-31  7:22 UTC (permalink / raw)
  To: Balaji Pothunoori
  Cc: kbuild-all, johannes, ath10k, linux-wireless, Ashok Raj Nagarajan,
	Balaji Pothunoori
In-Reply-To: <1553856549-21552-1-git-send-email-bpothuno@codeaurora.org>

[-- Attachment #1: Type: text/plain, Size: 98640 bytes --]

Hi Balaji,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mac80211-next/master]
[also build test WARNING on v5.1-rc2 next-20190329]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Balaji-Pothunoori/cfg80211-Add-support-to-set-tx-power-for-a-station-associated/20190331-104601
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   WARNING: convert(1) not found, for SVG to PDF conversion install ImageMagick (https://www.imagemagick.org)
   include/linux/rcupdate_wait.h:1: warning: no structured comments found
   include/linux/rcutree.h:1: warning: no structured comments found
   kernel/rcu/tree.c:710: warning: Excess function parameter 'irq' description in 'rcu_nmi_exit'
   include/linux/gfp.h:1: warning: no structured comments found
   include/net/cfg80211.h:1072: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
>> include/net/mac80211.h:4029: warning: Function parameter or member 'sta_set_txpwr' not described in 'ieee80211_ops'
>> include/net/mac80211.h:2000: warning: Function parameter or member 'txpwr' not described in 'ieee80211_sta'
   kernel/rcu/tree.c:711: warning: Excess function parameter 'irq' description in 'rcu_nmi_exit'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.active' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.active' not described in 'dma_buf'
   include/linux/dma-fence-array.h:54: warning: Function parameter or member 'work' not described in 'dma_fence_array'
   include/linux/firmware/intel/stratix10-svc-client.h:1: warning: no structured comments found
   include/linux/gpio/driver.h:371: warning: Function parameter or member 'init_valid_mask' not described in 'gpio_chip'
   include/linux/iio/hw-consumer.h:1: warning: no structured comments found
   include/linux/input/sparse-keymap.h:46: warning: Function parameter or member 'sw' not described in 'key_entry'
   include/linux/regulator/machine.h:199: warning: Function parameter or member 'max_uV_step' not described in 'regulation_constraints'
   include/linux/regulator/driver.h:228: warning: Function parameter or member 'resume' not described in 'regulator_ops'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw0' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw1' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw2' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw3' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.eadm' not described in 'irb'
   drivers/slimbus/stream.c:1: warning: no structured comments found
   include/linux/spi/spi.h:180: warning: Function parameter or member 'driver_override' not described in 'spi_device'
   drivers/target/target_core_device.c:1: warning: no structured comments found
   drivers/usb/typec/bus.c:1: warning: no structured comments found
   drivers/usb/typec/class.c:1: warning: no structured comments found
   include/linux/w1.h:281: warning: Function parameter or member 'of_match_table' not described in 'w1_family'
   fs/direct-io.c:257: warning: Excess function parameter 'offset' description in 'dio_complete'
   fs/file_table.c:1: warning: no structured comments found
   fs/libfs.c:477: warning: Excess function parameter 'available' description in 'simple_write_end'
   fs/posix_acl.c:646: warning: Function parameter or member 'inode' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'mode_p' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'acl' not described in 'posix_acl_update_mode'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:183: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Function parameter or member 'range' not described in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Function parameter or member 'range' not described in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:382: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:383: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'end' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:847: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:3095: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:128: warning: Incorrect use of kernel-doc format: Documentation Makefile include scripts source @atomic_obj
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'atomic_obj_lock' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: no structured comments found
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_pin' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_unpin' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_res_obj' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_get_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_import_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_vmap' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_vunmap' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_mmap' not described in 'drm_driver'
   include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
   drivers/gpu/drm/drm_dp_helper.c:1364: warning: Function parameter or member 'dsc_dpcd' not described in 'drm_dp_dsc_sink_max_slice_count'
   drivers/gpu/drm/drm_dp_helper.c:1364: warning: Function parameter or member 'is_edp' not described in 'drm_dp_dsc_sink_max_slice_count'
   drivers/gpu/drm/i915/i915_vma.h:49: warning: cannot understand function prototype: 'struct i915_vma '
   drivers/gpu/drm/i915/i915_vma.h:1: warning: no structured comments found
   drivers/gpu/drm/i915/intel_guc_fwif.h:536: warning: cannot understand function prototype: 'struct guc_log_buffer_state '
   drivers/gpu/drm/i915/i915_trace.h:1: warning: no structured comments found
   include/linux/skbuff.h:876: warning: Function parameter or member 'dev_scratch' not described in 'sk_buff'
   include/linux/skbuff.h:876: warning: Function parameter or member 'list' not described in 'sk_buff'

vim +4029 include/net/mac80211.h

cf2c92d840 Eliad Peller           2014-11-04  3188  
cf2c92d840 Eliad Peller           2014-11-04  3189  /**
75a5f0ccfd Johannes Berg          2007-09-18  3190   * struct ieee80211_ops - callbacks from mac80211 to the driver
75a5f0ccfd Johannes Berg          2007-09-18  3191   *
75a5f0ccfd Johannes Berg          2007-09-18  3192   * This structure contains various callbacks that the driver may
75a5f0ccfd Johannes Berg          2007-09-18  3193   * handle or, in some cases, must handle, for example to configure
75a5f0ccfd Johannes Berg          2007-09-18  3194   * the hardware to a new channel or to transmit a frame.
75a5f0ccfd Johannes Berg          2007-09-18  3195   *
75a5f0ccfd Johannes Berg          2007-09-18  3196   * @tx: Handler that 802.11 module calls for each transmitted frame.
f0706e828e Jiri Benc              2007-05-05  3197   *	skb contains the buffer starting from the IEEE 802.11 header.
f0706e828e Jiri Benc              2007-05-05  3198   *	The low-level driver should send the frame out based on
eefce91a38 Johannes Berg          2008-05-17  3199   *	configuration in the TX control data. This handler should,
11127e9121 Johannes Berg          2011-11-16  3200   *	preferably, never fail and stop queues appropriately.
11127e9121 Johannes Berg          2011-11-16  3201   *	Must be atomic.
75a5f0ccfd Johannes Berg          2007-09-18  3202   *
75a5f0ccfd Johannes Berg          2007-09-18  3203   * @start: Called before the first netdevice attached to the hardware
4150c57212 Johannes Berg          2007-09-17  3204   *	is enabled. This should turn on the hardware and must turn on
4150c57212 Johannes Berg          2007-09-17  3205   *	frame reception (for possibly enabled monitor interfaces.)
4150c57212 Johannes Berg          2007-09-17  3206   *	Returns negative error codes, these may be seen in userspace,
4150c57212 Johannes Berg          2007-09-17  3207   *	or zero.
4150c57212 Johannes Berg          2007-09-17  3208   *	When the device is started it should not have a MAC address
4150c57212 Johannes Berg          2007-09-17  3209   *	to avoid acknowledging frames before a non-monitor device
4150c57212 Johannes Berg          2007-09-17  3210   *	is added.
e1781ed33a Kalle Valo             2009-12-23  3211   *	Must be implemented and can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3212   *
75a5f0ccfd Johannes Berg          2007-09-18  3213   * @stop: Called after last netdevice attached to the hardware
4150c57212 Johannes Berg          2007-09-17  3214   *	is disabled. This should turn off the hardware (at least
4150c57212 Johannes Berg          2007-09-17  3215   *	it must turn off frame reception.)
4150c57212 Johannes Berg          2007-09-17  3216   *	May be called right after add_interface if that rejects
42935ecaf4 Luis R. Rodriguez      2009-07-29  3217   *	an interface. If you added any work onto the mac80211 workqueue
42935ecaf4 Luis R. Rodriguez      2009-07-29  3218   *	you should ensure to cancel it on this callback.
e1781ed33a Kalle Valo             2009-12-23  3219   *	Must be implemented and can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3220   *
eecc48000a Johannes Berg          2011-05-04  3221   * @suspend: Suspend the device; mac80211 itself will quiesce before and
eecc48000a Johannes Berg          2011-05-04  3222   *	stop transmitting and doing any other configuration, and then
eecc48000a Johannes Berg          2011-05-04  3223   *	ask the device to suspend. This is only invoked when WoWLAN is
eecc48000a Johannes Berg          2011-05-04  3224   *	configured, otherwise the device is deconfigured completely and
eecc48000a Johannes Berg          2011-05-04  3225   *	reconfigured at resume time.
2b4562dfd6 Johannes Berg          2011-07-02  3226   *	The driver may also impose special conditions under which it
2b4562dfd6 Johannes Berg          2011-07-02  3227   *	wants to use the "normal" suspend (deconfigure), say if it only
2b4562dfd6 Johannes Berg          2011-07-02  3228   *	supports WoWLAN when the device is associated. In this case, it
2b4562dfd6 Johannes Berg          2011-07-02  3229   *	must return 1 from this function.
eecc48000a Johannes Berg          2011-05-04  3230   *
eecc48000a Johannes Berg          2011-05-04  3231   * @resume: If WoWLAN was configured, this indicates that mac80211 is
eecc48000a Johannes Berg          2011-05-04  3232   *	now resuming its operation, after this the device must be fully
eecc48000a Johannes Berg          2011-05-04  3233   *	functional again. If this returns an error, the only way out is
eecc48000a Johannes Berg          2011-05-04  3234   *	to also unregister the device. If it returns 1, then mac80211
eecc48000a Johannes Berg          2011-05-04  3235   *	will also go through the regular complete restart on resume.
eecc48000a Johannes Berg          2011-05-04  3236   *
d13e141481 Johannes Berg          2012-06-09  3237   * @set_wakeup: Enable or disable wakeup when WoWLAN configuration is
d13e141481 Johannes Berg          2012-06-09  3238   *	modified. The reason is that device_set_wakeup_enable() is
d13e141481 Johannes Berg          2012-06-09  3239   *	supposed to be called when the configuration changes, not only
d13e141481 Johannes Berg          2012-06-09  3240   *	in suspend().
d13e141481 Johannes Berg          2012-06-09  3241   *
75a5f0ccfd Johannes Berg          2007-09-18  3242   * @add_interface: Called when a netdevice attached to the hardware is
e37d4dffdf Bob Copeland           2008-10-20  3243   *	enabled. Because it is not called for monitor mode devices, @start
75a5f0ccfd Johannes Berg          2007-09-18  3244   *	and @stop must be implemented.
4150c57212 Johannes Berg          2007-09-17  3245   *	The driver should perform any initialization it needs before
4150c57212 Johannes Berg          2007-09-17  3246   *	the device can be enabled. The initial configuration for the
4150c57212 Johannes Berg          2007-09-17  3247   *	interface is given in the conf parameter.
75a5f0ccfd Johannes Berg          2007-09-18  3248   *	The callback may refuse to add an interface by returning a
75a5f0ccfd Johannes Berg          2007-09-18  3249   *	negative error code (which will be seen in userspace.)
e1781ed33a Kalle Valo             2009-12-23  3250   *	Must be implemented and can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3251   *
34d4bc4d41 Johannes Berg          2010-08-27  3252   * @change_interface: Called when a netdevice changes type. This callback
34d4bc4d41 Johannes Berg          2010-08-27  3253   *	is optional, but only if it is supported can interface types be
34d4bc4d41 Johannes Berg          2010-08-27  3254   *	switched while the interface is UP. The callback may sleep.
34d4bc4d41 Johannes Berg          2010-08-27  3255   *	Note that while an interface is being switched, it will not be
34d4bc4d41 Johannes Berg          2010-08-27  3256   *	found by the interface iteration callbacks.
34d4bc4d41 Johannes Berg          2010-08-27  3257   *
75a5f0ccfd Johannes Berg          2007-09-18  3258   * @remove_interface: Notifies a driver that an interface is going down.
75a5f0ccfd Johannes Berg          2007-09-18  3259   *	The @stop callback is called after this if it is the last interface
75a5f0ccfd Johannes Berg          2007-09-18  3260   *	and no monitor interfaces are present.
4150c57212 Johannes Berg          2007-09-17  3261   *	When all interfaces are removed, the MAC address in the hardware
4150c57212 Johannes Berg          2007-09-17  3262   *	must be cleared so the device no longer acknowledges packets,
4150c57212 Johannes Berg          2007-09-17  3263   *	the mac_addr member of the conf structure is, however, set to the
4150c57212 Johannes Berg          2007-09-17  3264   *	MAC address of the device going away.
e1781ed33a Kalle Valo             2009-12-23  3265   *	Hence, this callback must be implemented. It can sleep.
4150c57212 Johannes Berg          2007-09-17  3266   *
75a5f0ccfd Johannes Berg          2007-09-18  3267   * @config: Handler for configuration requests. IEEE 802.11 code calls this
75a5f0ccfd Johannes Berg          2007-09-18  3268   *	function to change hardware configuration, e.g., channel.
6dd1bf3118 Bob Copeland           2009-01-08  3269   *	This function should never fail but returns a negative error code
e1781ed33a Kalle Valo             2009-12-23  3270   *	if it does. The callback can sleep.
4150c57212 Johannes Berg          2007-09-17  3271   *
471b3efdfc Johannes Berg          2007-12-28  3272   * @bss_info_changed: Handler for configuration requests related to BSS
471b3efdfc Johannes Berg          2007-12-28  3273   *	parameters that may vary during BSS's lifespan, and may affect low
471b3efdfc Johannes Berg          2007-12-28  3274   *	level driver (e.g. assoc/disassoc status, erp parameters).
471b3efdfc Johannes Berg          2007-12-28  3275   *	This function should not be used if no BSS has been set, unless
471b3efdfc Johannes Berg          2007-12-28  3276   *	for association indication. The @changed parameter indicates which
e1781ed33a Kalle Valo             2009-12-23  3277   *	of the bss parameters has changed when a call is made. The callback
e1781ed33a Kalle Valo             2009-12-23  3278   *	can sleep.
471b3efdfc Johannes Berg          2007-12-28  3279   *
3ac64beecd Johannes Berg          2009-08-17  3280   * @prepare_multicast: Prepare for multicast filter configuration.
3ac64beecd Johannes Berg          2009-08-17  3281   *	This callback is optional, and its return value is passed
3ac64beecd Johannes Berg          2009-08-17  3282   *	to configure_filter(). This callback must be atomic.
3ac64beecd Johannes Berg          2009-08-17  3283   *
75a5f0ccfd Johannes Berg          2007-09-18  3284   * @configure_filter: Configure the device's RX filter.
75a5f0ccfd Johannes Berg          2007-09-18  3285   *	See the section "Frame filtering" for more information.
e1781ed33a Kalle Valo             2009-12-23  3286   *	This callback must be implemented and can sleep.
8f20fc2498 Johannes Berg          2007-08-28  3287   *
1b09b5568e Andrei Otcheretianski  2015-08-15  3288   * @config_iface_filter: Configure the interface's RX filter.
1b09b5568e Andrei Otcheretianski  2015-08-15  3289   *	This callback is optional and is used to configure which frames
1b09b5568e Andrei Otcheretianski  2015-08-15  3290   *	should be passed to mac80211. The filter_flags is the combination
1b09b5568e Andrei Otcheretianski  2015-08-15  3291   *	of FIF_* flags. The changed_flags is a bit mask that indicates
1b09b5568e Andrei Otcheretianski  2015-08-15  3292   *	which flags are changed.
1b09b5568e Andrei Otcheretianski  2015-08-15  3293   *	This callback can sleep.
1b09b5568e Andrei Otcheretianski  2015-08-15  3294   *
546c80c91f Luis R. Rodriguez      2008-08-14  3295   * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
17741cdc26 Johannes Berg          2008-09-11  3296   * 	must be set or cleared for a given STA. Must be atomic.
11a843b7e1 Johannes Berg          2007-08-28  3297   *
75a5f0ccfd Johannes Berg          2007-09-18  3298   * @set_key: See the section "Hardware crypto acceleration"
e1781ed33a Kalle Valo             2009-12-23  3299   *	This callback is only called between add_interface and
e1781ed33a Kalle Valo             2009-12-23  3300   *	remove_interface calls, i.e. while the given virtual interface
dc822b5db4 Johannes Berg          2008-12-29  3301   *	is enabled.
6dd1bf3118 Bob Copeland           2009-01-08  3302   *	Returns a negative error code if the key can't be added.
e1781ed33a Kalle Valo             2009-12-23  3303   *	The callback can sleep.
11a843b7e1 Johannes Berg          2007-08-28  3304   *
9ae4fda332 Emmanuel Grumbach      2008-03-20  3305   * @update_tkip_key: See the section "Hardware crypto acceleration"
9ae4fda332 Emmanuel Grumbach      2008-03-20  3306   * 	This callback will be called in the context of Rx. Called for drivers
9ae4fda332 Emmanuel Grumbach      2008-03-20  3307   * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
eb807fb238 Kalle Valo             2010-01-24  3308   *	The callback must be atomic.
9ae4fda332 Emmanuel Grumbach      2008-03-20  3309   *
c68f4b892c Johannes Berg          2011-07-05  3310   * @set_rekey_data: If the device supports GTK rekeying, for example while the
c68f4b892c Johannes Berg          2011-07-05  3311   *	host is suspended, it can assign this callback to retrieve the data
c68f4b892c Johannes Berg          2011-07-05  3312   *	necessary to do GTK rekeying, this is the KEK, KCK and replay counter.
c68f4b892c Johannes Berg          2011-07-05  3313   *	After rekeying was done it should (for example during resume) notify
c68f4b892c Johannes Berg          2011-07-05  3314   *	userspace of the new replay counter using ieee80211_gtk_rekey_notify().
c68f4b892c Johannes Berg          2011-07-05  3315   *
de5fad8157 Yoni Divinsky          2012-05-30  3316   * @set_default_unicast_key: Set the default (unicast) key index, useful for
de5fad8157 Yoni Divinsky          2012-05-30  3317   *	WEP when the device sends data packets autonomously, e.g. for ARP
de5fad8157 Yoni Divinsky          2012-05-30  3318   *	offloading. The index can be 0-3, or -1 for unsetting it.
de5fad8157 Yoni Divinsky          2012-05-30  3319   *
75a5f0ccfd Johannes Berg          2007-09-18  3320   * @hw_scan: Ask the hardware to service the scan request, no need to start
8318d78a44 Johannes Berg          2008-01-24  3321   *	the scan state machine in stack. The scan must honour the channel
9050bdd858 Kalle Valo             2009-03-22  3322   *	configuration done by the regulatory agent in the wiphy's
9050bdd858 Kalle Valo             2009-03-22  3323   *	registered bands. The hardware (or the driver) needs to make sure
de95a54b1a Johannes Berg          2009-04-01  3324   *	that power save is disabled.
de95a54b1a Johannes Berg          2009-04-01  3325   *	The @req ie/ie_len members are rewritten by mac80211 to contain the
de95a54b1a Johannes Berg          2009-04-01  3326   *	entire IEs after the SSID, so that drivers need not look at these
de95a54b1a Johannes Berg          2009-04-01  3327   *	at all but just send them after the SSID -- mac80211 includes the
de95a54b1a Johannes Berg          2009-04-01  3328   *	(extended) supported rates and HT information (where applicable).
de95a54b1a Johannes Berg          2009-04-01  3329   *	When the scan finishes, ieee80211_scan_completed() must be called;
de95a54b1a Johannes Berg          2009-04-01  3330   *	note that it also must be called when the scan cannot finish due to
de95a54b1a Johannes Berg          2009-04-01  3331   *	any error unless this callback returned a negative error code.
e9da68ddea Johannes Berg          2018-10-18  3332   *	This callback is also allowed to return the special return value 1,
e9da68ddea Johannes Berg          2018-10-18  3333   *	this indicates that hardware scan isn't desirable right now and a
e9da68ddea Johannes Berg          2018-10-18  3334   *	software scan should be done instead. A driver wishing to use this
e9da68ddea Johannes Berg          2018-10-18  3335   *	capability must ensure its (hardware) scan capabilities aren't
e9da68ddea Johannes Berg          2018-10-18  3336   *	advertised as more capable than mac80211's software scan is.
e1781ed33a Kalle Valo             2009-12-23  3337   *	The callback can sleep.
11a843b7e1 Johannes Berg          2007-08-28  3338   *
b856439b1b Eliad Peller           2011-06-13  3339   * @cancel_hw_scan: Ask the low-level tp cancel the active hw scan.
b856439b1b Eliad Peller           2011-06-13  3340   *	The driver should ask the hardware to cancel the scan (if possible),
b856439b1b Eliad Peller           2011-06-13  3341   *	but the scan will be completed only after the driver will call
b856439b1b Eliad Peller           2011-06-13  3342   *	ieee80211_scan_completed().
b856439b1b Eliad Peller           2011-06-13  3343   *	This callback is needed for wowlan, to prevent enqueueing a new
b856439b1b Eliad Peller           2011-06-13  3344   *	scan_work after the low-level driver was already suspended.
b856439b1b Eliad Peller           2011-06-13  3345   *	The callback can sleep.
b856439b1b Eliad Peller           2011-06-13  3346   *
79f460ca49 Luciano Coelho         2011-05-11  3347   * @sched_scan_start: Ask the hardware to start scanning repeatedly at
79f460ca49 Luciano Coelho         2011-05-11  3348   *	specific intervals.  The driver must call the
79f460ca49 Luciano Coelho         2011-05-11  3349   *	ieee80211_sched_scan_results() function whenever it finds results.
79f460ca49 Luciano Coelho         2011-05-11  3350   *	This process will continue until sched_scan_stop is called.
79f460ca49 Luciano Coelho         2011-05-11  3351   *
79f460ca49 Luciano Coelho         2011-05-11  3352   * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan.
37e3308cb2 Johannes Berg          2014-02-17  3353   *	In this case, ieee80211_sched_scan_stopped() must not be called.
79f460ca49 Luciano Coelho         2011-05-11  3354   *
80e775bf08 Michael Buesch         2009-02-20  3355   * @sw_scan_start: Notifier function that is called just before a software scan
80e775bf08 Michael Buesch         2009-02-20  3356   *	is started. Can be NULL, if the driver doesn't need this notification.
a344d6778a Johannes Berg          2014-06-12  3357   *	The mac_addr parameter allows supporting NL80211_SCAN_FLAG_RANDOM_ADDR,
a344d6778a Johannes Berg          2014-06-12  3358   *	the driver may set the NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR flag if it
a344d6778a Johannes Berg          2014-06-12  3359   *	can use this parameter. The callback can sleep.
80e775bf08 Michael Buesch         2009-02-20  3360   *
e1781ed33a Kalle Valo             2009-12-23  3361   * @sw_scan_complete: Notifier function that is called just after a
e1781ed33a Kalle Valo             2009-12-23  3362   *	software scan finished. Can be NULL, if the driver doesn't need
e1781ed33a Kalle Valo             2009-12-23  3363   *	this notification.
e1781ed33a Kalle Valo             2009-12-23  3364   *	The callback can sleep.
80e775bf08 Michael Buesch         2009-02-20  3365   *
6dd1bf3118 Bob Copeland           2009-01-08  3366   * @get_stats: Return low-level statistics.
6dd1bf3118 Bob Copeland           2009-01-08  3367   * 	Returns zero if statistics are available.
e1781ed33a Kalle Valo             2009-12-23  3368   *	The callback can sleep.
7ac1bd6aec Johannes Berg          2007-09-14  3369   *
9352c19f63 Johannes Berg          2015-04-20  3370   * @get_key_seq: If your device implements encryption in hardware and does
9352c19f63 Johannes Berg          2015-04-20  3371   *	IV/PN assignment then this callback should be provided to read the
9352c19f63 Johannes Berg          2015-04-20  3372   *	IV/PN for the given key from hardware.
e1781ed33a Kalle Valo             2009-12-23  3373   *	The callback must be atomic.
75a5f0ccfd Johannes Berg          2007-09-18  3374   *
f23a478075 Arik Nemtsov           2010-11-08  3375   * @set_frag_threshold: Configuration of fragmentation threshold. Assign this
f3fe4e93dd Sara Sharon            2016-10-18  3376   *	if the device does fragmentation by itself. Note that to prevent the
f3fe4e93dd Sara Sharon            2016-10-18  3377   *	stack from doing fragmentation IEEE80211_HW_SUPPORTS_TX_FRAG
f3fe4e93dd Sara Sharon            2016-10-18  3378   *	should be set as well.
f23a478075 Arik Nemtsov           2010-11-08  3379   *	The callback can sleep.
f23a478075 Arik Nemtsov           2010-11-08  3380   *
75a5f0ccfd Johannes Berg          2007-09-18  3381   * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
e1781ed33a Kalle Valo             2009-12-23  3382   *	The callback can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3383   *
34e895075e Johannes Berg          2010-02-03  3384   * @sta_add: Notifies low level driver about addition of an associated station,
34e895075e Johannes Berg          2010-02-03  3385   *	AP, IBSS/WDS/mesh peer etc. This callback can sleep.
34e895075e Johannes Berg          2010-02-03  3386   *
34e895075e Johannes Berg          2010-02-03  3387   * @sta_remove: Notifies low level driver about removal of an associated
6a9d1b91f3 Johannes Berg          2013-12-04  3388   *	station, AP, IBSS/WDS/mesh peer etc. Note that after the callback
6a9d1b91f3 Johannes Berg          2013-12-04  3389   *	returns it isn't safe to use the pointer, not even RCU protected;
6a9d1b91f3 Johannes Berg          2013-12-04  3390   *	no RCU grace period is guaranteed between returning here and freeing
6a9d1b91f3 Johannes Berg          2013-12-04  3391   *	the station. See @sta_pre_rcu_remove if needed.
6a9d1b91f3 Johannes Berg          2013-12-04  3392   *	This callback can sleep.
34e895075e Johannes Berg          2010-02-03  3393   *
77d2ece6fd Sujith Manoharan       2012-11-20  3394   * @sta_add_debugfs: Drivers can use this callback to add debugfs files
77d2ece6fd Sujith Manoharan       2012-11-20  3395   *	when a station is added to mac80211's station list. This callback
c7e9dbcf09 Johannes Berg          2016-09-14  3396   *	should be within a CONFIG_MAC80211_DEBUGFS conditional. This
c7e9dbcf09 Johannes Berg          2016-09-14  3397   *	callback can sleep.
77d2ece6fd Sujith Manoharan       2012-11-20  3398   *
34e895075e Johannes Berg          2010-02-03  3399   * @sta_notify: Notifies low level driver about power state transition of an
d057e5a381 Arik Nemtsov           2011-01-31  3400   *	associated station, AP,  IBSS/WDS/mesh peer etc. For a VIF operating
d057e5a381 Arik Nemtsov           2011-01-31  3401   *	in AP mode, this callback will not be called when the flag
d057e5a381 Arik Nemtsov           2011-01-31  3402   *	%IEEE80211_HW_AP_LINK_PS is set. Must be atomic.
4571d3bf87 Christian Lamparter    2008-11-30  3403   *
f09603a259 Johannes Berg          2012-01-20  3404   * @sta_state: Notifies low level driver about state transition of a
f09603a259 Johannes Berg          2012-01-20  3405   *	station (which can be the AP, a client, IBSS/WDS/mesh peer etc.)
f09603a259 Johannes Berg          2012-01-20  3406   *	This callback is mutually exclusive with @sta_add/@sta_remove.
f09603a259 Johannes Berg          2012-01-20  3407   *	It must not fail for down transitions but may fail for transitions
6a9d1b91f3 Johannes Berg          2013-12-04  3408   *	up the list of states. Also note that after the callback returns it
6a9d1b91f3 Johannes Berg          2013-12-04  3409   *	isn't safe to use the pointer, not even RCU protected - no RCU grace
6a9d1b91f3 Johannes Berg          2013-12-04  3410   *	period is guaranteed between returning here and freeing the station.
6a9d1b91f3 Johannes Berg          2013-12-04  3411   *	See @sta_pre_rcu_remove if needed.
6a9d1b91f3 Johannes Berg          2013-12-04  3412   *	The callback can sleep.
6a9d1b91f3 Johannes Berg          2013-12-04  3413   *
6a9d1b91f3 Johannes Berg          2013-12-04  3414   * @sta_pre_rcu_remove: Notify driver about station removal before RCU
6a9d1b91f3 Johannes Berg          2013-12-04  3415   *	synchronisation. This is useful if a driver needs to have station
6a9d1b91f3 Johannes Berg          2013-12-04  3416   *	pointers protected using RCU, it can then use this call to clear
6a9d1b91f3 Johannes Berg          2013-12-04  3417   *	the pointers instead of waiting for an RCU grace period to elapse
6a9d1b91f3 Johannes Berg          2013-12-04  3418   *	in @sta_state.
f09603a259 Johannes Berg          2012-01-20  3419   *	The callback can sleep.
f09603a259 Johannes Berg          2012-01-20  3420   *
8f727ef3c4 Johannes Berg          2012-03-30  3421   * @sta_rc_update: Notifies the driver of changes to the bitrates that can be
8f727ef3c4 Johannes Berg          2012-03-30  3422   *	used to transmit to the station. The changes are advertised with bits
8f727ef3c4 Johannes Berg          2012-03-30  3423   *	from &enum ieee80211_rate_control_changed and the values are reflected
8f727ef3c4 Johannes Berg          2012-03-30  3424   *	in the station data. This callback should only be used when the driver
8f727ef3c4 Johannes Berg          2012-03-30  3425   *	uses hardware rate control (%IEEE80211_HW_HAS_RATE_CONTROL) since
8f727ef3c4 Johannes Berg          2012-03-30  3426   *	otherwise the rate control algorithm is notified directly.
8f727ef3c4 Johannes Berg          2012-03-30  3427   *	Must be atomic.
f815e2b3c0 Johannes Berg          2014-11-19  3428   * @sta_rate_tbl_update: Notifies the driver that the rate table changed. This
f815e2b3c0 Johannes Berg          2014-11-19  3429   *	is only used if the configured rate control algorithm actually uses
f815e2b3c0 Johannes Berg          2014-11-19  3430   *	the new rate table API, and is therefore optional. Must be atomic.
8f727ef3c4 Johannes Berg          2012-03-30  3431   *
2b9a7e1bac Johannes Berg          2014-11-17  3432   * @sta_statistics: Get statistics for this station. For example with beacon
2b9a7e1bac Johannes Berg          2014-11-17  3433   *	filtering, the statistics kept by mac80211 might not be accurate, so
2b9a7e1bac Johannes Berg          2014-11-17  3434   *	let the driver pre-fill the statistics. The driver can fill most of
2b9a7e1bac Johannes Berg          2014-11-17  3435   *	the values (indicating which by setting the filled bitmap), but not
2b9a7e1bac Johannes Berg          2014-11-17  3436   *	all of them make sense - see the source for which ones are possible.
2b9a7e1bac Johannes Berg          2014-11-17  3437   *	Statistics that the driver doesn't fill will be filled by mac80211.
2b9a7e1bac Johannes Berg          2014-11-17  3438   *	The callback can sleep.
2b9a7e1bac Johannes Berg          2014-11-17  3439   *
75a5f0ccfd Johannes Berg          2007-09-18  3440   * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
fe3fa82731 Johannes Berg          2008-09-08  3441   *	bursting) for a hardware TX queue.
6dd1bf3118 Bob Copeland           2009-01-08  3442   *	Returns a negative error code on failure.
e1781ed33a Kalle Valo             2009-12-23  3443   *	The callback can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3444   *
75a5f0ccfd Johannes Berg          2007-09-18  3445   * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
3b5d665b51 Alina Friedrichsen     2009-01-24  3446   *	this is only used for IBSS mode BSSID merging and debugging. Is not a
7b08b3b4a9 Alina Friedrichsen     2009-02-05  3447   *	required function.
e1781ed33a Kalle Valo             2009-12-23  3448   *	The callback can sleep.
3b5d665b51 Alina Friedrichsen     2009-01-24  3449   *
3b5d665b51 Alina Friedrichsen     2009-01-24  3450   * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
3b5d665b51 Alina Friedrichsen     2009-01-24  3451   *	Currently, this is only used for IBSS mode debugging. Is not a
7b08b3b4a9 Alina Friedrichsen     2009-02-05  3452   *	required function.
e1781ed33a Kalle Valo             2009-12-23  3453   *	The callback can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3454   *
354d381baf Pedersen, Thomas       2016-09-28  3455   * @offset_tsf: Offset the TSF timer by the specified value in the
354d381baf Pedersen, Thomas       2016-09-28  3456   *	firmware/hardware.  Preferred to set_tsf as it avoids delay between
354d381baf Pedersen, Thomas       2016-09-28  3457   *	calling set_tsf() and hardware getting programmed, which will show up
354d381baf Pedersen, Thomas       2016-09-28  3458   *	as TSF delay. Is not a required function.
354d381baf Pedersen, Thomas       2016-09-28  3459   *	The callback can sleep.
354d381baf Pedersen, Thomas       2016-09-28  3460   *
75a5f0ccfd Johannes Berg          2007-09-18  3461   * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
75a5f0ccfd Johannes Berg          2007-09-18  3462   *	with other STAs in the IBSS. This is only used in IBSS mode. This
75a5f0ccfd Johannes Berg          2007-09-18  3463   *	function is optional if the firmware/hardware takes full care of
75a5f0ccfd Johannes Berg          2007-09-18  3464   *	TSF synchronization.
e1781ed33a Kalle Valo             2009-12-23  3465   *	The callback can sleep.
75a5f0ccfd Johannes Berg          2007-09-18  3466   *
75a5f0ccfd Johannes Berg          2007-09-18  3467   * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
75a5f0ccfd Johannes Berg          2007-09-18  3468   *	This is needed only for IBSS mode and the result of this function is
75a5f0ccfd Johannes Berg          2007-09-18  3469   *	used to determine whether to reply to Probe Requests.
6dd1bf3118 Bob Copeland           2009-01-08  3470   *	Returns non-zero if this device sent the last beacon.
e1781ed33a Kalle Valo             2009-12-23  3471   *	The callback can sleep.
d3c990fb26 Ron Rindjunsky         2007-11-26  3472   *
4e8998f09b Randy Dunlap           2010-05-21  3473   * @get_survey: Return per-channel survey information
4e8998f09b Randy Dunlap           2010-05-21  3474   *
1f87f7d3a3 Johannes Berg          2009-06-02  3475   * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
1f87f7d3a3 Johannes Berg          2009-06-02  3476   *	need to set wiphy->rfkill_poll to %true before registration,
1f87f7d3a3 Johannes Berg          2009-06-02  3477   *	and need to call wiphy_rfkill_set_hw_state() in the callback.
e1781ed33a Kalle Valo             2009-12-23  3478   *	The callback can sleep.
aff89a9b90 Johannes Berg          2009-07-01  3479   *
310bc676e3 Lukáš Turek            2009-12-21  3480   * @set_coverage_class: Set slot time for given coverage class as specified
310bc676e3 Lukáš Turek            2009-12-21  3481   *	in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout
a4bcaf5556 Lorenzo Bianconi       2014-09-04  3482   *	accordingly; coverage class equals to -1 to enable ACK timeout
a4bcaf5556 Lorenzo Bianconi       2014-09-04  3483   *	estimation algorithm (dynack). To disable dynack set valid value for
a4bcaf5556 Lorenzo Bianconi       2014-09-04  3484   *	coverage class. This callback is not required and may sleep.
310bc676e3 Lukáš Turek            2009-12-21  3485   *
52981cd794 David Spinadel         2013-07-31  3486   * @testmode_cmd: Implement a cfg80211 test mode command. The passed @vif may
52981cd794 David Spinadel         2013-07-31  3487   *	be %NULL. The callback can sleep.
71063f0e89 Wey-Yi Guy             2011-05-20  3488   * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
a80f7c0b08 Johannes Berg          2009-12-23  3489   *
a80f7c0b08 Johannes Berg          2009-12-23  3490   * @flush: Flush all pending frames from the hardware queue, making sure
39ecc01d1b Johannes Berg          2013-02-13  3491   *	that the hardware queues are empty. The @queues parameter is a bitmap
39ecc01d1b Johannes Berg          2013-02-13  3492   *	of queues to flush, which is useful if different virtual interfaces
39ecc01d1b Johannes Berg          2013-02-13  3493   *	use different hardware queues; it may also indicate all queues.
39ecc01d1b Johannes Berg          2013-02-13  3494   *	If the parameter @drop is set to %true, pending frames may be dropped.
77be2c54c5 Emmanuel Grumbach      2014-03-27  3495   *	Note that vif can be NULL.
39ecc01d1b Johannes Berg          2013-02-13  3496   *	The callback can sleep.
5ce6e438d5 Johannes Berg          2010-05-11  3497   *
5ce6e438d5 Johannes Berg          2010-05-11  3498   * @channel_switch: Drivers that need (or want) to offload the channel
5ce6e438d5 Johannes Berg          2010-05-11  3499   *	switch operation for CSAs received from the AP may implement this
5ce6e438d5 Johannes Berg          2010-05-11  3500   *	callback. They must then call ieee80211_chswitch_done() to indicate
5ce6e438d5 Johannes Berg          2010-05-11  3501   *	completion of the channel switch.
4e6cbfd09c John W. Linville       2010-07-29  3502   *
79b1c460a0 Bruno Randolf          2010-11-24  3503   * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
79b1c460a0 Bruno Randolf          2010-11-24  3504   *	Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
79b1c460a0 Bruno Randolf          2010-11-24  3505   *	reject TX/RX mask combinations they cannot support by returning -EINVAL
79b1c460a0 Bruno Randolf          2010-11-24  3506   *	(also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
79b1c460a0 Bruno Randolf          2010-11-24  3507   *
79b1c460a0 Bruno Randolf          2010-11-24  3508   * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
4976b4eb9d Johannes Berg          2011-01-04  3509   *
4976b4eb9d Johannes Berg          2011-01-04  3510   * @remain_on_channel: Starts an off-channel period on the given channel, must
4976b4eb9d Johannes Berg          2011-01-04  3511   *	call back to ieee80211_ready_on_channel() when on that channel. Note
4976b4eb9d Johannes Berg          2011-01-04  3512   *	that normal channel traffic is not stopped as this is intended for hw
4976b4eb9d Johannes Berg          2011-01-04  3513   *	offload. Frames to transmit on the off-channel channel are transmitted
4976b4eb9d Johannes Berg          2011-01-04  3514   *	normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
4976b4eb9d Johannes Berg          2011-01-04  3515   *	duration (which will always be non-zero) expires, the driver must call
196ac1c13d Johannes Berg          2012-06-05  3516   *	ieee80211_remain_on_channel_expired().
196ac1c13d Johannes Berg          2012-06-05  3517   *	Note that this callback may be called while the device is in IDLE and
196ac1c13d Johannes Berg          2012-06-05  3518   *	must be accepted in this case.
196ac1c13d Johannes Berg          2012-06-05  3519   *	This callback may sleep.
4976b4eb9d Johannes Berg          2011-01-04  3520   * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
4976b4eb9d Johannes Berg          2011-01-04  3521   *	aborted before it expires. This callback may sleep.
38c091590f John W. Linville       2011-03-07  3522   *
38c091590f John W. Linville       2011-03-07  3523   * @set_ringparam: Set tx and rx ring sizes.
38c091590f John W. Linville       2011-03-07  3524   *
38c091590f John W. Linville       2011-03-07  3525   * @get_ringparam: Get tx and rx ring current and maximum sizes.
e8306f9894 Vivek Natarajan        2011-04-06  3526   *
e8306f9894 Vivek Natarajan        2011-04-06  3527   * @tx_frames_pending: Check if there is any pending frame in the hardware
e8306f9894 Vivek Natarajan        2011-04-06  3528   *	queues before entering power save.
bdbfd6b582 Sujith Manoharan       2011-04-27  3529   *
bdbfd6b582 Sujith Manoharan       2011-04-27  3530   * @set_bitrate_mask: Set a mask of rates to be used for rate control selection
bdbfd6b582 Sujith Manoharan       2011-04-27  3531   *	when transmitting a frame. Currently only legacy rates are handled.
bdbfd6b582 Sujith Manoharan       2011-04-27  3532   *	The callback can sleep.
a818292952 Emmanuel Grumbach      2015-03-16  3533   * @event_callback: Notify driver about any event in mac80211. See
a818292952 Emmanuel Grumbach      2015-03-16  3534   *	&enum ieee80211_event_type for the different types.
6382246e89 Emmanuel Grumbach      2015-04-20  3535   *	The callback must be atomic.
4049e09acd Johannes Berg          2011-09-29  3536   *
4049e09acd Johannes Berg          2011-09-29  3537   * @release_buffered_frames: Release buffered frames according to the given
4049e09acd Johannes Berg          2011-09-29  3538   *	parameters. In the case where the driver buffers some frames for
4049e09acd Johannes Berg          2011-09-29  3539   *	sleeping stations mac80211 will use this callback to tell the driver
4049e09acd Johannes Berg          2011-09-29  3540   *	to release some frames, either for PS-poll or uAPSD.
e227867f12 Masanari Iida          2014-02-18  3541   *	Note that if the @more_data parameter is %false the driver must check
4049e09acd Johannes Berg          2011-09-29  3542   *	if there are more frames on the given TIDs, and if there are more than
4049e09acd Johannes Berg          2011-09-29  3543   *	the frames being released then it must still set the more-data bit in
4049e09acd Johannes Berg          2011-09-29  3544   *	the frame. If the @more_data parameter is %true, then of course the
4049e09acd Johannes Berg          2011-09-29  3545   *	more-data bit must always be set.
4049e09acd Johannes Berg          2011-09-29  3546   *	The @tids parameter tells the driver which TIDs to release frames
4049e09acd Johannes Berg          2011-09-29  3547   *	from, for PS-poll it will always have only a single bit set.
deeaee197b Johannes Berg          2011-09-29  3548   *	In the case this is used for a PS-poll initiated release, the
deeaee197b Johannes Berg          2011-09-29  3549   *	@num_frames parameter will always be 1 so code can be shared. In
deeaee197b Johannes Berg          2011-09-29  3550   *	this case the driver must also set %IEEE80211_TX_STATUS_EOSP flag
deeaee197b Johannes Berg          2011-09-29  3551   *	on the TX status (and must report TX status) so that the PS-poll
deeaee197b Johannes Berg          2011-09-29  3552   *	period is properly ended. This is used to avoid sending multiple
deeaee197b Johannes Berg          2011-09-29  3553   *	responses for a retried PS-poll frame.
4049e09acd Johannes Berg          2011-09-29  3554   *	In the case this is used for uAPSD, the @num_frames parameter may be
4049e09acd Johannes Berg          2011-09-29  3555   *	bigger than one, but the driver may send fewer frames (it must send
4049e09acd Johannes Berg          2011-09-29  3556   *	at least one, however). In this case it is also responsible for
47086fc51a Johannes Berg          2011-09-29  3557   *	setting the EOSP flag in the QoS header of the frames. Also, when the
47086fc51a Johannes Berg          2011-09-29  3558   *	service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
37fbd90800 Johannes Berg          2011-09-29  3559   *	on the last frame in the SP. Alternatively, it may call the function
e943789edb Johannes Berg          2013-02-15  3560   *	ieee80211_sta_eosp() to inform mac80211 of the end of the SP.
4049e09acd Johannes Berg          2011-09-29  3561   *	This callback must be atomic.
40b9640883 Johannes Berg          2011-09-29  3562   * @allow_buffered_frames: Prepare device to allow the given number of frames
40b9640883 Johannes Berg          2011-09-29  3563   *	to go out to the given station. The frames will be sent by mac80211
40b9640883 Johannes Berg          2011-09-29  3564   *	via the usual TX path after this call. The TX information for frames
02f2f1a951 Johannes Berg          2012-02-27  3565   *	released will also have the %IEEE80211_TX_CTL_NO_PS_BUFFER flag set
40b9640883 Johannes Berg          2011-09-29  3566   *	and the last one will also have %IEEE80211_TX_STATUS_EOSP set. In case
40b9640883 Johannes Berg          2011-09-29  3567   *	frames from multiple TIDs are released and the driver might reorder
40b9640883 Johannes Berg          2011-09-29  3568   *	them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
40b9640883 Johannes Berg          2011-09-29  3569   *	on the last frame and clear it on all others and also handle the EOSP
37fbd90800 Johannes Berg          2011-09-29  3570   *	bit in the QoS header correctly. Alternatively, it can also call the
e943789edb Johannes Berg          2013-02-15  3571   *	ieee80211_sta_eosp() function.
40b9640883 Johannes Berg          2011-09-29  3572   *	The @tids parameter is a bitmap and tells the driver which TIDs the
40b9640883 Johannes Berg          2011-09-29  3573   *	frames will be on; it will at most have two bits set.
40b9640883 Johannes Berg          2011-09-29  3574   *	This callback must be atomic.
e352114fd6 Ben Greear             2012-04-23  3575   *
e352114fd6 Ben Greear             2012-04-23  3576   * @get_et_sset_count:  Ethtool API to get string-set count.
e352114fd6 Ben Greear             2012-04-23  3577   *
e352114fd6 Ben Greear             2012-04-23  3578   * @get_et_stats:  Ethtool API to get a set of u64 stats.
e352114fd6 Ben Greear             2012-04-23  3579   *
e352114fd6 Ben Greear             2012-04-23  3580   * @get_et_strings:  Ethtool API to get a set of strings to describe stats
e352114fd6 Ben Greear             2012-04-23  3581   *	and perhaps other supported types of ethtool data-sets.
e352114fd6 Ben Greear             2012-04-23  3582   *
a1845fc7c5 Johannes Berg          2012-06-27  3583   * @mgd_prepare_tx: Prepare for transmitting a management frame for association
a1845fc7c5 Johannes Berg          2012-06-27  3584   *	before associated. In multi-channel scenarios, a virtual interface is
a1845fc7c5 Johannes Berg          2012-06-27  3585   *	bound to a channel before it is associated, but as it isn't associated
a1845fc7c5 Johannes Berg          2012-06-27  3586   *	yet it need not necessarily be given airtime, in particular since any
a1845fc7c5 Johannes Berg          2012-06-27  3587   *	transmission to a P2P GO needs to be synchronized against the GO's
a1845fc7c5 Johannes Berg          2012-06-27  3588   *	powersave state. mac80211 will call this function before transmitting a
a1845fc7c5 Johannes Berg          2012-06-27  3589   *	management frame prior to having successfully associated to allow the
a1845fc7c5 Johannes Berg          2012-06-27  3590   *	driver to give it channel time for the transmission, to get a response
a1845fc7c5 Johannes Berg          2012-06-27  3591   *	and to be able to synchronize with the GO.
94ba92713f Ilan Peer              2018-02-19  3592   *	For drivers that set %IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP, mac80211
94ba92713f Ilan Peer              2018-02-19  3593   *	would also call this function before transmitting a deauthentication
94ba92713f Ilan Peer              2018-02-19  3594   *	frame in case that no beacon was heard from the AP/P2P GO.
a1845fc7c5 Johannes Berg          2012-06-27  3595   *	The callback will be called before each transmission and upon return
a1845fc7c5 Johannes Berg          2012-06-27  3596   *	mac80211 will transmit the frame right away.
d4e36e5554 Ilan Peer              2018-04-20  3597   *      If duration is greater than zero, mac80211 hints to the driver the
d4e36e5554 Ilan Peer              2018-04-20  3598   *      duration for which the operation is requested.
a1845fc7c5 Johannes Berg          2012-06-27  3599   *	The callback is optional and can (should!) sleep.
c3645eac47 Michal Kazior          2012-06-26  3600   *
ee10f2c779 Arik Nemtsov           2014-06-11  3601   * @mgd_protect_tdls_discover: Protect a TDLS discovery session. After sending
ee10f2c779 Arik Nemtsov           2014-06-11  3602   *	a TDLS discovery-request, we expect a reply to arrive on the AP's
ee10f2c779 Arik Nemtsov           2014-06-11  3603   *	channel. We must stay on the channel (no PSM, scan, etc.), since a TDLS
ee10f2c779 Arik Nemtsov           2014-06-11  3604   *	setup-response is a direct packet not buffered by the AP.
ee10f2c779 Arik Nemtsov           2014-06-11  3605   *	mac80211 will call this function just before the transmission of a TDLS
ee10f2c779 Arik Nemtsov           2014-06-11  3606   *	discovery-request. The recommended period of protection is at least
ee10f2c779 Arik Nemtsov           2014-06-11  3607   *	2 * (DTIM period).
ee10f2c779 Arik Nemtsov           2014-06-11  3608   *	The callback is optional and can sleep.
ee10f2c779 Arik Nemtsov           2014-06-11  3609   *
c3645eac47 Michal Kazior          2012-06-26  3610   * @add_chanctx: Notifies device driver about new channel context creation.
dcae9e0203 Chaitanya T K          2015-10-30  3611   *	This callback may sleep.
c3645eac47 Michal Kazior          2012-06-26  3612   * @remove_chanctx: Notifies device driver about channel context destruction.
dcae9e0203 Chaitanya T K          2015-10-30  3613   *	This callback may sleep.
c3645eac47 Michal Kazior          2012-06-26  3614   * @change_chanctx: Notifies device driver about channel context changes that
c3645eac47 Michal Kazior          2012-06-26  3615   *	may happen when combining different virtual interfaces on the same
c3645eac47 Michal Kazior          2012-06-26  3616   *	channel context with different settings
dcae9e0203 Chaitanya T K          2015-10-30  3617   *	This callback may sleep.
c3645eac47 Michal Kazior          2012-06-26  3618   * @assign_vif_chanctx: Notifies device driver about channel context being bound
c3645eac47 Michal Kazior          2012-06-26  3619   *	to vif. Possible use is for hw queue remapping.
dcae9e0203 Chaitanya T K          2015-10-30  3620   *	This callback may sleep.
c3645eac47 Michal Kazior          2012-06-26  3621   * @unassign_vif_chanctx: Notifies device driver about channel context being
c3645eac47 Michal Kazior          2012-06-26  3622   *	unbound from vif.
dcae9e0203 Chaitanya T K          2015-10-30  3623   *	This callback may sleep.
1a5f0c13d1 Luciano Coelho         2014-05-23  3624   * @switch_vif_chanctx: switch a number of vifs from one chanctx to
1a5f0c13d1 Luciano Coelho         2014-05-23  3625   *	another, as specified in the list of
1a5f0c13d1 Luciano Coelho         2014-05-23  3626   *	@ieee80211_vif_chanctx_switch passed to the driver, according
1a5f0c13d1 Luciano Coelho         2014-05-23  3627   *	to the mode defined in &ieee80211_chanctx_switch_mode.
dcae9e0203 Chaitanya T K          2015-10-30  3628   *	This callback may sleep.
1a5f0c13d1 Luciano Coelho         2014-05-23  3629   *
1041638f2b Johannes Berg          2012-10-19  3630   * @start_ap: Start operation on the AP interface, this is called after all the
1041638f2b Johannes Berg          2012-10-19  3631   *	information in bss_conf is set and beacon can be retrieved. A channel
1041638f2b Johannes Berg          2012-10-19  3632   *	context is bound before this is called. Note that if the driver uses
1041638f2b Johannes Berg          2012-10-19  3633   *	software scan or ROC, this (and @stop_ap) isn't called when the AP is
1041638f2b Johannes Berg          2012-10-19  3634   *	just "paused" for scanning/ROC, which is indicated by the beacon being
1041638f2b Johannes Berg          2012-10-19  3635   *	disabled/enabled via @bss_info_changed.
1041638f2b Johannes Berg          2012-10-19  3636   * @stop_ap: Stop operation on the AP interface.
9214ad7f9a Johannes Berg          2012-11-06  3637   *
cf2c92d840 Eliad Peller           2014-11-04  3638   * @reconfig_complete: Called after a call to ieee80211_restart_hw() and
cf2c92d840 Eliad Peller           2014-11-04  3639   *	during resume, when the reconfiguration has completed.
cf2c92d840 Eliad Peller           2014-11-04  3640   *	This can help the driver implement the reconfiguration step (and
cf2c92d840 Eliad Peller           2014-11-04  3641   *	indicate mac80211 is ready to receive frames).
cf2c92d840 Eliad Peller           2014-11-04  3642   *	This callback may sleep.
8f21b0adfe Johannes Berg          2013-01-11  3643   *
a65240c101 Johannes Berg          2013-01-14  3644   * @ipv6_addr_change: IPv6 address assignment on the given interface changed.
a65240c101 Johannes Berg          2013-01-14  3645   *	Currently, this is only called for managed or P2P client interfaces.
a65240c101 Johannes Berg          2013-01-14  3646   *	This callback is optional; it must not sleep.
73da7d5bab Simon Wunderlich       2013-07-11  3647   *
73da7d5bab Simon Wunderlich       2013-07-11  3648   * @channel_switch_beacon: Starts a channel switch to a new channel.
73da7d5bab Simon Wunderlich       2013-07-11  3649   *	Beacons are modified to include CSA or ECSA IEs before calling this
73da7d5bab Simon Wunderlich       2013-07-11  3650   *	function. The corresponding count fields in these IEs must be
66e01cf99e Luciano Coelho         2014-01-13  3651   *	decremented, and when they reach 1 the driver must call
73da7d5bab Simon Wunderlich       2013-07-11  3652   *	ieee80211_csa_finish(). Drivers which use ieee80211_beacon_get()
73da7d5bab Simon Wunderlich       2013-07-11  3653   *	get the csa counter decremented by mac80211, but must check if it is
66e01cf99e Luciano Coelho         2014-01-13  3654   *	1 using ieee80211_csa_is_complete() after the beacon has been
73da7d5bab Simon Wunderlich       2013-07-11  3655   *	transmitted and then call ieee80211_csa_finish().
66e01cf99e Luciano Coelho         2014-01-13  3656   *	If the CSA count starts as zero or 1, this function will not be called,
66e01cf99e Luciano Coelho         2014-01-13  3657   *	since there won't be any time to beacon before the switch anyway.
6d027bcc8a Luciano Coelho         2014-10-08  3658   * @pre_channel_switch: This is an optional callback that is called
6d027bcc8a Luciano Coelho         2014-10-08  3659   *	before a channel switch procedure is started (ie. when a STA
9332ef9dbd Masahiro Yamada        2017-02-27  3660   *	gets a CSA or a userspace initiated channel-switch), allowing
6d027bcc8a Luciano Coelho         2014-10-08  3661   *	the driver to prepare for the channel switch.
f1d65583bc Luciano Coelho         2014-10-08  3662   * @post_channel_switch: This is an optional callback that is called
f1d65583bc Luciano Coelho         2014-10-08  3663   *	after a channel switch procedure is completed, allowing the
f1d65583bc Luciano Coelho         2014-10-08  3664   *	driver to go back to a normal configuration.
b9cc81d827 Sara Sharon            2019-02-06  3665   * @abort_channel_switch: This is an optional callback that is called
b9cc81d827 Sara Sharon            2019-02-06  3666   *	when channel switch procedure was completed, allowing the
b9cc81d827 Sara Sharon            2019-02-06  3667   *	driver to go back to a normal configuration.
fafd2bce5a Sara Sharon            2019-02-06  3668   * @channel_switch_rx_beacon: This is an optional callback that is called
fafd2bce5a Sara Sharon            2019-02-06  3669   *	when channel switch procedure is in progress and additional beacon with
fafd2bce5a Sara Sharon            2019-02-06  3670   *	CSA IE was received, allowing driver to track changes in count.
55fff50113 Johannes Berg          2013-08-19  3671   * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
55fff50113 Johannes Berg          2013-08-19  3672   *	information in bss_conf is set up and the beacon can be retrieved. A
55fff50113 Johannes Berg          2013-08-19  3673   *	channel context is bound before this is called.
55fff50113 Johannes Berg          2013-08-19  3674   * @leave_ibss: Leave the IBSS again.
cca674d47e Antonio Quartulli      2014-05-19  3675   *
cca674d47e Antonio Quartulli      2014-05-19  3676   * @get_expected_throughput: extract the expected throughput towards the
cca674d47e Antonio Quartulli      2014-05-19  3677   *	specified station. The returned value is expressed in Kbps. It returns 0
cca674d47e Antonio Quartulli      2014-05-19  3678   *	if the RC algorithm does not have proper data to provide.
5b3dc42b1b Felix Fietkau          2014-10-26  3679   *
5b3dc42b1b Felix Fietkau          2014-10-26  3680   * @get_txpower: get current maximum tx power (in dBm) based on configuration
5b3dc42b1b Felix Fietkau          2014-10-26  3681   *	and hardware limits.
a7a6bdd067 Arik Nemtsov           2014-11-09  3682   *
a7a6bdd067 Arik Nemtsov           2014-11-09  3683   * @tdls_channel_switch: Start channel-switching with a TDLS peer. The driver
a7a6bdd067 Arik Nemtsov           2014-11-09  3684   *	is responsible for continually initiating channel-switching operations
a7a6bdd067 Arik Nemtsov           2014-11-09  3685   *	and returning to the base channel for communication with the AP. The
a7a6bdd067 Arik Nemtsov           2014-11-09  3686   *	driver receives a channel-switch request template and the location of
a7a6bdd067 Arik Nemtsov           2014-11-09  3687   *	the switch-timing IE within the template as part of the invocation.
a7a6bdd067 Arik Nemtsov           2014-11-09  3688   *	The template is valid only within the call, and the driver can
a7a6bdd067 Arik Nemtsov           2014-11-09  3689   *	optionally copy the skb for further re-use.
a7a6bdd067 Arik Nemtsov           2014-11-09  3690   * @tdls_cancel_channel_switch: Stop channel-switching with a TDLS peer. Both
a7a6bdd067 Arik Nemtsov           2014-11-09  3691   *	peers must be on the base channel when the call completes.
8a4d32f30d Arik Nemtsov           2014-11-09  3692   * @tdls_recv_channel_switch: a TDLS channel-switch related frame (request or
8a4d32f30d Arik Nemtsov           2014-11-09  3693   *	response) has been received from a remote peer. The driver gets
8a4d32f30d Arik Nemtsov           2014-11-09  3694   *	parameters parsed from the incoming frame and may use them to continue
8a4d32f30d Arik Nemtsov           2014-11-09  3695   *	an ongoing channel-switch operation. In addition, a channel-switch
8a4d32f30d Arik Nemtsov           2014-11-09  3696   *	response template is provided, together with the location of the
8a4d32f30d Arik Nemtsov           2014-11-09  3697   *	switch-timing IE within the template. The skb can only be used within
8a4d32f30d Arik Nemtsov           2014-11-09  3698   *	the function call.
ba8c3d6f16 Felix Fietkau          2015-03-27  3699   *
ba8c3d6f16 Felix Fietkau          2015-03-27  3700   * @wake_tx_queue: Called when new packets have been added to the queue.
f59374eb42 Sara Sharon            2016-03-02  3701   * @sync_rx_queues: Process all pending frames in RSS queues. This is a
f59374eb42 Sara Sharon            2016-03-02  3702   *	synchronization which is needed in case driver has in its RSS queues
f59374eb42 Sara Sharon            2016-03-02  3703   *	pending frames that were received prior to the control path action
f59374eb42 Sara Sharon            2016-03-02  3704   *	currently taken (e.g. disassociation) but are not processed yet.
708d50edb1 Ayala Beker            2016-09-20  3705   *
708d50edb1 Ayala Beker            2016-09-20  3706   * @start_nan: join an existing NAN cluster, or create a new one.
708d50edb1 Ayala Beker            2016-09-20  3707   * @stop_nan: leave the NAN cluster.
5953ff6d6a Ayala Beker            2016-09-20  3708   * @nan_change_conf: change NAN configuration. The data in cfg80211_nan_conf
5953ff6d6a Ayala Beker            2016-09-20  3709   *	contains full new configuration and changes specify which parameters
5953ff6d6a Ayala Beker            2016-09-20  3710   *	are changed with respect to the last NAN config.
5953ff6d6a Ayala Beker            2016-09-20  3711   *	The driver gets both full configuration and the changed parameters since
5953ff6d6a Ayala Beker            2016-09-20  3712   *	some devices may need the full configuration while others need only the
5953ff6d6a Ayala Beker            2016-09-20  3713   *	changed parameters.
167e33f4f6 Ayala Beker            2016-09-20  3714   * @add_nan_func: Add a NAN function. Returns 0 on success. The data in
167e33f4f6 Ayala Beker            2016-09-20  3715   *	cfg80211_nan_func must not be referenced outside the scope of
167e33f4f6 Ayala Beker            2016-09-20  3716   *	this call.
167e33f4f6 Ayala Beker            2016-09-20  3717   * @del_nan_func: Remove a NAN function. The driver must call
167e33f4f6 Ayala Beker            2016-09-20  3718   *	ieee80211_nan_func_terminated() with
167e33f4f6 Ayala Beker            2016-09-20  3719   *	NL80211_NAN_FUNC_TERM_REASON_USER_REQUEST reason code upon removal.
9739fe29a2 Sara Sharon            2018-09-05  3720   * @can_aggregate_in_amsdu: Called in order to determine if HW supports
9739fe29a2 Sara Sharon            2018-09-05  3721   *	aggregating two specific frames in the same A-MSDU. The relation
9739fe29a2 Sara Sharon            2018-09-05  3722   *	between the skbs should be symmetric and transitive. Note that while
9739fe29a2 Sara Sharon            2018-09-05  3723   *	skb is always a real frame, head may or may not be an A-MSDU.
bc847970f4 Pradeep Kumar Chitrapu 2018-10-03  3724   * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available.
bc847970f4 Pradeep Kumar Chitrapu 2018-10-03  3725   *	Statistics should be cumulative, currently no way to reset is provided.
cee7013be9 Johannes Berg          2018-10-16  3726   *
cee7013be9 Johannes Berg          2018-10-16  3727   * @start_pmsr: start peer measurement (e.g. FTM) (this call can sleep)
cee7013be9 Johannes Berg          2018-10-16  3728   * @abort_pmsr: abort peer measurement (this call can sleep)
8f20fc2498 Johannes Berg          2007-08-28  3729   */
75a5f0ccfd Johannes Berg          2007-09-18  3730  struct ieee80211_ops {
36323f817a Thomas Huehn           2012-07-23  3731  	void (*tx)(struct ieee80211_hw *hw,
36323f817a Thomas Huehn           2012-07-23  3732  		   struct ieee80211_tx_control *control,
36323f817a Thomas Huehn           2012-07-23  3733  		   struct sk_buff *skb);
75a5f0ccfd Johannes Berg          2007-09-18  3734  	int (*start)(struct ieee80211_hw *hw);
75a5f0ccfd Johannes Berg          2007-09-18  3735  	void (*stop)(struct ieee80211_hw *hw);
eecc48000a Johannes Berg          2011-05-04  3736  #ifdef CONFIG_PM
eecc48000a Johannes Berg          2011-05-04  3737  	int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
eecc48000a Johannes Berg          2011-05-04  3738  	int (*resume)(struct ieee80211_hw *hw);
6d52563f2b Johannes Berg          2012-04-04  3739  	void (*set_wakeup)(struct ieee80211_hw *hw, bool enabled);
eecc48000a Johannes Berg          2011-05-04  3740  #endif
75a5f0ccfd Johannes Berg          2007-09-18  3741  	int (*add_interface)(struct ieee80211_hw *hw,
1ed32e4fc8 Johannes Berg          2009-12-23  3742  			     struct ieee80211_vif *vif);
34d4bc4d41 Johannes Berg          2010-08-27  3743  	int (*change_interface)(struct ieee80211_hw *hw,
34d4bc4d41 Johannes Berg          2010-08-27  3744  				struct ieee80211_vif *vif,
2ca27bcff7 Johannes Berg          2010-09-16  3745  				enum nl80211_iftype new_type, bool p2p);
75a5f0ccfd Johannes Berg          2007-09-18  3746  	void (*remove_interface)(struct ieee80211_hw *hw,
1ed32e4fc8 Johannes Berg          2009-12-23  3747  				 struct ieee80211_vif *vif);
e8975581f6 Johannes Berg          2008-10-09  3748  	int (*config)(struct ieee80211_hw *hw, u32 changed);
471b3efdfc Johannes Berg          2007-12-28  3749  	void (*bss_info_changed)(struct ieee80211_hw *hw,
471b3efdfc Johannes Berg          2007-12-28  3750  				 struct ieee80211_vif *vif,
471b3efdfc Johannes Berg          2007-12-28  3751  				 struct ieee80211_bss_conf *info,
471b3efdfc Johannes Berg          2007-12-28  3752  				 u32 changed);
b2abb6e2bc Johannes Berg          2011-07-19  3753  
1041638f2b Johannes Berg          2012-10-19  3754  	int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
1041638f2b Johannes Berg          2012-10-19  3755  	void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
1041638f2b Johannes Berg          2012-10-19  3756  
3ac64beecd Johannes Berg          2009-08-17  3757  	u64 (*prepare_multicast)(struct ieee80211_hw *hw,
22bedad3ce Jiri Pirko             2010-04-01  3758  				 struct netdev_hw_addr_list *mc_list);
75a5f0ccfd Johannes Berg          2007-09-18  3759  	void (*configure_filter)(struct ieee80211_hw *hw,
75a5f0ccfd Johannes Berg          2007-09-18  3760  				 unsigned int changed_flags,
75a5f0ccfd Johannes Berg          2007-09-18  3761  				 unsigned int *total_flags,
3ac64beecd Johannes Berg          2009-08-17  3762  				 u64 multicast);
1b09b5568e Andrei Otcheretianski  2015-08-15  3763  	void (*config_iface_filter)(struct ieee80211_hw *hw,
1b09b5568e Andrei Otcheretianski  2015-08-15  3764  				    struct ieee80211_vif *vif,
1b09b5568e Andrei Otcheretianski  2015-08-15  3765  				    unsigned int filter_flags,
1b09b5568e Andrei Otcheretianski  2015-08-15  3766  				    unsigned int changed_flags);
17741cdc26 Johannes Berg          2008-09-11  3767  	int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
17741cdc26 Johannes Berg          2008-09-11  3768  		       bool set);
ea49c359f3 Johannes Berg          2007-09-18  3769  	int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
dc822b5db4 Johannes Berg          2008-12-29  3770  		       struct ieee80211_vif *vif, struct ieee80211_sta *sta,
11a843b7e1 Johannes Berg          2007-08-28  3771  		       struct ieee80211_key_conf *key);
9ae4fda332 Emmanuel Grumbach      2008-03-20  3772  	void (*update_tkip_key)(struct ieee80211_hw *hw,
b3fbdcf49f Johannes Berg          2010-01-21  3773  				struct ieee80211_vif *vif,
b3fbdcf49f Johannes Berg          2010-01-21  3774  				struct ieee80211_key_conf *conf,
b3fbdcf49f Johannes Berg          2010-01-21  3775  				struct ieee80211_sta *sta,
9ae4fda332 Emmanuel Grumbach      2008-03-20  3776  				u32 iv32, u16 *phase1key);
c68f4b892c Johannes Berg          2011-07-05  3777  	void (*set_rekey_data)(struct ieee80211_hw *hw,
c68f4b892c Johannes Berg          2011-07-05  3778  			       struct ieee80211_vif *vif,
c68f4b892c Johannes Berg          2011-07-05  3779  			       struct cfg80211_gtk_rekey_data *data);
de5fad8157 Yoni Divinsky          2012-05-30  3780  	void (*set_default_unicast_key)(struct ieee80211_hw *hw,
de5fad8157 Yoni Divinsky          2012-05-30  3781  					struct ieee80211_vif *vif, int idx);
a060bbfe4e Johannes Berg          2010-04-27  3782  	int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
c56ef67250 David Spinadel         2014-02-05  3783  		       struct ieee80211_scan_request *req);
b856439b1b Eliad Peller           2011-06-13  3784  	void (*cancel_hw_scan)(struct ieee80211_hw *hw,
b856439b1b Eliad Peller           2011-06-13  3785  			       struct ieee80211_vif *vif);
79f460ca49 Luciano Coelho         2011-05-11  3786  	int (*sched_scan_start)(struct ieee80211_hw *hw,
79f460ca49 Luciano Coelho         2011-05-11  3787  				struct ieee80211_vif *vif,
79f460ca49 Luciano Coelho         2011-05-11  3788  				struct cfg80211_sched_scan_request *req,
633e271326 David Spinadel         2014-02-06  3789  				struct ieee80211_scan_ies *ies);
37e3308cb2 Johannes Berg          2014-02-17  3790  	int (*sched_scan_stop)(struct ieee80211_hw *hw,
79f460ca49 Luciano Coelho         2011-05-11  3791  			       struct ieee80211_vif *vif);
a344d6778a Johannes Berg          2014-06-12  3792  	void (*sw_scan_start)(struct ieee80211_hw *hw,
a344d6778a Johannes Berg          2014-06-12  3793  			      struct ieee80211_vif *vif,
a344d6778a Johannes Berg          2014-06-12  3794  			      const u8 *mac_addr);
a344d6778a Johannes Berg          2014-06-12  3795  	void (*sw_scan_complete)(struct ieee80211_hw *hw,
a344d6778a Johannes Berg          2014-06-12  3796  				 struct ieee80211_vif *vif);
f0706e828e Jiri Benc              2007-05-05  3797  	int (*get_stats)(struct ieee80211_hw *hw,
f0706e828e Jiri Benc              2007-05-05  3798  			 struct ieee80211_low_level_stats *stats);
9352c19f63 Johannes Berg          2015-04-20  3799  	void (*get_key_seq)(struct ieee80211_hw *hw,
9352c19f63 Johannes Berg          2015-04-20  3800  			    struct ieee80211_key_conf *key,
9352c19f63 Johannes Berg          2015-04-20  3801  			    struct ieee80211_key_seq *seq);
f23a478075 Arik Nemtsov           2010-11-08  3802  	int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
f0706e828e Jiri Benc              2007-05-05  3803  	int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
34e895075e Johannes Berg          2010-02-03  3804  	int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
34e895075e Johannes Berg          2010-02-03  3805  		       struct ieee80211_sta *sta);
34e895075e Johannes Berg          2010-02-03  3806  	int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
34e895075e Johannes Berg          2010-02-03  3807  			  struct ieee80211_sta *sta);
77d2ece6fd Sujith Manoharan       2012-11-20  3808  #ifdef CONFIG_MAC80211_DEBUGFS
77d2ece6fd Sujith Manoharan       2012-11-20  3809  	void (*sta_add_debugfs)(struct ieee80211_hw *hw,
77d2ece6fd Sujith Manoharan       2012-11-20  3810  				struct ieee80211_vif *vif,
77d2ece6fd Sujith Manoharan       2012-11-20  3811  				struct ieee80211_sta *sta,
77d2ece6fd Sujith Manoharan       2012-11-20  3812  				struct dentry *dir);
77d2ece6fd Sujith Manoharan       2012-11-20  3813  #endif
32bfd35d4b Johannes Berg          2007-12-19  3814  	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
17741cdc26 Johannes Berg          2008-09-11  3815  			enum sta_notify_cmd, struct ieee80211_sta *sta);
f6a144eae3 Ashok Raj Nagarajan    2019-03-29  3816  	int (*sta_set_txpwr)(struct ieee80211_hw *hw,
f6a144eae3 Ashok Raj Nagarajan    2019-03-29  3817  			     struct ieee80211_vif *vif,
f6a144eae3 Ashok Raj Nagarajan    2019-03-29  3818  			     struct ieee80211_sta *sta);
f09603a259 Johannes Berg          2012-01-20  3819  	int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
f09603a259 Johannes Berg          2012-01-20  3820  			 struct ieee80211_sta *sta,
f09603a259 Johannes Berg          2012-01-20  3821  			 enum ieee80211_sta_state old_state,
f09603a259 Johannes Berg          2012-01-20  3822  			 enum ieee80211_sta_state new_state);
6a9d1b91f3 Johannes Berg          2013-12-04  3823  	void (*sta_pre_rcu_remove)(struct ieee80211_hw *hw,
6a9d1b91f3 Johannes Berg          2013-12-04  3824  				   struct ieee80211_vif *vif,
6a9d1b91f3 Johannes Berg          2013-12-04  3825  				   struct ieee80211_sta *sta);
8f727ef3c4 Johannes Berg          2012-03-30  3826  	void (*sta_rc_update)(struct ieee80211_hw *hw,
8f727ef3c4 Johannes Berg          2012-03-30  3827  			      struct ieee80211_vif *vif,
8f727ef3c4 Johannes Berg          2012-03-30  3828  			      struct ieee80211_sta *sta,
8f727ef3c4 Johannes Berg          2012-03-30  3829  			      u32 changed);
f815e2b3c0 Johannes Berg          2014-11-19  3830  	void (*sta_rate_tbl_update)(struct ieee80211_hw *hw,
f815e2b3c0 Johannes Berg          2014-11-19  3831  				    struct ieee80211_vif *vif,
f815e2b3c0 Johannes Berg          2014-11-19  3832  				    struct ieee80211_sta *sta);
2b9a7e1bac Johannes Berg          2014-11-17  3833  	void (*sta_statistics)(struct ieee80211_hw *hw,
2b9a7e1bac Johannes Berg          2014-11-17  3834  			       struct ieee80211_vif *vif,
2b9a7e1bac Johannes Berg          2014-11-17  3835  			       struct ieee80211_sta *sta,
2b9a7e1bac Johannes Berg          2014-11-17  3836  			       struct station_info *sinfo);
8a3a3c85e4 Eliad Peller           2011-10-02  3837  	int (*conf_tx)(struct ieee80211_hw *hw,
a3304b0a17 Johannes Berg          2012-03-28  3838  		       struct ieee80211_vif *vif, u16 ac,
f0706e828e Jiri Benc              2007-05-05  3839  		       const struct ieee80211_tx_queue_params *params);
37a41b4aff Eliad Peller           2011-09-21  3840  	u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
37a41b4aff Eliad Peller           2011-09-21  3841  	void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
37a41b4aff Eliad Peller           2011-09-21  3842  			u64 tsf);
354d381baf Pedersen, Thomas       2016-09-28  3843  	void (*offset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
354d381baf Pedersen, Thomas       2016-09-28  3844  			   s64 offset);
37a41b4aff Eliad Peller           2011-09-21  3845  	void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
f0706e828e Jiri Benc              2007-05-05  3846  	int (*tx_last_beacon)(struct ieee80211_hw *hw);
57eeb2086d Johannes Berg          2017-01-13  3847  
57eeb2086d Johannes Berg          2017-01-13  3848  	/**
57eeb2086d Johannes Berg          2017-01-13  3849  	 * @ampdu_action:
57eeb2086d Johannes Berg          2017-01-13  3850  	 * Perform a certain A-MPDU action.
57eeb2086d Johannes Berg          2017-01-13  3851  	 * The RA/TID combination determines the destination and TID we want
57eeb2086d Johannes Berg          2017-01-13  3852  	 * the ampdu action to be performed for. The action is defined through
57eeb2086d Johannes Berg          2017-01-13  3853  	 * ieee80211_ampdu_mlme_action.
57eeb2086d Johannes Berg          2017-01-13  3854  	 * When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
57eeb2086d Johannes Berg          2017-01-13  3855  	 * may neither send aggregates containing more subframes than @buf_size
57eeb2086d Johannes Berg          2017-01-13  3856  	 * nor send aggregates in a way that lost frames would exceed the
57eeb2086d Johannes Berg          2017-01-13  3857  	 * buffer size. If just limiting the aggregate size, this would be
57eeb2086d Johannes Berg          2017-01-13  3858  	 * possible with a buf_size of 8:
57eeb2086d Johannes Berg          2017-01-13  3859  	 *
57eeb2086d Johannes Berg          2017-01-13  3860  	 * - ``TX: 1.....7``
57eeb2086d Johannes Berg          2017-01-13  3861  	 * - ``RX:  2....7`` (lost frame #1)
57eeb2086d Johannes Berg          2017-01-13  3862  	 * - ``TX:        8..1...``
57eeb2086d Johannes Berg          2017-01-13  3863  	 *
57eeb2086d Johannes Berg          2017-01-13  3864  	 * which is invalid since #1 was now re-transmitted well past the
57eeb2086d Johannes Berg          2017-01-13  3865  	 * buffer size of 8. Correct ways to retransmit #1 would be:
57eeb2086d Johannes Berg          2017-01-13  3866  	 *
57eeb2086d Johannes Berg          2017-01-13  3867  	 * - ``TX:        1   or``
57eeb2086d Johannes Berg          2017-01-13  3868  	 * - ``TX:        18  or``
57eeb2086d Johannes Berg          2017-01-13  3869  	 * - ``TX:        81``
57eeb2086d Johannes Berg          2017-01-13  3870  	 *
57eeb2086d Johannes Berg          2017-01-13  3871  	 * Even ``189`` would be wrong since 1 could be lost again.
57eeb2086d Johannes Berg          2017-01-13  3872  	 *
57eeb2086d Johannes Berg          2017-01-13  3873  	 * Returns a negative error code on failure.
57eeb2086d Johannes Berg          2017-01-13  3874  	 * The callback can sleep.
57eeb2086d Johannes Berg          2017-01-13  3875  	 */
1b7d03acbf Ron Rindjunsky         2007-12-25  3876  	int (*ampdu_action)(struct ieee80211_hw *hw,
c951ad3550 Johannes Berg          2009-11-16  3877  			    struct ieee80211_vif *vif,
50ea05efaf Sara Sharon            2015-12-30  3878  			    struct ieee80211_ampdu_params *params);
1289723ef2 Holger Schurig         2010-04-19  3879  	int (*get_survey)(struct ieee80211_hw *hw, int idx,
1289723ef2 Holger Schurig         2010-04-19  3880  		struct survey_info *survey);
1f87f7d3a3 Johannes Berg          2009-06-02  3881  	void (*rfkill_poll)(struct ieee80211_hw *hw);
a4bcaf5556 Lorenzo Bianconi       2014-09-04  3882  	void (*set_coverage_class)(struct ieee80211_hw *hw, s16 coverage_class);
aff89a9b90 Johannes Berg          2009-07-01  3883  #ifdef CONFIG_NL80211_TESTMODE
52981cd794 David Spinadel         2013-07-31  3884  	int (*testmode_cmd)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
52981cd794 David Spinadel         2013-07-31  3885  			    void *data, int len);
71063f0e89 Wey-Yi Guy             2011-05-20  3886  	int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb,
71063f0e89 Wey-Yi Guy             2011-05-20  3887  			     struct netlink_callback *cb,
71063f0e89 Wey-Yi Guy             2011-05-20  3888  			     void *data, int len);
aff89a9b90 Johannes Berg          2009-07-01  3889  #endif
77be2c54c5 Emmanuel Grumbach      2014-03-27  3890  	void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
77be2c54c5 Emmanuel Grumbach      2014-03-27  3891  		      u32 queues, bool drop);
5ce6e438d5 Johannes Berg          2010-05-11  3892  	void (*channel_switch)(struct ieee80211_hw *hw,
0f791eb47f Luciano Coelho         2014-10-08  3893  			       struct ieee80211_vif *vif,
5ce6e438d5 Johannes Berg          2010-05-11  3894  			       struct ieee80211_channel_switch *ch_switch);
15d9675321 Bruno Randolf          2010-11-10  3895  	int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
15d9675321 Bruno Randolf          2010-11-10  3896  	int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
21f8358964 Johannes Berg          2010-12-18  3897  
21f8358964 Johannes Berg          2010-12-18  3898  	int (*remain_on_channel)(struct ieee80211_hw *hw,
4988456862 Eliad Peller           2012-11-19  3899  				 struct ieee80211_vif *vif,
21f8358964 Johannes Berg          2010-12-18  3900  				 struct ieee80211_channel *chan,
d339d5ca8e Ilan Peer              2013-02-12  3901  				 int duration,
d339d5ca8e Ilan Peer              2013-02-12  3902  				 enum ieee80211_roc_type type);
21f8358964 Johannes Berg          2010-12-18  3903  	int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
38c091590f John W. Linville       2011-03-07  3904  	int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
38c091590f John W. Linville       2011-03-07  3905  	void (*get_ringparam)(struct ieee80211_hw *hw,
38c091590f John W. Linville       2011-03-07  3906  			      u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
e8306f9894 Vivek Natarajan        2011-04-06  3907  	bool (*tx_frames_pending)(struct ieee80211_hw *hw);
bdbfd6b582 Sujith Manoharan       2011-04-27  3908  	int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bdbfd6b582 Sujith Manoharan       2011-04-27  3909  				const struct cfg80211_bitrate_mask *mask);
a818292952 Emmanuel Grumbach      2015-03-16  3910  	void (*event_callback)(struct ieee80211_hw *hw,
887da9176e Emmanuel Grumbach      2013-01-20  3911  			       struct ieee80211_vif *vif,
a818292952 Emmanuel Grumbach      2015-03-16  3912  			       const struct ieee80211_event *event);
4049e09acd Johannes Berg          2011-09-29  3913  
40b9640883 Johannes Berg          2011-09-29  3914  	void (*allow_buffered_frames)(struct ieee80211_hw *hw,
40b9640883 Johannes Berg          2011-09-29  3915  				      struct ieee80211_sta *sta,
40b9640883 Johannes Berg          2011-09-29  3916  				      u16 tids, int num_frames,
40b9640883 Johannes Berg          2011-09-29  3917  				      enum ieee80211_frame_release_type reason,
40b9640883 Johannes Berg          2011-09-29  3918  				      bool more_data);
4049e09acd Johannes Berg          2011-09-29  3919  	void (*release_buffered_frames)(struct ieee80211_hw *hw,
4049e09acd Johannes Berg          2011-09-29  3920  					struct ieee80211_sta *sta,
4049e09acd Johannes Berg          2011-09-29  3921  					u16 tids, int num_frames,
4049e09acd Johannes Berg          2011-09-29  3922  					enum ieee80211_frame_release_type reason,
4049e09acd Johannes Berg          2011-09-29  3923  					bool more_data);
e352114fd6 Ben Greear             2012-04-23  3924  
e352114fd6 Ben Greear             2012-04-23  3925  	int	(*get_et_sset_count)(struct ieee80211_hw *hw,
e352114fd6 Ben Greear             2012-04-23  3926  				     struct ieee80211_vif *vif, int sset);
e352114fd6 Ben Greear             2012-04-23  3927  	void	(*get_et_stats)(struct ieee80211_hw *hw,
e352114fd6 Ben Greear             2012-04-23  3928  				struct ieee80211_vif *vif,
e352114fd6 Ben Greear             2012-04-23  3929  				struct ethtool_stats *stats, u64 *data);
e352114fd6 Ben Greear             2012-04-23  3930  	void	(*get_et_strings)(struct ieee80211_hw *hw,
e352114fd6 Ben Greear             2012-04-23  3931  				  struct ieee80211_vif *vif,
e352114fd6 Ben Greear             2012-04-23  3932  				  u32 sset, u8 *data);
a1845fc7c5 Johannes Berg          2012-06-27  3933  
a1845fc7c5 Johannes Berg          2012-06-27  3934  	void	(*mgd_prepare_tx)(struct ieee80211_hw *hw,
d4e36e5554 Ilan Peer              2018-04-20  3935  				  struct ieee80211_vif *vif,
d4e36e5554 Ilan Peer              2018-04-20  3936  				  u16 duration);
c3645eac47 Michal Kazior          2012-06-26  3937  
ee10f2c779 Arik Nemtsov           2014-06-11  3938  	void	(*mgd_protect_tdls_discover)(struct ieee80211_hw *hw,
ee10f2c779 Arik Nemtsov           2014-06-11  3939  					     struct ieee80211_vif *vif);
ee10f2c779 Arik Nemtsov           2014-06-11  3940  
c3645eac47 Michal Kazior          2012-06-26  3941  	int (*add_chanctx)(struct ieee80211_hw *hw,
c3645eac47 Michal Kazior          2012-06-26  3942  			   struct ieee80211_chanctx_conf *ctx);
c3645eac47 Michal Kazior          2012-06-26  3943  	void (*remove_chanctx)(struct ieee80211_hw *hw,
c3645eac47 Michal Kazior          2012-06-26  3944  			       struct ieee80211_chanctx_conf *ctx);
c3645eac47 Michal Kazior          2012-06-26  3945  	void (*change_chanctx)(struct ieee80211_hw *hw,
c3645eac47 Michal Kazior          2012-06-26  3946  			       struct ieee80211_chanctx_conf *ctx,
c3645eac47 Michal Kazior          2012-06-26  3947  			       u32 changed);
c3645eac47 Michal Kazior          2012-06-26  3948  	int (*assign_vif_chanctx)(struct ieee80211_hw *hw,
c3645eac47 Michal Kazior          2012-06-26  3949  				  struct ieee80211_vif *vif,
c3645eac47 Michal Kazior          2012-06-26  3950  				  struct ieee80211_chanctx_conf *ctx);
c3645eac47 Michal Kazior          2012-06-26  3951  	void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
c3645eac47 Michal Kazior          2012-06-26  3952  				     struct ieee80211_vif *vif,
c3645eac47 Michal Kazior          2012-06-26  3953  				     struct ieee80211_chanctx_conf *ctx);
1a5f0c13d1 Luciano Coelho         2014-05-23  3954  	int (*switch_vif_chanctx)(struct ieee80211_hw *hw,
1a5f0c13d1 Luciano Coelho         2014-05-23  3955  				  struct ieee80211_vif_chanctx_switch *vifs,
1a5f0c13d1 Luciano Coelho         2014-05-23  3956  				  int n_vifs,
1a5f0c13d1 Luciano Coelho         2014-05-23  3957  				  enum ieee80211_chanctx_switch_mode mode);
9214ad7f9a Johannes Berg          2012-11-06  3958  
cf2c92d840 Eliad Peller           2014-11-04  3959  	void (*reconfig_complete)(struct ieee80211_hw *hw,
cf2c92d840 Eliad Peller           2014-11-04  3960  				  enum ieee80211_reconfig_type reconfig_type);
a65240c101 Johannes Berg          2013-01-14  3961  
a65240c101 Johannes Berg          2013-01-14  3962  #if IS_ENABLED(CONFIG_IPV6)
a65240c101 Johannes Berg          2013-01-14  3963  	void (*ipv6_addr_change)(struct ieee80211_hw *hw,
a65240c101 Johannes Berg          2013-01-14  3964  				 struct ieee80211_vif *vif,
a65240c101 Johannes Berg          2013-01-14  3965  				 struct inet6_dev *idev);
a65240c101 Johannes Berg          2013-01-14  3966  #endif
73da7d5bab Simon Wunderlich       2013-07-11  3967  	void (*channel_switch_beacon)(struct ieee80211_hw *hw,
73da7d5bab Simon Wunderlich       2013-07-11  3968  				      struct ieee80211_vif *vif,
73da7d5bab Simon Wunderlich       2013-07-11  3969  				      struct cfg80211_chan_def *chandef);
6d027bcc8a Luciano Coelho         2014-10-08  3970  	int (*pre_channel_switch)(struct ieee80211_hw *hw,
6d027bcc8a Luciano Coelho         2014-10-08  3971  				  struct ieee80211_vif *vif,
6d027bcc8a Luciano Coelho         2014-10-08  3972  				  struct ieee80211_channel_switch *ch_switch);
55fff50113 Johannes Berg          2013-08-19  3973  
f1d65583bc Luciano Coelho         2014-10-08  3974  	int (*post_channel_switch)(struct ieee80211_hw *hw,
f1d65583bc Luciano Coelho         2014-10-08  3975  				   struct ieee80211_vif *vif);
b9cc81d827 Sara Sharon            2019-02-06  3976  	void (*abort_channel_switch)(struct ieee80211_hw *hw,
b9cc81d827 Sara Sharon            2019-02-06  3977  				     struct ieee80211_vif *vif);
fafd2bce5a Sara Sharon            2019-02-06  3978  	void (*channel_switch_rx_beacon)(struct ieee80211_hw *hw,
fafd2bce5a Sara Sharon            2019-02-06  3979  					 struct ieee80211_vif *vif,
fafd2bce5a Sara Sharon            2019-02-06  3980  					 struct ieee80211_channel_switch *ch_switch);
f1d65583bc Luciano Coelho         2014-10-08  3981  
55fff50113 Johannes Berg          2013-08-19  3982  	int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
55fff50113 Johannes Berg          2013-08-19  3983  	void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
2439ca0402 Maxim Altshul          2016-08-04  3984  	u32 (*get_expected_throughput)(struct ieee80211_hw *hw,
2439ca0402 Maxim Altshul          2016-08-04  3985  				       struct ieee80211_sta *sta);
5b3dc42b1b Felix Fietkau          2014-10-26  3986  	int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
5b3dc42b1b Felix Fietkau          2014-10-26  3987  			   int *dbm);
a7a6bdd067 Arik Nemtsov           2014-11-09  3988  
a7a6bdd067 Arik Nemtsov           2014-11-09  3989  	int (*tdls_channel_switch)(struct ieee80211_hw *hw,
a7a6bdd067 Arik Nemtsov           2014-11-09  3990  				   struct ieee80211_vif *vif,
a7a6bdd067 Arik Nemtsov           2014-11-09  3991  				   struct ieee80211_sta *sta, u8 oper_class,
a7a6bdd067 Arik Nemtsov           2014-11-09  3992  				   struct cfg80211_chan_def *chandef,
8a4d32f30d Arik Nemtsov           2014-11-09  3993  				   struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie);
a7a6bdd067 Arik Nemtsov           2014-11-09  3994  	void (*tdls_cancel_channel_switch)(struct ieee80211_hw *hw,
a7a6bdd067 Arik Nemtsov           2014-11-09  3995  					   struct ieee80211_vif *vif,
a7a6bdd067 Arik Nemtsov           2014-11-09  3996  					   struct ieee80211_sta *sta);
8a4d32f30d Arik Nemtsov           2014-11-09  3997  	void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw,
8a4d32f30d Arik Nemtsov           2014-11-09  3998  					 struct ieee80211_vif *vif,
8a4d32f30d Arik Nemtsov           2014-11-09  3999  					 struct ieee80211_tdls_ch_sw_params *params);
ba8c3d6f16 Felix Fietkau          2015-03-27  4000  
e7881bd594 Johannes Berg          2017-12-19  4001  	void (*wake_tx_queue)(struct ieee80211_hw *hw,
e7881bd594 Johannes Berg          2017-12-19  4002  			      struct ieee80211_txq *txq);
f59374eb42 Sara Sharon            2016-03-02  4003  	void (*sync_rx_queues)(struct ieee80211_hw *hw);
708d50edb1 Ayala Beker            2016-09-20  4004  
708d50edb1 Ayala Beker            2016-09-20  4005  	int (*start_nan)(struct ieee80211_hw *hw,
708d50edb1 Ayala Beker            2016-09-20  4006  			 struct ieee80211_vif *vif,
708d50edb1 Ayala Beker            2016-09-20  4007  			 struct cfg80211_nan_conf *conf);
708d50edb1 Ayala Beker            2016-09-20  4008  	int (*stop_nan)(struct ieee80211_hw *hw,
708d50edb1 Ayala Beker            2016-09-20  4009  			struct ieee80211_vif *vif);
5953ff6d6a Ayala Beker            2016-09-20  4010  	int (*nan_change_conf)(struct ieee80211_hw *hw,
5953ff6d6a Ayala Beker            2016-09-20  4011  			       struct ieee80211_vif *vif,
5953ff6d6a Ayala Beker            2016-09-20  4012  			       struct cfg80211_nan_conf *conf, u32 changes);
167e33f4f6 Ayala Beker            2016-09-20  4013  	int (*add_nan_func)(struct ieee80211_hw *hw,
167e33f4f6 Ayala Beker            2016-09-20  4014  			    struct ieee80211_vif *vif,
167e33f4f6 Ayala Beker            2016-09-20  4015  			    const struct cfg80211_nan_func *nan_func);
167e33f4f6 Ayala Beker            2016-09-20  4016  	void (*del_nan_func)(struct ieee80211_hw *hw,
167e33f4f6 Ayala Beker            2016-09-20  4017  			    struct ieee80211_vif *vif,
167e33f4f6 Ayala Beker            2016-09-20  4018  			    u8 instance_id);
9739fe29a2 Sara Sharon            2018-09-05  4019  	bool (*can_aggregate_in_amsdu)(struct ieee80211_hw *hw,
9739fe29a2 Sara Sharon            2018-09-05  4020  				       struct sk_buff *head,
9739fe29a2 Sara Sharon            2018-09-05  4021  				       struct sk_buff *skb);
bc847970f4 Pradeep Kumar Chitrapu 2018-10-03  4022  	int (*get_ftm_responder_stats)(struct ieee80211_hw *hw,
bc847970f4 Pradeep Kumar Chitrapu 2018-10-03  4023  				       struct ieee80211_vif *vif,
bc847970f4 Pradeep Kumar Chitrapu 2018-10-03  4024  				       struct cfg80211_ftm_responder_stats *ftm_stats);
cee7013be9 Johannes Berg          2018-10-16  4025  	int (*start_pmsr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
cee7013be9 Johannes Berg          2018-10-16  4026  			  struct cfg80211_pmsr_request *request);
cee7013be9 Johannes Berg          2018-10-16  4027  	void (*abort_pmsr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
cee7013be9 Johannes Berg          2018-10-16  4028  			   struct cfg80211_pmsr_request *request);
f0706e828e Jiri Benc              2007-05-05 @4029  };
f0706e828e Jiri Benc              2007-05-05  4030  

:::::: The code at line 4029 was first introduced by commit
:::::: f0706e828e96d0fa4e80c0d25aa98523f6d589a0 [MAC80211]: Add mac80211 wireless stack.

:::::: TO: Jiri Benc <jbenc@suse.cz>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6589 bytes --]

^ permalink raw reply

* Re: [PATCH] iwlegacy: remove redundant assignment to *res
From: Mukesh Ojha @ 2019-03-31  7:15 UTC (permalink / raw)
  To: Colin King, Stanislaw Gruszka, Kalle Valo, David S . Miller,
	linux-wireless, netdev
  Cc: kernel-janitors, linux-kernel
In-Reply-To: <20190330201422.8024-1-colin.king@canonical.com>


On 3/31/2019 1:44 AM, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Currently 1 is being assigned to *res and then it is immediately
> updated with the computed result.  The first assignment is
> redundant and can be removed.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>

Cheers,
-Mukesh

> ---
>   drivers/net/wireless/intel/iwlegacy/4965.c | 1 -
>   1 file changed, 1 deletion(-)
>
> diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c
> index ce4144a89217..a20b6c885047 100644
> --- a/drivers/net/wireless/intel/iwlegacy/4965.c
> +++ b/drivers/net/wireless/intel/iwlegacy/4965.c
> @@ -577,7 +577,6 @@ il4965_math_div_round(s32 num, s32 denom, s32 * res)
>   		sign = -sign;
>   		denom = -denom;
>   	}
> -	*res = 1;
>   	*res = ((num * 2 + denom) / (denom * 2)) * sign;
>   
>   	return 1;

^ permalink raw reply

* Re: [PATCH v4 1/3] cfg80211: Add support to set tx power for a station associated
From: kbuild test robot @ 2019-03-31  6:00 UTC (permalink / raw)
  To: Balaji Pothunoori
  Cc: kbuild-all, johannes, ath10k, linux-wireless, Ashok Raj Nagarajan,
	Balaji Pothunoori
In-Reply-To: <1553856501-21492-1-git-send-email-bpothuno@codeaurora.org>

[-- Attachment #1: Type: text/plain, Size: 20528 bytes --]

Hi Balaji,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mac80211-next/master]
[also build test WARNING on v5.1-rc2 next-20190329]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Balaji-Pothunoori/cfg80211-Add-support-to-set-tx-power-for-a-station-associated/20190331-104601
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git master
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   WARNING: convert(1) not found, for SVG to PDF conversion install ImageMagick (https://www.imagemagick.org)
   include/linux/rcupdate_wait.h:1: warning: no structured comments found
   include/linux/rcutree.h:1: warning: no structured comments found
   kernel/rcu/tree.c:710: warning: Excess function parameter 'irq' description in 'rcu_nmi_exit'
   include/linux/gfp.h:1: warning: no structured comments found
>> include/net/cfg80211.h:1072: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
   kernel/rcu/tree.c:711: warning: Excess function parameter 'irq' description in 'rcu_nmi_exit'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_excl.active' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.cb' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.poll' not described in 'dma_buf'
   include/linux/dma-buf.h:304: warning: Function parameter or member 'cb_shared.active' not described in 'dma_buf'
   include/linux/dma-fence-array.h:54: warning: Function parameter or member 'work' not described in 'dma_fence_array'
   include/linux/firmware/intel/stratix10-svc-client.h:1: warning: no structured comments found
   include/linux/gpio/driver.h:371: warning: Function parameter or member 'init_valid_mask' not described in 'gpio_chip'
   include/linux/iio/hw-consumer.h:1: warning: no structured comments found
   include/linux/input/sparse-keymap.h:46: warning: Function parameter or member 'sw' not described in 'key_entry'
   include/linux/regulator/machine.h:199: warning: Function parameter or member 'max_uV_step' not described in 'regulation_constraints'
   include/linux/regulator/driver.h:228: warning: Function parameter or member 'resume' not described in 'regulator_ops'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw0' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw1' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw2' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.esw3' not described in 'irb'
   arch/s390/include/asm/cio.h:245: warning: Function parameter or member 'esw.eadm' not described in 'irb'
   drivers/slimbus/stream.c:1: warning: no structured comments found
   include/linux/spi/spi.h:180: warning: Function parameter or member 'driver_override' not described in 'spi_device'
   drivers/target/target_core_device.c:1: warning: no structured comments found
   drivers/usb/typec/bus.c:1: warning: no structured comments found
   drivers/usb/typec/class.c:1: warning: no structured comments found
   include/linux/w1.h:281: warning: Function parameter or member 'of_match_table' not described in 'w1_family'
   fs/direct-io.c:257: warning: Excess function parameter 'offset' description in 'dio_complete'
   fs/file_table.c:1: warning: no structured comments found
   fs/libfs.c:477: warning: Excess function parameter 'available' description in 'simple_write_end'
   fs/posix_acl.c:646: warning: Function parameter or member 'inode' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'mode_p' not described in 'posix_acl_update_mode'
   fs/posix_acl.c:646: warning: Function parameter or member 'acl' not described in 'posix_acl_update_mode'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:294: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:343: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:183: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Function parameter or member 'range' not described in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:295: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_start_hsa'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Function parameter or member 'range' not described in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'mm' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'start' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:344: warning: Excess function parameter 'end' description in 'amdgpu_mn_invalidate_range_end'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:382: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:383: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'end' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:555: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_leaf'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:603: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:847: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1352: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_func'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1519: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_huge'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:3095: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:128: warning: Incorrect use of kernel-doc format: Documentation Makefile include scripts source @atomic_obj
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'atomic_obj_lock' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:203: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: no structured comments found
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_pin' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_unpin' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_res_obj' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_get_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_import_sg_table' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_vmap' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_vunmap' not described in 'drm_driver'
   include/drm/drm_drv.h:618: warning: Function parameter or member 'gem_prime_mmap' not described in 'drm_driver'
   include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
   drivers/gpu/drm/drm_dp_helper.c:1364: warning: Function parameter or member 'dsc_dpcd' not described in 'drm_dp_dsc_sink_max_slice_count'
   drivers/gpu/drm/drm_dp_helper.c:1364: warning: Function parameter or member 'is_edp' not described in 'drm_dp_dsc_sink_max_slice_count'
   drivers/gpu/drm/i915/i915_vma.h:49: warning: cannot understand function prototype: 'struct i915_vma '
   drivers/gpu/drm/i915/i915_vma.h:1: warning: no structured comments found
   drivers/gpu/drm/i915/intel_guc_fwif.h:536: warning: cannot understand function prototype: 'struct guc_log_buffer_state '
   drivers/gpu/drm/i915/i915_trace.h:1: warning: no structured comments found
   include/linux/skbuff.h:876: warning: Function parameter or member 'dev_scratch' not described in 'sk_buff'
   include/linux/skbuff.h:876: warning: Function parameter or member 'list' not described in 'sk_buff'

vim +1072 include/net/cfg80211.h

3b9ce80ce Johannes Berg          2011-09-27   998  
3b9ce80ce Johannes Berg          2011-09-27   999  /**
5727ef1b2 Johannes Berg          2007-12-19  1000   * struct station_parameters - station parameters
5727ef1b2 Johannes Berg          2007-12-19  1001   *
5727ef1b2 Johannes Berg          2007-12-19  1002   * Used to change and create a new station.
5727ef1b2 Johannes Berg          2007-12-19  1003   *
5727ef1b2 Johannes Berg          2007-12-19  1004   * @vlan: vlan interface station should belong to
5727ef1b2 Johannes Berg          2007-12-19  1005   * @supported_rates: supported rates in IEEE 802.11 format
5727ef1b2 Johannes Berg          2007-12-19  1006   *	(or NULL for no change)
5727ef1b2 Johannes Berg          2007-12-19  1007   * @supported_rates_len: number of supported rates
eccb8e8f0 Johannes Berg          2009-05-11  1008   * @sta_flags_mask: station flags that changed
819bf5937 Johannes Berg          2016-10-11  1009   *	(bitmask of BIT(%NL80211_STA_FLAG_...))
eccb8e8f0 Johannes Berg          2009-05-11  1010   * @sta_flags_set: station flags values
819bf5937 Johannes Berg          2016-10-11  1011   *	(bitmask of BIT(%NL80211_STA_FLAG_...))
5727ef1b2 Johannes Berg          2007-12-19  1012   * @listen_interval: listen interval or -1 for no change
5727ef1b2 Johannes Berg          2007-12-19  1013   * @aid: AID or zero for no change
7d27a0ba7 Masashi Honma          2016-07-01  1014   * @peer_aid: mesh peer AID or zero for no change
abe37c4b8 Johannes Berg          2010-06-07  1015   * @plink_action: plink action to take
9c3990aae Javier Cardona         2011-05-03  1016   * @plink_state: set the peer link state for a station
abe37c4b8 Johannes Berg          2010-06-07  1017   * @ht_capa: HT capabilities of station
f461be3ef Mahesh Palivela        2012-10-11  1018   * @vht_capa: VHT capabilities of station
910868db3 Eliad Peller           2011-09-11  1019   * @uapsd_queues: bitmap of queues configured for uapsd. same format
910868db3 Eliad Peller           2011-09-11  1020   *	as the AC bitmap in the QoS info field
910868db3 Eliad Peller           2011-09-11  1021   * @max_sp: max Service Period. same format as the MAX_SP in the
910868db3 Eliad Peller           2011-09-11  1022   *	QoS info field (but already shifted down)
c26887d2a Johannes Berg          2011-11-08  1023   * @sta_modify_mask: bitmap indicating which parameters changed
c26887d2a Johannes Berg          2011-11-08  1024   *	(for those that don't have a natural "no change" value),
c26887d2a Johannes Berg          2011-11-08  1025   *	see &enum station_parameters_apply_mask
3b1c5a530 Marco Porsch           2013-01-07  1026   * @local_pm: local link-specific mesh power save mode (no change when set
3b1c5a530 Marco Porsch           2013-01-07  1027   *	to unknown)
9d62a9861 Jouni Malinen          2013-02-14  1028   * @capability: station capability
9d62a9861 Jouni Malinen          2013-02-14  1029   * @ext_capab: extended capabilities of the station
9d62a9861 Jouni Malinen          2013-02-14  1030   * @ext_capab_len: number of extended capabilities
c01fc9ada Sunil Dutt             2013-10-09  1031   * @supported_channels: supported channels in IEEE 802.11 format
c01fc9ada Sunil Dutt             2013-10-09  1032   * @supported_channels_len: number of supported channels
c01fc9ada Sunil Dutt             2013-10-09  1033   * @supported_oper_classes: supported oper classes in IEEE 802.11 format
c01fc9ada Sunil Dutt             2013-10-09  1034   * @supported_oper_classes_len: number of supported operating classes
60f4a7b16 Marek Kwaczynski       2013-12-03  1035   * @opmode_notif: operating mode field from Operating Mode Notification
60f4a7b16 Marek Kwaczynski       2013-12-03  1036   * @opmode_notif_used: information if operating mode field is used
17b942478 Ayala Beker            2016-03-17  1037   * @support_p2p_ps: information if station supports P2P PS mechanism
c4cbaf797 Luca Coelho            2018-06-09  1038   * @he_capa: HE capabilities of station
c4cbaf797 Luca Coelho            2018-06-09  1039   * @he_capa_len: the length of the HE capabilities
36647055b Toke Høiland-Jørgensen 2018-12-18  1040   * @airtime_weight: airtime scheduler weight for this station
5727ef1b2 Johannes Berg          2007-12-19  1041   */
5727ef1b2 Johannes Berg          2007-12-19  1042  struct station_parameters {
2c1aabf33 Johannes Berg          2013-02-14  1043  	const u8 *supported_rates;
5727ef1b2 Johannes Berg          2007-12-19  1044  	struct net_device *vlan;
eccb8e8f0 Johannes Berg          2009-05-11  1045  	u32 sta_flags_mask, sta_flags_set;
3b9ce80ce Johannes Berg          2011-09-27  1046  	u32 sta_modify_mask;
5727ef1b2 Johannes Berg          2007-12-19  1047  	int listen_interval;
5727ef1b2 Johannes Berg          2007-12-19  1048  	u16 aid;
7d27a0ba7 Masashi Honma          2016-07-01  1049  	u16 peer_aid;
5727ef1b2 Johannes Berg          2007-12-19  1050  	u8 supported_rates_len;
2ec600d67 Luis Carlos Cobo       2008-02-23  1051  	u8 plink_action;
9c3990aae Javier Cardona         2011-05-03  1052  	u8 plink_state;
2c1aabf33 Johannes Berg          2013-02-14  1053  	const struct ieee80211_ht_cap *ht_capa;
2c1aabf33 Johannes Berg          2013-02-14  1054  	const struct ieee80211_vht_cap *vht_capa;
c75786c9e Eliad Peller           2011-08-23  1055  	u8 uapsd_queues;
c75786c9e Eliad Peller           2011-08-23  1056  	u8 max_sp;
3b1c5a530 Marco Porsch           2013-01-07  1057  	enum nl80211_mesh_power_mode local_pm;
9d62a9861 Jouni Malinen          2013-02-14  1058  	u16 capability;
2c1aabf33 Johannes Berg          2013-02-14  1059  	const u8 *ext_capab;
9d62a9861 Jouni Malinen          2013-02-14  1060  	u8 ext_capab_len;
c01fc9ada Sunil Dutt             2013-10-09  1061  	const u8 *supported_channels;
c01fc9ada Sunil Dutt             2013-10-09  1062  	u8 supported_channels_len;
c01fc9ada Sunil Dutt             2013-10-09  1063  	const u8 *supported_oper_classes;
c01fc9ada Sunil Dutt             2013-10-09  1064  	u8 supported_oper_classes_len;
60f4a7b16 Marek Kwaczynski       2013-12-03  1065  	u8 opmode_notif;
60f4a7b16 Marek Kwaczynski       2013-12-03  1066  	bool opmode_notif_used;
17b942478 Ayala Beker            2016-03-17  1067  	int support_p2p_ps;
c4cbaf797 Luca Coelho            2018-06-09  1068  	const struct ieee80211_he_cap_elem *he_capa;
c4cbaf797 Luca Coelho            2018-06-09  1069  	u8 he_capa_len;
36647055b Toke Høiland-Jørgensen 2018-12-18  1070  	u16 airtime_weight;
115e5b332 Ashok Raj Nagarajan    2019-03-29  1071  	struct sta_txpwr txpwr;
5727ef1b2 Johannes Berg          2007-12-19 @1072  };
5727ef1b2 Johannes Berg          2007-12-19  1073  

:::::: The code at line 1072 was first introduced by commit
:::::: 5727ef1b2e797a1922f5bc239b6afb2b4cfb80bc cfg80211/nl80211: station handling

:::::: TO: Johannes Berg <johannes@sipsolutions.net>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6589 bytes --]

^ permalink raw reply

* Spende an dich
From: official @ 2019-03-30  8:19 UTC (permalink / raw)
  To: linux-wireless

4.800.000 € wurden Ihnen von Mavis Wanczyck gespendet, der im Juli 2017 den Powerball-Jackpot in Höhe von 758.700.000 $ gewonnen hat. Wenden Sie sich per E-Mail an mich, um weitere Informationen zur Rücknahme des Fonds zu erhalten--- [wanczykmavis107@gmail.com]

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus


^ permalink raw reply

* [PATCH] iwlegacy: remove redundant assignment to *res
From: Colin King @ 2019-03-30 20:14 UTC (permalink / raw)
  To: Stanislaw Gruszka, Kalle Valo, David S . Miller, linux-wireless,
	netdev
  Cc: kernel-janitors, linux-kernel

From: Colin Ian King <colin.king@canonical.com>

Currently 1 is being assigned to *res and then it is immediately
updated with the computed result.  The first assignment is
redundant and can be removed.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 drivers/net/wireless/intel/iwlegacy/4965.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlegacy/4965.c b/drivers/net/wireless/intel/iwlegacy/4965.c
index ce4144a89217..a20b6c885047 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965.c
@@ -577,7 +577,6 @@ il4965_math_div_round(s32 num, s32 denom, s32 * res)
 		sign = -sign;
 		denom = -denom;
 	}
-	*res = 1;
 	*res = ((num * 2 + denom) / (denom * 2)) * sign;
 
 	return 1;
-- 
2.20.1


^ permalink raw reply related

* Patch for mac80211_hwsim to use multiple BSSID
From: Matej Uhlik @ 2019-03-30 14:22 UTC (permalink / raw)
  To: linux-wireless

Hi,



I need to create patch that will do the following -> enables driver to
respond with ACK to more than just one BSSID targeted frames. This is
idea for SDWN solution namely Odin Wi-5, which works in a way, where
AP is called agent, and is hosting many APs called LVAP(Light Virtual
Access Point). The thing is, that normal AP is responding to one
BSSID, the one that is assigned to him from manufacturer. In this case
I need to make the driver, behaving as AP, respond to more than just
one BSSID. These BSSIDs should be stored in text file.



I am attaching link for ath9k driver, which has done the author of
Odin. You can take this as example, of what am I trying to do here.



https://github.com/Wi5/odin-wi5/blob/master/odin-patch-driver-ath9k/ath9k-bssid-mask.patch



If anyone has any idea, how can I do the same in mac80211_hwsim, I
would be more than happy. I am using Mininet-Wifi which is
incorporating this mac80211_hwsim driver, and thats why I need to
alter patch this driver.



Regards,

Matej.

^ permalink raw reply

* [PATCH] iwlwifi: properly check debugfs dentry before using it
From: Greg Kroah-Hartman @ 2019-03-30  9:31 UTC (permalink / raw)
  To: Luca Coelho
  Cc: Laura Abbott, linux-kernel, Johannes Berg, Emmanuel Grumbach,
	Intel Linux Wireless, Kalle Valo, linux-wireless, Luca Coelho,
	stable
In-Reply-To: <20190330092247.GA14300@kroah.com>

debugfs can now report an error code if something went wrong instead of
just NULL.  So if the return value is to be used as a "real" dentry, it
needs to be checked if it is an error before dereferencing it.

This is now happening because of ff9fb72bc077 ("debugfs: return error
values, not NULL").  If multiple iwlwifi devices are in the system, this
can cause problems when the driver attempts to create the main debugfs
directory again.  Later on in the code we fail horribly by trying to
dereference a pointer that is an error value.

Reported-by: Laura Abbott <labbott@redhat.com>
Cc: Johannes Berg <johannes.berg@intel.com>
Cc: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Cc: Luca Coelho <luciano.coelho@intel.com>
Cc: Intel Linux Wireless <linuxwifi@intel.com>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: stable <stable@vger.kernel.org> # 5.0
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 2453ceabf00d..6925527d8457 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -774,8 +774,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 		return;
 
 	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
-
-	if (!mvmvif->dbgfs_dir) {
+	if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) {
 		IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
 			dbgfs_dir);
 		return;

^ permalink raw reply related

* Re: [PATCH] iwlwifi: mvm: no need to check return value of debugfs_create functions
From: Greg Kroah-Hartman @ 2019-03-30  9:22 UTC (permalink / raw)
  To: Luca Coelho
  Cc: Laura Abbott, linux-kernel, Johannes Berg, Emmanuel Grumbach,
	Intel Linux Wireless, Kalle Valo, linux-wireless
In-Reply-To: <5f9c8beda0e925b079aa9342ce1c9523659837a4.camel@coelho.fi>

On Wed, Mar 27, 2019 at 08:35:37AM +0200, Luca Coelho wrote:
> On Wed, 2019-03-27 at 10:53 +0900, Greg Kroah-Hartman wrote:
> > On Tue, Mar 26, 2019 at 06:47:33PM -0700, Laura Abbott wrote:
> > > On 3/26/19 6:26 PM, Greg Kroah-Hartman wrote:
> > > > On Tue, Mar 26, 2019 at 04:55:54PM -0700, Laura Abbott wrote:
> > > > > On 1/22/19 7:21 AM, Greg Kroah-Hartman wrote:
> > > > > > diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
> > > > > > index 33b0af24a537..c52cdc538678 100644
> > > > > > --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
> > > > > > +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
> > > > > > @@ -1446,9 +1446,8 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
> > > > > >    #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
> > > > > >    	_MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
> > > > > >    #define MVM_DEBUGFS_ADD_FILE_VIF(name, parent, mode) do {		\
> > > > > > -		if (!debugfs_create_file(#name, mode, parent, vif,	\
> > > > > > -					 &iwl_dbgfs_##name##_ops))	\
> > > > > > -			goto err;					\
> > > > > > +		debugfs_create_file(#name, mode, parent, vif,		\
> > > > > > +				    &iwl_dbgfs_##name##_ops);		\
> > > > > >    	} while (0)
> > > > > >    MVM_DEBUGFS_READ_FILE_OPS(mac_params);
> > > > > > @@ -1483,12 +1482,6 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
> > > > > >    	mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
> > > > > > -	if (!mvmvif->dbgfs_dir) {
> > > > > > -		IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n",
> > > > > > -			dbgfs_dir);
> > > > > > -		return;
> > > > > > -	}
> > > > > > -
> > > > > >    	if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM &&
> > > > > >    	    ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) ||
> > > > > >    	     (vif->type == NL80211_IFTYPE_STATION && vif->p2p)))
> > > > > > @@ -1537,12 +1530,6 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
> > > > > >    	mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
> > > > > >    						     mvm->debugfs_dir, buf);
> > > > > > -	if (!mvmvif->dbgfs_slink)
> > > > > > -		IWL_ERR(mvm, "Can't create debugfs symbolic link under %pd\n",
> > > > > > -			dbgfs_dir);
> > > > > > -	return;
> > > > > > -err:
> > > > > > -	IWL_ERR(mvm, "Can't create debugfs entity\n");
> > > > > >    }
> > > > > 
> > > > > Fedora got a bug report https://bugzilla.redhat.com/show_bug.cgi?id=1691034
> > > > > of a crash with 5.0 and the user did a bisect which pointed to ff9fb72bc077
> > > > > ("debugfs: return error values, not NULL") because the error checking is
> > > > > no longer correct in this driver.
> > > > > 
> > > > > Based on https://patchwork.kernel.org/patch/10865839/, it looks like
> > > > > this is supposed to go in for 5.2 but this needs to go in now as
> > > > > the error checking is currently broken without it. Can this get queued
> > > > > for Linus so we can get it in 5.0 stable?
> > > > 
> > > > That's odd, I can't see how the error checking is wrong here.  If the
> > > > directory is not created, an error will be returned, which should be
> > > > able to be handled by debugfs_create_file().
> > > > 
> > > > So with this patch does the error go away?
> > > > 
> > > 
> > > The full patch didn't apply cleanly and I didn't try to backport it
> > > for the reporter to test. I was going off of the theory that if the
> > > patch was there it would fix the problem.
> > > 
> > > What I _think_ is going wrong is dbgfs_dir is actually an errno value:
> > > 
> > > 
> > >         struct dentry *dbgfs_dir = vif->debugfs_dir;
> > >         struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
> > >         char buf[100];
> > > 
> > >         /*
> > >          * Check if debugfs directory already exist before creating it.
> > >          * This may happen when, for example, resetting hw or suspend-resume
> > >          */
> > >         if (!dbgfs_dir || mvmvif->dbgfs_dir)
> > >                 return;
> > > 
> > > 
> > > so this blows up in the snprintf
> > > 
> > >         snprintf(buf, 100, "../../../%pd3/%pd",
> > >                  dbgfs_dir,
> > >                  mvmvif->dbgfs_dir);
> > 
> > Ah, yeah, that's horrible.  They had the name before, why pull it out of
> > the dentry again?  That will blow up hard, but maybe printk should check
> > to see if the pointer really is a pointer first.
> 
> I agree this is ugly.  But do you mean we could use
> ("../../../%pd3/%s", dbgfs_dir, "iwlmvm")? Or how did we have the name?

You "had" the name because you created this directory and name
previously :)

> Also, this would solve the sprintf() problem, but still wouldn't solve
> the real issue, which is not check for ERR in dbgfs_dir.

True.

> > > Unless I misunderstood what the debugfs error change did. I think this
> > > also means the if check needs to look for IS_ERR and not just !dbgfs_dir.
> > 
> > Yes, that is correct.
> 
> Yeah, we can do that.  So this patch doesn't need to be sent for
> v5.1-rc* and v5.0, right? At least I don't see how it would fix the
> issue.  What we need is a new patch with the IS_ERR check.

Ok, let me go create that right now...

thanks,

greg k-h

^ permalink raw reply

* Re: pull-request: iwlwifi-next 2019-02-22
From: Kalle Valo @ 2019-03-30  6:40 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, linuxwifi, david.e.box, joe.konno
In-Reply-To: <8dc374567ff4a1138b5c9605ecc2dc0aeb9bc4bc.camel@coelho.fi>

Luca Coelho <luca@coelho.fi> writes:

> This is the first batch of patches intended for v5.2.  This includes
> the last two patchsets I sent.  Usual development work.  More details
> about the contents in the tag description.
>
> I have sent this out before and kbuildbot reported success.
>
> Please let me know if there are any issues.
>
> Cheers,
> Luca.
>
>
> The following changes since commit 501faf710230b67e470b314868110357cf3a554d:
>
>   Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git (2019-02-28 11:50:40 +0200)
>
> are available in the Git repository at:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git tags/iwlwifi-next-for-kalle-2019-03-22
>
> for you to fetch changes up to fe63f21b20df1adaab90c1839d36ee7c6e4b6ac0:
>
>   iwlwifi: dbg_ini: align to FW api version 1 (2019-03-22 12:59:42 +0200)
>
> ----------------------------------------------------------------
> First batch of patches intended for v5.2
>
> * Send NO_DATA events so they can be captured in radiotap;
> * Some channel-switch changes;
> * Support for multiple BSSID;
> * Continued work and bugfixes for the new debugging infra;
> * Support for some new FW API versions;
> * Some work to support new hardware;
> * General bugfixes;
> * Other cleanups;
>
> ----------------------------------------------------------------

Pulled, thanks Luca.

-- 
Kalle Valo

^ permalink raw reply

* Re: pull-request: iwlwifi-fixes 2019-03-22
From: Kalle Valo @ 2019-03-30  6:36 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, linuxwifi, david.e.box, joe.konno
In-Reply-To: <c1c92313e0ecec1110d60d5624e94c8d75d5e664.camel@coelho.fi>

Luca Coelho <luca@coelho.fi> writes:

> Hi Kalle,
>
> This is the first batch of fixes for v5.1.  More details about the
> contents in the tag description.
>
> I have sent this out before and kbuildbot reported success.
>
> Please let me know if there are any issues.
>
> Cheers,
> Luca.
>
>
> The following changes since commit 7dfc45e6282a7662279d168cc1219929456f8750:
>
>   mt76x02: do not enable RTS/CTS by default (2019-03-19 17:37:25 +0200)
>
> are available in the Git repository at:
>
>   git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes.git tags/iwlwifi-for-kalle-2019-03-22
>
> for you to fetch changes up to 972d8e1377795556024e948357e82532890f2f7d:
>
>   iwlwifi: add new 0x2723/0x2080 card for 22000 (2019-03-22 12:49:05 +0200)
>
> ----------------------------------------------------------------
> First batch of iwlwifi fixes intended for v5.1
>
> * add some new PCI IDs (plus a struct name change they depend on);
> * fix crypto with new devices, namely 22560 and above;
> * a bunch of fixes (and a dependency) for the new debugging infra;
>
> ----------------------------------------------------------------

Pulled, thanks Luca.

-- 
Kalle Valo

^ permalink raw reply

* Re: [PATCH 1/4] mt76: add mac80211 driver for MT7615 PCIe-based chipsets
From: Kalle Valo @ 2019-03-30  6:08 UTC (permalink / raw)
  To: Ryder Lee
  Cc: Lorenzo Bianconi, Felix Fietkau, Roy Luo, Sean Wang, Nelson Chang,
	YF Luo, Kai Lin, Rorscha Yang, Kyle Lee, Miller Shen,
	Haipin Liang, linux-wireless, linux-mediatek, linux-kernel,
	Lorenzo Bianconi
In-Reply-To: <2849359e0b0ede6c13ae9f142aff77a016fd0a80.1553607739.git.ryder.lee@mediatek.com>

Ryder Lee <ryder.lee@mediatek.com> writes:

> This driver is for a newer generation of MediaTek MT7615 4x4 802.11ac
> PCIe-based chipsets, which support wave2 MU-MIMO up to 4 users/group
> and also support up to 160MHz bandwidth.
>
> The driver fully supports AP, station and monitor mode.
>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> Signed-off-by: Roy Luo <royluo@google.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>

[...]

> --- /dev/null
> +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
> @@ -0,0 +1,204 @@
> +// SPDX-License-Identifier: GPL-2.0

mt76 is under ISC so why did you choose GPLv2 here? I don't think it's a
good idea to use different licenses within the same driver.

Also mt76 does not use SPDX tags yet. I would prefer that the whole
driver is converted in one go to have consistent licensing information.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH AUTOSEL 4.19 03/57] rsi: improve kernel thread handling to fix kernel panic
From: Sasha Levin @ 2019-03-30  1:27 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Siva Rebbagondla, Kalle Valo, Sasha Levin, linux-wireless, netdev
In-Reply-To: <20190330012854.32212-1-sashal@kernel.org>

From: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>

[ Upstream commit 4c62764d0fc21a34ffc44eec1210038c3a2e4473 ]

While running regressions, observed below kernel panic when sdio disconnect
called. This is because of, kthread_stop() is taking care of
wait_for_completion() by default. When wait_for_completion triggered
in kthread_stop and as it was done already, giving kernel panic.
Hence, removing redundant wait_for_completion() from rsi_kill_thread().

... skipping ...
BUG: unable to handle kernel NULL pointer dereference at           (null)
IP: [<ffffffff810a63df>] exit_creds+0x1f/0x50
PGD 0
Oops: 0002 [#1] SMP
CPU: 0 PID: 6502 Comm: rmmod Tainted: G  OE   4.15.9-Generic #154-Ubuntu
Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.00 04/17/2017
Stack:
ffff88007392e600 ffff880075847dc0 ffffffff8108160a 0000000000000000
ffff88007392e600 ffff880075847de8 ffffffff810a484b ffff880076127000
ffff88003cd3a800 ffff880074f12a00 ffff880075847e28 ffffffffc09bed15
Call Trace:
[<ffffffff8108160a>] __put_task_struct+0x5a/0x140
[<ffffffff810a484b>] kthread_stop+0x10b/0x110
[<ffffffffc09bed15>] rsi_disconnect+0x2f5/0x300 [ven_rsi_sdio]
[<ffffffff81578bcb>] ? __pm_runtime_resume+0x5b/0x80
[<ffffffff816f0918>] sdio_bus_remove+0x38/0x100
[<ffffffff8156cc64>] __device_release_driver+0xa4/0x150
[<ffffffff8156d7a5>] driver_detach+0xb5/0xc0
[<ffffffff8156c6c5>] bus_remove_driver+0x55/0xd0
[<ffffffff8156dfbc>] driver_unregister+0x2c/0x50
[<ffffffff816f0b8a>] sdio_unregister_driver+0x1a/0x20
[<ffffffffc09bf0f5>] rsi_module_exit+0x15/0x30 [ven_rsi_sdio]
[<ffffffff8110cad8>] SyS_delete_module+0x1b8/0x210
[<ffffffff81851dc8>] entry_SYSCALL_64_fastpath+0x1c/0xbb

Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/net/wireless/rsi/rsi_common.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index d9ff3b8be86e..60f1f286b030 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -75,7 +75,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
 	atomic_inc(&handle->thread_done);
 	rsi_set_event(&handle->event);
 
-	wait_for_completion(&handle->completion);
 	return kthread_stop(handle->task);
 }
 
-- 
2.19.1


^ permalink raw reply related

* [PATCH AUTOSEL 4.14 02/37] rsi: improve kernel thread handling to fix kernel panic
From: Sasha Levin @ 2019-03-30  1:29 UTC (permalink / raw)
  To: linux-kernel, stable
  Cc: Siva Rebbagondla, Kalle Valo, Sasha Levin, linux-wireless, netdev
In-Reply-To: <20190330013020.379-1-sashal@kernel.org>

From: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>

[ Upstream commit 4c62764d0fc21a34ffc44eec1210038c3a2e4473 ]

While running regressions, observed below kernel panic when sdio disconnect
called. This is because of, kthread_stop() is taking care of
wait_for_completion() by default. When wait_for_completion triggered
in kthread_stop and as it was done already, giving kernel panic.
Hence, removing redundant wait_for_completion() from rsi_kill_thread().

... skipping ...
BUG: unable to handle kernel NULL pointer dereference at           (null)
IP: [<ffffffff810a63df>] exit_creds+0x1f/0x50
PGD 0
Oops: 0002 [#1] SMP
CPU: 0 PID: 6502 Comm: rmmod Tainted: G  OE   4.15.9-Generic #154-Ubuntu
Hardware name: Dell Inc. Edge Gateway 3003/ , BIOS 01.00.00 04/17/2017
Stack:
ffff88007392e600 ffff880075847dc0 ffffffff8108160a 0000000000000000
ffff88007392e600 ffff880075847de8 ffffffff810a484b ffff880076127000
ffff88003cd3a800 ffff880074f12a00 ffff880075847e28 ffffffffc09bed15
Call Trace:
[<ffffffff8108160a>] __put_task_struct+0x5a/0x140
[<ffffffff810a484b>] kthread_stop+0x10b/0x110
[<ffffffffc09bed15>] rsi_disconnect+0x2f5/0x300 [ven_rsi_sdio]
[<ffffffff81578bcb>] ? __pm_runtime_resume+0x5b/0x80
[<ffffffff816f0918>] sdio_bus_remove+0x38/0x100
[<ffffffff8156cc64>] __device_release_driver+0xa4/0x150
[<ffffffff8156d7a5>] driver_detach+0xb5/0xc0
[<ffffffff8156c6c5>] bus_remove_driver+0x55/0xd0
[<ffffffff8156dfbc>] driver_unregister+0x2c/0x50
[<ffffffff816f0b8a>] sdio_unregister_driver+0x1a/0x20
[<ffffffffc09bf0f5>] rsi_module_exit+0x15/0x30 [ven_rsi_sdio]
[<ffffffff8110cad8>] SyS_delete_module+0x1b8/0x210
[<ffffffff81851dc8>] entry_SYSCALL_64_fastpath+0x1c/0xbb

Signed-off-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/net/wireless/rsi/rsi_common.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h
index e579d694d13c..21986ba56a3c 100644
--- a/drivers/net/wireless/rsi/rsi_common.h
+++ b/drivers/net/wireless/rsi/rsi_common.h
@@ -74,7 +74,6 @@ static inline int rsi_kill_thread(struct rsi_thread *handle)
 	atomic_inc(&handle->thread_done);
 	rsi_set_event(&handle->event);
 
-	wait_for_completion(&handle->completion);
 	return kthread_stop(handle->task);
 }
 
-- 
2.19.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox