[][MAC80211][misc][preliminary version of Filogic 680 on Filogic 880]

[Description]
Add preliminary version of Filogic 680 on Filogic 880.
Based on mt76 revision: 269df4b01f27 ("wifi: mt76: fix rx checksum offload on mt7615/mt7915/mt7921")

This series adds mt7996, a new mac80211 driver for MediaTek Wi-Fi 7
(802.11be) devices, which currently supports AP, station, mesh, and
monitor modes.

mt7996 first supports Filogic 680, which is a Wi-Fi 7 chipset supporting
concurrent tri-band operation at 6 GHz, 5 GHz, and 2.4 GHz with 4x4
antennas on each band. There are several variants that will be added in
upcoming patches. For more details, please refer to [1].

mt7996 supports only Wi-Fi 6E at the moment, whereas Wi-Fi 7 and its
specific features are work in progress. They will be introduced in
further patches.

[1] https://corp.mediatek.com/news-events/press-releases/mediatek-announces-worlds-first-complete-wi-fi-7-platforms-for-access-points-and-clients

[Release-log]
N/A

Change-Id: I7d3dea2626556751c9b0462e587743fad5287be0
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6709775
diff --git a/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/src/tools/fwlog.c b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/src/tools/fwlog.c
new file mode 100644
index 0000000..e5d4a10
--- /dev/null
+++ b/autobuild_mac80211_release/mt7988_mt7996_mac80211/package/kernel/mt76/src/tools/fwlog.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <signal.h>
+#include "mt76-test.h"
+
+bool done = false;
+
+static const char *debugfs_path(const char *phyname, const char *file)
+{
+	static char path[256];
+
+	snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/mt76/%s", phyname, file);
+
+	return path;
+}
+
+static int mt76_set_fwlog_en(const char *phyname, bool en)
+{
+	FILE *f = fopen(debugfs_path(phyname, "fw_debug_bin"), "w");
+
+	if (!f) {
+		fprintf(stderr, "Could not open fw_debug_bin file\n");
+		return 1;
+	}
+
+	fprintf(f, "7");
+	fclose(f);
+
+	return 0;
+}
+
+int read_retry(int fd, void *buf, int len)
+{
+	int out_len = 0;
+	int r;
+
+	while (len > 0) {
+		if (done)
+			return -1;
+
+		r = read(fd, buf, len);
+		if (r < 0) {
+			if (errno == EINTR || errno == EAGAIN)
+				continue;
+
+			return -1;
+		}
+
+		if (!r)
+			return 0;
+
+		out_len += r;
+		len -= r;
+		buf += r;
+	}
+
+	return out_len;
+}
+
+static void handle_signal(int sig)
+{
+	done = true;
+}
+
+int mt76_fwlog(const char *phyname, int argc, char **argv)
+{
+	struct sockaddr_in local = {
+		.sin_family = AF_INET,
+		.sin_addr.s_addr = INADDR_ANY,
+	};
+	struct sockaddr_in remote = {
+		.sin_family = AF_INET,
+		.sin_port = htons(55688),
+	};
+	char buf[1504];
+	int ret = 0;
+	int yes = 1;
+	int s, fd;
+
+	if (argc < 1) {
+		fprintf(stderr, "need destination address\n");
+		return 1;
+	}
+
+	if (!inet_aton(argv[0], &remote.sin_addr)) {
+		fprintf(stderr, "invalid destination address\n");
+		return 1;
+	}
+
+	s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (s < 0) {
+		perror("socket");
+		return 1;
+	}
+
+	setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
+	if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
+		perror("bind");
+		return 1;
+	}
+
+	if (mt76_set_fwlog_en(phyname, true))
+		return 1;
+
+	fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Could not open fwlog_data file: %s\n", strerror(errno));
+		ret = 1;
+		goto out;
+	}
+
+	signal(SIGTERM, handle_signal);
+	signal(SIGINT, handle_signal);
+	signal(SIGQUIT, handle_signal);
+
+	while (1) {
+		struct pollfd pfd = {
+			.fd = fd,
+			.events = POLLIN | POLLHUP | POLLERR,
+		};
+		uint32_t len;
+		int r;
+
+		if (done)
+			break;
+
+		poll(&pfd, 1, -1);
+
+		r = read_retry(fd, &len, sizeof(len));
+		if (r < 0)
+			break;
+
+		if (!r)
+			continue;
+
+		if (len > sizeof(buf)) {
+			fprintf(stderr, "Length error: %d > %d\n", len, (int)sizeof(buf));
+			ret = 1;
+			break;
+		}
+
+		if (done)
+			break;
+
+		r = read_retry(fd, buf, len);
+		if (done)
+			break;
+
+		if (r != len) {
+			fprintf(stderr, "Short read: %d < %d\n", r, len);
+			ret = 1;
+			break;
+		}
+
+		/* send buf */
+		sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote));
+	}
+
+	close(fd);
+
+out:
+	mt76_set_fwlog_en(phyname, false);
+
+	return ret;
+}