Linux PCI subsystem development
 help / color / mirror / Atom feed
* [RFC Patch] pci: add power management for rtl8116af
@ 2026-05-21  3:38 javen
  2026-05-21  4:12 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: javen @ 2026-05-21  3:38 UTC (permalink / raw)
  To: bhelgaas; +Cc: linux-pci, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

RTL8116af is a multi function card. But due to the hardware design, only
function 0 and function 1(nic) are exposed to pci system. If the system
want to enter s0idle or cpu need to enter c10 when suspend, function 2
to 7 must be set to d3 and enable aspm. Function 5 and 6 are reserved,
so we skip them.

Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
Hi,
Just as the comments above, function 2 to 7 are hidden to pci system. So
we have to set d3 and aspm through our private register, which is CSI. I
have a discussion with netdev maintainer, and he thought this might be a
question to pci system.
I wonder whether this patch can be accepted here. Any feedback would be
highly appreciated!

Thanks,
BRs,
Javen
---
 drivers/pci/quirks.c | 119 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index caaed1a01dc0..e6538edcdff4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -35,6 +35,7 @@
 #include <linux/sizes.h>
 #include <linux/suspend.h>
 #include <linux/switchtec.h>
+#include <linux/iopoll.h>
 #include "pci.h"
 
 static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta)
@@ -6381,3 +6382,121 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout);
 #endif
+
+#define RTL_TX_CONFIG			0x40
+#define RTL_CSIDR			0x64
+#define RTL_CSIAR			0x68
+#define RTL_ERIDR			0x70
+#define RTL_ERIAR			0x74
+#define RTL_OCPDR			0xb0
+
+#define CSIAR_FLAG			0x80000000
+#define CSIAR_WRITE_CMD			0x80000000
+#define CSIAR_BYTE_ENABLE		0x0000f000
+#define CSIAR_ADDR_MASK			0x00000fff
+
+#define ERIAR_READ_CMD			0x80000000
+#define ERIAR_MASK_1111			0x0f000000
+#define ERIAR_EXGMAC			0
+#define ERIAR_FLAG			0x80000000
+
+static u32 quirk_rtl_csi_read(void __iomem *base, u8 multi_fun_sel_bit, int addr)
+{
+	u32 cmd = (addr & CSIAR_ADDR_MASK) | (multi_fun_sel_bit << 16) | CSIAR_BYTE_ENABLE;
+	u32 val;
+
+	writel(cmd, base + RTL_CSIAR);
+	if (readl_poll_timeout(base + RTL_CSIAR, val, val & CSIAR_FLAG, 10, 1000))
+		return ~0;
+	return readl(base + RTL_CSIDR);
+}
+
+static void quirk_rtl_csi_write(void __iomem *base, u8 multi_fun_sel_bit, int addr, int value)
+{
+	u32 cmd = CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+		  CSIAR_BYTE_ENABLE | (multi_fun_sel_bit << 16);
+	u32 val;
+
+	writel(value, base + RTL_CSIDR);
+	writel(cmd, base + RTL_CSIAR);
+	readl_poll_timeout(base + RTL_CSIAR, val, !(val & CSIAR_FLAG), 10, 1000);
+}
+
+static u16 quirk_r8168_mac_ocp_read(void __iomem *base, u32 reg)
+{
+	writel(reg << 15, base + RTL_OCPDR);
+	return (u16)readl(base + RTL_OCPDR);
+}
+
+static void quirk_rtl8168_clear_and_set_csi(void __iomem *base, u8 multi_fun_sel_bit,
+					    u32 addr, u32 clearmask, u32 setmask)
+{
+	u32 val = quirk_rtl_csi_read(base, multi_fun_sel_bit, addr);
+
+	if (val != ~0) {
+		val &= ~clearmask;
+		val |= setmask;
+		quirk_rtl_csi_write(base, multi_fun_sel_bit, addr, val);
+	}
+}
+
+static void quirk_rtl8168_other_fun_pci_setting(void __iomem *base, u32 addr,
+						u32 clearmask, u32 setmask)
+{
+	for (int i = 2; i < 8; i++) {
+		if (i == 5 || i == 6)
+			continue;
+		quirk_rtl8168_clear_and_set_csi(base, i, addr, clearmask, setmask);
+	}
+}
+
+static void quirk_rtl8168_set_aspm_clkreq(struct pci_dev *pdev)
+{
+	void __iomem *base;
+	u16 pci_command;
+	int mmio_bar;
+	u32 txconfig, xid;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (!(pci_command & PCI_COMMAND_MEMORY))
+		return;
+
+	mmio_bar = pci_select_bars(pdev, IORESOURCE_MEM);
+	if (!mmio_bar)
+		return;
+
+	mmio_bar = ffs(mmio_bar) - 1;
+	base = pci_iomap(pdev, mmio_bar, 0);
+	if (!base)
+		return;
+
+	txconfig = readl(base + RTL_TX_CONFIG);
+	if (txconfig == ~0U) {
+		pci_iounmap(pdev, base);
+		return;
+	}
+
+	xid = (txconfig >> 20) & 0xfcf;
+	if ((xid & 0x7cf) != 0x54b && (xid & 0x7cf) != 0x54a) {
+		pci_iounmap(pdev, base);
+		return;
+	}
+
+	if ((quirk_r8168_mac_ocp_read(base, 0xdc00) & 0x0078) != 0x0030 ||
+	    (quirk_r8168_mac_ocp_read(base, 0xd006) & 0x00ff) != 0x0000) {
+		pci_iounmap(pdev, base);
+		return;
+	}
+
+	quirk_rtl8168_other_fun_pci_setting(base, 0x80,
+					    BIT(0) | BIT(1) | BIT(8),
+					    BIT(0) | BIT(1) | BIT(8));
+
+	quirk_rtl8168_other_fun_pci_setting(base, 0x44,
+					    0,
+					    BIT(0) | BIT(1));
+
+	pci_iounmap(pdev, base);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REALTEK, 0x8168, quirk_rtl8168_set_aspm_clkreq);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_REALTEK, 0x8168, quirk_rtl8168_set_aspm_clkreq);
-- 
2.43.0


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

end of thread, other threads:[~2026-05-22  7:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21  3:38 [RFC Patch] pci: add power management for rtl8116af javen
2026-05-21  4:12 ` sashiko-bot
2026-05-21 16:09 ` Bjorn Helgaas
2026-05-22  6:34   ` Javen
2026-05-22  7:20 ` Lukas Wunner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox