@@ -42,7 +42,7 @@ static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw,
list_add_tail(&rtwtxq->list, &rtwdev->txqs);
spin_unlock_bh(&rtwdev->txq_lock);
- tasklet_schedule(&rtwdev->tx_tasklet);
+ rtw_work_schedule(&rtwdev->tx_work);
}
static int rtw_ops_start(struct ieee80211_hw *hw)
@@ -2,6 +2,7 @@
/* Copyright(c) 2018-2019 Realtek Corporation
*/
+#include <uapi/linux/sched/types.h>
#include "main.h"
#include "regd.h"
#include "fw.h"
@@ -311,6 +312,7 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta,
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
rtw_txq_cleanup(rtwdev, sta->txq[i]);
+ bitmap_zero(rtwdev->tx_work.state, RTW_WORK_FLAG_MAX);
kfree(si->mask);
rtwdev->sta_cnt--;
@@ -1657,7 +1659,8 @@ int rtw_core_init(struct rtw_dev *rtwdev)
timer_setup(&rtwdev->tx_report.purge_timer,
rtw_tx_report_purge_timer, 0);
- tasklet_setup(&rtwdev->tx_tasklet, rtw_tx_tasklet);
+ rtw_work_setup(&rtwdev->tx_work, rtw_tx_work);
+ sched_set_fifo_low(rtwdev->tx_work.task);
INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work);
INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work);
@@ -1735,7 +1738,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
if (wow_fw->firmware)
release_firmware(wow_fw->firmware);
- tasklet_kill(&rtwdev->tx_tasklet);
+ rtw_work_kill(&rtwdev->tx_work);
spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags);
skb_queue_purge(&rtwdev->tx_report.queue);
spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags);
@@ -1765,7 +1765,7 @@ struct rtw_dev {
/* used to protect txqs list */
spinlock_t txq_lock;
struct list_head txqs;
- struct tasklet_struct tx_tasklet;
+ struct rtw_work tx_work;
struct work_struct ba_work;
struct rtw_tx_report tx_report;
@@ -592,9 +592,9 @@ static void rtw_txq_push(struct rtw_dev *rtwdev,
rcu_read_unlock();
}
-void rtw_tx_tasklet(struct tasklet_struct *t)
+void rtw_tx_work(struct rtw_work *w)
{
- struct rtw_dev *rtwdev = from_tasklet(rtwdev, t, tx_tasklet);
+ struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work);
struct rtw_txq *rtwtxq, *tmp;
spin_lock_bh(&rtwdev->txq_lock);
@@ -98,7 +98,7 @@ void rtw_tx(struct rtw_dev *rtwdev,
struct sk_buff *skb);
void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq);
-void rtw_tx_tasklet(struct tasklet_struct *t);
+void rtw_tx_work(struct rtw_work *w);
void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev,
struct rtw_tx_pkt_info *pkt_info,
struct ieee80211_sta *sta,
@@ -105,3 +105,23 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss)
*mcs = rate - DESC_RATEMCS0;
}
}
+
+int rtw_work_func(void *ptr)
+{
+ struct rtw_work *w = ptr;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!test_and_clear_bit(RTW_WORK_FLAG_SCHEDULED, w->state)) {
+ schedule();
+ continue;
+ }
+ set_bit(RTW_WORK_FLAG_RUNNING, w->state);
+ set_current_state(TASK_RUNNING);
+ w->callback(w);
+ cond_resched();
+ clear_bit(RTW_WORK_FLAG_RUNNING, w->state);
+ }
+
+ return 0;
+}
@@ -5,8 +5,62 @@
#ifndef __RTW_UTIL_H__
#define __RTW_UTIL_H__
+#include <linux/err.h>
+
struct rtw_dev;
+enum {
+ RTW_WORK_FLAG_SCHEDULED,
+ RTW_WORK_FLAG_RUNNING,
+
+ /* keep last */
+ RTW_WORK_FLAG_MAX,
+};
+
+struct rtw_work {
+ struct task_struct *task;
+ void (*callback)(struct rtw_work *w);
+ DECLARE_BITMAP(state, RTW_WORK_FLAG_MAX);
+};
+
+int rtw_work_func(void *ptr);
+
+static inline int rtw_work_setup(struct rtw_work *w,
+ void (*cb)(struct rtw_work *w))
+{
+ int ret;
+
+ w->callback = cb;
+ w->task = kthread_create(rtw_work_func, w, "rtw_tx_work");
+
+ ret = PTR_ERR_OR_ZERO(w->task);
+ if (ret) {
+ w->task = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline void rtw_work_kill(struct rtw_work *w)
+{
+ if (!w->task)
+ return;
+
+ kthread_stop(w->task);
+ w->task = NULL;
+}
+
+static inline void rtw_work_schedule(struct rtw_work *w)
+{
+ if (!w->task)
+ return;
+
+ if (!test_and_set_bit(RTW_WORK_FLAG_SCHEDULED, w->state) &&
+ !test_bit(RTW_WORK_FLAG_RUNNING, w->state))
+ wake_up_process(w->task);
+}
+
#define rtw_iterate_vifs(rtwdev, iterator, data) \
ieee80211_iterate_active_interfaces(rtwdev->hw, \
IEEE80211_IFACE_ITER_NORMAL, iterator, data)