From d53a597196f75b8ab327cc93425c21f7be71c3ae Mon Sep 17 00:00:00 2001 From: Malloy Liu Date: Fri, 13 Jun 2025 15:57:28 +0800 Subject: [PATCH] PCI: phytium: Add hotplug and hotreset workaround patch for phytium SoCs 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: Malloy Liu --- drivers/pci/hotplug/pciehp_ctrl.c | 8 +++++++ drivers/pci/pci.c | 3 +++ drivers/pci/pci.h | 39 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 6503d15effbb..f8380e4d0beb 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -21,6 +21,10 @@ #include #include "pciehp.h" +#ifdef CONFIG_ARCH_PHYTIUM +#include "../pci.h" +#endif + /* The following routines constitute the bulk of the hotplug controller logic */ @@ -275,6 +279,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 64f9df655170..7b04859fd1b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4856,6 +4856,9 @@ 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 1e0b765abb86..6f802d7c557e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -687,4 +687,43 @@ static inline int pci_acpi_program_hp_params(struct pci_dev *dev) } #endif +#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