Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7cbaa86b authored by Dan Wolstenholme's avatar Dan Wolstenholme Committed by Jeff Garzik
Browse files

[libata] sata_vsc: support PCI MSI



Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 553c4aa6
Loading
Loading
Loading
Loading
+41 −3
Original line number Diff line number Diff line
@@ -94,8 +94,14 @@ enum {
			      VSC_SATA_INT_ERROR_P    | VSC_SATA_INT_ERROR_R | \
			      VSC_SATA_INT_ERROR_E    | VSC_SATA_INT_ERROR_M | \
			      VSC_SATA_INT_PHY_CHANGE),

	/* Host private flags (hp_flags) */
	VSC_SATA_HP_FLAG_MSI    = (1 << 0),
};

struct vsc_sata_host_priv {
	u32	hp_flags;
};

#define is_vsc_sata_int_err(port_idx, int_status) \
	 (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
@@ -118,6 +124,20 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
}


static void vsc_sata_host_stop(struct ata_host_set *host_set)
{
	struct vsc_sata_host_priv *hpriv = host_set->private_data;
	struct pci_dev *pdev = to_pci_dev(host_set->dev);

	if (hpriv->hp_flags & VSC_SATA_HP_FLAG_MSI)
		pci_disable_msi(pdev);
	else
		pci_intx(pdev, 0);
	kfree (hpriv);
	ata_pci_host_stop(host_set);
}


static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
{
	void __iomem *mask_addr;
@@ -312,7 +332,7 @@ static const struct ata_port_operations vsc_sata_ops = {
	.scr_write		= vsc_sata_scr_write,
	.port_start		= ata_port_start,
	.port_stop		= ata_port_stop,
	.host_stop		= ata_pci_host_stop,
	.host_stop		= vsc_sata_host_stop,
};

static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
@@ -341,6 +361,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
{
	static int printed_version;
	struct ata_probe_ent *probe_ent = NULL;
	struct vsc_sata_host_priv *hpriv;
	unsigned long base;
	int pci_dev_busy = 0;
	void __iomem *mmio_base;
@@ -382,6 +403,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
		rc = -ENOMEM;
		goto err_out_regions;
	}

	memset(probe_ent, 0, sizeof(*probe_ent));
	probe_ent->dev = pci_dev_to_dev(pdev);
	INIT_LIST_HEAD(&probe_ent->node);
@@ -393,19 +415,33 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
	}
	base = (unsigned long) mmio_base;

	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
	if (!hpriv) {
		rc = -ENOMEM;
		goto err_out_iounmap;
	}
	memset(hpriv, 0, sizeof(*hpriv));

	/*
	 * Due to a bug in the chip, the default cache line size can't be used
	 */
	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);

	if (pci_enable_msi(pdev) == 0) {
		hpriv->hp_flags |= VSC_SATA_HP_FLAG_MSI;
		pci_intx(pdev, 0);
	}
	else
		probe_ent->irq_flags = IRQF_SHARED;

	probe_ent->sht = &vsc_sata_sht;
	probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
				ATA_FLAG_MMIO;
	probe_ent->port_ops = &vsc_sata_ops;
	probe_ent->n_ports = 4;
	probe_ent->irq = pdev->irq;
	probe_ent->irq_flags = IRQF_SHARED;
	probe_ent->mmio_base = mmio_base;
	probe_ent->private_data = hpriv;

	/* We don't care much about the PIO/UDMA masks, but the core won't like us
	 * if we don't fill these
@@ -432,10 +468,12 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d

	/* FIXME: check ata_device_add return value */
	ata_device_add(probe_ent);
	kfree(probe_ent);

	kfree(probe_ent);
	return 0;

err_out_iounmap:
	pci_iounmap(pdev, mmio_base);
err_out_free_ent:
	kfree(probe_ent);
err_out_regions: