18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include "mt76.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_cibool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
108c2ecf20Sopenharmony_ci		 int timeout)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	u32 cur;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	timeout /= 10;
158c2ecf20Sopenharmony_ci	do {
168c2ecf20Sopenharmony_ci		cur = __mt76_rr(dev, offset) & mask;
178c2ecf20Sopenharmony_ci		if (cur == val)
188c2ecf20Sopenharmony_ci			return true;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci		udelay(10);
218c2ecf20Sopenharmony_ci	} while (timeout-- > 0);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	return false;
248c2ecf20Sopenharmony_ci}
258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt76_poll);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cibool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
288c2ecf20Sopenharmony_ci		      int timeout)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	u32 cur;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	timeout /= 10;
338c2ecf20Sopenharmony_ci	do {
348c2ecf20Sopenharmony_ci		cur = __mt76_rr(dev, offset) & mask;
358c2ecf20Sopenharmony_ci		if (cur == val)
368c2ecf20Sopenharmony_ci			return true;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci		usleep_range(10000, 20000);
398c2ecf20Sopenharmony_ci	} while (timeout-- > 0);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	return false;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt76_poll_msec);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciint mt76_wcid_alloc(u32 *mask, int size)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	int i, idx = 0, cur;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
508c2ecf20Sopenharmony_ci		idx = ffs(~mask[i]);
518c2ecf20Sopenharmony_ci		if (!idx)
528c2ecf20Sopenharmony_ci			continue;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		idx--;
558c2ecf20Sopenharmony_ci		cur = i * 32 + idx;
568c2ecf20Sopenharmony_ci		if (cur >= size)
578c2ecf20Sopenharmony_ci			break;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		mask[i] |= BIT(idx);
608c2ecf20Sopenharmony_ci		return cur;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return -1;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_wcid_alloc);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
708c2ecf20Sopenharmony_ci	int i, j, min_rssi = 0;
718c2ecf20Sopenharmony_ci	s8 cur_rssi;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	local_bh_disable();
748c2ecf20Sopenharmony_ci	rcu_read_lock();
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
778c2ecf20Sopenharmony_ci		u32 mask = dev->wcid_mask[i];
788c2ecf20Sopenharmony_ci		u32 phy_mask = dev->wcid_phy_mask[i];
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		if (!mask)
818c2ecf20Sopenharmony_ci			continue;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) {
848c2ecf20Sopenharmony_ci			if (!(mask & 1))
858c2ecf20Sopenharmony_ci				continue;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci			if (!!(phy_mask & 1) != ext_phy)
888c2ecf20Sopenharmony_ci				continue;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci			wcid = rcu_dereference(dev->wcid[j]);
918c2ecf20Sopenharmony_ci			if (!wcid)
928c2ecf20Sopenharmony_ci				continue;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci			spin_lock(&dev->rx_lock);
958c2ecf20Sopenharmony_ci			if (wcid->inactive_count++ < 5)
968c2ecf20Sopenharmony_ci				cur_rssi = -ewma_signal_read(&wcid->rssi);
978c2ecf20Sopenharmony_ci			else
988c2ecf20Sopenharmony_ci				cur_rssi = 0;
998c2ecf20Sopenharmony_ci			spin_unlock(&dev->rx_lock);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci			if (cur_rssi < min_rssi)
1028c2ecf20Sopenharmony_ci				min_rssi = cur_rssi;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	rcu_read_unlock();
1078c2ecf20Sopenharmony_ci	local_bh_enable();
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return min_rssi;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciint __mt76_worker_fn(void *ptr)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct mt76_worker *w = ptr;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
1188c2ecf20Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		if (kthread_should_park()) {
1218c2ecf20Sopenharmony_ci			kthread_parkme();
1228c2ecf20Sopenharmony_ci			continue;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) {
1268c2ecf20Sopenharmony_ci			schedule();
1278c2ecf20Sopenharmony_ci			continue;
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		set_bit(MT76_WORKER_RUNNING, &w->state);
1318c2ecf20Sopenharmony_ci		set_current_state(TASK_RUNNING);
1328c2ecf20Sopenharmony_ci		w->fn(w);
1338c2ecf20Sopenharmony_ci		cond_resched();
1348c2ecf20Sopenharmony_ci		clear_bit(MT76_WORKER_RUNNING, &w->state);
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return 0;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt76_worker_fn);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
142