sata_sil24: MSI support, disabled by default
[safe/jmp/linux-2.6] / drivers / ata / pata_via.c
index 57d951b..520d5a3 100644 (file)
@@ -1,7 +1,6 @@
 /*
  * pata_via.c  - VIA PATA for new ATA layer
  *                       (C) 2005-2006 Red Hat Inc
- *                       Alan Cox <alan@redhat.com>
  *
  *  Documentation
  *     Most chipset documentation available under NDA only
@@ -63,7 +62,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_via"
-#define DRV_VERSION "0.3.3"
+#define DRV_VERSION "0.3.4"
 
 /*
  *     The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -87,6 +86,10 @@ enum {
        VIA_SATA_PATA   = 0x800, /* SATA/PATA combined configuration */
 };
 
+enum {
+       VIA_IDFLAG_SINGLE = (1 << 0), /* single channel controller) */
+};
+
 /*
  * VIA SouthBridge chips.
  */
@@ -98,12 +101,17 @@ static const struct via_isa_bridge {
        u8 rev_max;
        u16 flags;
 } via_isa_bridges[] = {
+       { "vx855",      PCI_DEVICE_ID_VIA_VX855,    0x00, 0x2f,
+         VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
        { "vx800",      PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, VIA_UDMA_133 |
        VIA_BAD_AST | VIA_SATA_PATA },
+       { "vt8261",     PCI_DEVICE_ID_VIA_8261,     0x00, 0x2f,
+         VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
-       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
+       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
+       { "vt6415",     PCI_DEVICE_ID_VIA_6415,     0x00, 0xff, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
        { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -123,9 +131,14 @@ static const struct via_isa_bridge {
        { "vt82c586",   PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
        { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
        { "vt82c576",   PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+       { "vtxxxx",     PCI_DEVICE_ID_VIA_ANON,    0x00, 0x2f,
+         VIA_UDMA_133 | VIA_BAD_AST },
        { NULL }
 };
 
+struct via_port {
+       u8 cached_device;
+};
 
 /*
  *     Cable special cases
@@ -324,29 +337,38 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 }
 
 /**
- *     via_ata_sff_tf_load - send taskfile registers to host controller
+ *     via_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
  *     @tf: ATA taskfile register set
  *
  *     Outputs ATA taskfile to standard ATA host controller.
  *
  *     Note: This is to fix the internal bug of via chipsets, which
- *  will reset the device register after changing the IEN bit on
- *  ctl register
+ *     will reset the device register after changing the IEN bit on
+ *     ctl register
  */
-static void via_ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+static void via_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
+       struct via_port *vp = ap->private_data;
        unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+       int newctl = 0;
 
        if (tf->ctl != ap->last_ctl) {
                iowrite8(tf->ctl, ioaddr->ctl_addr);
-               iowrite8(tf->device, ioaddr->device_addr);
                ap->last_ctl = tf->ctl;
                ata_wait_idle(ap);
+               newctl = 1;
        }
 
+       if (tf->flags & ATA_TFLAG_DEVICE) {
+               iowrite8(tf->device, ioaddr->device_addr);
+               vp->cached_device = tf->device;
+       } else if (newctl)
+               iowrite8(vp->cached_device, ioaddr->device_addr);
+
        if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+               WARN_ON_ONCE(!ioaddr->ctl_addr);
                iowrite8(tf->hob_feature, ioaddr->feature_addr);
                iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
                iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
@@ -374,14 +396,25 @@ static void via_ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
                        tf->lbah);
        }
 
-       if (tf->flags & ATA_TFLAG_DEVICE) {
-               iowrite8(tf->device, ioaddr->device_addr);
-               VPRINTK("device 0x%X\n", tf->device);
-       }
-
        ata_wait_idle(ap);
 }
 
+static int via_port_start(struct ata_port *ap)
+{
+       struct via_port *vp;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+       int ret = ata_sff_port_start(ap);
+       if (ret < 0)
+               return ret;
+
+       vp = devm_kzalloc(&pdev->dev, sizeof(struct via_port), GFP_KERNEL);
+       if (vp == NULL)
+               return -ENOMEM;
+       ap->private_data = vp;
+       return 0;
+}
+
 static struct scsi_host_template via_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -392,13 +425,13 @@ static struct ata_port_operations via_port_ops = {
        .set_piomode    = via_set_piomode,
        .set_dmamode    = via_set_dmamode,
        .prereset       = via_pre_reset,
-       .sff_tf_load = via_ata_tf_load,
+       .sff_tf_load    = via_tf_load,
+       .port_start     = via_port_start,
 };
 
 static struct ata_port_operations via_port_ops_noirq = {
        .inherits       = &via_port_ops,
        .sff_data_xfer  = ata_sff_data_xfer_noirq,
-       .sff_tf_load = via_ata_tf_load,
 };
 
 /**
@@ -449,55 +482,56 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Early VIA without UDMA support */
        static const struct ata_port_info via_mwdma_info = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .port_ops = &via_port_ops
        };
        /* Ditto with IRQ masking required */
        static const struct ata_port_info via_mwdma_info_borked = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .port_ops = &via_port_ops_noirq,
        };
        /* VIA UDMA 33 devices (and borked 66) */
        static const struct ata_port_info via_udma33_info = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .udma_mask = ATA_UDMA2,
                .port_ops = &via_port_ops
        };
        /* VIA UDMA 66 devices */
        static const struct ata_port_info via_udma66_info = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .udma_mask = ATA_UDMA4,
                .port_ops = &via_port_ops
        };
        /* VIA UDMA 100 devices */
        static const struct ata_port_info via_udma100_info = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .udma_mask = ATA_UDMA5,
                .port_ops = &via_port_ops
        };
        /* UDMA133 with bad AST (All current 133) */
        static const struct ata_port_info via_udma133_info = {
                .flags = ATA_FLAG_SLAVE_POSS,
-               .pio_mask = 0x1f,
-               .mwdma_mask = 0x07,
+               .pio_mask = ATA_PIO4,
+               .mwdma_mask = ATA_MWDMA2,
                .udma_mask = ATA_UDMA6, /* FIXME: should check north bridge */
                .port_ops = &via_port_ops
        };
        const struct ata_port_info *ppi[] = { NULL, NULL };
-       struct pci_dev *isa = NULL;
+       struct pci_dev *isa;
        const struct via_isa_bridge *config;
        static int printed_version;
        u8 enable;
        u32 timing;
+       unsigned long flags = id->driver_data;
        int rc;
 
        if (!printed_version++)
@@ -507,25 +541,23 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
+       if (flags & VIA_IDFLAG_SINGLE)
+               ppi[1] = &ata_dummy_port_info;
+
        /* To find out how the IDE will behave and what features we
           actually have to look at the bridge not the IDE controller */
-       for (config = via_isa_bridges; config->id; config++)
+       for (config = via_isa_bridges; config->id != PCI_DEVICE_ID_VIA_ANON;
+            config++)
                if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
                        !!(config->flags & VIA_BAD_ID),
                        config->id, NULL))) {
+                       u8 rev = isa->revision;
+                       pci_dev_put(isa);
 
-                       if (isa->revision >= config->rev_min &&
-                           isa->revision <= config->rev_max)
+                       if (rev >= config->rev_min && rev <= config->rev_max)
                                break;
-                       pci_dev_put(isa);
                }
 
-       if (!config->id) {
-               printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n");
-               return -ENODEV;
-       }
-       pci_dev_put(isa);
-
        if (!(config->flags & VIA_NO_ENABLES)) {
                /* 0x40 low bits indicate enabled channels */
                pci_read_config_byte(pdev, 0x40 , &enable);
@@ -620,11 +652,13 @@ static int via_reinit_one(struct pci_dev *pdev)
 #endif
 
 static const struct pci_device_id via[] = {
+       { PCI_VDEVICE(VIA, 0x0415), },
        { PCI_VDEVICE(VIA, 0x0571), },
        { PCI_VDEVICE(VIA, 0x0581), },
        { PCI_VDEVICE(VIA, 0x1571), },
        { PCI_VDEVICE(VIA, 0x3164), },
        { PCI_VDEVICE(VIA, 0x5324), },
+       { PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE },
 
        { },
 };