diff options
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 92 |
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 | } |
1888 | EXPORT_SYMBOL(pci_disable_ido); | 1888 | EXPORT_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 | */ | ||
1909 | int 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 | } | ||
1956 | EXPORT_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 | */ | ||
1964 | void 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 | } | ||
1980 | EXPORT_SYMBOL(pci_disable_obff); | ||
1981 | |||
1890 | static int pci_acs_enable; | 1982 | static int pci_acs_enable; |
1891 | 1983 | ||
1892 | /** | 1984 | /** |