Some H2C commands need to wait for target C2H events to confirm they
are executed well. The characteristics of a target C2H event will be
encoded into a value, called condition. Then, the corresponding H2C
command will wait for it. And, C2H events will complete a condition
according to their own characteristics. So, when conditions of both
side match, the corresponding H2C command will be completed.
Originally, condition waiting window is opened after the H2C command
is sent. However, for CPU-bound systems, target C2H event might be
already done before the H2C command opens condition waiting window.
Without that, C2H event won't match condition, and it will complete
nothing. Finally, H2C command wait will time out.
Hence, now open condition waiting window first for H2C commands which
need to wait for target C2H events. The waiting function is split to
two parts, prepare and evaluate. And, waiting side becomes the below
where prepare part and evaluate part must be a pair.
waiting prepare: condition
(open condition waiting window)
Do the needed things to trigger completing side.
Record errors that will cause no real completer.
waiting evaluate: prepare, errors
(start waiting for completion if things are fine;
otherwise, clean up and return final result.)
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250915065352.39082-1-pkshih@realtek.com
}
}
-int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
+struct rtw89_wait_response *
+rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond)
{
struct rtw89_wait_response *prep;
- unsigned long time_left;
unsigned int cur;
- int err = 0;
+
+ /* use -EPERM _iff_ telling eval side not to make any changes */
cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
if (cur != RTW89_WAIT_COND_IDLE)
- return -EBUSY;
+ return ERR_PTR(-EPERM);
prep = kzalloc(sizeof(*prep), GFP_KERNEL);
- if (!prep) {
- err = -ENOMEM;
- goto reset;
- }
+ if (!prep)
+ return ERR_PTR(-ENOMEM);
init_completion(&prep->completion);
rcu_assign_pointer(wait->resp, prep);
+ return prep;
+}
+
+int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait,
+ struct rtw89_wait_response *prep, int err)
+{
+ unsigned long time_left;
+
+ if (IS_ERR(prep)) {
+ err = err ?: PTR_ERR(prep);
+
+ /* special error case: no permission to reset anything */
+ if (PTR_ERR(prep) == -EPERM)
+ return err;
+
+ goto reset;
+ }
+
+ if (err)
+ goto cleanup;
+
time_left = wait_for_completion_timeout(&prep->completion,
RTW89_WAIT_FOR_COND_TIMEOUT);
if (time_left == 0) {
const char *rtw89_regd_get_string(enum rtw89_regulation_type regd);
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);
+struct rtw89_wait_response *
+rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond)
+__acquires(rtw89_wait);
+int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait,
+ struct rtw89_wait_response *prep, int err)
+__releases(rtw89_wait);
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);
static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
struct rtw89_wait_info *wait, unsigned int cond)
{
- int ret;
+ struct rtw89_wait_response *prep;
+ int ret = 0;
lockdep_assert_wiphy(rtwdev->hw->wiphy);
+ prep = rtw89_wait_for_cond_prep(wait, cond);
+ if (IS_ERR(prep))
+ goto out;
+
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
rtw89_err(rtwdev, "failed to send h2c\n");
dev_kfree_skb_any(skb);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
- if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags))
- return 1;
+ if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) {
+ ret = 1;
+ goto out;
+ }
- return rtw89_wait_for_cond(wait, cond);
+out:
+ return rtw89_wait_for_cond_eval(wait, prep, ret);
}
#define H2C_ADD_MCC_LEN 16