X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fata%2Fpata_via.c;h=45657cacec43ff21f5c10bda21f813d980f724a1;hb=7766a3fb905f0b078b05f5d6a6be8df4c64b9f51;hp=e66bb85ad3d114b536dfdafd12951fef2f49a38b;hpb=1bd5b715a305f6f13455e89becbd839010dd14b5;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index e66bb85..45657ca 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -1,7 +1,6 @@ /* * pata_via.c - VIA PATA for new ATA layer * (C) 2005-2006 Red Hat Inc - * Alan Cox * * Documentation * Most chipset documentation available under NDA only @@ -63,7 +62,7 @@ #include #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,11 +101,17 @@ static const struct via_isa_bridge { u8 rev_max; u16 flags; } via_isa_bridges[] = { - { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, + { "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, 0x2f, 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 }, @@ -122,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 @@ -210,23 +224,11 @@ static int via_pre_reset(struct ata_link *link, unsigned long deadline) return -ENOENT; } - return ata_std_prereset(link, deadline); + return ata_sff_prereset(link, deadline); } /** - * via_error_handler - reset for VIA chips - * @ap: ATA port - * - * Handle the reset callback for the later chips with cable detect - */ - -static void via_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, via_pre_reset, ata_std_softreset, NULL, ata_std_postreset); -} - -/** * via_do_set_mode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device @@ -271,15 +273,15 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo pci_read_config_byte(pdev, 0x4C, &setup); setup &= ~(3 << shift); - setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */ + setup |= clamp_val(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */ pci_write_config_byte(pdev, 0x4C, setup); } /* Load the PIO mode bits */ pci_write_config_byte(pdev, 0x4F - ap->port_no, - ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1)); + ((clamp_val(t.act8b, 1, 16) - 1) << 4) | (clamp_val(t.rec8b, 1, 16) - 1)); pci_write_config_byte(pdev, 0x48 + offset, - ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1)); + ((clamp_val(t.active, 1, 16) - 1) << 4) | (clamp_val(t.recover, 1, 16) - 1)); /* Load the UDMA bits according to type */ switch(udma_type) { @@ -287,16 +289,16 @@ static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mo /* BUG() ? */ /* fall through */ case 33: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 5) - 2)) : 0x03; break; case 66: - ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f; + ut = t.udma ? (0xe8 | (clamp_val(t.udma, 2, 9) - 2)) : 0x0f; break; case 100: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; case 133: - ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07; + ut = t.udma ? (0xe0 | (clamp_val(t.udma, 2, 9) - 2)) : 0x07; break; } @@ -334,6 +336,85 @@ static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev) via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]); } +/** + * 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 + */ +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); + 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); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + 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), }; @@ -343,12 +424,14 @@ static struct ata_port_operations via_port_ops = { .cable_detect = via_cable_detect, .set_piomode = via_set_piomode, .set_dmamode = via_set_dmamode, - .error_handler = via_error_handler, + .prereset = via_pre_reset, + .sff_tf_load = via_tf_load, + .port_start = via_port_start, }; static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, - .data_xfer = ata_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer_noirq, }; /** @@ -399,56 +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 }; - struct ata_port_info type; - const struct ata_port_info *ppi[] = { &type, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; struct pci_dev *isa = NULL; 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++) @@ -458,9 +541,13 @@ 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))) { @@ -471,17 +558,14 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_dev_put(isa); } - if (!config->id) { - printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n"); - return -ENODEV; - } pci_dev_put(isa); - /* 0x40 low bits indicate enabled channels */ - pci_read_config_byte(pdev, 0x40 , &enable); - enable &= 3; - if (enable == 0) { - return -ENODEV; + if (!(config->flags & VIA_NO_ENABLES)) { + /* 0x40 low bits indicate enabled channels */ + pci_read_config_byte(pdev, 0x40 , &enable); + enable &= 3; + if (enable == 0) + return -ENODEV; } /* Initialise the FIFO for the enabled channels. */ @@ -491,25 +575,25 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: if (config->flags & VIA_NO_UNMASK) - type = via_mwdma_info_borked; + ppi[0] = &via_mwdma_info_borked; else - type = via_mwdma_info; + ppi[0] = &via_mwdma_info; break; case VIA_UDMA_33: - type = via_udma33_info; + ppi[0] = &via_udma33_info; break; case VIA_UDMA_66: - type = via_udma66_info; + ppi[0] = &via_udma66_info; /* The 66 MHz devices require we enable the clock */ pci_read_config_dword(pdev, 0x50, &timing); timing |= 0x80008; pci_write_config_dword(pdev, 0x50, timing); break; case VIA_UDMA_100: - type = via_udma100_info; + ppi[0] = &via_udma100_info; break; case VIA_UDMA_133: - type = via_udma133_info; + ppi[0] = &via_udma133_info; break; default: WARN_ON(1); @@ -524,9 +608,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } /* We have established the device type, now fire it up */ - type.private_data = (void *)config; - - return ata_pci_init_one(pdev, ppi, &via_sht); + return ata_pci_sff_init_one(pdev, ppi, &via_sht, (void *)config); } #ifdef CONFIG_PM @@ -572,11 +654,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 }, { }, };