Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abce00f9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'upstream-linus' of git://github.com/jgarzik/libata-dev

* 'upstream-linus' of git://github.com/jgarzik/libata-dev:
  ahci: support the STA2X11 I/O Hub
  pata_bf54x: fix BMIDE status register emulation
  ata: add ata port hibernate callbacks
  ata: update ata port's runtime status during system resume
  [SCSI] runtime resume parent for child's system-resume
  ahci: platform support for suspend/resume
  libata-core: kill duplicate statement in ata_do_set_mode()
  pata_of_platform: remove direct dependency on OF_IRQ
  SATA/PATA: convert drivers/ata/* to use module_platform_driver()
  pata_cs5536: forward port changes from cs5536
  libata-sff: use ATAPI_{COD|IO}
  ata: add ata port runtime PM callbacks
  ata: add ata port system PM callbacks
  [SCSI] sd: check runtime PM status in sd_shutdown
  [SCSI] check runtime PM status in system PM
  [SCSI] add flag to skip the runtime PM calls on the host
  ata: make ata port as parent device of scsi host
  ahci: start engine only during soft/hard resets
parents 90160371 318893e1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -820,7 +820,7 @@ config PATA_PLATFORM

config PATA_OF_PLATFORM
	tristate "OpenFirmware platform device PATA support"
	depends on PATA_PLATFORM && OF && OF_IRQ
	depends on PATA_PLATFORM && OF
	help
	  This option enables support for generic directly connected ATA
	  devices commonly found on embedded systems with OpenFirmware
+21 −5
Original line number Diff line number Diff line
@@ -52,7 +52,8 @@
#define DRV_VERSION	"3.0"

enum {
	AHCI_PCI_BAR		= 5,
	AHCI_PCI_BAR_STA2X11	= 0,
	AHCI_PCI_BAR_STANDARD	= 5,
};

enum board_ids {
@@ -375,6 +376,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
	{ PCI_VDEVICE(SI, 0x1185), board_ahci },		/* SiS 968 */
	{ PCI_VDEVICE(SI, 0x0186), board_ahci },		/* SiS 968 */

	/* ST Microelectronics */
	{ PCI_VDEVICE(STMICRO, 0xCC06), board_ahci },		/* ST ConneXt */

	/* Marvell */
	{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv },	/* 6145 */
	{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv },	/* 6121 */
@@ -622,6 +626,13 @@ static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
{
	int rc;

	/*
	 * If the device fixup already set the dma_mask to some non-standard
	 * value, don't extend it here. This happens on STA2X11, for example.
	 */
	if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32))
		return 0;

	if (using_dac &&
	    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -1026,6 +1037,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	struct ahci_host_priv *hpriv;
	struct ata_host *host;
	int n_ports, i, rc;
	int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;

	VPRINTK("ENTER\n");

@@ -1057,6 +1069,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
		dev_info(&pdev->dev,
			 "PDC42819 can only drive SATA devices with this driver\n");

	/* The Connext uses non-standard BAR */
	if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
		ahci_pci_bar = AHCI_PCI_BAR_STA2X11;

	/* acquire resources */
	rc = pcim_enable_device(pdev);
	if (rc)
@@ -1065,7 +1081,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	/* AHCI controllers often implement SFF compatible interface.
	 * Grab all PCI BARs just in case.
	 */
	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
	rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME);
	if (rc == -EBUSY)
		pcim_pin_device(pdev);
	if (rc)
@@ -1108,7 +1124,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
		pci_intx(pdev, 1);

	hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
	hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];

	/* save initial config */
	ahci_pci_save_initial_config(pdev, hpriv);
@@ -1172,8 +1188,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	for (i = 0; i < host->n_ports; i++) {
		struct ata_port *ap = host->ports[i];

		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
		ata_port_pbar_desc(ap, ahci_pci_bar, -1, "abar");
		ata_port_pbar_desc(ap, ahci_pci_bar,
				   0x100 + ap->port_no * 0x80, "port");

		/* set enclosure management message type */
+68 −0
Original line number Diff line number Diff line
@@ -202,6 +202,71 @@ static int __devexit ahci_remove(struct platform_device *pdev)
	return 0;
}

#ifdef CONFIG_PM
static int ahci_suspend(struct device *dev)
{
	struct ahci_platform_data *pdata = dev_get_platdata(dev);
	struct ata_host *host = dev_get_drvdata(dev);
	struct ahci_host_priv *hpriv = host->private_data;
	void __iomem *mmio = hpriv->mmio;
	u32 ctl;
	int rc;

	if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
		dev_err(dev, "firmware update required for suspend/resume\n");
		return -EIO;
	}

	/*
	 * AHCI spec rev1.1 section 8.3.3:
	 * Software must disable interrupts prior to requesting a
	 * transition of the HBA to D3 state.
	 */
	ctl = readl(mmio + HOST_CTL);
	ctl &= ~HOST_IRQ_EN;
	writel(ctl, mmio + HOST_CTL);
	readl(mmio + HOST_CTL); /* flush */

	rc = ata_host_suspend(host, PMSG_SUSPEND);
	if (rc)
		return rc;

	if (pdata && pdata->suspend)
		return pdata->suspend(dev);
	return 0;
}

static int ahci_resume(struct device *dev)
{
	struct ahci_platform_data *pdata = dev_get_platdata(dev);
	struct ata_host *host = dev_get_drvdata(dev);
	int rc;

	if (pdata && pdata->resume) {
		rc = pdata->resume(dev);
		if (rc)
			return rc;
	}

	if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
		rc = ahci_reset_controller(host);
		if (rc)
			return rc;

		ahci_init_controller(host);
	}

	ata_host_resume(host);

	return 0;
}

static struct dev_pm_ops ahci_pm_ops = {
	.suspend		= &ahci_suspend,
	.resume			= &ahci_resume,
};
#endif

static const struct of_device_id ahci_of_match[] = {
	{ .compatible = "calxeda,hb-ahci", },
	{},
@@ -214,6 +279,9 @@ static struct platform_driver ahci_driver = {
		.name = "ahci",
		.owner = THIS_MODULE,
		.of_match_table = ahci_of_match,
#ifdef CONFIG_PM
		.pm = &ahci_pm_ops,
#endif
	},
	.id_table	= ahci_devtype,
};
+1 −4
Original line number Diff line number Diff line
@@ -746,9 +746,6 @@ static void ahci_start_port(struct ata_port *ap)
	/* enable FIS reception */
	ahci_start_fis_rx(ap);

	/* enable DMA */
	ahci_start_engine(ap);

	/* turn on LEDs */
	if (ap->flags & ATA_FLAG_EM) {
		ata_for_each_link(link, ap, EDGE) {
@@ -2022,7 +2019,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
		ahci_power_down(ap);
	else {
		ata_port_err(ap, "%s (%d)\n", emsg, rc);
		ahci_start_port(ap);
		ata_port_freeze(ap);
	}

	return rc;
+124 −64
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@
#include <asm/byteorder.h>
#include <linux/cdrom.h>
#include <linux/ratelimit.h>
#include <linux/pm_runtime.h>

#include "libata.h"
#include "libata-transport.h"
@@ -3248,10 +3249,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
		ata_force_xfermask(dev);

		pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
		dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);

		if (libata_dma_mask & mode_mask)
			dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
			dma_mask = ata_pack_xfermask(0, dev->mwdma_mask,
						     dev->udma_mask);
		else
			dma_mask = 0;

@@ -5234,16 +5235,13 @@ bool ata_link_offline(struct ata_link *link)
}

#ifdef CONFIG_PM
static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
			       unsigned int action, unsigned int ehi_flags,
			       int wait)
{
	unsigned long flags;
	int i, rc;

	for (i = 0; i < host->n_ports; i++) {
		struct ata_port *ap = host->ports[i];
	struct ata_link *link;
	unsigned long flags;
	int rc;

	/* Previous resume operation might still be in
	 * progress.  Wait for PM_PENDING to clear.
@@ -5276,31 +5274,16 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
	if (wait) {
		ata_port_wait_eh(ap);
		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
			if (rc)
				return rc;
		}
	}

	return 0;
	return rc;
}

/**
 *	ata_host_suspend - suspend host
 *	@host: host to suspend
 *	@mesg: PM message
 *
 *	Suspend @host.  Actual operation is performed by EH.  This
 *	function requests EH to perform PM operations and waits for EH
 *	to finish.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep).
 *
 *	RETURNS:
 *	0 on success, -errno on failure.
 */
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
#define to_ata_port(d) container_of(d, struct ata_port, tdev)

static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
{
	struct ata_port *ap = to_ata_port(dev);
	unsigned int ehi_flags = ATA_EHI_QUIET;
	int rc;

@@ -5315,31 +5298,108 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
	if (mesg.event == PM_EVENT_SUSPEND)
		ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;

	rc = ata_host_request_pm(host, mesg, 0, ehi_flags, 1);
	if (rc == 0)
		host->dev->power.power_state = mesg;
	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
	return rc;
}

static int ata_port_suspend(struct device *dev)
{
	if (pm_runtime_suspended(dev))
		return 0;

	return ata_port_suspend_common(dev, PMSG_SUSPEND);
}

static int ata_port_do_freeze(struct device *dev)
{
	if (pm_runtime_suspended(dev))
		pm_runtime_resume(dev);

	return ata_port_suspend_common(dev, PMSG_FREEZE);
}

static int ata_port_poweroff(struct device *dev)
{
	if (pm_runtime_suspended(dev))
		return 0;

	return ata_port_suspend_common(dev, PMSG_HIBERNATE);
}

static int ata_port_resume_common(struct device *dev)
{
	struct ata_port *ap = to_ata_port(dev);
	int rc;

	rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
	return rc;
}

static int ata_port_resume(struct device *dev)
{
	int rc;

	rc = ata_port_resume_common(dev);
	if (!rc) {
		pm_runtime_disable(dev);
		pm_runtime_set_active(dev);
		pm_runtime_enable(dev);
	}

	return rc;
}

static int ata_port_runtime_idle(struct device *dev)
{
	return pm_runtime_suspend(dev);
}

static const struct dev_pm_ops ata_port_pm_ops = {
	.suspend = ata_port_suspend,
	.resume = ata_port_resume,
	.freeze = ata_port_do_freeze,
	.thaw = ata_port_resume,
	.poweroff = ata_port_poweroff,
	.restore = ata_port_resume,

	.runtime_suspend = ata_port_suspend,
	.runtime_resume = ata_port_resume_common,
	.runtime_idle = ata_port_runtime_idle,
};

/**
 *	ata_host_suspend - suspend host
 *	@host: host to suspend
 *	@mesg: PM message
 *
 *	Suspend @host.  Actual operation is performed by port suspend.
 */
int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
{
	host->dev->power.power_state = mesg;
	return 0;
}

/**
 *	ata_host_resume - resume host
 *	@host: host to resume
 *
 *	Resume @host.  Actual operation is performed by EH.  This
 *	function requests EH to perform PM operations and returns.
 *	Note that all resume operations are performed parallelly.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep).
 *	Resume @host.  Actual operation is performed by port resume.
 */
void ata_host_resume(struct ata_host *host)
{
	ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
			    ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
	host->dev->power.power_state = PMSG_ON;
}
#endif

struct device_type ata_port_type = {
	.name = "ata_port",
#ifdef CONFIG_PM
	.pm = &ata_port_pm_ops,
#endif
};

/**
 *	ata_dev_init - Initialize an ata_device structure
 *	@dev: Device structure to initialize
Loading