Hi! While version 2.1 works OK, v2.3 some more cleanups and enhancements to the driver. These are: * Added VIA clone chipsets to the comments at the beginning of the file. * Simpler VIA southbridge detection using a table only now, two version specific kludges removed. * Removed 8-bit timing entries (they were #ifdefed out anyway), because indeed the hardware should take care of that. * Fixed a misplaced brace in the FIT macro. * Enhanced the EIDE PIO & MWDMA timing setup to modify the mode timing based on drive capabilites instead selecting a slower mode based on the same numbers. This should give better performance on some drives. * Use the 'recommended timing' value for MWDMA modes to enhance performance on MWDMA drives. Using 'minimum timing', as done before results in flowcontrol being triggered too often, which slows down the transfers considerably. * Don't try to set PIO_SLOW mode. Drives that need it don't support PIO mode setting anyway. * Check for interface presence before trying to tune it. Higher layers still can request tuning on a nonexistent interface. Anyone interested, please test this out, if it is as problemless as version 2.1, I'll send this to Linus for inclusion in the kernel. -- Vojtech Pavlik SuSE Labs
--- via82cxxx.c-2.1 Tue Aug 29 11:19:27 2000 +++ via82cxxx.c Tue Sep 12 13:02:22 2000 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 2.1 2000/08/29 01:34:60 vojtech Exp $ + * $Id: via82cxxx.c,v 2.3 2000/09/12 12:52:60 vojtech Exp $ * * Copyright (c) 2000 Vojtech Pavlik * @@ -18,17 +18,21 @@ * * southbridges, which can be found in * - * VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4 - * VIA Apollo Pro, Pro Plus, Pro 133, Pro 133A, ProMedia 601, ProSavage 605 - * VIA Apollo KX133, KT133 - * AMD-640, AMD-750 IronGate - * - * chipsets. Supports PIO 0-5, MWDMA 0-2, SWDMA 0-2 and - * UDMA 0-5 (includes UDMA33, 66 and 100) modes. UDMA100 isn't possible - * on any of the supported chipsets yet. - * - * UDMA66 and higher modes are autodetected only in case the BIOS has enabled them. - * To force UDMA66, use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. + * VIA Apollo VP, VPX, VPX/97, VP2, VP2/97, VP3, MVP3, MVP4, Pro, Pro Plus, + * Pro 133, Pro 133A, ProMedia 601, ProSavage 605, ProSavage PM133, KX133, KT133 + * PC-Chips VXPro, VXPro+, TXPro-III, TXPro-AGP, ViaGra, BXToo, BXTel + * AMD 640, 640 AGP, 750 IronGate + * ETEQ 6618, 6628, 6638 + * Micron Samurai + * + * chipsets. Supports + * + * PIO 0-5, MWDMA 0-2, SWDMA 0-2 and UDMA 0-5 + * + * (includes UDMA33, 66 and 100) modes. UDMA100 isn't possible + * on any of the supported chipsets yet. UDMA66 and higher modes are + * autodetected only in case the BIOS has enabled them. To force UDMA66, + * use 'ide0=ata66' or 'ide1=ata66' on the kernel command line. */ /* @@ -88,17 +92,18 @@ static const struct { char *name; unsigned short id; + unsigned char rev; unsigned char speed; } via_isa_bridges[] = { - { "vt8231", PCI_DEVICE_ID_VIA_8231, XFER_UDMA_4 }, - { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, XFER_UDMA_4 }, - { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_4 }, - { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, XFER_UDMA_2 }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, - { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, - { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, XFER_MW_DMA_2 }, - { "Unknown SouthBridge", 0, XFER_UDMA_4 }, - { "Unknown SouthBridge", 0, XFER_UDMA_2 }, + { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, XFER_UDMA_4 }, + { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, XFER_UDMA_4 }, + { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, XFER_UDMA_4 }, + { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, XFER_UDMA_4 }, + { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, XFER_UDMA_2 }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, XFER_UDMA_2 }, + { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, XFER_UDMA_2 }, + { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, XFER_MW_DMA_2 }, + { NULL } }; static unsigned char via_config; @@ -109,10 +114,6 @@ * PIO 0-5, MWDMA 0-2 and UDMA 0-5 timings (in nanoseconds). * These were taken from ATA/ATAPI-6 standard, rev 0a, except * for PIO 5, which is a nonstandard extension. - * - * Dilemma: 8-bit (register) PIO accesses need more relaxed timing. - * Hopefully the chipset is taking care of that. If it doesn't - * do so, define VIA_USE_8_BIT_TIMING to see if it helps. */ #ifndef XFER_PIO_5 @@ -148,15 +149,9 @@ { XFER_PIO_4, "PIO4", 25, 70, 25, 120, 0 }, { XFER_PIO_3, "PIO3", 30, 80, 70, 180, 0 }, -#ifdef VIA_USE_8_BIT_TIMING - { XFER_PIO_2, "PIO2", 30, 290, 60, 330, 0 }, - { XFER_PIO_1, "PIO1", 50, 290, 100, 383, 0 }, - { XFER_PIO_0, "PIO0", 70, 290, 300, 600, 0 }, -#else { XFER_PIO_2, "PIO2", 30, 100, 90, 240, 0 }, { XFER_PIO_1, "PIO1", 50, 125, 100, 383, 0 }, { XFER_PIO_0, "PIO0", 70, 165, 150, 600, 0 }, -#endif { XFER_PIO_SLOW, "SLOW", 120, 290, 240, 960, 0 }, { 0 } @@ -193,11 +188,14 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 2.1"); + via_print("Driver Version: 2.3"); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); via_print("South Bridge: VIA %s rev %#x", via_isa_bridges[via_config].name, t); + pci_read_config_byte(dev, PCI_REVISION_ID, &t); + via_print("IDE type: Apollo VP rev %#x", t); + pci_read_config_word(dev, PCI_COMMAND, &c); via_print("Command register: %#x", c); @@ -208,8 +206,8 @@ via_print("PCI clock: %dMHz", pci_clock); pci_read_config_byte(dev, VIA_MISC_1, &t); - via_print("Master Read Cycle IRDY: %dws", (t & 64) >>6 ); - via_print("Master Write Cycle IRDY: %dws", (t & 32) >> 5 ); + via_print("Master Read Cycle IRDY: %dws", (t & 64) >> 6); + via_print("Master Write Cycle IRDY: %dws", (t & 32) >> 5); via_print("FIFO Output Data 1/2 Clock Advance: %s", (t & 16) ? "on" : "off" ); via_print("BM IDE Status Register Read Retry: %s", (t & 8) ? "on" : "off" ); @@ -278,8 +276,10 @@ #endif -#define FIT(v,min,max) (((v)>(max)?(max):(v))<(min)?(min):(v)) -#define ENOUGH(v,un) (((v)-1)/(un)+1) +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define FIT(v,min,max) MAX(MIN(v,max),min) +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) #ifdef DEBUG #define via_write_config_byte(dev,number,value) do {\ @@ -308,11 +308,29 @@ printk(KERN_DEBUG "VP_IDE: Setting drive %d to %s\n", drive->dn, via_timing[i].name); #endif + if (!via_timing[i].name) + return -EINVAL; + setup = ENOUGH(via_timing[i].setup, T); active = ENOUGH(via_timing[i].active, T); recover = ENOUGH(via_timing[i].recover, T); cycle = ENOUGH(via_timing[i].cycle, T); + if (drive->id->field_valid & 2) { /* EIDE drive */ + + if ((speed & 0xf0) == 0x00) { /* PIO mode */ + if (speed <= XFER_PIO_2) + cycle = MAX(cycle, ENOUGH(drive->id->eide_pio, T)); + else + cycle = MAX(cycle, ENOUGH(drive->id->eide_pio_iordy, +T)); + } + + if ((speed & 0xf0) == 0x20) { /* MWDMA mode */ + cycle = MAX(cycle, drive->id->eide_dma_time / T); + cycle = MAX(cycle, ENOUGH(drive->id->eide_dma_min, T)); + } + } + if (active + recover < cycle) { active += (cycle - (active + recover)) / 2; recover = cycle - active; @@ -337,7 +355,7 @@ * UDMA cycle */ - if (via_timing[i].udma) { + if ((speed & 0xf0) == 0x40) { /* UDMA mode */ t = 0xe8; if (via_isa_bridges[via_config].speed >= XFER_UDMA_4) t |= FIT(ENOUGH(via_timing[i].udma, T >> 1) - 2, 0, 7); @@ -351,6 +369,9 @@ * Drive init */ + if (speed == XFER_PIO_SLOW) /* SLOW can't be set */ + return 0; /* and drives needing it can't be set to +anything else either */ + if (!drive->init_speed) drive->init_speed = speed; if ((err = ide_config_drive_speed(drive, speed))) return err; @@ -361,35 +382,32 @@ static void config_chipset_for_pio(ide_drive_t *drive) { - short eide_pio_timing[] = {600, 383, 240, 180, 120, 100}; - signed char pio, ide_pio; + unsigned char black, pio = - if (drive->id->eide_pio_iordy > 0) { /* Has timing table */ - for (pio = 5; pio >= 0; pio--) - if (drive->id->eide_pio_iordy <= eide_pio_timing[pio]) - break; - } else { /* No timing table -> use mode capabilities */ - pio = (drive->id->eide_pio_modes & 4) ? 5 : - (drive->id->eide_pio_modes & 2) ? 4 : - (drive->id->eide_pio_modes & 1) ? 3 : - (drive->id->tPIO == 2) ? 2 : - (drive->id->tPIO == 1) ? 1 : 0; + (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 : + (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 : + (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : + (drive->id->tPIO == 2) ? XFER_PIO_2 : + (drive->id->tPIO == 1) ? XFER_PIO_1 : + (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW; + + drive->dn = HWIF(drive)->channel * 2 + (drive->select.b.unit & 1); /* Fix for +broken ide-probe.c */ + + if ((black = ide_scan_pio_blacklist(drive->id->model)) != 255) { + printk(KERN_INFO "VP_IDE: Changing PIO mode from %d to %d for drive %d +based on drive blacklist.\n", + pio - XFER_PIO_0, black, drive->dn); + pio = black + XFER_PIO_0; } - ide_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - pio = (pio >= ide_pio) ? pio : ide_pio; /* Phew. What about the blacklist? */ - - if (!pio) pio = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - else pio += XFER_PIO_0; - - /* Fixup because of broken ide-probe.c */ - drive->dn = HWIF(drive)->channel * 2 + (drive->select.b.unit & 1); - via_set_speed(drive, pio); } -static void via82cxxx_tune_drive(ide_drive_t *drive, byte pio) +static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio) { + + if (!((via_enabled >> HWIF(drive)->channel) & 1)) /* ide-probe.c will call us +even when we're not here */ + return; + if (pio == 255) { config_chipset_for_pio(drive); return; @@ -479,7 +497,6 @@ return HWIF(drive)->dmaproc(dma_func, drive); } - int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { if (func == ide_dma_check) @@ -492,51 +509,40 @@ { struct pci_dev *isa = NULL; unsigned char f, t, m; - unsigned int u, i; + unsigned int u; + int i; /* * Find ISA bridge to see how good the IDE is. */ for (via_config = 0; via_isa_bridges[via_config].id; via_config++) - if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, via_isa_bridges[via_config].id, NULL))) - break; -/* - * Read revision. - */ + if ((isa = pci_find_device(PCI_VENDOR_ID_VIA, +via_isa_bridges[via_config].id, NULL))) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + if (t >= via_isa_bridges[via_config].rev) + break; + } - if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C586_0) { - pci_read_config_byte(isa, PCI_REVISION_ID, &t); - if (t < 0x30) via_config++; /* vt82c586a */ - if (t < 0x20) via_config++; /* vt82c586 */ + if (!via_isa_bridges[via_config].id) { + printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech +Pavlik <[EMAIL PROTECTED]>\n"); + return -ENODEV; } /* - * Check UDMA66 mode set by BIOS. + * Check UDMA66 mode set by BIOS & enable 66 MHz timing. */ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); - for (i = 0; i < 4; i++) { - pci_read_config_byte(dev, VIA_UDMA_TIMING + (3 - i), &t); - if ((u & (0x80000 >> ((i >> 1) << 4))) && ((t & 7) < 2)) via_ata66 |= (1 << (i >> 1)); - } + for (i = 24; i >= 0; i -= 8) + if (((u >> (i & 16)) & 8) && (((u >> i) & 7) < 2)) /* 2x PCI +clock && less than 3T/cycle */ + via_ata66 |= (1 << (1 - (i >> 4))); #ifdef DEBUG printk(KERN_DEBUG "VP_IDE: BIOS enabled ATA66: primary: %s, secondary: %s\n", via_ata66 & 1 ? "yes" : "no", via_ata66 & 2 ? "yes" : "no"); #endif - -/* - * Set UDMA66 double clock bits. - */ - - pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - - if ((via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596 || !isa) - && (u & 0x80008) != 0x80008) - via_config++; /* vt82c596a / Unknown UDMA33 */ /* * Set up FIFO, flush, prefetch and post-writes.