diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2008-11-11 04:17:48 -0500 |
|---|---|---|
| committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-01-07 14:12:25 -0500 |
| commit | 1ca887970a3971a22e4875b7c6ad5ae3ce49f61a (patch) | |
| tree | 8368a3f90da7ee894818658ff925478ef0b43947 | |
| parent | f7b7baae6b30ff04124259ff8d7c0c0d281320e6 (diff) | |
PCI: Extend pci_reset_function() to support PCI Advanced Features
Some PCI devices implement PCI Advanced Features, which means they
support Function Level Reset(FLR). Implement support for that in
pci_reset_function.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
| -rw-r--r-- | drivers/pci/pci.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 62978f644a92..3c2fa2fdc9cd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -1789,6 +1789,43 @@ static int __pcie_flr(struct pci_dev *dev, int probe) | |||
| 1789 | return 0; | 1789 | return 0; |
| 1790 | } | 1790 | } |
| 1791 | 1791 | ||
| 1792 | static int __pci_af_flr(struct pci_dev *dev, int probe) | ||
| 1793 | { | ||
| 1794 | int cappos = pci_find_capability(dev, PCI_CAP_ID_AF); | ||
| 1795 | u8 status; | ||
| 1796 | u8 cap; | ||
| 1797 | |||
| 1798 | if (!cappos) | ||
| 1799 | return -ENOTTY; | ||
| 1800 | pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap); | ||
| 1801 | if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR)) | ||
| 1802 | return -ENOTTY; | ||
| 1803 | |||
| 1804 | if (probe) | ||
| 1805 | return 0; | ||
| 1806 | |||
| 1807 | pci_block_user_cfg_access(dev); | ||
| 1808 | |||
| 1809 | /* Wait for Transaction Pending bit clean */ | ||
| 1810 | msleep(100); | ||
| 1811 | pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); | ||
| 1812 | if (status & PCI_AF_STATUS_TP) { | ||
| 1813 | dev_info(&dev->dev, "Busy after 100ms while trying to" | ||
| 1814 | " reset; sleeping for 1 second\n"); | ||
| 1815 | ssleep(1); | ||
| 1816 | pci_read_config_byte(dev, | ||
| 1817 | cappos + PCI_AF_STATUS, &status); | ||
| 1818 | if (status & PCI_AF_STATUS_TP) | ||
| 1819 | dev_info(&dev->dev, "Still busy after 1s; " | ||
| 1820 | "proceeding with reset anyway\n"); | ||
| 1821 | } | ||
| 1822 | pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); | ||
| 1823 | mdelay(100); | ||
| 1824 | |||
| 1825 | pci_unblock_user_cfg_access(dev); | ||
| 1826 | return 0; | ||
| 1827 | } | ||
| 1828 | |||
| 1792 | static int __pci_reset_function(struct pci_dev *pdev, int probe) | 1829 | static int __pci_reset_function(struct pci_dev *pdev, int probe) |
| 1793 | { | 1830 | { |
| 1794 | int res; | 1831 | int res; |
| @@ -1797,6 +1834,10 @@ static int __pci_reset_function(struct pci_dev *pdev, int probe) | |||
| 1797 | if (res != -ENOTTY) | 1834 | if (res != -ENOTTY) |
| 1798 | return res; | 1835 | return res; |
| 1799 | 1836 | ||
| 1837 | res = __pci_af_flr(pdev, probe); | ||
| 1838 | if (res != -ENOTTY) | ||
| 1839 | return res; | ||
| 1840 | |||
| 1800 | return res; | 1841 | return res; |
| 1801 | } | 1842 | } |
| 1802 | 1843 | ||
