xref: /linux/drivers/net/wireless/mediatek/mt76/util.c (revision 2da68a77)
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
4  */
5 
6 #include <linux/module.h>
7 #include "mt76.h"
8 
9 bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
10 		 int timeout)
11 {
12 	u32 cur;
13 
14 	timeout /= 10;
15 	do {
16 		cur = __mt76_rr(dev, offset) & mask;
17 		if (cur == val)
18 			return true;
19 
20 		udelay(10);
21 	} while (timeout-- > 0);
22 
23 	return false;
24 }
25 EXPORT_SYMBOL_GPL(__mt76_poll);
26 
27 bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
28 		      int timeout)
29 {
30 	u32 cur;
31 
32 	timeout /= 10;
33 	do {
34 		cur = __mt76_rr(dev, offset) & mask;
35 		if (cur == val)
36 			return true;
37 
38 		usleep_range(10000, 20000);
39 	} while (timeout-- > 0);
40 
41 	return false;
42 }
43 EXPORT_SYMBOL_GPL(__mt76_poll_msec);
44 
45 int mt76_wcid_alloc(u32 *mask, int size)
46 {
47 	int i, idx = 0, cur;
48 
49 	for (i = 0; i < DIV_ROUND_UP(size, 32); i++) {
50 		idx = ffs(~mask[i]);
51 		if (!idx)
52 			continue;
53 
54 		idx--;
55 		cur = i * 32 + idx;
56 		if (cur >= size)
57 			break;
58 
59 		mask[i] |= BIT(idx);
60 		return cur;
61 	}
62 
63 	return -1;
64 }
65 EXPORT_SYMBOL_GPL(mt76_wcid_alloc);
66 
67 int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
68 {
69 	struct mt76_wcid *wcid;
70 	int i, j, min_rssi = 0;
71 	s8 cur_rssi;
72 
73 	local_bh_disable();
74 	rcu_read_lock();
75 
76 	for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
77 		u32 mask = dev->wcid_mask[i];
78 		u32 phy_mask = dev->wcid_phy_mask[i];
79 
80 		if (!mask)
81 			continue;
82 
83 		for (j = i * 32; mask; j++, mask >>= 1, phy_mask >>= 1) {
84 			if (!(mask & 1))
85 				continue;
86 
87 			if (!!(phy_mask & 1) != ext_phy)
88 				continue;
89 
90 			wcid = rcu_dereference(dev->wcid[j]);
91 			if (!wcid)
92 				continue;
93 
94 			spin_lock(&dev->rx_lock);
95 			if (wcid->inactive_count++ < 5)
96 				cur_rssi = -ewma_signal_read(&wcid->rssi);
97 			else
98 				cur_rssi = 0;
99 			spin_unlock(&dev->rx_lock);
100 
101 			if (cur_rssi < min_rssi)
102 				min_rssi = cur_rssi;
103 		}
104 	}
105 
106 	rcu_read_unlock();
107 	local_bh_enable();
108 
109 	return min_rssi;
110 }
111 EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi);
112 
113 int __mt76_worker_fn(void *ptr)
114 {
115 	struct mt76_worker *w = ptr;
116 
117 	while (!kthread_should_stop()) {
118 		set_current_state(TASK_INTERRUPTIBLE);
119 
120 		if (kthread_should_park()) {
121 			kthread_parkme();
122 			continue;
123 		}
124 
125 		if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) {
126 			schedule();
127 			continue;
128 		}
129 
130 		set_bit(MT76_WORKER_RUNNING, &w->state);
131 		set_current_state(TASK_RUNNING);
132 		w->fn(w);
133 		cond_resched();
134 		clear_bit(MT76_WORKER_RUNNING, &w->state);
135 	}
136 
137 	return 0;
138 }
139 EXPORT_SYMBOL_GPL(__mt76_worker_fn);
140 
141 MODULE_LICENSE("Dual BSD/GPL");
142