aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-01-10 15:46:36 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-05-11 18:18:48 -0400
commit48a92a8179b3e677fac07db7bd109e68f020468c (patch)
treea0d43c7fc33fd5c899ce81103097117c27dd3e60 /drivers/pci/pci.c
parentb48d4425b602f5f4978299474743dbea130d940d (diff)
PCI: add OBFF enable/disable support
OBFF (optimized buffer flush/fill), where supported, can help improve energy efficiency by giving devices information about when interrupts and other activity will have a reduced power impact. It requires support from both the device and system (i.e. not only does the device need to respond to OBFF messages, but the platform must be capable of generating and routing them to the end point). Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d0182bed7acc..01e4cab2e5cb 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1887,6 +1887,98 @@ void pci_disable_ido(struct pci_dev *dev, unsigned long type)
1887} 1887}
1888EXPORT_SYMBOL(pci_disable_ido); 1888EXPORT_SYMBOL(pci_disable_ido);
1889 1889
1890/**
1891 * pci_enable_obff - enable optimized buffer flush/fill
1892 * @dev: PCI device
1893 * @type: type of signaling to use
1894 *
1895 * Try to enable @type OBFF signaling on @dev. It will try using WAKE#
1896 * signaling if possible, falling back to message signaling only if
1897 * WAKE# isn't supported. @type should indicate whether the PCIe link
1898 * be brought out of L0s or L1 to send the message. It should be either
1899 * %PCI_EXP_OBFF_SIGNAL_ALWAYS or %PCI_OBFF_SIGNAL_L0.
1900 *
1901 * If your device can benefit from receiving all messages, even at the
1902 * power cost of bringing the link back up from a low power state, use
1903 * %PCI_EXP_OBFF_SIGNAL_ALWAYS. Otherwise, use %PCI_OBFF_SIGNAL_L0 (the
1904 * preferred type).
1905 *
1906 * RETURNS:
1907 * Zero on success, appropriate error number on failure.
1908 */
1909int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
1910{
1911 int pos;
1912 u32 cap;
1913 u16 ctrl;
1914 int ret;
1915
1916 if (!pci_is_pcie(dev))
1917 return -ENOTSUPP;
1918
1919 pos = pci_pcie_cap(dev);
1920 if (!pos)
1921 return -ENOTSUPP;
1922
1923 pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
1924 if (!(cap & PCI_EXP_OBFF_MASK))
1925 return -ENOTSUPP; /* no OBFF support at all */
1926
1927 /* Make sure the topology supports OBFF as well */
1928 if (dev->bus) {
1929 ret = pci_enable_obff(dev->bus->self, type);
1930 if (ret)
1931 return ret;
1932 }
1933
1934 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
1935 if (cap & PCI_EXP_OBFF_WAKE)
1936 ctrl |= PCI_EXP_OBFF_WAKE_EN;
1937 else {
1938 switch (type) {
1939 case PCI_EXP_OBFF_SIGNAL_L0:
1940 if (!(ctrl & PCI_EXP_OBFF_WAKE_EN))
1941 ctrl |= PCI_EXP_OBFF_MSGA_EN;
1942 break;
1943 case PCI_EXP_OBFF_SIGNAL_ALWAYS:
1944 ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
1945 ctrl |= PCI_EXP_OBFF_MSGB_EN;
1946 break;
1947 default:
1948 WARN(1, "bad OBFF signal type\n");
1949 return -ENOTSUPP;
1950 }
1951 }
1952 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
1953
1954 return 0;
1955}
1956EXPORT_SYMBOL(pci_enable_obff);
1957
1958/**
1959 * pci_disable_obff - disable optimized buffer flush/fill
1960 * @dev: PCI device
1961 *
1962 * Disable OBFF on @dev.
1963 */
1964void pci_disable_obff(struct pci_dev *dev)
1965{
1966 int pos;
1967 u16 ctrl;
1968
1969 if (!pci_is_pcie(dev))
1970 return;
1971
1972 pos = pci_pcie_cap(dev);
1973 if (!pos)
1974 return;
1975
1976 pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
1977 ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
1978 pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
1979}
1980EXPORT_SYMBOL(pci_disable_obff);
1981
1890static int pci_acs_enable; 1982static int pci_acs_enable;
1891 1983
1892/** 1984/**