[coreboot-gerrit] New patch to review for coreboot: 54070eb PCIe: Add L1 Sub-State support.

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Mar 20 16:43:22 CET 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8832

-gerrit

commit 54070ebb911c5927babb6521023ddd9679948b8f
Author: Kenji Chen <kenji.chen at intel.com>
Date:   Sat Oct 4 01:14:44 2014 +0800

    PCIe: Add L1 Sub-State support.
    
    Enable L1 Sub-State when both root port and endpoint support it.
    
    Change-Id: Id11fc7c73eb865411747eef63f5f901e00a17f84
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 6ac04ad7e2261846e40da297f7fa317ccebda092
    Original-BUG=chrome-os-partner:31424
    Original-TEST=Build a image and run on Samus proto boards to check if the
    Original-settings are applied correctly. I just only have proto boards and
    Original-need someone having EVT boards to confirm the settings.
    Original-Signed-off-by: Kenji Chen <kenji.chen at intel.com>
    Original-Change-Id: Id1b5a52ff0b896f4531c4a6e68e70a2cea8c736a
    Original-Reviewed-on: https://chromium-review.googlesource.com/221436
    Original-Reviewed-by: Duncan Laurie <dlaurie at chromium.org>
---
 src/device/Kconfig           |   8 ++
 src/device/pciexp_device.c   | 182 +++++++++++++++++++++++++++++++++++++++++++
 src/include/device/pci.h     |   1 +
 src/include/device/pci_def.h |   6 ++
 src/include/device/pciexp.h  |   1 +
 5 files changed, 198 insertions(+)

diff --git a/src/device/Kconfig b/src/device/Kconfig
index 7f43888..71b9b34 100644
--- a/src/device/Kconfig
+++ b/src/device/Kconfig
@@ -271,6 +271,14 @@ config EARLY_PCI_BRIDGE
 	  This option enables static configuration for a single pre-defined
 	  PCI bridge function on bus 0.
 
+config PCIEXP_L1_SUB_STATE
+	prompt "Enable PCIe ASPM L1 SubState"
+	bool
+	depends on PCIEXP_PLUGIN_SUPPORT
+	default n
+	help
+	  Detect and enable ASPM on PCIe links.
+
 if EARLY_PCI_BRIDGE
 
 config EARLY_PCI_BRIDGE_DEVICE
diff --git a/src/device/pciexp_device.c b/src/device/pciexp_device.c
index edb103d..002a897 100644
--- a/src/device/pciexp_device.c
+++ b/src/device/pciexp_device.c
@@ -25,6 +25,29 @@
 #include <device/pci_ids.h>
 #include <device/pciexp.h>
 
+unsigned int pciexp_find_extended_cap(device_t dev, unsigned int cap)
+{
+	unsigned int this_cap_offset, next_cap_offset;
+	unsigned int this_cap, cafe;
+
+	this_cap_offset = PCIE_EXT_CAP_OFFSET;
+	do {
+		this_cap = pci_mmio_read_config32(dev, this_cap_offset);
+		next_cap_offset = this_cap >> 20;
+		this_cap &= 0xffff;
+		cafe = pci_mmio_read_config32(dev, this_cap_offset + 4);
+		cafe &= 0xffff;
+		if (this_cap == cap)
+			return this_cap_offset;
+		else if (cafe == cap)
+			return this_cap_offset + 4;
+		else
+			this_cap_offset = next_cap_offset;
+	} while (next_cap_offset != 0);
+
+	return 0;
+}
+
 #if CONFIG_PCIEXP_COMMON_CLOCK
 /*
  * Re-train a PCIe link
@@ -107,6 +130,160 @@ static void pciexp_enable_clock_power_pm(device_t endp, unsigned endp_cap)
 }
 #endif /* CONFIG_PCIEXP_CLK_PM */
 
+#if CONFIG_PCIEXP_L1_SUB_STATE
+static void pcie_update_cfg(device_t dev, int reg, u32 mask, u32 or)
+{
+	u32 reg32;
+
+	reg32 = pci_mmio_read_config32(dev, reg);
+	reg32 &= mask;
+	reg32 |= or;
+	pci_mmio_write_config32(dev, reg, reg32);
+}
+
+static void pciexp_config_max_latency(device_t root, device_t dev)
+{
+	unsigned int cap;
+	cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_LTR_ID);
+	if (root->ops->ops_pci->set_L1_ss_latency != NULL)
+		root->ops->ops_pci->set_L1_ss_latency(dev, cap + 4);
+}
+
+static void pciexp_enable_ltr(device_t dev)
+{
+	unsigned int cap;
+	cap = pci_find_capability(dev, PCI_CAP_ID_PCIE);
+
+	pcie_update_cfg(dev, cap + 0x28, ~(1 << 10), 1 << 10);
+}
+
+static unsigned char pciexp_L1_substate_cal(device_t dev, unsigned int endp_cap,
+	unsigned int *data)
+{
+	unsigned char mult[4] = {2, 10, 100, 0};
+
+	unsigned int L1SubStateSupport = *data & 0xf;
+	unsigned int comm_mode_rst_time = (*data >> 8) & 0xff;
+	unsigned int power_on_scale = (*data >> 16) & 0x3;
+	unsigned int power_on_value = (*data >> 19) & 0x1f;
+
+	unsigned int endp_data = pci_mmio_read_config32(dev, endp_cap + 4);
+	unsigned int endp_L1SubStateSupport = endp_data & 0xf;
+	unsigned int endp_comm_mode_restore_time = (endp_data >> 8) & 0xff;
+	unsigned int endp_power_on_scale = (endp_data >> 16) & 0x3;
+	unsigned int endp_power_on_value = (endp_data >> 19) & 0x1f;
+
+	L1SubStateSupport &= endp_L1SubStateSupport;
+
+	if (L1SubStateSupport == 0)
+		return 0;
+
+	if (power_on_value * mult[power_on_scale] <
+		endp_power_on_value * mult[endp_power_on_scale]) {
+		power_on_value = endp_power_on_value;
+		power_on_scale = endp_power_on_scale;
+	}
+	if (comm_mode_rst_time < endp_comm_mode_restore_time)
+		comm_mode_rst_time = endp_comm_mode_restore_time;
+
+	*data = (comm_mode_rst_time << 8) | (power_on_scale << 16)
+		| (power_on_value << 19) | L1SubStateSupport;
+
+	return 1;
+}
+
+static void pciexp_L1_substate_commit(device_t root, device_t dev,
+	unsigned int root_cap, unsigned int end_cap)
+{
+	device_t dev_t;
+	unsigned char L1_ss_ok;
+	unsigned int rp_L1_support = pci_mmio_read_config32(root, root_cap + 4);
+	unsigned int L1SubStateSupport;
+	unsigned int comm_mode_rst_time;
+	unsigned int power_on_scale;
+	unsigned int endp_power_on_value;
+
+	for (dev_t = dev; dev_t; dev_t = dev_t->sibling) {
+		/*
+		 * rp_L1_support is init'd above from root port.
+		 * it needs coordination with endpoints to reach in common.
+		 * if certain endpoint doesn't support L1 Sub-State, abort
+		 * this feature enabling.
+		 */
+		L1_ss_ok = pciexp_L1_substate_cal(dev_t, end_cap,
+						&rp_L1_support);
+		if (!L1_ss_ok)
+			return;
+	}
+
+	L1SubStateSupport = rp_L1_support & 0xf;
+	comm_mode_rst_time = (rp_L1_support >> 8) & 0xff;
+	power_on_scale = (rp_L1_support >> 16) & 0x3;
+	endp_power_on_value = (rp_L1_support >> 19) & 0x1f;
+
+	printk(BIOS_INFO, "L1 Sub-State supported from root port %d\n",
+		root->path.pci.devfn >> 3);
+	printk(BIOS_INFO, "L1 Sub-State Support = 0x%x\n", L1SubStateSupport);
+	printk(BIOS_INFO, "CommonModeRestoreTime = 0x%x\n", comm_mode_rst_time);
+	printk(BIOS_INFO, "Power On Value = 0x%x, Power On Scale = 0x%x\n",
+		endp_power_on_value, power_on_scale);
+
+	pciexp_enable_ltr(root);
+
+	pcie_update_cfg(root, root_cap + 0x08, ~0xff00,
+		(comm_mode_rst_time << 8));
+
+	pcie_update_cfg(root, root_cap + 0x0c , 0xffffff04,
+		(endp_power_on_value << 3) | (power_on_scale));
+
+	pcie_update_cfg(root, root_cap + 0x08, ~0xe3ff0000,
+		(1 << 21) | (1 << 23) | (1 << 30));
+
+	pcie_update_cfg(root, root_cap + 0x08, ~0xf,
+		L1SubStateSupport);
+
+	for (dev_t = dev; dev_t; dev_t = dev_t->sibling) {
+		pcie_update_cfg(dev_t, end_cap + 0x08, ~0xff00,
+			(comm_mode_rst_time << 8));
+
+		pcie_update_cfg(dev_t, end_cap + 0x0c , 0xffffff04,
+			(endp_power_on_value << 3) | (power_on_scale));
+
+		pcie_update_cfg(dev_t, end_cap + 0x08, ~0xe3ff0000,
+			(1 << 21) | (1 << 23) | (1 << 30));
+
+		pcie_update_cfg(dev_t, end_cap + 0x08, ~0xf,
+			L1SubStateSupport);
+
+		pciexp_enable_ltr(dev_t);
+
+		pciexp_config_max_latency(root, dev_t);
+	}
+}
+
+static void pciexp_config_L1_sub_state(device_t root, device_t dev)
+{
+	unsigned int root_cap, end_cap;
+
+	/* Do it for function 0 only */
+	if (dev->path.pci.devfn & 0x7)
+		return;
+
+	root_cap = pciexp_find_extended_cap(root, PCIE_EXT_CAP_L1SS_ID);
+	if (!root_cap)
+		return;
+
+	end_cap = pciexp_find_extended_cap(dev, PCIE_EXT_CAP_L1SS_ID);
+	if (!end_cap) {
+		end_cap = pciexp_find_extended_cap(dev, 0xcafe);
+		if (!end_cap)
+			return;
+	}
+
+	pciexp_L1_substate_commit(root, dev, root_cap, end_cap);
+}
+#endif /* CONFIG_PCIEXP_L1_SUB_STATE */
+
 #if CONFIG_PCIEXP_ASPM
 /*
  * Determine the ASPM L0s or L1 exit latency for a link
@@ -222,6 +399,11 @@ static void pciexp_tune_dev(device_t dev)
 	pciexp_enable_clock_power_pm(dev, cap);
 #endif
 
+#if CONFIG_PCIEXP_L1_SUB_STATE
+	/* Enable L1 Sub-State when both root port and endpoint support */
+	pciexp_config_L1_sub_state(root, dev);
+#endif /* CONFIG_PCIEXP_L1_SUB_STATE */
+
 #if CONFIG_PCIEXP_ASPM
 	/* Check for and enable ASPM */
 	enum aspm_type apmc = pciexp_enable_aspm(root, root_cap, dev, cap);
diff --git a/src/include/device/pci.h b/src/include/device/pci.h
index 0670da4..4e712f9 100644
--- a/src/include/device/pci.h
+++ b/src/include/device/pci.h
@@ -33,6 +33,7 @@
 struct pci_operations {
 	/* set the Subsystem IDs for the PCI device */
 	void (*set_subsystem)(device_t dev, unsigned vendor, unsigned device);
+	void (*set_L1_ss_latency)(device_t dev, unsigned int off);
 };
 
 /* Common pci bus operations */
diff --git a/src/include/device/pci_def.h b/src/include/device/pci_def.h
index 4039785..c49e4eb 100644
--- a/src/include/device/pci_def.h
+++ b/src/include/device/pci_def.h
@@ -405,6 +405,12 @@
 #define PCI_EXT_CAP_ID_DSN	3
 #define PCI_EXT_CAP_ID_PWR	4
 
+/* Extended Capability lists*/
+#define PCIE_EXT_CAP_OFFSET	0x100
+#define  PCIE_EXT_CAP_AER_ID	0x0001
+#define  PCIE_EXT_CAP_L1SS_ID	0x001E
+#define  PCIE_EXT_CAP_LTR_ID	0x0018
+
 /* Advanced Error Reporting */
 #define PCI_ERR_UNCOR_STATUS	4	/* Uncorrectable Error Status */
 #define  PCI_ERR_UNC_TRAIN	0x00000001	/* Training */
diff --git a/src/include/device/pciexp.h b/src/include/device/pciexp.h
index 87a5002..1146557 100644
--- a/src/include/device/pciexp.h
+++ b/src/include/device/pciexp.h
@@ -15,4 +15,5 @@ unsigned int pciexp_scan_bridge(device_t dev, unsigned int max);
 
 extern struct device_operations default_pciexp_ops_bus;
 
+unsigned int pciexp_find_extended_cap(device_t dev, unsigned int cap);
 #endif /* DEVICE_PCIEXP_H */



More information about the coreboot-gerrit mailing list