Commit 3dff7c6e authored by Yan-Hsuan Chuang's avatar Yan-Hsuan Chuang Committed by Kalle Valo

rtw88: allows to enable/disable HCI link PS mechanism

Different interfaces have its own link-related power save mechanism.
Such as PCI can enter L1 state based on the traffic on the link, and
sometimes driver needs to enable/disable it to avoid some issues, like
throughput degrade when PCI trying to enter L1 state even if driver is
having heavy traffic.

For now, rtw88 only supports PCIE chips, and they just need to disable
ASPM L1 when driver is not in power save mode, such as IPS and LPS.
Signed-off-by: default avatarYan-Hsuan Chuang <yhchuang@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent d2e2c47e
...@@ -14,6 +14,7 @@ struct rtw_hci_ops { ...@@ -14,6 +14,7 @@ struct rtw_hci_ops {
int (*start)(struct rtw_dev *rtwdev); int (*start)(struct rtw_dev *rtwdev);
void (*stop)(struct rtw_dev *rtwdev); void (*stop)(struct rtw_dev *rtwdev);
void (*deep_ps)(struct rtw_dev *rtwdev, bool enter); void (*deep_ps)(struct rtw_dev *rtwdev, bool enter);
void (*link_ps)(struct rtw_dev *rtwdev, bool enter);
int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size); int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size); int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size);
...@@ -53,6 +54,11 @@ static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter) ...@@ -53,6 +54,11 @@ static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter)
rtwdev->hci.ops->deep_ps(rtwdev, enter); rtwdev->hci.ops->deep_ps(rtwdev, enter);
} }
static inline void rtw_hci_link_ps(struct rtw_dev *rtwdev, bool enter)
{
rtwdev->hci.ops->link_ps(rtwdev, enter);
}
static inline int static inline int
rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
{ {
......
...@@ -1150,6 +1150,43 @@ static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable) ...@@ -1150,6 +1150,43 @@ static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable)
rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
} }
static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable)
{
u8 value;
int ret;
ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value);
if (ret) {
rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret);
return;
}
if (enable)
value |= BIT_L1_SW_EN;
else
value &= ~BIT_L1_SW_EN;
rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
}
static void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
/* Like CLKREQ, ASPM is also implemented by two HW modules, and can
* only be enabled when host supports it.
*
* And ASPM mechanism should be enabled when driver/firmware enters
* power save mode, without having heavy traffic. Because we've
* experienced some inter-operability issues that the link tends
* to enter L1 state on the fly even when driver is having high
* throughput. This is probably because the ASPM behavior slightly
* varies from different SOC.
*/
if (rtwpci->link_ctrl & PCI_EXP_LNKCTL_ASPM_L1)
rtw_pci_aspm_set(rtwdev, enter);
}
static void rtw_pci_link_cfg(struct rtw_dev *rtwdev) static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
{ {
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
...@@ -1292,6 +1329,7 @@ static struct rtw_hci_ops rtw_pci_ops = { ...@@ -1292,6 +1329,7 @@ static struct rtw_hci_ops rtw_pci_ops = {
.start = rtw_pci_start, .start = rtw_pci_start,
.stop = rtw_pci_stop, .stop = rtw_pci_stop,
.deep_ps = rtw_pci_deep_ps, .deep_ps = rtw_pci_deep_ps,
.link_ps = rtw_pci_link_ps,
.read8 = rtw_pci_read8, .read8 = rtw_pci_read8,
.read16 = rtw_pci_read16, .read16 = rtw_pci_read16,
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define RTK_PCIE_LINK_CFG 0x0719 #define RTK_PCIE_LINK_CFG 0x0719
#define BIT_CLKREQ_SW_EN BIT(4) #define BIT_CLKREQ_SW_EN BIT(4)
#define BIT_L1_SW_EN BIT(3)
#define BIT_PCI_BCNQ_FLAG BIT(4) #define BIT_PCI_BCNQ_FLAG BIT(4)
#define RTK_PCI_TXBD_DESA_BCNQ 0x308 #define RTK_PCI_TXBD_DESA_BCNQ 0x308
......
...@@ -31,6 +31,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev) ...@@ -31,6 +31,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
rtw_core_stop(rtwdev); rtw_core_stop(rtwdev);
rtw_hci_link_ps(rtwdev, true);
return 0; return 0;
} }
...@@ -49,6 +50,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) ...@@ -49,6 +50,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
{ {
int ret; int ret;
rtw_hci_link_ps(rtwdev, false);
ret = rtw_ips_pwr_up(rtwdev); ret = rtw_ips_pwr_up(rtwdev);
if (ret) { if (ret) {
rtw_err(rtwdev, "failed to leave ips state\n"); rtw_err(rtwdev, "failed to leave ips state\n");
...@@ -150,6 +153,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) ...@@ -150,6 +153,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
conf->rlbm = 0; conf->rlbm = 0;
conf->smart_ps = 0; conf->smart_ps = 0;
rtw_hci_link_ps(rtwdev, false);
rtw_fw_set_pwr_mode(rtwdev); rtw_fw_set_pwr_mode(rtwdev);
rtw_fw_leave_lps_state_check(rtwdev); rtw_fw_leave_lps_state_check(rtwdev);
...@@ -187,6 +191,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) ...@@ -187,6 +191,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE); rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
rtw_fw_set_pwr_mode(rtwdev); rtw_fw_set_pwr_mode(rtwdev);
rtw_hci_link_ps(rtwdev, true);
set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment