git: 6c92544d7c97 - main - mt76: import mediatek/mt76 driver

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Sun, 23 Apr 2023 21:31:36 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=6c92544d7c9722a3fe6263134938d1f864c158c5

commit 6c92544d7c9722a3fe6263134938d1f864c158c5
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2023-04-18 14:26:38 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2023-04-23 21:29:49 +0000

    mt76: import mediatek/mt76 driver
    
    Import ISC-licensed driver parts of mediatek/mt76
    assumed to be based on Linux wireless-testing at
    a02411a5b98612c12be99349836d99f07db12a77 (tag: wt-2022-11-23).
    
    Complement the driver and LinuxKPI with our own (dummy)
    implementations of missing parts (util.h and soc/mediatek/)
    as well as changes to make compile on FreeBSD with changes
    covered by #ifdef (__FreeBSD__) conditions.
    Further select updates were applied since the initial import
    in order to keep compiling along with other LinuxKPI based
    drivers.
    
    For the moment we only target the mt7915 and mt7921 PCI parts.
    More may follow in the future.
    
    Firmware is provided by port net/wifi-firmware-mt76-kmod.
    
    Given the lack of full license texts on non-local files this is
    imported under the draft policy for handling SPDX files (D29226). [1]
    
    Approved by:    core (emaste, 2022-04-08) [1]
    MFC after:      2 months
---
 .../common/include/linux/soc/mediatek/mtk_wed.h    |   48 +
 sys/contrib/dev/mediatek/mt76/agg-rx.c             |  301 ++
 sys/contrib/dev/mediatek/mt76/debugfs.c            |  147 +
 sys/contrib/dev/mediatek/mt76/dma.c                |  826 +++++
 sys/contrib/dev/mediatek/mt76/dma.h                |   52 +
 sys/contrib/dev/mediatek/mt76/eeprom.c             |  373 +++
 sys/contrib/dev/mediatek/mt76/mac80211.c           | 1712 ++++++++++
 sys/contrib/dev/mediatek/mt76/mcu.c                |  138 +
 sys/contrib/dev/mediatek/mt76/mmio.c               |  121 +
 sys/contrib/dev/mediatek/mt76/mt76.h               | 1472 +++++++++
 sys/contrib/dev/mediatek/mt76/mt7603/beacon.c      |  190 ++
 sys/contrib/dev/mediatek/mt76/mt7603/core.c        |   65 +
 sys/contrib/dev/mediatek/mt76/mt7603/debugfs.c     |  118 +
 sys/contrib/dev/mediatek/mt76/mt7603/dma.c         |  241 ++
 sys/contrib/dev/mediatek/mt76/mt7603/eeprom.c      |  187 ++
 sys/contrib/dev/mediatek/mt76/mt7603/eeprom.h      |   91 +
 sys/contrib/dev/mediatek/mt76/mt7603/init.c        |  562 ++++
 sys/contrib/dev/mediatek/mt76/mt7603/mac.c         | 1878 +++++++++++
 sys/contrib/dev/mediatek/mt76/mt7603/mac.h         |  242 ++
 sys/contrib/dev/mediatek/mt76/mt7603/main.c        |  755 +++++
 sys/contrib/dev/mediatek/mt76/mt7603/mcu.c         |  433 +++
 sys/contrib/dev/mediatek/mt76/mt7603/mcu.h         |  103 +
 sys/contrib/dev/mediatek/mt76/mt7603/mt7603.h      |  265 ++
 sys/contrib/dev/mediatek/mt76/mt7603/pci.c         |   83 +
 sys/contrib/dev/mediatek/mt76/mt7603/regs.h        |  768 +++++
 sys/contrib/dev/mediatek/mt76/mt7603/soc.c         |   82 +
 sys/contrib/dev/mediatek/mt76/mt7615/Makefile      |   20 +
 sys/contrib/dev/mediatek/mt76/mt7615/debugfs.c     |  611 ++++
 sys/contrib/dev/mediatek/mt76/mt7615/dma.c         |  315 ++
 sys/contrib/dev/mediatek/mt76/mt7615/eeprom.c      |  353 ++
 sys/contrib/dev/mediatek/mt76/mt7615/eeprom.h      |  116 +
 sys/contrib/dev/mediatek/mt76/mt7615/init.c        |  561 ++++
 sys/contrib/dev/mediatek/mt76/mt7615/mac.c         | 2383 +++++++++++++
 sys/contrib/dev/mediatek/mt76/mt7615/mac.h         |  337 ++
 sys/contrib/dev/mediatek/mt76/mt7615/main.c        | 1347 ++++++++
 sys/contrib/dev/mediatek/mt76/mt7615/mcu.c         | 2570 ++++++++++++++
 sys/contrib/dev/mediatek/mt76/mt7615/mcu.h         |  254 ++
 sys/contrib/dev/mediatek/mt76/mt7615/mmio.c        |  292 ++
 sys/contrib/dev/mediatek/mt76/mt7615/mt7615.h      |  565 ++++
 .../dev/mediatek/mt76/mt7615/mt7615_trace.h        |   56 +
 sys/contrib/dev/mediatek/mt76/mt7615/pci.c         |  202 ++
 sys/contrib/dev/mediatek/mt76/mt7615/pci_init.c    |  186 ++
 sys/contrib/dev/mediatek/mt76/mt7615/pci_mac.c     |  293 ++
 sys/contrib/dev/mediatek/mt76/mt7615/regs.h        |  609 ++++
 sys/contrib/dev/mediatek/mt76/mt7615/sdio.c        |  257 ++
 sys/contrib/dev/mediatek/mt76/mt7615/soc.c         |   72 +
 sys/contrib/dev/mediatek/mt76/mt7615/testmode.c    |  376 +++
 sys/contrib/dev/mediatek/mt76/mt7615/trace.c       |   12 +
 sys/contrib/dev/mediatek/mt76/mt7615/usb.c         |  285 ++
 sys/contrib/dev/mediatek/mt76/mt7615/usb_sdio.c    |  352 ++
 sys/contrib/dev/mediatek/mt76/mt76_connac.h        |  371 +++
 sys/contrib/dev/mediatek/mt76/mt76_connac2_mac.h   |  331 ++
 sys/contrib/dev/mediatek/mt76/mt76_connac_mac.c    | 1059 ++++++
 sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.c    | 3129 ++++++++++++++++++
 sys/contrib/dev/mediatek/mt76/mt76_connac_mcu.h    | 1821 ++++++++++
 sys/contrib/dev/mediatek/mt76/mt76x0/pci.c         |  318 ++
 sys/contrib/dev/mediatek/mt76/mt76x0/pci_mcu.c     |  133 +
 sys/contrib/dev/mediatek/mt76/mt76x0/usb_mcu.c     |  174 +
 sys/contrib/dev/mediatek/mt76/mt76x02.h            |  273 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_beacon.c     |  217 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_debugfs.c    |  140 +
 sys/contrib/dev/mediatek/mt76/mt76x02_dfs.c        |  892 +++++
 sys/contrib/dev/mediatek/mt76/mt76x02_dfs.h        |  132 +
 sys/contrib/dev/mediatek/mt76/mt76x02_dma.h        |   65 +
 sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.c     |  154 +
 sys/contrib/dev/mediatek/mt76/mt76x02_eeprom.h     |  187 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_mac.c        | 1236 +++++++
 sys/contrib/dev/mediatek/mt76/mt76x02_mac.h        |  208 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_mcu.c        |  171 +
 sys/contrib/dev/mediatek/mt76/mt76x02_mcu.h        |  100 +
 sys/contrib/dev/mediatek/mt76/mt76x02_mmio.c       |  556 ++++
 sys/contrib/dev/mediatek/mt76/mt76x02_phy.c        |  204 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_phy.h        |   49 +
 sys/contrib/dev/mediatek/mt76/mt76x02_regs.h       |  708 ++++
 sys/contrib/dev/mediatek/mt76/mt76x02_trace.c      |   12 +
 sys/contrib/dev/mediatek/mt76/mt76x02_trace.h      |   87 +
 sys/contrib/dev/mediatek/mt76/mt76x02_txrx.c       |  183 +
 sys/contrib/dev/mediatek/mt76/mt76x02_usb.h        |   25 +
 sys/contrib/dev/mediatek/mt76/mt76x02_usb_core.c   |  282 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_usb_mcu.c    |  296 ++
 sys/contrib/dev/mediatek/mt76/mt76x02_util.c       |  700 ++++
 sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.c      |  512 +++
 sys/contrib/dev/mediatek/mt76/mt76x2/eeprom.h      |   83 +
 sys/contrib/dev/mediatek/mt76/mt76x2/init.c        |  204 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/mac.c         |   46 +
 sys/contrib/dev/mediatek/mt76/mt76x2/mac.h         |   24 +
 sys/contrib/dev/mediatek/mt76/mt76x2/mcu.c         |  108 +
 sys/contrib/dev/mediatek/mt76/mt76x2/mcu.h         |   68 +
 sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2.h      |   80 +
 sys/contrib/dev/mediatek/mt76/mt76x2/mt76x2u.h     |   43 +
 sys/contrib/dev/mediatek/mt76/mt76x2/pci.c         |  181 +
 sys/contrib/dev/mediatek/mt76/mt76x2/pci_init.c    |  320 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/pci_main.c    |  164 +
 sys/contrib/dev/mediatek/mt76/mt76x2/pci_mcu.c     |  198 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/pci_phy.c     |  311 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/phy.c         |  349 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/usb.c         |  150 +
 sys/contrib/dev/mediatek/mt76/mt76x2/usb_init.c    |  250 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/usb_mac.c     |  174 +
 sys/contrib/dev/mediatek/mt76/mt76x2/usb_main.c    |  129 +
 sys/contrib/dev/mediatek/mt76/mt76x2/usb_mcu.c     |  255 ++
 sys/contrib/dev/mediatek/mt76/mt76x2/usb_phy.c     |  201 ++
 sys/contrib/dev/mediatek/mt76/mt7915/Kconfig       |   24 +
 sys/contrib/dev/mediatek/mt76/mt7915/Makefile      |    9 +
 sys/contrib/dev/mediatek/mt76/mt7915/debugfs.c     | 1188 +++++++
 sys/contrib/dev/mediatek/mt76/mt7915/dma.c         |  487 +++
 sys/contrib/dev/mediatek/mt76/mt7915/eeprom.c      |  354 ++
 sys/contrib/dev/mediatek/mt76/mt7915/eeprom.h      |  165 +
 sys/contrib/dev/mediatek/mt76/mt7915/init.c        | 1184 +++++++
 sys/contrib/dev/mediatek/mt76/mt7915/mac.c         | 2199 ++++++++++++
 sys/contrib/dev/mediatek/mt76/mt7915/mac.h         |  101 +
 sys/contrib/dev/mediatek/mt76/mt7915/main.c        | 1493 +++++++++
 sys/contrib/dev/mediatek/mt76/mt7915/mcu.c         | 3492 ++++++++++++++++++++
 sys/contrib/dev/mediatek/mt76/mt7915/mcu.h         |  477 +++
 sys/contrib/dev/mediatek/mt76/mt7915/mmio.c        |  729 ++++
 sys/contrib/dev/mediatek/mt76/mt7915/mt7915.h      |  594 ++++
 sys/contrib/dev/mediatek/mt76/mt7915/pci.c         |  355 ++
 sys/contrib/dev/mediatek/mt76/mt7915/regs.h        | 1116 +++++++
 sys/contrib/dev/mediatek/mt76/mt7915/soc.c         | 1243 +++++++
 sys/contrib/dev/mediatek/mt76/mt7915/testmode.c    |  789 +++++
 sys/contrib/dev/mediatek/mt76/mt7915/testmode.h    |  105 +
 sys/contrib/dev/mediatek/mt76/mt7921/Kconfig       |   37 +
 sys/contrib/dev/mediatek/mt76/mt7921/Makefile      |   15 +
 sys/contrib/dev/mediatek/mt76/mt7921/debugfs.c     |  461 +++
 sys/contrib/dev/mediatek/mt76/mt7921/dma.c         |  317 ++
 sys/contrib/dev/mediatek/mt76/mt7921/eeprom.h      |   30 +
 sys/contrib/dev/mediatek/mt76/mt7921/init.c        |  330 ++
 sys/contrib/dev/mediatek/mt76/mt7921/mac.c         | 1262 +++++++
 sys/contrib/dev/mediatek/mt76/mt7921/mac.h         |   53 +
 sys/contrib/dev/mediatek/mt76/mt7921/main.c        | 1628 +++++++++
 sys/contrib/dev/mediatek/mt76/mt7921/mcu.c         | 1143 +++++++
 sys/contrib/dev/mediatek/mt76/mt7921/mcu.h         |  113 +
 sys/contrib/dev/mediatek/mt76/mt7921/mt7921.h      |  513 +++
 .../dev/mediatek/mt76/mt7921/mt7921_trace.h        |   51 +
 sys/contrib/dev/mediatek/mt76/mt7921/pci.c         |  514 +++
 sys/contrib/dev/mediatek/mt76/mt7921/pci_mac.c     |  142 +
 sys/contrib/dev/mediatek/mt76/mt7921/pci_mcu.c     |  129 +
 sys/contrib/dev/mediatek/mt76/mt7921/regs.h        |  526 +++
 sys/contrib/dev/mediatek/mt76/mt7921/sdio.c        |  319 ++
 sys/contrib/dev/mediatek/mt76/mt7921/sdio_mac.c    |  142 +
 sys/contrib/dev/mediatek/mt76/mt7921/sdio_mcu.c    |  175 +
 sys/contrib/dev/mediatek/mt76/mt7921/testmode.c    |  197 ++
 sys/contrib/dev/mediatek/mt76/mt7921/trace.c       |   12 +
 sys/contrib/dev/mediatek/mt76/mt7921/usb.c         |  386 +++
 sys/contrib/dev/mediatek/mt76/mt7921/usb_mac.c     |  255 ++
 sys/contrib/dev/mediatek/mt76/pci.c                |   47 +
 sys/contrib/dev/mediatek/mt76/sdio.c               |  667 ++++
 sys/contrib/dev/mediatek/mt76/sdio.h               |  140 +
 sys/contrib/dev/mediatek/mt76/sdio_txrx.c          |  380 +++
 sys/contrib/dev/mediatek/mt76/testmode.c           |  675 ++++
 sys/contrib/dev/mediatek/mt76/testmode.h           |  200 ++
 sys/contrib/dev/mediatek/mt76/trace.c              |   15 +
 sys/contrib/dev/mediatek/mt76/trace.h              |  111 +
 sys/contrib/dev/mediatek/mt76/tx.c                 |  786 +++++
 sys/contrib/dev/mediatek/mt76/usb.c                | 1130 +++++++
 sys/contrib/dev/mediatek/mt76/usb_trace.c          |   12 +
 sys/contrib/dev/mediatek/mt76/usb_trace.h          |   86 +
 sys/contrib/dev/mediatek/mt76/util.c               |  150 +
 sys/contrib/dev/mediatek/mt76/util.h               |  162 +
 159 files changed, 71155 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
new file mode 100644
index 000000000000..1205d7ea32b0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H
+#define	_LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H
+
+struct mtk_wed_device {
+};
+
+#define	mtk_wed_device_start(_dev, _mask)		do { } while(0)
+#define	mtk_wed_device_detach(_dev)			do { } while(0)
+#define	mtk_wed_device_irq_get(_dev, _mask)		0
+#define	mtk_wed_device_irq_set_mask(_dev, _mask)	do { } while(0)
+
+static inline bool
+mtk_wed_device_active(struct mtk_wed_device *dev __unused)
+{
+
+	return (false);
+}
+
+#endif	/* _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H */
diff --git a/sys/contrib/dev/mediatek/mt76/agg-rx.c b/sys/contrib/dev/mediatek/mt76/agg-rx.c
new file mode 100644
index 000000000000..10cbd9e560e7
--- /dev/null
+++ b/sys/contrib/dev/mediatek/mt76/agg-rx.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
+ */
+#include "mt76.h"
+
+static unsigned long mt76_aggr_tid_to_timeo(u8 tidno)
+{
+	/* Currently voice traffic (AC_VO) always runs without aggregation,
+	 * no special handling is needed. AC_BE/AC_BK use tids 0-3. Just check
+	 * for non AC_BK/AC_BE and set smaller timeout for it. */
+	return HZ / (tidno >= 4 ? 25 : 10);
+}
+
+static void
+mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx)
+{
+	struct sk_buff *skb;
+
+	tid->head = ieee80211_sn_inc(tid->head);
+
+	skb = tid->reorder_buf[idx];
+	if (!skb)
+		return;
+
+	tid->reorder_buf[idx] = NULL;
+	tid->nframes--;
+	__skb_queue_tail(frames, skb);
+}
+
+static void
+mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid,
+			    struct sk_buff_head *frames,
+			    u16 head)
+{
+	int idx;
+
+	while (ieee80211_sn_less(tid->head, head)) {
+		idx = tid->head % tid->size;
+		mt76_aggr_release(tid, frames, idx);
+	}
+}
+
+static void
+mt76_rx_aggr_release_head(struct mt76_rx_tid *tid, struct sk_buff_head *frames)
+{
+	int idx = tid->head % tid->size;
+
+	while (tid->reorder_buf[idx]) {
+		mt76_aggr_release(tid, frames, idx);
+		idx = tid->head % tid->size;
+	}
+}
+
+static void
+mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames)
+{
+	struct mt76_rx_status *status;
+	struct sk_buff *skb;
+	int start, idx, nframes;
+
+	if (!tid->nframes)
+		return;
+
+	mt76_rx_aggr_release_head(tid, frames);
+
+	start = tid->head % tid->size;
+	nframes = tid->nframes;
+
+	for (idx = (tid->head + 1) % tid->size;
+	     idx != start && nframes;
+	     idx = (idx + 1) % tid->size) {
+		skb = tid->reorder_buf[idx];
+		if (!skb)
+			continue;
+
+		nframes--;
+		status = (struct mt76_rx_status *)skb->cb;
+		if (!time_after32(jiffies,
+				  status->reorder_time +
+				  mt76_aggr_tid_to_timeo(tid->num)))
+			continue;
+
+		mt76_rx_aggr_release_frames(tid, frames, status->seqno);
+	}
+
+	mt76_rx_aggr_release_head(tid, frames);
+}
+
+static void
+mt76_rx_aggr_reorder_work(struct work_struct *work)
+{
+	struct mt76_rx_tid *tid = container_of(work, struct mt76_rx_tid,
+					       reorder_work.work);
+	struct mt76_dev *dev = tid->dev;
+	struct sk_buff_head frames;
+	int nframes;
+
+	__skb_queue_head_init(&frames);
+
+	local_bh_disable();
+	rcu_read_lock();
+
+	spin_lock(&tid->lock);
+	mt76_rx_aggr_check_release(tid, &frames);
+	nframes = tid->nframes;
+	spin_unlock(&tid->lock);
+
+	if (nframes)
+		ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work,
+					     mt76_aggr_tid_to_timeo(tid->num));
+	mt76_rx_complete(dev, &frames, NULL);
+
+	rcu_read_unlock();
+	local_bh_enable();
+}
+
+static void
+mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct ieee80211_bar *bar = mt76_skb_get_hdr(skb);
+	struct mt76_wcid *wcid = status->wcid;
+	struct mt76_rx_tid *tid;
+	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
+	u16 seqno;
+
+	if (!ieee80211_is_ctl(bar->frame_control))
+		return;
+
+	if (!ieee80211_is_back_req(bar->frame_control))
+		return;
+
+	status->qos_ctl = tidno = le16_to_cpu(bar->control) >> 12;
+	seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
+	tid = rcu_dereference(wcid->aggr[tidno]);
+	if (!tid)
+		return;
+
+	spin_lock_bh(&tid->lock);
+	if (!tid->stopped) {
+		mt76_rx_aggr_release_frames(tid, frames, seqno);
+		mt76_rx_aggr_release_head(tid, frames);
+	}
+	spin_unlock_bh(&tid->lock);
+}
+
+void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)
+{
+	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+	struct mt76_wcid *wcid = status->wcid;
+	struct ieee80211_sta *sta;
+	struct mt76_rx_tid *tid;
+	bool sn_less;
+	u16 seqno, head, size, idx;
+	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
+	u8 ackp;
+
+	__skb_queue_tail(frames, skb);
+
+	sta = wcid_to_sta(wcid);
+	if (!sta)
+		return;
+
+	if (!status->aggr) {
+		if (!(status->flag & RX_FLAG_8023))
+			mt76_rx_aggr_check_ctl(skb, frames);
+		return;
+	}
+
+	/* not part of a BA session */
+	ackp = status->qos_ctl & IEEE80211_QOS_CTL_ACK_POLICY_MASK;
+	if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK)
+		return;
+
+	tid = rcu_dereference(wcid->aggr[tidno]);
+	if (!tid)
+		return;
+
+	status->flag |= RX_FLAG_DUP_VALIDATED;
+	spin_lock_bh(&tid->lock);
+
+	if (tid->stopped)
+		goto out;
+
+	head = tid->head;
+	seqno = status->seqno;
+	size = tid->size;
+	sn_less = ieee80211_sn_less(seqno, head);
+
+	if (!tid->started) {
+		if (sn_less)
+			goto out;
+
+		tid->started = true;
+	}
+
+	if (sn_less) {
+		__skb_unlink(skb, frames);
+		dev_kfree_skb(skb);
+		goto out;
+	}
+
+	if (seqno == head) {
+		tid->head = ieee80211_sn_inc(head);
+		if (tid->nframes)
+			mt76_rx_aggr_release_head(tid, frames);
+		goto out;
+	}
+
+	__skb_unlink(skb, frames);
+
+	/*
+	 * Frame sequence number exceeds buffering window, free up some space
+	 * by releasing previous frames
+	 */
+	if (!ieee80211_sn_less(seqno, head + size)) {
+		head = ieee80211_sn_inc(ieee80211_sn_sub(seqno, size));
+		mt76_rx_aggr_release_frames(tid, frames, head);
+	}
+
+	idx = seqno % size;
+
+	/* Discard if the current slot is already in use */
+	if (tid->reorder_buf[idx]) {
+		dev_kfree_skb(skb);
+		goto out;
+	}
+
+	status->reorder_time = jiffies;
+	tid->reorder_buf[idx] = skb;
+	tid->nframes++;
+	mt76_rx_aggr_release_head(tid, frames);
+
+	ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work,
+				     mt76_aggr_tid_to_timeo(tid->num));
+
+out:
+	spin_unlock_bh(&tid->lock);
+}
+
+int mt76_rx_aggr_start(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno,
+		       u16 ssn, u16 size)
+{
+	struct mt76_rx_tid *tid;
+
+	mt76_rx_aggr_stop(dev, wcid, tidno);
+
+	tid = kzalloc(struct_size(tid, reorder_buf, size), GFP_KERNEL);
+	if (!tid)
+		return -ENOMEM;
+
+	tid->dev = dev;
+	tid->head = ssn;
+	tid->size = size;
+	tid->num = tidno;
+	INIT_DELAYED_WORK(&tid->reorder_work, mt76_rx_aggr_reorder_work);
+	spin_lock_init(&tid->lock);
+
+	rcu_assign_pointer(wcid->aggr[tidno], tid);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_rx_aggr_start);
+
+static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid)
+{
+	u16 size = tid->size;
+	int i;
+
+	spin_lock_bh(&tid->lock);
+
+	tid->stopped = true;
+	for (i = 0; tid->nframes && i < size; i++) {
+		struct sk_buff *skb = tid->reorder_buf[i];
+
+		if (!skb)
+			continue;
+
+		tid->reorder_buf[i] = NULL;
+		tid->nframes--;
+		dev_kfree_skb(skb);
+	}
+
+	spin_unlock_bh(&tid->lock);
+
+	cancel_delayed_work_sync(&tid->reorder_work);
+}
+
+void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno)
+{
+	struct mt76_rx_tid *tid = NULL;
+
+	tid = rcu_replace_pointer(wcid->aggr[tidno], tid,
+				  lockdep_is_held(&dev->mutex));
+	if (tid) {
+		mt76_rx_aggr_shutdown(dev, tid);
+		kfree_rcu(tid, rcu_head);
+	}
+}
+EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop);
diff --git a/sys/contrib/dev/mediatek/mt76/debugfs.c b/sys/contrib/dev/mediatek/mt76/debugfs.c
new file mode 100644
index 000000000000..47e9911ee9fe
--- /dev/null
+++ b/sys/contrib/dev/mediatek/mt76/debugfs.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ */
+#include "mt76.h"
+
+static int
+mt76_reg_set(void *data, u64 val)
+{
+	struct mt76_dev *dev = data;
+
+	__mt76_wr(dev, dev->debugfs_reg, val);
+	return 0;
+}
+
+static int
+mt76_reg_get(void *data, u64 *val)
+{
+	struct mt76_dev *dev = data;
+
+	*val = __mt76_rr(dev, dev->debugfs_reg);
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set,
+			 "0x%08llx\n");
+
+static int
+mt76_napi_threaded_set(void *data, u64 val)
+{
+	struct mt76_dev *dev = data;
+
+	if (!mt76_is_mmio(dev))
+		return -EOPNOTSUPP;
+
+	if (dev->napi_dev.threaded != val)
+		return dev_set_threaded(&dev->napi_dev, val);
+
+	return 0;
+}
+
+static int
+mt76_napi_threaded_get(void *data, u64 *val)
+{
+	struct mt76_dev *dev = data;
+
+	*val = dev->napi_dev.threaded;
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_napi_threaded, mt76_napi_threaded_get,
+			 mt76_napi_threaded_set, "%llu\n");
+
+int mt76_queues_read(struct seq_file *s, void *data)
+{
+	struct mt76_dev *dev = dev_get_drvdata(s->private);
+	int i;
+
+	seq_puts(s, "     queue | hw-queued |      head |      tail |\n");
+	for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
+		struct mt76_queue *q = dev->phy.q_tx[i];
+
+		if (!q)
+			continue;
+
+		seq_printf(s, " %9d | %9d | %9d | %9d |\n",
+			   i, q->queued, q->head, q->tail);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_queues_read);
+
+static int mt76_rx_queues_read(struct seq_file *s, void *data)
+{
+	struct mt76_dev *dev = dev_get_drvdata(s->private);
+	int i, queued;
+
+	seq_puts(s, "     queue | hw-queued |      head |      tail |\n");
+	mt76_for_each_q_rx(dev, i) {
+		struct mt76_queue *q = &dev->q_rx[i];
+
+		queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued;
+		seq_printf(s, " %9d | %9d | %9d | %9d |\n",
+			   i, queued, q->head, q->tail);
+	}
+
+	return 0;
+}
+
+void mt76_seq_puts_array(struct seq_file *file, const char *str,
+			 s8 *val, int len)
+{
+	int i;
+
+	seq_printf(file, "%10s:", str);
+	for (i = 0; i < len; i++)
+		seq_printf(file, " %2d", val[i]);
+	seq_puts(file, "\n");
+}
+EXPORT_SYMBOL_GPL(mt76_seq_puts_array);
+
+static int mt76_read_rate_txpower(struct seq_file *s, void *data)
+{
+	struct mt76_dev *dev = dev_get_drvdata(s->private);
+
+	mt76_seq_puts_array(s, "CCK", dev->rate_power.cck,
+			    ARRAY_SIZE(dev->rate_power.cck));
+	mt76_seq_puts_array(s, "OFDM", dev->rate_power.ofdm,
+			    ARRAY_SIZE(dev->rate_power.ofdm));
+	mt76_seq_puts_array(s, "STBC", dev->rate_power.stbc,
+			    ARRAY_SIZE(dev->rate_power.stbc));
+	mt76_seq_puts_array(s, "HT", dev->rate_power.ht,
+			    ARRAY_SIZE(dev->rate_power.ht));
+	mt76_seq_puts_array(s, "VHT", dev->rate_power.vht,
+			    ARRAY_SIZE(dev->rate_power.vht));
+	return 0;
+}
+
+struct dentry *
+mt76_register_debugfs_fops(struct mt76_phy *phy,
+			   const struct file_operations *ops)
+{
+	const struct file_operations *fops = ops ? ops : &fops_regval;
+	struct mt76_dev *dev = phy->dev;
+	struct dentry *dir;
+
+	dir = debugfs_create_dir("mt76", phy->hw->wiphy->debugfsdir);
+	if (!dir)
+		return NULL;
+
+	debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin);
+	debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
+	debugfs_create_file_unsafe("regval", 0600, dir, dev, fops);
+	debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev,
+				   &fops_napi_threaded);
+	debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
+	if (dev->otp.data)
+		debugfs_create_blob("otp", 0400, dir, &dev->otp);
+	debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir,
+				    mt76_read_rate_txpower);
+	debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir,
+				    mt76_rx_queues_read);
+
+	return dir;
+}
+EXPORT_SYMBOL_GPL(mt76_register_debugfs_fops);
diff --git a/sys/contrib/dev/mediatek/mt76/dma.c b/sys/contrib/dev/mediatek/mt76/dma.c
new file mode 100644
index 000000000000..dba7c323d205
--- /dev/null
+++ b/sys/contrib/dev/mediatek/mt76/dma.c
@@ -0,0 +1,826 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <linux/dma-mapping.h>
+#if defined(__FreeBSD__)
+#include <linux/cache.h>
+#endif
+#include "mt76.h"
+#include "dma.h"
+
+#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
+
+#define Q_READ(_dev, _q, _field) ({					\
+	u32 _offset = offsetof(struct mt76_queue_regs, _field);		\
+	u32 _val;							\
+	if ((_q)->flags & MT_QFLAG_WED)					\
+		_val = mtk_wed_device_reg_read(&(_dev)->mmio.wed,	\
+					       ((_q)->wed_regs +	\
+					        _offset));		\
+	else								\
+		_val = readl(&(_q)->regs->_field);			\
+	_val;								\
+})
+
+#define Q_WRITE(_dev, _q, _field, _val)	do {				\
+	u32 _offset = offsetof(struct mt76_queue_regs, _field);		\
+	if ((_q)->flags & MT_QFLAG_WED)					\
+		mtk_wed_device_reg_write(&(_dev)->mmio.wed,		\
+					 ((_q)->wed_regs + _offset),	\
+					 _val);				\
+	else								\
+		writel(_val, &(_q)->regs->_field);			\
+} while (0)
+
+#else
+
+#define Q_READ(_dev, _q, _field)	readl(&(_q)->regs->_field)
+#define Q_WRITE(_dev, _q, _field, _val)	writel(_val, &(_q)->regs->_field)
+
+#endif
+
+static struct mt76_txwi_cache *
+mt76_alloc_txwi(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *t;
+	dma_addr_t addr;
+	u8 *txwi;
+	int size;
+
+	size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
+	txwi = kzalloc(size, GFP_ATOMIC);
+	if (!txwi)
+		return NULL;
+
+	addr = dma_map_single(dev->dma_dev, txwi, dev->drv->txwi_size,
+			      DMA_TO_DEVICE);
+	t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
+	t->dma_addr = addr;
+
+	return t;
+}
+
+static struct mt76_txwi_cache *
+__mt76_get_txwi(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *t = NULL;
+
+	spin_lock(&dev->lock);
+	if (!list_empty(&dev->txwi_cache)) {
+		t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,
+				     list);
+		list_del(&t->list);
+	}
+	spin_unlock(&dev->lock);
+
+	return t;
+}
+
+static struct mt76_txwi_cache *
+mt76_get_txwi(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *t = __mt76_get_txwi(dev);
+
+	if (t)
+		return t;
+
+	return mt76_alloc_txwi(dev);
+}
+
+void
+mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+{
+	if (!t)
+		return;
+
+	spin_lock(&dev->lock);
+	list_add(&t->list, &dev->txwi_cache);
+	spin_unlock(&dev->lock);
+}
+EXPORT_SYMBOL_GPL(mt76_put_txwi);
+
+static void
+mt76_free_pending_txwi(struct mt76_dev *dev)
+{
+	struct mt76_txwi_cache *t;
+
+	local_bh_disable();
+	while ((t = __mt76_get_txwi(dev)) != NULL) {
+		dma_unmap_single(dev->dma_dev, t->dma_addr, dev->drv->txwi_size,
+				 DMA_TO_DEVICE);
+		kfree(mt76_get_txwi_ptr(dev, t));
+	}
+	local_bh_enable();
+}
+
+static void
+mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
+{
+	Q_WRITE(dev, q, desc_base, q->desc_dma);
+	Q_WRITE(dev, q, ring_size, q->ndesc);
+	q->head = Q_READ(dev, q, dma_idx);
+	q->tail = q->head;
+}
+
+static void
+mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
+{
+	int i;
+
+	if (!q || !q->ndesc)
+		return;
+
+	/* clear descriptors */
+	for (i = 0; i < q->ndesc; i++)
+		q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+
+	Q_WRITE(dev, q, cpu_idx, 0);
+	Q_WRITE(dev, q, dma_idx, 0);
+	mt76_dma_sync_idx(dev, q);
+}
+
+static int
+mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
+		 struct mt76_queue_buf *buf, int nbufs, u32 info,
+		 struct sk_buff *skb, void *txwi)
+{
+	struct mt76_queue_entry *entry;
+	struct mt76_desc *desc;
+	u32 ctrl;
+	int i, idx = -1;
+
+	if (txwi) {
+		q->entry[q->head].txwi = DMA_DUMMY_DATA;
+		q->entry[q->head].skip_buf0 = true;
+	}
+
+	for (i = 0; i < nbufs; i += 2, buf += 2) {
+		u32 buf0 = buf[0].addr, buf1 = 0;
+
+		idx = q->head;
+		q->head = (q->head + 1) % q->ndesc;
+
+		desc = &q->desc[idx];
+		entry = &q->entry[idx];
+
+		if (buf[0].skip_unmap)
+			entry->skip_buf0 = true;
+		entry->skip_buf1 = i == nbufs - 1;
+
+		entry->dma_addr[0] = buf[0].addr;
+		entry->dma_len[0] = buf[0].len;
+
+		ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+		if (i < nbufs - 1) {
+			entry->dma_addr[1] = buf[1].addr;
+			entry->dma_len[1] = buf[1].len;
+			buf1 = buf[1].addr;
+			ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
+			if (buf[1].skip_unmap)
+				entry->skip_buf1 = true;
+		}
+
+		if (i == nbufs - 1)
+			ctrl |= MT_DMA_CTL_LAST_SEC0;
+		else if (i == nbufs - 2)
+			ctrl |= MT_DMA_CTL_LAST_SEC1;
+
+		WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));
+		WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
+		WRITE_ONCE(desc->info, cpu_to_le32(info));
+		WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
+
+		q->queued++;
+	}
+
+	q->entry[idx].txwi = txwi;
+	q->entry[idx].skb = skb;
+	q->entry[idx].wcid = 0xffff;
+
+	return idx;
+}
+
+static void
+mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+			struct mt76_queue_entry *prev_e)
+{
+	struct mt76_queue_entry *e = &q->entry[idx];
+
+	if (!e->skip_buf0)
+		dma_unmap_single(dev->dma_dev, e->dma_addr[0], e->dma_len[0],
+				 DMA_TO_DEVICE);
+
+	if (!e->skip_buf1)
+		dma_unmap_single(dev->dma_dev, e->dma_addr[1], e->dma_len[1],
+				 DMA_TO_DEVICE);
+
+	if (e->txwi == DMA_DUMMY_DATA)
+		e->txwi = NULL;
+
+	if (e->skb == DMA_DUMMY_DATA)
+		e->skb = NULL;
+
+	*prev_e = *e;
+	memset(e, 0, sizeof(*e));
+}
+
+static void
+mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
+{
+	wmb();
+	Q_WRITE(dev, q, cpu_idx, q->head);
+}
+
+static void
+mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
+{
+	struct mt76_queue_entry entry;
+	int last;
+
+	if (!q || !q->ndesc)
+		return;
+
+	spin_lock_bh(&q->cleanup_lock);
+	if (flush)
+		last = -1;
+	else
+		last = Q_READ(dev, q, dma_idx);
+
+	while (q->queued > 0 && q->tail != last) {
+		mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
+		mt76_queue_tx_complete(dev, q, &entry);
+
+		if (entry.txwi) {
+			if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
+				mt76_put_txwi(dev, entry.txwi);
+		}
+
+		if (!flush && q->tail == last)
+			last = Q_READ(dev, q, dma_idx);
+	}
+	spin_unlock_bh(&q->cleanup_lock);
+
+	if (flush) {
+		spin_lock_bh(&q->lock);
+		mt76_dma_sync_idx(dev, q);
+		mt76_dma_kick_queue(dev, q);
+		spin_unlock_bh(&q->lock);
+	}
+
*** 71319 LINES SKIPPED ***