Release 4.7 drivers/ata/libahci.c
/*
* libahci.c - Common AHCI SATA low-level routines
*
* Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
* Copyright 2004-2005 Red Hat, Inc.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* libata documentation is available via 'make {ps|pdf}docs',
* as Documentation/DocBook/libata.*
*
* AHCI hardware documentation:
* http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
* http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
*
*/
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include <linux/pci.h>
#include "ahci.h"
#include "libata.h"
static int ahci_skip_host_reset;
int ahci_ignore_sss;
EXPORT_SYMBOL_GPL(ahci_ignore_sss);
module_param_named(skip_host_reset, ahci_skip_host_reset, int, 0444);
MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)");
module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned hints);
static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size);
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size);
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep);
static void ahci_enable_fbs(struct ata_port *ap);
static void ahci_disable_fbs(struct ata_port *ap);
static void ahci_pmp_attach(struct ata_port *ap);
static void ahci_pmp_detach(struct ata_port *ap);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static void ahci_postreset(struct ata_link *link, unsigned int *class);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static void ahci_dev_config(struct ata_device *dev);
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
#endif
static ssize_t ahci_activity_show(struct ata_device *dev, char *buf);
static ssize_t ahci_activity_store(struct ata_device *dev,
enum sw_activity val);
static void ahci_init_sw_activity(struct ata_link *link);
static ssize_t ahci_show_host_caps(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_show_host_cap2(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_read_em_buffer(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_store_em_buffer(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size);
static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf);
static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO,
ahci_read_em_buffer, ahci_store_em_buffer);
static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL);
struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_link_power_management_policy,
&dev_attr_em_message_type,
&dev_attr_em_message,
&dev_attr_ahci_host_caps,
&dev_attr_ahci_host_cap2,
&dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd,
&dev_attr_em_buffer,
&dev_attr_em_message_supported,
NULL
};
EXPORT_SYMBOL_GPL(ahci_shost_attrs);
struct device_attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity,
&dev_attr_unload_heads,
NULL
};
EXPORT_SYMBOL_GPL(ahci_sdev_attrs);
struct ata_port_operations ahci_ops = {
.inherits = &sata_pmp_port_ops,
.qc_defer = ahci_pmp_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.qc_fill_rtf = ahci_qc_fill_rtf,
.freeze = ahci_freeze,
.thaw = ahci_thaw,
.softreset = ahci_softreset,
.hardreset = ahci_hardreset,
.postreset = ahci_postreset,
.pmp_softreset = ahci_softreset,
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
.dev_config = ahci_dev_config,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
.pmp_attach = ahci_pmp_attach,
.pmp_detach = ahci_pmp_detach,
.set_lpm = ahci_set_lpm,
.em_show = ahci_led_show,
.em_store = ahci_led_store,
.sw_activity_show = ahci_activity_show,
.sw_activity_store = ahci_activity_store,
.transmit_led_message = ahci_transmit_led_message,
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
#endif
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
EXPORT_SYMBOL_GPL(ahci_ops);
struct ata_port_operations ahci_pmp_retry_srst_ops = {
.inherits = &ahci_ops,
.softreset = ahci_pmp_retry_softreset,
};
EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops);
static bool ahci_em_messages __read_mostly = true;
EXPORT_SYMBOL_GPL(ahci_em_messages);
module_param(ahci_em_messages, bool, 0444);
/* add other LED protocol types when they become supported */
MODULE_PARM_DESC(ahci_em_messages,
"AHCI Enclosure Management Message control (0 = off, 1 = on)");
/* device sleep idle timeout in ms */
static int devslp_idle_timeout __read_mostly = 1000;
module_param(devslp_idle_timeout, int, 0644);
MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout");
static void ahci_enable_ahci(void __iomem *mmio)
{
int i;
u32 tmp;
/* turn on AHCI_EN */
tmp = readl(mmio + HOST_CTL);
if (tmp & HOST_AHCI_EN)
return;
/* Some controllers need AHCI_EN to be written multiple times.
* Try a few times before giving up.
*/
for (i = 0; i < 5; i++) {
tmp |= HOST_AHCI_EN;
writel(tmp, mmio + HOST_CTL);
tmp = readl(mmio + HOST_CTL); /* flush && sanity check */
if (tmp & HOST_AHCI_EN)
return;
msleep(10);
}
WARN_ON(1);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 90 | 100.00% | 1 | 100.00% |
| Total | 90 | 100.00% | 1 | 100.00% |
/**
* 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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mika westerberg | mika westerberg | 19 | 100.00% | 1 | 100.00% |
| Total | 19 | 100.00% | 1 | 100.00% |
/**
* 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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
mika westerberg | mika westerberg | 18 | 100.00% | 1 | 100.00% |
| Total | 18 | 100.00% | 1 | 100.00% |
static ssize_t ahci_show_host_caps(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
return sprintf(buf, "%x\n", hpriv->cap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 63 | 100.00% | 1 | 100.00% |
| Total | 63 | 100.00% | 1 | 100.00% |
static ssize_t ahci_show_host_cap2(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
return sprintf(buf, "%x\n", hpriv->cap2);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 36 | 57.14% | 1 | 50.00% |
harry zhang | harry zhang | 27 | 42.86% | 1 | 50.00% |
| Total | 63 | 100.00% | 2 | 100.00% |
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
return sprintf(buf, "%x\n", hpriv->version);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
harry zhang | harry zhang | 60 | 95.24% | 1 | 50.00% |
mika westerberg | mika westerberg | 3 | 4.76% | 1 | 50.00% |
| Total | 63 | 100.00% | 2 | 100.00% |
static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
void __iomem *port_mmio = ahci_port_base(ap);
ssize_t ret;
ahci_rpm_get_port(ap);
ret = sprintf(buf, "%x\n", readl(port_mmio + PORT_CMD));
ahci_rpm_put_port(ap);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
harry zhang | harry zhang | 64 | 78.05% | 1 | 50.00% |
mika westerberg | mika westerberg | 18 | 21.95% | 1 | 50.00% |
| Total | 82 | 100.00% | 2 | 100.00% |
static ssize_t ahci_read_em_buffer(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = hpriv->mmio;
void __iomem *em_mmio = mmio + hpriv->em_loc;
u32 em_ctl, msg;
unsigned long flags;
size_t count;
int i;
ahci_rpm_get_port(ap);
spin_lock_irqsave(ap->lock, flags);
em_ctl = readl(mmio + HOST_EM_CTL);
if (!(ap->flags & ATA_FLAG_EM) || em_ctl & EM_CTL_XMT ||
!(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO)) {
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return -EINVAL;
}
if (!(em_ctl & EM_CTL_MR)) {
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return -EAGAIN;
}
if (!(em_ctl & EM_CTL_SMB))
em_mmio += hpriv->em_buf_sz;
count = hpriv->em_buf_sz;
/* the count should not be larger than PAGE_SIZE */
if (count > PAGE_SIZE) {
if (printk_ratelimit())
ata_port_warn(ap,
"EM read buffer size too large: "
"buffer size %u, page size %lu\n",
hpriv->em_buf_sz, PAGE_SIZE);
count = PAGE_SIZE;
}
for (i = 0; i < count; i += 4) {
msg = readl(em_mmio + i);
buf[i] = msg & 0xff;
buf[i + 1] = (msg >> 8) & 0xff;
buf[i + 2] = (msg >> 16) & 0xff;
buf[i + 3] = (msg >> 24) & 0xff;
}
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return i;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
harry zhang | harry zhang | 304 | 91.84% | 1 | 25.00% |
mika westerberg | mika westerberg | 20 | 6.04% | 1 | 25.00% |
anton vorontsov | anton vorontsov | 6 | 1.81% | 1 | 25.00% |
joe perches | joe perches | 1 | 0.30% | 1 | 25.00% |
| Total | 331 | 100.00% | 4 | 100.00% |
static ssize_t ahci_store_em_buffer(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = hpriv->mmio;
void __iomem *em_mmio = mmio + hpriv->em_loc;
const unsigned char *msg_buf = buf;
u32 em_ctl, msg;
unsigned long flags;
int i;
/* check size validity */
if (!(ap->flags & ATA_FLAG_EM) ||
!(hpriv->em_msg_type & EM_MSG_TYPE_SGPIO) ||
size % 4 || size > hpriv->em_buf_sz)
return -EINVAL;
ahci_rpm_get_port(ap);
spin_lock_irqsave(ap->lock, flags);
em_ctl = readl(mmio + HOST_EM_CTL);
if (em_ctl & EM_CTL_TM) {
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return -EBUSY;
}
for (i = 0; i < size; i += 4) {
msg = msg_buf[i] | msg_buf[i + 1] << 8 |
msg_buf[i + 2] << 16 | msg_buf[i + 3] << 24;
writel(msg, em_mmio + i);
}
writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return size;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
harry zhang | harry zhang | 171 | 64.29% | 2 | 50.00% |
anton vorontsov | anton vorontsov | 80 | 30.08% | 1 | 25.00% |
mika westerberg | mika westerberg | 15 | 5.64% | 1 | 25.00% |
| Total | 266 | 100.00% | 4 | 100.00% |
static ssize_t ahci_show_em_supported(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(dev);
struct ata_port *ap = ata_shost_to_port(shost);
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 em_ctl;
ahci_rpm_get_port(ap);
em_ctl = readl(mmio + HOST_EM_CTL);
ahci_rpm_put_port(ap);
return sprintf(buf, "%s%s%s%s\n",
em_ctl & EM_CTL_LED ? "led " : "",
em_ctl & EM_CTL_SAFTE ? "saf-te " : "",
em_ctl & EM_CTL_SES ? "ses-2 " : "",
em_ctl & EM_CTL_SGPIO ? "sgpio " : "");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
hannes reinecke | hannes reinecke | 112 | 91.80% | 1 | 50.00% |
mika westerberg | mika westerberg | 10 | 8.20% | 1 | 50.00% |
| Total | 122 | 100.00% | 2 | 100.00% |
/**
* ahci_save_initial_config - Save and fixup initial config values
* @dev: target AHCI device
* @hpriv: host private area to store config values
*
* Some registers containing configuration info might be setup by
* BIOS and might be cleared on reset. This function saves the
* initial values of those registers into @hpriv such that they
* can be restored after controller reset.
*
* If inconsistent, config values are fixed up by this function.
*
* If it is not set already this function sets hpriv->start_engine to
* ahci_start_engine.
*
* LOCKING:
* None.
*/
void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
{
void __iomem *mmio = hpriv->mmio;
u32 cap, cap2, vers, port_map;
int i;
/* make sure AHCI mode is enabled before accessing CAP */
ahci_enable_ahci(mmio);
/* Values prefixed with saved_ are written back to host after
* reset. Values without are used for driver operation.
*/
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
/* CAP2 register is only defined for AHCI 1.2 and later */
vers = readl(mmio + HOST_VERSION);
if ((vers >> 16) > 1 ||
((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
else
hpriv->saved_cap2 = cap2 = 0;
/* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_info(dev, "controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
dev_info(dev, "controller can't do NCQ, turning off CAP_NCQ\n");
cap &= ~HOST_CAP_NCQ;
}
if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) {
dev_info(dev, "controller can do NCQ, turning on CAP_NCQ\n");
cap |= HOST_CAP_NCQ;
}
if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
dev_info(dev, "controller can't do PMP, turning off CAP_PMP\n");
cap &= ~HOST_CAP_PMP;
}
if ((cap & HOST_CAP_SNTF) && (hpriv->flags & AHCI_HFLAG_NO_SNTF)) {
dev_info(dev,
"controller can't do SNTF, turning off CAP_SNTF\n");
cap &= ~HOST_CAP_SNTF;
}
if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) {
dev_info(dev,
"controller can't do DEVSLP, turning off\n");
cap2 &= ~HOST_CAP2_SDS;
cap2 &= ~HOST_CAP2_SADM;
}
if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) {
dev_info(dev, "controller can do FBS, turning on CAP_FBS\n");
cap |= HOST_CAP_FBS;
}
if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) {
dev_info(dev, "controller can't do FBS, turning off CAP_FBS\n");
cap &= ~HOST_CAP_FBS;
}
if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
port_map, hpriv->force_port_map);
port_map = hpriv->force_port_map;
hpriv->saved_port_map = port_map;
}
if (hpriv->mask_port_map) {
dev_warn(dev, "masking port_map 0x%x -> 0x%x\n",
port_map,
port_map & hpriv->mask_port_map);
port_map &= hpriv->mask_port_map;
}
/* cross check port_map and cap.n_ports */
if (port_map) {
int map_ports = 0;
for (i = 0; i < AHCI_MAX_PORTS; i++)
if (port_map & (1 << i))
map_ports++;
/* If PI has more ports than n_ports, whine, clear
* port_map and let it be generated from n_ports.
*/
if (map_ports > ahci_nr_ports(cap)) {
dev_warn(dev,
"implemented port map (0x%x) contains more ports than nr_ports (%u), using nr_ports\n",
port_map, ahci_nr_ports(cap));
port_map = 0;
}
}
/* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
if (!port_map && vers < 0x10300) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
/* write the fixed up value to the PI register */
hpriv->saved_port_map = port_map;
}
/* record values to use during operation */
hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->version = readl(mmio + HOST_VERSION);
hpriv->port_map = port_map;
if (!hpriv->start_engine)
hpriv->start_engine = ahci_start_engine;
if (!hpriv->irq_handler)
hpriv->irq_handler = ahci_single_level_irq_intr;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 441 | 72.53% | 1 | 9.09% |
jacob pan | jacob pan | 35 | 5.76% | 1 | 9.09% |
tejun heo | tejun heo | 34 | 5.59% | 2 | 18.18% |
kefeng wang | kefeng wang | 30 | 4.93% | 1 | 9.09% |
antoine tenart | antoine tenart | 14 | 2.30% | 1 | 9.09% |
suman tripathi | suman tripathi | 13 | 2.14% | 1 | 9.09% |
hans de goede | hans de goede | 13 | 2.14% | 1 | 9.09% |
joe perches | joe perches | 11 | 1.81% | 1 | 9.09% |
mika westerberg | mika westerberg | 11 | 1.81% | 1 | 9.09% |
srinivas kandagatla | srinivas kandagatla | 6 | 0.99% | 1 | 9.09% |
| Total | 608 | 100.00% | 11 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
/**
* ahci_restore_initial_config - Restore initial config
* @host: target ATA host
*
* Restore initial config stored by ahci_save_initial_config().
*
* LOCKING:
* None.
*/
static void ahci_restore_initial_config(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
writel(hpriv->saved_cap, mmio + HOST_CAP);
if (hpriv->saved_cap2)
writel(hpriv->saved_cap2, mmio + HOST_CAP2);
writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 79 | 100.00% | 1 | 100.00% |
| Total | 79 | 100.00% | 1 | 100.00% |
static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
{
static const int offset[] = {
[SCR_STATUS] = PORT_SCR_STAT,
[SCR_CONTROL] = PORT_SCR_CTL,
[SCR_ERROR] = PORT_SCR_ERR,
[SCR_ACTIVE] = PORT_SCR_ACT,
[SCR_NOTIFICATION] = PORT_SCR_NTF,
};
struct ahci_host_priv *hpriv = ap->host->private_data;
if (sc_reg < ARRAY_SIZE(offset) &&
(sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
return offset[sc_reg];
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 96 | 100.00% | 1 | 100.00% |
| Total | 96 | 100.00% | 1 | 100.00% |
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
*val = readl(port_mmio + offset);
return 0;
}
return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 66 | 100.00% | 1 | 100.00% |
| Total | 66 | 100.00% | 1 | 100.00% |
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) {
writel(val, port_mmio + offset);
return 0;
}
return -EINVAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 64 | 100.00% | 1 | 100.00% |
| Total | 64 | 100.00% | 1 | 100.00% |
void ahci_start_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* start DMA */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_START;
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 54 | 100.00% | 1 | 100.00% |
| Total | 54 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_start_engine);
int ahci_stop_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
/*
* On some controllers, stopping a port's DMA engine while the port
* is in ALPM state (partial or slumber) results in failures on
* subsequent DMA engine starts. For those controllers, put the
* port back in active state before stopping its DMA engine.
*/
if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
(ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
dev_err(ap->host->dev, "Failed to wake up port before engine stop\n");
return -EIO;
}
tmp = readl(port_mmio + PORT_CMD);
/* check if the HBA is idle */
if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
return 0;
/* setting HBA to idle */
tmp &= ~PORT_CMD_START;
writel(tmp, port_mmio + PORT_CMD);
/* wait for engine to stop. This could be as long as 500 msec */
tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
if (tmp & PORT_CMD_LIST_ON)
return -EIO;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 96 | 60.38% | 1 | 33.33% |
danesh petigara | danesh petigara | 61 | 38.36% | 1 | 33.33% |
tejun heo | tejun heo | 2 | 1.26% | 1 | 33.33% |
| Total | 159 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_stop_engine);
void ahci_start_fis_rx(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
u32 tmp;
/* set FIS registers */
if (hpriv->cap & HOST_CAP_64)
writel((pp->cmd_slot_dma >> 16) >> 16,
port_mmio + PORT_LST_ADDR_HI);
writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
if (hpriv->cap & HOST_CAP_64)
writel((pp->rx_fis_dma >> 16) >> 16,
port_mmio + PORT_FIS_ADDR_HI);
writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
/* enable FIS reception */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_FIS_RX;
writel(tmp, port_mmio + PORT_CMD);
/* flush */
readl(port_mmio + PORT_CMD);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 151 | 100.00% | 1 | 100.00% |
| Total | 151 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_start_fis_rx);
static int ahci_stop_fis_rx(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* disable FIS reception */
tmp = readl(port_mmio + PORT_CMD);
tmp &= ~PORT_CMD_FIS_RX;
writel(tmp, port_mmio + PORT_CMD);
/* wait for completion, spec says 500ms, give it 1000 */
tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
PORT_CMD_FIS_ON, 10, 1000);
if (tmp & PORT_CMD_FIS_ON)
return -EBUSY;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 79 | 97.53% | 1 | 50.00% |
tejun heo | tejun heo | 2 | 2.47% | 1 | 50.00% |
| Total | 81 | 100.00% | 2 | 100.00% |
static void ahci_power_up(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd;
cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
/* spin up device */
if (hpriv->cap & HOST_CAP_SSS) {
cmd |= PORT_CMD_SPIN_UP;
writel(cmd, port_mmio + PORT_CMD);
}
/* wake up link */
writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 83 | 100.00% | 1 | 100.00% |
| Total | 83 | 100.00% | 1 | 100.00% |
static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
unsigned int hints)
{
struct ata_port *ap = link->ap;
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
if (policy != ATA_LPM_MAX_POWER) {
/* wakeup flag only applies to the max power policy */
hints &= ~ATA_LPM_WAKE_ONLY;
/*
* Disable interrupts on Phy Ready. This keeps us from
* getting woken up due to spurious phy ready
* interrupts.
*/
pp->intr_mask &= ~PORT_IRQ_PHYRDY;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
sata_link_scr_lpm(link, policy, false);
}
if (hpriv->cap & HOST_CAP_ALPM) {
u32 cmd = readl(port_mmio + PORT_CMD);
if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
if (!(hints & ATA_LPM_WAKE_ONLY))
cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
cmd |= PORT_CMD_ICC_ACTIVE;
writel(cmd, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD);
/* wait 10ms to be sure we've come out of LPM state */
ata_msleep(ap, 10);
if (hints & ATA_LPM_WAKE_ONLY)
return 0;
} else {
cmd |= PORT_CMD_ALPE;
if (policy == ATA_LPM_MIN_POWER)
cmd |= PORT_CMD_ASP;
/* write out new cmd value */
writel(cmd, port_mmio + PORT_CMD);
}
}
/* set aggressive device sleep */
if ((hpriv->cap2 & HOST_CAP2_SDS) &&
(hpriv->cap2 & HOST_CAP2_SADM) &&
(link->device->flags & ATA_DFLAG_DEVSLP)) {
if (policy == ATA_LPM_MIN_POWER)
ahci_set_aggressive_devslp(ap, true);
else
ahci_set_aggressive_devslp(ap, false);
}
if (policy == ATA_LPM_MAX_POWER) {
sata_link_scr_lpm(link, policy, false);
/* turn PHYRDY IRQ back on */
pp->intr_mask |= PORT_IRQ_PHYRDY;
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tejun heo | tejun heo | 126 | 41.04% | 2 | 40.00% |
anton vorontsov | anton vorontsov | 105 | 34.20% | 1 | 20.00% |
shane huang | shane huang | 52 | 16.94% | 1 | 20.00% |
danesh petigara | danesh petigara | 24 | 7.82% | 1 | 20.00% |
| Total | 307 | 100.00% | 5 | 100.00% |
#ifdef CONFIG_PM
static void ahci_power_down(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd, scontrol;
if (!(hpriv->cap & HOST_CAP_SSS))
return;
/* put device into listen mode, first set PxSCTL.DET to 0 */
scontrol = readl(port_mmio + PORT_SCR_CTL);
scontrol &= ~0xf;
writel(scontrol, port_mmio + PORT_SCR_CTL);
/* then set PxCMD.SUD to 0 */
cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
cmd &= ~PORT_CMD_SPIN_UP;
writel(cmd, port_mmio + PORT_CMD);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 100 | 100.00% | 1 | 100.00% |
| Total | 100 | 100.00% | 1 | 100.00% |
#endif
static void ahci_start_port(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
struct ata_link *link;
struct ahci_em_priv *emp;
ssize_t rc;
int i;
/* enable FIS reception */
ahci_start_fis_rx(ap);
/* enable DMA */
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
hpriv->start_engine(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
ata_for_each_link(link, ap, EDGE) {
emp = &pp->em_priv[link->pmp];
/* EM Transmit bit maybe busy during init */
for (i = 0; i < EM_MAX_RETRY; i++) {
rc = ap->ops->transmit_led_message(ap,
emp->led_state,
4);
/*
* If busy, give a breather but do not
* release EH ownership by using msleep()
* instead of ata_msleep(). EM Transmit
* bit is busy for the whole host and
* releasing ownership will cause other
* ports to fail the same way.
*/
if (rc == -EBUSY)
msleep(1);
else
break;
}
}
}
if (ap->flags & ATA_FLAG_SW_ACTIVITY)
ata_for_each_link(link, ap, EDGE)
ahci_init_sw_activity(link);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 137 | 78.74% | 1 | 20.00% |
brian norris | brian norris | 27 | 15.52% | 1 | 20.00% |
mark langsdorf | mark langsdorf | 5 | 2.87% | 1 | 20.00% |
hans de goede | hans de goede | 3 | 1.72% | 1 | 20.00% |
lukasz dorau | lukasz dorau | 2 | 1.15% | 1 | 20.00% |
| Total | 174 | 100.00% | 5 | 100.00% |
static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
{
int rc;
/* disable DMA */
rc = ahci_stop_engine(ap);
if (rc) {
*emsg = "failed to stop engine";
return rc;
}
/* disable FIS reception */
rc = ahci_stop_fis_rx(ap);
if (rc) {
*emsg = "failed stop FIS RX";
return rc;
}
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 67 | 100.00% | 1 | 100.00% |
| Total | 67 | 100.00% | 1 | 100.00% |
int ahci_reset_controller(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 tmp;
/* we must be in AHCI mode, before using anything
* AHCI-specific, such as HOST_RESET.
*/
ahci_enable_ahci(mmio);
/* global controller reset */
if (!ahci_skip_host_reset) {
tmp = readl(mmio + HOST_CTL);
if ((tmp & HOST_RESET) == 0) {
writel(tmp | HOST_RESET, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
}
/*
* to perform host reset, OS should set HOST_RESET
* and poll until this bit is read to be "0".
* reset must complete within 1 second, or
* the hardware should be considered fried.
*/
tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
HOST_RESET, 10, 1000);
if (tmp & HOST_RESET) {
dev_err(host->dev, "controller reset failed (0x%x)\n",
tmp);
return -EIO;
}
/* turn on AHCI mode */
ahci_enable_ahci(mmio);
/* Some registers might be cleared on reset. Restore
* initial values.
*/
ahci_restore_initial_config(host);
} else
dev_info(host->dev, "skipping global host reset\n");
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 149 | 97.39% | 1 | 33.33% |
tejun heo | tejun heo | 2 | 1.31% | 1 | 33.33% |
joe perches | joe perches | 2 | 1.31% | 1 | 33.33% |
| Total | 153 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_reset_controller);
static void ahci_sw_activity(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
if (!(link->flags & ATA_LFLAG_SW_ACTIVITY))
return;
emp->activity++;
if (!timer_pending(&emp->timer))
mod_timer(&emp->timer, jiffies + msecs_to_jiffies(10));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 87 | 100.00% | 1 | 100.00% |
| Total | 87 | 100.00% | 1 | 100.00% |
static void ahci_sw_activity_blink(unsigned long arg)
{
struct ata_link *link = (struct ata_link *)arg;
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
unsigned long led_message = emp->led_state;
u32 activity_led_state;
unsigned long flags;
led_message &= EM_MSG_LED_VALUE;
led_message |= ap->port_no | (link->pmp << 8);
/* check to see if we've had activity. If so,
* toggle state of LED and reset timer. If not,
* turn LED to desired idle state.
*/
spin_lock_irqsave(ap->lock, flags);
if (emp->saved_activity != emp->activity) {
emp->saved_activity = emp->activity;
/* get the current LED state */
activity_led_state = led_message & EM_MSG_LED_VALUE_ON;
if (activity_led_state)
activity_led_state = 0;
else
activity_led_state = 1;
/* clear old state */
led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
/* toggle state */
led_message |= (activity_led_state << 16);
mod_timer(&emp->timer, jiffies + msecs_to_jiffies(100));
} else {
/* switch to idle */
led_message &= ~EM_MSG_LED_VALUE_ACTIVITY;
if (emp->blink_policy == BLINK_OFF)
led_message |= (1 << 16);
}
spin_unlock_irqrestore(ap->lock, flags);
ap->ops->transmit_led_message(ap, led_message, 4);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 210 | 97.67% | 1 | 50.00% |
mark langsdorf | mark langsdorf | 5 | 2.33% | 1 | 50.00% |
| Total | 215 | 100.00% | 2 | 100.00% |
static void ahci_init_sw_activity(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
/* init activity stats, setup timer */
emp->saved_activity = emp->activity = 0;
setup_timer(&emp->timer, ahci_sw_activity_blink, (unsigned long)link);
/* check our blink policy and set flag for link if it's enabled */
if (emp->blink_policy)
link->flags |= ATA_LFLAG_SW_ACTIVITY;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 84 | 100.00% | 1 | 100.00% |
| Total | 84 | 100.00% | 1 | 100.00% |
int ahci_reset_em(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 em_ctl;
em_ctl = readl(mmio + HOST_EM_CTL);
if ((em_ctl & EM_CTL_TM) || (em_ctl & EM_CTL_RST))
return -EINVAL;
writel(em_ctl | EM_CTL_RST, mmio + HOST_EM_CTL);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 72 | 100.00% | 1 | 100.00% |
| Total | 72 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_reset_em);
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
ssize_t size)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *mmio = hpriv->mmio;
u32 em_ctl;
u32 message[] = {0, 0};
unsigned long flags;
int pmp;
struct ahci_em_priv *emp;
/* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp];
else
return -EINVAL;
ahci_rpm_get_port(ap);
spin_lock_irqsave(ap->lock, flags);
/*
* if we are still busy transmitting a previous message,
* do not allow
*/
em_ctl = readl(mmio + HOST_EM_CTL);
if (em_ctl & EM_CTL_TM) {
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return -EBUSY;
}
if (hpriv->em_msg_type & EM_MSG_TYPE_LED) {
/*
* create message header - this is all zero except for
* the message size, which is 4 bytes.
*/
message[0] |= (4 << 8);
/* ignore 0:4 of byte zero, fill in port info yourself */
message[1] = ((state & ~EM_MSG_LED_HBA_PORT) | ap->port_no);
/* write message to EM_LOC */
writel(message[0], mmio + hpriv->em_loc);
writel(message[1], mmio + hpriv->em_loc+4);
/*
* tell hardware to transmit the message
*/
writel(em_ctl | EM_CTL_TM, mmio + HOST_EM_CTL);
}
/* save off new led state for port/slot */
emp->led_state = state;
spin_unlock_irqrestore(ap->lock, flags);
ahci_rpm_put_port(ap);
return size;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 227 | 86.97% | 1 | 33.33% |
harry zhang | harry zhang | 19 | 7.28% | 1 | 33.33% |
mika westerberg | mika westerberg | 15 | 5.75% | 1 | 33.33% |
| Total | 261 | 100.00% | 3 | 100.00% |
static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
{
struct ahci_port_priv *pp = ap->private_data;
struct ata_link *link;
struct ahci_em_priv *emp;
int rc = 0;
ata_for_each_link(link, ap, EDGE) {
emp = &pp->em_priv[link->pmp];
rc += sprintf(buf, "%lx\n", emp->led_state);
}
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 77 | 100.00% | 1 | 100.00% |
| Total | 77 | 100.00% | 1 | 100.00% |
static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
size_t size)
{
unsigned int state;
int pmp;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp;
if (kstrtouint(buf, 0, &state) < 0)
return -EINVAL;
/* get the slot number from the message */
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
if (pmp < EM_MAX_SLOTS)
emp = &pp->em_priv[pmp];
else
return -EINVAL;
/* mask off the activity bits if we are in sw_activity
* mode, user should turn off sw_activity before setting
* activity led through em_message
*/
if (emp->blink_policy)
state &= ~EM_MSG_LED_VALUE_ACTIVITY;
return ap->ops->transmit_led_message(ap, state, size);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 97 | 83.62% | 1 | 33.33% |
daeseok youn | daeseok youn | 14 | 12.07% | 1 | 33.33% |
mark langsdorf | mark langsdorf | 5 | 4.31% | 1 | 33.33% |
| Total | 116 | 100.00% | 3 | 100.00% |
static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
u32 port_led_state = emp->led_state;
/* save the desired Activity LED behavior */
if (val == OFF) {
/* clear LFLAG */
link->flags &= ~(ATA_LFLAG_SW_ACTIVITY);
/* set the LED to OFF */
port_led_state &= EM_MSG_LED_VALUE_OFF;
port_led_state |= (ap->port_no | (link->pmp << 8));
ap->ops->transmit_led_message(ap, port_led_state, 4);
} else {
link->flags |= ATA_LFLAG_SW_ACTIVITY;
if (val == BLINK_OFF) {
/* set LED to ON for idle */
port_led_state &= EM_MSG_LED_VALUE_OFF;
port_led_state |= (ap->port_no | (link->pmp << 8));
port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
ap->ops->transmit_led_message(ap, port_led_state, 4);
}
}
emp->blink_policy = val;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 172 | 94.51% | 1 | 50.00% |
mark langsdorf | mark langsdorf | 10 | 5.49% | 1 | 50.00% |
| Total | 182 | 100.00% | 2 | 100.00% |
static ssize_t ahci_activity_show(struct ata_device *dev, char *buf)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_em_priv *emp = &pp->em_priv[link->pmp];
/* display the saved value of activity behavior for this
* disk.
*/
return sprintf(buf, "%d\n", emp->blink_policy);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 70 | 100.00% | 1 | 100.00% |
| Total | 70 | 100.00% | 1 | 100.00% |
static void ahci_port_init(struct device *dev, struct ata_port *ap,
int port_no, void __iomem *mmio,
void __iomem *port_mmio)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
const char *emsg = NULL;
int rc;
u32 tmp;
/* make sure port is not active */
rc = ahci_deinit_port(ap, &emsg);
if (rc)
dev_warn(dev, "%s (%d)\n", emsg, rc);
/* clear SError */
tmp = readl(port_mmio + PORT_SCR_ERR);
VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
writel(tmp, port_mmio + PORT_SCR_ERR);
/* clear port IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
if (tmp)
writel(tmp, port_mmio + PORT_IRQ_STAT);
writel(1 << port_no, mmio + HOST_IRQ_STAT);
/* mark esata ports */
tmp = readl(port_mmio + PORT_CMD);
if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
ap->pflags |= ATA_PFLAG_EXTERNAL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 135 | 75.84% | 1 | 50.00% |
manuel lauss | manuel lauss | 43 | 24.16% | 1 | 50.00% |
| Total | 178 | 100.00% | 2 | 100.00% |
void ahci_init_controller(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
int i;
void __iomem *port_mmio;
u32 tmp;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
port_mmio = ahci_port_base(ap);
if (ata_port_is_dummy(ap))
continue;
ahci_port_init(host->dev, ap, i, mmio, port_mmio);
}
tmp = readl(mmio + HOST_CTL);
VPRINTK("HOST_CTL 0x%x\n", tmp);
writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
tmp = readl(mmio + HOST_CTL);
VPRINTK("HOST_CTL 0x%x\n", tmp);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 141 | 100.00% | 1 | 100.00% |
| Total | 141 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_init_controller);
static void ahci_dev_config(struct ata_device *dev)
{
struct ahci_host_priv *hpriv = dev->link->ap->host->private_data;
if (hpriv->flags & AHCI_HFLAG_SECT255) {
dev->max_sectors = 255;
ata_dev_info(dev,
"SB600 AHCI: limiting to 255 sectors per cmd\n");
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 48 | 97.96% | 1 | 50.00% |
joe perches | joe perches | 1 | 2.04% | 1 | 50.00% |
| Total | 49 | 100.00% | 2 | 100.00% |
unsigned int ahci_dev_classify(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_taskfile tf;
u32 tmp;
tmp = readl(port_mmio + PORT_SIG);
tf.lbah = (tmp >> 24) & 0xff;
tf.lbam = (tmp >> 16) & 0xff;
tf.lbal = (tmp >> 8) & 0xff;
tf.nsect = (tmp) & 0xff;
return ata_dev_classify(&tf);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 90 | 100.00% | 1 | 100.00% |
| Total | 90 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_dev_classify);
void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
u32 opts)
{
dma_addr_t cmd_tbl_dma;
cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
pp->cmd_slot[tag].opts = cpu_to_le32(opts);
pp->cmd_slot[tag].status = 0;
pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 91 | 100.00% | 1 | 100.00% |
| Total | 91 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_fill_cmd_slot);
int ahci_kick_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
u32 tmp;
int busy, rc;
/* stop engine */
rc = ahci_stop_engine(ap);
if (rc)
goto out_restart;
/* need to do CLO?
* always do CLO if PMP is attached (AHCI-1.3 9.2)
*/
busy = status & (ATA_BUSY | ATA_DRQ);
if (!busy && !sata_pmp_attached(ap)) {
rc = 0;
goto out_restart;
}
if (!(hpriv->cap & HOST_CAP_CLO)) {
rc = -EOPNOTSUPP;
goto out_restart;
}
/* perform CLO */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD);
rc = 0;
tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO)
rc = -EIO;
/* restart engine */
out_restart:
hpriv->start_engine(ap);
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 183 | 97.34% | 1 | 33.33% |
hans de goede | hans de goede | 3 | 1.60% | 1 | 33.33% |
tejun heo | tejun heo | 2 | 1.06% | 1 | 33.33% |
| Total | 188 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_kick_engine);
static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
struct ata_taskfile *tf, int is_cmd, u16 flags,
unsigned long timeout_msec)
{
const u32 cmd_fis_len = 5; /* five dwords */
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u8 *fis = pp->cmd_tbl;
u32 tmp;
/* prep the command */
ata_tf_to_fis(tf, pmp, is_cmd, fis);
ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
/* set port value for softreset of Port Multiplier */
if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
tmp = readl(port_mmio + PORT_FBS);
tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
tmp |= pmp << PORT_FBS_DEV_OFFSET;
writel(tmp, port_mmio + PORT_FBS);
pp->fbs_last_dev = pmp;
}
/* issue & wait */
writel(1, port_mmio + PORT_CMD_ISSUE);
if (timeout_msec) {
tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
0x1, 0x1, 1, timeout_msec);
if (tmp & 0x1) {
ahci_kick_engine(ap);
return -EBUSY;
}
} else
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 157 | 73.71% | 1 | 33.33% |
xiangliang yu | xiangliang yu | 54 | 25.35% | 1 | 33.33% |
tejun heo | tejun heo | 2 | 0.94% | 1 | 33.33% |
| Total | 213 | 100.00% | 3 | 100.00% |
int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline,
int (*check_ready)(struct ata_link *link))
{
struct ata_port *ap = link->ap;
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
bool fbs_disabled = false;
int rc;
DPRINTK("ENTER\n");
/* prepare for SRST (AHCI-1.1 10.4.1) */
rc = ahci_kick_engine(ap);
if (rc && rc != -EOPNOTSUPP)
ata_link_warn(link, "failed to reset engine (errno=%d)\n", rc);
/*
* According to AHCI-1.2 9.3.9: if FBS is enable, software shall
* clear PxFBS.EN to '0' prior to issuing software reset to devices
* that is attached to port multiplier.
*/
if (!ata_is_host_link(link) && pp->fbs_enabled) {
ahci_disable_fbs(ap);
fbs_disabled = true;
}
ata_tf_init(link->device, &tf);
/* issue the first D2H Register FIS */
msecs = 0;
now = jiffies;
if (time_after(deadline, now))
msecs = jiffies_to_msecs(deadline - now);
tf.ctl |= ATA_SRST;
if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
}
/* spec says at least 5us, but be generous and sleep for 1ms */
ata_msleep(ap, 1);
/* issue the second D2H Register FIS */
tf.ctl &= ~ATA_SRST;
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* wait for link to become ready */
rc = ata_wait_after_reset(link, deadline, check_ready);
if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) {
/*
* Workaround for cases where link online status can't
* be trusted. Treat device readiness timeout as link
* offline.
*/
ata_link_info(link, "device not ready, treating as offline\n");
*class = ATA_DEV_NONE;
} else if (rc) {
/* link occupied, -ENODEV too is an error */
reason = "device not ready";
goto fail;
} else
*class = ahci_dev_classify(ap);
/* re-enable FBS if disabled before */
if (fbs_disabled)
ahci_enable_fbs(ap);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
fail:
ata_link_err(link, "softreset failed (%s)\n", reason);
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 295 | 84.05% | 1 | 20.00% |
xiangliang yu | xiangliang yu | 48 | 13.68% | 1 | 20.00% |
tejun heo | tejun heo | 5 | 1.42% | 2 | 40.00% |
joe perches | joe perches | 3 | 0.85% | 1 | 20.00% |
| Total | 351 | 100.00% | 5 | 100.00% |
int ahci_check_ready(struct ata_link *link)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
return ata_check_ready(status);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 40 | 100.00% | 1 | 100.00% |
| Total | 40 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_check_ready);
static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
int pmp = sata_srst_pmp(link);
DPRINTK("ENTER\n");
return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 47 | 100.00% | 1 | 100.00% |
| Total | 47 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_do_softreset);
static int ahci_bad_pmp_check_ready(struct ata_link *link)
{
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
/*
* There is no need to check TFDATA if BAD PMP is found due to HW bug,
* which can save timeout delay.
*/
if (irq_status & PORT_IRQ_BAD_PMP)
return -EIO;
return ata_check_ready(status);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yuan-hsin chen | yuan-hsin chen | 62 | 100.00% | 1 | 100.00% |
| Total | 62 | 100.00% | 1 | 100.00% |
static int ahci_pmp_retry_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
int pmp = sata_srst_pmp(link);
int rc;
u32 irq_sts;
DPRINTK("ENTER\n");
rc = ahci_do_softreset(link, class, pmp, deadline,
ahci_bad_pmp_check_ready);
/*
* Soft reset fails with IPMS set when PMP is enabled but
* SATA HDD/ODD is connected to SATA port, do soft reset
* again to port 0.
*/
if (rc == -EIO) {
irq_sts = readl(port_mmio + PORT_IRQ_STAT);
if (irq_sts & PORT_IRQ_BAD_PMP) {
ata_link_warn(link,
"applying PMP SRST workaround "
"and retrying\n");
rc = ahci_do_softreset(link, class, 0, deadline,
ahci_check_ready);
}
}
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yuan-hsin chen | yuan-hsin chen | 124 | 98.41% | 1 | 33.33% |
daeseok youn | daeseok youn | 1 | 0.79% | 1 | 33.33% |
wei yongjun | wei yongjun | 1 | 0.79% | 1 | 33.33% |
| Total | 126 | 100.00% | 3 | 100.00% |
static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
int rc;
DPRINTK("ENTER\n");
ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
tf.command = ATA_BUSY;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 155 | 91.18% | 1 | 33.33% |
hans de goede | hans de goede | 14 | 8.24% | 1 | 33.33% |
sergei shtylyov | sergei shtylyov | 1 | 0.59% | 1 | 33.33% |
| Total | 170 | 100.00% | 3 | 100.00% |
static void ahci_postreset(struct ata_link *link, unsigned int *class)
{
struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
u32 new_tmp, tmp;
ata_std_postreset(link, class);
/* Make sure port's ATAPI bit is set appropriately */
new_tmp = tmp = readl(port_mmio + PORT_CMD);
if (*class == ATA_DEV_ATAPI)
new_tmp |= PORT_CMD_ATAPI;
else
new_tmp &= ~PORT_CMD_ATAPI;
if (new_tmp != tmp) {
writel(new_tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 101 | 100.00% | 1 | 100.00% |
| Total | 101 | 100.00% | 1 | 100.00% |
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{
struct scatterlist *sg;
struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
unsigned int si;
VPRINTK("ENTER\n");
/*
* Next, the S/G list.
*/
for_each_sg(qc->sg, sg, qc->n_elem, si) {
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
}
return si;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 117 | 100.00% | 1 | 100.00% |
| Total | 117 | 100.00% | 1 | 100.00% |
static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
if (!sata_pmp_attached(ap) || pp->fbs_enabled)
return ata_std_qc_defer(qc);
else
return sata_pmp_qc_defer_cmd_switch(qc);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 54 | 100.00% | 1 | 100.00% |
| Total | 54 | 100.00% | 1 | 100.00% |
static void ahci_qc_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ahci_port_priv *pp = ap->private_data;
int is_atapi = ata_is_atapi(qc->tf.protocol);
void *cmd_tbl;
u32 opts;
const u32 cmd_fis_len = 5; /* five dwords */
unsigned int n_elem;
/*
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
}
n_elem = 0;
if (qc->flags & ATA_QCFLAG_DMAMAP)
n_elem = ahci_fill_sg(qc, cmd_tbl);
/*
* Fill in command slot information.
*/
opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
if (qc->tf.flags & ATA_TFLAG_WRITE)
opts |= AHCI_CMD_WRITE;
if (is_atapi)
opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
ahci_fill_cmd_slot(pp, qc->tag, opts);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 203 | 100.00% | 1 | 100.00% |
| Total | 203 | 100.00% | 1 | 100.00% |
static void ahci_fbs_dec_intr(struct ata_port *ap)
{
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs = readl(port_mmio + PORT_FBS);
int retries = 3;
DPRINTK("ENTER\n");
BUG_ON(!pp->fbs_enabled);
/* time to wait for DEC is not specified by AHCI spec,
* add a retry loop for safety.
*/
writel(fbs | PORT_FBS_DEC, port_mmio + PORT_FBS);
fbs = readl(port_mmio + PORT_FBS);
while ((fbs & PORT_FBS_DEC) && retries--) {
udelay(1);
fbs = readl(port_mmio + PORT_FBS);
}
if (fbs & PORT_FBS_DEC)
dev_err(ap->host->dev, "failed to clear device error\n");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 122 | 99.19% | 1 | 50.00% |
joe perches | joe perches | 1 | 0.81% | 1 | 50.00% |
| Total | 123 | 100.00% | 2 | 100.00% |
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
struct ata_eh_info *host_ehi = &ap->link.eh_info;
struct ata_link *link = NULL;
struct ata_queued_cmd *active_qc;
struct ata_eh_info *active_ehi;
bool fbs_need_dec = false;
u32 serror;
/* determine active link with error */
if (pp->fbs_enabled) {
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs = readl(port_mmio + PORT_FBS);
int pmp = fbs >> PORT_FBS_DWE_OFFSET;
if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
link = &ap->pmp_link[pmp];
fbs_need_dec = true;
}
} else
ata_for_each_link(link, ap, EDGE)
if (ata_link_active(link))
break;
if (!link)
link = &ap->link;
active_qc = ata_qc_from_tag(ap, link->active_tag);
active_ehi = &link->eh_info;
/* record irq stat */
ata_ehi_clear_desc(host_ehi);
ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */
ahci_scr_read(&ap->link, SCR_ERROR, &serror);
ahci_scr_write(&ap->link, SCR_ERROR, serror);
host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
irq_stat &= ~PORT_IRQ_IF_ERR;
if (irq_stat & PORT_IRQ_TF_ERR) {
/* If qc is active, charge it; otherwise, the active
* link. There's no active qc on NCQ errors. It will
* be determined by EH by reading log page 10h.
*/
if (active_qc)
active_qc->err_mask |= AC_ERR_DEV;
else
active_ehi->err_mask |= AC_ERR_DEV;
if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
host_ehi->serror &= ~SERR_INTERNAL;
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
u32 *unk = pp->rx_fis + RX_FIS_UNK;
active_ehi->err_mask |= AC_ERR_HSM;
active_ehi->action |= ATA_EH_RESET;
ata_ehi_push_desc(active_ehi,
"unknown FIS %08x %08x %08x %08x" ,
unk[0], unk[1], unk[2], unk[3]);
}
if (sata_pmp_attached(ap) && (irq_stat & PORT_IRQ_BAD_PMP)) {
active_ehi->err_mask |= AC_ERR_HSM;
active_ehi->action |= ATA_EH_RESET;
ata_ehi_push_desc(active_ehi, "incorrect PMP");
}
if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
host_ehi->err_mask |= AC_ERR_HOST_BUS;
host_ehi->action |= ATA_EH_RESET;
ata_ehi_push_desc(host_ehi, "host bus error");
}
if (irq_stat & PORT_IRQ_IF_ERR) {
if (fbs_need_dec)
active_ehi->err_mask |= AC_ERR_DEV;
else {
host_ehi->err_mask |= AC_ERR_ATA_BUS;
host_ehi->action |= ATA_EH_RESET;
}
ata_ehi_push_desc(host_ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
ata_ehi_hotplugged(host_ehi);
ata_ehi_push_desc(host_ehi, "%s",
irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
/* okay, let's hand over to EH */
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
else if (fbs_need_dec) {
ata_link_abort(link);
ahci_fbs_dec_intr(ap);
} else
ata_port_abort(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 517 | 100.00% | 1 | 100.00% |
| Total | 517 | 100.00% | 1 | 100.00% |
static void ahci_handle_port_interrupt(struct ata_port *ap,
void __iomem *port_mmio, u32 status)
{
struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 qc_active = 0;
int rc;
/* ignore BAD_PMP while resetting */
if (unlikely(resetting))
status &= ~PORT_IRQ_BAD_PMP;
if (sata_lpm_ignore_phy_events(&ap->link)) {
status &= ~PORT_IRQ_PHYRDY;
ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
}
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
}
if (status & PORT_IRQ_SDB_FIS) {
/* If SNotification is available, leave notification
* handling to sata_async_notification(). If not,
* emulate it by snooping SDB FIS RX area.
*
* Snooping FIS RX area is probably cheaper than
* poking SNotification but some constrollers which
* implement SNotification, ICH9 for example, don't
* store AN SDB FIS into receive area.
*/
if (hpriv->cap & HOST_CAP_SNTF)
sata_async_notification(ap);
else {
/* If the 'N' bit in word 0 of the FIS is set,
* we just received asynchronous notification.
* Tell libata about it.
*
* Lack of SNotification should not appear in
* ahci 1.2, so the workaround is unnecessary
* when FBS is enabled.
*/
if (pp->fbs_enabled)
WARN_ON_ONCE(1);
else {
const __le32 *f = pp->rx_fis + RX_FIS_SDB;
u32 f0 = le32_to_cpu(f[0]);
if (f0 & (1 << 15))
sata_async_notification(ap);
}
}
}
/* pp->active_link is not reliable once FBS is enabled, both
* PORT_SCR_ACT and PORT_CMD_ISSUE should be checked because
* NCQ and non-NCQ commands may be in flight at the same time.
*/
if (pp->fbs_enabled) {
if (ap->qc_active) {
qc_active = readl(port_mmio + PORT_SCR_ACT);
qc_active |= readl(port_mmio + PORT_CMD_ISSUE);
}
} else {
/* pp->active_link is valid iff any command is in flight */
if (ap->qc_active && pp->active_link->sactive)
qc_active = readl(port_mmio + PORT_SCR_ACT);
else
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
}
rc = ata_qc_complete_multiple(ap, qc_active);
/* while resetting, invalid completions are expected */
if (unlikely(rc < 0 && !resetting)) {
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alexander gordeev | alexander gordeev | 178 | 55.45% | 1 | 25.00% |
anton vorontsov | anton vorontsov | 136 | 42.37% | 1 | 25.00% |
gabriele mazzotta | gabriele mazzotta | 4 | 1.25% | 1 | 25.00% |
tejun heo | tejun heo | 3 | 0.93% | 1 | 25.00% |
| Total | 321 | 100.00% | 4 | 100.00% |
static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 status;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
ahci_handle_port_interrupt(ap, port_mmio, status);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alexander gordeev | alexander gordeev | 44 | 86.27% | 2 | 50.00% |
tejun heo | tejun heo | 6 | 11.76% | 1 | 25.00% |
rashika kheria | rashika kheria | 1 | 1.96% | 1 | 25.00% |
| Total | 51 | 100.00% | 4 | 100.00% |
static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
{
struct ata_port *ap = dev_instance;
void __iomem *port_mmio = ahci_port_base(ap);
u32 status;
VPRINTK("ENTER\n");
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
spin_lock(ap->lock);
ahci_handle_port_interrupt(ap, port_mmio, status);
spin_unlock(ap->lock);
VPRINTK("EXIT\n");
return IRQ_HANDLED;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alexander gordeev | alexander gordeev | 61 | 70.11% | 3 | 60.00% |
dan williams | dan williams | 20 | 22.99% | 1 | 20.00% |
anton vorontsov | anton vorontsov | 6 | 6.90% | 1 | 20.00% |
| Total | 87 | 100.00% | 5 | 100.00% |
u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
{
unsigned int i, handled = 0;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
if (!(irq_masked & (1 << i)))
continue;
ap = host->ports[i];
if (ap) {
ahci_port_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
if (ata_ratelimit())
dev_warn(host->dev,
"interrupt on disabled port %u\n", i);
}
handled = 1;
}
return handled;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 104 | 88.89% | 1 | 25.00% |
suman tripathi | suman tripathi | 11 | 9.40% | 1 | 25.00% |
tejun heo | tejun heo | 1 | 0.85% | 1 | 25.00% |
joe perches | joe perches | 1 | 0.85% | 1 | 25.00% |
| Total | 117 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv;
unsigned int rc = 0;
void __iomem *mmio;
u32 irq_stat, irq_masked;
VPRINTK("ENTER\n");
hpriv = host->private_data;
mmio = hpriv->mmio;
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
if (!irq_stat)
return IRQ_NONE;
irq_masked = irq_stat & hpriv->port_map;
spin_lock(&host->lock);
rc = ahci_handle_port_intr(host, irq_masked);
/* HOST_IRQ_STAT behaves as level triggered latch meaning that
* it should be cleared after all the port events are cleared;
* otherwise, it will raise a spurious interrupt after each
* valid one. Please read section 10.6.2 of ahci 1.1 for more
* information.
*
* Also, use the unmasked value to clear interrupt as spurious
* pending event on a dummy port might cause screaming IRQ.
*/
writel(irq_stat, mmio + HOST_IRQ_STAT);
spin_unlock(&host->lock);
VPRINTK("EXIT\n");
return IRQ_RETVAL(rc);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
suman tripathi | suman tripathi | 86 | 66.15% | 1 | 25.00% |
anton vorontsov | anton vorontsov | 33 | 25.38% | 1 | 25.00% |
tejun heo | tejun heo | 11 | 8.46% | 2 | 50.00% |
| Total | 130 | 100.00% | 4 | 100.00% |
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_port_priv *pp = ap->private_data;
/* Keep track of the currently active link. It will be used
* in completion path to determine whether NCQ phase is in
* progress.
*/
pp->active_link = qc->dev->link;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
u32 fbs = readl(port_mmio + PORT_FBS);
fbs &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
writel(fbs, port_mmio + PORT_FBS);
pp->fbs_last_dev = qc->dev->link->pmp;
}
writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
ahci_sw_activity(qc->dev->link);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 170 | 100.00% | 1 | 100.00% |
| Total | 170 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_qc_issue);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
{
struct ahci_port_priv *pp = qc->ap->private_data;
u8 *rx_fis = pp->rx_fis;
if (pp->fbs_enabled)
rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
/*
* After a successful execution of an ATA PIO data-in command,
* the device doesn't send D2H Reg FIS to update the TF and
* the host should take TF and E_Status from the preceding PIO
* Setup FIS.
*/
if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
!(qc->flags & ATA_QCFLAG_FAILED)) {
ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
} else
ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
return true;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tejun heo | tejun heo | 61 | 51.26% | 1 | 50.00% |
anton vorontsov | anton vorontsov | 58 | 48.74% | 1 | 50.00% |
| Total | 119 | 100.00% | 2 | 100.00% |
static void ahci_freeze(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
/* turn IRQ off */
writel(0, port_mmio + PORT_IRQ_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 31 | 100.00% | 1 | 100.00% |
| Total | 31 | 100.00% | 1 | 100.00% |
static void ahci_thaw(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = hpriv->mmio;
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
struct ahci_port_priv *pp = ap->private_data;
/* clear IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
writel(tmp, port_mmio + PORT_IRQ_STAT);
writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
/* turn IRQ back on */
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 97 | 100.00% | 1 | 100.00% |
| Total | 97 | 100.00% | 1 | 100.00% |
void ahci_error_handler(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
hpriv->start_engine(ap);
}
sata_pmp_error_handler(ap);
if (!ata_dev_enabled(ap->link.device))
ahci_stop_engine(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 38 | 55.07% | 1 | 33.33% |
tejun heo | tejun heo | 17 | 24.64% | 1 | 33.33% |
hans de goede | hans de goede | 14 | 20.29% | 1 | 33.33% |
| Total | 69 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_error_handler);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
if (qc->flags & ATA_QCFLAG_FAILED)
ahci_kick_engine(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 34 | 100.00% | 1 | 100.00% |
| Total | 34 | 100.00% | 1 | 100.00% |
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
int rc;
unsigned int err_mask;
devslp = readl(port_mmio + PORT_DEVSLP);
if (!(devslp & PORT_DEVSLP_DSP)) {
dev_info(ap->host->dev, "port does not support device sleep\n");
return;
}
/* disable device sleep */
if (!sleep) {
if (devslp & PORT_DEVSLP_ADSE) {
writel(devslp & ~PORT_DEVSLP_ADSE,
port_mmio + PORT_DEVSLP);
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_DISABLE,
SATA_DEVSLP);
if (err_mask && err_mask != AC_ERR_DEV)
ata_dev_warn(dev, "failed to disable DEVSLP\n");
}
return;
}
/* device sleep was already enabled */
if (devslp & PORT_DEVSLP_ADSE)
return;
/* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */
rc = ahci_stop_engine(ap);
if (rc)
return;
dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
dito = devslp_idle_timeout / (dm + 1);
if (dito > 0x3ff)
dito = 0x3ff;
/* Use the nominal value 10 ms if the read MDAT is zero,
* the nominal value of DETO is 20 ms.
*/
if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
ATA_LOG_DEVSLP_VALID_MASK) {
mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
ATA_LOG_DEVSLP_MDAT_MASK;
if (!mdat)
mdat = 10;
deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
if (!deto)
deto = 20;
} else {
mdat = 10;
deto = 20;
}
devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
(mdat << PORT_DEVSLP_MDAT_OFFSET) |
(deto << PORT_DEVSLP_DETO_OFFSET) |
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
hpriv->start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE,
SATA_DEVSLP);
if (err_mask && err_mask != AC_ERR_DEV)
ata_dev_warn(dev, "failed to enable DEVSLP\n");
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
shane huang | shane huang | 317 | 95.48% | 2 | 50.00% |
hans de goede | hans de goede | 14 | 4.22% | 1 | 25.00% |
gabriele mazzotta | gabriele mazzotta | 1 | 0.30% | 1 | 25.00% |
| Total | 332 | 100.00% | 4 | 100.00% |
static void ahci_enable_fbs(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
int rc;
if (!pp->fbs_supported)
return;
fbs = readl(port_mmio + PORT_FBS);
if (fbs & PORT_FBS_EN) {
pp->fbs_enabled = true;
pp->fbs_last_dev = -1; /* initialization */
return;
}
rc = ahci_stop_engine(ap);
if (rc)
return;
writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
fbs = readl(port_mmio + PORT_FBS);
if (fbs & PORT_FBS_EN) {
dev_info(ap->host->dev, "FBS is enabled\n");
pp->fbs_enabled = true;
pp->fbs_last_dev = -1; /* initialization */
} else
dev_err(ap->host->dev, "Failed to enable FBS\n");
hpriv->start_engine(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 154 | 90.06% | 1 | 33.33% |
hans de goede | hans de goede | 14 | 8.19% | 1 | 33.33% |
joe perches | joe perches | 3 | 1.75% | 1 | 33.33% |
| Total | 171 | 100.00% | 3 | 100.00% |
static void ahci_disable_fbs(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
int rc;
if (!pp->fbs_supported)
return;
fbs = readl(port_mmio + PORT_FBS);
if ((fbs & PORT_FBS_EN) == 0) {
pp->fbs_enabled = false;
return;
}
rc = ahci_stop_engine(ap);
if (rc)
return;
writel(fbs & ~PORT_FBS_EN, port_mmio + PORT_FBS);
fbs = readl(port_mmio + PORT_FBS);
if (fbs & PORT_FBS_EN)
dev_err(ap->host->dev, "Failed to disable FBS\n");
else {
dev_info(ap->host->dev, "FBS is disabled\n");
pp->fbs_enabled = false;
}
hpriv->start_engine(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 143 | 89.38% | 1 | 33.33% |
hans de goede | hans de goede | 14 | 8.75% | 1 | 33.33% |
joe perches | joe perches | 3 | 1.88% | 1 | 33.33% |
| Total | 160 | 100.00% | 3 | 100.00% |
static void ahci_pmp_attach(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
cmd = readl(port_mmio + PORT_CMD);
cmd |= PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
ahci_enable_fbs(ap);
pp->intr_mask |= PORT_IRQ_BAD_PMP;
/*
* We must not change the port interrupt mask register if the
* port is marked frozen, the value in pp->intr_mask will be
* restored later when the port is thawed.
*
* Note that during initialization, the port is marked as
* frozen since the irq handler is not yet registered.
*/
if (!(ap->pflags & ATA_PFLAG_FROZEN))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 77 | 86.52% | 1 | 50.00% |
maxime bizon | maxime bizon | 12 | 13.48% | 1 | 50.00% |
| Total | 89 | 100.00% | 2 | 100.00% |
static void ahci_pmp_detach(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_port_priv *pp = ap->private_data;
u32 cmd;
ahci_disable_fbs(ap);
cmd = readl(port_mmio + PORT_CMD);
cmd &= ~PORT_CMD_PMP;
writel(cmd, port_mmio + PORT_CMD);
pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
/* see comment above in ahci_pmp_attach() */
if (!(ap->pflags & ATA_PFLAG_FROZEN))
writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 79 | 86.81% | 1 | 50.00% |
maxime bizon | maxime bizon | 12 | 13.19% | 1 | 50.00% |
| Total | 91 | 100.00% | 2 | 100.00% |
int ahci_port_resume(struct ata_port *ap)
{
ahci_rpm_get_port(ap);
ahci_power_up(ap);
ahci_start_port(ap);
if (sata_pmp_attached(ap))
ahci_pmp_attach(ap);
else
ahci_pmp_detach(ap);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 41 | 89.13% | 1 | 50.00% |
mika westerberg | mika westerberg | 5 | 10.87% | 1 | 50.00% |
| Total | 46 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_port_resume);
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
const char *emsg = NULL;
int rc;
rc = ahci_deinit_port(ap, &emsg);
if (rc == 0)
ahci_power_down(ap);
else {
ata_port_err(ap, "%s (%d)\n", emsg, rc);
ata_port_freeze(ap);
}
ahci_rpm_put_port(ap);
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 65 | 90.28% | 1 | 25.00% |
mika westerberg | mika westerberg | 5 | 6.94% | 1 | 25.00% |
joe perches | joe perches | 1 | 1.39% | 1 | 25.00% |
tejun heo | tejun heo | 1 | 1.39% | 1 | 25.00% |
| Total | 72 | 100.00% | 4 | 100.00% |
#endif
static int ahci_port_start(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct device *dev = ap->host->dev;
struct ahci_port_priv *pp;
void *mem;
dma_addr_t mem_dma;
size_t dma_sz, rx_fis_sz;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
if (ap->host->n_ports > 1) {
pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
if (!pp->irq_desc) {
devm_kfree(dev, pp);
return -ENOMEM;
}
snprintf(pp->irq_desc, 8,
"%s%d", dev_driver_string(dev), ap->port_no);
}
/* check FBS capability */
if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd = readl(port_mmio + PORT_CMD);
if (cmd & PORT_CMD_FBSCP)
pp->fbs_supported = true;
else if (hpriv->flags & AHCI_HFLAG_YES_FBS) {
dev_info(dev, "port %d can do FBS, forcing FBSCP\n",
ap->port_no);
pp->fbs_supported = true;
} else
dev_warn(dev, "port %d is not capable of FBS\n",
ap->port_no);
}
if (pp->fbs_supported) {
dma_sz = AHCI_PORT_PRIV_FBS_DMA_SZ;
rx_fis_sz = AHCI_RX_FIS_SZ * 16;
} else {
dma_sz = AHCI_PORT_PRIV_DMA_SZ;
rx_fis_sz = AHCI_RX_FIS_SZ;
}
mem = dmam_alloc_coherent(dev, dma_sz, &mem_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
memset(mem, 0, dma_sz);
/*
* First item in chunk of DMA memory: 32-slot command table,
* 32 bytes each in size
*/
pp->cmd_slot = mem;
pp->cmd_slot_dma = mem_dma;
mem += AHCI_CMD_SLOT_SZ;
mem_dma += AHCI_CMD_SLOT_SZ;
/*
* Second item: Received-FIS area
*/
pp->rx_fis = mem;
pp->rx_fis_dma = mem_dma;
mem += rx_fis_sz;
mem_dma += rx_fis_sz;
/*
* Third item: data area for storing a single command
* and its scatter-gather table
*/
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
/*
* Save off initial list of interrupts to be enabled.
* This could be changed later
*/
pp->intr_mask = DEF_PORT_IRQ;
/*
* Switch to per-port locking in case each port has its own MSI vector.
*/
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI) {
spin_lock_init(&pp->lock);
ap->lock = &pp->lock;
}
ap->private_data = pp;
/* engage engines, captain */
return ahci_port_resume(ap);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 266 | 67.68% | 1 | 16.67% |
alexander gordeev | alexander gordeev | 82 | 20.87% | 2 | 33.33% |
tejun heo | tejun heo | 43 | 10.94% | 2 | 33.33% |
joe perches | joe perches | 2 | 0.51% | 1 | 16.67% |
| Total | 393 | 100.00% | 6 | 100.00% |
static void ahci_port_stop(struct ata_port *ap)
{
const char *emsg = NULL;
int rc;
/* de-initialize port */
rc = ahci_deinit_port(ap, &emsg);
if (rc)
ata_port_warn(ap, "%s (%d)\n", emsg, rc);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 46 | 97.87% | 1 | 50.00% |
joe perches | joe perches | 1 | 2.13% | 1 | 50.00% |
| Total | 47 | 100.00% | 2 | 100.00% |
void ahci_print_info(struct ata_host *host, const char *scc_s)
{
struct ahci_host_priv *hpriv = host->private_data;
u32 vers, cap, cap2, impl, speed;
const char *speed_s;
vers = hpriv->version;
cap = hpriv->cap;
cap2 = hpriv->cap2;
impl = hpriv->port_map;
speed = (cap >> 20) & 0xf;
if (speed == 1)
speed_s = "1.5";
else if (speed == 2)
speed_s = "3";
else if (speed == 3)
speed_s = "6";
else
speed_s = "?";
dev_info(host->dev,
"AHCI %02x%02x.%02x%02x "
"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
,
(vers >> 24) & 0xff,
(vers >> 16) & 0xff,
(vers >> 8) & 0xff,
vers & 0xff,
((cap >> 8) & 0x1f) + 1,
(cap & 0x1f) + 1,
speed_s,
impl,
scc_s);
dev_info(host->dev,
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
"%s%s\n"
,
cap & HOST_CAP_64 ? "64bit " : "",
cap & HOST_CAP_NCQ ? "ncq " : "",
cap & HOST_CAP_SNTF ? "sntf " : "",
cap & HOST_CAP_MPS ? "ilck " : "",
cap & HOST_CAP_SSS ? "stag " : "",
cap & HOST_CAP_ALPM ? "pm " : "",
cap & HOST_CAP_LED ? "led " : "",
cap & HOST_CAP_CLO ? "clo " : "",
cap & HOST_CAP_ONLY ? "only " : "",
cap & HOST_CAP_PMP ? "pmp " : "",
cap & HOST_CAP_FBS ? "fbs " : "",
cap & HOST_CAP_PIO_MULTI ? "pio " : "",
cap & HOST_CAP_SSC ? "slum " : "",
cap & HOST_CAP_PART ? "part " : "",
cap & HOST_CAP_CCC ? "ccc " : "",
cap & HOST_CAP_EMS ? "ems " : "",
cap & HOST_CAP_SXS ? "sxs " : "",
cap2 & HOST_CAP2_DESO ? "deso " : "",
cap2 & HOST_CAP2_SADM ? "sadm " : "",
cap2 & HOST_CAP2_SDS ? "sds " : "",
cap2 & HOST_CAP2_APST ? "apst " : "",
cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
cap2 & HOST_CAP2_BOH ? "boh " : ""
);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 343 | 92.20% | 1 | 33.33% |
shane huang | shane huang | 26 | 6.99% | 1 | 33.33% |
mika westerberg | mika westerberg | 3 | 0.81% | 1 | 33.33% |
| Total | 372 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_print_info);
void ahci_set_em_messages(struct ahci_host_priv *hpriv,
struct ata_port_info *pi)
{
u8 messages;
void __iomem *mmio = hpriv->mmio;
u32 em_loc = readl(mmio + HOST_EM_LOC);
u32 em_ctl = readl(mmio + HOST_EM_CTL);
if (!ahci_em_messages || !(hpriv->cap & HOST_CAP_EMS))
return;
messages = (em_ctl & EM_CTRL_MSG_TYPE) >> 16;
if (messages) {
/* store em_loc */
hpriv->em_loc = ((em_loc >> 16) * 4);
hpriv->em_buf_sz = ((em_loc & 0xff) * 4);
hpriv->em_msg_type = messages;
pi->flags |= ATA_FLAG_EM;
if (!(em_ctl & EM_CTL_ALHD))
pi->flags |= ATA_FLAG_SW_ACTIVITY;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 114 | 85.07% | 1 | 33.33% |
harry zhang | harry zhang | 20 | 14.93% | 2 | 66.67% |
| Total | 134 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_set_em_messages);
static int ahci_host_activate_multi_irqs(struct ata_host *host,
struct scsi_host_template *sht)
{
struct ahci_host_priv *hpriv = host->private_data;
int i, rc;
rc = ata_host_start(host);
if (rc)
return rc;
/*
* Requests IRQs according to AHCI-1.1 when multiple MSIs were
* allocated. That is one MSI per port, starting from @irq.
*/
for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data;
int irq = ahci_irq_vector(hpriv, i);
/* Do not receive interrupts sent by dummy ports */
if (!pp) {
disable_irq(irq + i);
continue;
}
rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard,
0, pp->irq_desc, host->ports[i]);
if (rc)
return rc;
ata_port_desc(host->ports[i], "irq %d", irq);
}
return ata_host_register(host, sht);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alexander gordeev | alexander gordeev | 129 | 82.17% | 2 | 25.00% |
dan williams | dan williams | 27 | 17.20% | 5 | 62.50% |
robert richter | robert richter | 1 | 0.64% | 1 | 12.50% |
| Total | 157 | 100.00% | 8 | 100.00% |
/**
* ahci_host_activate - start AHCI host, request IRQs and register it
* @host: target ATA host
* @sht: scsi_host_template to use when registering the host
*
* LOCKING:
* Inherited from calling layer (may sleep).
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
{
struct ahci_host_priv *hpriv = host->private_data;
int irq = hpriv->irq;
int rc;
if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
if (hpriv->irq_handler)
dev_warn(host->dev,
"both AHCI_HFLAG_MULTI_MSI flag set and custom irq handler implemented\n");
rc = ahci_host_activate_multi_irqs(host, sht);
} else {
rc = ata_host_activate(host, irq, hpriv->irq_handler,
IRQF_SHARED, sht);
}
return rc;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alexander gordeev | alexander gordeev | 49 | 51.58% | 1 | 14.29% |
suman tripathi | suman tripathi | 30 | 31.58% | 2 | 28.57% |
robert richter | robert richter | 7 | 7.37% | 1 | 14.29% |
tejun heo | tejun heo | 4 | 4.21% | 1 | 14.29% |
dan williams | dan williams | 4 | 4.21% | 1 | 14.29% |
sander eikelenboom | sander eikelenboom | 1 | 1.05% | 1 | 14.29% |
| Total | 95 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL_GPL(ahci_host_activate);
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Common AHCI SATA low-level routines");
MODULE_LICENSE("GPL");
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton vorontsov | anton vorontsov | 8511 | 71.68% | 1 | 1.49% |
harry zhang | harry zhang | 725 | 6.11% | 3 | 4.48% |
alexander gordeev | alexander gordeev | 548 | 4.62% | 6 | 8.96% |
shane huang | shane huang | 432 | 3.64% | 2 | 2.99% |
tejun heo | tejun heo | 341 | 2.87% | 14 | 20.90% |
yuan-hsin chen | yuan-hsin chen | 227 | 1.91% | 1 | 1.49% |
suman tripathi | suman tripathi | 167 | 1.41% | 4 | 5.97% |
hannes reinecke | hannes reinecke | 146 | 1.23% | 1 | 1.49% |
mika westerberg | mika westerberg | 144 | 1.21% | 2 | 2.99% |
xiangliang yu | xiangliang yu | 102 | 0.86% | 2 | 2.99% |
hans de goede | hans de goede | 89 | 0.75% | 1 | 1.49% |
danesh petigara | danesh petigara | 85 | 0.72% | 1 | 1.49% |
dan williams | dan williams | 54 | 0.45% | 5 | 7.46% |
manuel lauss | manuel lauss | 43 | 0.36% | 1 | 1.49% |
jacob pan | jacob pan | 35 | 0.29% | 1 | 1.49% |
joe perches | joe perches | 30 | 0.25% | 2 | 2.99% |
kefeng wang | kefeng wang | 30 | 0.25% | 1 | 1.49% |
mark langsdorf | mark langsdorf | 30 | 0.25% | 1 | 1.49% |
brian norris | brian norris | 27 | 0.23% | 1 | 1.49% |
maxime bizon | maxime bizon | 24 | 0.20% | 1 | 1.49% |
antoine tenart | antoine tenart | 15 | 0.13% | 1 | 1.49% |
daeseok youn | daeseok youn | 15 | 0.13% | 2 | 2.99% |
david milburn | david milburn | 10 | 0.08% | 1 | 1.49% |
robert richter | robert richter | 9 | 0.08% | 1 | 1.49% |
liu chuansheng | liu chuansheng | 8 | 0.07% | 1 | 1.49% |
srinivas kandagatla | srinivas kandagatla | 6 | 0.05% | 1 | 1.49% |
rob herring | rob herring | 5 | 0.04% | 1 | 1.49% |
richard zhu | richard zhu | 5 | 0.04% | 1 | 1.49% |
gabriele mazzotta | gabriele mazzotta | 5 | 0.04% | 2 | 2.99% |
lukasz dorau | lukasz dorau | 2 | 0.02% | 1 | 1.49% |
sander eikelenboom | sander eikelenboom | 1 | 0.01% | 1 | 1.49% |
rashika kheria | rashika kheria | 1 | 0.01% | 1 | 1.49% |
sergei shtylyov | sergei shtylyov | 1 | 0.01% | 1 | 1.49% |
wei yongjun | wei yongjun | 1 | 0.01% | 1 | 1.49% |
| Total | 11874 | 100.00% | 67 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.