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

[libata] sata_vsc: support PCI MSI

Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 553c4aa6
...@@ -94,8 +94,14 @@ enum { ...@@ -94,8 +94,14 @@ enum {
VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \ VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \ VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
VSC_SATA_INT_PHY_CHANGE), 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) \ #define is_vsc_sata_int_err(port_idx, int_status) \
(int_status & (VSC_SATA_INT_ERROR << (8 * port_idx))) (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, ...@@ -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) static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
{ {
void __iomem *mask_addr; void __iomem *mask_addr;
...@@ -312,7 +332,7 @@ static const struct ata_port_operations vsc_sata_ops = { ...@@ -312,7 +332,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.scr_write = vsc_sata_scr_write, .scr_write = vsc_sata_scr_write,
.port_start = ata_port_start, .port_start = ata_port_start,
.port_stop = ata_port_stop, .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) 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 ...@@ -341,6 +361,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
{ {
static int printed_version; static int printed_version;
struct ata_probe_ent *probe_ent = NULL; struct ata_probe_ent *probe_ent = NULL;
struct vsc_sata_host_priv *hpriv;
unsigned long base; unsigned long base;
int pci_dev_busy = 0; int pci_dev_busy = 0;
void __iomem *mmio_base; void __iomem *mmio_base;
...@@ -382,6 +403,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d ...@@ -382,6 +403,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
rc = -ENOMEM; rc = -ENOMEM;
goto err_out_regions; goto err_out_regions;
} }
memset(probe_ent, 0, sizeof(*probe_ent)); memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev); probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node); 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 ...@@ -393,19 +415,33 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
} }
base = (unsigned long) mmio_base; 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 * 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); 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->sht = &vsc_sata_sht;
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO; ATA_FLAG_MMIO;
probe_ent->port_ops = &vsc_sata_ops; probe_ent->port_ops = &vsc_sata_ops;
probe_ent->n_ports = 4; probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq; probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base; 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 /* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these * 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 ...@@ -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 */ /* FIXME: check ata_device_add return value */
ata_device_add(probe_ent); ata_device_add(probe_ent);
kfree(probe_ent);
kfree(probe_ent);
return 0; return 0;
err_out_iounmap:
pci_iounmap(pdev, mmio_base);
err_out_free_ent: err_out_free_ent:
kfree(probe_ent); kfree(probe_ent);
err_out_regions: err_out_regions:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment