diff options
-rw-r--r-- | drivers/ata/ata_piix.c | 251 |
1 files changed, 247 insertions, 4 deletions
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 024e6d52eab2..a65c8ae5c461 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -101,9 +101,14 @@ enum { | |||
101 | ICH5_PMR = 0x90, /* port mapping register */ | 101 | ICH5_PMR = 0x90, /* port mapping register */ |
102 | ICH5_PCS = 0x92, /* port control and status */ | 102 | ICH5_PCS = 0x92, /* port control and status */ |
103 | PIIX_SCC = 0x0A, /* sub-class code register */ | 103 | PIIX_SCC = 0x0A, /* sub-class code register */ |
104 | PIIX_SIDPR_BAR = 5, | ||
105 | PIIX_SIDPR_LEN = 16, | ||
106 | PIIX_SIDPR_IDX = 0, | ||
107 | PIIX_SIDPR_DATA = 4, | ||
104 | 108 | ||
105 | PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ | 109 | PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ |
106 | PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ | 110 | PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ |
111 | PIIX_FLAG_SIDPR = (1 << 29), /* SATA idx/data pair regs */ | ||
107 | 112 | ||
108 | PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, | 113 | PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, |
109 | PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, | 114 | PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, |
@@ -152,6 +157,7 @@ struct piix_map_db { | |||
152 | 157 | ||
153 | struct piix_host_priv { | 158 | struct piix_host_priv { |
154 | const int *map; | 159 | const int *map; |
160 | void __iomem *sidpr; | ||
155 | }; | 161 | }; |
156 | 162 | ||
157 | static int piix_init_one(struct pci_dev *pdev, | 163 | static int piix_init_one(struct pci_dev *pdev, |
@@ -162,6 +168,9 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); | |||
162 | static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); | 168 | static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); |
163 | static int ich_pata_cable_detect(struct ata_port *ap); | 169 | static int ich_pata_cable_detect(struct ata_port *ap); |
164 | static u8 piix_vmw_bmdma_status(struct ata_port *ap); | 170 | static u8 piix_vmw_bmdma_status(struct ata_port *ap); |
171 | static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); | ||
172 | static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); | ||
173 | static void piix_sidpr_error_handler(struct ata_port *ap); | ||
165 | #ifdef CONFIG_PM | 174 | #ifdef CONFIG_PM |
166 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); | 175 | static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); |
167 | static int piix_pci_device_resume(struct pci_dev *pdev); | 176 | static int piix_pci_device_resume(struct pci_dev *pdev); |
@@ -411,6 +420,35 @@ static const struct ata_port_operations piix_vmw_ops = { | |||
411 | .port_start = ata_port_start, | 420 | .port_start = ata_port_start, |
412 | }; | 421 | }; |
413 | 422 | ||
423 | static const struct ata_port_operations piix_sidpr_sata_ops = { | ||
424 | .tf_load = ata_tf_load, | ||
425 | .tf_read = ata_tf_read, | ||
426 | .check_status = ata_check_status, | ||
427 | .exec_command = ata_exec_command, | ||
428 | .dev_select = ata_std_dev_select, | ||
429 | |||
430 | .bmdma_setup = ata_bmdma_setup, | ||
431 | .bmdma_start = ata_bmdma_start, | ||
432 | .bmdma_stop = ata_bmdma_stop, | ||
433 | .bmdma_status = ata_bmdma_status, | ||
434 | .qc_prep = ata_qc_prep, | ||
435 | .qc_issue = ata_qc_issue_prot, | ||
436 | .data_xfer = ata_data_xfer, | ||
437 | |||
438 | .scr_read = piix_sidpr_scr_read, | ||
439 | .scr_write = piix_sidpr_scr_write, | ||
440 | |||
441 | .freeze = ata_bmdma_freeze, | ||
442 | .thaw = ata_bmdma_thaw, | ||
443 | .error_handler = piix_sidpr_error_handler, | ||
444 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
445 | |||
446 | .irq_clear = ata_bmdma_irq_clear, | ||
447 | .irq_on = ata_irq_on, | ||
448 | |||
449 | .port_start = ata_port_start, | ||
450 | }; | ||
451 | |||
414 | static const struct piix_map_db ich5_map_db = { | 452 | static const struct piix_map_db ich5_map_db = { |
415 | .mask = 0x7, | 453 | .mask = 0x7, |
416 | .port_enable = 0x3, | 454 | .port_enable = 0x3, |
@@ -598,7 +636,8 @@ static struct ata_port_info piix_port_info[] = { | |||
598 | 636 | ||
599 | [ich8_sata_ahci] = | 637 | [ich8_sata_ahci] = |
600 | { | 638 | { |
601 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, | 639 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | |
640 | PIIX_FLAG_SIDPR, | ||
602 | .pio_mask = 0x1f, /* pio0-4 */ | 641 | .pio_mask = 0x1f, /* pio0-4 */ |
603 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 642 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
604 | .udma_mask = ATA_UDMA6, | 643 | .udma_mask = ATA_UDMA6, |
@@ -607,7 +646,8 @@ static struct ata_port_info piix_port_info[] = { | |||
607 | 646 | ||
608 | [ich8_2port_sata] = | 647 | [ich8_2port_sata] = |
609 | { | 648 | { |
610 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, | 649 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | |
650 | PIIX_FLAG_SIDPR, | ||
611 | .pio_mask = 0x1f, /* pio0-4 */ | 651 | .pio_mask = 0x1f, /* pio0-4 */ |
612 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 652 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
613 | .udma_mask = ATA_UDMA6, | 653 | .udma_mask = ATA_UDMA6, |
@@ -625,7 +665,8 @@ static struct ata_port_info piix_port_info[] = { | |||
625 | 665 | ||
626 | [ich8m_apple_sata_ahci] = | 666 | [ich8m_apple_sata_ahci] = |
627 | { | 667 | { |
628 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, | 668 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | |
669 | PIIX_FLAG_SIDPR, | ||
629 | .pio_mask = 0x1f, /* pio0-4 */ | 670 | .pio_mask = 0x1f, /* pio0-4 */ |
630 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 671 | .mwdma_mask = 0x07, /* mwdma0-2 */ |
631 | .udma_mask = ATA_UDMA6, | 672 | .udma_mask = ATA_UDMA6, |
@@ -974,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |||
974 | do_pata_set_dmamode(ap, adev, 1); | 1015 | do_pata_set_dmamode(ap, adev, 1); |
975 | } | 1016 | } |
976 | 1017 | ||
1018 | /* | ||
1019 | * Serial ATA Index/Data Pair Superset Registers access | ||
1020 | * | ||
1021 | * Beginning from ICH8, there's a sane way to access SCRs using index | ||
1022 | * and data register pair located at BAR5. This creates an | ||
1023 | * interesting problem of mapping two SCRs to one port. | ||
1024 | * | ||
1025 | * Although they have separate SCRs, the master and slave aren't | ||
1026 | * independent enough to be treated as separate links - e.g. softreset | ||
1027 | * resets both. Also, there's no protocol defined for hard resetting | ||
1028 | * singled device sharing the virtual port (no defined way to acquire | ||
1029 | * device signature). This is worked around by merging the SCR values | ||
1030 | * into one sensible value and requesting follow-up SRST after | ||
1031 | * hardreset. | ||
1032 | * | ||
1033 | * SCR merging is perfomed in nibbles which is the unit contents in | ||
1034 | * SCRs are organized. If two values are equal, the value is used. | ||
1035 | * When they differ, merge table which lists precedence of possible | ||
1036 | * values is consulted and the first match or the last entry when | ||
1037 | * nothing matches is used. When there's no merge table for the | ||
1038 | * specific nibble, value from the first port is used. | ||
1039 | */ | ||
1040 | static const int piix_sidx_map[] = { | ||
1041 | [SCR_STATUS] = 0, | ||
1042 | [SCR_ERROR] = 2, | ||
1043 | [SCR_CONTROL] = 1, | ||
1044 | }; | ||
1045 | |||
1046 | static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg) | ||
1047 | { | ||
1048 | struct ata_port *ap = dev->link->ap; | ||
1049 | struct piix_host_priv *hpriv = ap->host->private_data; | ||
1050 | |||
1051 | iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg], | ||
1052 | hpriv->sidpr + PIIX_SIDPR_IDX); | ||
1053 | } | ||
1054 | |||
1055 | static int piix_sidpr_read(struct ata_device *dev, unsigned int reg) | ||
1056 | { | ||
1057 | struct piix_host_priv *hpriv = dev->link->ap->host->private_data; | ||
1058 | |||
1059 | piix_sidpr_sel(dev, reg); | ||
1060 | return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); | ||
1061 | } | ||
1062 | |||
1063 | static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val) | ||
1064 | { | ||
1065 | struct piix_host_priv *hpriv = dev->link->ap->host->private_data; | ||
1066 | |||
1067 | piix_sidpr_sel(dev, reg); | ||
1068 | iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); | ||
1069 | } | ||
1070 | |||
1071 | u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) | ||
1072 | { | ||
1073 | u32 val = 0; | ||
1074 | int i, mi; | ||
1075 | |||
1076 | for (i = 0, mi = 0; i < 32 / 4; i++) { | ||
1077 | u8 c0 = (val0 >> (i * 4)) & 0xf; | ||
1078 | u8 c1 = (val1 >> (i * 4)) & 0xf; | ||
1079 | u8 merged = c0; | ||
1080 | const int *cur; | ||
1081 | |||
1082 | /* if no merge preference, assume the first value */ | ||
1083 | cur = merge_tbl[mi]; | ||
1084 | if (!cur) | ||
1085 | goto done; | ||
1086 | mi++; | ||
1087 | |||
1088 | /* if two values equal, use it */ | ||
1089 | if (c0 == c1) | ||
1090 | goto done; | ||
1091 | |||
1092 | /* choose the first match or the last from the merge table */ | ||
1093 | while (*cur != -1) { | ||
1094 | if (c0 == *cur || c1 == *cur) | ||
1095 | break; | ||
1096 | cur++; | ||
1097 | } | ||
1098 | if (*cur == -1) | ||
1099 | cur--; | ||
1100 | merged = *cur; | ||
1101 | done: | ||
1102 | val |= merged << (i * 4); | ||
1103 | } | ||
1104 | |||
1105 | return val; | ||
1106 | } | ||
1107 | |||
1108 | static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val) | ||
1109 | { | ||
1110 | const int * const sstatus_merge_tbl[] = { | ||
1111 | /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 }, | ||
1112 | /* SPD */ (const int []){ 2, 1, 0, -1 }, | ||
1113 | /* IPM */ (const int []){ 6, 2, 1, 0, -1 }, | ||
1114 | NULL, | ||
1115 | }; | ||
1116 | const int * const scontrol_merge_tbl[] = { | ||
1117 | /* DET */ (const int []){ 1, 0, 4, 0, -1 }, | ||
1118 | /* SPD */ (const int []){ 0, 2, 1, 0, -1 }, | ||
1119 | /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 }, | ||
1120 | NULL, | ||
1121 | }; | ||
1122 | u32 v0, v1; | ||
1123 | |||
1124 | if (reg >= ARRAY_SIZE(piix_sidx_map)) | ||
1125 | return -EINVAL; | ||
1126 | |||
1127 | if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { | ||
1128 | *val = piix_sidpr_read(&ap->link.device[0], reg); | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | v0 = piix_sidpr_read(&ap->link.device[0], reg); | ||
1133 | v1 = piix_sidpr_read(&ap->link.device[1], reg); | ||
1134 | |||
1135 | switch (reg) { | ||
1136 | case SCR_STATUS: | ||
1137 | *val = piix_merge_scr(v0, v1, sstatus_merge_tbl); | ||
1138 | break; | ||
1139 | case SCR_ERROR: | ||
1140 | *val = v0 | v1; | ||
1141 | break; | ||
1142 | case SCR_CONTROL: | ||
1143 | *val = piix_merge_scr(v0, v1, scontrol_merge_tbl); | ||
1144 | break; | ||
1145 | } | ||
1146 | |||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) | ||
1151 | { | ||
1152 | if (reg >= ARRAY_SIZE(piix_sidx_map)) | ||
1153 | return -EINVAL; | ||
1154 | |||
1155 | piix_sidpr_write(&ap->link.device[0], reg, val); | ||
1156 | |||
1157 | if (ap->flags & ATA_FLAG_SLAVE_POSS) | ||
1158 | piix_sidpr_write(&ap->link.device[1], reg, val); | ||
1159 | |||
1160 | return 0; | ||
1161 | } | ||
1162 | |||
1163 | static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, | ||
1164 | unsigned long deadline) | ||
1165 | { | ||
1166 | const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); | ||
1167 | int rc; | ||
1168 | |||
1169 | /* do hardreset */ | ||
1170 | rc = sata_link_hardreset(link, timing, deadline); | ||
1171 | if (rc) { | ||
1172 | ata_link_printk(link, KERN_ERR, | ||
1173 | "COMRESET failed (errno=%d)\n", rc); | ||
1174 | return rc; | ||
1175 | } | ||
1176 | |||
1177 | /* TODO: phy layer with polling, timeouts, etc. */ | ||
1178 | if (ata_link_offline(link)) { | ||
1179 | *class = ATA_DEV_NONE; | ||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | return -EAGAIN; | ||
1184 | } | ||
1185 | |||
1186 | static void piix_sidpr_error_handler(struct ata_port *ap) | ||
1187 | { | ||
1188 | ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, | ||
1189 | piix_sidpr_hardreset, ata_std_postreset); | ||
1190 | } | ||
1191 | |||
977 | #ifdef CONFIG_PM | 1192 | #ifdef CONFIG_PM |
978 | static int piix_broken_suspend(void) | 1193 | static int piix_broken_suspend(void) |
979 | { | 1194 | { |
@@ -1304,6 +1519,32 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, | |||
1304 | return map; | 1519 | return map; |
1305 | } | 1520 | } |
1306 | 1521 | ||
1522 | static void __devinit piix_init_sidpr(struct ata_host *host) | ||
1523 | { | ||
1524 | struct pci_dev *pdev = to_pci_dev(host->dev); | ||
1525 | struct piix_host_priv *hpriv = host->private_data; | ||
1526 | int i; | ||
1527 | |||
1528 | /* check for availability */ | ||
1529 | for (i = 0; i < 4; i++) | ||
1530 | if (hpriv->map[i] == IDE) | ||
1531 | return; | ||
1532 | |||
1533 | if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) | ||
1534 | return; | ||
1535 | |||
1536 | if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || | ||
1537 | pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) | ||
1538 | return; | ||
1539 | |||
1540 | if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) | ||
1541 | return; | ||
1542 | |||
1543 | hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; | ||
1544 | host->ports[0]->ops = &piix_sidpr_sata_ops; | ||
1545 | host->ports[1]->ops = &piix_sidpr_sata_ops; | ||
1546 | } | ||
1547 | |||
1307 | static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) | 1548 | static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) |
1308 | { | 1549 | { |
1309 | static const struct dmi_system_id sysids[] = { | 1550 | static const struct dmi_system_id sysids[] = { |
@@ -1408,8 +1649,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1408 | } | 1649 | } |
1409 | } | 1650 | } |
1410 | 1651 | ||
1411 | if (port_flags & ATA_FLAG_SATA) | 1652 | if (port_flags & ATA_FLAG_SATA) { |
1412 | piix_init_pcs(host, piix_map_db_table[ent->driver_data]); | 1653 | piix_init_pcs(host, piix_map_db_table[ent->driver_data]); |
1654 | piix_init_sidpr(host); | ||
1655 | } | ||
1413 | 1656 | ||
1414 | /* apply IOCFG bit18 quirk */ | 1657 | /* apply IOCFG bit18 quirk */ |
1415 | piix_iocfg_bit18_quirk(pdev); | 1658 | piix_iocfg_bit18_quirk(pdev); |