1 /* SPDX-License-Identifier: BSD-3-Clause-Clear */ 2 /* 3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 4 */ 5 6 #ifndef __MT76_UTIL_H 7 #define __MT76_UTIL_H 8 9 #include <linux/skbuff.h> 10 #include <linux/bitops.h> 11 #include <linux/bitfield.h> 12 #include <net/mac80211.h> 13 14 struct mt76_worker 15 { 16 struct task_struct *task; 17 void (*fn)(struct mt76_worker *); 18 unsigned long state; 19 }; 20 21 enum { 22 MT76_WORKER_SCHEDULED, 23 MT76_WORKER_RUNNING, 24 }; 25 26 #define MT76_INCR(_var, _size) \ 27 (_var = (((_var) + 1) % (_size))) 28 29 int mt76_wcid_alloc(u32 *mask, int size); 30 31 static inline void 32 mt76_wcid_mask_set(u32 *mask, int idx) 33 { 34 mask[idx / 32] |= BIT(idx % 32); 35 } 36 37 static inline void 38 mt76_wcid_mask_clear(u32 *mask, int idx) 39 { 40 mask[idx / 32] &= ~BIT(idx % 32); 41 } 42 43 static inline void 44 mt76_skb_set_moredata(struct sk_buff *skb, bool enable) 45 { 46 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 47 48 if (enable) 49 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); 50 else 51 hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); 52 } 53 54 int __mt76_worker_fn(void *ptr); 55 56 static inline int 57 mt76_worker_setup(struct ieee80211_hw *hw, struct mt76_worker *w, 58 void (*fn)(struct mt76_worker *), 59 const char *name) 60 { 61 const char *dev_name = wiphy_name(hw->wiphy); 62 int ret; 63 64 if (fn) 65 w->fn = fn; 66 w->task = kthread_run(__mt76_worker_fn, w, 67 "mt76-%s %s", name, dev_name); 68 69 if (IS_ERR(w->task)) { 70 ret = PTR_ERR(w->task); 71 w->task = NULL; 72 return ret; 73 } 74 75 return 0; 76 } 77 78 static inline void mt76_worker_schedule(struct mt76_worker *w) 79 { 80 if (!w->task) 81 return; 82 83 if (!test_and_set_bit(MT76_WORKER_SCHEDULED, &w->state) && 84 !test_bit(MT76_WORKER_RUNNING, &w->state)) 85 wake_up_process(w->task); 86 } 87 88 static inline void mt76_worker_disable(struct mt76_worker *w) 89 { 90 if (!w->task) 91 return; 92 93 kthread_park(w->task); 94 WRITE_ONCE(w->state, 0); 95 } 96 97 static inline void mt76_worker_enable(struct mt76_worker *w) 98 { 99 if (!w->task) 100 return; 101 102 kthread_unpark(w->task); 103 mt76_worker_schedule(w); 104 } 105 106 static inline void mt76_worker_teardown(struct mt76_worker *w) 107 { 108 if (!w->task) 109 return; 110 111 kthread_stop(w->task); 112 w->task = NULL; 113 } 114 115 #endif 116