Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 162935
b: refs/heads/master
c: ff7cddf
h: refs/heads/master
i:
  162933: c964e60
  162931: 2c5a21d
  162927: faeec36
v: v3
  • Loading branch information
Mikael Pettersson authored and Jeff Garzik committed Sep 17, 2009
1 parent 896a491 commit 48b0f49
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0ae6654da437db4ae6333d232e718b570c7a3eac
refs/heads/master: ff7cddf59e3618d29e12b061651ab3f5a53f4a98
121 changes: 120 additions & 1 deletion trunk/drivers/ata/sata_promise.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ enum {
/* host register offsets (from host->iomap[PDC_MMIO_BAR]) */
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
PDC_FLASH_CTL = 0x44, /* Flash control register */
PDC_PCI_CTL = 0x48, /* PCI control/status reg */
PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
Expand All @@ -75,7 +76,17 @@ enum {
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */

/* per-port SATA register offsets (from ap->ioaddr.scr_addr) */
PDC_SATA_ERROR = 0x04,
PDC_PHYMODE4 = 0x14,
PDC_LINK_LAYER_ERRORS = 0x6C,
PDC_FPDMA_CTLSTAT = 0xD8,
PDC_INTERNAL_DEBUG_1 = 0xF8, /* also used for PATA */
PDC_INTERNAL_DEBUG_2 = 0xFC, /* also used for PATA */

/* PDC_FPDMA_CTLSTAT bit definitions */
PDC_FPDMA_CTLSTAT_RESET = 1 << 3,
PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG = 1 << 10,
PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG = 1 << 11,

/* PDC_GLOBAL_CTL bit definitions */
PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
Expand Down Expand Up @@ -359,12 +370,76 @@ static int pdc_sata_port_start(struct ata_port *ap)
return 0;
}

static void pdc_fpdma_clear_interrupt_flag(struct ata_port *ap)
{
void __iomem *sata_mmio = ap->ioaddr.scr_addr;
u32 tmp;

tmp = readl(sata_mmio + PDC_FPDMA_CTLSTAT);
tmp |= PDC_FPDMA_CTLSTAT_DMASETUP_INT_FLAG;
tmp |= PDC_FPDMA_CTLSTAT_SETDB_INT_FLAG;

/* It's not allowed to write to the entire FPDMA_CTLSTAT register
when NCQ is running. So do a byte-sized write to bits 10 and 11. */
writeb(tmp >> 8, sata_mmio + PDC_FPDMA_CTLSTAT + 1);
readb(sata_mmio + PDC_FPDMA_CTLSTAT + 1); /* flush */
}

static void pdc_fpdma_reset(struct ata_port *ap)
{
void __iomem *sata_mmio = ap->ioaddr.scr_addr;
u8 tmp;

tmp = (u8)readl(sata_mmio + PDC_FPDMA_CTLSTAT);
tmp &= 0x7F;
tmp |= PDC_FPDMA_CTLSTAT_RESET;
writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */
udelay(100);
tmp &= ~PDC_FPDMA_CTLSTAT_RESET;
writeb(tmp, sata_mmio + PDC_FPDMA_CTLSTAT);
readl(sata_mmio + PDC_FPDMA_CTLSTAT); /* flush */

pdc_fpdma_clear_interrupt_flag(ap);
}

static void pdc_not_at_command_packet_phase(struct ata_port *ap)
{
void __iomem *sata_mmio = ap->ioaddr.scr_addr;
unsigned int i;
u32 tmp;

/* check not at ASIC packet command phase */
for (i = 0; i < 100; ++i) {
writel(0, sata_mmio + PDC_INTERNAL_DEBUG_1);
tmp = readl(sata_mmio + PDC_INTERNAL_DEBUG_2);
if ((tmp & 0xF) != 1)
break;
udelay(100);
}
}

static void pdc_clear_internal_debug_record_error_register(struct ata_port *ap)
{
void __iomem *sata_mmio = ap->ioaddr.scr_addr;

writel(0xffffffff, sata_mmio + PDC_SATA_ERROR);
writel(0xffff0000, sata_mmio + PDC_LINK_LAYER_ERRORS);
}

static void pdc_reset_port(struct ata_port *ap)
{
void __iomem *ata_ctlstat_mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;

if (ap->flags & PDC_FLAG_GEN_II)
pdc_not_at_command_packet_phase(ap);

tmp = readl(ata_ctlstat_mmio);
tmp |= PDC_RESET;
writel(tmp, ata_ctlstat_mmio);

for (i = 11; i > 0; i--) {
tmp = readl(ata_ctlstat_mmio);
if (tmp & PDC_RESET)
Expand All @@ -379,6 +454,11 @@ static void pdc_reset_port(struct ata_port *ap)
tmp &= ~PDC_RESET;
writel(tmp, ata_ctlstat_mmio);
readl(ata_ctlstat_mmio); /* flush */

if (sata_scr_valid(&ap->link) && (ap->flags & PDC_FLAG_GEN_II)) {
pdc_fpdma_reset(ap);
pdc_clear_internal_debug_record_error_register(ap);
}
}

static int pdc_pata_cable_detect(struct ata_port *ap)
Expand Down Expand Up @@ -706,11 +786,50 @@ static int pdc_pata_softreset(struct ata_link *link, unsigned int *class,
return ata_sff_softreset(link, class, deadline);
}

static unsigned int pdc_ata_port_to_ata_no(const struct ata_port *ap)
{
void __iomem *ata_mmio = ap->ioaddr.cmd_addr;
void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];

/* ata_mmio == host_mmio + 0x200 + ata_no * 0x80 */
return (ata_mmio - host_mmio - 0x200) / 0x80;
}

static void pdc_hard_reset_port(struct ata_port *ap)
{
void __iomem *host_mmio = ap->host->iomap[PDC_MMIO_BAR];
void __iomem *pcictl_b1_mmio = host_mmio + PDC_PCI_CTL + 1;
unsigned int ata_no = pdc_ata_port_to_ata_no(ap);
u8 tmp;

spin_lock(&ap->host->lock);

tmp = readb(pcictl_b1_mmio);
tmp &= ~(0x10 << ata_no);
writeb(tmp, pcictl_b1_mmio);
readb(pcictl_b1_mmio); /* flush */
udelay(100);
tmp |= (0x10 << ata_no);
writeb(tmp, pcictl_b1_mmio);
readb(pcictl_b1_mmio); /* flush */

spin_unlock(&ap->host->lock);
}

static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
if (link->ap->flags & PDC_FLAG_GEN_II)
pdc_not_at_command_packet_phase(link->ap);
/* hotplug IRQs should have been masked by pdc_sata_freeze() */
pdc_hard_reset_port(link->ap);
pdc_reset_port(link->ap);
return sata_sff_hardreset(link, class, deadline);

/* sata_promise can't reliably acquire the first D2H Reg FIS
* after hardreset. Do non-waiting hardreset and request
* follow-up SRST.
*/
return sata_std_hardreset(link, class, deadline);
}

static void pdc_error_handler(struct ata_port *ap)
Expand Down

0 comments on commit 48b0f49

Please sign in to comment.