aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislaw Gruszka2019-03-19 11:37:43 +0100
committerFelix Fietkau2019-05-01 13:03:56 +0200
commit7e07c27d37bd4e8d50188dd61a821daa35b5ca6a (patch)
treec1ea0f11cdcc87b8d52f47c939fd0313a0f083b8
parentb98558e25299860f2428eff2e7636510c6d8fba0 (diff)
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 <sgruszka@redhat.com> Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c36
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 @@ 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 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)