aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Lord <liml@rtr.ca>2008-04-16 14:59:07 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-04-17 15:56:19 -0400
commite49856d82a887ce365637176f9f99ab68076eae8 (patch)
tree1b50c22bf1b3975eb5c40a5ae70c3b3be5cd32c0 /drivers
parent02c1f32f1c524d2a389989f2482121f7c7d9b164 (diff)
sata_mv add basic port multiplier support
Add basic port-multiplier support to sata_mv. This works in Command-based-switching mode for Gen-II chipsets, and in FIS-based-switching mode for Gen-IIe chipsets. Error handling remains at the primary port level for now (works okay, but not great). This will get fixed in a subsequent patch series for IRQ/EH handling fixes. There are also some known NCQ/PMP errata to be dealt with in the near future, once we have this basic PMP support in place. Signed-off-by: Mark Lord <mlord@pobox.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/sata_mv.c93
1 files changed, 89 insertions, 4 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 6a7420546609..b822b8a40c65 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -40,7 +40,7 @@
40 40
41 5) Investigate problems with PCI Message Signalled Interrupts (MSI). 41 5) Investigate problems with PCI Message Signalled Interrupts (MSI).
42 42
43 6) Add port multiplier support (intermediate) 43 6) Cache frequently-accessed registers in mv_port_priv to reduce overhead.
44 44
45 7) Fix/reenable hot plug/unplug (should happen as a side-effect of (2) above). 45 7) Fix/reenable hot plug/unplug (should happen as a side-effect of (2) above).
46 46
@@ -528,6 +528,12 @@ static int mv_stop_edma(struct ata_port *ap);
528static int mv_stop_edma_engine(void __iomem *port_mmio); 528static int mv_stop_edma_engine(void __iomem *port_mmio);
529static void mv_edma_cfg(struct ata_port *ap, int want_ncq); 529static void mv_edma_cfg(struct ata_port *ap, int want_ncq);
530 530
531static void mv_pmp_select(struct ata_port *ap, int pmp);
532static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
533 unsigned long deadline);
534static int mv_softreset(struct ata_link *link, unsigned int *class,
535 unsigned long deadline);
536
531/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below 537/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
532 * because we have to allow room for worst case splitting of 538 * because we have to allow room for worst case splitting of
533 * PRDs for 64K boundaries in mv_fill_sg(). 539 * PRDs for 64K boundaries in mv_fill_sg().
@@ -566,14 +572,20 @@ static struct ata_port_operations mv5_ops = {
566 572
567static struct ata_port_operations mv6_ops = { 573static struct ata_port_operations mv6_ops = {
568 .inherits = &mv5_ops, 574 .inherits = &mv5_ops,
569 .qc_defer = ata_std_qc_defer, 575 .qc_defer = sata_pmp_qc_defer_cmd_switch,
570 .dev_config = mv6_dev_config, 576 .dev_config = mv6_dev_config,
571 .scr_read = mv_scr_read, 577 .scr_read = mv_scr_read,
572 .scr_write = mv_scr_write, 578 .scr_write = mv_scr_write,
579
580 .pmp_hardreset = mv_pmp_hardreset,
581 .pmp_softreset = mv_softreset,
582 .softreset = mv_softreset,
583 .error_handler = sata_pmp_error_handler,
573}; 584};
574 585
575static struct ata_port_operations mv_iie_ops = { 586static struct ata_port_operations mv_iie_ops = {
576 .inherits = &mv6_ops, 587 .inherits = &mv6_ops,
588 .qc_defer = ata_std_qc_defer, /* FIS-based switching */
577 .dev_config = ATA_OP_NULL, 589 .dev_config = ATA_OP_NULL,
578 .qc_prep = mv_qc_prep_iie, 590 .qc_prep = mv_qc_prep_iie,
579}; 591};
@@ -599,6 +611,7 @@ static const struct ata_port_info mv_port_info[] = {
599 }, 611 },
600 { /* chip_604x */ 612 { /* chip_604x */
601 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | 613 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
614 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
602 ATA_FLAG_NCQ, 615 ATA_FLAG_NCQ,
603 .pio_mask = 0x1f, /* pio0-4 */ 616 .pio_mask = 0x1f, /* pio0-4 */
604 .udma_mask = ATA_UDMA6, 617 .udma_mask = ATA_UDMA6,
@@ -606,6 +619,7 @@ static const struct ata_port_info mv_port_info[] = {
606 }, 619 },
607 { /* chip_608x */ 620 { /* chip_608x */
608 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | 621 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
622 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
609 ATA_FLAG_NCQ | MV_FLAG_DUAL_HC, 623 ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
610 .pio_mask = 0x1f, /* pio0-4 */ 624 .pio_mask = 0x1f, /* pio0-4 */
611 .udma_mask = ATA_UDMA6, 625 .udma_mask = ATA_UDMA6,
@@ -613,6 +627,7 @@ static const struct ata_port_info mv_port_info[] = {
613 }, 627 },
614 { /* chip_6042 */ 628 { /* chip_6042 */
615 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | 629 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
630 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
616 ATA_FLAG_NCQ, 631 ATA_FLAG_NCQ,
617 .pio_mask = 0x1f, /* pio0-4 */ 632 .pio_mask = 0x1f, /* pio0-4 */
618 .udma_mask = ATA_UDMA6, 633 .udma_mask = ATA_UDMA6,
@@ -620,6 +635,7 @@ static const struct ata_port_info mv_port_info[] = {
620 }, 635 },
621 { /* chip_7042 */ 636 { /* chip_7042 */
622 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | 637 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
638 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
623 ATA_FLAG_NCQ, 639 ATA_FLAG_NCQ,
624 .pio_mask = 0x1f, /* pio0-4 */ 640 .pio_mask = 0x1f, /* pio0-4 */
625 .udma_mask = ATA_UDMA6, 641 .udma_mask = ATA_UDMA6,
@@ -627,6 +643,7 @@ static const struct ata_port_info mv_port_info[] = {
627 }, 643 },
628 { /* chip_soc */ 644 { /* chip_soc */
629 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS | 645 .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
646 ATA_FLAG_PMP | ATA_FLAG_ACPI_SATA |
630 ATA_FLAG_NCQ | MV_FLAG_SOC, 647 ATA_FLAG_NCQ | MV_FLAG_SOC,
631 .pio_mask = 0x1f, /* pio0-4 */ 648 .pio_mask = 0x1f, /* pio0-4 */
632 .udma_mask = ATA_UDMA6, 649 .udma_mask = ATA_UDMA6,
@@ -1006,12 +1023,42 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
1006static void mv6_dev_config(struct ata_device *adev) 1023static void mv6_dev_config(struct ata_device *adev)
1007{ 1024{
1008 /* 1025 /*
1026 * Deal with Gen-II ("mv6") hardware quirks/restrictions:
1027 *
1028 * Gen-II does not support NCQ over a port multiplier
1029 * (no FIS-based switching).
1030 *
1009 * We don't have hob_nsect when doing NCQ commands on Gen-II. 1031 * We don't have hob_nsect when doing NCQ commands on Gen-II.
1010 * See mv_qc_prep() for more info. 1032 * See mv_qc_prep() for more info.
1011 */ 1033 */
1012 if (adev->flags & ATA_DFLAG_NCQ) 1034 if (adev->flags & ATA_DFLAG_NCQ) {
1013 if (adev->max_sectors > ATA_MAX_SECTORS) 1035 if (sata_pmp_attached(adev->link->ap))
1036 adev->flags &= ~ATA_DFLAG_NCQ;
1037 else if (adev->max_sectors > ATA_MAX_SECTORS)
1014 adev->max_sectors = ATA_MAX_SECTORS; 1038 adev->max_sectors = ATA_MAX_SECTORS;
1039 }
1040}
1041
1042static void mv_config_fbs(void __iomem *port_mmio, int enable_fbs)
1043{
1044 u32 old_fcfg, new_fcfg, old_ltmode, new_ltmode;
1045 /*
1046 * Various bit settings required for operation
1047 * in FIS-based switching (fbs) mode on GenIIe:
1048 */
1049 old_fcfg = readl(port_mmio + FIS_CFG_OFS);
1050 old_ltmode = readl(port_mmio + LTMODE_OFS);
1051 if (enable_fbs) {
1052 new_fcfg = old_fcfg | FIS_CFG_SINGLE_SYNC;
1053 new_ltmode = old_ltmode | LTMODE_BIT8;
1054 } else { /* disable fbs */
1055 new_fcfg = old_fcfg & ~FIS_CFG_SINGLE_SYNC;
1056 new_ltmode = old_ltmode & ~LTMODE_BIT8;
1057 }
1058 if (new_fcfg != old_fcfg)
1059 writelfl(new_fcfg, port_mmio + FIS_CFG_OFS);
1060 if (new_ltmode != old_ltmode)
1061 writelfl(new_ltmode, port_mmio + LTMODE_OFS);
1015} 1062}
1016 1063
1017static void mv_edma_cfg(struct ata_port *ap, int want_ncq) 1064static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
@@ -1035,6 +1082,13 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
1035 cfg |= (1 << 22); /* enab 4-entry host queue cache */ 1082 cfg |= (1 << 22); /* enab 4-entry host queue cache */
1036 cfg |= (1 << 18); /* enab early completion */ 1083 cfg |= (1 << 18); /* enab early completion */
1037 cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */ 1084 cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
1085
1086 if (want_ncq && sata_pmp_attached(ap)) {
1087 cfg |= EDMA_CFG_EDMA_FBS; /* FIS-based switching */
1088 mv_config_fbs(port_mmio, 1);
1089 } else {
1090 mv_config_fbs(port_mmio, 0);
1091 }
1038 } 1092 }
1039 1093
1040 if (want_ncq) { 1094 if (want_ncq) {
@@ -1240,6 +1294,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
1240 flags |= CRQB_FLAG_READ; 1294 flags |= CRQB_FLAG_READ;
1241 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); 1295 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1242 flags |= qc->tag << CRQB_TAG_SHIFT; 1296 flags |= qc->tag << CRQB_TAG_SHIFT;
1297 flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
1243 1298
1244 /* get current queue index from software */ 1299 /* get current queue index from software */
1245 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK; 1300 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
@@ -1331,6 +1386,7 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
1331 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag); 1386 WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
1332 flags |= qc->tag << CRQB_TAG_SHIFT; 1387 flags |= qc->tag << CRQB_TAG_SHIFT;
1333 flags |= qc->tag << CRQB_HOSTQ_SHIFT; 1388 flags |= qc->tag << CRQB_HOSTQ_SHIFT;
1389 flags |= (qc->dev->link->pmp & 0xf) << CRQB_PMP_SHIFT;
1334 1390
1335 /* get current queue index from software */ 1391 /* get current queue index from software */
1336 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK; 1392 in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
@@ -1394,6 +1450,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
1394 * shadow block, etc registers. 1450 * shadow block, etc registers.
1395 */ 1451 */
1396 mv_stop_edma(ap); 1452 mv_stop_edma(ap);
1453 mv_pmp_select(ap, qc->dev->link->pmp);
1397 return ata_sff_qc_issue(qc); 1454 return ata_sff_qc_issue(qc);
1398 } 1455 }
1399 1456
@@ -2289,6 +2346,34 @@ static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
2289 mdelay(1); 2346 mdelay(1);
2290} 2347}
2291 2348
2349static void mv_pmp_select(struct ata_port *ap, int pmp)
2350{
2351 if (sata_pmp_supported(ap)) {
2352 void __iomem *port_mmio = mv_ap_base(ap);
2353 u32 reg = readl(port_mmio + SATA_IFCTL_OFS);
2354 int old = reg & 0xf;
2355
2356 if (old != pmp) {
2357 reg = (reg & ~0xf) | pmp;
2358 writelfl(reg, port_mmio + SATA_IFCTL_OFS);
2359 }
2360 }
2361}
2362
2363static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
2364 unsigned long deadline)
2365{
2366 mv_pmp_select(link->ap, sata_srst_pmp(link));
2367 return sata_std_hardreset(link, class, deadline);
2368}
2369
2370static int mv_softreset(struct ata_link *link, unsigned int *class,
2371 unsigned long deadline)
2372{
2373 mv_pmp_select(link->ap, sata_srst_pmp(link));
2374 return ata_sff_softreset(link, class, deadline);
2375}
2376
2292static int mv_hardreset(struct ata_link *link, unsigned int *class, 2377static int mv_hardreset(struct ata_link *link, unsigned int *class,
2293 unsigned long deadline) 2378 unsigned long deadline)
2294{ 2379{