Commit f31e039f authored by Chin-Yen Lee's avatar Chin-Yen Lee Committed by Kalle Valo
Browse files

rtw88: add C2H response for checking firmware leave lps



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: default avatarChin-Yen Lee <timlee@realtek.com>
Signed-off-by: default avatarTzu-En Huang <tehuang@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20201030084826.9034-4-tehuang@realtek.com
parent a9594960
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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,
};
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -1741,6 +1741,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;

+47 −5
Original line number Diff line number Diff line
@@ -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);

Loading