From patchwork Fri Oct 30 08:40:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Huang X-Patchwork-Id: 11868771 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BFEFB1592 for ; Fri, 30 Oct 2020 08:40:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A7A862083B for ; Fri, 30 Oct 2020 08:40:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726041AbgJ3Ik3 (ORCPT ); Fri, 30 Oct 2020 04:40:29 -0400 Received: from rtits2.realtek.com ([211.75.126.72]:48082 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725974AbgJ3Ik2 (ORCPT ); Fri, 30 Oct 2020 04:40:28 -0400 Authenticated-By: X-SpamFilter-By: ArmorX SpamTrap 5.73 with qID 09U8eIeW5008838, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (rtexmb04.realtek.com.tw[172.21.6.97]) by rtits2.realtek.com.tw (8.15.2/2.70/5.88) with ESMTPS id 09U8eIeW5008838 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 30 Oct 2020 16:40:18 +0800 Received: from localhost.localdomain (172.21.69.222) by RTEXMB04.realtek.com.tw (172.21.6.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2044.4; Fri, 30 Oct 2020 16:40:18 +0800 From: To: , CC: , Subject: [PATCH 1/4] rtw88: sync the power state between driver and firmware Date: Fri, 30 Oct 2020 16:40:10 +0800 Message-ID: <20201030084013.8457-2-tehuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030084013.8457-1-tehuang@realtek.com> References: <20201030084013.8457-1-tehuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.69.222] X-ClientProxiedBy: RTEXMB03.realtek.com.tw (172.21.6.96) To RTEXMB04.realtek.com.tw (172.21.6.97) Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Chin-Yen Lee In current flow, driver issues power requests to firmware for entering or leaving deep power mode. But driver does not wait for an ack from firmware via reading CPWM register when driver requests to enter deep power mode. The behavior will lead to unsynchronized state between firmware and driver. Furthermore, consecutive same power requests may confuse firmware and leads to unexpected value of CPWM register. This patch ensures that the power request will wait for an ack from firmware and only send one power request each time. Signed-off-by: Chin-Yen Lee Signed-off-by: Tzu-En Huang --- drivers/net/wireless/realtek/rtw88/ps.c | 69 +++++++++++-------------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 7a189a9926fe..8ed243628dcb 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -68,48 +68,39 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) { u8 request, confirm, polling; - u8 polling_cnt; - u8 retry_cnt = 0; - - for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { - request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); - confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); - - /* toggle to request power mode, others remain 0 */ - request ^= request | BIT_RPWM_TOGGLE; - if (!enter) { - request |= POWER_MODE_ACK; - } else { - request |= POWER_MODE_LCLK; - if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) - request |= POWER_MODE_PG; - } - - rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); - - if (enter) - return; + int ret; - /* check confirm power mode has left power save state */ - for (polling_cnt = 0; polling_cnt < 50; polling_cnt++) { - polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); - if ((polling ^ confirm) & BIT_RPWM_TOGGLE) - return; - udelay(100); - } - - /* in case of fw/hw missed the request, retry */ - rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", - retry_cnt); + request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); + confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + + /* toggle to request power mode, others remain 0 */ + request ^= request | BIT_RPWM_TOGGLE; + if (enter) { + request |= POWER_MODE_LCLK; + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + request |= POWER_MODE_PG; } + /* Each request require an ack from firmware */ + request |= POWER_MODE_ACK; - /* Hit here means that driver failed to change hardware power mode to - * active state after retry 3 times. If the power state is locked at - * Deep sleep, most of the hardware circuits is not working, even - * register read/write. It should be treated as fatal error and - * requires an entire analysis about the firmware/hardware - */ - WARN(1, "Hardware power state locked\n"); + rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); + + /* Check firmware get the power requset and ack via cpwm register */ + ret = read_poll_timeout_atomic(rtw_read8, polling, + (polling ^ confirm) & BIT_RPWM_TOGGLE, + 100, 15000, true, rtwdev, + rtwdev->hci.cpwm_addr); + if (ret) { + /* Hit here means that driver failed to get an ack from firmware. + * The reason could be that hardware is locked at Deep sleep, + * so most of the hardware circuits are not working, even + * register read/write; or firmware is locked in some state and + * cannot get the request. It should be treated as fatal error + * and requires an entire analysis about the firmware/hardware. + */ + WARN(1, "firmware failed to ack driver for %s Deep Power mode\n", + enter ? "entering" : "leaving"); + } } EXPORT_SYMBOL(rtw_power_mode_change); From patchwork Fri Oct 30 08:40:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Huang X-Patchwork-Id: 11868767 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D7B6157C for ; Fri, 30 Oct 2020 08:40:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 04F782083B for ; Fri, 30 Oct 2020 08:40:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726003AbgJ3Ik2 (ORCPT ); Fri, 30 Oct 2020 04:40:28 -0400 Received: from rtits2.realtek.com ([211.75.126.72]:48081 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725875AbgJ3Ik0 (ORCPT ); Fri, 30 Oct 2020 04:40:26 -0400 Authenticated-By: X-SpamFilter-By: ArmorX SpamTrap 5.73 with qID 09U8eIeX5008838, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (rtexmb04.realtek.com.tw[172.21.6.97]) by rtits2.realtek.com.tw (8.15.2/2.70/5.88) with ESMTPS id 09U8eIeX5008838 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 30 Oct 2020 16:40:18 +0800 Received: from localhost.localdomain (172.21.69.222) by RTEXMB04.realtek.com.tw (172.21.6.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2044.4; Fri, 30 Oct 2020 16:40:18 +0800 From: To: , CC: , Subject: [PATCH 2/4] rtw88: store firmware feature in firmware header Date: Fri, 30 Oct 2020 16:40:11 +0800 Message-ID: <20201030084013.8457-3-tehuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030084013.8457-1-tehuang@realtek.com> References: <20201030084013.8457-1-tehuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.69.222] X-ClientProxiedBy: RTEXMB03.realtek.com.tw (172.21.6.96) To RTEXMB04.realtek.com.tw (172.21.6.97) Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Chin-Yen Lee Some functions need the support of firmware with special version. In order to get the feature of current firmware, we store the information in firmware header and parse after firmware is loaded. The current feature list in firmware header includes checking leave lps via C2H and supported lps deep mode. Signed-off-by: Chin-Yen Lee Signed-off-by: Tzu-En Huang --- drivers/net/wireless/realtek/rtw88/fw.h | 10 +++++++++- drivers/net/wireless/realtek/rtw88/main.c | 13 +++++++++++++ drivers/net/wireless/realtek/rtw88/main.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 08644540d259..5b74830c4d2c 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -72,6 +72,14 @@ enum rtw_fw_rf_type { FW_RF_MAX_TYPE = 0xF, }; +enum rtw_fw_feature { + FW_FEATURE_SIG = BIT(0), + FW_FEATURE_LPS_C2H = BIT(1), + FW_FEATURE_LCLK = BIT(2), + FW_FEATURE_PG = BIT(3), + FW_FEATURE_MAX = BIT(31), +}; + struct rtw_coex_info_req { u8 seq; u8 op_code; @@ -177,7 +185,7 @@ struct rtw_fw_hdr { u8 subversion; u8 subindex; __le32 rsvd; /* 0x08 */ - __le32 rsvd2; /* 0x0C */ + __le32 feature; /* 0x0C */ u8 month; /* 0x10 */ u8 day; u8 hour; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 565efd880624..259ad849af93 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1259,6 +1259,17 @@ static void rtw_unset_supported_band(struct ieee80211_hw *hw, kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]); } +static void __update_firmware_feature(struct rtw_dev *rtwdev, + struct rtw_fw_state *fw) +{ + u32 feature; + const struct rtw_fw_hdr *fw_hdr = + (const struct rtw_fw_hdr *)fw->firmware->data; + + feature = le32_to_cpu(fw_hdr->feature); + fw->feature = feature & FW_FEATURE_SIG ? feature : 0; +} + static void __update_firmware_info(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { @@ -1269,6 +1280,8 @@ static void __update_firmware_info(struct rtw_dev *rtwdev, fw->version = le16_to_cpu(fw_hdr->version); fw->sub_version = fw_hdr->subversion; fw->sub_index = fw_hdr->subindex; + + __update_firmware_feature(rtwdev, fw); } static void __update_firmware_info_legacy(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index ffb02e614217..b00235573a13 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1633,6 +1633,7 @@ struct rtw_fw_state { u8 sub_index; u16 h2c_version; u8 prev_dump_seq; + u32 feature; }; struct rtw_hal { From patchwork Fri Oct 30 08:40:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Huang X-Patchwork-Id: 11868773 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9E9A814B2 for ; Fri, 30 Oct 2020 08:40:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 83DFD2083B for ; Fri, 30 Oct 2020 08:40:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726019AbgJ3Ik2 (ORCPT ); Fri, 30 Oct 2020 04:40:28 -0400 Received: from rtits2.realtek.com ([211.75.126.72]:48080 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725790AbgJ3Ik1 (ORCPT ); Fri, 30 Oct 2020 04:40:27 -0400 Authenticated-By: X-SpamFilter-By: ArmorX SpamTrap 5.73 with qID 09U8eIhhD008854, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (rtexmb04.realtek.com.tw[172.21.6.97]) by rtits2.realtek.com.tw (8.15.2/2.70/5.88) with ESMTPS id 09U8eIhhD008854 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 30 Oct 2020 16:40:18 +0800 Received: from localhost.localdomain (172.21.69.222) by RTEXMB04.realtek.com.tw (172.21.6.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2044.4; Fri, 30 Oct 2020 16:40:18 +0800 From: To: , CC: , Subject: [PATCH 3/4] rtw88: add C2H response for checking firmware leave lps Date: Fri, 30 Oct 2020 16:40:12 +0800 Message-ID: <20201030084013.8457-4-tehuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030084013.8457-1-tehuang@realtek.com> References: <20201030084013.8457-1-tehuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.69.222] X-ClientProxiedBy: RTEXMB03.realtek.com.tw (172.21.6.96) To RTEXMB04.realtek.com.tw (172.21.6.97) Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Chin-Yen Lee Originally driver checks if firmware has left lps via reading the setting of REG_TCR register. But this way may fail when firmware is frequently changing power state. Therefore, firmware provides a safer option for driver. When firmware leaves lps successfully, it sends a C2H response to inform driver. Signed-off-by: Chin-Yen Lee Signed-off-by: Tzu-En Huang --- drivers/net/wireless/realtek/rtw88/fw.c | 3 ++ drivers/net/wireless/realtek/rtw88/fw.h | 1 + drivers/net/wireless/realtek/rtw88/main.c | 1 + drivers/net/wireless/realtek/rtw88/main.h | 1 + drivers/net/wireless/realtek/rtw88/ps.c | 52 ++++++++++++++++++++--- drivers/net/wireless/realtek/rtw88/ps.h | 1 + 6 files changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 042015bc8055..29fffacf4085 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -183,6 +183,9 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, case C2H_BT_MP_INFO: rtw_coex_info_response(rtwdev, skb); break; + case C2H_WLAN_RFON: + complete(&rtwdev->lps_leave_check); + break; default: /* pass offset for further operation */ *((u32 *)skb->cb) = pkt_offset; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 5b74830c4d2c..39c905c1b1d8 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -31,6 +31,7 @@ enum rtw_c2h_cmd_id { C2H_RA_RPT = 0x0c, C2H_HW_FEATURE_REPORT = 0x19, C2H_WLAN_INFO = 0x27, + C2H_WLAN_RFON = 0x32, C2H_HW_FEATURE_DUMP = 0xfd, C2H_HALMAC = 0xff, }; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 259ad849af93..5c46f5d2e87c 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1652,6 +1652,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) mutex_init(&rtwdev->hal.tx_power_mutex); init_waitqueue_head(&rtwdev->coex.wait); + init_completion(&rtwdev->lps_leave_check); rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b00235573a13..53ddd8661c44 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1740,6 +1740,7 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; bool ps_enabled; + struct completion lps_leave_check; struct dentry *debugfs; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 8ed243628dcb..233b3df264b3 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -109,7 +109,7 @@ static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev) rtw_hci_deep_ps(rtwdev, false); } -static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev) +static int __rtw_fw_leave_lps_check_reg(struct rtw_dev *rtwdev) { int i; @@ -127,12 +127,53 @@ static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev) */ for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) { if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0) - return; + return 0; msleep(20); } - rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0); - rtw_warn(rtwdev, "firmware failed to restore hardware setting\n"); + return -EBUSY; +} + +static int __rtw_fw_leave_lps_check_c2h(struct rtw_dev *rtwdev) +{ + if (wait_for_completion_timeout(&rtwdev->lps_leave_check, + LEAVE_LPS_TIMEOUT)) + return 0; + return -EBUSY; +} + +static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev) +{ + bool ret = false; + struct rtw_fw_state *fw; + + if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) + fw = &rtwdev->wow_fw; + else + fw = &rtwdev->fw; + + if (fw->feature & FW_FEATURE_LPS_C2H) + ret = __rtw_fw_leave_lps_check_c2h(rtwdev); + else + ret = __rtw_fw_leave_lps_check_reg(rtwdev); + + if (ret) { + rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN); + rtw_warn(rtwdev, "firmware failed to leave lps state\n"); + } +} + +static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev) +{ + struct rtw_fw_state *fw; + + if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) + fw = &rtwdev->wow_fw; + else + fw = &rtwdev->fw; + + if (fw->feature & FW_FEATURE_LPS_C2H) + reinit_completion(&rtwdev->lps_leave_check); } static void rtw_leave_lps_core(struct rtw_dev *rtwdev) @@ -145,8 +186,9 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) conf->smart_ps = 0; rtw_hci_link_ps(rtwdev, false); + rtw_fw_leave_lps_check_prepare(rtwdev); rtw_fw_set_pwr_mode(rtwdev); - rtw_fw_leave_lps_state_check(rtwdev); + rtw_fw_leave_lps_check(rtwdev); clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 19afceca7d0e..915b200081fc 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -12,6 +12,7 @@ #define POWER_MODE_LCLK BIT(0) #define LEAVE_LPS_TRY_CNT 5 +#define LEAVE_LPS_TIMEOUT msecs_to_jiffies(100) int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); From patchwork Fri Oct 30 08:40:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Huang X-Patchwork-Id: 11868769 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F321139F for ; Fri, 30 Oct 2020 08:40:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 377EE2083B for ; Fri, 30 Oct 2020 08:40:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726051AbgJ3Ik3 (ORCPT ); Fri, 30 Oct 2020 04:40:29 -0400 Received: from rtits2.realtek.com ([211.75.126.72]:48079 "EHLO rtits2.realtek.com.tw" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725784AbgJ3Ik2 (ORCPT ); Fri, 30 Oct 2020 04:40:28 -0400 Authenticated-By: X-SpamFilter-By: ArmorX SpamTrap 5.73 with qID 09U8eIhjD008854, This message is accepted by code: ctloc85258 Received: from mail.realtek.com (rtexmb04.realtek.com.tw[172.21.6.97]) by rtits2.realtek.com.tw (8.15.2/2.70/5.88) with ESMTPS id 09U8eIhjD008854 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT); Fri, 30 Oct 2020 16:40:18 +0800 Received: from localhost.localdomain (172.21.69.222) by RTEXMB04.realtek.com.tw (172.21.6.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2044.4; Fri, 30 Oct 2020 16:40:18 +0800 From: To: , CC: , Subject: [PATCH 4/4] rtw88: decide lps deep mode from firmware feature. Date: Fri, 30 Oct 2020 16:40:13 +0800 Message-ID: <20201030084013.8457-5-tehuang@realtek.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201030084013.8457-1-tehuang@realtek.com> References: <20201030084013.8457-1-tehuang@realtek.com> MIME-Version: 1.0 X-Originating-IP: [172.21.69.222] X-ClientProxiedBy: RTEXMB03.realtek.com.tw (172.21.6.96) To RTEXMB04.realtek.com.tw (172.21.6.97) Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Chin-Yen Lee This patch checks the supported lps deep mode from firmware feature, and allows different firmware have different deep power mode. Original module parameter rtw_fw_lps_deep_mode is replaced with rtw_disable_lps_deep_mode for user to disable lps deep mode. Signed-off-by: Chin-Yen Lee Signed-off-by: Tzu-En Huang --- drivers/net/wireless/realtek/rtw88/fw.c | 3 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw88/main.c | 36 ++++++++++++++----- drivers/net/wireless/realtek/rtw88/main.h | 3 +- drivers/net/wireless/realtek/rtw88/ps.c | 14 ++++++-- drivers/net/wireless/realtek/rtw88/ps.h | 2 +- drivers/net/wireless/realtek/rtw88/wow.c | 5 +-- 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 29fffacf4085..3cd46759802c 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -13,6 +13,7 @@ #include "debug.h" #include "util.h" #include "wow.h" +#include "ps.h" static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb) @@ -631,7 +632,7 @@ void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable) SET_NLO_FUN_EN(h2c_pkt, enable); if (enable) { - if (rtw_fw_lps_deep_mode) + if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE) SET_NLO_PS_32K(h2c_pkt, enable); SET_NLO_IGNORE_SECURITY(h2c_pkt, enable); SET_NLO_LOC_NLO_INFO(h2c_pkt, loc_nlo); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index c92fba2fa480..c69397719fdf 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -519,7 +519,7 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } /* download new cam settings for PG to backup */ - if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG) rtw_fw_download_rsvd_page(rtwdev); out: diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 5c46f5d2e87c..71d90b98d6f1 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -16,17 +16,17 @@ #include "debug.h" #include "bf.h" -unsigned int rtw_fw_lps_deep_mode; -EXPORT_SYMBOL(rtw_fw_lps_deep_mode); +bool rtw_disable_lps_deep_mode; +EXPORT_SYMBOL(rtw_disable_lps_deep_mode); bool rtw_bf_support = true; unsigned int rtw_debug_mask; EXPORT_SYMBOL(rtw_debug_mask); -module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); +module_param_named(disable_lps_deep, rtw_disable_lps_deep_mode, bool, 0644); module_param_named(support_bf, rtw_bf_support, bool, 0644); module_param_named(debug_mask, rtw_debug_mask, uint, 0644); -MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); +MODULE_PARM_DESC(disable_lps_deep, "Set Y to disable Deep PS"); MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); MODULE_PARM_DESC(debug_mask, "Debugging mask"); @@ -1023,6 +1023,26 @@ static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) return 0; } +static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, + struct rtw_fw_state *fw) +{ + struct rtw_chip_info *chip = rtwdev->chip; + + if (rtw_disable_lps_deep_mode || !chip->lps_deep_mode_supported || + !fw->feature) + return LPS_DEEP_MODE_NONE; + + if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_PG)) && + (fw->feature & FW_FEATURE_PG)) + return LPS_DEEP_MODE_PG; + + if ((chip->lps_deep_mode_supported & BIT(LPS_DEEP_MODE_LCLK)) && + (fw->feature & FW_FEATURE_LCLK)) + return LPS_DEEP_MODE_LCLK; + + return LPS_DEEP_MODE_NONE; +} + static int rtw_power_on(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -1097,6 +1117,9 @@ int rtw_core_start(struct rtw_dev *rtwdev) rtw_sec_enable_sec_engine(rtwdev); + rtwdev->lps_conf.deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->fw); + rtwdev->lps_conf.wow_deep_mode = rtw_update_lps_deep_mode(rtwdev, &rtwdev->wow_fw); + /* rcr reset after powered on */ rtw_write32(rtwdev, REG_RCR, rtwdev->hal.rcr); @@ -1657,10 +1680,6 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); - if (!(BIT(rtw_fw_lps_deep_mode) & chip->lps_deep_mode_supported)) - rtwdev->lps_conf.deep_mode = LPS_DEEP_MODE_NONE; - else - rtwdev->lps_conf.deep_mode = rtw_fw_lps_deep_mode; rtw_stats_init(rtwdev); @@ -1685,6 +1704,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) return ret; } } + return 0; } EXPORT_SYMBOL(rtw_core_init); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 53ddd8661c44..bbfc3312eef5 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -37,7 +37,7 @@ #define RTW_TP_SHIFT 18 /* bytes/2s --> Mbps */ extern bool rtw_bf_support; -extern unsigned int rtw_fw_lps_deep_mode; +extern bool rtw_disable_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; @@ -664,6 +664,7 @@ enum rtw_pwr_state { struct rtw_lps_conf { enum rtw_lps_mode mode; enum rtw_lps_deep_mode deep_mode; + enum rtw_lps_deep_mode wow_deep_mode; enum rtw_pwr_state state; u8 awake_interval; u8 rlbm; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 233b3df264b3..3bead34c3d10 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -77,7 +77,7 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) request ^= request | BIT_RPWM_TOGGLE; if (enter) { request |= POWER_MODE_LCLK; - if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG) request |= POWER_MODE_PG; } /* Each request require an ack from firmware */ @@ -195,9 +195,17 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); } +enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev) +{ + if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) + return rtwdev->lps_conf.wow_deep_mode; + else + return rtwdev->lps_conf.deep_mode; +} + static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) { - if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE) + if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_NONE) return; if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) { @@ -206,7 +214,7 @@ static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) return; } - if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG) rtw_fw_set_pg_info(rtwdev); rtw_hci_deep_ps(rtwdev, true); diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 915b200081fc..7819391c8663 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -21,5 +21,5 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter); void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id); void rtw_leave_lps(struct rtw_dev *rtwdev); void rtw_leave_lps_deep(struct rtw_dev *rtwdev); - +enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw88/wow.c b/drivers/net/wireless/realtek/rtw88/wow.c index 2fcdf70a3a77..b419bc28861f 100644 --- a/drivers/net/wireless/realtek/rtw88/wow.c +++ b/drivers/net/wireless/realtek/rtw88/wow.c @@ -555,7 +555,7 @@ static int rtw_wow_leave_no_link_ps(struct rtw_dev *rtwdev) int ret = 0; if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags)) { - if (rtw_fw_lps_deep_mode) + if (rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE) rtw_leave_lps_deep(rtwdev); } else { if (test_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags)) { @@ -616,7 +616,8 @@ static int rtw_wow_enter_ps(struct rtw_dev *rtwdev) if (rtw_wow_mgd_linked(rtwdev)) ret = rtw_wow_enter_linked_ps(rtwdev); - else if (rtw_wow_no_link(rtwdev) && rtw_fw_lps_deep_mode) + else if (rtw_wow_no_link(rtwdev) && + rtw_get_lps_deep_mode(rtwdev) != LPS_DEEP_MODE_NONE) ret = rtw_wow_enter_no_link_ps(rtwdev); return ret;