2019-02-28 08:03:42

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 00/12] mt76x02: AP support for with PS

On USB we do not have available PSD queue. Using standard AC queues is
unreliable for sending PS buffered frames, stations can go sleep again
before frames are sent. Only reliable way I could find to sent broadcast
PS buffered frames is put them into beacon data registers, then frames
are sent just after proper beacon. HW do the work when we encrypt the
frames in software.

I tested functionality used arping to iwlwifi station that do
aggressive PS, it works like this:

# arping -c 1 -I wlan0 192.168.9.110
ARPING 192.168.9.110 from 192.168.9.1 wlan0
Unicast reply from 192.168.9.110 [4C:34:88:5E:76:D5] 324.885ms
Sent 1 probes (1 broadcast(s))

Otherwise arping fails:

# arping -c 1 -I wlan0 192.168.9.110
ARPING 192.168.9.110 from 192.168.1.148 wlan0
Sent 1 probes (1 broadcast(s))
Received 0 response(s)

I'm not sure how to test mt76_release_buffered_frames functionality.
Also I have not tested on MMIO hardware, but for this only code
movement was done so things should not break.

Stanislaw Gruszka (12):
mt76x02: introduce mt76x02_beacon.c
mt76x02: add hrtimer for pre TBTT for USB
mt76x02: introduce beacon_ops
mt76x02u: implement beacon_ops
mt76x02: generalize some mmio beaconing functions
mt76x02u: add sta_ps
mt76x02: fix hdr pointer in write txwi for USB
mt76x02: disable HW encryption for group frames
mt76x02u: implement pre TBTT work for USB
mt76x02u: add mt76_release_buffered_frames
mt76x02: enable AP mode for USB
mt76x02: remove set_tim

drivers/net/wireless/mediatek/mt76/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt76x0/init.c | 1 -
.../net/wireless/mediatek/mt76/mt76x0/main.c | 8 +-
.../net/wireless/mediatek/mt76/mt76x0/pci.c | 10 +-
.../net/wireless/mediatek/mt76/mt76x0/usb.c | 9 +-
drivers/net/wireless/mediatek/mt76/mt76x02.h | 22 ++
.../wireless/mediatek/mt76/mt76x02_beacon.c | 308 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt76x02_mac.c | 138 --------
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 131 +++-----
.../net/wireless/mediatek/mt76/mt76x02_regs.h | 5 +-
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 2 +
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 156 ++++++++-
.../net/wireless/mediatek/mt76/mt76x02_util.c | 77 +----
.../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +-
.../wireless/mediatek/mt76/mt76x2/pci_main.c | 7 -
.../net/wireless/mediatek/mt76/mt76x2/usb.c | 1 +
.../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +-
.../wireless/mediatek/mt76/mt76x2/usb_main.c | 1 +
drivers/net/wireless/mediatek/mt76/usb.c | 13 +-
19 files changed, 568 insertions(+), 327 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c

--
2.20.1



2019-02-28 08:03:48

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 01/12] mt76x02: introduce mt76x02_beacon.c

Move most of beaconing code into separate file and separate beacon
initialization for USB and MMIO as pre TBTT implementation for USB
will be different.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/Makefile | 2 +-
.../net/wireless/mediatek/mt76/mt76x0/init.c | 1 -
.../net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +
.../net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +
drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 +
.../wireless/mediatek/mt76/mt76x02_beacon.c | 212 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt76x02_mac.c | 138 ------------
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 17 +-
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 1 +
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 6 +
.../net/wireless/mediatek/mt76/mt76x02_util.c | 62 -----
.../wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +-
.../wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +-
13 files changed, 242 insertions(+), 206 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c

diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 3fd1b64b4aa7..cad4fed1a6ac 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -16,7 +16,7 @@ CFLAGS_mt76x02_trace.o := -I$(src)
mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
mt76x02_eeprom.o mt76x02_phy.o mt76x02_mmio.o \
mt76x02_txrx.o mt76x02_trace.o mt76x02_debugfs.o \
- mt76x02_dfs.o
+ mt76x02_dfs.o mt76x02_beacon.o

mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
index bcb72e019fd2..e5f4ce3b595b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
@@ -259,7 +259,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev)
return ret;

mt76x0_phy_init(dev);
- mt76x02_init_beacon_config(dev);

return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index f302162036d0..fafe57653ac0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -128,6 +128,8 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev)
if (err < 0)
return err;

+ mt76x02e_init_beacon_config(dev);
+
if (mt76_chip(&dev->mt76) == 0x7610) {
u16 val;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 91718647da02..9d3ad8586530 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -175,6 +175,8 @@ static int mt76x0u_init_hardware(struct mt76x02_dev *dev)
if (err < 0)
return err;

+ mt76x02u_init_beacon_config(dev);
+
mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
mt76_wr(dev, MT_TXOP_CTRL_CFG,
FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 6915cce5def9..78bc0211e479 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -183,6 +183,7 @@ void mt76x02_bss_info_changed(struct ieee80211_hw *hw,

extern const u16 mt76x02_beacon_offsets[16];
void mt76x02_init_beacon_config(struct mt76x02_dev *dev);
+void mt76x02e_init_beacon_config(struct mt76x02_dev *dev);
void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set);
void mt76x02_mac_start(struct mt76x02_dev *dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
new file mode 100644
index 000000000000..e9f71def9f21
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 Felix Fietkau <[email protected]>
+ * Copyright (C) 2018 Lorenzo Bianconi <[email protected]>
+ * Copyright (C) 2018 Stanislaw Gruszka <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "mt76x02.h"
+
+const u16 mt76x02_beacon_offsets[16] = {
+ /* 1024 byte per beacon */
+ 0xc000,
+ 0xc400,
+ 0xc800,
+ 0xcc00,
+ 0xd000,
+ 0xd400,
+ 0xd800,
+ 0xdc00,
+ /* BSS idx 8-15 not used for beacons */
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+ 0xc000,
+};
+
+static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
+{
+ u16 val, base = MT_BEACON_BASE;
+ u32 regs[4] = {};
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ val = mt76x02_beacon_offsets[i] - base;
+ regs[i / 4] |= (val / 64) << (8 * (i % 4));
+ }
+
+ for (i = 0; i < 4; i++)
+ mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
+}
+
+static int
+mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
+{
+ int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
+ struct mt76x02_txwi txwi;
+
+ if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
+ return -ENOSPC;
+
+ mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
+
+ mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
+ offset += sizeof(txwi);
+
+ mt76_wr_copy(dev, offset, skb->data, skb->len);
+ return 0;
+}
+
+static int
+__mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx,
+ struct sk_buff *skb)
+{
+ int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
+ int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
+ int ret = 0;
+ int i;
+
+ /* Prevent corrupt transmissions during update */
+ mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
+
+ if (skb) {
+ ret = mt76x02_write_beacon(dev, beacon_addr, skb);
+ if (!ret)
+ dev->beacon_data_mask |= BIT(bcn_idx);
+ } else {
+ dev->beacon_data_mask &= ~BIT(bcn_idx);
+ for (i = 0; i < beacon_len; i += 4)
+ mt76_wr(dev, beacon_addr + i, 0);
+ }
+
+ mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
+
+ return ret;
+}
+
+int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
+ struct sk_buff *skb)
+{
+ bool force_update = false;
+ int bcn_idx = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
+ if (vif_idx == i) {
+ force_update = !!dev->beacons[i] ^ !!skb;
+
+ if (dev->beacons[i])
+ dev_kfree_skb(dev->beacons[i]);
+
+ dev->beacons[i] = skb;
+ __mt76x02_mac_set_beacon(dev, bcn_idx, skb);
+ } else if (force_update && dev->beacons[i]) {
+ __mt76x02_mac_set_beacon(dev, bcn_idx,
+ dev->beacons[i]);
+ }
+
+ bcn_idx += !!dev->beacons[i];
+ }
+
+ for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
+ if (!(dev->beacon_data_mask & BIT(i)))
+ break;
+
+ __mt76x02_mac_set_beacon(dev, i, NULL);
+ }
+
+ mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
+ bcn_idx - 1);
+ return 0;
+}
+
+static void
+__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
+ bool val, struct sk_buff *skb)
+{
+ u8 old_mask = dev->beacon_mask;
+ bool en;
+ u32 reg;
+
+ if (val) {
+ dev->beacon_mask |= BIT(vif_idx);
+ if (skb)
+ mt76x02_mac_set_beacon(dev, vif_idx, skb);
+ } else {
+ dev->beacon_mask &= ~BIT(vif_idx);
+ mt76x02_mac_set_beacon(dev, vif_idx, NULL);
+ }
+
+ if (!!old_mask == !!dev->beacon_mask)
+ return;
+
+ en = dev->beacon_mask;
+
+ reg = MT_BEACON_TIME_CFG_BEACON_TX |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_TIMER_EN;
+ mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
+
+ if (mt76_is_usb(dev))
+ return;
+
+ mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
+ if (en)
+ mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+ else
+ mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+}
+
+void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
+ struct ieee80211_vif *vif, bool val)
+{
+ u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx;
+ struct sk_buff *skb = NULL;
+
+ if (mt76_is_mmio(dev))
+ tasklet_disable(&dev->pre_tbtt_tasklet);
+ else if (val)
+ skb = ieee80211_beacon_get(mt76_hw(dev), vif);
+
+ if (!dev->beacon_mask)
+ dev->tbtt_count = 0;
+
+ __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb);
+
+ if (mt76_is_mmio(dev))
+ tasklet_enable(&dev->pre_tbtt_tasklet);
+}
+
+void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
+{
+ int i;
+
+ mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX));
+ mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE);
+ mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff);
+
+ for (i = 0; i < 8; i++)
+ mt76x02_mac_set_beacon(dev, i, NULL);
+
+ mt76x02_set_beacon_offsets(dev);
+}
+EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config);
+
+
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index 91ff6598eccf..71bd82cccb6b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -996,141 +996,3 @@ void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR,
get_unaligned_le16(addr + 4));
}
-
-static int
-mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb)
-{
- int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
- struct mt76x02_txwi txwi;
-
- if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
- return -ENOSPC;
-
- mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len);
-
- mt76_wr_copy(dev, offset, &txwi, sizeof(txwi));
- offset += sizeof(txwi);
-
- mt76_wr_copy(dev, offset, skb->data, skb->len);
- return 0;
-}
-
-static int
-__mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx,
- struct sk_buff *skb)
-{
- int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
- int beacon_addr = mt76x02_beacon_offsets[bcn_idx];
- int ret = 0;
- int i;
-
- /* Prevent corrupt transmissions during update */
- mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx));
-
- if (skb) {
- ret = mt76x02_write_beacon(dev, beacon_addr, skb);
- if (!ret)
- dev->beacon_data_mask |= BIT(bcn_idx);
- } else {
- dev->beacon_data_mask &= ~BIT(bcn_idx);
- for (i = 0; i < beacon_len; i += 4)
- mt76_wr(dev, beacon_addr + i, 0);
- }
-
- mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask);
-
- return ret;
-}
-
-int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
- struct sk_buff *skb)
-{
- bool force_update = false;
- int bcn_idx = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) {
- if (vif_idx == i) {
- force_update = !!dev->beacons[i] ^ !!skb;
-
- if (dev->beacons[i])
- dev_kfree_skb(dev->beacons[i]);
-
- dev->beacons[i] = skb;
- __mt76x02_mac_set_beacon(dev, bcn_idx, skb);
- } else if (force_update && dev->beacons[i]) {
- __mt76x02_mac_set_beacon(dev, bcn_idx,
- dev->beacons[i]);
- }
-
- bcn_idx += !!dev->beacons[i];
- }
-
- for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) {
- if (!(dev->beacon_data_mask & BIT(i)))
- break;
-
- __mt76x02_mac_set_beacon(dev, i, NULL);
- }
-
- mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N,
- bcn_idx - 1);
- return 0;
-}
-
-static void
-__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
- bool val, struct sk_buff *skb)
-{
- u8 old_mask = dev->beacon_mask;
- bool en;
- u32 reg;
-
- if (val) {
- dev->beacon_mask |= BIT(vif_idx);
- if (skb)
- mt76x02_mac_set_beacon(dev, vif_idx, skb);
- } else {
- dev->beacon_mask &= ~BIT(vif_idx);
- mt76x02_mac_set_beacon(dev, vif_idx, NULL);
- }
-
- if (!!old_mask == !!dev->beacon_mask)
- return;
-
- en = dev->beacon_mask;
-
- reg = MT_BEACON_TIME_CFG_BEACON_TX |
- MT_BEACON_TIME_CFG_TBTT_EN |
- MT_BEACON_TIME_CFG_TIMER_EN;
- mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);
-
- if (mt76_is_usb(dev))
- return;
-
- mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
- if (en)
- mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
- else
- mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
-}
-
-void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
- struct ieee80211_vif *vif, bool val)
-{
- u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx;
- struct sk_buff *skb = NULL;
-
- if (mt76_is_mmio(dev))
- tasklet_disable(&dev->pre_tbtt_tasklet);
- else if (val)
- skb = ieee80211_beacon_get(mt76_hw(dev), vif);
-
- if (!dev->beacon_mask)
- dev->tbtt_count = 0;
-
- __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb);
-
- if (mt76_is_mmio(dev))
- tasklet_enable(&dev->pre_tbtt_tasklet);
-}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index 1229f19f2b02..c21bcb56c7de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -151,6 +151,21 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
spin_unlock_bh(&q->lock);
}

+void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
+{
+ tasklet_init(&dev->pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
+ (unsigned long)dev);
+
+ /* Fire a pre-TBTT interrupt 8 ms before TBTT */
+ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4);
+ mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER,
+ MT_DFS_GP_INTERVAL);
+ mt76_wr(dev, MT_INT_TIMER_EN, 0);
+
+ mt76x02_init_beacon_config(dev);
+}
+EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config);
+
static int
mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
int idx, int n_desc)
@@ -228,8 +243,6 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
return -ENOMEM;

tasklet_init(&dev->tx_tasklet, mt76x02_tx_tasklet, (unsigned long) dev);
- tasklet_init(&dev->pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
- (unsigned long)dev);

kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
index 0126e51d77ed..3874f363418f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
@@ -31,4 +31,5 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
u32 *tx_info);
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush);
+void mt76x02u_init_beacon_config(struct mt76x02_dev *dev);
#endif /* __MT76x02_USB_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 43f07461c8d3..833ca97d07fc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -104,3 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
return mt76x02u_skb_dma_info(skb, WLAN_PORT, flags);
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);
+
+void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
+{
+ mt76x02_init_beacon_config(dev);
+}
+EXPORT_SYMBOL_GPL(mt76x02u_init_beacon_config);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index a48c261b0c63..83fc9d1add82 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -629,68 +629,6 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
}
EXPORT_SYMBOL_GPL(mt76x02_sta_ps);

-const u16 mt76x02_beacon_offsets[16] = {
- /* 1024 byte per beacon */
- 0xc000,
- 0xc400,
- 0xc800,
- 0xcc00,
- 0xd000,
- 0xd400,
- 0xd800,
- 0xdc00,
- /* BSS idx 8-15 not used for beacons */
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
- 0xc000,
-};
-
-static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
-{
- u16 val, base = MT_BEACON_BASE;
- u32 regs[4] = {};
- int i;
-
- for (i = 0; i < 16; i++) {
- val = mt76x02_beacon_offsets[i] - base;
- regs[i / 4] |= (val / 64) << (8 * (i % 4));
- }
-
- for (i = 0; i < 4; i++)
- mt76_wr(dev, MT_BCN_OFFSET(i), regs[i]);
-}
-
-void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
-{
- int i;
-
- if (mt76_is_mmio(dev)) {
- /* Fire a pre-TBTT interrupt 8 ms before TBTT */
- mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT,
- 8 << 4);
- mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER,
- MT_DFS_GP_INTERVAL);
- mt76_wr(dev, MT_INT_TIMER_EN, 0);
- }
-
- mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN |
- MT_BEACON_TIME_CFG_TBTT_EN |
- MT_BEACON_TIME_CFG_BEACON_TX));
- mt76_set(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_SYNC_MODE);
- mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xffff);
-
- for (i = 0; i < 8; i++)
- mt76x02_mac_set_beacon(dev, i, NULL);
-
- mt76x02_set_beacon_offsets(dev);
-}
-EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config);
-
void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
index 984d9c4c2e1a..7a40a2b0a632 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
@@ -120,7 +120,7 @@ static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
mt76_clear(dev, MT_FCE_L2_STUFF, MT_FCE_L2_STUFF_WR_MPDU_LEN_EN);

mt76x02_mac_setaddr(dev, macaddr);
- mt76x02_init_beacon_config(dev);
+ mt76x02e_init_beacon_config(dev);
if (!hard)
return 0;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
index 1da90e58d942..35bdf5ffae00 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c
@@ -183,7 +183,7 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev)
mt76x02_mac_shared_key_setup(dev, i, k, NULL);
}

- mt76x02_init_beacon_config(dev);
+ mt76x02u_init_beacon_config(dev);

mt76_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e);
mt76_wr(dev, MT_TXOP_CTRL_CFG, 0x583f);
--
2.20.1


2019-02-28 08:03:55

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 02/12] mt76x02: add hrtimer for pre TBTT for USB

Add timer and work for pre TBTT for USB devices. For now code
doesn't do anyting useful, just add hrtimer which synchronize
with hardware MT_TBTT_TIMER.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +
.../net/wireless/mediatek/mt76/mt76x02_regs.h | 5 +-
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 70 +++++++++++++++++++
3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 78bc0211e479..edb1c140c487 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -87,6 +87,9 @@ struct mt76x02_dev {
struct delayed_work mac_work;
struct delayed_work wdt_work;

+ struct hrtimer pre_tbtt_timer;
+ struct work_struct pre_tbtt_work;
+
u32 aggr_stats[32];

struct sk_buff *beacons[8];
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
index 7401cb94fb72..2ce05b543dff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h
@@ -356,7 +356,10 @@
#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24)

#define MT_TBTT_SYNC_CFG 0x1118
-#define MT_TBTT_TIMER_CFG 0x1124
+#define MT_TSF_TIMER_DW0 0x111c
+#define MT_TSF_TIMER_DW1 0x1120
+#define MT_TBTT_TIMER 0x1124
+#define MT_TBTT_TIMER_VAL GENMASK(16, 0)

#define MT_INT_TIMER_CFG 0x1128
#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 833ca97d07fc..051fa68a85d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -105,8 +105,78 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);

+/* Trigger pre-TBTT event 8 ms before TBTT */
+#define PRE_TBTT_USEC 8000
+static void mt76x02u_start_pre_tbtt_timer(struct mt76x02_dev *dev)
+{
+ u64 time;
+ u32 tbtt;
+
+ /* Get remaining TBTT in usec */
+ tbtt = mt76_get_field(dev, MT_TBTT_TIMER, MT_TBTT_TIMER_VAL);
+ tbtt *= 32;
+
+ if (tbtt <= PRE_TBTT_USEC) {
+ queue_work(system_highpri_wq, &dev->pre_tbtt_work);
+ return;
+ }
+
+ time = (tbtt - PRE_TBTT_USEC) * 1000ull;
+ hrtimer_start(&dev->pre_tbtt_timer, time, HRTIMER_MODE_REL);
+}
+
+static void mt76x02u_restart_pre_tbtt_timer(struct mt76x02_dev *dev)
+{
+ u32 tbtt, dw0, dw1;
+ u64 tsf, time;
+
+ /* Get remaining TBTT in usec */
+ tbtt = mt76_get_field(dev, MT_TBTT_TIMER, MT_TBTT_TIMER_VAL);
+ tbtt *= 32;
+
+ dw0 = mt76_rr(dev, MT_TSF_TIMER_DW0);
+ dw1 = mt76_rr(dev, MT_TSF_TIMER_DW1);
+ tsf = (u64)dw0 << 32 | dw1;
+ dev_dbg(dev->mt76.dev, "TSF: %llu us TBTT %u us\n", tsf, tbtt);
+
+ /* Convert beacon interval in TU (1024 usec) to nsec */
+ time = ((1000000000ull * dev->beacon_int) >> 10);
+
+ /* Adjust time to trigger hrtimer 8ms before TBTT */
+ if (tbtt < PRE_TBTT_USEC)
+ time -= (PRE_TBTT_USEC - tbtt) * 1000ull;
+ else
+ time += (tbtt - PRE_TBTT_USEC) * 1000ull;
+
+ hrtimer_start(&dev->pre_tbtt_timer, time, HRTIMER_MODE_REL);
+}
+
+static void mt76x02u_pre_tbtt_work(struct work_struct *work)
+{
+ struct mt76x02_dev *dev =
+ container_of(work, struct mt76x02_dev, pre_tbtt_work);
+
+ if (!dev->beacon_mask)
+ return;
+ mt76x02u_restart_pre_tbtt_timer(dev);
+}
+
+static enum hrtimer_restart mt76x02u_pre_tbtt_interrupt(struct hrtimer *timer)
+{
+ struct mt76x02_dev *dev =
+ container_of(timer, struct mt76x02_dev, pre_tbtt_timer);
+
+ queue_work(system_highpri_wq, &dev->pre_tbtt_work);
+
+ return HRTIMER_NORESTART;
+}
+
void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
{
+ hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt;
+ INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work);
+
mt76x02_init_beacon_config(dev);
}
EXPORT_SYMBOL_GPL(mt76x02u_init_beacon_config);
--
2.20.1


2019-02-28 08:03:59

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 03/12] mt76x02: introduce beacon_ops

Enabling/disableing TBTT and beacon will be diffrent for USB. Introduce
beacon_ops to encapsulate that and implement it for MMIO. USB
implementation is noop for now.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
.../net/wireless/mediatek/mt76/mt76x0/main.c | 8 +++----
drivers/net/wireless/mediatek/mt76/mt76x02.h | 7 ++++++
.../wireless/mediatek/mt76/mt76x02_beacon.c | 18 ++++-----------
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 23 +++++++++++++++++++
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 14 +++++++++++
5 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
index fee16ab21edb..691984037f98 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c
@@ -22,10 +22,9 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
int ret;

cancel_delayed_work_sync(&dev->cal_work);
- if (mt76_is_mmio(dev)) {
- tasklet_disable(&dev->pre_tbtt_tasklet);
+ dev->beacon_ops->pre_tbtt_enable(dev, false);
+ if (mt76_is_mmio(dev))
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
- }

mt76_set_channel(&dev->mt76);
ret = mt76x0_phy_set_channel(dev, chandef);
@@ -38,9 +37,10 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)

if (mt76_is_mmio(dev)) {
mt76x02_dfs_init_params(dev);
- tasklet_enable(&dev->pre_tbtt_tasklet);
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
}
+ dev->beacon_ops->pre_tbtt_enable(dev, true);
+
mt76_txq_schedule_all(&dev->mt76);

return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index edb1c140c487..46c4635cd66a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -67,6 +67,11 @@ struct mt76x02_calibration {
s8 tssi_dc;
};

+struct mt76x02_beacon_ops {
+ void (*pre_tbtt_enable) (struct mt76x02_dev *, bool);
+ void (*beacon_enable) (struct mt76x02_dev *, bool);
+};
+
struct mt76x02_dev {
struct mt76_dev mt76; /* must be first */

@@ -90,6 +95,8 @@ struct mt76x02_dev {
struct hrtimer pre_tbtt_timer;
struct work_struct pre_tbtt_work;

+ const struct mt76x02_beacon_ops *beacon_ops;
+
u32 aggr_stats[32];

struct sk_buff *beacons[8];
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index e9f71def9f21..42798a918c0c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -162,14 +162,7 @@ __mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
MT_BEACON_TIME_CFG_TIMER_EN;
mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en);

- if (mt76_is_usb(dev))
- return;
-
- mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
- if (en)
- mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
- else
- mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+ dev->beacon_ops->beacon_enable(dev, en);
}

void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
@@ -178,9 +171,9 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx;
struct sk_buff *skb = NULL;

- if (mt76_is_mmio(dev))
- tasklet_disable(&dev->pre_tbtt_tasklet);
- else if (val)
+ dev->beacon_ops->pre_tbtt_enable(dev, true);
+
+ if (mt76_is_usb(dev))
skb = ieee80211_beacon_get(mt76_hw(dev), vif);

if (!dev->beacon_mask)
@@ -188,8 +181,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,

__mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb);

- if (mt76_is_mmio(dev))
- tasklet_enable(&dev->pre_tbtt_tasklet);
+ dev->beacon_ops->pre_tbtt_enable(dev, true);
}

void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index c21bcb56c7de..f83a633144ab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -151,8 +151,31 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
spin_unlock_bh(&q->lock);
}

+static void mt76x02e_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
+{
+ if (en)
+ tasklet_enable(&dev->pre_tbtt_tasklet);
+ else
+ tasklet_disable(&dev->pre_tbtt_tasklet);
+}
+
+static void mt76x02e_beacon_enable(struct mt76x02_dev *dev, bool en)
+{
+ mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en);
+ if (en)
+ mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+ else
+ mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT);
+}
+
void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
{
+ static const struct mt76x02_beacon_ops beacon_ops = {
+ .pre_tbtt_enable = mt76x02e_pre_tbtt_enable,
+ .beacon_enable = mt76x02e_beacon_enable,
+ };
+ dev->beacon_ops = &beacon_ops;
+
tasklet_init(&dev->pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
(unsigned long)dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 051fa68a85d5..5dd39c59a797 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -171,8 +171,22 @@ static enum hrtimer_restart mt76x02u_pre_tbtt_interrupt(struct hrtimer *timer)
return HRTIMER_NORESTART;
}

+static void mt76x02u_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
+{
+}
+
+static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en)
+{
+}
+
void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
{
+ static const struct mt76x02_beacon_ops beacon_ops = {
+ .pre_tbtt_enable = mt76x02u_pre_tbtt_enable,
+ .beacon_enable = mt76x02u_beacon_enable,
+ };
+ dev->beacon_ops = &beacon_ops;
+
hrtimer_init(&dev->pre_tbtt_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
dev->pre_tbtt_timer.function = mt76x02u_pre_tbtt_interrupt;
INIT_WORK(&dev->pre_tbtt_work, mt76x02u_pre_tbtt_work);
--
2.20.1


2019-02-28 08:04:04

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 04/12] mt76x02u: implement beacon_ops

Add implementation of beacon_ops for USB and exit function to
stop the timer if running when device is removed. Still no
actual work on pre tbtt event.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
.../net/wireless/mediatek/mt76/mt76x0/usb.c | 5 +--
.../net/wireless/mediatek/mt76/mt76x02_usb.h | 1 +
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 33 +++++++++++++++++++
3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 9d3ad8586530..7f3113b91498 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -87,14 +87,11 @@ static void mt76x0u_mac_stop(struct mt76x02_dev *dev)
cancel_delayed_work_sync(&dev->cal_work);
cancel_delayed_work_sync(&dev->mac_work);
mt76u_stop_stat_wk(&dev->mt76);
+ mt76x02u_exit_beacon_config(dev);

if (test_bit(MT76_REMOVED, &dev->mt76.state))
return;

- mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN |
- MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN |
- MT_BEACON_TIME_CFG_BEACON_TX);
-
if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000))
dev_warn(dev->mt76.dev, "TX DMA did not stop\n");

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
index 3874f363418f..d9389bf6dabe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
@@ -32,4 +32,5 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q,
struct mt76_queue_entry *e, bool flush);
void mt76x02u_init_beacon_config(struct mt76x02_dev *dev);
+void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev);
#endif /* __MT76x02_USB_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 5dd39c59a797..fdd6a021914d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -151,6 +151,15 @@ static void mt76x02u_restart_pre_tbtt_timer(struct mt76x02_dev *dev)
hrtimer_start(&dev->pre_tbtt_timer, time, HRTIMER_MODE_REL);
}

+static void mt76x02u_stop_pre_tbtt_timer(struct mt76x02_dev *dev)
+{
+ do {
+ hrtimer_cancel(&dev->pre_tbtt_timer);
+ cancel_work_sync(&dev->pre_tbtt_work);
+ /* Timer can be rearmed by work. */
+ } while (hrtimer_active(&dev->pre_tbtt_timer));
+}
+
static void mt76x02u_pre_tbtt_work(struct work_struct *work)
{
struct mt76x02_dev *dev =
@@ -173,10 +182,21 @@ static enum hrtimer_restart mt76x02u_pre_tbtt_interrupt(struct hrtimer *timer)

static void mt76x02u_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)
{
+ if (en && dev->beacon_mask && !hrtimer_active(&dev->pre_tbtt_timer))
+ mt76x02u_start_pre_tbtt_timer(dev);
+ if (!en)
+ mt76x02u_stop_pre_tbtt_timer(dev);
}

static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en)
{
+ if (WARN_ON_ONCE(!dev->beacon_int))
+ return;
+
+ if (en)
+ mt76x02u_start_pre_tbtt_timer(dev);
+
+ /* Nothing to do on disable as timer is already stopped */
}

void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
@@ -194,3 +214,16 @@ void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
mt76x02_init_beacon_config(dev);
}
EXPORT_SYMBOL_GPL(mt76x02u_init_beacon_config);
+
+void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev)
+{
+ if (!test_bit(MT76_REMOVED, &dev->mt76.state))
+ mt76_clear(dev, MT_BEACON_TIME_CFG,
+ MT_BEACON_TIME_CFG_TIMER_EN |
+ MT_BEACON_TIME_CFG_SYNC_MODE |
+ MT_BEACON_TIME_CFG_TBTT_EN |
+ MT_BEACON_TIME_CFG_BEACON_TX);
+
+ mt76x02u_stop_pre_tbtt_timer(dev);
+}
+EXPORT_SYMBOL_GPL(mt76x02u_exit_beacon_config);
--
2.20.1


2019-02-28 08:04:09

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 05/12] mt76x02: generalize some mmio beaconing functions

Move some TBTT mmio functions to mt76x02_beacon.c and create new ones
in order to be reused by USB pre-TBTT.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02.h | 11 ++
.../wireless/mediatek/mt76/mt76x02_beacon.c | 102 ++++++++++++++++++
.../net/wireless/mediatek/mt76/mt76x02_mmio.c | 91 +---------------
3 files changed, 115 insertions(+), 89 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 46c4635cd66a..356ea5e443d2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -192,8 +192,19 @@ void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *info, u32 changed);

extern const u16 mt76x02_beacon_offsets[16];
+struct beacon_bc_data {
+ struct mt76x02_dev *dev;
+ struct sk_buff_head q;
+ struct sk_buff *tail[8];
+};
void mt76x02_init_beacon_config(struct mt76x02_dev *dev);
void mt76x02e_init_beacon_config(struct mt76x02_dev *dev);
+void mt76x02_resync_beacon_timer(struct mt76x02_dev *dev);
+void mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
+void mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev,
+ struct beacon_bc_data *data,
+ int max_nframes);
+
void mt76x02_set_irq_mask(struct mt76x02_dev *dev, u32 clear, u32 set);
void mt76x02_mac_start(struct mt76x02_dev *dev);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index 42798a918c0c..28102082772b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -184,6 +184,108 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev,
dev->beacon_ops->pre_tbtt_enable(dev, true);
}

+void
+mt76x02_resync_beacon_timer(struct mt76x02_dev *dev)
+{
+ u32 timer_val = dev->beacon_int << 4;
+
+ dev->tbtt_count++;
+
+ /*
+ * Beacon timer drifts by 1us every tick, the timer is configured
+ * in 1/16 TU (64us) units.
+ */
+ if (dev->tbtt_count < 63)
+ return;
+
+ /*
+ * The updated beacon interval takes effect after two TBTT, because
+ * at this point the original interval has already been loaded into
+ * the next TBTT_TIMER value
+ */
+ if (dev->tbtt_count == 63)
+ timer_val -= 1;
+
+ mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
+ MT_BEACON_TIME_CFG_INTVAL, timer_val);
+
+ if (dev->tbtt_count >= 64) {
+ dev->tbtt_count = 0;
+ return;
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_resync_beacon_timer);
+
+void
+mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct mt76x02_dev *dev = (struct mt76x02_dev *)priv;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+ struct sk_buff *skb = NULL;
+
+ if (!(dev->beacon_mask & BIT(mvif->idx)))
+ return;
+
+ skb = ieee80211_beacon_get(mt76_hw(dev), vif);
+ if (!skb)
+ return;
+
+ mt76x02_mac_set_beacon(dev, mvif->idx, skb);
+}
+EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter);
+
+static void
+mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct beacon_bc_data *data = priv;
+ struct mt76x02_dev *dev = data->dev;
+ struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb;
+
+ if (!(dev->beacon_mask & BIT(mvif->idx)))
+ return;
+
+ skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif);
+ if (!skb)
+ return;
+
+ info = IEEE80211_SKB_CB(skb);
+ info->control.vif = vif;
+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+ mt76_skb_set_moredata(skb, true);
+ __skb_queue_tail(&data->q, skb);
+ data->tail[mvif->idx] = skb;
+}
+
+void
+mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev, struct beacon_bc_data *data,
+ int max_nframes)
+{
+ int i, nframes;
+
+ data->dev = dev;
+ __skb_queue_head_init(&data->q);
+
+ do {
+ nframes = skb_queue_len(&data->q);
+ ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt76x02_add_buffered_bc, data);
+ } while (nframes != skb_queue_len(&data->q) &&
+ skb_queue_len(&data->q) < max_nframes);
+
+ if (!skb_queue_len(&data->q))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(data->tail); i++) {
+ if (!data->tail[i])
+ continue;
+ mt76_skb_set_moredata(data->tail[i], false);
+ }
+}
+EXPORT_SYMBOL_GPL(mt76x02_enqueue_buffered_bc);
+
void mt76x02_init_beacon_config(struct mt76x02_dev *dev)
{
int i;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index f83a633144ab..e6723bd44e04 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -21,97 +21,16 @@
#include "mt76x02.h"
#include "mt76x02_trace.h"

-struct beacon_bc_data {
- struct mt76x02_dev *dev;
- struct sk_buff_head q;
- struct sk_buff *tail[8];
-};
-
-static void
-mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
-{
- struct mt76x02_dev *dev = (struct mt76x02_dev *)priv;
- struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
- struct sk_buff *skb = NULL;
-
- if (!(dev->beacon_mask & BIT(mvif->idx)))
- return;
-
- skb = ieee80211_beacon_get(mt76_hw(dev), vif);
- if (!skb)
- return;
-
- mt76x02_mac_set_beacon(dev, mvif->idx, skb);
-}
-
-static void
-mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
-{
- struct beacon_bc_data *data = priv;
- struct mt76x02_dev *dev = data->dev;
- struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
- struct ieee80211_tx_info *info;
- struct sk_buff *skb;
-
- if (!(dev->beacon_mask & BIT(mvif->idx)))
- return;
-
- skb = ieee80211_get_buffered_bc(mt76_hw(dev), vif);
- if (!skb)
- return;
-
- info = IEEE80211_SKB_CB(skb);
- info->control.vif = vif;
- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
- mt76_skb_set_moredata(skb, true);
- __skb_queue_tail(&data->q, skb);
- data->tail[mvif->idx] = skb;
-}
-
-static void
-mt76x02_resync_beacon_timer(struct mt76x02_dev *dev)
-{
- u32 timer_val = dev->beacon_int << 4;
-
- dev->tbtt_count++;
-
- /*
- * Beacon timer drifts by 1us every tick, the timer is configured
- * in 1/16 TU (64us) units.
- */
- if (dev->tbtt_count < 63)
- return;
-
- /*
- * The updated beacon interval takes effect after two TBTT, because
- * at this point the original interval has already been loaded into
- * the next TBTT_TIMER value
- */
- if (dev->tbtt_count == 63)
- timer_val -= 1;
-
- mt76_rmw_field(dev, MT_BEACON_TIME_CFG,
- MT_BEACON_TIME_CFG_INTVAL, timer_val);
-
- if (dev->tbtt_count >= 64) {
- dev->tbtt_count = 0;
- return;
- }
-}
-
static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
{
struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
struct mt76_queue *q = &dev->mt76.q_tx[MT_TXQ_PSD];
struct beacon_bc_data data = {};
struct sk_buff *skb;
- int i, nframes;
+ int i;

mt76x02_resync_beacon_timer(dev);

- data.dev = dev;
- __skb_queue_head_init(&data.q);
-
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt76x02_update_beacon_iter, dev);
@@ -121,13 +40,7 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
if (dev->mt76.csa_complete)
return;

- do {
- nframes = skb_queue_len(&data.q);
- ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt76x02_add_buffered_bc, &data);
- } while (nframes != skb_queue_len(&data.q) &&
- skb_queue_len(&data.q) < 8);
+ mt76x02_enqueue_buffered_bc(dev, &data, 8);

if (!skb_queue_len(&data.q))
return;
--
2.20.1


2019-02-28 08:04:13

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 06/12] mt76x02u: add sta_ps

Add sta_ps callback but dont set WCID drop sicne registers for USB
can not be accessed from tasklet context.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 +
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 ++-
drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 7f3113b91498..0348a1b38d2d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -222,6 +222,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
.tx_complete_skb = mt76x02u_tx_complete_skb,
.tx_status_data = mt76x02_tx_status_data,
.rx_skb = mt76x02_queue_rx_skb,
+ .sta_ps = mt76x02_sta_ps,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 83fc9d1add82..97a8aa30c333 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -625,7 +625,8 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
int idx = msta->wcid.idx;

mt76_stop_tx_queues(&dev->mt76, sta, true);
- mt76x02_mac_wcid_set_drop(dev, idx, ps);
+ if (mt76_is_mmio(dev))
+ mt76x02_mac_wcid_set_drop(dev, idx, ps);
}
EXPORT_SYMBOL_GPL(mt76x02_sta_ps);

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index ddb6b2c48e01..03cd744bb89d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -41,6 +41,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
.tx_complete_skb = mt76x02u_tx_complete_skb,
.tx_status_data = mt76x02_tx_status_data,
.rx_skb = mt76x02_queue_rx_skb,
+ .sta_ps = mt76x02_sta_ps,
.sta_add = mt76x02_sta_add,
.sta_remove = mt76x02_sta_remove,
};
--
2.20.1


2019-02-28 08:04:20

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 07/12] mt76x02: fix hdr pointer in write txwi for USB

Since we add txwi at the begining of skb->data, it no longer point
to ieee80211_hdr. This breaks settings TS bit for probe response and
beacons.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index fdd6a021914d..bcf3126efda9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -85,8 +85,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,

mt76x02_insert_hdr_pad(skb);

- txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
+ txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
+ skb_push(skb, sizeof(struct mt76x02_txwi));

pid = mt76_tx_status_skb_add(mdev, wcid, skb);
txwi->pktid = pid;
--
2.20.1


2019-02-28 08:04:27

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 08/12] mt76x02: disable HW encryption for group frames

This is required to sent multicast/broadcast frames in USB AP
mode just after beacon.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 97a8aa30c333..6e5ad900bf4e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -418,6 +418,16 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;

+ /*
+ * In USB AP mode, broadcast/multicast frames are setup in beacon
+ * data registers and sent via HW beacons engine, they require to
+ * be already encrypted.
+ */
+ if (mt76_is_usb(dev) &&
+ vif->type == NL80211_IFTYPE_AP &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EOPNOTSUPP;
+
msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL;
wcid = msta ? &msta->wcid : &mvif->group_wcid;

--
2.20.1


2019-02-28 08:04:32

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 09/12] mt76x02u: implement pre TBTT work for USB

Program beacons data and PS buffered frames on TBTT work for USB.
We do not have MT_TXQ_PSD queue available via USB endpoints. The way
we can send PS broadcast frames in timely manner before PS stations go
sleep again is program them in beacon data area. Hardware do not modify
those frames since TXWI is properly configured. mt76x02_mac_set_beacon()
already handle this and free no longer used frames.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
.../wireless/mediatek/mt76/mt76x02_beacon.c | 2 ++
.../wireless/mediatek/mt76/mt76x02_usb_core.c | 36 +++++++++++++++++--
2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index 28102082772b..63e2926cdd0c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -38,6 +38,7 @@ const u16 mt76x02_beacon_offsets[16] = {
0xc000,
0xc000,
};
+EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets);

static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
{
@@ -134,6 +135,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
bcn_idx - 1);
return 0;
}
+EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon);

static void
__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index bcf3126efda9..2761a9300755 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -165,9 +165,32 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work)
{
struct mt76x02_dev *dev =
container_of(work, struct mt76x02_dev, pre_tbtt_work);
+ int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0];
+ struct beacon_bc_data data = {};
+ struct sk_buff *skb;
+ int i, nbeacons;

if (!dev->beacon_mask)
return;
+
+ mt76x02_resync_beacon_timer(dev);
+
+ ieee80211_iterate_active_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt76x02_update_beacon_iter, dev);
+
+ nbeacons = hweight8(dev->beacon_mask);
+ mt76x02_enqueue_buffered_bc(dev, &data, 8 - nbeacons);
+
+ for (i = nbeacons; i < 8; i++) {
+ skb = __skb_dequeue(&data.q);
+ if (skb && skb->len >= beacon_len) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ mt76x02_mac_set_beacon(dev, i, skb);
+ }
+
mt76x02u_restart_pre_tbtt_timer(dev);
}

@@ -191,13 +214,20 @@ static void mt76x02u_pre_tbtt_enable(struct mt76x02_dev *dev, bool en)

static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en)
{
+ int i;
+
if (WARN_ON_ONCE(!dev->beacon_int))
return;

- if (en)
+ if (en) {
mt76x02u_start_pre_tbtt_timer(dev);
-
- /* Nothing to do on disable as timer is already stopped */
+ } else {
+ /* Timer is already stopped, only clean up
+ * PS buffered frames if any.
+ */
+ for (i = 0; i < 8; i++)
+ mt76x02_mac_set_beacon(dev, i, NULL);
+ }
}

void mt76x02u_init_beacon_config(struct mt76x02_dev *dev)
--
2.20.1


2019-02-28 08:04:35

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 10/12] mt76x02u: add mt76_release_buffered_frames

Create software MT_TXQ_PSD queue for USB and map it to MT_TXQ_VO
since we do not have USB endpoint for PSD. This should make
mt76_release_buffered_frames() work by sending released frames
via MT_TXQ_VO.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 +
.../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 +
drivers/net/wireless/mediatek/mt76/usb.c | 13 ++++++++-----
3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 0348a1b38d2d..b9b8a1dafbc9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -152,6 +152,7 @@ static const struct ieee80211_ops mt76x0u_ops = {
.set_rts_threshold = mt76x02_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
.get_txpower = mt76_get_txpower,
+ .release_buffered_frames = mt76_release_buffered_frames,
};

static int mt76x0u_init_hardware(struct mt76x02_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 2ac78e4dc41a..653b8df29ca3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -125,4 +125,5 @@ const struct ieee80211_ops mt76x2u_ops = {
.sw_scan_complete = mt76x02_sw_scan_complete,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.get_txpower = mt76_get_txpower,
+ .release_buffered_frames = mt76_release_buffered_frames,
};
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index ae6ada370597..f181200c05cb 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -632,7 +632,7 @@ static void mt76u_tx_tasklet(unsigned long data)
bool wake;
int i;

- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
q = &dev->q_tx[i];

spin_lock_bh(&q->lock);
@@ -785,11 +785,14 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
struct mt76_queue *q;
int i, j;

- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
q = &dev->q_tx[i];
spin_lock_init(&q->lock);
INIT_LIST_HEAD(&q->swq);
- q->hw_idx = mt76_ac_to_hwq(i);
+ if (i < IEEE80211_NUM_ACS)
+ q->hw_idx = mt76_ac_to_hwq(i);
+ else
+ q->hw_idx = 0;

q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
@@ -825,7 +828,7 @@ static void mt76u_free_tx(struct mt76_dev *dev)
struct mt76_queue *q;
int i, j;

- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
q = &dev->q_tx[i];
for (j = 0; j < q->ndesc; j++)
usb_free_urb(q->entry[j].ubuf.urb);
@@ -837,7 +840,7 @@ static void mt76u_stop_tx(struct mt76_dev *dev)
struct mt76_queue *q;
int i, j;

- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
q = &dev->q_tx[i];
for (j = 0; j < q->ndesc; j++)
usb_kill_urb(q->entry[j].ubuf.urb);
--
2.20.1


2019-02-28 08:04:37

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 11/12] mt76x02: enable AP mode for USB

Enable AP mode. For now without multi-vif support, this will require
more testing and investigation.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 6e5ad900bf4e..49da4e6ae0c7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -142,6 +142,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev)

wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
@@ -158,7 +159,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
wiphy->reg_notifier = mt76x02_regd_notifier;
wiphy->iface_combinations = mt76x02_if_comb;
wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb);
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;

/* init led callbacks */
--
2.20.1


2019-02-28 08:04:42

by Stanislaw Gruszka

[permalink] [raw]
Subject: [RFC 12/12] mt76x02: remove set_tim

set_tim callback is not used by mac80211 if AP_LINK_PS hw flag is set.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 8 --------
drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 7 -------
2 files changed, 15 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index fafe57653ac0..68d44929dafa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -74,13 +74,6 @@ mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
}

-static int
-mt76x0e_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- bool set)
-{
- return 0;
-}
-
static const struct ieee80211_ops mt76x0e_ops = {
.tx = mt76x02_tx,
.start = mt76x0e_start,
@@ -101,7 +94,6 @@ static const struct ieee80211_ops mt76x0e_ops = {
.get_survey = mt76_get_survey,
.get_txpower = mt76_get_txpower,
.flush = mt76x0e_flush,
- .set_tim = mt76x0e_set_tim,
.release_buffered_frames = mt76_release_buffered_frames,
.set_coverage_class = mt76x02_set_coverage_class,
.set_rts_threshold = mt76x02_set_rts_threshold,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
index 878ce92405ed..f45847f48920 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
@@ -135,12 +135,6 @@ mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
}

-static int
-mt76x2_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
-{
- return 0;
-}
-
static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
u32 rx_ant)
{
@@ -197,7 +191,6 @@ const struct ieee80211_ops mt76x2_ops = {
.release_buffered_frames = mt76_release_buffered_frames,
.set_coverage_class = mt76x02_set_coverage_class,
.get_survey = mt76_get_survey,
- .set_tim = mt76x2_set_tim,
.set_antenna = mt76x2_set_antenna,
.get_antenna = mt76x2_get_antenna,
.set_rts_threshold = mt76x02_set_rts_threshold,
--
2.20.1


2019-02-28 09:38:29

by Lorenzo Bianconi

[permalink] [raw]
Subject: Re: [RFC 07/12] mt76x02: fix hdr pointer in write txwi for USB

> Since we add txwi at the begining of skb->data, it no longer point
> to ieee80211_hdr. This breaks settings TS bit for probe response and
> beacons.
>
> Signed-off-by: Stanislaw Gruszka <[email protected]>
> ---
> drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> index fdd6a021914d..bcf3126efda9 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> @@ -85,8 +85,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
>
> mt76x02_insert_hdr_pad(skb);
>
> - txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
> + txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
> mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
> + skb_push(skb, sizeof(struct mt76x02_txwi));
>
> pid = mt76_tx_status_skb_add(mdev, wcid, skb);
> txwi->pktid = pid;
> --
> 2.20.1
>

Good catch :)
I think we should post it ontop of wireless-drivers since sw encryption is not
working now.

Acked-by: Lorenzo Bianconi <[email protected]>


Attachments:
(No filename) (1.22 kB)
signature.asc (228.00 B)
Download all attachments

2019-02-28 10:51:42

by Felix Fietkau

[permalink] [raw]
Subject: Re: [RFC 12/12] mt76x02: remove set_tim

On 2019-02-28 09:03, Stanislaw Gruszka wrote:
> set_tim callback is not used by mac80211 if AP_LINK_PS hw flag is set.
>
> Signed-off-by: Stanislaw Gruszka <[email protected]>

There's a check in __sta_info_recalc_tim:

/* No need to do anything if the driver does all */
if (ieee80211_hw_check(&local->hw, AP_LINK_PS) && !local->ops->set_tim)
return;

At the moment we need this dummy callback to ensure that the
beacon TIM bits are set.

- Felix

2019-02-28 13:52:22

by Stanislaw Gruszka

[permalink] [raw]
Subject: Re: [RFC 07/12] mt76x02: fix hdr pointer in write txwi for USB

On Thu, Feb 28, 2019 at 10:38:20AM +0100, Lorenzo Bianconi wrote:
> > Since we add txwi at the begining of skb->data, it no longer point
> > to ieee80211_hdr. This breaks settings TS bit for probe response and
> > beacons.
> >
> > Signed-off-by: Stanislaw Gruszka <[email protected]>
> > ---
> > drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 ++-
> > 1 file changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> > index fdd6a021914d..bcf3126efda9 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
> > @@ -85,8 +85,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
> >
> > mt76x02_insert_hdr_pad(skb);
> >
> > - txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
> > + txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
> > mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
> > + skb_push(skb, sizeof(struct mt76x02_txwi));
> >
> > pid = mt76_tx_status_skb_add(mdev, wcid, skb);
> > txwi->pktid = pid;
> > --
> > 2.20.1
> >
>
> Good catch :)
> I think we should post it ontop of wireless-drivers since sw encryption is not
> working now.
>
> Acked-by: Lorenzo Bianconi <[email protected]>

I can send it against 5.0, if Kalle will accept it, however
I do not have practical bug associated with this. Maybe we
sometimes can send ordinal frame with TS bit in txwi and it
is then malformed by HW, but I'm not sure. IBSS work with
this bug, not sure about MESH.

Stanislaw


2019-02-28 14:23:45

by Kalle Valo

[permalink] [raw]
Subject: Re: [RFC 07/12] mt76x02: fix hdr pointer in write txwi for USB

Stanislaw Gruszka <[email protected]> writes:

> On Thu, Feb 28, 2019 at 10:38:20AM +0100, Lorenzo Bianconi wrote:
>> > Since we add txwi at the begining of skb->data, it no longer point
>> > to ieee80211_hdr. This breaks settings TS bit for probe response and
>> > beacons.
>> >
>> > Signed-off-by: Stanislaw Gruszka <[email protected]>
>> > ---
>> > drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 3 ++-
>> > 1 file changed, 2 insertions(+), 1 deletion(-)
>> >
>> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
>> > index fdd6a021914d..bcf3126efda9 100644
>> > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
>> > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
>> > @@ -85,8 +85,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
>> >
>> > mt76x02_insert_hdr_pad(skb);
>> >
>> > - txwi = skb_push(skb, sizeof(struct mt76x02_txwi));
>> > + txwi = (struct mt76x02_txwi *)(skb->data - sizeof(struct mt76x02_txwi));
>> > mt76x02_mac_write_txwi(dev, txwi, skb, wcid, sta, len);
>> > + skb_push(skb, sizeof(struct mt76x02_txwi));
>> >
>> > pid = mt76_tx_status_skb_add(mdev, wcid, skb);
>> > txwi->pktid = pid;
>> > --
>> > 2.20.1
>> >
>>
>> Good catch :)
>> I think we should post it ontop of wireless-drivers since sw encryption is not
>> working now.
>>
>> Acked-by: Lorenzo Bianconi <[email protected]>
>
> I can send it against 5.0, if Kalle will accept it, however
> I do not have practical bug associated with this. Maybe we
> sometimes can send ordinal frame with TS bit in txwi and it
> is then malformed by HW, but I'm not sure. IBSS work with
> this bug, not sure about MESH.

Too late for 5.0 as Linus will most likely release it on Sunday. I
recommend sending it to wireless-drivers-next so that I can queue it for
5.1.

--
Kalle Valo