From 91ade885195d0ede633dd2fb4b5f58bae4b612af Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 19 Mar 2019 11:37:37 +0100 Subject: [PATCH] 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 Signed-off-by: Felix Fietkau --- mt76x02.h | 3 ++ mt76x02_regs.h | 5 +++- mt76x02_usb_core.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/mt76x02.h b/mt76x02.h index 216ff554..74c516b7 100644 --- a/mt76x02.h +++ b/mt76x02.h @@ -89,6 +89,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/mt76x02_regs.h b/mt76x02_regs.h index 7401cb94..2ce05b54 100644 --- a/mt76x02_regs.h +++ b/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/mt76x02_usb_core.c b/mt76x02_usb_core.c index fd81b48c..4e6cdf47 100644 --- a/mt76x02_usb_core.c +++ b/mt76x02_usb_core.c @@ -106,8 +106,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);