aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/sata_sil24.c76
1 files changed, 56 insertions, 20 deletions
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5f8afa950043..e6fe4c424a62 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -531,16 +531,60 @@ static int sil24_init_port(struct ata_port *ap)
531 return 0; 531 return 0;
532} 532}
533 533
534static int sil24_softreset(struct ata_port *ap, unsigned int *class, 534static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
535 unsigned long deadline) 535 const struct ata_taskfile *tf,
536 int is_cmd, u32 ctrl,
537 unsigned long timeout_msec)
536{ 538{
537 void __iomem *port = ap->ioaddr.cmd_addr; 539 void __iomem *port = ap->ioaddr.cmd_addr;
538 struct sil24_port_priv *pp = ap->private_data; 540 struct sil24_port_priv *pp = ap->private_data;
539 struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; 541 struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
540 dma_addr_t paddr = pp->cmd_block_dma; 542 dma_addr_t paddr = pp->cmd_block_dma;
543 u32 irq_enabled, irq_mask, irq_stat;
544 int rc;
545
546 prb->ctrl = cpu_to_le16(ctrl);
547 ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
548
549 /* temporarily plug completion and error interrupts */
550 irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
551 writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
552
553 writel((u32)paddr, port + PORT_CMD_ACTIVATE);
554 writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
555
556 irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
557 irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
558 10, timeout_msec);
559
560 writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
561 irq_stat >>= PORT_IRQ_RAW_SHIFT;
562
563 if (irq_stat & PORT_IRQ_COMPLETE)
564 rc = 0;
565 else {
566 /* force port into known state */
567 sil24_init_port(ap);
568
569 if (irq_stat & PORT_IRQ_ERROR)
570 rc = -EIO;
571 else
572 rc = -EBUSY;
573 }
574
575 /* restore IRQ enabled */
576 writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
577
578 return rc;
579}
580
581static int sil24_softreset(struct ata_port *ap, unsigned int *class,
582 unsigned long deadline)
583{
584 unsigned long timeout_msec = 0;
541 struct ata_taskfile tf; 585 struct ata_taskfile tf;
542 u32 mask, irq_stat;
543 const char *reason; 586 const char *reason;
587 int rc;
544 588
545 DPRINTK("ENTER\n"); 589 DPRINTK("ENTER\n");
546 590
@@ -557,24 +601,16 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
557 } 601 }
558 602
559 /* do SRST */ 603 /* do SRST */
560 prb->ctrl = cpu_to_le16(PRB_CTRL_SRST); 604 if (time_after(deadline, jiffies))
561 prb->fis[1] = 0; /* no PMP yet */ 605 timeout_msec = jiffies_to_msecs(deadline - jiffies);
562 606
563 writel((u32)paddr, port + PORT_CMD_ACTIVATE); 607 ata_tf_init(ap->device, &tf); /* doesn't really matter */
564 writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); 608 rc = sil24_exec_polled_cmd(ap, 0, &tf, 0, PRB_CTRL_SRST, timeout_msec);
565 609 if (rc == -EBUSY) {
566 mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; 610 reason = "timeout";
567 irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0, 611 goto err;
568 100, jiffies_to_msecs(deadline - jiffies)); 612 } else if (rc) {
569 613 reason = "SRST command error";
570 writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
571 irq_stat >>= PORT_IRQ_RAW_SHIFT;
572
573 if (!(irq_stat & PORT_IRQ_COMPLETE)) {
574 if (irq_stat & PORT_IRQ_ERROR)
575 reason = "SRST command error";
576 else
577 reason = "timeout";
578 goto err; 614 goto err;
579 } 615 }
580 616