Commit 4c521c8e authored by Robert Hancock's avatar Robert Hancock Committed by Jeff Garzik

ahci: display all AHCI 1.3 HBA capability flags (v2)

Update the AHCI driver to display all of the HBA capabilities defined in the
AHCI 1.3 specification. Some of these are in a new CAP2 (HBA Capabilities
Extended) register which is only defined on AHCI 1.2 or later. The spec says
that undefined registers should always return 0 on read, but to be safe we
assume a value of 0 unless the controller reports AHCI version 1.2 or later.
The value can also be retrieved through sysfs as with the existing capability
field.

For example, on an Intel Ibex Peak (PCH) controller:

ahci 0000:00:1f.2: flags: 64bit ncq sntf stag pm led clo pmp pio slum part ems
sxs apst

We don't do anything special with the new flags yet.

Also, change the code that displays the flags to use the same bit enumerations
that are used to control actual operation.
Signed-off-by: default avatarRobert Hancock <hancockrwd@gmail.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent c21c8066
...@@ -122,6 +122,7 @@ enum { ...@@ -122,6 +122,7 @@ enum {
HOST_VERSION = 0x10, /* AHCI spec. version compliancy */ HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
HOST_EM_LOC = 0x1c, /* Enclosure Management location */ HOST_EM_LOC = 0x1c, /* Enclosure Management location */
HOST_EM_CTL = 0x20, /* Enclosure Management Control */ HOST_EM_CTL = 0x20, /* Enclosure Management Control */
HOST_CAP2 = 0x24, /* host capabilities, extended */
/* HOST_CTL bits */ /* HOST_CTL bits */
HOST_RESET = (1 << 0), /* reset controller; self-clear */ HOST_RESET = (1 << 0), /* reset controller; self-clear */
...@@ -129,16 +130,29 @@ enum { ...@@ -129,16 +130,29 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */ /* HOST_CAP bits */
HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
HOST_CAP_SSC = (1 << 14), /* Slumber capable */ HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
HOST_CAP_PART = (1 << 13), /* Partial state capable */
HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */ HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_LED = (1 << 25), /* Supports activity LED */
HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
/* HOST_CAP2 bits */
HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
/* registers for each SATA port */ /* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */ PORT_LST_ADDR = 0x00, /* command list DMA addr */
PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */ PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
...@@ -267,8 +281,10 @@ struct ahci_em_priv { ...@@ -267,8 +281,10 @@ struct ahci_em_priv {
struct ahci_host_priv { struct ahci_host_priv {
unsigned int flags; /* AHCI_HFLAG_* */ unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */ u32 cap; /* cap to use */
u32 cap2; /* cap2 to use */
u32 port_map; /* port map to use */ u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */ u32 saved_cap; /* saved initial cap */
u32 saved_cap2; /* saved initial cap2 */
u32 saved_port_map; /* saved initial port_map */ u32 saved_port_map; /* saved initial port_map */
u32 em_loc; /* enclosure management location */ u32 em_loc; /* enclosure management location */
}; };
...@@ -331,12 +347,15 @@ static void ahci_init_sw_activity(struct ata_link *link); ...@@ -331,12 +347,15 @@ static void ahci_init_sw_activity(struct ata_link *link);
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);
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, static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
static ssize_t ahci_show_port_cmd(struct device *dev, static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
...@@ -345,6 +364,7 @@ static struct device_attribute *ahci_shost_attrs[] = { ...@@ -345,6 +364,7 @@ static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_em_message_type, &dev_attr_em_message_type,
&dev_attr_em_message, &dev_attr_em_message,
&dev_attr_ahci_host_caps, &dev_attr_ahci_host_caps,
&dev_attr_ahci_host_cap2,
&dev_attr_ahci_host_version, &dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd, &dev_attr_ahci_port_cmd,
NULL NULL
...@@ -733,6 +753,16 @@ static ssize_t ahci_show_host_caps(struct device *dev, ...@@ -733,6 +753,16 @@ static ssize_t ahci_show_host_caps(struct device *dev,
return sprintf(buf, "%x\n", hpriv->cap); return sprintf(buf, "%x\n", hpriv->cap);
} }
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);
}
static ssize_t ahci_show_host_version(struct device *dev, static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -772,7 +802,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, ...@@ -772,7 +802,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
struct ahci_host_priv *hpriv) struct ahci_host_priv *hpriv)
{ {
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
u32 cap, port_map; u32 cap, cap2, vers, port_map;
int i; int i;
int mv; int mv;
...@@ -785,6 +815,14 @@ static void ahci_save_initial_config(struct pci_dev *pdev, ...@@ -785,6 +815,14 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP); hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL); 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 */ /* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) { if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev, dev_printk(KERN_INFO, &pdev->dev,
...@@ -870,6 +908,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev, ...@@ -870,6 +908,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
/* record values to use during operation */ /* record values to use during operation */
hpriv->cap = cap; hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->port_map = port_map; hpriv->port_map = port_map;
} }
...@@ -888,6 +927,8 @@ static void ahci_restore_initial_config(struct ata_host *host) ...@@ -888,6 +927,8 @@ static void ahci_restore_initial_config(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
writel(hpriv->saved_cap, mmio + HOST_CAP); 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); writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
} }
...@@ -2535,13 +2576,14 @@ static void ahci_print_info(struct ata_host *host) ...@@ -2535,13 +2576,14 @@ static void ahci_print_info(struct ata_host *host)
struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev); struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 vers, cap, impl, speed; u32 vers, cap, cap2, impl, speed;
const char *speed_s; const char *speed_s;
u16 cc; u16 cc;
const char *scc_s; const char *scc_s;
vers = readl(mmio + HOST_VERSION); vers = readl(mmio + HOST_VERSION);
cap = hpriv->cap; cap = hpriv->cap;
cap2 = hpriv->cap2;
impl = hpriv->port_map; impl = hpriv->port_map;
speed = (cap >> 20) & 0xf; speed = (cap >> 20) & 0xf;
...@@ -2584,25 +2626,29 @@ static void ahci_print_info(struct ata_host *host) ...@@ -2584,25 +2626,29 @@ static void ahci_print_info(struct ata_host *host)
"flags: " "flags: "
"%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s"
"%s\n" "%s%s%s%s%s%s\n"
, ,
cap & (1 << 31) ? "64bit " : "", cap & HOST_CAP_64 ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "", cap & HOST_CAP_NCQ ? "ncq " : "",
cap & (1 << 29) ? "sntf " : "", cap & HOST_CAP_SNTF ? "sntf " : "",
cap & (1 << 28) ? "ilck " : "", cap & HOST_CAP_MPS ? "ilck " : "",
cap & (1 << 27) ? "stag " : "", cap & HOST_CAP_SSS ? "stag " : "",
cap & (1 << 26) ? "pm " : "", cap & HOST_CAP_ALPM ? "pm " : "",
cap & (1 << 25) ? "led " : "", cap & HOST_CAP_LED ? "led " : "",
cap & HOST_CAP_CLO ? "clo " : "",
cap & (1 << 24) ? "clo " : "", cap & HOST_CAP_ONLY ? "only " : "",
cap & (1 << 19) ? "nz " : "", cap & HOST_CAP_PMP ? "pmp " : "",
cap & (1 << 18) ? "only " : "", cap & HOST_CAP_FBS ? "fbs " : "",
cap & (1 << 17) ? "pmp " : "", cap & HOST_CAP_PIO_MULTI ? "pio " : "",
cap & (1 << 15) ? "pio " : "", cap & HOST_CAP_SSC ? "slum " : "",
cap & (1 << 14) ? "slum " : "", cap & HOST_CAP_PART ? "part " : "",
cap & (1 << 13) ? "part " : "", cap & HOST_CAP_CCC ? "ccc " : "",
cap & (1 << 6) ? "ems ": "" cap & HOST_CAP_EMS ? "ems " : "",
cap & HOST_CAP_SXS ? "sxs " : "",
cap2 & HOST_CAP2_APST ? "apst " : "",
cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
cap2 & HOST_CAP2_BOH ? "boh " : ""
); );
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment