This will be needed for upcoming LS1028a support. The code is taken from U-Boot which suffices for our usecase. The kernel code is much more elaborated here. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- drivers/pci/pci.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pci.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a3e7e70871..84678e40a9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -553,6 +553,38 @@ pci_of_match_device(struct device *parent, unsigned int devfn) return NULL; } +/** + * pcie_flr - initiate a PCIe function level reset + * @dev: device to reset + * + * Initiate a function level reset on @dev. + */ +int pci_flr(struct pci_dev *pdev) +{ + u16 val; + int pcie_off; + u32 cap; + + /* look for PCI Express Capability */ + pcie_off = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!pcie_off) + return -ENOENT; + + /* check FLR capability */ + pci_read_config_dword(pdev, pcie_off + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -ENOENT; + + pci_read_config_word(pdev, pcie_off + PCI_EXP_DEVCTL, &val); + val |= PCI_EXP_DEVCTL_BCR_FLR; + pci_write_config_word(pdev, pcie_off + PCI_EXP_DEVCTL, val); + + /* wait 100ms, per PCI spec */ + mdelay(100); + + return 0; +} + static unsigned int pci_scan_bus(struct pci_bus *bus) { struct pci_dev *dev; diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e907209a7..fe5285116a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -329,6 +329,8 @@ u8 pci_find_capability(struct pci_dev *dev, int cap); extern void __iomem *pci_iomap(struct pci_dev *dev, int bar); +int pci_flr(struct pci_dev *pdev); + /* * The world is not perfect and supplies us with broken PCI devices. * For at least a part of these bugs we need a work-around, so both -- 2.39.2