diff options
author | Sheng Yang <sheng@linux.intel.com> | 2008-10-21 05:38:25 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2008-10-22 19:42:35 -0400 |
commit | 8dd7f8036c123296fc4214f9d8810eb485570422 (patch) | |
tree | 0c6cab9083be724d2c72ba4aabef9e3b0dffd7fc /drivers/pci | |
parent | c4ed02fae78bf6cea0b22edd34a67df972f29832 (diff) |
PCI: add support for function level reset
Sometimes, it's necessary to enable software's ability to quiesce and
reset endpoint hardware with function-level granularity, so provide
support for it.
The patch implement Function Level Reset(FLR) feature following PCI-e
spec. And this is the first step. We would add more generic method, like
D0/D3, to allow more devices support this function.
The patch contains two functions. pcie_reset_function() is the new
driver API, and, contains some action to quiesce a device. The other
function is a helper: pcie_execute_reset_function() just executes the
reset for a particular device function.
Current the usage model is in KVM. Function reset is necessary for
assigning device to a guest, or moving it between partitions.
For Function Level Reset(FLR), please refer to PCI Express spec chapter
6.6.2.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index aee73cf251b6..533aeb5fcbe4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/log2.h> | 18 | #include <linux/log2.h> |
19 | #include <linux/pci-aspm.h> | 19 | #include <linux/pci-aspm.h> |
20 | #include <linux/pm_wakeup.h> | 20 | #include <linux/pm_wakeup.h> |
21 | #include <linux/interrupt.h> | ||
21 | #include <asm/dma.h> /* isa_dma_bridge_buggy */ | 22 | #include <asm/dma.h> /* isa_dma_bridge_buggy */ |
22 | #include "pci.h" | 23 | #include "pci.h" |
23 | 24 | ||
@@ -1746,6 +1747,103 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary); | |||
1746 | #endif | 1747 | #endif |
1747 | 1748 | ||
1748 | /** | 1749 | /** |
1750 | * pci_execute_reset_function() - Reset a PCI device function | ||
1751 | * @dev: Device function to reset | ||
1752 | * | ||
1753 | * Some devices allow an individual function to be reset without affecting | ||
1754 | * other functions in the same device. The PCI device must be responsive | ||
1755 | * to PCI config space in order to use this function. | ||
1756 | * | ||
1757 | * The device function is presumed to be unused when this function is called. | ||
1758 | * Resetting the device will make the contents of PCI configuration space | ||
1759 | * random, so any caller of this must be prepared to reinitialise the | ||
1760 | * device including MSI, bus mastering, BARs, decoding IO and memory spaces, | ||
1761 | * etc. | ||
1762 | * | ||
1763 | * Returns 0 if the device function was successfully reset or -ENOTTY if the | ||
1764 | * device doesn't support resetting a single function. | ||
1765 | */ | ||
1766 | int pci_execute_reset_function(struct pci_dev *dev) | ||
1767 | { | ||
1768 | u16 status; | ||
1769 | u32 cap; | ||
1770 | int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
1771 | |||
1772 | if (!exppos) | ||
1773 | return -ENOTTY; | ||
1774 | pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); | ||
1775 | if (!(cap & PCI_EXP_DEVCAP_FLR)) | ||
1776 | return -ENOTTY; | ||
1777 | |||
1778 | pci_block_user_cfg_access(dev); | ||
1779 | |||
1780 | /* Wait for Transaction Pending bit clean */ | ||
1781 | msleep(100); | ||
1782 | pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); | ||
1783 | if (status & PCI_EXP_DEVSTA_TRPND) { | ||
1784 | dev_info(&dev->dev, "Busy after 100ms while trying to reset; " | ||
1785 | "sleeping for 1 second\n"); | ||
1786 | ssleep(1); | ||
1787 | pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); | ||
1788 | if (status & PCI_EXP_DEVSTA_TRPND) | ||
1789 | dev_info(&dev->dev, "Still busy after 1s; " | ||
1790 | "proceeding with reset anyway\n"); | ||
1791 | } | ||
1792 | |||
1793 | pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, | ||
1794 | PCI_EXP_DEVCTL_BCR_FLR); | ||
1795 | mdelay(100); | ||
1796 | |||
1797 | pci_unblock_user_cfg_access(dev); | ||
1798 | return 0; | ||
1799 | } | ||
1800 | EXPORT_SYMBOL_GPL(pci_execute_reset_function); | ||
1801 | |||
1802 | /** | ||
1803 | * pci_reset_function() - quiesce and reset a PCI device function | ||
1804 | * @dev: Device function to reset | ||
1805 | * | ||
1806 | * Some devices allow an individual function to be reset without affecting | ||
1807 | * other functions in the same device. The PCI device must be responsive | ||
1808 | * to PCI config space in order to use this function. | ||
1809 | * | ||
1810 | * This function does not just reset the PCI portion of a device, but | ||
1811 | * clears all the state associated with the device. This function differs | ||
1812 | * from pci_execute_reset_function in that it saves and restores device state | ||
1813 | * over the reset. | ||
1814 | * | ||
1815 | * Returns 0 if the device function was successfully reset or -ENOTTY if the | ||
1816 | * device doesn't support resetting a single function. | ||
1817 | */ | ||
1818 | int pci_reset_function(struct pci_dev *dev) | ||
1819 | { | ||
1820 | u32 cap; | ||
1821 | int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); | ||
1822 | int r; | ||
1823 | |||
1824 | if (!exppos) | ||
1825 | return -ENOTTY; | ||
1826 | pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); | ||
1827 | if (!(cap & PCI_EXP_DEVCAP_FLR)) | ||
1828 | return -ENOTTY; | ||
1829 | |||
1830 | if (!dev->msi_enabled && !dev->msix_enabled) | ||
1831 | disable_irq(dev->irq); | ||
1832 | pci_save_state(dev); | ||
1833 | |||
1834 | pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); | ||
1835 | |||
1836 | r = pci_execute_reset_function(dev); | ||
1837 | |||
1838 | pci_restore_state(dev); | ||
1839 | if (!dev->msi_enabled && !dev->msix_enabled) | ||
1840 | enable_irq(dev->irq); | ||
1841 | |||
1842 | return r; | ||
1843 | } | ||
1844 | EXPORT_SYMBOL_GPL(pci_reset_function); | ||
1845 | |||
1846 | /** | ||
1749 | * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count | 1847 | * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count |
1750 | * @dev: PCI device to query | 1848 | * @dev: PCI device to query |
1751 | * | 1849 | * |