xref: /freebsd/sys/contrib/dev/mediatek/mt76/util.c (revision cbb3ec25236ba72f91cbdf23f8b78b9d1af0cedf)
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