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 | ||