wifi: rtw89: rfk: add a completion to wait RF calibration report from C2H event
authorPing-Ke Shih <pkshih@realtek.com>
Fri, 2 Feb 2024 03:06:32 +0000 (11:06 +0800)
committerKalle Valo <kvalo@kernel.org>
Tue, 6 Feb 2024 18:05:21 +0000 (20:05 +0200)
The RF calibrations should be executed one by one, so add a completion
to ensure one is finish before next. The report from C2H event contains
state and optional version, and we only check the state for now. We also
care about the time a RF calibration takes, so record start time before
asking firmware to do calibration and get the delta time when receiving
report.

Consider SER recovery, we can't receive C2H event, use half of argument
'ms' as fixed delay that is 2 times of measured maximum time of
calibrations.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://msgid.link/20240202030642.108385-2-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h

index 260da86bf04af61c63ccfa052de8e6494b183960..c6c3e0c0bf843438e5dbfab0ff70a1a1ef3e0d44 100644 (file)
@@ -4205,6 +4205,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
        INIT_WORK(&btc->icmp_notify_work, rtw89_btc_ntfy_icmp_packet_work);
 
        init_completion(&rtwdev->fw.req.completion);
+       init_completion(&rtwdev->rfk_wait.completion);
 
        schedule_work(&rtwdev->load_firmware_work);
 
index 30cc77ac78c558e0e8b0d3c50b6e86369ca14ab0..d88a6b9bc4e9ee4da6735625bcdc7b0bab0385cb 100644 (file)
@@ -4252,6 +4252,21 @@ struct rtw89_phy_stat {
        struct rtw89_pkt_stat last_pkt_stat;
 };
 
+enum rtw89_rfk_report_state {
+       RTW89_RFK_STATE_START = 0x0,
+       RTW89_RFK_STATE_OK = 0x1,
+       RTW89_RFK_STATE_FAIL = 0x2,
+       RTW89_RFK_STATE_TIMEOUT = 0x3,
+       RTW89_RFK_STATE_H2C_CMD_ERR = 0x4,
+};
+
+struct rtw89_rfk_wait_info {
+       struct completion completion;
+       ktime_t start_time;
+       enum rtw89_rfk_report_state state;
+       u8 version;
+};
+
 #define RTW89_DACK_PATH_NR 2
 #define RTW89_DACK_IDX_NR 2
 #define RTW89_DACK_MSBK_NR 16
@@ -4944,6 +4959,7 @@ struct rtw89_dev {
        DECLARE_BITMAP(pkt_offload, RTW89_MAX_PKT_OFLD_NUM);
 
        struct rtw89_phy_stat phystat;
+       struct rtw89_rfk_wait_info rfk_wait;
        struct rtw89_dack_info dack;
        struct rtw89_iqk_info iqk;
        struct rtw89_dpk_info dpk;
index ae69e455cd645121227036529068a986fc6ce73d..9a2c50c35f2aa4ccbb426f07b534e753f050b9e1 100644 (file)
@@ -4013,6 +4013,12 @@ struct rtw89_c2h_rf_txgapk_rpt_log {
        u8 rsv1;
 } __packed;
 
+struct rtw89_c2h_rfk_report {
+       struct rtw89_c2h_hdr hdr;
+       u8 state; /* enum rtw89_rfk_report_state */
+       u8 version;
+} __packed;
+
 #define RTW89_FW_RSVD_PLE_SIZE 0x800
 
 #define RTW89_FW_BACKTRACE_INFO_SIZE 8
index f661be2f12878365749a46e4412fb94a367d9584..3de61c0d7b03afae383dcf1c6087854a96d7f224 100644 (file)
@@ -2834,9 +2834,61 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
        [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
 };
 
+void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+
+       wait->state = RTW89_RFK_STATE_START;
+       wait->start_time = ktime_get();
+       reinit_completion(&wait->completion);
+}
+
+int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name,
+                             unsigned int ms)
+{
+       struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+       unsigned long time_left;
+
+       /* Since we can't receive C2H event during SER, use a fixed delay. */
+       if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) {
+               fsleep(1000 * ms / 2);
+               goto out;
+       }
+
+       time_left = wait_for_completion_timeout(&wait->completion,
+                                               msecs_to_jiffies(ms));
+       if (time_left == 0) {
+               rtw89_warn(rtwdev, "failed to wait RF %s\n", rfk_name);
+               return -ETIMEDOUT;
+       } else if (wait->state != RTW89_RFK_STATE_OK) {
+               rtw89_warn(rtwdev, "failed to do RF %s result from state %d\n",
+                          rfk_name, wait->state);
+               return -EFAULT;
+       }
+
+out:
+       rtw89_debug(rtwdev, RTW89_DBG_RFK, "RF %s takes %lld ms to complete\n",
+                   rfk_name, ktime_ms_delta(ktime_get(), wait->start_time));
+
+       return 0;
+}
+
 static void
 rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
 {
+       const struct rtw89_c2h_rfk_report *report =
+               (const struct rtw89_c2h_rfk_report *)c2h->data;
+       struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
+
+       wait->state = report->state;
+       wait->version = report->version;
+
+       complete(&wait->completion);
+
+       rtw89_debug(rtwdev, RTW89_DBG_RFK,
+                   "RFK report state %d with version %d (%*ph)\n",
+                   wait->state, wait->version,
+                   (int)(len - sizeof(report->hdr)), &report->state);
 }
 
 static
index 13903ca1eaa9ec6f9c7347266a1465b98a508a3c..df915cb0833f366c093ea583f4dcab66fac99627 100644 (file)
@@ -885,6 +885,9 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
 bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func);
 void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
                          u32 len, u8 class, u8 func);
+void rtw89_phy_rfk_report_prep(struct rtw89_dev *rtwdev);
+int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name,
+                             unsigned int ms);
 void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev);
 void rtw89_phy_cfo_track_work(struct work_struct *work);
 void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val,