From ff9aa890947a848d1b016635e3b1ff44f0e1dfde Mon Sep 17 00:00:00 2001 From: Li Guohui Date: Fri, 13 Jun 2025 15:48:16 +0800 Subject: [PATCH] anolis: PCI: phytium: Add hotplug and hotreset workaround patch for phytium SoCs ANBZ: #21776 When the PCIe device is unplugged or under hotreset, the PCIe controller's protrction mechanism is triggered, which will make the link inaccessible. This patch disables the protection after the link is up and makes the PCIe hotplug or hotreset process work well. Signed-off-by: Li Guohui Signed-off-by: Long Shixiang Signed-off-by: Wang Yinfeng --- drivers/pci/hotplug/pciehp_ctrl.c | 8 ++++++- drivers/pci/pci.c | 4 ++++ drivers/pci/pci.h | 39 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 5ec5f8a63200..9b25e9090624 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -20,7 +20,9 @@ #include #include #include "pciehp.h" - +#ifdef CONFIG_ARCH_PHYTIUM +#include "../pci.h" +#endif /* The following routines constitute the bulk of the hotplug controller logic */ @@ -303,6 +305,10 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) if (link_active) ctrl_info(ctrl, "Slot(%s): Link Up\n", slot_name(ctrl)); +#ifdef CONFIG_ARCH_PHYTIUM + if (present && link_active) + phytium_clear_ctrl_prot(ctrl->pcie->port, PHYTIUM_PCIE_HOTPLUG); +#endif ctrl->request_result = pciehp_enable_slot(ctrl); break; default: diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 595a5f4fdc94..59e7e4b28c30 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5008,6 +5008,10 @@ void pci_reset_secondary_bus(struct pci_dev *dev) ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + +#ifdef CONFIG_ARCH_PHYTIUM + phytium_clear_ctrl_prot(dev, PHYTIUM_PCIE_HOTRESET); +#endif } void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 0bc9927c2f5d..e258030e4f31 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -728,4 +728,43 @@ extern const struct attribute_group aspm_ctrl_attr_group; void pci_seq_tree_add_dev(struct pci_dev *dev); void pci_seq_tree_remove_dev(struct pci_dev *dev); +#ifdef CONFIG_ARCH_PHYTIUM +#include +#define PHYTIUM_PCIE_HOTRESET 0 +#define PHYTIUM_PCIE_HOTPLUG 1 +#define PHYTIUM_PCI_VENDOR_ID 0x1DB7 +#define PHYTIUM_PCI_CTRL_ID 0x0100 +#define PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID 0xC2000020 +static inline void phytium_clear_ctrl_prot(struct pci_dev *pdev, int op) +{ + int socket; + u8 bus = pdev->bus->number; + u8 device = PCI_SLOT(pdev->devfn); + u8 function = PCI_FUNC(pdev->devfn); + u16 vendor_id = pdev->vendor; + u16 device_id = pdev->device; + struct arm_smccc_res res; + u32 arg; + + if (vendor_id != PHYTIUM_PCI_VENDOR_ID || + device_id != PHYTIUM_PCI_CTRL_ID || + pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) + return; + + socket = dev_to_node(&pdev->dev); + if (socket < 0) { + pci_err(pdev, "Cannot find socket, stop clean pcie protection\n"); + return; + } + + arg = (socket << 16) | (bus << 8) | (device << 3) | function; + arm_smccc_smc(PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID, arg, op, 0, 0, 0, 0, 0, &res); + if (res.a0 != 0) + pci_err(pdev, "Error: Firmware call PCIE protection clear Failed: %d, sbdf: 0x%x\n", + (int)res.a0, arg); + else + pci_info(pdev, "%s : Clear pcie protection successfully\n", + op ? "HotPlug" : "HotReset"); +} +#endif #endif /* DRIVERS_PCI_H */ -- Gitee