diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ahci.c | 171 |
1 files changed, 94 insertions, 77 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index fb71fa7bc5de..a9e0c5f79096 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -572,6 +572,94 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg) | |||
572 | return 0; | 572 | return 0; |
573 | } | 573 | } |
574 | 574 | ||
575 | static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev) | ||
576 | { | ||
577 | u32 cap_save, tmp; | ||
578 | |||
579 | cap_save = readl(mmio + HOST_CAP); | ||
580 | cap_save &= ( (1<<28) | (1<<17) ); | ||
581 | cap_save |= (1 << 27); | ||
582 | |||
583 | /* global controller reset */ | ||
584 | tmp = readl(mmio + HOST_CTL); | ||
585 | if ((tmp & HOST_RESET) == 0) { | ||
586 | writel(tmp | HOST_RESET, mmio + HOST_CTL); | ||
587 | readl(mmio + HOST_CTL); /* flush */ | ||
588 | } | ||
589 | |||
590 | /* reset must complete within 1 second, or | ||
591 | * the hardware should be considered fried. | ||
592 | */ | ||
593 | ssleep(1); | ||
594 | |||
595 | tmp = readl(mmio + HOST_CTL); | ||
596 | if (tmp & HOST_RESET) { | ||
597 | dev_printk(KERN_ERR, &pdev->dev, | ||
598 | "controller reset failed (0x%x)\n", tmp); | ||
599 | return -EIO; | ||
600 | } | ||
601 | |||
602 | writel(HOST_AHCI_EN, mmio + HOST_CTL); | ||
603 | (void) readl(mmio + HOST_CTL); /* flush */ | ||
604 | writel(cap_save, mmio + HOST_CAP); | ||
605 | writel(0xf, mmio + HOST_PORTS_IMPL); | ||
606 | (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ | ||
607 | |||
608 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) { | ||
609 | u16 tmp16; | ||
610 | |||
611 | /* configure PCS */ | ||
612 | pci_read_config_word(pdev, 0x92, &tmp16); | ||
613 | tmp16 |= 0xf; | ||
614 | pci_write_config_word(pdev, 0x92, tmp16); | ||
615 | } | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, | ||
621 | int n_ports, u32 cap) | ||
622 | { | ||
623 | int i, rc; | ||
624 | u32 tmp; | ||
625 | |||
626 | for (i = 0; i < n_ports; i++) { | ||
627 | void __iomem *port_mmio = ahci_port_base(mmio, i); | ||
628 | const char *emsg = NULL; | ||
629 | |||
630 | #if 0 /* BIOSen initialize this incorrectly */ | ||
631 | if (!(hpriv->port_map & (1 << i))) | ||
632 | continue; | ||
633 | #endif | ||
634 | |||
635 | /* make sure port is not active */ | ||
636 | rc = ahci_deinit_port(port_mmio, cap, &emsg); | ||
637 | if (rc) | ||
638 | dev_printk(KERN_WARNING, &pdev->dev, | ||
639 | "%s (%d)\n", emsg, rc); | ||
640 | |||
641 | /* clear SError */ | ||
642 | tmp = readl(port_mmio + PORT_SCR_ERR); | ||
643 | VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); | ||
644 | writel(tmp, port_mmio + PORT_SCR_ERR); | ||
645 | |||
646 | /* clear & turn off port IRQ */ | ||
647 | tmp = readl(port_mmio + PORT_IRQ_STAT); | ||
648 | VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); | ||
649 | if (tmp) | ||
650 | writel(tmp, port_mmio + PORT_IRQ_STAT); | ||
651 | |||
652 | writel(1 << i, mmio + HOST_IRQ_STAT); | ||
653 | writel(0, port_mmio + PORT_IRQ_MASK); | ||
654 | } | ||
655 | |||
656 | tmp = readl(mmio + HOST_CTL); | ||
657 | VPRINTK("HOST_CTL 0x%x\n", tmp); | ||
658 | writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); | ||
659 | tmp = readl(mmio + HOST_CTL); | ||
660 | VPRINTK("HOST_CTL 0x%x\n", tmp); | ||
661 | } | ||
662 | |||
575 | static unsigned int ahci_dev_classify(struct ata_port *ap) | 663 | static unsigned int ahci_dev_classify(struct ata_port *ap) |
576 | { | 664 | { |
577 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; | 665 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; |
@@ -1215,47 +1303,12 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
1215 | struct ahci_host_priv *hpriv = probe_ent->private_data; | 1303 | struct ahci_host_priv *hpriv = probe_ent->private_data; |
1216 | struct pci_dev *pdev = to_pci_dev(probe_ent->dev); | 1304 | struct pci_dev *pdev = to_pci_dev(probe_ent->dev); |
1217 | void __iomem *mmio = probe_ent->mmio_base; | 1305 | void __iomem *mmio = probe_ent->mmio_base; |
1218 | u32 tmp, cap_save; | ||
1219 | unsigned int i, using_dac; | 1306 | unsigned int i, using_dac; |
1220 | int rc; | 1307 | int rc; |
1221 | void __iomem *port_mmio; | ||
1222 | |||
1223 | cap_save = readl(mmio + HOST_CAP); | ||
1224 | cap_save &= ( (1<<28) | (1<<17) ); | ||
1225 | cap_save |= (1 << 27); | ||
1226 | |||
1227 | /* global controller reset */ | ||
1228 | tmp = readl(mmio + HOST_CTL); | ||
1229 | if ((tmp & HOST_RESET) == 0) { | ||
1230 | writel(tmp | HOST_RESET, mmio + HOST_CTL); | ||
1231 | readl(mmio + HOST_CTL); /* flush */ | ||
1232 | } | ||
1233 | |||
1234 | /* reset must complete within 1 second, or | ||
1235 | * the hardware should be considered fried. | ||
1236 | */ | ||
1237 | ssleep(1); | ||
1238 | |||
1239 | tmp = readl(mmio + HOST_CTL); | ||
1240 | if (tmp & HOST_RESET) { | ||
1241 | dev_printk(KERN_ERR, &pdev->dev, | ||
1242 | "controller reset failed (0x%x)\n", tmp); | ||
1243 | return -EIO; | ||
1244 | } | ||
1245 | 1308 | ||
1246 | writel(HOST_AHCI_EN, mmio + HOST_CTL); | 1309 | rc = ahci_reset_controller(mmio, pdev); |
1247 | (void) readl(mmio + HOST_CTL); /* flush */ | 1310 | if (rc) |
1248 | writel(cap_save, mmio + HOST_CAP); | 1311 | return rc; |
1249 | writel(0xf, mmio + HOST_PORTS_IMPL); | ||
1250 | (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ | ||
1251 | |||
1252 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) { | ||
1253 | u16 tmp16; | ||
1254 | |||
1255 | pci_read_config_word(pdev, 0x92, &tmp16); | ||
1256 | tmp16 |= 0xf; | ||
1257 | pci_write_config_word(pdev, 0x92, tmp16); | ||
1258 | } | ||
1259 | 1312 | ||
1260 | hpriv->cap = readl(mmio + HOST_CAP); | 1313 | hpriv->cap = readl(mmio + HOST_CAP); |
1261 | hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); | 1314 | hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); |
@@ -1291,46 +1344,10 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
1291 | } | 1344 | } |
1292 | } | 1345 | } |
1293 | 1346 | ||
1294 | for (i = 0; i < probe_ent->n_ports; i++) { | 1347 | for (i = 0; i < probe_ent->n_ports; i++) |
1295 | const char *emsg = NULL; | 1348 | ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); |
1296 | |||
1297 | #if 0 /* BIOSen initialize this incorrectly */ | ||
1298 | if (!(hpriv->port_map & (1 << i))) | ||
1299 | continue; | ||
1300 | #endif | ||
1301 | 1349 | ||
1302 | port_mmio = ahci_port_base(mmio, i); | 1350 | ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap); |
1303 | VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio); | ||
1304 | |||
1305 | ahci_setup_port(&probe_ent->port[i], | ||
1306 | (unsigned long) mmio, i); | ||
1307 | |||
1308 | /* make sure port is not active */ | ||
1309 | rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg); | ||
1310 | if (rc) | ||
1311 | dev_printk(KERN_WARNING, &pdev->dev, | ||
1312 | "%s (%d)\n", emsg, rc); | ||
1313 | |||
1314 | /* clear SError */ | ||
1315 | tmp = readl(port_mmio + PORT_SCR_ERR); | ||
1316 | VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); | ||
1317 | writel(tmp, port_mmio + PORT_SCR_ERR); | ||
1318 | |||
1319 | /* clear & turn off port IRQ */ | ||
1320 | tmp = readl(port_mmio + PORT_IRQ_STAT); | ||
1321 | VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); | ||
1322 | if (tmp) | ||
1323 | writel(tmp, port_mmio + PORT_IRQ_STAT); | ||
1324 | |||
1325 | writel(1 << i, mmio + HOST_IRQ_STAT); | ||
1326 | writel(0, port_mmio + PORT_IRQ_MASK); | ||
1327 | } | ||
1328 | |||
1329 | tmp = readl(mmio + HOST_CTL); | ||
1330 | VPRINTK("HOST_CTL 0x%x\n", tmp); | ||
1331 | writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); | ||
1332 | tmp = readl(mmio + HOST_CTL); | ||
1333 | VPRINTK("HOST_CTL 0x%x\n", tmp); | ||
1334 | 1351 | ||
1335 | pci_set_master(pdev); | 1352 | pci_set_master(pdev); |
1336 | 1353 | ||