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