diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-04-26 17:28:12 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-05-03 05:18:29 -0400 |
commit | eb48eb005098cc6f845d281dd079baea7573f54c (patch) | |
tree | 18eef2f8743a764c34d6ea0cc0f202f2321fba0b /drivers/gpu/drm/i915 | |
parent | 6ebebc9206fca1d20d90edec4873e819cc4051d0 (diff) |
drm/i915: move the ips code to intel_pm.c
We now have a nice home for power management code, so let's use it!
v2: Resolve conflict agains "Only enable IPS polling for gen5"
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 478 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_pm.c | 481 |
3 files changed, 487 insertions, 475 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 833ac8a0cf43..1b1f8e70df8d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -36,14 +36,12 @@ | |||
36 | #include "i915_drm.h" | 36 | #include "i915_drm.h" |
37 | #include "i915_drv.h" | 37 | #include "i915_drv.h" |
38 | #include "i915_trace.h" | 38 | #include "i915_trace.h" |
39 | #include "../../../platform/x86/intel_ips.h" | ||
40 | #include <linux/pci.h> | 39 | #include <linux/pci.h> |
41 | #include <linux/vgaarb.h> | 40 | #include <linux/vgaarb.h> |
42 | #include <linux/acpi.h> | 41 | #include <linux/acpi.h> |
43 | #include <linux/pnp.h> | 42 | #include <linux/pnp.h> |
44 | #include <linux/vga_switcheroo.h> | 43 | #include <linux/vga_switcheroo.h> |
45 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
46 | #include <linux/module.h> | ||
47 | #include <acpi/video.h> | 45 | #include <acpi/video.h> |
48 | #include <asm/pat.h> | 46 | #include <asm/pat.h> |
49 | 47 | ||
@@ -1481,468 +1479,6 @@ static void i915_ironlake_get_mem_freq(struct drm_device *dev) | |||
1481 | } | 1479 | } |
1482 | } | 1480 | } |
1483 | 1481 | ||
1484 | static const struct cparams { | ||
1485 | u16 i; | ||
1486 | u16 t; | ||
1487 | u16 m; | ||
1488 | u16 c; | ||
1489 | } cparams[] = { | ||
1490 | { 1, 1333, 301, 28664 }, | ||
1491 | { 1, 1066, 294, 24460 }, | ||
1492 | { 1, 800, 294, 25192 }, | ||
1493 | { 0, 1333, 276, 27605 }, | ||
1494 | { 0, 1066, 276, 27605 }, | ||
1495 | { 0, 800, 231, 23784 }, | ||
1496 | }; | ||
1497 | |||
1498 | unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) | ||
1499 | { | ||
1500 | u64 total_count, diff, ret; | ||
1501 | u32 count1, count2, count3, m = 0, c = 0; | ||
1502 | unsigned long now = jiffies_to_msecs(jiffies), diff1; | ||
1503 | int i; | ||
1504 | |||
1505 | diff1 = now - dev_priv->last_time1; | ||
1506 | |||
1507 | /* Prevent division-by-zero if we are asking too fast. | ||
1508 | * Also, we don't get interesting results if we are polling | ||
1509 | * faster than once in 10ms, so just return the saved value | ||
1510 | * in such cases. | ||
1511 | */ | ||
1512 | if (diff1 <= 10) | ||
1513 | return dev_priv->chipset_power; | ||
1514 | |||
1515 | count1 = I915_READ(DMIEC); | ||
1516 | count2 = I915_READ(DDREC); | ||
1517 | count3 = I915_READ(CSIEC); | ||
1518 | |||
1519 | total_count = count1 + count2 + count3; | ||
1520 | |||
1521 | /* FIXME: handle per-counter overflow */ | ||
1522 | if (total_count < dev_priv->last_count1) { | ||
1523 | diff = ~0UL - dev_priv->last_count1; | ||
1524 | diff += total_count; | ||
1525 | } else { | ||
1526 | diff = total_count - dev_priv->last_count1; | ||
1527 | } | ||
1528 | |||
1529 | for (i = 0; i < ARRAY_SIZE(cparams); i++) { | ||
1530 | if (cparams[i].i == dev_priv->c_m && | ||
1531 | cparams[i].t == dev_priv->r_t) { | ||
1532 | m = cparams[i].m; | ||
1533 | c = cparams[i].c; | ||
1534 | break; | ||
1535 | } | ||
1536 | } | ||
1537 | |||
1538 | diff = div_u64(diff, diff1); | ||
1539 | ret = ((m * diff) + c); | ||
1540 | ret = div_u64(ret, 10); | ||
1541 | |||
1542 | dev_priv->last_count1 = total_count; | ||
1543 | dev_priv->last_time1 = now; | ||
1544 | |||
1545 | dev_priv->chipset_power = ret; | ||
1546 | |||
1547 | return ret; | ||
1548 | } | ||
1549 | |||
1550 | unsigned long i915_mch_val(struct drm_i915_private *dev_priv) | ||
1551 | { | ||
1552 | unsigned long m, x, b; | ||
1553 | u32 tsfs; | ||
1554 | |||
1555 | tsfs = I915_READ(TSFS); | ||
1556 | |||
1557 | m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); | ||
1558 | x = I915_READ8(TR1); | ||
1559 | |||
1560 | b = tsfs & TSFS_INTR_MASK; | ||
1561 | |||
1562 | return ((m * x) / 127) - b; | ||
1563 | } | ||
1564 | |||
1565 | static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) | ||
1566 | { | ||
1567 | static const struct v_table { | ||
1568 | u16 vd; /* in .1 mil */ | ||
1569 | u16 vm; /* in .1 mil */ | ||
1570 | } v_table[] = { | ||
1571 | { 0, 0, }, | ||
1572 | { 375, 0, }, | ||
1573 | { 500, 0, }, | ||
1574 | { 625, 0, }, | ||
1575 | { 750, 0, }, | ||
1576 | { 875, 0, }, | ||
1577 | { 1000, 0, }, | ||
1578 | { 1125, 0, }, | ||
1579 | { 4125, 3000, }, | ||
1580 | { 4125, 3000, }, | ||
1581 | { 4125, 3000, }, | ||
1582 | { 4125, 3000, }, | ||
1583 | { 4125, 3000, }, | ||
1584 | { 4125, 3000, }, | ||
1585 | { 4125, 3000, }, | ||
1586 | { 4125, 3000, }, | ||
1587 | { 4125, 3000, }, | ||
1588 | { 4125, 3000, }, | ||
1589 | { 4125, 3000, }, | ||
1590 | { 4125, 3000, }, | ||
1591 | { 4125, 3000, }, | ||
1592 | { 4125, 3000, }, | ||
1593 | { 4125, 3000, }, | ||
1594 | { 4125, 3000, }, | ||
1595 | { 4125, 3000, }, | ||
1596 | { 4125, 3000, }, | ||
1597 | { 4125, 3000, }, | ||
1598 | { 4125, 3000, }, | ||
1599 | { 4125, 3000, }, | ||
1600 | { 4125, 3000, }, | ||
1601 | { 4125, 3000, }, | ||
1602 | { 4125, 3000, }, | ||
1603 | { 4250, 3125, }, | ||
1604 | { 4375, 3250, }, | ||
1605 | { 4500, 3375, }, | ||
1606 | { 4625, 3500, }, | ||
1607 | { 4750, 3625, }, | ||
1608 | { 4875, 3750, }, | ||
1609 | { 5000, 3875, }, | ||
1610 | { 5125, 4000, }, | ||
1611 | { 5250, 4125, }, | ||
1612 | { 5375, 4250, }, | ||
1613 | { 5500, 4375, }, | ||
1614 | { 5625, 4500, }, | ||
1615 | { 5750, 4625, }, | ||
1616 | { 5875, 4750, }, | ||
1617 | { 6000, 4875, }, | ||
1618 | { 6125, 5000, }, | ||
1619 | { 6250, 5125, }, | ||
1620 | { 6375, 5250, }, | ||
1621 | { 6500, 5375, }, | ||
1622 | { 6625, 5500, }, | ||
1623 | { 6750, 5625, }, | ||
1624 | { 6875, 5750, }, | ||
1625 | { 7000, 5875, }, | ||
1626 | { 7125, 6000, }, | ||
1627 | { 7250, 6125, }, | ||
1628 | { 7375, 6250, }, | ||
1629 | { 7500, 6375, }, | ||
1630 | { 7625, 6500, }, | ||
1631 | { 7750, 6625, }, | ||
1632 | { 7875, 6750, }, | ||
1633 | { 8000, 6875, }, | ||
1634 | { 8125, 7000, }, | ||
1635 | { 8250, 7125, }, | ||
1636 | { 8375, 7250, }, | ||
1637 | { 8500, 7375, }, | ||
1638 | { 8625, 7500, }, | ||
1639 | { 8750, 7625, }, | ||
1640 | { 8875, 7750, }, | ||
1641 | { 9000, 7875, }, | ||
1642 | { 9125, 8000, }, | ||
1643 | { 9250, 8125, }, | ||
1644 | { 9375, 8250, }, | ||
1645 | { 9500, 8375, }, | ||
1646 | { 9625, 8500, }, | ||
1647 | { 9750, 8625, }, | ||
1648 | { 9875, 8750, }, | ||
1649 | { 10000, 8875, }, | ||
1650 | { 10125, 9000, }, | ||
1651 | { 10250, 9125, }, | ||
1652 | { 10375, 9250, }, | ||
1653 | { 10500, 9375, }, | ||
1654 | { 10625, 9500, }, | ||
1655 | { 10750, 9625, }, | ||
1656 | { 10875, 9750, }, | ||
1657 | { 11000, 9875, }, | ||
1658 | { 11125, 10000, }, | ||
1659 | { 11250, 10125, }, | ||
1660 | { 11375, 10250, }, | ||
1661 | { 11500, 10375, }, | ||
1662 | { 11625, 10500, }, | ||
1663 | { 11750, 10625, }, | ||
1664 | { 11875, 10750, }, | ||
1665 | { 12000, 10875, }, | ||
1666 | { 12125, 11000, }, | ||
1667 | { 12250, 11125, }, | ||
1668 | { 12375, 11250, }, | ||
1669 | { 12500, 11375, }, | ||
1670 | { 12625, 11500, }, | ||
1671 | { 12750, 11625, }, | ||
1672 | { 12875, 11750, }, | ||
1673 | { 13000, 11875, }, | ||
1674 | { 13125, 12000, }, | ||
1675 | { 13250, 12125, }, | ||
1676 | { 13375, 12250, }, | ||
1677 | { 13500, 12375, }, | ||
1678 | { 13625, 12500, }, | ||
1679 | { 13750, 12625, }, | ||
1680 | { 13875, 12750, }, | ||
1681 | { 14000, 12875, }, | ||
1682 | { 14125, 13000, }, | ||
1683 | { 14250, 13125, }, | ||
1684 | { 14375, 13250, }, | ||
1685 | { 14500, 13375, }, | ||
1686 | { 14625, 13500, }, | ||
1687 | { 14750, 13625, }, | ||
1688 | { 14875, 13750, }, | ||
1689 | { 15000, 13875, }, | ||
1690 | { 15125, 14000, }, | ||
1691 | { 15250, 14125, }, | ||
1692 | { 15375, 14250, }, | ||
1693 | { 15500, 14375, }, | ||
1694 | { 15625, 14500, }, | ||
1695 | { 15750, 14625, }, | ||
1696 | { 15875, 14750, }, | ||
1697 | { 16000, 14875, }, | ||
1698 | { 16125, 15000, }, | ||
1699 | }; | ||
1700 | if (dev_priv->info->is_mobile) | ||
1701 | return v_table[pxvid].vm; | ||
1702 | else | ||
1703 | return v_table[pxvid].vd; | ||
1704 | } | ||
1705 | |||
1706 | void i915_update_gfx_val(struct drm_i915_private *dev_priv) | ||
1707 | { | ||
1708 | struct timespec now, diff1; | ||
1709 | u64 diff; | ||
1710 | unsigned long diffms; | ||
1711 | u32 count; | ||
1712 | |||
1713 | if (dev_priv->info->gen != 5) | ||
1714 | return; | ||
1715 | |||
1716 | getrawmonotonic(&now); | ||
1717 | diff1 = timespec_sub(now, dev_priv->last_time2); | ||
1718 | |||
1719 | /* Don't divide by 0 */ | ||
1720 | diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; | ||
1721 | if (!diffms) | ||
1722 | return; | ||
1723 | |||
1724 | count = I915_READ(GFXEC); | ||
1725 | |||
1726 | if (count < dev_priv->last_count2) { | ||
1727 | diff = ~0UL - dev_priv->last_count2; | ||
1728 | diff += count; | ||
1729 | } else { | ||
1730 | diff = count - dev_priv->last_count2; | ||
1731 | } | ||
1732 | |||
1733 | dev_priv->last_count2 = count; | ||
1734 | dev_priv->last_time2 = now; | ||
1735 | |||
1736 | /* More magic constants... */ | ||
1737 | diff = diff * 1181; | ||
1738 | diff = div_u64(diff, diffms * 10); | ||
1739 | dev_priv->gfx_power = diff; | ||
1740 | } | ||
1741 | |||
1742 | unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) | ||
1743 | { | ||
1744 | unsigned long t, corr, state1, corr2, state2; | ||
1745 | u32 pxvid, ext_v; | ||
1746 | |||
1747 | pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); | ||
1748 | pxvid = (pxvid >> 24) & 0x7f; | ||
1749 | ext_v = pvid_to_extvid(dev_priv, pxvid); | ||
1750 | |||
1751 | state1 = ext_v; | ||
1752 | |||
1753 | t = i915_mch_val(dev_priv); | ||
1754 | |||
1755 | /* Revel in the empirically derived constants */ | ||
1756 | |||
1757 | /* Correction factor in 1/100000 units */ | ||
1758 | if (t > 80) | ||
1759 | corr = ((t * 2349) + 135940); | ||
1760 | else if (t >= 50) | ||
1761 | corr = ((t * 964) + 29317); | ||
1762 | else /* < 50 */ | ||
1763 | corr = ((t * 301) + 1004); | ||
1764 | |||
1765 | corr = corr * ((150142 * state1) / 10000 - 78642); | ||
1766 | corr /= 100000; | ||
1767 | corr2 = (corr * dev_priv->corr); | ||
1768 | |||
1769 | state2 = (corr2 * state1) / 10000; | ||
1770 | state2 /= 100; /* convert to mW */ | ||
1771 | |||
1772 | i915_update_gfx_val(dev_priv); | ||
1773 | |||
1774 | return dev_priv->gfx_power + state2; | ||
1775 | } | ||
1776 | |||
1777 | /* Global for IPS driver to get at the current i915 device */ | ||
1778 | static struct drm_i915_private *i915_mch_dev; | ||
1779 | /* | ||
1780 | * Lock protecting IPS related data structures | ||
1781 | * - i915_mch_dev | ||
1782 | * - dev_priv->max_delay | ||
1783 | * - dev_priv->min_delay | ||
1784 | * - dev_priv->fmax | ||
1785 | * - dev_priv->gpu_busy | ||
1786 | */ | ||
1787 | static DEFINE_SPINLOCK(mchdev_lock); | ||
1788 | |||
1789 | /** | ||
1790 | * i915_read_mch_val - return value for IPS use | ||
1791 | * | ||
1792 | * Calculate and return a value for the IPS driver to use when deciding whether | ||
1793 | * we have thermal and power headroom to increase CPU or GPU power budget. | ||
1794 | */ | ||
1795 | unsigned long i915_read_mch_val(void) | ||
1796 | { | ||
1797 | struct drm_i915_private *dev_priv; | ||
1798 | unsigned long chipset_val, graphics_val, ret = 0; | ||
1799 | |||
1800 | spin_lock(&mchdev_lock); | ||
1801 | if (!i915_mch_dev) | ||
1802 | goto out_unlock; | ||
1803 | dev_priv = i915_mch_dev; | ||
1804 | |||
1805 | chipset_val = i915_chipset_val(dev_priv); | ||
1806 | graphics_val = i915_gfx_val(dev_priv); | ||
1807 | |||
1808 | ret = chipset_val + graphics_val; | ||
1809 | |||
1810 | out_unlock: | ||
1811 | spin_unlock(&mchdev_lock); | ||
1812 | |||
1813 | return ret; | ||
1814 | } | ||
1815 | EXPORT_SYMBOL_GPL(i915_read_mch_val); | ||
1816 | |||
1817 | /** | ||
1818 | * i915_gpu_raise - raise GPU frequency limit | ||
1819 | * | ||
1820 | * Raise the limit; IPS indicates we have thermal headroom. | ||
1821 | */ | ||
1822 | bool i915_gpu_raise(void) | ||
1823 | { | ||
1824 | struct drm_i915_private *dev_priv; | ||
1825 | bool ret = true; | ||
1826 | |||
1827 | spin_lock(&mchdev_lock); | ||
1828 | if (!i915_mch_dev) { | ||
1829 | ret = false; | ||
1830 | goto out_unlock; | ||
1831 | } | ||
1832 | dev_priv = i915_mch_dev; | ||
1833 | |||
1834 | if (dev_priv->max_delay > dev_priv->fmax) | ||
1835 | dev_priv->max_delay--; | ||
1836 | |||
1837 | out_unlock: | ||
1838 | spin_unlock(&mchdev_lock); | ||
1839 | |||
1840 | return ret; | ||
1841 | } | ||
1842 | EXPORT_SYMBOL_GPL(i915_gpu_raise); | ||
1843 | |||
1844 | /** | ||
1845 | * i915_gpu_lower - lower GPU frequency limit | ||
1846 | * | ||
1847 | * IPS indicates we're close to a thermal limit, so throttle back the GPU | ||
1848 | * frequency maximum. | ||
1849 | */ | ||
1850 | bool i915_gpu_lower(void) | ||
1851 | { | ||
1852 | struct drm_i915_private *dev_priv; | ||
1853 | bool ret = true; | ||
1854 | |||
1855 | spin_lock(&mchdev_lock); | ||
1856 | if (!i915_mch_dev) { | ||
1857 | ret = false; | ||
1858 | goto out_unlock; | ||
1859 | } | ||
1860 | dev_priv = i915_mch_dev; | ||
1861 | |||
1862 | if (dev_priv->max_delay < dev_priv->min_delay) | ||
1863 | dev_priv->max_delay++; | ||
1864 | |||
1865 | out_unlock: | ||
1866 | spin_unlock(&mchdev_lock); | ||
1867 | |||
1868 | return ret; | ||
1869 | } | ||
1870 | EXPORT_SYMBOL_GPL(i915_gpu_lower); | ||
1871 | |||
1872 | /** | ||
1873 | * i915_gpu_busy - indicate GPU business to IPS | ||
1874 | * | ||
1875 | * Tell the IPS driver whether or not the GPU is busy. | ||
1876 | */ | ||
1877 | bool i915_gpu_busy(void) | ||
1878 | { | ||
1879 | struct drm_i915_private *dev_priv; | ||
1880 | bool ret = false; | ||
1881 | |||
1882 | spin_lock(&mchdev_lock); | ||
1883 | if (!i915_mch_dev) | ||
1884 | goto out_unlock; | ||
1885 | dev_priv = i915_mch_dev; | ||
1886 | |||
1887 | ret = dev_priv->busy; | ||
1888 | |||
1889 | out_unlock: | ||
1890 | spin_unlock(&mchdev_lock); | ||
1891 | |||
1892 | return ret; | ||
1893 | } | ||
1894 | EXPORT_SYMBOL_GPL(i915_gpu_busy); | ||
1895 | |||
1896 | /** | ||
1897 | * i915_gpu_turbo_disable - disable graphics turbo | ||
1898 | * | ||
1899 | * Disable graphics turbo by resetting the max frequency and setting the | ||
1900 | * current frequency to the default. | ||
1901 | */ | ||
1902 | bool i915_gpu_turbo_disable(void) | ||
1903 | { | ||
1904 | struct drm_i915_private *dev_priv; | ||
1905 | bool ret = true; | ||
1906 | |||
1907 | spin_lock(&mchdev_lock); | ||
1908 | if (!i915_mch_dev) { | ||
1909 | ret = false; | ||
1910 | goto out_unlock; | ||
1911 | } | ||
1912 | dev_priv = i915_mch_dev; | ||
1913 | |||
1914 | dev_priv->max_delay = dev_priv->fstart; | ||
1915 | |||
1916 | if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) | ||
1917 | ret = false; | ||
1918 | |||
1919 | out_unlock: | ||
1920 | spin_unlock(&mchdev_lock); | ||
1921 | |||
1922 | return ret; | ||
1923 | } | ||
1924 | EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); | ||
1925 | |||
1926 | /** | ||
1927 | * Tells the intel_ips driver that the i915 driver is now loaded, if | ||
1928 | * IPS got loaded first. | ||
1929 | * | ||
1930 | * This awkward dance is so that neither module has to depend on the | ||
1931 | * other in order for IPS to do the appropriate communication of | ||
1932 | * GPU turbo limits to i915. | ||
1933 | */ | ||
1934 | static void | ||
1935 | ips_ping_for_i915_load(void) | ||
1936 | { | ||
1937 | void (*link)(void); | ||
1938 | |||
1939 | link = symbol_get(ips_link_to_i915_driver); | ||
1940 | if (link) { | ||
1941 | link(); | ||
1942 | symbol_put(ips_link_to_i915_driver); | ||
1943 | } | ||
1944 | } | ||
1945 | |||
1946 | static void | 1482 | static void |
1947 | i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base, | 1483 | i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base, |
1948 | unsigned long size) | 1484 | unsigned long size) |
@@ -2152,14 +1688,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
2152 | setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, | 1688 | setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, |
2153 | (unsigned long) dev); | 1689 | (unsigned long) dev); |
2154 | 1690 | ||
2155 | if (IS_GEN5(dev)) { | 1691 | if (IS_GEN5(dev)) |
2156 | spin_lock(&mchdev_lock); | 1692 | intel_gpu_ips_init(dev_priv); |
2157 | i915_mch_dev = dev_priv; | ||
2158 | dev_priv->mchdev_lock = &mchdev_lock; | ||
2159 | spin_unlock(&mchdev_lock); | ||
2160 | |||
2161 | ips_ping_for_i915_load(); | ||
2162 | } | ||
2163 | 1693 | ||
2164 | return 0; | 1694 | return 0; |
2165 | 1695 | ||
@@ -2194,9 +1724,7 @@ int i915_driver_unload(struct drm_device *dev) | |||
2194 | struct drm_i915_private *dev_priv = dev->dev_private; | 1724 | struct drm_i915_private *dev_priv = dev->dev_private; |
2195 | int ret; | 1725 | int ret; |
2196 | 1726 | ||
2197 | spin_lock(&mchdev_lock); | 1727 | intel_gpu_ips_teardown(); |
2198 | i915_mch_dev = NULL; | ||
2199 | spin_unlock(&mchdev_lock); | ||
2200 | 1728 | ||
2201 | i915_teardown_sysfs(dev); | 1729 | i915_teardown_sysfs(dev); |
2202 | 1730 | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4b7ec449d3cc..f4f1e8bba535 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -462,5 +462,8 @@ extern void intel_init_pm(struct drm_device *dev); | |||
462 | extern bool intel_fbc_enabled(struct drm_device *dev); | 462 | extern bool intel_fbc_enabled(struct drm_device *dev); |
463 | extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); | 463 | extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); |
464 | extern void intel_update_fbc(struct drm_device *dev); | 464 | extern void intel_update_fbc(struct drm_device *dev); |
465 | /* IPS */ | ||
466 | extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); | ||
467 | extern void intel_gpu_ips_teardown(void); | ||
465 | 468 | ||
466 | #endif /* __INTEL_DRV_H__ */ | 469 | #endif /* __INTEL_DRV_H__ */ |
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0a3699908fdf..e0f016c24dce 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/cpufreq.h> | 28 | #include <linux/cpufreq.h> |
29 | #include "i915_drv.h" | 29 | #include "i915_drv.h" |
30 | #include "intel_drv.h" | 30 | #include "intel_drv.h" |
31 | #include "../../../platform/x86/intel_ips.h" | ||
32 | #include <linux/module.h> | ||
31 | 33 | ||
32 | /* FBC, or Frame Buffer Compression, is a technique employed to compress the | 34 | /* FBC, or Frame Buffer Compression, is a technique employed to compress the |
33 | * framebuffer contents in-memory, aiming at reducing the required bandwidth | 35 | * framebuffer contents in-memory, aiming at reducing the required bandwidth |
@@ -2508,6 +2510,485 @@ static unsigned long intel_pxfreq(u32 vidfreq) | |||
2508 | return freq; | 2510 | return freq; |
2509 | } | 2511 | } |
2510 | 2512 | ||
2513 | static const struct cparams { | ||
2514 | u16 i; | ||
2515 | u16 t; | ||
2516 | u16 m; | ||
2517 | u16 c; | ||
2518 | } cparams[] = { | ||
2519 | { 1, 1333, 301, 28664 }, | ||
2520 | { 1, 1066, 294, 24460 }, | ||
2521 | { 1, 800, 294, 25192 }, | ||
2522 | { 0, 1333, 276, 27605 }, | ||
2523 | { 0, 1066, 276, 27605 }, | ||
2524 | { 0, 800, 231, 23784 }, | ||
2525 | }; | ||
2526 | |||
2527 | unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) | ||
2528 | { | ||
2529 | u64 total_count, diff, ret; | ||
2530 | u32 count1, count2, count3, m = 0, c = 0; | ||
2531 | unsigned long now = jiffies_to_msecs(jiffies), diff1; | ||
2532 | int i; | ||
2533 | |||
2534 | diff1 = now - dev_priv->last_time1; | ||
2535 | |||
2536 | /* Prevent division-by-zero if we are asking too fast. | ||
2537 | * Also, we don't get interesting results if we are polling | ||
2538 | * faster than once in 10ms, so just return the saved value | ||
2539 | * in such cases. | ||
2540 | */ | ||
2541 | if (diff1 <= 10) | ||
2542 | return dev_priv->chipset_power; | ||
2543 | |||
2544 | count1 = I915_READ(DMIEC); | ||
2545 | count2 = I915_READ(DDREC); | ||
2546 | count3 = I915_READ(CSIEC); | ||
2547 | |||
2548 | total_count = count1 + count2 + count3; | ||
2549 | |||
2550 | /* FIXME: handle per-counter overflow */ | ||
2551 | if (total_count < dev_priv->last_count1) { | ||
2552 | diff = ~0UL - dev_priv->last_count1; | ||
2553 | diff += total_count; | ||
2554 | } else { | ||
2555 | diff = total_count - dev_priv->last_count1; | ||
2556 | } | ||
2557 | |||
2558 | for (i = 0; i < ARRAY_SIZE(cparams); i++) { | ||
2559 | if (cparams[i].i == dev_priv->c_m && | ||
2560 | cparams[i].t == dev_priv->r_t) { | ||
2561 | m = cparams[i].m; | ||
2562 | c = cparams[i].c; | ||
2563 | break; | ||
2564 | } | ||
2565 | } | ||
2566 | |||
2567 | diff = div_u64(diff, diff1); | ||
2568 | ret = ((m * diff) + c); | ||
2569 | ret = div_u64(ret, 10); | ||
2570 | |||
2571 | dev_priv->last_count1 = total_count; | ||
2572 | dev_priv->last_time1 = now; | ||
2573 | |||
2574 | dev_priv->chipset_power = ret; | ||
2575 | |||
2576 | return ret; | ||
2577 | } | ||
2578 | |||
2579 | unsigned long i915_mch_val(struct drm_i915_private *dev_priv) | ||
2580 | { | ||
2581 | unsigned long m, x, b; | ||
2582 | u32 tsfs; | ||
2583 | |||
2584 | tsfs = I915_READ(TSFS); | ||
2585 | |||
2586 | m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT); | ||
2587 | x = I915_READ8(TR1); | ||
2588 | |||
2589 | b = tsfs & TSFS_INTR_MASK; | ||
2590 | |||
2591 | return ((m * x) / 127) - b; | ||
2592 | } | ||
2593 | |||
2594 | static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid) | ||
2595 | { | ||
2596 | static const struct v_table { | ||
2597 | u16 vd; /* in .1 mil */ | ||
2598 | u16 vm; /* in .1 mil */ | ||
2599 | } v_table[] = { | ||
2600 | { 0, 0, }, | ||
2601 | { 375, 0, }, | ||
2602 | { 500, 0, }, | ||
2603 | { 625, 0, }, | ||
2604 | { 750, 0, }, | ||
2605 | { 875, 0, }, | ||
2606 | { 1000, 0, }, | ||
2607 | { 1125, 0, }, | ||
2608 | { 4125, 3000, }, | ||
2609 | { 4125, 3000, }, | ||
2610 | { 4125, 3000, }, | ||
2611 | { 4125, 3000, }, | ||
2612 | { 4125, 3000, }, | ||
2613 | { 4125, 3000, }, | ||
2614 | { 4125, 3000, }, | ||
2615 | { 4125, 3000, }, | ||
2616 | { 4125, 3000, }, | ||
2617 | { 4125, 3000, }, | ||
2618 | { 4125, 3000, }, | ||
2619 | { 4125, 3000, }, | ||
2620 | { 4125, 3000, }, | ||
2621 | { 4125, 3000, }, | ||
2622 | { 4125, 3000, }, | ||
2623 | { 4125, 3000, }, | ||
2624 | { 4125, 3000, }, | ||
2625 | { 4125, 3000, }, | ||
2626 | { 4125, 3000, }, | ||
2627 | { 4125, 3000, }, | ||
2628 | { 4125, 3000, }, | ||
2629 | { 4125, 3000, }, | ||
2630 | { 4125, 3000, }, | ||
2631 | { 4125, 3000, }, | ||
2632 | { 4250, 3125, }, | ||
2633 | { 4375, 3250, }, | ||
2634 | { 4500, 3375, }, | ||
2635 | { 4625, 3500, }, | ||
2636 | { 4750, 3625, }, | ||
2637 | { 4875, 3750, }, | ||
2638 | { 5000, 3875, }, | ||
2639 | { 5125, 4000, }, | ||
2640 | { 5250, 4125, }, | ||
2641 | { 5375, 4250, }, | ||
2642 | { 5500, 4375, }, | ||
2643 | { 5625, 4500, }, | ||
2644 | { 5750, 4625, }, | ||
2645 | { 5875, 4750, }, | ||
2646 | { 6000, 4875, }, | ||
2647 | { 6125, 5000, }, | ||
2648 | { 6250, 5125, }, | ||
2649 | { 6375, 5250, }, | ||
2650 | { 6500, 5375, }, | ||
2651 | { 6625, 5500, }, | ||
2652 | { 6750, 5625, }, | ||
2653 | { 6875, 5750, }, | ||
2654 | { 7000, 5875, }, | ||
2655 | { 7125, 6000, }, | ||
2656 | { 7250, 6125, }, | ||
2657 | { 7375, 6250, }, | ||
2658 | { 7500, 6375, }, | ||
2659 | { 7625, 6500, }, | ||
2660 | { 7750, 6625, }, | ||
2661 | { 7875, 6750, }, | ||
2662 | { 8000, 6875, }, | ||
2663 | { 8125, 7000, }, | ||
2664 | { 8250, 7125, }, | ||
2665 | { 8375, 7250, }, | ||
2666 | { 8500, 7375, }, | ||
2667 | { 8625, 7500, }, | ||
2668 | { 8750, 7625, }, | ||
2669 | { 8875, 7750, }, | ||
2670 | { 9000, 7875, }, | ||
2671 | { 9125, 8000, }, | ||
2672 | { 9250, 8125, }, | ||
2673 | { 9375, 8250, }, | ||
2674 | { 9500, 8375, }, | ||
2675 | { 9625, 8500, }, | ||
2676 | { 9750, 8625, }, | ||
2677 | { 9875, 8750, }, | ||
2678 | { 10000, 8875, }, | ||
2679 | { 10125, 9000, }, | ||
2680 | { 10250, 9125, }, | ||
2681 | { 10375, 9250, }, | ||
2682 | { 10500, 9375, }, | ||
2683 | { 10625, 9500, }, | ||
2684 | { 10750, 9625, }, | ||
2685 | { 10875, 9750, }, | ||
2686 | { 11000, 9875, }, | ||
2687 | { 11125, 10000, }, | ||
2688 | { 11250, 10125, }, | ||
2689 | { 11375, 10250, }, | ||
2690 | { 11500, 10375, }, | ||
2691 | { 11625, 10500, }, | ||
2692 | { 11750, 10625, }, | ||
2693 | { 11875, 10750, }, | ||
2694 | { 12000, 10875, }, | ||
2695 | { 12125, 11000, }, | ||
2696 | { 12250, 11125, }, | ||
2697 | { 12375, 11250, }, | ||
2698 | { 12500, 11375, }, | ||
2699 | { 12625, 11500, }, | ||
2700 | { 12750, 11625, }, | ||
2701 | { 12875, 11750, }, | ||
2702 | { 13000, 11875, }, | ||
2703 | { 13125, 12000, }, | ||
2704 | { 13250, 12125, }, | ||
2705 | { 13375, 12250, }, | ||
2706 | { 13500, 12375, }, | ||
2707 | { 13625, 12500, }, | ||
2708 | { 13750, 12625, }, | ||
2709 | { 13875, 12750, }, | ||
2710 | { 14000, 12875, }, | ||
2711 | { 14125, 13000, }, | ||
2712 | { 14250, 13125, }, | ||
2713 | { 14375, 13250, }, | ||
2714 | { 14500, 13375, }, | ||
2715 | { 14625, 13500, }, | ||
2716 | { 14750, 13625, }, | ||
2717 | { 14875, 13750, }, | ||
2718 | { 15000, 13875, }, | ||
2719 | { 15125, 14000, }, | ||
2720 | { 15250, 14125, }, | ||
2721 | { 15375, 14250, }, | ||
2722 | { 15500, 14375, }, | ||
2723 | { 15625, 14500, }, | ||
2724 | { 15750, 14625, }, | ||
2725 | { 15875, 14750, }, | ||
2726 | { 16000, 14875, }, | ||
2727 | { 16125, 15000, }, | ||
2728 | }; | ||
2729 | if (dev_priv->info->is_mobile) | ||
2730 | return v_table[pxvid].vm; | ||
2731 | else | ||
2732 | return v_table[pxvid].vd; | ||
2733 | } | ||
2734 | |||
2735 | void i915_update_gfx_val(struct drm_i915_private *dev_priv) | ||
2736 | { | ||
2737 | struct timespec now, diff1; | ||
2738 | u64 diff; | ||
2739 | unsigned long diffms; | ||
2740 | u32 count; | ||
2741 | |||
2742 | if (dev_priv->info->gen != 5) | ||
2743 | return; | ||
2744 | |||
2745 | getrawmonotonic(&now); | ||
2746 | diff1 = timespec_sub(now, dev_priv->last_time2); | ||
2747 | |||
2748 | /* Don't divide by 0 */ | ||
2749 | diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; | ||
2750 | if (!diffms) | ||
2751 | return; | ||
2752 | |||
2753 | count = I915_READ(GFXEC); | ||
2754 | |||
2755 | if (count < dev_priv->last_count2) { | ||
2756 | diff = ~0UL - dev_priv->last_count2; | ||
2757 | diff += count; | ||
2758 | } else { | ||
2759 | diff = count - dev_priv->last_count2; | ||
2760 | } | ||
2761 | |||
2762 | dev_priv->last_count2 = count; | ||
2763 | dev_priv->last_time2 = now; | ||
2764 | |||
2765 | /* More magic constants... */ | ||
2766 | diff = diff * 1181; | ||
2767 | diff = div_u64(diff, diffms * 10); | ||
2768 | dev_priv->gfx_power = diff; | ||
2769 | } | ||
2770 | |||
2771 | unsigned long i915_gfx_val(struct drm_i915_private *dev_priv) | ||
2772 | { | ||
2773 | unsigned long t, corr, state1, corr2, state2; | ||
2774 | u32 pxvid, ext_v; | ||
2775 | |||
2776 | pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4)); | ||
2777 | pxvid = (pxvid >> 24) & 0x7f; | ||
2778 | ext_v = pvid_to_extvid(dev_priv, pxvid); | ||
2779 | |||
2780 | state1 = ext_v; | ||
2781 | |||
2782 | t = i915_mch_val(dev_priv); | ||
2783 | |||
2784 | /* Revel in the empirically derived constants */ | ||
2785 | |||
2786 | /* Correction factor in 1/100000 units */ | ||
2787 | if (t > 80) | ||
2788 | corr = ((t * 2349) + 135940); | ||
2789 | else if (t >= 50) | ||
2790 | corr = ((t * 964) + 29317); | ||
2791 | else /* < 50 */ | ||
2792 | corr = ((t * 301) + 1004); | ||
2793 | |||
2794 | corr = corr * ((150142 * state1) / 10000 - 78642); | ||
2795 | corr /= 100000; | ||
2796 | corr2 = (corr * dev_priv->corr); | ||
2797 | |||
2798 | state2 = (corr2 * state1) / 10000; | ||
2799 | state2 /= 100; /* convert to mW */ | ||
2800 | |||
2801 | i915_update_gfx_val(dev_priv); | ||
2802 | |||
2803 | return dev_priv->gfx_power + state2; | ||
2804 | } | ||
2805 | |||
2806 | /* Global for IPS driver to get at the current i915 device */ | ||
2807 | static struct drm_i915_private *i915_mch_dev; | ||
2808 | /* | ||
2809 | * Lock protecting IPS related data structures | ||
2810 | * - i915_mch_dev | ||
2811 | * - dev_priv->max_delay | ||
2812 | * - dev_priv->min_delay | ||
2813 | * - dev_priv->fmax | ||
2814 | * - dev_priv->gpu_busy | ||
2815 | */ | ||
2816 | static DEFINE_SPINLOCK(mchdev_lock); | ||
2817 | |||
2818 | /** | ||
2819 | * i915_read_mch_val - return value for IPS use | ||
2820 | * | ||
2821 | * Calculate and return a value for the IPS driver to use when deciding whether | ||
2822 | * we have thermal and power headroom to increase CPU or GPU power budget. | ||
2823 | */ | ||
2824 | unsigned long i915_read_mch_val(void) | ||
2825 | { | ||
2826 | struct drm_i915_private *dev_priv; | ||
2827 | unsigned long chipset_val, graphics_val, ret = 0; | ||
2828 | |||
2829 | spin_lock(&mchdev_lock); | ||
2830 | if (!i915_mch_dev) | ||
2831 | goto out_unlock; | ||
2832 | dev_priv = i915_mch_dev; | ||
2833 | |||
2834 | chipset_val = i915_chipset_val(dev_priv); | ||
2835 | graphics_val = i915_gfx_val(dev_priv); | ||
2836 | |||
2837 | ret = chipset_val + graphics_val; | ||
2838 | |||
2839 | out_unlock: | ||
2840 | spin_unlock(&mchdev_lock); | ||
2841 | |||
2842 | return ret; | ||
2843 | } | ||
2844 | EXPORT_SYMBOL_GPL(i915_read_mch_val); | ||
2845 | |||
2846 | /** | ||
2847 | * i915_gpu_raise - raise GPU frequency limit | ||
2848 | * | ||
2849 | * Raise the limit; IPS indicates we have thermal headroom. | ||
2850 | */ | ||
2851 | bool i915_gpu_raise(void) | ||
2852 | { | ||
2853 | struct drm_i915_private *dev_priv; | ||
2854 | bool ret = true; | ||
2855 | |||
2856 | spin_lock(&mchdev_lock); | ||
2857 | if (!i915_mch_dev) { | ||
2858 | ret = false; | ||
2859 | goto out_unlock; | ||
2860 | } | ||
2861 | dev_priv = i915_mch_dev; | ||
2862 | |||
2863 | if (dev_priv->max_delay > dev_priv->fmax) | ||
2864 | dev_priv->max_delay--; | ||
2865 | |||
2866 | out_unlock: | ||
2867 | spin_unlock(&mchdev_lock); | ||
2868 | |||
2869 | return ret; | ||
2870 | } | ||
2871 | EXPORT_SYMBOL_GPL(i915_gpu_raise); | ||
2872 | |||
2873 | /** | ||
2874 | * i915_gpu_lower - lower GPU frequency limit | ||
2875 | * | ||
2876 | * IPS indicates we're close to a thermal limit, so throttle back the GPU | ||
2877 | * frequency maximum. | ||
2878 | */ | ||
2879 | bool i915_gpu_lower(void) | ||
2880 | { | ||
2881 | struct drm_i915_private *dev_priv; | ||
2882 | bool ret = true; | ||
2883 | |||
2884 | spin_lock(&mchdev_lock); | ||
2885 | if (!i915_mch_dev) { | ||
2886 | ret = false; | ||
2887 | goto out_unlock; | ||
2888 | } | ||
2889 | dev_priv = i915_mch_dev; | ||
2890 | |||
2891 | if (dev_priv->max_delay < dev_priv->min_delay) | ||
2892 | dev_priv->max_delay++; | ||
2893 | |||
2894 | out_unlock: | ||
2895 | spin_unlock(&mchdev_lock); | ||
2896 | |||
2897 | return ret; | ||
2898 | } | ||
2899 | EXPORT_SYMBOL_GPL(i915_gpu_lower); | ||
2900 | |||
2901 | /** | ||
2902 | * i915_gpu_busy - indicate GPU business to IPS | ||
2903 | * | ||
2904 | * Tell the IPS driver whether or not the GPU is busy. | ||
2905 | */ | ||
2906 | bool i915_gpu_busy(void) | ||
2907 | { | ||
2908 | struct drm_i915_private *dev_priv; | ||
2909 | bool ret = false; | ||
2910 | |||
2911 | spin_lock(&mchdev_lock); | ||
2912 | if (!i915_mch_dev) | ||
2913 | goto out_unlock; | ||
2914 | dev_priv = i915_mch_dev; | ||
2915 | |||
2916 | ret = dev_priv->busy; | ||
2917 | |||
2918 | out_unlock: | ||
2919 | spin_unlock(&mchdev_lock); | ||
2920 | |||
2921 | return ret; | ||
2922 | } | ||
2923 | EXPORT_SYMBOL_GPL(i915_gpu_busy); | ||
2924 | |||
2925 | /** | ||
2926 | * i915_gpu_turbo_disable - disable graphics turbo | ||
2927 | * | ||
2928 | * Disable graphics turbo by resetting the max frequency and setting the | ||
2929 | * current frequency to the default. | ||
2930 | */ | ||
2931 | bool i915_gpu_turbo_disable(void) | ||
2932 | { | ||
2933 | struct drm_i915_private *dev_priv; | ||
2934 | bool ret = true; | ||
2935 | |||
2936 | spin_lock(&mchdev_lock); | ||
2937 | if (!i915_mch_dev) { | ||
2938 | ret = false; | ||
2939 | goto out_unlock; | ||
2940 | } | ||
2941 | dev_priv = i915_mch_dev; | ||
2942 | |||
2943 | dev_priv->max_delay = dev_priv->fstart; | ||
2944 | |||
2945 | if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart)) | ||
2946 | ret = false; | ||
2947 | |||
2948 | out_unlock: | ||
2949 | spin_unlock(&mchdev_lock); | ||
2950 | |||
2951 | return ret; | ||
2952 | } | ||
2953 | EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); | ||
2954 | |||
2955 | /** | ||
2956 | * Tells the intel_ips driver that the i915 driver is now loaded, if | ||
2957 | * IPS got loaded first. | ||
2958 | * | ||
2959 | * This awkward dance is so that neither module has to depend on the | ||
2960 | * other in order for IPS to do the appropriate communication of | ||
2961 | * GPU turbo limits to i915. | ||
2962 | */ | ||
2963 | static void | ||
2964 | ips_ping_for_i915_load(void) | ||
2965 | { | ||
2966 | void (*link)(void); | ||
2967 | |||
2968 | link = symbol_get(ips_link_to_i915_driver); | ||
2969 | if (link) { | ||
2970 | link(); | ||
2971 | symbol_put(ips_link_to_i915_driver); | ||
2972 | } | ||
2973 | } | ||
2974 | |||
2975 | void intel_gpu_ips_init(struct drm_i915_private *dev_priv) | ||
2976 | { | ||
2977 | spin_lock(&mchdev_lock); | ||
2978 | i915_mch_dev = dev_priv; | ||
2979 | dev_priv->mchdev_lock = &mchdev_lock; | ||
2980 | spin_unlock(&mchdev_lock); | ||
2981 | |||
2982 | ips_ping_for_i915_load(); | ||
2983 | } | ||
2984 | |||
2985 | void intel_gpu_ips_teardown(void) | ||
2986 | { | ||
2987 | spin_lock(&mchdev_lock); | ||
2988 | i915_mch_dev = NULL; | ||
2989 | spin_unlock(&mchdev_lock); | ||
2990 | } | ||
2991 | |||
2511 | void intel_init_emon(struct drm_device *dev) | 2992 | void intel_init_emon(struct drm_device *dev) |
2512 | { | 2993 | { |
2513 | struct drm_i915_private *dev_priv = dev->dev_private; | 2994 | struct drm_i915_private *dev_priv = dev->dev_private; |