aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/ahci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r--drivers/ata/ahci.c132
1 files changed, 102 insertions, 30 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index e3a92a6da39a..c81d809c111b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -61,6 +61,7 @@ enum board_ids {
61 /* board IDs by feature in alphabetical order */ 61 /* board IDs by feature in alphabetical order */
62 board_ahci, 62 board_ahci,
63 board_ahci_ign_iferr, 63 board_ahci_ign_iferr,
64 board_ahci_noncq,
64 board_ahci_nosntf, 65 board_ahci_nosntf,
65 board_ahci_yes_fbs, 66 board_ahci_yes_fbs,
66 67
@@ -83,6 +84,8 @@ enum board_ids {
83static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 84static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
84static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 85static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
85 unsigned long deadline); 86 unsigned long deadline);
87static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
88static bool is_mcp89_apple(struct pci_dev *pdev);
86static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, 89static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
87 unsigned long deadline); 90 unsigned long deadline);
88#ifdef CONFIG_PM 91#ifdef CONFIG_PM
@@ -119,6 +122,13 @@ static const struct ata_port_info ahci_port_info[] = {
119 .udma_mask = ATA_UDMA6, 122 .udma_mask = ATA_UDMA6,
120 .port_ops = &ahci_ops, 123 .port_ops = &ahci_ops,
121 }, 124 },
125 [board_ahci_noncq] = {
126 AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ),
127 .flags = AHCI_FLAG_COMMON,
128 .pio_mask = ATA_PIO4,
129 .udma_mask = ATA_UDMA6,
130 .port_ops = &ahci_ops,
131 },
122 [board_ahci_nosntf] = { 132 [board_ahci_nosntf] = {
123 AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), 133 AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF),
124 .flags = AHCI_FLAG_COMMON, 134 .flags = AHCI_FLAG_COMMON,
@@ -450,6 +460,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
450 { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ 460 { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
451 { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ 461 { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
452 462
463 /*
464 * Samsung SSDs found on some macbooks. NCQ times out.
465 * https://bugzilla.kernel.org/show_bug.cgi?id=60731
466 */
467 { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
468
453 /* Enmotus */ 469 /* Enmotus */
454 { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, 470 { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
455 471
@@ -664,6 +680,10 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
664 if (rc) 680 if (rc)
665 return rc; 681 return rc;
666 682
683 /* Apple BIOS helpfully mangles the registers on resume */
684 if (is_mcp89_apple(pdev))
685 ahci_mcp89_apple_enable(pdev);
686
667 if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { 687 if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
668 rc = ahci_pci_reset_controller(host); 688 rc = ahci_pci_reset_controller(host);
669 if (rc) 689 if (rc)
@@ -780,6 +800,48 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
780 } 800 }
781} 801}
782 802
803/*
804 * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when
805 * booting in BIOS compatibility mode. We restore the registers but not ID.
806 */
807static void ahci_mcp89_apple_enable(struct pci_dev *pdev)
808{
809 u32 val;
810
811 printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n");
812
813 pci_read_config_dword(pdev, 0xf8, &val);
814 val |= 1 << 0x1b;
815 /* the following changes the device ID, but appears not to affect function */
816 /* val = (val & ~0xf0000000) | 0x80000000; */
817 pci_write_config_dword(pdev, 0xf8, val);
818
819 pci_read_config_dword(pdev, 0x54c, &val);
820 val |= 1 << 0xc;
821 pci_write_config_dword(pdev, 0x54c, val);
822
823 pci_read_config_dword(pdev, 0x4a4, &val);
824 val &= 0xff;
825 val |= 0x01060100;
826 pci_write_config_dword(pdev, 0x4a4, val);
827
828 pci_read_config_dword(pdev, 0x54c, &val);
829 val &= ~(1 << 0xc);
830 pci_write_config_dword(pdev, 0x54c, val);
831
832 pci_read_config_dword(pdev, 0xf8, &val);
833 val &= ~(1 << 0x1b);
834 pci_write_config_dword(pdev, 0xf8, val);
835}
836
837static bool is_mcp89_apple(struct pci_dev *pdev)
838{
839 return pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
840 pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
841 pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
842 pdev->subsystem_device == 0xcb89;
843}
844
783/* only some SB600 ahci controllers can do 64bit DMA */ 845/* only some SB600 ahci controllers can do 64bit DMA */
784static bool ahci_sb600_enable_64bit(struct pci_dev *pdev) 846static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
785{ 847{
@@ -1100,26 +1162,42 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
1100{} 1162{}
1101#endif 1163#endif
1102 1164
1103int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) 1165static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
1166 struct ahci_host_priv *hpriv)
1104{ 1167{
1105 int rc; 1168 int rc, nvec;
1106 unsigned int maxvec;
1107 1169
1108 if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) { 1170 if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1109 rc = pci_enable_msi_block_auto(pdev, &maxvec); 1171 goto intx;
1110 if (rc > 0) { 1172
1111 if ((rc == maxvec) || (rc == 1)) 1173 rc = pci_msi_vec_count(pdev);
1112 return rc; 1174 if (rc < 0)
1113 /* 1175 goto intx;
1114 * Assume that advantage of multipe MSIs is negated, 1176
1115 * so fallback to single MSI mode to save resources 1177 /*
1116 */ 1178 * If number of MSIs is less than number of ports then Sharing Last
1117 pci_disable_msi(pdev); 1179 * Message mode could be enforced. In this case assume that advantage
1118 if (!pci_enable_msi(pdev)) 1180 * of multipe MSIs is negated and use single MSI mode instead.
1119 return 1; 1181 */
1120 } 1182 if (rc < n_ports)
1121 } 1183 goto single_msi;
1184
1185 nvec = rc;
1186 rc = pci_enable_msi_block(pdev, nvec);
1187 if (rc < 0)
1188 goto intx;
1189 else if (rc > 0)
1190 goto single_msi;
1191
1192 return nvec;
1122 1193
1194single_msi:
1195 rc = pci_enable_msi(pdev);
1196 if (rc)
1197 goto intx;
1198 return 1;
1199
1200intx:
1123 pci_intx(pdev, 1); 1201 pci_intx(pdev, 1);
1124 return 0; 1202 return 0;
1125} 1203}
@@ -1212,15 +1290,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1212 if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable) 1290 if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable)
1213 return -ENODEV; 1291 return -ENODEV;
1214 1292
1215 /* 1293 /* Apple BIOS on MCP89 prevents us using AHCI */
1216 * For some reason, MCP89 on MacBook 7,1 doesn't work with 1294 if (is_mcp89_apple(pdev))
1217 * ahci, use ata_generic instead. 1295 ahci_mcp89_apple_enable(pdev);
1218 */
1219 if (pdev->vendor == PCI_VENDOR_ID_NVIDIA &&
1220 pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA &&
1221 pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
1222 pdev->subsystem_device == 0xcb89)
1223 return -ENODEV;
1224 1296
1225 /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode. 1297 /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode.
1226 * At the moment, we can only use the AHCI mode. Let the users know 1298 * At the moment, we can only use the AHCI mode. Let the users know
@@ -1286,10 +1358,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1286 1358
1287 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; 1359 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1288 1360
1289 n_msis = ahci_init_interrupts(pdev, hpriv);
1290 if (n_msis > 1)
1291 hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
1292
1293 /* save initial config */ 1361 /* save initial config */
1294 ahci_pci_save_initial_config(pdev, hpriv); 1362 ahci_pci_save_initial_config(pdev, hpriv);
1295 1363
@@ -1344,6 +1412,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1344 */ 1412 */
1345 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 1413 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1346 1414
1415 n_msis = ahci_init_interrupts(pdev, n_ports, hpriv);
1416 if (n_msis > 1)
1417 hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
1418
1347 host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 1419 host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
1348 if (!host) 1420 if (!host)
1349 return -ENOMEM; 1421 return -ENOMEM;