diff options
Diffstat (limited to 'drivers/scsi/sata_sil24.c')
-rw-r--r-- | drivers/scsi/sata_sil24.c | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 07a1c6a8a414..3f368c7d3ef9 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c | |||
@@ -92,6 +92,7 @@ enum { | |||
92 | HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ | 92 | HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ |
93 | HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ | 93 | HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ |
94 | HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ | 94 | HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ |
95 | HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ | ||
95 | 96 | ||
96 | /* | 97 | /* |
97 | * Port registers | 98 | * Port registers |
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap); | |||
338 | static void sil24_port_stop(struct ata_port *ap); | 339 | static void sil24_port_stop(struct ata_port *ap); |
339 | static void sil24_host_stop(struct ata_host_set *host_set); | 340 | static void sil24_host_stop(struct ata_host_set *host_set); |
340 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | 341 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
342 | static int sil24_pci_device_resume(struct pci_dev *pdev); | ||
341 | 343 | ||
342 | static const struct pci_device_id sil24_pci_tbl[] = { | 344 | static const struct pci_device_id sil24_pci_tbl[] = { |
343 | { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, | 345 | { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, |
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = { | |||
353 | .id_table = sil24_pci_tbl, | 355 | .id_table = sil24_pci_tbl, |
354 | .probe = sil24_init_one, | 356 | .probe = sil24_init_one, |
355 | .remove = ata_pci_remove_one, /* safe? */ | 357 | .remove = ata_pci_remove_one, /* safe? */ |
358 | .suspend = ata_pci_device_suspend, | ||
359 | .resume = sil24_pci_device_resume, | ||
356 | }; | 360 | }; |
357 | 361 | ||
358 | static struct scsi_host_template sil24_sht = { | 362 | static struct scsi_host_template sil24_sht = { |
@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = { | |||
372 | .slave_configure = ata_scsi_slave_config, | 376 | .slave_configure = ata_scsi_slave_config, |
373 | .slave_destroy = ata_scsi_slave_destroy, | 377 | .slave_destroy = ata_scsi_slave_destroy, |
374 | .bios_param = ata_std_bios_param, | 378 | .bios_param = ata_std_bios_param, |
379 | .suspend = ata_scsi_device_suspend, | ||
380 | .resume = ata_scsi_device_resume, | ||
375 | }; | 381 | }; |
376 | 382 | ||
377 | static const struct ata_port_operations sil24_ops = { | 383 | static const struct ata_port_operations sil24_ops = { |
@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) | |||
607 | /* SStatus oscillates between zero and valid status after | 613 | /* SStatus oscillates between zero and valid status after |
608 | * DEV_RST, debounce it. | 614 | * DEV_RST, debounce it. |
609 | */ | 615 | */ |
610 | rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst); | 616 | rc = sata_phy_debounce(ap, sata_deb_timing_long); |
611 | if (rc) { | 617 | if (rc) { |
612 | reason = "PHY debouncing failed"; | 618 | reason = "PHY debouncing failed"; |
613 | goto err; | 619 | goto err; |
@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set) | |||
988 | kfree(hpriv); | 994 | kfree(hpriv); |
989 | } | 995 | } |
990 | 996 | ||
997 | static void sil24_init_controller(struct pci_dev *pdev, int n_ports, | ||
998 | unsigned long host_flags, | ||
999 | void __iomem *host_base, | ||
1000 | void __iomem *port_base) | ||
1001 | { | ||
1002 | u32 tmp; | ||
1003 | int i; | ||
1004 | |||
1005 | /* GPIO off */ | ||
1006 | writel(0, host_base + HOST_FLASH_CMD); | ||
1007 | |||
1008 | /* clear global reset & mask interrupts during initialization */ | ||
1009 | writel(0, host_base + HOST_CTRL); | ||
1010 | |||
1011 | /* init ports */ | ||
1012 | for (i = 0; i < n_ports; i++) { | ||
1013 | void __iomem *port = port_base + i * PORT_REGS_SIZE; | ||
1014 | |||
1015 | /* Initial PHY setting */ | ||
1016 | writel(0x20c, port + PORT_PHY_CFG); | ||
1017 | |||
1018 | /* Clear port RST */ | ||
1019 | tmp = readl(port + PORT_CTRL_STAT); | ||
1020 | if (tmp & PORT_CS_PORT_RST) { | ||
1021 | writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); | ||
1022 | tmp = ata_wait_register(port + PORT_CTRL_STAT, | ||
1023 | PORT_CS_PORT_RST, | ||
1024 | PORT_CS_PORT_RST, 10, 100); | ||
1025 | if (tmp & PORT_CS_PORT_RST) | ||
1026 | dev_printk(KERN_ERR, &pdev->dev, | ||
1027 | "failed to clear port RST\n"); | ||
1028 | } | ||
1029 | |||
1030 | /* Configure IRQ WoC */ | ||
1031 | if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC) | ||
1032 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); | ||
1033 | else | ||
1034 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); | ||
1035 | |||
1036 | /* Zero error counters. */ | ||
1037 | writel(0x8000, port + PORT_DECODE_ERR_THRESH); | ||
1038 | writel(0x8000, port + PORT_CRC_ERR_THRESH); | ||
1039 | writel(0x8000, port + PORT_HSHK_ERR_THRESH); | ||
1040 | writel(0x0000, port + PORT_DECODE_ERR_CNT); | ||
1041 | writel(0x0000, port + PORT_CRC_ERR_CNT); | ||
1042 | writel(0x0000, port + PORT_HSHK_ERR_CNT); | ||
1043 | |||
1044 | /* Always use 64bit activation */ | ||
1045 | writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); | ||
1046 | |||
1047 | /* Clear port multiplier enable and resume bits */ | ||
1048 | writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); | ||
1049 | } | ||
1050 | |||
1051 | /* Turn on interrupts */ | ||
1052 | writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); | ||
1053 | } | ||
1054 | |||
991 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 1055 | static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
992 | { | 1056 | { |
993 | static int printed_version = 0; | 1057 | static int printed_version = 0; |
@@ -1042,7 +1106,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1042 | 1106 | ||
1043 | probe_ent->irq = pdev->irq; | 1107 | probe_ent->irq = pdev->irq; |
1044 | probe_ent->irq_flags = IRQF_SHARED; | 1108 | probe_ent->irq_flags = IRQF_SHARED; |
1045 | probe_ent->mmio_base = port_base; | ||
1046 | probe_ent->private_data = hpriv; | 1109 | probe_ent->private_data = hpriv; |
1047 | 1110 | ||
1048 | hpriv->host_base = host_base; | 1111 | hpriv->host_base = host_base; |
@@ -1076,9 +1139,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1076 | } | 1139 | } |
1077 | } | 1140 | } |
1078 | 1141 | ||
1079 | /* GPIO off */ | ||
1080 | writel(0, host_base + HOST_FLASH_CMD); | ||
1081 | |||
1082 | /* Apply workaround for completion IRQ loss on PCI-X errata */ | 1142 | /* Apply workaround for completion IRQ loss on PCI-X errata */ |
1083 | if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) { | 1143 | if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) { |
1084 | tmp = readl(host_base + HOST_CTRL); | 1144 | tmp = readl(host_base + HOST_CTRL); |
@@ -1090,56 +1150,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1090 | probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; | 1150 | probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; |
1091 | } | 1151 | } |
1092 | 1152 | ||
1093 | /* clear global reset & mask interrupts during initialization */ | ||
1094 | writel(0, host_base + HOST_CTRL); | ||
1095 | |||
1096 | for (i = 0; i < probe_ent->n_ports; i++) { | 1153 | for (i = 0; i < probe_ent->n_ports; i++) { |
1097 | void __iomem *port = port_base + i * PORT_REGS_SIZE; | 1154 | unsigned long portu = |
1098 | unsigned long portu = (unsigned long)port; | 1155 | (unsigned long)port_base + i * PORT_REGS_SIZE; |
1099 | 1156 | ||
1100 | probe_ent->port[i].cmd_addr = portu; | 1157 | probe_ent->port[i].cmd_addr = portu; |
1101 | probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; | 1158 | probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; |
1102 | 1159 | ||
1103 | ata_std_ports(&probe_ent->port[i]); | 1160 | ata_std_ports(&probe_ent->port[i]); |
1104 | |||
1105 | /* Initial PHY setting */ | ||
1106 | writel(0x20c, port + PORT_PHY_CFG); | ||
1107 | |||
1108 | /* Clear port RST */ | ||
1109 | tmp = readl(port + PORT_CTRL_STAT); | ||
1110 | if (tmp & PORT_CS_PORT_RST) { | ||
1111 | writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); | ||
1112 | tmp = ata_wait_register(port + PORT_CTRL_STAT, | ||
1113 | PORT_CS_PORT_RST, | ||
1114 | PORT_CS_PORT_RST, 10, 100); | ||
1115 | if (tmp & PORT_CS_PORT_RST) | ||
1116 | dev_printk(KERN_ERR, &pdev->dev, | ||
1117 | "failed to clear port RST\n"); | ||
1118 | } | ||
1119 | |||
1120 | /* Configure IRQ WoC */ | ||
1121 | if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) | ||
1122 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); | ||
1123 | else | ||
1124 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); | ||
1125 | |||
1126 | /* Zero error counters. */ | ||
1127 | writel(0x8000, port + PORT_DECODE_ERR_THRESH); | ||
1128 | writel(0x8000, port + PORT_CRC_ERR_THRESH); | ||
1129 | writel(0x8000, port + PORT_HSHK_ERR_THRESH); | ||
1130 | writel(0x0000, port + PORT_DECODE_ERR_CNT); | ||
1131 | writel(0x0000, port + PORT_CRC_ERR_CNT); | ||
1132 | writel(0x0000, port + PORT_HSHK_ERR_CNT); | ||
1133 | |||
1134 | /* Always use 64bit activation */ | ||
1135 | writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); | ||
1136 | |||
1137 | /* Clear port multiplier enable and resume bits */ | ||
1138 | writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); | ||
1139 | } | 1161 | } |
1140 | 1162 | ||
1141 | /* Turn on interrupts */ | 1163 | sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags, |
1142 | writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); | 1164 | host_base, port_base); |
1143 | 1165 | ||
1144 | pci_set_master(pdev); | 1166 | pci_set_master(pdev); |
1145 | 1167 | ||
@@ -1162,6 +1184,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1162 | return rc; | 1184 | return rc; |
1163 | } | 1185 | } |
1164 | 1186 | ||
1187 | static int sil24_pci_device_resume(struct pci_dev *pdev) | ||
1188 | { | ||
1189 | struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); | ||
1190 | struct sil24_host_priv *hpriv = host_set->private_data; | ||
1191 | |||
1192 | ata_pci_device_do_resume(pdev); | ||
1193 | |||
1194 | if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) | ||
1195 | writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL); | ||
1196 | |||
1197 | sil24_init_controller(pdev, host_set->n_ports, | ||
1198 | host_set->ports[0]->flags, | ||
1199 | hpriv->host_base, hpriv->port_base); | ||
1200 | |||
1201 | ata_host_set_resume(host_set); | ||
1202 | |||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1165 | static int __init sil24_init(void) | 1206 | static int __init sil24_init(void) |
1166 | { | 1207 | { |
1167 | return pci_module_init(&sil24_pci_driver); | 1208 | return pci_module_init(&sil24_pci_driver); |