2019-03-19 10:37:59

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 00/12] mt76x02: AP support for USB 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)

Tested on MT7610U and MT7630E (on this device TX hang
in AP mode on 2.4GHz band, but this is not related to this
patch set).

RFC -> v1:
- do no remove set_tim
- add tbtt_start/stop for mt76x2u
- rebase on top of:
[PATCH 0/5] introduce mt76_sw_queue data structure
https://lore.kernel.org/linux-wireless/[email protected]/

v1 -> v2
- fix true/false bug in patch 3
- change beacon slot size for USB

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: disable HW encryption for group frames
mt76x02u: implement pre TBTT work for USB
mt76x02: make beacon slots bigger for USB
mt76x02u: add mt76_release_buffered_frames
mt76: unify set_tim
mt76x02: enable AP mode for USB

drivers/net/wireless/mediatek/mt76/Makefile | 2 +-
drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +
drivers/net/wireless/mediatek/mt76/mt76.h | 2 +
drivers/net/wireless/mediatek/mt76/mt7603/main.c | 8 +-
drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 1 -
drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 8 +-
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 11 +-
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 10 +-
drivers/net/wireless/mediatek/mt76/mt76x02.h | 25 +-
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 286 +++++++++++++++++++++
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 138 ----------
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 133 +++-------
drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 5 +-
drivers/net/wireless/mediatek/mt76/mt76x02_usb.h | 2 +
.../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 157 +++++++++++
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 77 +-----
.../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +-
.../net/wireless/mediatek/mt76/mt76x2/pci_main.c | 8 +-
drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 +
.../net/wireless/mediatek/mt76/mt76x2/usb_init.c | 2 +-
.../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 6 +
drivers/net/wireless/mediatek/mt76/usb.c | 7 +-
22 files changed, 568 insertions(+), 330 deletions(-)
create mode 100644 drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c

--
1.9.3



2019-03-19 10:38:01

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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 +-
drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 1 -
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +
drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 +
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 212 +++++++++++++++++++++
drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 138 --------------
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 17 +-
drivers/net/wireless/mediatek/mt76/mt76x02_usb.h | 1 +
.../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 6 +
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 62 ------
.../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 2 +-
.../net/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 e07a62246db7..e35165416cf0 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 cb5792b41d2d..e93f4840cace 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -186,6 +186,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_mac_start(struct mt76x02_dev *dev);

void mt76x02_init_debugfs(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 df6930a94f74..1eb669ccd5a7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -1053,141 +1053,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 ec94d612f53c..75dceeeed059 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -152,6 +152,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_sw_queue *q,
int idx, int n_desc)
@@ -230,8 +245,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 8f98cc6ce094..6ff740f09bc9 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,
struct mt76_tx_info *tx_info);
void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
struct mt76_queue_entry *e);
+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 394dfe5b4a2e..7e0a5f364469 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 81d65319d3ea..1026939d6b63 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -619,68 +619,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 d3927a13e92e..9e88a8cec9e5 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 @@ 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);
--
1.9.3


2019-03-19 10:38:08

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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 +
drivers/net/wireless/mediatek/mt76/mt76x02_regs.h | 5 +-
.../net/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 e93f4840cace..9fa6e4fc221f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -88,6 +88,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 7e0a5f364469..f1a3d41c8209 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);
--
1.9.3


2019-03-19 10:38:11

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 8 ++++----
drivers/net/wireless/mediatek/mt76/mt76x02.h | 7 +++++++
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 18 +++++------------
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 23 ++++++++++++++++++++++
.../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 14 +++++++++++++
.../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 4 ++++
6 files changed, 57 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 @@
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 @@

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 9fa6e4fc221f..0bfc3a9839d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -68,6 +68,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 */

@@ -91,6 +96,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..e980becb6683 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -162,14 +162,7 @@ int mt76x02_mac_set_beacon(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, false);
+
+ 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 75dceeeed059..2be3ca0c67be 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -152,8 +152,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 f1a3d41c8209..eec6f856f88a 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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 2ac78e4dc41a..1e6856856536 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -57,6 +57,8 @@ static void mt76x2u_stop(struct ieee80211_hw *hw)

mt76_set_channel(&dev->mt76);

+ dev->beacon_ops->pre_tbtt_enable(dev, false);
+
mt76x2_mac_stop(dev, false);

err = mt76x2u_phy_set_channel(dev, chandef);
@@ -64,6 +66,8 @@ static void mt76x2u_stop(struct ieee80211_hw *hw)
mt76x2_mac_resume(dev);
mt76x02_edcca_init(dev, true);

+ dev->beacon_ops->pre_tbtt_enable(dev, true);
+
clear_bit(MT76_RESET, &dev->mt76.state);
mt76_txq_schedule_all(&dev->mt76);

--
1.9.3


2019-03-19 10:38:12

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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]>
---
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 5 +---
drivers/net/wireless/mediatek/mt76/mt76x02_usb.h | 1 +
.../net/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 6ff740f09bc9..a012410c5ae7 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, enum mt76_txq_id qid,
struct mt76_queue_entry *e);
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 eec6f856f88a..82b78cc5b362 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);
--
1.9.3


2019-03-19 10:38:13

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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 +++
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 102 +++++++++++++++++++++
drivers/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 0bfc3a9839d0..93f9436ab809 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -195,8 +195,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_mac_start(struct mt76x02_dev *dev);

void mt76x02_init_debugfs(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 e980becb6683..d77088b7659e 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 2be3ca0c67be..eea8e4718600 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -22,97 +22,16 @@
#include "mt76x02_mcu.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].q;
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);
@@ -122,13 +41,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;
--
1.9.3


2019-03-19 10:38:17

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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 1026939d6b63..168c62a90361 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -615,7 +615,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 7a5d539873ca..1f0b1bebed79 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -40,6 +40,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,
};
--
1.9.3


2019-03-19 10:38:20

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 07/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 168c62a90361..ed6463c9166e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -424,6 +424,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;

--
1.9.3


2019-03-19 10:38:25

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 08/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]>
---
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 2 ++
.../net/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 d77088b7659e..c0be90988f82 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -38,6 +38,7 @@
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 82b78cc5b362..89249621bcec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -164,9 +164,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);
}

@@ -190,13 +213,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)
--
1.9.3


2019-03-19 10:38:29

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 09/12] mt76x02: make beacon slots bigger for USB

Since we sent PS buffered frames via beacon memory we need to make
beacon slots bigger. That imply we will also need to decrease number
of slots as beacon SRAM memory is limited to 8kB.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mt76x02.h | 3 +-
.../net/wireless/mediatek/mt76/mt76x02_beacon.c | 34 ++++------------------
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 2 ++
.../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 20 ++++++++-----
4 files changed, 22 insertions(+), 37 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 93f9436ab809..d665137d256c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -69,6 +69,8 @@ struct mt76x02_calibration {
};

struct mt76x02_beacon_ops {
+ unsigned int nslots;
+ unsigned int slot_size;
void (*pre_tbtt_enable) (struct mt76x02_dev *, bool);
void (*beacon_enable) (struct mt76x02_dev *, bool);
};
@@ -194,7 +196,6 @@ void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
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;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
index c0be90988f82..0c232d02f189 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
@@ -18,36 +18,14 @@

#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,
-};
-EXPORT_SYMBOL_GPL(mt76x02_beacon_offsets);
-
static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
{
- u16 val, base = MT_BEACON_BASE;
u32 regs[4] = {};
+ u16 val;
int i;

- for (i = 0; i < 16; i++) {
- val = mt76x02_beacon_offsets[i] - base;
+ for (i = 0; i < dev->beacon_ops->nslots; i++) {
+ val = i * dev->beacon_ops->slot_size;
regs[i / 4] |= (val / 64) << (8 * (i % 4));
}

@@ -58,7 +36,7 @@ static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
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];
+ int beacon_len = dev->beacon_ops->slot_size;
struct mt76x02_txwi txwi;

if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi)))
@@ -77,8 +55,8 @@ static void mt76x02_set_beacon_offsets(struct mt76x02_dev *dev)
__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 beacon_len = dev->beacon_ops->slot_size;
+ int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx);
int ret = 0;
int i;

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index eea8e4718600..79c1126f4ba4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -85,6 +85,8 @@ static void mt76x02e_beacon_enable(struct mt76x02_dev *dev, bool en)
void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
{
static const struct mt76x02_beacon_ops beacon_ops = {
+ .nslots = 8,
+ .slot_size = 1024,
.pre_tbtt_enable = mt76x02e_pre_tbtt_enable,
.beacon_enable = mt76x02e_beacon_enable,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 89249621bcec..c403218533da 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -107,6 +107,13 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,

/* Trigger pre-TBTT event 8 ms before TBTT */
#define PRE_TBTT_USEC 8000
+
+/* Beacon SRAM memory is limited to 8kB. We need to send PS buffered frames
+ * (which can be 1500 bytes big) via beacon memory. That make limit of number
+ * of slots to 5. TODO: dynamically calculate offsets in beacon SRAM.
+ */
+#define N_BCN_SLOTS 5
+
static void mt76x02u_start_pre_tbtt_timer(struct mt76x02_dev *dev)
{
u64 time;
@@ -164,7 +171,6 @@ 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;
@@ -179,14 +185,10 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work)
mt76x02_update_beacon_iter, dev);

nbeacons = hweight8(dev->beacon_mask);
- mt76x02_enqueue_buffered_bc(dev, &data, 8 - nbeacons);
+ mt76x02_enqueue_buffered_bc(dev, &data, N_BCN_SLOTS - nbeacons);

- for (i = nbeacons; i < 8; i++) {
+ for (i = nbeacons; i < N_BCN_SLOTS; 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);
}

@@ -224,7 +226,7 @@ static void mt76x02u_beacon_enable(struct mt76x02_dev *dev, bool en)
/* Timer is already stopped, only clean up
* PS buffered frames if any.
*/
- for (i = 0; i < 8; i++)
+ for (i = 0; i < N_BCN_SLOTS; i++)
mt76x02_mac_set_beacon(dev, i, NULL);
}
}
@@ -232,6 +234,8 @@ 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 = {
+ .nslots = N_BCN_SLOTS,
+ .slot_size = (8192 / N_BCN_SLOTS) & ~63,
.pre_tbtt_enable = mt76x02u_pre_tbtt_enable,
.beacon_enable = mt76x02u_beacon_enable,
};
--
1.9.3


2019-03-19 10:38:30

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 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 +
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 +
drivers/net/wireless/mediatek/mt76/usb.c | 7 ++++++-
3 files changed, 8 insertions(+), 1 deletion(-)

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 void mt76x0u_stop(struct ieee80211_hw *hw)
.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 1e6856856536..46c6b3764f5a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -129,4 +129,5 @@ static void mt76x2u_stop(struct ieee80211_hw *hw)
.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 27896a435d6c..7b62bd63d395 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -792,9 +792,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++) {
INIT_LIST_HEAD(&dev->q_tx[i].swq);

+ if (i >= IEEE80211_NUM_ACS) {
+ dev->q_tx[i].q = dev->q_tx[0].q;
+ continue;
+ }
+
q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
if (!q)
return -ENOMEM;
--
1.9.3


2019-03-19 10:38:33

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 11/12] mt76: unify set_tim

All mt76 drivers (now also USB drivers) require empty .set_tim
callback. Add it to common mt76 module and use on all drivers.

Signed-off-by: Stanislaw Gruszka <[email protected]>
---
drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++
drivers/net/wireless/mediatek/mt76/mt7603/main.c | 8 +-------
drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 9 +--------
drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 +
drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 8 +-------
drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 +
7 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 47eecb4d4d01..851caabbecda 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -785,3 +785,10 @@ void mt76_csa_check(struct mt76_dev *dev)
__mt76_csa_check, dev);
}
EXPORT_SYMBOL_GPL(mt76_csa_check);
+
+int
+mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_set_tim);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index edff44f32c8e..c163ba68647e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -732,6 +732,8 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void mt76_csa_check(struct mt76_dev *dev);
void mt76_csa_finish(struct mt76_dev *dev);

+int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
+
/* internal */
void mt76_tx_free(struct mt76_dev *dev);
struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 7849528db134..a03729824c4d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -664,12 +664,6 @@ static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *cont
mt76_tx(&dev->mt76, control->sta, wcid, skb);
}

-static int
-mt7603_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
-{
- return 0;
-}
-
const struct ieee80211_ops mt7603_ops = {
.tx = mt7603_tx,
.start = mt7603_start,
@@ -691,7 +685,7 @@ static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *cont
.sta_rate_tbl_update = mt7603_sta_rate_tbl_update,
.release_buffered_frames = mt7603_release_buffered_frames,
.set_coverage_class = mt7603_set_coverage_class,
- .set_tim = mt7603_set_tim,
+ .set_tim = mt76_set_tim,
.get_survey = mt76_get_survey,
};

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index e35165416cf0..a7ff7e32b9b3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -74,13 +74,6 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
{
}

-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,7 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
.get_survey = mt76_get_survey,
.get_txpower = mt76_get_txpower,
.flush = mt76x0e_flush,
- .set_tim = mt76x0e_set_tim,
+ .set_tim = mt76_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/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index b9b8a1dafbc9..cf97bbd89485 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -152,6 +152,7 @@ static void mt76x0u_stop(struct ieee80211_hw *hw)
.set_rts_threshold = mt76x02_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
.get_txpower = mt76_get_txpower,
+ .set_tim = mt76_set_tim,
.release_buffered_frames = mt76_release_buffered_frames,
};

diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c
index 878ce92405ed..16dc8e2451b5 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 @@
{
}

-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,7 @@ static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
.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_tim = mt76_set_tim,
.set_antenna = mt76x2_set_antenna,
.get_antenna = mt76x2_get_antenna,
.set_rts_threshold = mt76x02_set_rts_threshold,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
index 46c6b3764f5a..eb414fb75fb1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c
@@ -129,5 +129,6 @@ static void mt76x2u_stop(struct ieee80211_hw *hw)
.sw_scan_complete = mt76x02_sw_scan_complete,
.sta_rate_tbl_update = mt76x02_sta_rate_tbl_update,
.get_txpower = mt76_get_txpower,
+ .set_tim = mt76_set_tim,
.release_buffered_frames = mt76_release_buffered_frames,
};
--
1.9.3


2019-03-19 10:38:35

by Stanislaw Gruszka

[permalink] [raw]
Subject: [PATCH v2 12/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 ed6463c9166e..284dae65cdf1 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 */
--
1.9.3


2019-03-24 07:23:37

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 00/12] mt76x02: AP support for USB with PS

On 2019-03-19 11:37, Stanislaw Gruszka wrote:
> 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)
>
> Tested on MT7610U and MT7630E (on this device TX hang
> in AP mode on 2.4GHz band, but this is not related to this
> patch set).
Applied, thanks.

- Felix

2019-04-03 09:08:56

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 01/12] mt76x02: introduce mt76x02_beacon.c

On 2019-03-19 11:37, Stanislaw Gruszka wrote:
> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> index ec94d612f53c..75dceeeed059 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> @@ -152,6 +152,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_sw_queue *q,
> int idx, int n_desc)
> @@ -230,8 +245,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);
Moving the tasklet init to mt76x02e_init_beacon_config can crash the
kernel, because it leads to the tasklet being re-initialized on every
reset. I will update that commit and move it back.

- Felix

2019-04-03 11:48:49

by Stanislaw Gruszka

[permalink] [raw]
Subject: Re: [PATCH v2 01/12] mt76x02: introduce mt76x02_beacon.c

On Wed, Apr 03, 2019 at 11:08:53AM +0200, Felix Fietkau wrote:
> On 2019-03-19 11:37, Stanislaw Gruszka wrote:
> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > index ec94d612f53c..75dceeeed059 100644
> > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
> > @@ -152,6 +152,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_sw_queue *q,
> > int idx, int n_desc)
> > @@ -230,8 +245,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);
> Moving the tasklet init to mt76x02e_init_beacon_config can crash the
> kernel, because it leads to the tasklet being re-initialized on every
> reset. I will update that commit and move it back.

Ehh. Some further patches will not apply and will require to be modified.
Perhaps could be easer move mt76x02e_init_beacon_config() to
mt76x2_init_hardware() (or other proper function that is used only
once once during initialization). Or just apply fix on top of the set
as separate patch. Anyway I'm leaving that up to you. Thanks.

Stanislaw

2019-04-03 11:53:27

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 01/12] mt76x02: introduce mt76x02_beacon.c

On 2019-04-03 13:48, Stanislaw Gruszka wrote:
> On Wed, Apr 03, 2019 at 11:08:53AM +0200, Felix Fietkau wrote:
>> On 2019-03-19 11:37, Stanislaw Gruszka wrote:
>> > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
>> > index ec94d612f53c..75dceeeed059 100644
>> > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
>> > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
>> > @@ -152,6 +152,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_sw_queue *q,
>> > int idx, int n_desc)
>> > @@ -230,8 +245,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);
>> Moving the tasklet init to mt76x02e_init_beacon_config can crash the
>> kernel, because it leads to the tasklet being re-initialized on every
>> reset. I will update that commit and move it back.
>
> Ehh. Some further patches will not apply and will require to be modified.
> Perhaps could be easer move mt76x02e_init_beacon_config() to
> mt76x2_init_hardware() (or other proper function that is used only
> once once during initialization). Or just apply fix on top of the set
> as separate patch. Anyway I'm leaving that up to you. Thanks.
It was easy enough to fix up using git rebase. I've pushed the result to
my tree already.

- Felix