aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-09-23 00:19:54 -0400
committerJeff Garzik <jeff@garzik.org>2007-10-12 14:55:44 -0400
commit238180343eff95697ed71eea137cf61ba3cea6ad (patch)
treee7beaf26a9181e26e3b7bbf57dc8f321ef2949c7
parent3454dc6922dc550c0d3ccf292c4e227403b10b6e (diff)
sata_sil24: implement PORT_RST
As DEV_RST (hardreset) sometimes fail to recover the controller (especially after PMP DMA CS errata). In such cases, perform PORT_RST prior to DEV_RST. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/sata_sil24.c93
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 03bfbb65c533..15b9a80a1782 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -323,6 +323,7 @@ struct sil24_port_priv {
323 union sil24_cmd_block *cmd_block; /* 32 cmd blocks */ 323 union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
324 dma_addr_t cmd_block_dma; /* DMA base addr for them */ 324 dma_addr_t cmd_block_dma; /* DMA base addr for them */
325 struct ata_taskfile tf; /* Cached taskfile registers */ 325 struct ata_taskfile tf; /* Cached taskfile registers */
326 int do_port_rst;
326}; 327};
327 328
328static void sil24_dev_config(struct ata_device *dev); 329static void sil24_dev_config(struct ata_device *dev);
@@ -536,6 +537,31 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
536 *tf = pp->tf; 537 *tf = pp->tf;
537} 538}
538 539
540static void sil24_config_port(struct ata_port *ap)
541{
542 void __iomem *port = ap->ioaddr.cmd_addr;
543
544 /* configure IRQ WoC */
545 if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
546 writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
547 else
548 writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
549
550 /* zero error counters. */
551 writel(0x8000, port + PORT_DECODE_ERR_THRESH);
552 writel(0x8000, port + PORT_CRC_ERR_THRESH);
553 writel(0x8000, port + PORT_HSHK_ERR_THRESH);
554 writel(0x0000, port + PORT_DECODE_ERR_CNT);
555 writel(0x0000, port + PORT_CRC_ERR_CNT);
556 writel(0x0000, port + PORT_HSHK_ERR_CNT);
557
558 /* always use 64bit activation */
559 writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
560
561 /* clear port multiplier enable and resume bits */
562 writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
563}
564
539static void sil24_config_pmp(struct ata_port *ap, int attached) 565static void sil24_config_pmp(struct ata_port *ap, int attached)
540{ 566{
541 void __iomem *port = ap->ioaddr.cmd_addr; 567 void __iomem *port = ap->ioaddr.cmd_addr;
@@ -564,6 +590,7 @@ static void sil24_clear_pmp(struct ata_port *ap)
564static int sil24_init_port(struct ata_port *ap) 590static int sil24_init_port(struct ata_port *ap)
565{ 591{
566 void __iomem *port = ap->ioaddr.cmd_addr; 592 void __iomem *port = ap->ioaddr.cmd_addr;
593 struct sil24_port_priv *pp = ap->private_data;
567 u32 tmp; 594 u32 tmp;
568 595
569 /* clear PMP error status */ 596 /* clear PMP error status */
@@ -576,8 +603,12 @@ static int sil24_init_port(struct ata_port *ap)
576 tmp = ata_wait_register(port + PORT_CTRL_STAT, 603 tmp = ata_wait_register(port + PORT_CTRL_STAT,
577 PORT_CS_RDY, 0, 10, 100); 604 PORT_CS_RDY, 0, 10, 100);
578 605
579 if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) 606 if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
607 pp->do_port_rst = 1;
608 ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
580 return -EIO; 609 return -EIO;
610 }
611
581 return 0; 612 return 0;
582} 613}
583 614
@@ -692,10 +723,34 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
692{ 723{
693 struct ata_port *ap = link->ap; 724 struct ata_port *ap = link->ap;
694 void __iomem *port = ap->ioaddr.cmd_addr; 725 void __iomem *port = ap->ioaddr.cmd_addr;
726 struct sil24_port_priv *pp = ap->private_data;
727 int did_port_rst = 0;
695 const char *reason; 728 const char *reason;
696 int tout_msec, rc; 729 int tout_msec, rc;
697 u32 tmp; 730 u32 tmp;
698 731
732 retry:
733 /* Sometimes, DEV_RST is not enough to recover the controller.
734 * This happens often after PM DMA CS errata.
735 */
736 if (pp->do_port_rst) {
737 ata_port_printk(ap, KERN_WARNING, "controller in dubious "
738 "state, performing PORT_RST\n");
739
740 writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
741 msleep(10);
742 writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
743 ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
744 10, 5000);
745
746 /* restore port configuration */
747 sil24_config_port(ap);
748 sil24_config_pmp(ap, ap->nr_pmp_links);
749
750 pp->do_port_rst = 0;
751 did_port_rst = 1;
752 }
753
699 /* sil24 does the right thing(tm) without any protection */ 754 /* sil24 does the right thing(tm) without any protection */
700 sata_set_spd(link); 755 sata_set_spd(link);
701 756
@@ -732,6 +787,11 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
732 return -EAGAIN; 787 return -EAGAIN;
733 788
734 err: 789 err:
790 if (!did_port_rst) {
791 pp->do_port_rst = 1;
792 goto retry;
793 }
794
735 ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason); 795 ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
736 return -EIO; 796 return -EIO;
737} 797}
@@ -997,6 +1057,7 @@ static void sil24_error_intr(struct ata_port *ap)
997 ehi->err_mask |= AC_ERR_OTHER; 1057 ehi->err_mask |= AC_ERR_OTHER;
998 ehi->action |= ATA_EH_HARDRESET; 1058 ehi->action |= ATA_EH_HARDRESET;
999 ata_ehi_push_desc(ehi, "PMP DMA CS errata"); 1059 ata_ehi_push_desc(ehi, "PMP DMA CS errata");
1060 pp->do_port_rst = 1;
1000 freeze = 1; 1061 freeze = 1;
1001 } 1062 }
1002 1063
@@ -1152,6 +1213,8 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
1152 1213
1153static void sil24_error_handler(struct ata_port *ap) 1214static void sil24_error_handler(struct ata_port *ap)
1154{ 1215{
1216 struct sil24_port_priv *pp = ap->private_data;
1217
1155 if (sil24_init_port(ap)) 1218 if (sil24_init_port(ap))
1156 ata_eh_freeze_port(ap); 1219 ata_eh_freeze_port(ap);
1157 1220
@@ -1160,6 +1223,8 @@ static void sil24_error_handler(struct ata_port *ap)
1160 ata_std_postreset, sata_pmp_std_prereset, 1223 ata_std_postreset, sata_pmp_std_prereset,
1161 sil24_pmp_softreset, sil24_pmp_hardreset, 1224 sil24_pmp_softreset, sil24_pmp_hardreset,
1162 sata_pmp_std_postreset); 1225 sata_pmp_std_postreset);
1226
1227 pp->do_port_rst = 0;
1163} 1228}
1164 1229
1165static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) 1230static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -1206,7 +1271,6 @@ static int sil24_port_start(struct ata_port *ap)
1206static void sil24_init_controller(struct ata_host *host) 1271static void sil24_init_controller(struct ata_host *host)
1207{ 1272{
1208 void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; 1273 void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
1209 void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
1210 u32 tmp; 1274 u32 tmp;
1211 int i; 1275 int i;
1212 1276
@@ -1218,7 +1282,8 @@ static void sil24_init_controller(struct ata_host *host)
1218 1282
1219 /* init ports */ 1283 /* init ports */
1220 for (i = 0; i < host->n_ports; i++) { 1284 for (i = 0; i < host->n_ports; i++) {
1221 void __iomem *port = port_base + i * PORT_REGS_SIZE; 1285 struct ata_port *ap = host->ports[i];
1286 void __iomem *port = ap->ioaddr.cmd_addr;
1222 1287
1223 /* Initial PHY setting */ 1288 /* Initial PHY setting */
1224 writel(0x20c, port + PORT_PHY_CFG); 1289 writel(0x20c, port + PORT_PHY_CFG);
@@ -1235,26 +1300,8 @@ static void sil24_init_controller(struct ata_host *host)
1235 "failed to clear port RST\n"); 1300 "failed to clear port RST\n");
1236 } 1301 }
1237 1302
1238 /* Configure IRQ WoC */ 1303 /* configure port */
1239 if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC) 1304 sil24_config_port(ap);
1240 writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
1241 else
1242 writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
1243
1244 /* Zero error counters. */
1245 writel(0x8000, port + PORT_DECODE_ERR_THRESH);
1246 writel(0x8000, port + PORT_CRC_ERR_THRESH);
1247 writel(0x8000, port + PORT_HSHK_ERR_THRESH);
1248 writel(0x0000, port + PORT_DECODE_ERR_CNT);
1249 writel(0x0000, port + PORT_CRC_ERR_CNT);
1250 writel(0x0000, port + PORT_HSHK_ERR_CNT);
1251
1252 /* Always use 64bit activation */
1253 writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
1254
1255 /* Clear port multiplier enable and resume bits */
1256 writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
1257 port + PORT_CTRL_CLR);
1258 } 1305 }
1259 1306
1260 /* Turn on interrupts */ 1307 /* Turn on interrupts */