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, int tick) 29 { 30 u32 cur; 31 32 timeout /= tick; 33 do { 34 cur = __mt76_rr(dev, offset) & mask; 35 if (cur == val) 36 return true; 37 38 usleep_range(1000 * tick, 2000 * tick); 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, u8 phy_idx) 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 79 if (!mask) 80 continue; 81 82 for (j = i * 32; mask; j++, mask >>= 1) { 83 if (!(mask & 1)) 84 continue; 85 86 wcid = rcu_dereference(dev->wcid[j]); 87 if (!wcid || wcid->phy_idx != phy_idx) 88 continue; 89 90 spin_lock(&dev->rx_lock); 91 if (wcid->inactive_count++ < 5) 92 cur_rssi = -ewma_signal_read(&wcid->rssi); 93 else 94 cur_rssi = 0; 95 spin_unlock(&dev->rx_lock); 96 97 if (cur_rssi < min_rssi) 98 min_rssi = cur_rssi; 99 } 100 } 101 102 rcu_read_unlock(); 103 local_bh_enable(); 104 105 return min_rssi; 106 } 107 EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi); 108 109 int __mt76_worker_fn(void *ptr) 110 { 111 struct mt76_worker *w = ptr; 112 113 while (!kthread_should_stop()) { 114 set_current_state(TASK_INTERRUPTIBLE); 115 116 if (kthread_should_park()) { 117 kthread_parkme(); 118 continue; 119 } 120 121 if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) { 122 schedule(); 123 continue; 124 } 125 126 set_bit(MT76_WORKER_RUNNING, &w->state); 127 set_current_state(TASK_RUNNING); 128 w->fn(w); 129 cond_resched(); 130 clear_bit(MT76_WORKER_RUNNING, &w->state); 131 } 132 133 return 0; 134 } 135 EXPORT_SYMBOL_GPL(__mt76_worker_fn); 136 137 MODULE_DESCRIPTION("MediaTek MT76x helpers"); 138 MODULE_LICENSE("Dual BSD/GPL"); 139