You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.9 KiB
157 lines
5.9 KiB
1 year ago
|
From 54cf47d424e54c02da1ac09766a86a09e13be7d9 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= <ihuguet@redhat.com>
|
||
|
Date: Wed, 24 May 2023 15:00:30 +0200
|
||
|
Subject: [PATCH 068/142] wifi: rtw89: introduce helpers to wait/complete on
|
||
|
condition
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
Bugzilla: https://bugzilla.redhat.com/2207499
|
||
|
|
||
|
commit 22b10cdb73921cfb28ccde5ce8b47d7fc434e7c6
|
||
|
Author: Zong-Zhe Yang <kevin_yang@realtek.com>
|
||
|
Date: Tue Nov 29 16:31:27 2022 +0800
|
||
|
|
||
|
wifi: rtw89: introduce helpers to wait/complete on condition
|
||
|
|
||
|
MCC (multi-channel concurrency) related H2Cs (host to chip commands)
|
||
|
require to wait for C2H (chip to host events) responses to judge the
|
||
|
execution result and data. We introduce helpers to assist this process.
|
||
|
Besides, we would like the helpers to be generic for use in driver even
|
||
|
outside of MCC H2C/C2H, so we make a independent patch for them.
|
||
|
|
||
|
In the following, I describe the things first.
|
||
|
```
|
||
|
(A) C2H is generated by FW, and then transferred upto driver. Hence,
|
||
|
driver cannot get it immediately without a bit waitting/blocking.
|
||
|
For this, we choose to use wait_for_completion_*() instead of
|
||
|
busy polling.
|
||
|
(B) From the driver management perspective, a scenario, e.g. MCC,
|
||
|
may have mulitple kind of H2C functions requiring this process
|
||
|
to wait for corresponding C2Hs. But, the driver management flow
|
||
|
uses mutex to protect each behavior. So, one scenario triggers
|
||
|
one H2C function at one time. To avoid rampant instances of
|
||
|
struct completion for each H2C function, we choose to use one
|
||
|
struct completion with one condition flag for one scenario.
|
||
|
(C) C2Hs, which H2Cs will be waitting for, cannot be ordered with
|
||
|
driver management flow, i.e. cannot enqueue work to the same
|
||
|
ordered workqueue and cannot lock by the same mutex, to prevent
|
||
|
H2C side from getting no C2H responses. So, those C2Hs are parsed
|
||
|
in interrupt context directly as done in previous commit.
|
||
|
(D) Following (C), the above underline H2Cs and C2Hs will be handled
|
||
|
in different contexts without sync. So, we use atomic_cmpxchg()
|
||
|
to compare and change the condition in atomic.
|
||
|
```
|
||
|
|
||
|
So, we introduce struct rtw89_wait_info which combines struct completion
|
||
|
and atomic_t. Then, the below are the descriptions for helper functions.
|
||
|
* rtw89_wait_for_cond() to wait for a completion based on a condition.
|
||
|
* rtw89_complete_cond() to complete a given condition and carry data.
|
||
|
Each rtw89_wait_info instance independently determines the meaning of
|
||
|
its waitting conditions. But, RTW89_WAIT_COND_IDLE (UINT_MAX) is reserved.
|
||
|
|
||
|
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
|
||
|
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
|
||
|
Signed-off-by: Kalle Valo <kvalo@kernel.org>
|
||
|
Link: https://lore.kernel.org/r/20221129083130.45708-4-pkshih@realtek.com
|
||
|
|
||
|
Signed-off-by: Íñigo Huguet <ihuguet@redhat.com>
|
||
|
---
|
||
|
drivers/net/wireless/realtek/rtw89/core.c | 35 +++++++++++++++++++++++++++++++
|
||
|
drivers/net/wireless/realtek/rtw89/core.h | 25 ++++++++++++++++++++++
|
||
|
2 files changed, 60 insertions(+)
|
||
|
|
||
|
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
|
||
|
index 3647998014408..4ec3c982ff4e0 100644
|
||
|
--- a/drivers/net/wireless/realtek/rtw89/core.c
|
||
|
+++ b/drivers/net/wireless/realtek/rtw89/core.c
|
||
|
@@ -2974,6 +2974,41 @@ void rtw89_core_update_beacon_work(struct work_struct *work)
|
||
|
mutex_unlock(&rtwdev->mutex);
|
||
|
}
|
||
|
|
||
|
+int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
|
||
|
+{
|
||
|
+ struct completion *cmpl = &wait->completion;
|
||
|
+ unsigned long timeout;
|
||
|
+ unsigned int cur;
|
||
|
+
|
||
|
+ cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
|
||
|
+ if (cur != RTW89_WAIT_COND_IDLE)
|
||
|
+ return -EBUSY;
|
||
|
+
|
||
|
+ timeout = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
|
||
|
+ if (timeout == 0) {
|
||
|
+ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
|
||
|
+ return -ETIMEDOUT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (wait->data.err)
|
||
|
+ return -EFAULT;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
|
||
|
+ const struct rtw89_completion_data *data)
|
||
|
+{
|
||
|
+ unsigned int cur;
|
||
|
+
|
||
|
+ cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE);
|
||
|
+ if (cur != cond)
|
||
|
+ return;
|
||
|
+
|
||
|
+ wait->data = *data;
|
||
|
+ complete(&wait->completion);
|
||
|
+}
|
||
|
+
|
||
|
int rtw89_core_start(struct rtw89_dev *rtwdev)
|
||
|
{
|
||
|
int ret;
|
||
|
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
|
||
|
index d0efeeabcb773..a9b9b1c901c18 100644
|
||
|
--- a/drivers/net/wireless/realtek/rtw89/core.h
|
||
|
+++ b/drivers/net/wireless/realtek/rtw89/core.h
|
||
|
@@ -2812,6 +2812,28 @@ struct rtw89_mac_info {
|
||
|
u8 cpwm_seq_num;
|
||
|
};
|
||
|
|
||
|
+#define RTW89_COMPLETION_BUF_SIZE 24
|
||
|
+#define RTW89_WAIT_COND_IDLE UINT_MAX
|
||
|
+
|
||
|
+struct rtw89_completion_data {
|
||
|
+ bool err;
|
||
|
+ u8 buf[RTW89_COMPLETION_BUF_SIZE];
|
||
|
+};
|
||
|
+
|
||
|
+struct rtw89_wait_info {
|
||
|
+ atomic_t cond;
|
||
|
+ struct completion completion;
|
||
|
+ struct rtw89_completion_data data;
|
||
|
+};
|
||
|
+
|
||
|
+#define RTW89_WAIT_FOR_COND_TIMEOUT msecs_to_jiffies(100)
|
||
|
+
|
||
|
+static inline void rtw89_init_wait(struct rtw89_wait_info *wait)
|
||
|
+{
|
||
|
+ init_completion(&wait->completion);
|
||
|
+ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
|
||
|
+}
|
||
|
+
|
||
|
enum rtw89_fw_type {
|
||
|
RTW89_FW_NORMAL = 1,
|
||
|
RTW89_FW_WOWLAN = 3,
|
||
|
@@ -4469,6 +4491,9 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
|
||
|
void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request);
|
||
|
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
|
||
|
struct rtw89_traffic_stats *stats);
|
||
|
+int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond);
|
||
|
+void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
|
||
|
+ const struct rtw89_completion_data *data);
|
||
|
int rtw89_core_start(struct rtw89_dev *rtwdev);
|
||
|
void rtw89_core_stop(struct rtw89_dev *rtwdev);
|
||
|
void rtw89_core_update_beacon_work(struct work_struct *work);
|
||
|
--
|
||
|
2.13.6
|
||
|
|