Commit b503ce39 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Jeff Garzik

[libata] Fix flush of Device Control register to device

Also add some ServerWorks-specific tweaks.
parent 2cb1b24d
...@@ -133,7 +133,11 @@ void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -133,7 +133,11 @@ void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf)
struct ata_ioports *ioaddr = &ap->ioaddr; struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
outb(tf->ctl, ioaddr->ctl_addr); if (tf->ctl != ap->last_ctl) {
outb(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
outb(tf->hob_feature, ioaddr->error_addr); outb(tf->hob_feature, ioaddr->error_addr);
...@@ -187,7 +191,11 @@ void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -187,7 +191,11 @@ void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
struct ata_ioports *ioaddr = &ap->ioaddr; struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
writeb(tf->ctl, ap->ioaddr.ctl_addr); if (tf->ctl != ap->last_ctl) {
writeb(tf->ctl, ap->ioaddr.ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
writeb(tf->hob_feature, (void *) ioaddr->error_addr); writeb(tf->hob_feature, (void *) ioaddr->error_addr);
...@@ -1281,9 +1289,9 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, ...@@ -1281,9 +1289,9 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
/* software reset. causes dev0 to be selected */ /* software reset. causes dev0 to be selected */
if (ap->flags & ATA_FLAG_MMIO) { if (ap->flags & ATA_FLAG_MMIO) {
writeb(ap->ctl, ioaddr->ctl_addr); writeb(ap->ctl, ioaddr->ctl_addr);
udelay(10); /* FIXME: flush */ udelay(20); /* FIXME: flush */
writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
udelay(10); /* FIXME: flush */ udelay(20); /* FIXME: flush */
writeb(ap->ctl, ioaddr->ctl_addr); writeb(ap->ctl, ioaddr->ctl_addr);
} else { } else {
outb(ap->ctl, ioaddr->ctl_addr); outb(ap->ctl, ioaddr->ctl_addr);
...@@ -2755,6 +2763,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, ...@@ -2755,6 +2763,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
ap->cbl = ATA_CBL_NONE; ap->cbl = ATA_CBL_NONE;
ap->device[0].flags = ATA_DFLAG_MASTER; ap->device[0].flags = ATA_DFLAG_MASTER;
ap->active_tag = ATA_TAG_POISON; ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
/* ata_engine init */ /* ata_engine init */
ap->eng.flags = 0; ap->eng.flags = 0;
......
...@@ -69,8 +69,11 @@ static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) ...@@ -69,8 +69,11 @@ static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
struct ata_ioports *ioaddr = &ap->ioaddr; struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
writeb(tf->ctl, ioaddr->ctl_addr); if (tf->ctl != ap->last_ctl) {
writeb(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr); writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr);
writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
...@@ -311,13 +314,24 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e ...@@ -311,13 +314,24 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
rc = -ENODEV; rc = -ENODEV;
goto err_out_unmap; goto err_out_unmap;
} }
/* Clear a magic bit in SCR1 according to Darwin, those help
* some funky seagate drives (though so far, those were already
* set by the firmware on the machines I had access to
*/
writel(readl(mmio_base + 0x80) & ~0x00040000, mmio_base + 0x80);
/* Clear SATA error & interrupts we don't use */
writel(0xffffffff, mmio_base + 0x44);
writel(0x0, mmio_base + 0x88);
probe_ent->sht = &k2_sata_sht; probe_ent->sht = &k2_sata_sht;
probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
ATA_FLAG_SRST | ATA_FLAG_MMIO; ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
probe_ent->port_ops = &k2_sata_ops; probe_ent->port_ops = &k2_sata_ops;
probe_ent->n_ports = 2; probe_ent->n_ports = 2;
probe_ent->irq = pdev->irq; probe_ent->irq = pdev->irq;
probe_ent->irq_flags = SA_SHIRQ; probe_ent->irq_flags = SA_SHIRQ;
probe_ent->mmio_base = mmio_base; probe_ent->mmio_base = mmio_base;
/* /*
......
...@@ -310,6 +310,7 @@ struct ata_port { ...@@ -310,6 +310,7 @@ struct ata_port {
struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */
u8 ctl; /* cache of ATA control register */ u8 ctl; /* cache of ATA control register */
u8 last_ctl; /* Cache last written value */
unsigned int bus_state; unsigned int bus_state;
unsigned int port_state; unsigned int port_state;
unsigned int pio_mask; unsigned int pio_mask;
...@@ -522,12 +523,12 @@ static inline u8 ata_irq_on(struct ata_port *ap) ...@@ -522,12 +523,12 @@ static inline u8 ata_irq_on(struct ata_port *ap)
struct ata_ioports *ioaddr = &ap->ioaddr; struct ata_ioports *ioaddr = &ap->ioaddr;
ap->ctl &= ~ATA_NIEN; ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
if (ap->flags & ATA_FLAG_MMIO) if (ap->flags & ATA_FLAG_MMIO)
writeb(ap->ctl, ioaddr->ctl_addr); writeb(ap->ctl, ioaddr->ctl_addr);
else else
outb(ap->ctl, ioaddr->ctl_addr); outb(ap->ctl, ioaddr->ctl_addr);
return ata_wait_idle(ap); return ata_wait_idle(ap);
} }
......
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