summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw88/pci.c
diff options
context:
space:
mode:
authorYan-Hsuan Chuang <yhchuang@realtek.com>2019-11-18 17:54:32 +0800
committerKalle Valo <kvalo@codeaurora.org>2019-11-20 09:44:51 +0200
commit3dff7c6e37499c87a7ba3f728b2ad1775cbbf725 (patch)
treed5b1b286cf0b0af3b1c8831efe2e4436876e6e9f /drivers/net/wireless/realtek/rtw88/pci.c
parentd2e2c47e65af7310ad7d40ebf4cbb1d898719ec2 (diff)
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: Yan-Hsuan Chuang <yhchuang@realtek.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/pci.c')
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 6e99aad39487..a58e8276a41a 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -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);
}
+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)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
@@ -1292,6 +1329,7 @@ static struct rtw_hci_ops rtw_pci_ops = {
.start = rtw_pci_start,
.stop = rtw_pci_stop,
.deep_ps = rtw_pci_deep_ps,
+ .link_ps = rtw_pci_link_ps,
.read8 = rtw_pci_read8,
.read16 = rtw_pci_read16,