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