Skip to content

Commit

Permalink
mt76x02: add hrtimer for pre TBTT for USB
Browse files Browse the repository at this point in the history
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 <sgruszka@redhat.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
Stanislaw Gruszka authored and nbd168 committed Mar 24, 2019
1 parent f2a18f5 commit 91ade88
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
3 changes: 3 additions & 0 deletions mt76x02.h
Expand Up @@ -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];
Expand Down
5 changes: 4 additions & 1 deletion mt76x02_regs.h
Expand Up @@ -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)
Expand Down
70 changes: 70 additions & 0 deletions mt76x02_usb_core.c
Expand Up @@ -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);

0 comments on commit 91ade88

Please sign in to comment.