#include <linux/libata.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "2.1"
+#define DRV_VERSION "2.3"
enum {
AHCI_MAX_PORTS = 32,
AHCI_MAX_SG = 168, /* hardware max is 64K */
AHCI_DMA_BOUNDARY = 0xffffffff,
- AHCI_USE_CLUSTERING = 0,
+ AHCI_USE_CLUSTERING = 1,
AHCI_MAX_CMDS = 32,
AHCI_CMD_SZ = 32,
AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
board_ahci_vt8251 = 2,
board_ahci_ign_iferr = 3,
board_ahci_sb600 = 4,
+ board_ahci_mv = 5,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
+ AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
+ AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
+ AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY,
+ ATA_FLAG_SKIP_D2H_BSY |
+ ATA_FLAG_ACPI_SATA,
};
struct ahci_cmd_hdr {
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+static int ahci_port_resume(struct ata_port *ap);
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts);
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
-static int ahci_port_resume(struct ata_port *ap);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
#endif
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
-#ifdef CONFIG_PM
- .suspend = ata_scsi_device_suspend,
- .resume = ata_scsi_device_resume,
-#endif
};
static const struct ata_port_operations ahci_ops = {
{
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_pi */
{
.flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
.pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
.flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
AHCI_FLAG_NO_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
.flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
.pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
.flags = AHCI_FLAG_COMMON |
- AHCI_FLAG_IGN_SERR_INTERNAL,
+ AHCI_FLAG_IGN_SERR_INTERNAL |
+ AHCI_FLAG_32BIT_ONLY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_ops,
+ },
+ /* board_ahci_mv */
+ {
+ .sht = &ahci_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
+ AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
+ AHCI_FLAG_MV_PATA,
.pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
};
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
{ PCI_VDEVICE(NVIDIA, 0x0559), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055a), board_ahci }, /* MCP67 */
{ PCI_VDEVICE(NVIDIA, 0x055b), board_ahci }, /* MCP67 */
+ { PCI_VDEVICE(NVIDIA, 0x07f0), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f1), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f2), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f3), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f4), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f5), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f6), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f7), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f8), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07f9), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fa), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x07fb), board_ahci }, /* MCP73 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad0), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad1), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad2), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad3), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad4), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad5), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad6), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad7), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad8), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */
/* SiS */
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+ /* Marvell */
+ { PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
+
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
return (cap & 0x1f) + 1;
}
-static inline void __iomem *ahci_port_base(struct ata_port *ap)
+static inline void __iomem *__ahci_port_base(struct ata_host *host,
+ unsigned int port_no)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- return mmio + 0x100 + (ap->port_no * 0x80);
+ return mmio + 0x100 + (port_no * 0x80);
+}
+
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+ return __ahci_port_base(ap->host, ap->port_no);
}
/**
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+ /* some chips lie about 64bit support */
+ if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do 64bit DMA, forcing 32bit\n");
+ cap &= ~HOST_CAP_64;
+ }
+
/* fixup zero port_map */
if (!port_map) {
- port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
+ port_map = (1 << ahci_nr_ports(cap)) - 1;
dev_printk(KERN_WARNING, &pdev->dev,
"PORTS_IMPL is zero, forcing 0x%x\n", port_map);
hpriv->saved_port_map = port_map;
}
+ /*
+ * Temporary Marvell 6145 hack: PATA port presence
+ * is asserted through the standard AHCI port
+ * presence register, as bit 4 (counting from 0)
+ */
+ if (pi->flags & AHCI_FLAG_MV_PATA) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "MV_AHCI HACK: port_map %x -> %x\n",
+ hpriv->port_map,
+ hpriv->port_map & 0xf);
+
+ port_map &= 0xf;
+ }
+
/* cross check port_map and cap.n_ports */
if (pi->flags & AHCI_FLAG_HONOR_PI) {
u32 tmp_port_map = port_map;
}
#endif
-static void ahci_init_port(struct ata_port *ap)
+static void ahci_start_port(struct ata_port *ap)
{
/* enable FIS reception */
ahci_start_fis_rx(ap);
return 0;
}
+static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
+ int port_no, void __iomem *mmio,
+ void __iomem *port_mmio)
+{
+ const char *emsg = NULL;
+ int rc;
+ u32 tmp;
+
+ /* make sure port is not active */
+ rc = ahci_deinit_port(ap, &emsg);
+ if (rc)
+ dev_printk(KERN_WARNING, &pdev->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);
+}
+
static void ahci_init_controller(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- int i, rc;
+ int i;
+ void __iomem *port_mmio;
u32 tmp;
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
- void __iomem *port_mmio = ahci_port_base(ap);
- const char *emsg = NULL;
-
- if (ata_port_is_dummy(ap))
- continue;
-
- /* make sure port is not active */
- rc = ahci_deinit_port(ap, &emsg);
- if (rc)
- dev_printk(KERN_WARNING, &pdev->dev,
- "%s (%d)\n", emsg, rc);
+ if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+ port_mmio = __ahci_port_base(host, 4);
- /* clear SError */
- tmp = readl(port_mmio + PORT_SCR_ERR);
- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
- writel(tmp, port_mmio + PORT_SCR_ERR);
+ writel(0, port_mmio + PORT_IRQ_MASK);
/* 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);
+ }
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
- writel(1 << i, mmio + HOST_IRQ_STAT);
+ port_mmio = ahci_port_base(ap);
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ ahci_port_init(pdev, ap, i, mmio, port_mmio);
}
tmp = readl(mmio + HOST_CTL);
*/
msleep(150);
- *class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
- rc = ata_wait_ready(ap, deadline);
- if (rc && rc != -ENODEV) {
- reason = "device not ready";
- goto fail;
- }
- *class = ahci_dev_classify(ap);
+ rc = ata_wait_ready(ap, deadline);
+ /* link occupied, -ENODEV too is an error */
+ if (rc) {
+ reason = "device not ready";
+ goto fail;
}
+ *class = ahci_dev_classify(ap);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
ata_port_abort(ap);
}
-static void ahci_host_intr(struct ata_port *ap)
+static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ata_eh_info *ehi = &ap->eh_info;
ap = host->ports[i];
if (ap) {
- ahci_host_intr(ap);
+ ahci_port_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
ahci_power_down(ap);
else {
ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
- ahci_init_port(ap);
+ ahci_start_port(ap);
}
return rc;
static int ahci_port_resume(struct ata_port *ap)
{
ahci_power_up(ap);
- ahci_init_port(ap);
+ ahci_start_port(ap);
return 0;
}
ap->private_data = pp;
- /* power up port */
- ahci_power_up(ap);
-
- /* initialize port */
- ahci_init_port(ap);
-
- return 0;
+ /* engage engines, captain */
+ return ahci_port_resume(ap);
}
static void ahci_port_stop(struct ata_port *ap)
if (rc)
return rc;
- if (pci_enable_msi(pdev))
+ if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
host->private_data = hpriv;
for (i = 0; i < host->n_ports; i++) {
- if (hpriv->port_map & (1 << i)) {
- struct ata_port *ap = host->ports[i];
- void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port_mmio = ahci_port_base(ap);
+ /* standard SATA port setup */
+ if (hpriv->port_map & (1 << i)) {
ap->ioaddr.cmd_addr = port_mmio;
ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
- } else
- host->ports[i]->ops = &ata_dummy_port_ops;
+ }
+
+ /* disabled/not-implemented port */
+ else
+ ap->ops = &ata_dummy_port_ops;
}
/* initialize adapter */