16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /*
36c92544dSBjoern A. Zeeb * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
46c92544dSBjoern A. Zeeb */
56c92544dSBjoern A. Zeeb
66c92544dSBjoern A. Zeeb #include <linux/module.h>
76c92544dSBjoern A. Zeeb #if defined(__FreeBSD__)
86c92544dSBjoern A. Zeeb #include <linux/delay.h>
96c92544dSBjoern A. Zeeb #include <linux/kthread.h>
106c92544dSBjoern A. Zeeb #endif
116c92544dSBjoern A. Zeeb #include "mt76.h"
126c92544dSBjoern A. Zeeb
__mt76_poll(struct mt76_dev * dev,u32 offset,u32 mask,u32 val,int timeout)136c92544dSBjoern A. Zeeb bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
146c92544dSBjoern A. Zeeb int timeout)
156c92544dSBjoern A. Zeeb {
166c92544dSBjoern A. Zeeb u32 cur;
176c92544dSBjoern A. Zeeb
186c92544dSBjoern A. Zeeb timeout /= 10;
196c92544dSBjoern A. Zeeb do {
206c92544dSBjoern A. Zeeb cur = __mt76_rr(dev, offset) & mask;
216c92544dSBjoern A. Zeeb if (cur == val)
226c92544dSBjoern A. Zeeb return true;
236c92544dSBjoern A. Zeeb
246c92544dSBjoern A. Zeeb udelay(10);
256c92544dSBjoern A. Zeeb } while (timeout-- > 0);
266c92544dSBjoern A. Zeeb
276c92544dSBjoern A. Zeeb return false;
286c92544dSBjoern A. Zeeb }
296c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_poll);
306c92544dSBjoern A. Zeeb
____mt76_poll_msec(struct mt76_dev * dev,u32 offset,u32 mask,u32 val,int timeout,int tick)31*cbb3ec25SBjoern A. Zeeb bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
32*cbb3ec25SBjoern A. Zeeb int timeout, int tick)
336c92544dSBjoern A. Zeeb {
346c92544dSBjoern A. Zeeb u32 cur;
356c92544dSBjoern A. Zeeb
36*cbb3ec25SBjoern A. Zeeb timeout /= tick;
376c92544dSBjoern A. Zeeb do {
386c92544dSBjoern A. Zeeb cur = __mt76_rr(dev, offset) & mask;
396c92544dSBjoern A. Zeeb if (cur == val)
406c92544dSBjoern A. Zeeb return true;
416c92544dSBjoern A. Zeeb
42*cbb3ec25SBjoern A. Zeeb usleep_range(1000 * tick, 2000 * tick);
436c92544dSBjoern A. Zeeb } while (timeout-- > 0);
446c92544dSBjoern A. Zeeb
456c92544dSBjoern A. Zeeb return false;
466c92544dSBjoern A. Zeeb }
47*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(____mt76_poll_msec);
486c92544dSBjoern A. Zeeb
mt76_wcid_alloc(u32 * mask,int size)496c92544dSBjoern A. Zeeb int mt76_wcid_alloc(u32 *mask, int size)
506c92544dSBjoern A. Zeeb {
516c92544dSBjoern A. Zeeb int i, idx = 0, cur;
526c92544dSBjoern A. Zeeb
536c92544dSBjoern A. Zeeb for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
546c92544dSBjoern A. Zeeb idx = ffs(~mask[i]);
556c92544dSBjoern A. Zeeb if (!idx)
566c92544dSBjoern A. Zeeb continue;
576c92544dSBjoern A. Zeeb
586c92544dSBjoern A. Zeeb idx--;
596c92544dSBjoern A. Zeeb cur = i * 32 + idx;
606c92544dSBjoern A. Zeeb if (cur >= size)
616c92544dSBjoern A. Zeeb break;
626c92544dSBjoern A. Zeeb
636c92544dSBjoern A. Zeeb mask[i] |= BIT(idx);
646c92544dSBjoern A. Zeeb return cur;
656c92544dSBjoern A. Zeeb }
666c92544dSBjoern A. Zeeb
676c92544dSBjoern A. Zeeb return -1;
686c92544dSBjoern A. Zeeb }
696c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
706c92544dSBjoern A. Zeeb
mt76_get_min_avg_rssi(struct mt76_dev * dev,bool ext_phy)716c92544dSBjoern A. Zeeb int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
726c92544dSBjoern A. Zeeb {
736c92544dSBjoern A. Zeeb struct mt76_wcid *wcid;
746c92544dSBjoern A. Zeeb int i, j, min_rssi = 0;
756c92544dSBjoern A. Zeeb s8 cur_rssi;
766c92544dSBjoern A. Zeeb
776c92544dSBjoern A. Zeeb local_bh_disable();
786c92544dSBjoern A. Zeeb rcu_read_lock();
796c92544dSBjoern A. Zeeb
806c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
816c92544dSBjoern A. Zeeb u32 mask = dev->wcid_mask[i];
826c92544dSBjoern A. Zeeb u32 phy_mask = dev->wcid_phy_mask[i];
836c92544dSBjoern A. Zeeb
846c92544dSBjoern A. Zeeb if (!mask)
856c92544dSBjoern A. Zeeb continue;
866c92544dSBjoern A. Zeeb
876c92544dSBjoern A. Zeeb for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) {
886c92544dSBjoern A. Zeeb if (!(mask & 1))
896c92544dSBjoern A. Zeeb continue;
906c92544dSBjoern A. Zeeb
916c92544dSBjoern A. Zeeb if (!!(phy_mask & 1) != ext_phy)
926c92544dSBjoern A. Zeeb continue;
936c92544dSBjoern A. Zeeb
946c92544dSBjoern A. Zeeb wcid = rcu_dereference(dev->wcid[j]);
956c92544dSBjoern A. Zeeb if (!wcid)
966c92544dSBjoern A. Zeeb continue;
976c92544dSBjoern A. Zeeb
986c92544dSBjoern A. Zeeb spin_lock(&dev->rx_lock);
996c92544dSBjoern A. Zeeb if (wcid->inactive_count++ < 5)
1006c92544dSBjoern A. Zeeb cur_rssi = -ewma_signal_read(&wcid->rssi);
1016c92544dSBjoern A. Zeeb else
1026c92544dSBjoern A. Zeeb cur_rssi = 0;
1036c92544dSBjoern A. Zeeb spin_unlock(&dev->rx_lock);
1046c92544dSBjoern A. Zeeb
1056c92544dSBjoern A. Zeeb if (cur_rssi < min_rssi)
1066c92544dSBjoern A. Zeeb min_rssi = cur_rssi;
1076c92544dSBjoern A. Zeeb }
1086c92544dSBjoern A. Zeeb }
1096c92544dSBjoern A. Zeeb
1106c92544dSBjoern A. Zeeb rcu_read_unlock();
1116c92544dSBjoern A. Zeeb local_bh_enable();
1126c92544dSBjoern A. Zeeb
1136c92544dSBjoern A. Zeeb return min_rssi;
1146c92544dSBjoern A. Zeeb }
1156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi);
1166c92544dSBjoern A. Zeeb
__mt76_worker_fn(void * ptr)1176c92544dSBjoern A. Zeeb int __mt76_worker_fn(void *ptr)
1186c92544dSBjoern A. Zeeb {
1196c92544dSBjoern A. Zeeb struct mt76_worker *w = ptr;
1206c92544dSBjoern A. Zeeb
1216c92544dSBjoern A. Zeeb while (!kthread_should_stop()) {
1226c92544dSBjoern A. Zeeb set_current_state(TASK_INTERRUPTIBLE);
1236c92544dSBjoern A. Zeeb
1246c92544dSBjoern A. Zeeb if (kthread_should_park()) {
1256c92544dSBjoern A. Zeeb kthread_parkme();
1266c92544dSBjoern A. Zeeb continue;
1276c92544dSBjoern A. Zeeb }
1286c92544dSBjoern A. Zeeb
1296c92544dSBjoern A. Zeeb if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) {
1306c92544dSBjoern A. Zeeb schedule();
1316c92544dSBjoern A. Zeeb continue;
1326c92544dSBjoern A. Zeeb }
1336c92544dSBjoern A. Zeeb
1346c92544dSBjoern A. Zeeb set_bit(MT76_WORKER_RUNNING, &w->state);
1356c92544dSBjoern A. Zeeb set_current_state(TASK_RUNNING);
1366c92544dSBjoern A. Zeeb w->fn(w);
1376c92544dSBjoern A. Zeeb cond_resched();
1386c92544dSBjoern A. Zeeb clear_bit(MT76_WORKER_RUNNING, &w->state);
1396c92544dSBjoern A. Zeeb }
1406c92544dSBjoern A. Zeeb
1416c92544dSBjoern A. Zeeb return 0;
1426c92544dSBjoern A. Zeeb }
1436c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_worker_fn);
1446c92544dSBjoern A. Zeeb
1456c92544dSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
1466c92544dSBjoern A. Zeeb #if defined(__FreeBSD__)
1476c92544dSBjoern A. Zeeb MODULE_VERSION(mt76_core, 1);
1486c92544dSBjoern A. Zeeb MODULE_DEPEND(mt76_core, linuxkpi, 1, 1, 1);
1496c92544dSBjoern A. Zeeb MODULE_DEPEND(mt76_core, linuxkpi_wlan, 1, 1, 1);
1506c92544dSBjoern A. Zeeb #endif
151