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(wiphy: 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(ptr: w->task)) { |
71 | ret = PTR_ERR(ptr: 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(nr: MT76_WORKER_SCHEDULED, addr: &w->state) && |
85 | !test_bit(MT76_WORKER_RUNNING, &w->state)) |
86 | wake_up_process(tsk: 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(k: 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(k: 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(k: w->task); |
113 | w->task = NULL; |
114 | } |
115 | |
116 | #endif |
117 | |