diff options
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r-- | drivers/ata/ahci.c | 50 |
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 | ||
1118 | static 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 |
1119 | static void ahci_gtf_filter_workaround(struct ata_host *host) | 1130 | static 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 | ||
1166 | static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, | 1177 | static 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 | ||
1194 | single_msi: | 1212 | single_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 | ||