All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM
@ 2019-11-07 11:15 yhchuang
  2019-11-07 11:16 ` [PATCH 1/4] rtw88: pci: use macros to access PCI DBI/MDIO registers yhchuang
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: yhchuang @ 2019-11-07 11:15 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, briannorris

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

This set enables PCI CLKREQ and ASPM for power save. Basically
they should be enabled through PCI configuration space, but
for some reasons (see comments in pci.c), they are disabled by
default. So driver requires to check the configuration space
and then enable them properly.

Yan-Hsuan Chuang (4):
  rtw88: pci: use macros to access PCI DBI/MDIO registers
  rtw88: pci: use for loop instead of while loop for DBI/MDIO
  rtw88: pci: enable CLKREQ function if host supports it
  rtw88: allows to enable/disable HCI link PS mechanism

 drivers/net/wireless/realtek/rtw88/hci.h |   6 +
 drivers/net/wireless/realtek/rtw88/pci.c | 158 ++++++++++++++++++++---
 drivers/net/wireless/realtek/rtw88/pci.h |  16 +++
 drivers/net/wireless/realtek/rtw88/ps.c  |   6 +
 4 files changed, 168 insertions(+), 18 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] rtw88: pci: use macros to access PCI DBI/MDIO registers
  2019-11-07 11:15 [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM yhchuang
@ 2019-11-07 11:16 ` yhchuang
  2019-11-07 11:16 ` [PATCH 2/4] rtw88: pci: use for loop instead of while loop for DBI/MDIO yhchuang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: yhchuang @ 2019-11-07 11:16 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, briannorris

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

Add some register and bit macros to access DBI/MDIO register. This
should not change the logic.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/pci.c | 21 ++++++++++-----------
 drivers/net/wireless/realtek/rtw88/pci.h | 10 ++++++++++
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 17b9cdf9cb05..b158ef8ded17 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1060,14 +1060,15 @@ static void rtw_pci_io_unmapping(struct rtw_dev *rtwdev,
 static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
 {
 	u16 write_addr;
-	u16 remainder = addr & 0x3;
+	u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK);
 	u8 flag;
-	u8 cnt = 20;
+	u8 cnt = RTW_PCI_WR_RETRY_CNT;
 
-	write_addr = ((addr & 0x0ffc) | (BIT(0) << (remainder + 12)));
+	write_addr = addr & BITS_DBI_ADDR_MASK;
+	write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN);
 	rtw_write8(rtwdev, REG_DBI_WDATA_V1 + remainder, data);
 	rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr);
-	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, 0x01);
+	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16);
 
 	flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
 	while (flag && (cnt != 0)) {
@@ -1083,19 +1084,17 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
 {
 	u8 page;
 	u8 wflag;
-	u8 cnt;
+	u8 cnt = RTW_PCI_WR_RETRY_CNT;
 
 	rtw_write16(rtwdev, REG_MDIO_V1, data);
 
-	page = addr < 0x20 ? 0 : 1;
-	page += g1 ? 0 : 2;
-	rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & 0x1f);
+	page = addr < RTW_PCI_MDIO_PG_SZ ? 0 : 1;
+	page += g1 ? RTW_PCI_MDIO_PG_OFFS_G1 : RTW_PCI_MDIO_PG_OFFS_G2;
+	rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & BITS_MDIO_ADDR_MASK);
 	rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page);
-
 	rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1);
-	wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1);
 
-	cnt = 20;
+	wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1);
 	while (wflag && (cnt != 0)) {
 		udelay(10);
 		wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG,
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index 87824a4caba9..50aff49738d4 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -21,9 +21,19 @@
 #define BIT_RX_TAG_EN		BIT(15)
 #define REG_DBI_WDATA_V1	0x03E8
 #define REG_DBI_FLAG_V1		0x03F0
+#define BIT_DBI_RFLAG		BIT(17)
+#define BIT_DBI_WFLAG		BIT(16)
+#define BITS_DBI_WREN		GENMASK(15, 12)
+#define BITS_DBI_ADDR_MASK	GENMASK(11, 2)
+
 #define REG_MDIO_V1		0x03F4
 #define REG_PCIE_MIX_CFG	0x03F8
+#define BITS_MDIO_ADDR_MASK	GENMASK(4, 0)
 #define BIT_MDIO_WFLAG_V1	BIT(5)
+#define RTW_PCI_MDIO_PG_SZ	BIT(5)
+#define RTW_PCI_MDIO_PG_OFFS_G1	0
+#define RTW_PCI_MDIO_PG_OFFS_G2	2
+#define RTW_PCI_WR_RETRY_CNT	20
 
 #define BIT_PCI_BCNQ_FLAG	BIT(4)
 #define RTK_PCI_TXBD_DESA_BCNQ	0x308
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] rtw88: pci: use for loop instead of while loop for DBI/MDIO
  2019-11-07 11:15 [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM yhchuang
  2019-11-07 11:16 ` [PATCH 1/4] rtw88: pci: use macros to access PCI DBI/MDIO registers yhchuang
@ 2019-11-07 11:16 ` yhchuang
  2019-11-07 11:16 ` [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it yhchuang
  2019-11-07 11:16 ` [PATCH 4/4] rtw88: allows to enable/disable HCI link PS mechanism yhchuang
  3 siblings, 0 replies; 8+ messages in thread
From: yhchuang @ 2019-11-07 11:16 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, briannorris

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

Use a for loop to polling DBI/MDIO read/write flags to avoid
infinite loop happens

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/pci.c | 26 +++++++++++++-----------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index b158ef8ded17..6d1aa6f41e84 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1062,7 +1062,7 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
 	u16 write_addr;
 	u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK);
 	u8 flag;
-	u8 cnt = RTW_PCI_WR_RETRY_CNT;
+	u8 cnt;
 
 	write_addr = addr & BITS_DBI_ADDR_MASK;
 	write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN);
@@ -1070,21 +1070,22 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
 	rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr);
 	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16);
 
-	flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
-	while (flag && (cnt != 0)) {
-		udelay(10);
+	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
 		flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
-		cnt--;
+		if (flag == 0)
+			return;
+
+		udelay(10);
 	}
 
-	WARN(flag, "DBI write fail\n");
+	WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
 }
 
 static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
 {
 	u8 page;
 	u8 wflag;
-	u8 cnt = RTW_PCI_WR_RETRY_CNT;
+	u8 cnt;
 
 	rtw_write16(rtwdev, REG_MDIO_V1, data);
 
@@ -1094,15 +1095,16 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
 	rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page);
 	rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1);
 
-	wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1);
-	while (wflag && (cnt != 0)) {
-		udelay(10);
+	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
 		wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG,
 					BIT_MDIO_WFLAG_V1);
-		cnt--;
+		if (wflag == 0)
+			return;
+
+		udelay(10);
 	}
 
-	WARN(wflag, "MDIO write fail\n");
+	WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr);
 }
 
 static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it
  2019-11-07 11:15 [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM yhchuang
  2019-11-07 11:16 ` [PATCH 1/4] rtw88: pci: use macros to access PCI DBI/MDIO registers yhchuang
  2019-11-07 11:16 ` [PATCH 2/4] rtw88: pci: use for loop instead of while loop for DBI/MDIO yhchuang
@ 2019-11-07 11:16 ` yhchuang
  2019-11-13  6:13   ` Chris Chiu
  2019-11-07 11:16 ` [PATCH 4/4] rtw88: allows to enable/disable HCI link PS mechanism yhchuang
  3 siblings, 1 reply; 8+ messages in thread
From: yhchuang @ 2019-11-07 11:16 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, briannorris

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

By Realtek's design, there are two HW modules associated for CLKREQ,
one is responsible to follow the PCIE host settings, and another
is to actually working on it. But the module that is actually working
on it is default disabled, and driver should enable that module if
host and device have successfully sync'ed with each other.

The module is default disabled because sometimes the host does not
support it, and if there is any incorrect settings (ex. CLKREQ# is
not Bi-Direction), device can be lost and disconnected to the host.

So driver should first check after host and device are sync'ed, and
the host does support the function and set it in configuration
space, then driver can turn on the HW module to working on it.

Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
---
 drivers/net/wireless/realtek/rtw88/pci.c | 83 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/pci.h |  5 ++
 2 files changed, 88 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 6d1aa6f41e84..4fcef8a6fc42 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1081,6 +1081,33 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
 	WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
 }
 
+static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
+{
+	u16 read_addr = addr & BITS_DBI_ADDR_MASK;
+	u8 flag;
+	u8 cnt;
+
+	rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
+	rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16);
+
+	for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
+		flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
+		if (flag == 0)
+			break;
+
+		udelay(10);
+	}
+
+	if (flag != 0) {
+		WARN(1, "failed to read DBI register, addr=0x%04x\n", addr);
+		return -EIO;
+	}
+
+	read_addr = REG_DBI_RDATA_V1 + (addr & 3);
+	*value = rtw_read8(rtwdev, read_addr);
+	return 0;
+}
+
 static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
 {
 	u8 page;
@@ -1107,6 +1134,60 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1)
 	WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr);
 }
 
+static void rtw_pci_clkreq_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 CLKREQ_L1, ret=%d", ret);
+		return;
+	}
+
+	if (enable)
+		value |= BIT_CLKREQ_SW_EN;
+	else
+		value &= ~BIT_CLKREQ_SW_EN;
+
+	rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value);
+}
+
+static void rtw_pci_link_cfg(struct rtw_dev *rtwdev)
+{
+	struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+	struct pci_dev *pdev = rtwpci->pdev;
+	u16 link_ctrl;
+	int ret;
+
+	/* Though there is standard PCIE configuration space to set the
+	 * link control register, but by Realtek's design, driver should
+	 * check if host supports CLKREQ/ASPM to enable the HW module.
+	 *
+	 * These functions are implemented by two HW modules associated,
+	 * one is responsible to access PCIE configuration space to
+	 * follow the host settings, and another is in charge of doing
+	 * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes
+	 * the host does not support it, and due to some reasons or wrong
+	 * settings (ex. CLKREQ# not Bi-Direction), it could lead to device
+	 * loss if HW misbehaves on the link.
+	 *
+	 * Hence it's designed that driver should first check the PCIE
+	 * configuration space is sync'ed and enabled, then driver can turn
+	 * on the other module that is actually working on the mechanism.
+	 */
+	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl);
+	if (ret) {
+		rtw_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret);
+		return;
+	}
+
+	if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN)
+		rtw_pci_clkreq_set(rtwdev, true);
+
+	rtwpci->link_ctrl = link_ctrl;
+}
+
 static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
 {
 	struct rtw_chip_info *chip = rtwdev->chip;
@@ -1145,6 +1226,8 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev)
 		else
 			rtw_dbi_write8(rtwdev, offset, value);
 	}
+
+	rtw_pci_link_cfg(rtwdev);
 }
 
 static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev)
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index 50aff49738d4..90efb73c607e 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -20,6 +20,7 @@
 #define BIT_RST_TRXDMA_INTF	BIT(20)
 #define BIT_RX_TAG_EN		BIT(15)
 #define REG_DBI_WDATA_V1	0x03E8
+#define REG_DBI_RDATA_V1	0x03EC
 #define REG_DBI_FLAG_V1		0x03F0
 #define BIT_DBI_RFLAG		BIT(17)
 #define BIT_DBI_WFLAG		BIT(16)
@@ -35,6 +36,9 @@
 #define RTW_PCI_MDIO_PG_OFFS_G2	2
 #define RTW_PCI_WR_RETRY_CNT	20
 
+#define RTK_PCIE_LINK_CFG	0x0719
+#define BIT_CLKREQ_SW_EN	BIT(4)
+
 #define BIT_PCI_BCNQ_FLAG	BIT(4)
 #define RTK_PCI_TXBD_DESA_BCNQ	0x308
 #define RTK_PCI_TXBD_DESA_H2CQ	0x1320
@@ -200,6 +204,7 @@ struct rtw_pci {
 	u16 rx_tag;
 	struct rtw_pci_tx_ring tx_rings[RTK_MAX_TX_QUEUE_NUM];
 	struct rtw_pci_rx_ring rx_rings[RTK_MAX_RX_QUEUE_NUM];
+	u16 link_ctrl;
 
 	void __iomem *mmap;
 };
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] rtw88: allows to enable/disable HCI link PS mechanism
  2019-11-07 11:15 [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM yhchuang
                   ` (2 preceding siblings ...)
  2019-11-07 11:16 ` [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it yhchuang
@ 2019-11-07 11:16 ` yhchuang
  3 siblings, 0 replies; 8+ messages in thread
From: yhchuang @ 2019-11-07 11:16 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, briannorris

From: Yan-Hsuan Chuang <yhchuang@realtek.com>

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>
---
 drivers/net/wireless/realtek/rtw88/hci.h |  6 ++++
 drivers/net/wireless/realtek/rtw88/pci.c | 38 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw88/pci.h |  1 +
 drivers/net/wireless/realtek/rtw88/ps.c  |  6 ++++
 4 files changed, 51 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h
index 4afbf0d163d1..3d91aea942c3 100644
--- a/drivers/net/wireless/realtek/rtw88/hci.h
+++ b/drivers/net/wireless/realtek/rtw88/hci.h
@@ -14,6 +14,7 @@ struct rtw_hci_ops {
 	int (*start)(struct rtw_dev *rtwdev);
 	void (*stop)(struct rtw_dev *rtwdev);
 	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_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)
 	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
 rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size)
 {
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 4fcef8a6fc42..3f951e6e555b 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1153,6 +1153,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;
@@ -1295,6 +1332,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,
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index 90efb73c607e..49bf29a92152 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -38,6 +38,7 @@
 
 #define RTK_PCIE_LINK_CFG	0x0719
 #define BIT_CLKREQ_SW_EN	BIT(4)
+#define BIT_L1_SW_EN		BIT(3)
 
 #define BIT_PCI_BCNQ_FLAG	BIT(4)
 #define RTK_PCI_TXBD_DESA_BCNQ	0x308
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
index 820e0a3a141c..522593bd38b7 100644
--- a/drivers/net/wireless/realtek/rtw88/ps.c
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
@@ -32,6 +32,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev)
 	rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
 
 	rtw_core_stop(rtwdev);
+	rtw_hci_link_ps(rtwdev, true);
 
 	return 0;
 }
@@ -50,6 +51,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev)
 {
 	int ret;
 
+	rtw_hci_link_ps(rtwdev, false);
+
 	ret = rtw_ips_pwr_up(rtwdev);
 	if (ret) {
 		rtw_err(rtwdev, "failed to leave ips state\n");
@@ -151,6 +154,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
 	conf->rlbm = 0;
 	conf->smart_ps = 0;
 
+	rtw_hci_link_ps(rtwdev, false);
 	rtw_fw_set_pwr_mode(rtwdev);
 	rtw_fw_leave_lps_state_check(rtwdev);
 
@@ -188,6 +192,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
 	rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
 
 	rtw_fw_set_pwr_mode(rtwdev);
+	rtw_hci_link_ps(rtwdev, true);
+
 	set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it
  2019-11-07 11:16 ` [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it yhchuang
@ 2019-11-13  6:13   ` Chris Chiu
  2019-11-13  7:16     ` Tony Chuang
  0 siblings, 1 reply; 8+ messages in thread
From: Chris Chiu @ 2019-11-13  6:13 UTC (permalink / raw)
  To: Tony Chuang; +Cc: Kalle Valo, linux-wireless, Brian Norris

On Thu, Nov 7, 2019 at 7:16 PM <yhchuang@realtek.com> wrote:
>
> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
>
> By Realtek's design, there are two HW modules associated for CLKREQ,
> one is responsible to follow the PCIE host settings, and another
> is to actually working on it. But the module that is actually working
> on it is default disabled, and driver should enable that module if
> host and device have successfully sync'ed with each other.
>
> The module is default disabled because sometimes the host does not
> support it, and if there is any incorrect settings (ex. CLKREQ# is
> not Bi-Direction), device can be lost and disconnected to the host.
>
> So driver should first check after host and device are sync'ed, and
> the host does support the function and set it in configuration
> space, then driver can turn on the HW module to working on it.
>
> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
> ---
>  drivers/net/wireless/realtek/rtw88/pci.c | 83 ++++++++++++++++++++++++
>  drivers/net/wireless/realtek/rtw88/pci.h |  5 ++
>  2 files changed, 88 insertions(+)
>
> diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
> index 6d1aa6f41e84..4fcef8a6fc42 100644
> --- a/drivers/net/wireless/realtek/rtw88/pci.c
> +++ b/drivers/net/wireless/realtek/rtw88/pci.c
> @@ -1081,6 +1081,33 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data)
>         WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr);
>  }
>
> +static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
> +{
> +       u16 read_addr = addr & BITS_DBI_ADDR_MASK;
> +       u8 flag;
> +       u8 cnt;
> +
> +       rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
> +       rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16);
> +
> +       for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
> +               flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
> +               if (flag == 0)
> +                       break;
Why not just doing ' rtw_read8(rtwdev, read_addr);' and return here?
Then you don't need to check the flag != 0 at the following. It would
make the code cleaner and same expressive.

> +
> +               udelay(10);
> +       }
> +
> +       if (flag != 0) {
> +               WARN(1, "failed to read DBI register, addr=0x%04x\n", addr);
> +               return -EIO;
> +       }
> +
> +       read_addr = REG_DBI_RDATA_V1 + (addr & 3);
> +       *value = rtw_read8(rtwdev, read_addr);
> +       return 0;
> +}
> +
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* RE: [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it
  2019-11-13  6:13   ` Chris Chiu
@ 2019-11-13  7:16     ` Tony Chuang
  2019-11-13  7:46       ` Chris Chiu
  0 siblings, 1 reply; 8+ messages in thread
From: Tony Chuang @ 2019-11-13  7:16 UTC (permalink / raw)
  To: Chris Chiu; +Cc: Kalle Valo, linux-wireless, Brian Norris

> On Thu, Nov 7, 2019 at 7:16 PM <yhchuang@realtek.com> wrote:
> >
> > From: Yan-Hsuan Chuang <yhchuang@realtek.com>
> >
> > By Realtek's design, there are two HW modules associated for CLKREQ,
> > one is responsible to follow the PCIE host settings, and another
> > is to actually working on it. But the module that is actually working
> > on it is default disabled, and driver should enable that module if
> > host and device have successfully sync'ed with each other.
> >
> > The module is default disabled because sometimes the host does not
> > support it, and if there is any incorrect settings (ex. CLKREQ# is
> > not Bi-Direction), device can be lost and disconnected to the host.
> >
> > So driver should first check after host and device are sync'ed, and
> > the host does support the function and set it in configuration
> > space, then driver can turn on the HW module to working on it.
> >
> > Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
> > ---
> >  drivers/net/wireless/realtek/rtw88/pci.c | 83
> ++++++++++++++++++++++++
> >  drivers/net/wireless/realtek/rtw88/pci.h |  5 ++
> >  2 files changed, 88 insertions(+)
> >
> > diff --git a/drivers/net/wireless/realtek/rtw88/pci.c
> b/drivers/net/wireless/realtek/rtw88/pci.c
> > index 6d1aa6f41e84..4fcef8a6fc42 100644
> > --- a/drivers/net/wireless/realtek/rtw88/pci.c
> > +++ b/drivers/net/wireless/realtek/rtw88/pci.c
> > @@ -1081,6 +1081,33 @@ static void rtw_dbi_write8(struct rtw_dev
> *rtwdev, u16 addr, u8 data)
> >         WARN(flag, "failed to write to DBI register, addr=0x%04x\n",
> addr);
> >  }
> >
> > +static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
> > +{
> > +       u16 read_addr = addr & BITS_DBI_ADDR_MASK;
> > +       u8 flag;
> > +       u8 cnt;
> > +
> > +       rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
> > +       rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >>
> 16);
> > +
> > +       for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
> > +               flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
> > +               if (flag == 0)
> > +                       break;
> Why not just doing ' rtw_read8(rtwdev, read_addr);' and return here?
> Then you don't need to check the flag != 0 at the following. It would
> make the code cleaner and same expressive.

Maybe it would look cleaner, but you need to add statements when
'if (flag == 0)', then the indents will be deeper.
Also you will need to return 0 at the end if 'flag == 0'.

So you still think it's cleaner to write it that way? If so, I can try to send
v2 for it.

> 
> > +
> > +               udelay(10);
> > +       }
> > +
> > +       if (flag != 0) {
> > +               WARN(1, "failed to read DBI register, addr=0x%04x\n",
> addr);
> > +               return -EIO;
> > +       }
> > +
> > +       read_addr = REG_DBI_RDATA_V1 + (addr & 3);
> > +       *value = rtw_read8(rtwdev, read_addr);
> > +       return 0;
> > +}
> > +
> > --
> > 2.17.1
> >
> 

Yan-Hsuan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it
  2019-11-13  7:16     ` Tony Chuang
@ 2019-11-13  7:46       ` Chris Chiu
  0 siblings, 0 replies; 8+ messages in thread
From: Chris Chiu @ 2019-11-13  7:46 UTC (permalink / raw)
  To: Tony Chuang; +Cc: Kalle Valo, linux-wireless, Brian Norris



Tony Chuang <yhchuang@realtek.com> 於 2019年11月13日 下午3:16 寫道:

>>> On Thu, Nov 7, 2019 at 7:16 PM <yhchuang@realtek.com> wrote:
>>> 
>>> From: Yan-Hsuan Chuang <yhchuang@realtek.com>
>>> 
>>> By Realtek's design, there are two HW modules associated for CLKREQ,
>>> one is responsible to follow the PCIE host settings, and another
>>> is to actually working on it. But the module that is actually working
>>> on it is default disabled, and driver should enable that module if
>>> host and device have successfully sync'ed with each other.
>>> 
>>> The module is default disabled because sometimes the host does not
>>> support it, and if there is any incorrect settings (ex. CLKREQ# is
>>> not Bi-Direction), device can be lost and disconnected to the host.
>>> 
>>> So driver should first check after host and device are sync'ed, and
>>> the host does support the function and set it in configuration
>>> space, then driver can turn on the HW module to working on it.
>>> 
>>> Signed-off-by: Yan-Hsuan Chuang <yhchuang@realtek.com>
>>> ---
>>> drivers/net/wireless/realtek/rtw88/pci.c | 83
>> ++++++++++++++++++++++++
>>> drivers/net/wireless/realtek/rtw88/pci.h |  5 ++
>>> 2 files changed, 88 insertions(+)
>>> 
>>> diff --git a/drivers/net/wireless/realtek/rtw88/pci.c
>> b/drivers/net/wireless/realtek/rtw88/pci.c
>>> index 6d1aa6f41e84..4fcef8a6fc42 100644
>>> --- a/drivers/net/wireless/realtek/rtw88/pci.c
>>> +++ b/drivers/net/wireless/realtek/rtw88/pci.c
>>> @@ -1081,6 +1081,33 @@ static void rtw_dbi_write8(struct rtw_dev
>> *rtwdev, u16 addr, u8 data)
>>>        WARN(flag, "failed to write to DBI register, addr=0x%04x\n",
>> addr);
>>> }
>>> 
>>> +static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value)
>>> +{
>>> +       u16 read_addr = addr & BITS_DBI_ADDR_MASK;
>>> +       u8 flag;
>>> +       u8 cnt;
>>> +
>>> +       rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr);
>>> +       rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >>
>> 16);
>>> +
>>> +       for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) {
>>> +               flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2);
>>> +               if (flag == 0)
>>> +                       break;
>> Why not just doing ' rtw_read8(rtwdev, read_addr);' and return here?
>> Then you don't need to check the flag != 0 at the following. It would
>> make the code cleaner and same expressive.
> 
> Maybe it would look cleaner, but you need to add statements when
> 'if (flag == 0)', then the indents will be deeper.
> Also you will need to return 0 at the end if 'flag == 0'.
> 

Yup. And I believe it’s still under 80 characters so I think I’m cool with it.

> So you still think it's cleaner to write it that way? If so, I can try to send
> v2 for it.
>> 
>>> +
>>> +               udelay(10);
>>> +       }
>>> +
>>> +       if (flag != 0) {
>>> +               WARN(1, "failed to read DBI register, addr=0x%04x\n",
>> addr);
>>> +               return -EIO;
>>> +       }
>>> +
>>> +       read_addr = REG_DBI_RDATA_V1 + (addr & 3);
>>> +       *value = rtw_read8(rtwdev, read_addr);
>>> +       return 0;
>>> +}
>>> +
>>> --
>>> 2.17.1
>>> 
>> 
> 
> Yan-Hsuan

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-11-13  7:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-07 11:15 [PATCH 0/4] rtw88: enable PCI CLKREQ and ASPM yhchuang
2019-11-07 11:16 ` [PATCH 1/4] rtw88: pci: use macros to access PCI DBI/MDIO registers yhchuang
2019-11-07 11:16 ` [PATCH 2/4] rtw88: pci: use for loop instead of while loop for DBI/MDIO yhchuang
2019-11-07 11:16 ` [PATCH 3/4] rtw88: pci: enable CLKREQ function if host supports it yhchuang
2019-11-13  6:13   ` Chris Chiu
2019-11-13  7:16     ` Tony Chuang
2019-11-13  7:46       ` Chris Chiu
2019-11-07 11:16 ` [PATCH 4/4] rtw88: allows to enable/disable HCI link PS mechanism yhchuang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.