Revision 85a00d9bbfb4704fbf368944b1cb9fed8f1598c5 authored by Peter Jones on 22 September 2010, 20:05:04 UTC, committed by Linus Torvalds on 23 September 2010, 00:22:39 UTC
Some Apple machines have identical DMI data but different memory
configurations for the video.  Given that, check that the address in our
table is actually within the range of a PCI BAR on a VGA device in the
machine.

This also fixes up the return value from set_system(), which has always
been wrong, but never resulted in bad behavior since there's only ever
been one matching entry in the dmi table.

The patch

1) stops people's machines from crashing when we get their display wrong,
   which seems to be unfortunately inevitable,

2) allows us to support identical dmi data with differing video memory
   configurations

This also adds me as the efifb maintainer, since I've effectively been
acting as such for quite some time.

Signed-off-by: Peter Jones <pjones@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a0c42ba
Raw File
scsi_pm.c
/*
 *	scsi_pm.c	Copyright (C) 2010 Alan Stern
 *
 *	SCSI dynamic Power Management
 *		Initial version: Alan Stern <stern@rowland.harvard.edu>
 */

#include <linux/pm_runtime.h>

#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_host.h>

#include "scsi_priv.h"

static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg)
{
	struct device_driver *drv;
	int err;

	err = scsi_device_quiesce(to_scsi_device(dev));
	if (err == 0) {
		drv = dev->driver;
		if (drv && drv->suspend)
			err = drv->suspend(dev, msg);
	}
	dev_dbg(dev, "scsi suspend: %d\n", err);
	return err;
}

static int scsi_dev_type_resume(struct device *dev)
{
	struct device_driver *drv;
	int err = 0;

	drv = dev->driver;
	if (drv && drv->resume)
		err = drv->resume(dev);
	scsi_device_resume(to_scsi_device(dev));
	dev_dbg(dev, "scsi resume: %d\n", err);
	return err;
}

#ifdef CONFIG_PM_SLEEP

static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg)
{
	int err = 0;

	if (scsi_is_sdev_device(dev))
		err = scsi_dev_type_suspend(dev, msg);
	return err;
}

static int scsi_bus_resume_common(struct device *dev)
{
	int err = 0;

	if (scsi_is_sdev_device(dev))
		err = scsi_dev_type_resume(dev);

	if (err == 0) {
		pm_runtime_disable(dev);
		pm_runtime_set_active(dev);
		pm_runtime_enable(dev);
	}
	return err;
}

static int scsi_bus_suspend(struct device *dev)
{
	return scsi_bus_suspend_common(dev, PMSG_SUSPEND);
}

static int scsi_bus_freeze(struct device *dev)
{
	return scsi_bus_suspend_common(dev, PMSG_FREEZE);
}

static int scsi_bus_poweroff(struct device *dev)
{
	return scsi_bus_suspend_common(dev, PMSG_HIBERNATE);
}

#else /* CONFIG_PM_SLEEP */

#define scsi_bus_resume_common		NULL
#define scsi_bus_suspend		NULL
#define scsi_bus_freeze			NULL
#define scsi_bus_poweroff		NULL

#endif /* CONFIG_PM_SLEEP */

#ifdef CONFIG_PM_RUNTIME

static int scsi_runtime_suspend(struct device *dev)
{
	int err = 0;

	dev_dbg(dev, "scsi_runtime_suspend\n");
	if (scsi_is_sdev_device(dev)) {
		err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND);
		if (err == -EAGAIN)
			pm_schedule_suspend(dev, jiffies_to_msecs(
				round_jiffies_up_relative(HZ/10)));
	}

	/* Insert hooks here for targets, hosts, and transport classes */

	return err;
}

static int scsi_runtime_resume(struct device *dev)
{
	int err = 0;

	dev_dbg(dev, "scsi_runtime_resume\n");
	if (scsi_is_sdev_device(dev))
		err = scsi_dev_type_resume(dev);

	/* Insert hooks here for targets, hosts, and transport classes */

	return err;
}

static int scsi_runtime_idle(struct device *dev)
{
	int err;

	dev_dbg(dev, "scsi_runtime_idle\n");

	/* Insert hooks here for targets, hosts, and transport classes */

	if (scsi_is_sdev_device(dev))
		err = pm_schedule_suspend(dev, 100);
	else
		err = pm_runtime_suspend(dev);
	return err;
}

int scsi_autopm_get_device(struct scsi_device *sdev)
{
	int	err;

	err = pm_runtime_get_sync(&sdev->sdev_gendev);
	if (err < 0)
		pm_runtime_put_sync(&sdev->sdev_gendev);
	else if (err > 0)
		err = 0;
	return err;
}
EXPORT_SYMBOL_GPL(scsi_autopm_get_device);

void scsi_autopm_put_device(struct scsi_device *sdev)
{
	pm_runtime_put_sync(&sdev->sdev_gendev);
}
EXPORT_SYMBOL_GPL(scsi_autopm_put_device);

void scsi_autopm_get_target(struct scsi_target *starget)
{
	pm_runtime_get_sync(&starget->dev);
}

void scsi_autopm_put_target(struct scsi_target *starget)
{
	pm_runtime_put_sync(&starget->dev);
}

int scsi_autopm_get_host(struct Scsi_Host *shost)
{
	int	err;

	err = pm_runtime_get_sync(&shost->shost_gendev);
	if (err < 0)
		pm_runtime_put_sync(&shost->shost_gendev);
	else if (err > 0)
		err = 0;
	return err;
}

void scsi_autopm_put_host(struct Scsi_Host *shost)
{
	pm_runtime_put_sync(&shost->shost_gendev);
}

#else

#define scsi_runtime_suspend	NULL
#define scsi_runtime_resume	NULL
#define scsi_runtime_idle	NULL

#endif /* CONFIG_PM_RUNTIME */

const struct dev_pm_ops scsi_bus_pm_ops = {
	.suspend =		scsi_bus_suspend,
	.resume =		scsi_bus_resume_common,
	.freeze =		scsi_bus_freeze,
	.thaw =			scsi_bus_resume_common,
	.poweroff =		scsi_bus_poweroff,
	.restore =		scsi_bus_resume_common,
	.runtime_suspend =	scsi_runtime_suspend,
	.runtime_resume =	scsi_runtime_resume,
	.runtime_idle =		scsi_runtime_idle,
};
back to top