diff options
-rw-r--r-- | drivers/pci/pci.c | 92 | ||||
-rw-r--r-- | include/linux/pci.h | 16 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 6 |
3 files changed, 114 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 | /** |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 551ddcb5f940..45a035cccd93 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -833,6 +833,13 @@ static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, | |||
833 | void pci_enable_ido(struct pci_dev *dev, unsigned long type); | 833 | void pci_enable_ido(struct pci_dev *dev, unsigned long type); |
834 | void pci_disable_ido(struct pci_dev *dev, unsigned long type); | 834 | void pci_disable_ido(struct pci_dev *dev, unsigned long type); |
835 | 835 | ||
836 | enum pci_obff_signal_type { | ||
837 | PCI_EXP_OBFF_SIGNAL_L0, | ||
838 | PCI_EXP_OBFF_SIGNAL_ALWAYS, | ||
839 | }; | ||
840 | int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type); | ||
841 | void pci_disable_obff(struct pci_dev *dev); | ||
842 | |||
836 | /* For use by arch with custom probe code */ | 843 | /* For use by arch with custom probe code */ |
837 | void set_pcie_port_type(struct pci_dev *pdev); | 844 | void set_pcie_port_type(struct pci_dev *pdev); |
838 | void set_pcie_hotplug_bridge(struct pci_dev *pdev); | 845 | void set_pcie_hotplug_bridge(struct pci_dev *pdev); |
@@ -1220,6 +1227,15 @@ static inline void pci_disable_ido(struct pci_dev *dev, unsigned long type) | |||
1220 | { | 1227 | { |
1221 | } | 1228 | } |
1222 | 1229 | ||
1230 | static inline int pci_enable_obff(struct pci_dev *dev, unsigned long type) | ||
1231 | { | ||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | static inline void pci_disable_obff(struct pci_dev *dev) | ||
1236 | { | ||
1237 | } | ||
1238 | |||
1223 | static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) | 1239 | static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) |
1224 | { | 1240 | { |
1225 | return -EIO; | 1241 | return -EIO; |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index d9acf9b99814..aa420261843d 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
@@ -508,10 +508,16 @@ | |||
508 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ | 508 | #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ |
509 | #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ | 509 | #define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ |
510 | #define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ | 510 | #define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */ |
511 | #define PCI_EXP_OBFF_MASK 0xc0000 /* OBFF support mechanism */ | ||
512 | #define PCI_EXP_OBFF_MSG 0x40000 /* New message signaling */ | ||
513 | #define PCI_EXP_OBFF_WAKE 0x80000 /* Re-use WAKE# for OBFF */ | ||
511 | #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ | 514 | #define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ |
512 | #define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ | 515 | #define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */ |
513 | #define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ | 516 | #define PCI_EXP_IDO_REQ_EN 0x100 /* ID-based ordering request enable */ |
514 | #define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ | 517 | #define PCI_EXP_IDO_CMP_EN 0x200 /* ID-based ordering completion enable */ |
518 | #define PCI_EXP_OBFF_MSGA_EN 0x2000 /* OBFF enable with Message type A */ | ||
519 | #define PCI_EXP_OBFF_MSGB_EN 0x4000 /* OBFF enable with Message type B */ | ||
520 | #define PCI_EXP_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ | ||
515 | #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ | 521 | #define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ |
516 | #define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ | 522 | #define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ |
517 | 523 | ||