#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
#endif
static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
- struct ahci_host_priv *hpriv)
+ struct ahci_host_priv *hpriv)
{
int rc, nvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
goto intx;
- rc = pci_msi_vec_count(pdev);
- if (rc < 0)
+ nvec = pci_msi_vec_count(pdev);
+ if (nvec < 0)
goto intx;
/*
* Message mode could be enforced. In this case assume that advantage
* of multipe MSIs is negated and use single MSI mode instead.
*/
- if (rc < n_ports)
+ if (nvec < n_ports)
goto single_msi;
- nvec = rc;
- rc = pci_enable_msi_block(pdev, nvec);
- if (rc < 0)
+ rc = pci_enable_msi_exact(pdev, nvec);
+ if (rc == -ENOSPC)
+ goto single_msi;
+ else if (rc < 0)
goto intx;
- else if (rc > 0)
+
+ /* fallback to single MSI mode if the controller enforced MRSM mode */
+ if (readl(hpriv->mmio + HOST_CTL) & HOST_MRSM) {
+ pci_disable_msi(pdev);
+ printk(KERN_INFO "ahci: MRSM is on, fallback to single MSI\n");
goto single_msi;
+ }
return nvec;
single_msi:
- rc = pci_enable_msi(pdev);
- if (rc)
+ if (pci_enable_msi(pdev))
goto intx;
return 1;
return rc;
for (i = 0; i < host->n_ports; i++) {
- const char* desc;
struct ahci_port_priv *pp = host->ports[i]->private_data;
- /* pp is NULL for dummy ports */
- if (pp)
- desc = pp->irq_desc;
- else
- desc = dev_driver_string(host->dev);
+ /* Do not receive interrupts sent by dummy ports */
+ if (!pp) {
+ disable_irq(irq + i);
+ continue;
+ }
- rc = devm_request_threaded_irq(host->dev,
- irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
- desc, host->ports[i]);
+ rc = devm_request_threaded_irq(host->dev, irq + i,
+ ahci_hw_interrupt,
+ ahci_thread_fn, IRQF_SHARED,
+ pp->irq_desc, host->ports[i]);
if (rc)
goto out_free_irqs;
}