cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

power.c (9169B)


      1/**************************************************************************
      2 * Copyright (c) 2009-2011, Intel Corporation.
      3 * All Rights Reserved.
      4 *
      5 * Permission is hereby granted, free of charge, to any person obtaining a
      6 * copy of this software and associated documentation files (the "Software"),
      7 * to deal in the Software without restriction, including without limitation
      8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9 * and/or sell copies of the Software, and to permit persons to whom the
     10 * Software is furnished to do so, subject to the following conditions:
     11 *
     12 * The above copyright notice and this permission notice (including the next
     13 * paragraph) shall be included in all copies or substantial portions of the
     14 * Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22 * SOFTWARE.
     23 *
     24 * Authors:
     25 *    Benjamin Defnet <benjamin.r.defnet@intel.com>
     26 *    Rajesh Poornachandran <rajesh.poornachandran@intel.com>
     27 * Massively reworked
     28 *    Alan Cox <alan@linux.intel.com>
     29 */
     30
     31#include "gem.h"
     32#include "power.h"
     33#include "psb_drv.h"
     34#include "psb_reg.h"
     35#include "psb_intel_reg.h"
     36#include "psb_irq.h"
     37#include <linux/mutex.h>
     38#include <linux/pm_runtime.h>
     39
     40static struct mutex power_mutex;	/* Serialize power ops */
     41static DEFINE_SPINLOCK(power_ctrl_lock);	/* Serialize power claim */
     42
     43/**
     44 *	gma_power_init		-	initialise power manager
     45 *	@dev: our device
     46 *
     47 *	Set up for power management tracking of our hardware.
     48 */
     49void gma_power_init(struct drm_device *dev)
     50{
     51	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
     52
     53	/* FIXME: Move APM/OSPM base into relevant device code */
     54	dev_priv->apm_base = dev_priv->apm_reg & 0xffff;
     55	dev_priv->ospm_base &= 0xffff;
     56
     57	dev_priv->display_power = true;	/* We start active */
     58	dev_priv->display_count = 0;	/* Currently no users */
     59	dev_priv->suspended = false;	/* And not suspended */
     60	mutex_init(&power_mutex);
     61
     62	if (dev_priv->ops->init_pm)
     63		dev_priv->ops->init_pm(dev);
     64}
     65
     66/**
     67 *	gma_power_uninit	-	end power manager
     68 *	@dev: device to end for
     69 *
     70 *	Undo the effects of gma_power_init
     71 */
     72void gma_power_uninit(struct drm_device *dev)
     73{
     74	pm_runtime_disable(dev->dev);
     75	pm_runtime_set_suspended(dev->dev);
     76}
     77
     78/**
     79 *	gma_suspend_display	-	suspend the display logic
     80 *	@dev: our DRM device
     81 *
     82 *	Suspend the display logic of the graphics interface
     83 */
     84static void gma_suspend_display(struct drm_device *dev)
     85{
     86	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
     87
     88	if (dev_priv->suspended)
     89		return;
     90	dev_priv->ops->save_regs(dev);
     91	dev_priv->ops->power_down(dev);
     92	dev_priv->display_power = false;
     93}
     94
     95/**
     96 *	gma_resume_display	-	resume display side logic
     97 *	@pdev: PCI device
     98 *
     99 *	Resume the display hardware restoring state and enabling
    100 *	as necessary.
    101 */
    102static void gma_resume_display(struct pci_dev *pdev)
    103{
    104	struct drm_device *dev = pci_get_drvdata(pdev);
    105	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    106
    107	/* turn on the display power island */
    108	dev_priv->ops->power_up(dev);
    109	dev_priv->suspended = false;
    110	dev_priv->display_power = true;
    111
    112	PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL);
    113	pci_write_config_word(pdev, PSB_GMCH_CTRL,
    114			dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED);
    115
    116	/* Rebuild our GTT mappings */
    117	psb_gtt_resume(dev);
    118	psb_gem_mm_resume(dev);
    119	dev_priv->ops->restore_regs(dev);
    120}
    121
    122/**
    123 *	gma_suspend_pci		-	suspend PCI side
    124 *	@pdev: PCI device
    125 *
    126 *	Perform the suspend processing on our PCI device state
    127 */
    128static void gma_suspend_pci(struct pci_dev *pdev)
    129{
    130	struct drm_device *dev = pci_get_drvdata(pdev);
    131	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    132	int bsm, vbt;
    133
    134	if (dev_priv->suspended)
    135		return;
    136
    137	pci_save_state(pdev);
    138	pci_read_config_dword(pdev, 0x5C, &bsm);
    139	dev_priv->regs.saveBSM = bsm;
    140	pci_read_config_dword(pdev, 0xFC, &vbt);
    141	dev_priv->regs.saveVBT = vbt;
    142	pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
    143	pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
    144
    145	pci_disable_device(pdev);
    146	pci_set_power_state(pdev, PCI_D3hot);
    147
    148	dev_priv->suspended = true;
    149}
    150
    151/**
    152 *	gma_resume_pci		-	resume helper
    153 *	@pdev: our PCI device
    154 *
    155 *	Perform the resume processing on our PCI device state - rewrite
    156 *	register state and re-enable the PCI device
    157 */
    158static bool gma_resume_pci(struct pci_dev *pdev)
    159{
    160	struct drm_device *dev = pci_get_drvdata(pdev);
    161	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    162	int ret;
    163
    164	if (!dev_priv->suspended)
    165		return true;
    166
    167	pci_set_power_state(pdev, PCI_D0);
    168	pci_restore_state(pdev);
    169	pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
    170	pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
    171	/* restoring MSI address and data in PCIx space */
    172	pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
    173	pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
    174	ret = pci_enable_device(pdev);
    175
    176	if (ret != 0)
    177		dev_err(&pdev->dev, "pci_enable failed: %d\n", ret);
    178	else
    179		dev_priv->suspended = false;
    180	return !dev_priv->suspended;
    181}
    182
    183/**
    184 *	gma_power_suspend		-	bus callback for suspend
    185 *	@_dev: our device
    186 *
    187 *	Called back by the PCI layer during a suspend of the system. We
    188 *	perform the necessary shut down steps and save enough state that
    189 *	we can undo this when resume is called.
    190 */
    191int gma_power_suspend(struct device *_dev)
    192{
    193	struct pci_dev *pdev = to_pci_dev(_dev);
    194	struct drm_device *dev = pci_get_drvdata(pdev);
    195	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    196
    197	mutex_lock(&power_mutex);
    198	if (!dev_priv->suspended) {
    199		if (dev_priv->display_count) {
    200			mutex_unlock(&power_mutex);
    201			dev_err(dev->dev, "GPU hardware busy, cannot suspend\n");
    202			return -EBUSY;
    203		}
    204		gma_irq_uninstall(dev);
    205		gma_suspend_display(dev);
    206		gma_suspend_pci(pdev);
    207	}
    208	mutex_unlock(&power_mutex);
    209	return 0;
    210}
    211
    212/**
    213 *	gma_power_resume		-	resume power
    214 *	@_dev: our device
    215 *
    216 *	Resume the PCI side of the graphics and then the displays
    217 */
    218int gma_power_resume(struct device *_dev)
    219{
    220	struct pci_dev *pdev = to_pci_dev(_dev);
    221	struct drm_device *dev = pci_get_drvdata(pdev);
    222
    223	mutex_lock(&power_mutex);
    224	gma_resume_pci(pdev);
    225	gma_resume_display(pdev);
    226	gma_irq_preinstall(dev);
    227	gma_irq_postinstall(dev);
    228	mutex_unlock(&power_mutex);
    229	return 0;
    230}
    231
    232/**
    233 *	gma_power_is_on		-	returne true if power is on
    234 *	@dev: our DRM device
    235 *
    236 *	Returns true if the display island power is on at this moment
    237 */
    238bool gma_power_is_on(struct drm_device *dev)
    239{
    240	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    241	return dev_priv->display_power;
    242}
    243
    244/**
    245 *	gma_power_begin		-	begin requiring power
    246 *	@dev: our DRM device
    247 *	@force_on: true to force power on
    248 *
    249 *	Begin an action that requires the display power island is enabled.
    250 *	We refcount the islands.
    251 */
    252bool gma_power_begin(struct drm_device *dev, bool force_on)
    253{
    254	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    255	struct pci_dev *pdev = to_pci_dev(dev->dev);
    256	int ret;
    257	unsigned long flags;
    258
    259	spin_lock_irqsave(&power_ctrl_lock, flags);
    260	/* Power already on ? */
    261	if (dev_priv->display_power) {
    262		dev_priv->display_count++;
    263		pm_runtime_get(dev->dev);
    264		spin_unlock_irqrestore(&power_ctrl_lock, flags);
    265		return true;
    266	}
    267	if (force_on == false)
    268		goto out_false;
    269
    270	/* Ok power up needed */
    271	ret = gma_resume_pci(pdev);
    272	if (ret == 0) {
    273		gma_irq_preinstall(dev);
    274		gma_irq_postinstall(dev);
    275		pm_runtime_get(dev->dev);
    276		dev_priv->display_count++;
    277		spin_unlock_irqrestore(&power_ctrl_lock, flags);
    278		return true;
    279	}
    280out_false:
    281	spin_unlock_irqrestore(&power_ctrl_lock, flags);
    282	return false;
    283}
    284
    285/**
    286 *	gma_power_end		-	end use of power
    287 *	@dev: Our DRM device
    288 *
    289 *	Indicate that one of our gma_power_begin() requested periods when
    290 *	the diplay island power is needed has completed.
    291 */
    292void gma_power_end(struct drm_device *dev)
    293{
    294	struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
    295	unsigned long flags;
    296	spin_lock_irqsave(&power_ctrl_lock, flags);
    297	dev_priv->display_count--;
    298	WARN_ON(dev_priv->display_count < 0);
    299	spin_unlock_irqrestore(&power_ctrl_lock, flags);
    300	pm_runtime_put(dev->dev);
    301}
    302
    303int psb_runtime_suspend(struct device *dev)
    304{
    305	return gma_power_suspend(dev);
    306}
    307
    308int psb_runtime_resume(struct device *dev)
    309{
    310	return gma_power_resume(dev);
    311}
    312
    313int psb_runtime_idle(struct device *dev)
    314{
    315	struct drm_device *drmdev = pci_get_drvdata(to_pci_dev(dev));
    316	struct drm_psb_private *dev_priv = to_drm_psb_private(drmdev);
    317	if (dev_priv->display_count)
    318		return 0;
    319	else
    320		return 1;
    321}
    322
    323int gma_power_thaw(struct device *_dev)
    324{
    325	return gma_power_resume(_dev);
    326}
    327
    328int gma_power_freeze(struct device *_dev)
    329{
    330	return gma_power_suspend(_dev);
    331}
    332
    333int gma_power_restore(struct device *_dev)
    334{
    335	return gma_power_resume(_dev);
    336}