* [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 = ¶ms->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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox