Hi Matthew How about this time? -- From: Sheng Yang <sheng.yang@xxxxxxxxx> Date: Thu, 28 Aug 2008 13:28:26 +0800 Subject: [PATCH] PCI: Enable Function Level Reset(FLR) for PCI-E The FLR mechanism enables software to quiesce and reset Endpoint hardware with Function-level granularity. Current the usage model for VT-d support in KVM. We'd better to do FLR before assigning device to the guest. This can also be used with other purpose. Please refer to PCI Express spec chapter 6.6.2. Signed-off-by: Sheng Yang <sheng.yang@xxxxxxxxx> --- drivers/pci/pci.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + include/linux/pci_regs.h | 2 + 3 files changed, 54 insertions(+), 0 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c9884bb..53025b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1849,6 +1849,57 @@ out: EXPORT_SYMBOL(pcie_set_readrq); /** + * pcie_do_flr() - execute Function Level Reset + * @dev: PCI device to execute FLR + * + * Returns 0 on success, or -EOPNOTSUPP if device don't support the feature. + * + * The caller should maintained the save/restore of PCI configuration space. + * + * Notice that on rare case, the Transaction Pending bit does not clear before + * FLR, we forced to continue the process, then bless... + **/ +int pcie_do_flr(struct pci_dev *dev) +{ + u16 status; + u32 cap; + int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + + if (!exppos) + return -EOPNOTSUPP; + pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -EOPNOTSUPP; + + pci_block_user_cfg_access(dev); + + /* Clear entire Command register */ + pci_write_config_word(dev, PCI_COMMAND, 0); + pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, 0); + + /* Wait for Transaction Pending bit clean */ + msleep(100); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) { + dev_info(&dev->dev, "trasaction pending when doing FLR, " + "waiting for another 5 seconds\n"); + ssleep(5); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) + dev_info(&dev->dev, "still busy after 5s when doing " + "FLR, reset anyway\n"); + } + + pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); + mdelay(100); + + pci_unblock_user_cfg_access(dev); + return 0; +} +EXPORT_SYMBOL(pcie_do_flr); + +/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected diff --git a/include/linux/pci.h b/include/linux/pci.h index c0e1400..ac804c6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -626,6 +626,7 @@ int pcix_get_mmrbc(struct pci_dev *dev); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); +int pcie_do_flr(struct pci_dev *dev); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int pci_select_bars(struct pci_dev *dev, unsigned long flags); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 450684f..ee55f27 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -377,6 +377,7 @@ #define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ #define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ @@ -389,6 +390,7 @@ #define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ #define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ #define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ #define PCI_EXP_DEVSTA 10 /* Device Status */ #define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ #define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ -- 1.5.6
From 5fae3938340644c6221878f08d8ff2c2fd39ccc8 Mon Sep 17 00:00:00 2001 From: Sheng Yang <sheng.yang@xxxxxxxxx> Date: Thu, 28 Aug 2008 13:28:26 +0800 Subject: [PATCH] PCI: Enable Function Level Reset(FLR) for PCI-E The FLR mechanism enables software to quiesce and reset Endpoint hardware with Function-level granularity. Current the usage model for VT-d support in KVM. We'd better to do FLR before assigning device to the guest. This can also be used with other purpose. Please refer to PCI Express spec chapter 6.6.2. Signed-off-by: Sheng Yang <sheng.yang@xxxxxxxxx> --- drivers/pci/pci.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 1 + include/linux/pci_regs.h | 2 + 3 files changed, 54 insertions(+), 0 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index c9884bb..53025b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1849,6 +1849,57 @@ out: EXPORT_SYMBOL(pcie_set_readrq); /** + * pcie_do_flr() - execute Function Level Reset + * @dev: PCI device to execute FLR + * + * Returns 0 on success, or -EOPNOTSUPP if device don't support the feature. + * + * The caller should maintained the save/restore of PCI configuration space. + * + * Notice that on rare case, the Transaction Pending bit does not clear before + * FLR, we forced to continue the process, then bless... + **/ +int pcie_do_flr(struct pci_dev *dev) +{ + u16 status; + u32 cap; + int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + + if (!exppos) + return -EOPNOTSUPP; + pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -EOPNOTSUPP; + + pci_block_user_cfg_access(dev); + + /* Clear entire Command register */ + pci_write_config_word(dev, PCI_COMMAND, 0); + pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, 0); + + /* Wait for Transaction Pending bit clean */ + msleep(100); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) { + dev_info(&dev->dev, "trasaction pending when doing FLR, " + "waiting for another 5 seconds\n"); + ssleep(5); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) + dev_info(&dev->dev, "still busy after 5s when doing " + "FLR, reset anyway\n"); + } + + pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); + mdelay(100); + + pci_unblock_user_cfg_access(dev); + return 0; +} +EXPORT_SYMBOL(pcie_do_flr); + +/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected diff --git a/include/linux/pci.h b/include/linux/pci.h index c0e1400..ac804c6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -626,6 +626,7 @@ int pcix_get_mmrbc(struct pci_dev *dev); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); +int pcie_do_flr(struct pci_dev *dev); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int pci_select_bars(struct pci_dev *dev, unsigned long flags); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index 450684f..ee55f27 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -377,6 +377,7 @@ #define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ #define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ @@ -389,6 +390,7 @@ #define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ #define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ #define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ #define PCI_EXP_DEVSTA 10 /* Device Status */ #define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ #define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ -- 1.5.6