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.c50
1 files changed, 36 insertions, 14 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 5a0bf8ed649b..60707814a84b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1115,6 +1115,17 @@ static bool ahci_broken_online(struct pci_dev *pdev)
1115 return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); 1115 return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
1116} 1116}
1117 1117
1118static bool ahci_broken_devslp(struct pci_dev *pdev)
1119{
1120 /* device with broken DEVSLP but still showing SDS capability */
1121 static const struct pci_device_id ids[] = {
1122 { PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */
1123 {}
1124 };
1125
1126 return pci_match_id(ids, pdev);
1127}
1128
1118#ifdef CONFIG_ATA_ACPI 1129#ifdef CONFIG_ATA_ACPI
1119static void ahci_gtf_filter_workaround(struct ata_host *host) 1130static void ahci_gtf_filter_workaround(struct ata_host *host)
1120{ 1131{
@@ -1164,9 +1175,9 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
1164#endif 1175#endif
1165 1176
1166static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, 1177static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
1167 struct ahci_host_priv *hpriv) 1178 struct ahci_host_priv *hpriv)
1168{ 1179{
1169 int nvec; 1180 int rc, nvec;
1170 1181
1171 if (hpriv->flags & AHCI_HFLAG_NO_MSI) 1182 if (hpriv->flags & AHCI_HFLAG_NO_MSI)
1172 goto intx; 1183 goto intx;
@@ -1183,12 +1194,19 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
1183 if (nvec < n_ports) 1194 if (nvec < n_ports)
1184 goto single_msi; 1195 goto single_msi;
1185 1196
1186 nvec = pci_enable_msi_range(pdev, nvec, nvec); 1197 rc = pci_enable_msi_exact(pdev, nvec);
1187 if (nvec == -ENOSPC) 1198 if (rc == -ENOSPC)
1188 goto single_msi; 1199 goto single_msi;
1189 else if (nvec < 0) 1200 else if (rc < 0)
1190 goto intx; 1201 goto intx;
1191 1202
1203 /* fallback to single MSI mode if the controller enforced MRSM mode */
1204 if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
1205 pci_disable_msi(pdev);
1206 printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
1207 goto single_msi;
1208 }
1209
1192 return nvec; 1210 return nvec;
1193 1211
1194single_msi: 1212single_msi:
@@ -1232,18 +1250,18 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
1232 return rc; 1250 return rc;
1233 1251
1234 for (i = 0; i < host->n_ports; i++) { 1252 for (i = 0; i < host->n_ports; i++) {
1235 const char* desc;
1236 struct ahci_port_priv *pp = host->ports[i]->private_data; 1253 struct ahci_port_priv *pp = host->ports[i]->private_data;
1237 1254
1238 /* pp is NULL for dummy ports */ 1255 /* Do not receive interrupts sent by dummy ports */
1239 if (pp) 1256 if (!pp) {
1240 desc = pp->irq_desc; 1257 disable_irq(irq + i);
1241 else 1258 continue;
1242 desc = dev_driver_string(host->dev); 1259 }
1243 1260
1244 rc = devm_request_threaded_irq(host->dev, 1261 rc = devm_request_threaded_irq(host->dev, irq + i,
1245 irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED, 1262 ahci_hw_interrupt,
1246 desc, host->ports[i]); 1263 ahci_thread_fn, IRQF_SHARED,
1264 pp->irq_desc, host->ports[i]);
1247 if (rc) 1265 if (rc)
1248 goto out_free_irqs; 1266 goto out_free_irqs;
1249 } 1267 }
@@ -1357,6 +1375,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1357 1375
1358 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; 1376 hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
1359 1377
1378 /* must set flag prior to save config in order to take effect */
1379 if (ahci_broken_devslp(pdev))
1380 hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
1381
1360 /* save initial config */ 1382 /* save initial config */
1361 ahci_pci_save_initial_config(pdev, hpriv); 1383 ahci_pci_save_initial_config(pdev, hpriv);
1362 1384