aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-07-26 02:59:26 -0400
committerJeff Garzik <jeff@garzik.org>2006-07-29 04:01:31 -0400
commit0be0aa98985dfec42502c0d0af2a1baff9bdb19f (patch)
tree110f8d9419bc18370ddc410082e65a634d8a8109 /drivers/scsi
parent9f5920567bfabbd1be26112a31c44652b6587394 (diff)
[PATCH] libata: improve driver initialization and deinitialization
Implement ahci_[de]init_port() and use it during initialization and de-initialization. ahci_[de]init_port() are supersets of what used to be done during driver [de-]initialization. This patch makes the following behavior changes. * Per-port IRQ mask is cleared on driver load as done in other drivers. The mask will be configured properly during probe. * During init_one(), HOST_IRQ_STAT is cleared after masking port IRQs such that there is no race window. * CMD_SPIN_UP is cleared during init_one() instead of being set. It is set in port_start(). This is more consistent with overall structure of initialization. Note that CMD_SPIN_UP simply controls PHY activation. * Slumber and staggered spin-up are handled properly. * All init/deinit operations are done in step-by-step manner as described in the spec instead of issued as single merged command. Original implementation is from Zhao, Forrest <forrest.zhao@intel.com> Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Zhao, Forrest <forrest.zhao@intel.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ahci.c202
1 files changed, 151 insertions, 51 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index e02b9c65287b..fb71fa7bc5de 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -92,7 +92,9 @@ enum {
92 HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ 92 HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
93 93
94 /* HOST_CAP bits */ 94 /* HOST_CAP bits */
95 HOST_CAP_SSC = (1 << 14), /* Slumber capable */
95 HOST_CAP_CLO = (1 << 24), /* Command List Override support */ 96 HOST_CAP_CLO = (1 << 24), /* Command List Override support */
97 HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
96 HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ 98 HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
97 HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ 99 HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
98 100
@@ -155,6 +157,7 @@ enum {
155 PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ 157 PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
156 PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ 158 PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
157 159
160 PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
158 PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ 161 PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
159 PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ 162 PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
160 PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ 163 PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
@@ -440,6 +443,135 @@ static int ahci_stop_engine(void __iomem *port_mmio)
440 return 0; 443 return 0;
441} 444}
442 445
446static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
447 dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
448{
449 u32 tmp;
450
451 /* set FIS registers */
452 if (cap & HOST_CAP_64)
453 writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
454 writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
455
456 if (cap & HOST_CAP_64)
457 writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
458 writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
459
460 /* enable FIS reception */
461 tmp = readl(port_mmio + PORT_CMD);
462 tmp |= PORT_CMD_FIS_RX;
463 writel(tmp, port_mmio + PORT_CMD);
464
465 /* flush */
466 readl(port_mmio + PORT_CMD);
467}
468
469static int ahci_stop_fis_rx(void __iomem *port_mmio)
470{
471 u32 tmp;
472
473 /* disable FIS reception */
474 tmp = readl(port_mmio + PORT_CMD);
475 tmp &= ~PORT_CMD_FIS_RX;
476 writel(tmp, port_mmio + PORT_CMD);
477
478 /* wait for completion, spec says 500ms, give it 1000 */
479 tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
480 PORT_CMD_FIS_ON, 10, 1000);
481 if (tmp & PORT_CMD_FIS_ON)
482 return -EBUSY;
483
484 return 0;
485}
486
487static void ahci_power_up(void __iomem *port_mmio, u32 cap)
488{
489 u32 cmd;
490
491 cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
492
493 /* spin up device */
494 if (cap & HOST_CAP_SSS) {
495 cmd |= PORT_CMD_SPIN_UP;
496 writel(cmd, port_mmio + PORT_CMD);
497 }
498
499 /* wake up link */
500 writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
501}
502
503static void ahci_power_down(void __iomem *port_mmio, u32 cap)
504{
505 u32 cmd, scontrol;
506
507 cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
508
509 if (cap & HOST_CAP_SSC) {
510 /* enable transitions to slumber mode */
511 scontrol = readl(port_mmio + PORT_SCR_CTL);
512 if ((scontrol & 0x0f00) > 0x100) {
513 scontrol &= ~0xf00;
514 writel(scontrol, port_mmio + PORT_SCR_CTL);
515 }
516
517 /* put device into slumber mode */
518 writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
519
520 /* wait for the transition to complete */
521 ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
522 PORT_CMD_ICC_SLUMBER, 1, 50);
523 }
524
525 /* put device into listen mode */
526 if (cap & HOST_CAP_SSS) {
527 /* first set PxSCTL.DET to 0 */
528 scontrol = readl(port_mmio + PORT_SCR_CTL);
529 scontrol &= ~0xf;
530 writel(scontrol, port_mmio + PORT_SCR_CTL);
531
532 /* then set PxCMD.SUD to 0 */
533 cmd &= ~PORT_CMD_SPIN_UP;
534 writel(cmd, port_mmio + PORT_CMD);
535 }
536}
537
538static void ahci_init_port(void __iomem *port_mmio, u32 cap,
539 dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
540{
541 /* power up */
542 ahci_power_up(port_mmio, cap);
543
544 /* enable FIS reception */
545 ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
546
547 /* enable DMA */
548 ahci_start_engine(port_mmio);
549}
550
551static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
552{
553 int rc;
554
555 /* disable DMA */
556 rc = ahci_stop_engine(port_mmio);
557 if (rc) {
558 *emsg = "failed to stop engine";
559 return rc;
560 }
561
562 /* disable FIS reception */
563 rc = ahci_stop_fis_rx(port_mmio);
564 if (rc) {
565 *emsg = "failed stop FIS RX";
566 return rc;
567 }
568
569 /* put device into slumber mode */
570 ahci_power_down(port_mmio, cap);
571
572 return 0;
573}
574
443static unsigned int ahci_dev_classify(struct ata_port *ap) 575static unsigned int ahci_dev_classify(struct ata_port *ap)
444{ 576{
445 void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; 577 void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -1037,20 +1169,8 @@ static int ahci_port_start(struct ata_port *ap)
1037 1169
1038 ap->private_data = pp; 1170 ap->private_data = pp;
1039 1171
1040 if (hpriv->cap & HOST_CAP_64) 1172 /* initialize port */
1041 writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); 1173 ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
1042 writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
1043 readl(port_mmio + PORT_LST_ADDR); /* flush */
1044
1045 if (hpriv->cap & HOST_CAP_64)
1046 writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
1047 writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
1048 readl(port_mmio + PORT_FIS_ADDR); /* flush */
1049
1050 writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
1051 PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
1052 PORT_CMD_START, port_mmio + PORT_CMD);
1053 readl(port_mmio + PORT_CMD); /* flush */
1054 1174
1055 return 0; 1175 return 0;
1056} 1176}
@@ -1058,20 +1178,17 @@ static int ahci_port_start(struct ata_port *ap)
1058static void ahci_port_stop(struct ata_port *ap) 1178static void ahci_port_stop(struct ata_port *ap)
1059{ 1179{
1060 struct device *dev = ap->host_set->dev; 1180 struct device *dev = ap->host_set->dev;
1181 struct ahci_host_priv *hpriv = ap->host_set->private_data;
1061 struct ahci_port_priv *pp = ap->private_data; 1182 struct ahci_port_priv *pp = ap->private_data;
1062 void __iomem *mmio = ap->host_set->mmio_base; 1183 void __iomem *mmio = ap->host_set->mmio_base;
1063 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); 1184 void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
1064 u32 tmp; 1185 const char *emsg = NULL;
1065 1186 int rc;
1066 tmp = readl(port_mmio + PORT_CMD);
1067 tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
1068 writel(tmp, port_mmio + PORT_CMD);
1069 readl(port_mmio + PORT_CMD); /* flush */
1070 1187
1071 /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so 1188 /* de-initialize port */
1072 * this is slightly incorrect. 1189 rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1073 */ 1190 if (rc)
1074 msleep(500); 1191 ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
1075 1192
1076 ap->private_data = NULL; 1193 ap->private_data = NULL;
1077 dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, 1194 dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
@@ -1099,7 +1216,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
1099 struct pci_dev *pdev = to_pci_dev(probe_ent->dev); 1216 struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
1100 void __iomem *mmio = probe_ent->mmio_base; 1217 void __iomem *mmio = probe_ent->mmio_base;
1101 u32 tmp, cap_save; 1218 u32 tmp, cap_save;
1102 unsigned int i, j, using_dac; 1219 unsigned int i, using_dac;
1103 int rc; 1220 int rc;
1104 void __iomem *port_mmio; 1221 void __iomem *port_mmio;
1105 1222
@@ -1175,6 +1292,8 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
1175 } 1292 }
1176 1293
1177 for (i = 0; i < probe_ent->n_ports; i++) { 1294 for (i = 0; i < probe_ent->n_ports; i++) {
1295 const char *emsg = NULL;
1296
1178#if 0 /* BIOSen initialize this incorrectly */ 1297#if 0 /* BIOSen initialize this incorrectly */
1179 if (!(hpriv->port_map & (1 << i))) 1298 if (!(hpriv->port_map & (1 << i)))
1180 continue; 1299 continue;
@@ -1187,43 +1306,24 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
1187 (unsigned long) mmio, i); 1306 (unsigned long) mmio, i);
1188 1307
1189 /* make sure port is not active */ 1308 /* make sure port is not active */
1190 tmp = readl(port_mmio + PORT_CMD); 1309 rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
1191 VPRINTK("PORT_CMD 0x%x\n", tmp); 1310 if (rc)
1192 if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | 1311 dev_printk(KERN_WARNING, &pdev->dev,
1193 PORT_CMD_FIS_RX | PORT_CMD_START)) { 1312 "%s (%d)\n", emsg, rc);
1194 tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
1195 PORT_CMD_FIS_RX | PORT_CMD_START);
1196 writel(tmp, port_mmio + PORT_CMD);
1197 readl(port_mmio + PORT_CMD); /* flush */
1198
1199 /* spec says 500 msecs for each bit, so
1200 * this is slightly incorrect.
1201 */
1202 msleep(500);
1203 }
1204
1205 writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
1206
1207 j = 0;
1208 while (j < 100) {
1209 msleep(10);
1210 tmp = readl(port_mmio + PORT_SCR_STAT);
1211 if ((tmp & 0xf) == 0x3)
1212 break;
1213 j++;
1214 }
1215 1313
1314 /* clear SError */
1216 tmp = readl(port_mmio + PORT_SCR_ERR); 1315 tmp = readl(port_mmio + PORT_SCR_ERR);
1217 VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); 1316 VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
1218 writel(tmp, port_mmio + PORT_SCR_ERR); 1317 writel(tmp, port_mmio + PORT_SCR_ERR);
1219 1318
1220 /* ack any pending irq events for this port */ 1319 /* clear & turn off port IRQ */
1221 tmp = readl(port_mmio + PORT_IRQ_STAT); 1320 tmp = readl(port_mmio + PORT_IRQ_STAT);
1222 VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); 1321 VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
1223 if (tmp) 1322 if (tmp)
1224 writel(tmp, port_mmio + PORT_IRQ_STAT); 1323 writel(tmp, port_mmio + PORT_IRQ_STAT);
1225 1324
1226 writel(1 << i, mmio + HOST_IRQ_STAT); 1325 writel(1 << i, mmio + HOST_IRQ_STAT);
1326 writel(0, port_mmio + PORT_IRQ_MASK);
1227 } 1327 }
1228 1328
1229 tmp = readl(mmio + HOST_CTL); 1329 tmp = readl(mmio + HOST_CTL);