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

Commit bb03c640 authored by Mika Westerberg's avatar Mika Westerberg Committed by Tejun Heo
Browse files

ahci: Add functions to manage runtime PM of AHCI ports



Add new functions ahci_rpm_get_port()/ahci_rpm_put_port() that change
runtime PM status of AHCI ports. Depending if the AHCI host has runtime PM
enabled or disabled calling these may trigger runtime suspend/resume of the
host controller.

We also call these functions in appropriate places to make sure host
controller registers are available before using them.

Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent f1d848f9
Loading
Loading
Loading
Loading
+47 −1
Original line number Original line Diff line number Diff line
@@ -225,6 +225,31 @@ static void ahci_enable_ahci(void __iomem *mmio)
	WARN_ON(1);
	WARN_ON(1);
}
}


/**
 *	ahci_rpm_get_port - Make sure the port is powered on
 *	@ap: Port to power on
 *
 *	Whenever there is need to access the AHCI host registers outside of
 *	normal execution paths, call this function to make sure the host is
 *	actually powered on.
 */
static int ahci_rpm_get_port(struct ata_port *ap)
{
	return pm_runtime_get_sync(ap->dev);
}

/**
 *	ahci_rpm_put_port - Undoes ahci_rpm_get_port()
 *	@ap: Port to power down
 *
 *	Undoes ahci_rpm_get_port() and possibly powers down the AHCI host
 *	if it has no more active users.
 */
static void ahci_rpm_put_port(struct ata_port *ap)
{
	pm_runtime_put(ap->dev);
}

static ssize_t ahci_show_host_caps(struct device *dev,
static ssize_t ahci_show_host_caps(struct device *dev,
				   struct device_attribute *attr, char *buf)
				   struct device_attribute *attr, char *buf)
{
{
@@ -261,8 +286,13 @@ static ssize_t ahci_show_port_cmd(struct device *dev,
	struct Scsi_Host *shost = class_to_shost(dev);
	struct Scsi_Host *shost = class_to_shost(dev);
	struct ata_port *ap = ata_shost_to_port(shost);
	struct ata_port *ap = ata_shost_to_port(shost);
	void __iomem *port_mmio = ahci_port_base(ap);
	void __iomem *port_mmio = ahci_port_base(ap);
	ssize_t ret;


	return sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
	ahci_rpm_get_port(ap);
	ret = sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
	ahci_rpm_put_port(ap);

	return ret;
}
}


static ssize_t ahci_read_em_buffer(struct device *dev,
static ssize_t ahci_read_em_buffer(struct device *dev,
@@ -278,17 +308,20 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
	size_t count;
	size_t count;
	int i;
	int i;


	ahci_rpm_get_port(ap);
	spin_lock_irqsave(ap->lock, flags);
	spin_lock_irqsave(ap->lock, flags);


	em_ctl = readl(mmio + HOST_EM_CTL);
	em_ctl = readl(mmio + HOST_EM_CTL);
	if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
	if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
	    !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
	    !(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
		spin_unlock_irqrestore(ap->lock, flags);
		spin_unlock_irqrestore(ap->lock, flags);
		ahci_rpm_put_port(ap);
		return -EINVAL;
		return -EINVAL;
	}
	}


	if (!(em_ctl & EM_CTL_MR)) {
	if (!(em_ctl & EM_CTL_MR)) {
		spin_unlock_irqrestore(ap->lock, flags);
		spin_unlock_irqrestore(ap->lock, flags);
		ahci_rpm_put_port(ap);
		return -EAGAIN;
		return -EAGAIN;
	}
	}


@@ -316,6 +349,7 @@ static ssize_t ahci_read_em_buffer(struct device *dev,
	}
	}


	spin_unlock_irqrestore(ap->lock, flags);
	spin_unlock_irqrestore(ap->lock, flags);
	ahci_rpm_put_port(ap);


	return i;
	return i;
}
}
@@ -340,11 +374,13 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
	    size % 4 || size > hpriv->em_buf_sz)
	    size % 4 || size > hpriv->em_buf_sz)
		return -EINVAL;
		return -EINVAL;


	ahci_rpm_get_port(ap);
	spin_lock_irqsave(ap->lock, flags);
	spin_lock_irqsave(ap->lock, flags);


	em_ctl = readl(mmio + HOST_EM_CTL);
	em_ctl = readl(mmio + HOST_EM_CTL);
	if (em_ctl & EM_CTL_TM) {
	if (em_ctl & EM_CTL_TM) {
		spin_unlock_irqrestore(ap->lock, flags);
		spin_unlock_irqrestore(ap->lock, flags);
		ahci_rpm_put_port(ap);
		return -EBUSY;
		return -EBUSY;
	}
	}


@@ -357,6 +393,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
	writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);


	spin_unlock_irqrestore(ap->lock, flags);
	spin_unlock_irqrestore(ap->lock, flags);
	ahci_rpm_put_port(ap);


	return size;
	return size;
}
}
@@ -370,7 +407,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
	void __iomem *mmio = hpriv->mmio;
	void __iomem *mmio = hpriv->mmio;
	u32 em_ctl;
	u32 em_ctl;


	ahci_rpm_get_port(ap);
	em_ctl = readl(mmio + HOST_EM_CTL);
	em_ctl = readl(mmio + HOST_EM_CTL);
	ahci_rpm_put_port(ap);


	return sprintf(buf, "%s%s%s%s\n",
	return sprintf(buf, "%s%s%s%s\n",
		       em_ctl & EM_CTL_LED ? "led " : "",
		       em_ctl & EM_CTL_LED ? "led " : "",
@@ -1014,6 +1053,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
	else
	else
		return -EINVAL;
		return -EINVAL;


	ahci_rpm_get_port(ap);
	spin_lock_irqsave(ap->lock, flags);
	spin_lock_irqsave(ap->lock, flags);


	/*
	/*
@@ -1023,6 +1063,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
	em_ctl = readl(mmio + HOST_EM_CTL);
	em_ctl = readl(mmio + HOST_EM_CTL);
	if (em_ctl & EM_CTL_TM) {
	if (em_ctl & EM_CTL_TM) {
		spin_unlock_irqrestore(ap->lock, flags);
		spin_unlock_irqrestore(ap->lock, flags);
		ahci_rpm_put_port(ap);
		return -EBUSY;
		return -EBUSY;
	}
	}


@@ -1050,6 +1091,8 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
	emp->led_state = state;
	emp->led_state = state;


	spin_unlock_irqrestore(ap->lock, flags);
	spin_unlock_irqrestore(ap->lock, flags);
	ahci_rpm_put_port(ap);

	return size;
	return size;
}
}


@@ -2216,6 +2259,8 @@ static void ahci_pmp_detach(struct ata_port *ap)


int ahci_port_resume(struct ata_port *ap)
int ahci_port_resume(struct ata_port *ap)
{
{
	ahci_rpm_get_port(ap);

	ahci_power_up(ap);
	ahci_power_up(ap);
	ahci_start_port(ap);
	ahci_start_port(ap);


@@ -2242,6 +2287,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
		ata_port_freeze(ap);
		ata_port_freeze(ap);
	}
	}


	ahci_rpm_put_port(ap);
	return rc;
	return rc;
}
}
#endif
#endif