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.
kmod-redhat-rtw89/SOURCES/0068-wifi-rtw89-introduce-h...

157 lines
5.9 KiB

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