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