diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 5ec5f8a632008784a391b5a4aded5e32f5019dee..9b25e90906243684100b3cede4397d5c23b9cf32 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 595a5f4fdc9473a6e5a20bd153ab25644758261d..59e7e4b28c30cafd6f91470e00a5f7aa01097317 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 0bc9927c2f5dd3da5cbf894c67f26672b4d6cdbe..e258030e4f31df9952fb54d263246c1257972842 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 */