aboutsummaryrefslogtreecommitdiff
path: root/nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch')
-rw-r--r--nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch148
1 files changed, 148 insertions, 0 deletions
diff --git a/nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch b/nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch
new file mode 100644
index 0000000..c565c7f
--- /dev/null
+++ b/nixos/modules/omnia-kernel-patches/0051-PCI-aardvark-Send-Set_Slot_Power_Limit-message.patch
@@ -0,0 +1,148 @@
+From 2010d62095990f6074350d37483579f4089b4239 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 31 Aug 2022 15:57:01 +0200
+Subject: [PATCH 51/53] PCI: aardvark: Send Set_Slot_Power_Limit message
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Emulate Slot PowerLimit Scale and Value bits in the Slot Capabilities
+register of the emulated bridge and if slot power limit value is
+defined, send that Set_Slot_Power_Limit message via Message Generation
+Control Register in Link Up handler on link up event.
+
+Slot power limit value is read from device-tree property
+'slot-power-limit-milliwatt'. If this property is not specified, we
+treat it as "Slot Capabilities register has not yet been initialized".
+
+According to PCIe Base specification 3.0, when transitioning from a
+non-DL_Up Status to a DL_Up Status, the Port must initiate the
+transmission of a Set_Slot_Power_Limit Message to the other component
+on the Link to convey the value programmed in the Slot Power Limit
+Scale and Value fields of the Slot Capabilities register. This
+transmission is optional if the Slot Capabilities register has not
+yet been initialized.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Marek Behún <kabel@kernel.org>
+---
+ drivers/pci/controller/pci-aardvark.c | 51 ++++++++++++++++++++++++---
+ 1 file changed, 47 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
+index 9a7db62982a6..3a7aece3eff2 100644
+--- a/drivers/pci/controller/pci-aardvark.c
++++ b/drivers/pci/controller/pci-aardvark.c
+@@ -213,6 +213,11 @@ enum {
+ };
+
+ #define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
++#define PME_MSG_GEN_CTRL (LMI_BASE_ADDR + 0x220)
++#define SEND_SET_SLOT_POWER_LIMIT BIT(13)
++#define SEND_PME_TURN_OFF BIT(14)
++#define SLOT_POWER_LIMIT_DATA_SHIFT 16
++#define SLOT_POWER_LIMIT_DATA_MASK GENMASK(25, 16)
+
+ /* PCIe core controller registers */
+ #define CTRL_CORE_BASE_ADDR 0x18000
+@@ -285,6 +290,8 @@ struct advk_pcie {
+ raw_spinlock_t msi_irq_lock;
+ DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
+ struct mutex msi_used_lock;
++ u8 slot_power_limit_value;
++ u8 slot_power_limit_scale;
+ int link_gen;
+ bool link_was_up;
+ struct timer_list link_irq_timer;
+@@ -317,8 +324,9 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
+ {
+ /* check if LTSSM is in normal operation - some L* state */
+ u8 ltssm_state = advk_pcie_ltssm_state(pcie);
++ u16 slotsta, slotctl;
++ u32 slotpwr, val;
+ bool link_is_up;
+- u16 slotsta;
+
+ link_is_up = ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED;
+
+@@ -332,6 +340,27 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
+ pcie->bridge.pcie_conf.slotsta = cpu_to_le16(slotsta);
+
+ mod_timer(&pcie->link_irq_timer, jiffies + 1);
++
++ /*
++ * According to PCIe Base specification 3.0, when transitioning
++ * from a non-DL_Up Status to a DL_Up Status, the Port must
++ * initiate the transmission of a Set_Slot_Power_Limit Message
++ * to the other component on the Link to convey the value
++ * programmed in the Slot Power Limit Scale and Value fields of
++ * the Slot Capabilities register. This transmission is optional
++ * if the Slot Capabilities register has not yet been
++ * initialized.
++ */
++ slotctl = le16_to_cpu(pcie->bridge.pcie_conf.slotctl);
++ slotpwr = FIELD_GET(PCI_EXP_SLTCAP_SPLV | PCI_EXP_SLTCAP_SPLS,
++ le32_to_cpu(pcie->bridge.pcie_conf.slotcap));
++ if (!(slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE) && slotpwr) {
++ val = advk_readl(pcie, PME_MSG_GEN_CTRL);
++ val &= ~SLOT_POWER_LIMIT_DATA_MASK;
++ val |= slotpwr << SLOT_POWER_LIMIT_DATA_SHIFT;
++ val |= SEND_SET_SLOT_POWER_LIMIT;
++ advk_writel(pcie, val, PME_MSG_GEN_CTRL);
++ }
+ }
+
+ return link_is_up;
+@@ -944,8 +973,9 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
+
+ case PCI_EXP_SLTCTL: {
+ u16 slotctl = le16_to_cpu(bridge->pcie_conf.slotctl);
+- /* Only emulation of HPIE and DLLSCE bits is provided */
+- slotctl &= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE;
++ /* Only emulation of HPIE, DLLSCE and ASPLD bits is provided */
++ slotctl &= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE |
++ PCI_EXP_SLTCTL_ASPL_DISABLE;
+ bridge->pcie_conf.slotctl = cpu_to_le16(slotctl);
+ break;
+ }
+@@ -1109,9 +1139,13 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
+ * Set physical slot number to 1 since there is only one port and zero
+ * value is reserved for ports within the same silicon as Root Port
+ * which is not our case.
++ *
++ * Set slot power limit.
+ */
+ slotcap = PCI_EXP_SLTCAP_NCCS | PCI_EXP_SLTCAP_HPC |
+- FIELD_PREP(PCI_EXP_SLTCAP_PSN, 1);
++ FIELD_PREP(PCI_EXP_SLTCAP_PSN, 1) |
++ FIELD_PREP(PCI_EXP_SLTCAP_SPLV, pcie->slot_power_limit_value) |
++ FIELD_PREP(PCI_EXP_SLTCAP_SPLS, pcie->slot_power_limit_scale);
+ bridge->pcie_conf.slotcap = cpu_to_le32(slotcap);
+ bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
+
+@@ -1851,6 +1885,7 @@ static int advk_pcie_probe(struct platform_device *pdev)
+ struct advk_pcie *pcie;
+ struct pci_host_bridge *bridge;
+ struct resource_entry *entry;
++ u32 slot_power_limit;
+ int ret, irq;
+
+ bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie));
+@@ -1971,6 +2006,14 @@ static int advk_pcie_probe(struct platform_device *pdev)
+ else
+ pcie->link_gen = ret;
+
++ slot_power_limit = of_pci_get_slot_power_limit(dev->of_node,
++ &pcie->slot_power_limit_value,
++ &pcie->slot_power_limit_scale);
++ if (slot_power_limit)
++ dev_info(dev, "Slot Power Limit: %u.%uW\n",
++ slot_power_limit / 1000,
++ (slot_power_limit / 100) % 10);
++
+ ret = advk_pcie_setup_phy(pcie);
+ if (ret)
+ return ret;
+--
+2.37.3
+