diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 78 |
1 files changed, 76 insertions, 2 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 413270b2c794..8a1f4f059a43 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -215,6 +215,7 @@ static u8 ahci_check_status(struct ata_port *ap); | |||
215 | static void ahci_freeze(struct ata_port *ap); | 215 | static void ahci_freeze(struct ata_port *ap); |
216 | static void ahci_thaw(struct ata_port *ap); | 216 | static void ahci_thaw(struct ata_port *ap); |
217 | static void ahci_error_handler(struct ata_port *ap); | 217 | static void ahci_error_handler(struct ata_port *ap); |
218 | static void ahci_vt8251_error_handler(struct ata_port *ap); | ||
218 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); | 219 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); |
219 | static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); | 220 | static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); |
220 | static int ahci_port_resume(struct ata_port *ap); | 221 | static int ahci_port_resume(struct ata_port *ap); |
@@ -274,6 +275,37 @@ static const struct ata_port_operations ahci_ops = { | |||
274 | .port_stop = ahci_port_stop, | 275 | .port_stop = ahci_port_stop, |
275 | }; | 276 | }; |
276 | 277 | ||
278 | static const struct ata_port_operations ahci_vt8251_ops = { | ||
279 | .port_disable = ata_port_disable, | ||
280 | |||
281 | .check_status = ahci_check_status, | ||
282 | .check_altstatus = ahci_check_status, | ||
283 | .dev_select = ata_noop_dev_select, | ||
284 | |||
285 | .tf_read = ahci_tf_read, | ||
286 | |||
287 | .qc_prep = ahci_qc_prep, | ||
288 | .qc_issue = ahci_qc_issue, | ||
289 | |||
290 | .irq_handler = ahci_interrupt, | ||
291 | .irq_clear = ahci_irq_clear, | ||
292 | |||
293 | .scr_read = ahci_scr_read, | ||
294 | .scr_write = ahci_scr_write, | ||
295 | |||
296 | .freeze = ahci_freeze, | ||
297 | .thaw = ahci_thaw, | ||
298 | |||
299 | .error_handler = ahci_vt8251_error_handler, | ||
300 | .post_internal_cmd = ahci_post_internal_cmd, | ||
301 | |||
302 | .port_suspend = ahci_port_suspend, | ||
303 | .port_resume = ahci_port_resume, | ||
304 | |||
305 | .port_start = ahci_port_start, | ||
306 | .port_stop = ahci_port_stop, | ||
307 | }; | ||
308 | |||
277 | static const struct ata_port_info ahci_port_info[] = { | 309 | static const struct ata_port_info ahci_port_info[] = { |
278 | /* board_ahci */ | 310 | /* board_ahci */ |
279 | { | 311 | { |
@@ -290,10 +322,11 @@ static const struct ata_port_info ahci_port_info[] = { | |||
290 | .sht = &ahci_sht, | 322 | .sht = &ahci_sht, |
291 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 323 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
292 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | | 324 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | |
293 | ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_NO_NCQ, | 325 | ATA_FLAG_SKIP_D2H_BSY | |
326 | ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ, | ||
294 | .pio_mask = 0x1f, /* pio0-4 */ | 327 | .pio_mask = 0x1f, /* pio0-4 */ |
295 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ | 328 | .udma_mask = 0x7f, /* udma0-6 ; FIXME */ |
296 | .port_ops = &ahci_ops, | 329 | .port_ops = &ahci_vt8251_ops, |
297 | }, | 330 | }, |
298 | /* board_ahci_ign_iferr */ | 331 | /* board_ahci_ign_iferr */ |
299 | { | 332 | { |
@@ -864,6 +897,31 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) | |||
864 | return rc; | 897 | return rc; |
865 | } | 898 | } |
866 | 899 | ||
900 | static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) | ||
901 | { | ||
902 | void __iomem *mmio = ap->host->mmio_base; | ||
903 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
904 | int rc; | ||
905 | |||
906 | DPRINTK("ENTER\n"); | ||
907 | |||
908 | ahci_stop_engine(port_mmio); | ||
909 | |||
910 | rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context)); | ||
911 | |||
912 | /* vt8251 needs SError cleared for the port to operate */ | ||
913 | ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR)); | ||
914 | |||
915 | ahci_start_engine(port_mmio); | ||
916 | |||
917 | DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); | ||
918 | |||
919 | /* vt8251 doesn't clear BSY on signature FIS reception, | ||
920 | * request follow-up softreset. | ||
921 | */ | ||
922 | return rc ?: -EAGAIN; | ||
923 | } | ||
924 | |||
867 | static void ahci_postreset(struct ata_port *ap, unsigned int *class) | 925 | static void ahci_postreset(struct ata_port *ap, unsigned int *class) |
868 | { | 926 | { |
869 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; | 927 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; |
@@ -1187,6 +1245,22 @@ static void ahci_error_handler(struct ata_port *ap) | |||
1187 | ahci_postreset); | 1245 | ahci_postreset); |
1188 | } | 1246 | } |
1189 | 1247 | ||
1248 | static void ahci_vt8251_error_handler(struct ata_port *ap) | ||
1249 | { | ||
1250 | void __iomem *mmio = ap->host->mmio_base; | ||
1251 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
1252 | |||
1253 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { | ||
1254 | /* restart engine */ | ||
1255 | ahci_stop_engine(port_mmio); | ||
1256 | ahci_start_engine(port_mmio); | ||
1257 | } | ||
1258 | |||
1259 | /* perform recovery */ | ||
1260 | ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_vt8251_hardreset, | ||
1261 | ahci_postreset); | ||
1262 | } | ||
1263 | |||
1190 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | 1264 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) |
1191 | { | 1265 | { |
1192 | struct ata_port *ap = qc->ap; | 1266 | struct ata_port *ap = qc->ap; |