aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/pci/pci.c92
-rw-r--r--include/linux/pci.h16
-rw-r--r--include/linux/pci_regs.h6
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}
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/**
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,
833void pci_enable_ido(struct pci_dev *dev, unsigned long type); 833void pci_enable_ido(struct pci_dev *dev, unsigned long type);
834void pci_disable_ido(struct pci_dev *dev, unsigned long type); 834void pci_disable_ido(struct pci_dev *dev, unsigned long type);
835 835
836enum pci_obff_signal_type {
837 PCI_EXP_OBFF_SIGNAL_L0,
838 PCI_EXP_OBFF_SIGNAL_ALWAYS,
839};
840int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type);
841void 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 */
837void set_pcie_port_type(struct pci_dev *pdev); 844void set_pcie_port_type(struct pci_dev *pdev);
838void set_pcie_hotplug_bridge(struct pci_dev *pdev); 845void 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
1230static inline int pci_enable_obff(struct pci_dev *dev, unsigned long type)
1231{
1232 return 0;
1233}
1234
1235static inline void pci_disable_obff(struct pci_dev *dev)
1236{
1237}
1238
1223static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) 1239static 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