18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#ifndef __MT76_UTIL_H
88c2ecf20Sopenharmony_ci#define __MT76_UTIL_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
118c2ecf20Sopenharmony_ci#include <linux/bitops.h>
128c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
138c2ecf20Sopenharmony_ci#include <net/mac80211.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistruct mt76_worker
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	struct task_struct *task;
188c2ecf20Sopenharmony_ci	void (*fn)(struct mt76_worker *);
198c2ecf20Sopenharmony_ci	unsigned long state;
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cienum {
238c2ecf20Sopenharmony_ci	MT76_WORKER_SCHEDULED,
248c2ecf20Sopenharmony_ci	MT76_WORKER_RUNNING,
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define MT76_INCR(_var, _size) \
288c2ecf20Sopenharmony_ci	(_var = (((_var) + 1) % (_size)))
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint mt76_wcid_alloc(u32 *mask, int size);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic inline bool
338c2ecf20Sopenharmony_cimt76_wcid_mask_test(u32 *mask, int idx)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	return mask[idx / 32] & BIT(idx % 32);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline void
398c2ecf20Sopenharmony_cimt76_wcid_mask_set(u32 *mask, int idx)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	mask[idx / 32] |= BIT(idx % 32);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline void
458c2ecf20Sopenharmony_cimt76_wcid_mask_clear(u32 *mask, int idx)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	mask[idx / 32] &= ~BIT(idx % 32);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic inline void
518c2ecf20Sopenharmony_cimt76_skb_set_moredata(struct sk_buff *skb, bool enable)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (enable)
568c2ecf20Sopenharmony_ci		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
578c2ecf20Sopenharmony_ci	else
588c2ecf20Sopenharmony_ci		hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ciint __mt76_worker_fn(void *ptr);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline int
648c2ecf20Sopenharmony_cimt76_worker_setup(struct ieee80211_hw *hw, struct mt76_worker *w,
658c2ecf20Sopenharmony_ci		  void (*fn)(struct mt76_worker *),
668c2ecf20Sopenharmony_ci		  const char *name)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	const char *dev_name = wiphy_name(hw->wiphy);
698c2ecf20Sopenharmony_ci	int ret;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (fn)
728c2ecf20Sopenharmony_ci		w->fn = fn;
738c2ecf20Sopenharmony_ci	w->task = kthread_create(__mt76_worker_fn, w, "mt76-%s %s",
748c2ecf20Sopenharmony_ci				 name, dev_name);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	ret = PTR_ERR_OR_ZERO(w->task);
778c2ecf20Sopenharmony_ci	if (ret) {
788c2ecf20Sopenharmony_ci		w->task = NULL;
798c2ecf20Sopenharmony_ci		return ret;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	wake_up_process(w->task);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline void mt76_worker_schedule(struct mt76_worker *w)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	if (!w->task)
908c2ecf20Sopenharmony_ci		return;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (!test_and_set_bit(MT76_WORKER_SCHEDULED, &w->state) &&
938c2ecf20Sopenharmony_ci	    !test_bit(MT76_WORKER_RUNNING, &w->state))
948c2ecf20Sopenharmony_ci		wake_up_process(w->task);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic inline void mt76_worker_disable(struct mt76_worker *w)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	if (!w->task)
1008c2ecf20Sopenharmony_ci		return;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	kthread_park(w->task);
1038c2ecf20Sopenharmony_ci	WRITE_ONCE(w->state, 0);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline void mt76_worker_enable(struct mt76_worker *w)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	if (!w->task)
1098c2ecf20Sopenharmony_ci		return;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	kthread_unpark(w->task);
1128c2ecf20Sopenharmony_ci	mt76_worker_schedule(w);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline void mt76_worker_teardown(struct mt76_worker *w)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	if (!w->task)
1188c2ecf20Sopenharmony_ci		return;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	kthread_stop(w->task);
1218c2ecf20Sopenharmony_ci	w->task = NULL;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#endif
125