diff options
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.patch | 148 |
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 + |