Hi! I have found a couple bugs in the VIA IDE kernel I'm now maintaining that manifest themselves on hardware I don't have: 1) On old SWDMA devices the timing is programmed incorrectly. This will result in DMA timeouts or data corruption. 2) On UDMA devices used with vt82c596a (old buggy VIA MobileSouth), the chip will get confused, which will result in DMA timeouts and UDMA being disabled. No data corruption here, just very poor performance. 3) One extra sprintf was forgotten in the via_display_info function. This is harmless, but a bug nevertheless. Here goes a detailed description of the patch that fixes the above three bugs: Chunk1: Changes version number Chunk2: Removes UDMA66 unknown southbridge entry. We can't try to program unknown southbridges to UDMA66, because that can result in crashes (as shown by vt82c596a). UDMA33 should be safe, because the only southbridge that doesn't support it is vt82c586. Chunk3: Fix SWDMA modes. By a typo there were 0's everywhere. This is important, without this fix SWDMA devices will be programmed incorrectly. Chunk4: Change version number in /proc Chunk5: Remove the sprintf(). Chunk6: Don't program UDMA66 enable bit on UDMA33 controllers. They *should* ignore it, but 596a doesn't, resulting in timeouts on boot. This is critical. Also don't program UDMA at all on the old vt82c586. Chunk7: The correct way to check for 596a. Chunk8: Remove the old check for 596a. It doesn't work, because the 596a doesn't ignore the UDMA66 bits as it should. Don't set UDMA66 on 596a at all, it causes crashes. Critical. I hope this will get into test9-pre6, because otherwise it's quite unusable for vt82c596a users. TIA. -- Vojtech Pavlik SuSE Labs
--- linux-old/drivers/ide/via82cxxx.c Wed Sep 6 17:07:56 2000 +++ linux/drivers/ide/via82cxxx.c Wed Sep 20 23:33:08 2000 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 2.1 2000/08/29 01:34:60 vojtech Exp $ + * $Id: via82cxxx.c,v 2.1b 2000/09/20 23:19:60 vojtech Exp $ * * Copyright (c) 2000 Vojtech Pavlik * @@ -97,7 +97,6 @@ { "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 }, }; @@ -140,8 +139,8 @@ { XFER_MW_DMA_1, "MDMA1", 45, 80, 50, 150, 0 }, { XFER_MW_DMA_0, "MDMA0", 60, 215, 215, 480, 0 }, - { XFER_SW_DMA_0, "SDMA0", 60, 120, 120, 240, 0 }, - { XFER_SW_DMA_0, "SDMA0", 90, 240, 240, 480, 0 }, + { XFER_SW_DMA_2, "SDMA2", 60, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, "SDMA1", 90, 240, 240, 480, 0 }, { XFER_SW_DMA_0, "SDMA0",120, 480, 480, 960, 0 }, { XFER_PIO_5, "PIO5", 20, 50, 30, 100, 0 }, @@ -193,7 +192,7 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 2.1"); + via_print("Driver Version: 2.1b"); 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); @@ -213,9 +212,6 @@ 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" ); - pci_read_config_byte(dev, VIA_MISC_2, &t); - sprintf(p, "Interrupt Steering Swap: %s", (t & 64) ? "on" : "off"); - pci_read_config_byte(dev, VIA_MISC_3, &t); via_print("Max DRDY Pulse Width: %s%s", via_control3[(t & 0x03)], (t & 0x03) ? "PCI clocks" : ""); @@ -337,15 +333,13 @@ * UDMA cycle */ - if (via_timing[i].udma) { - t = 0xe8; - if (via_isa_bridges[via_config].speed >= XFER_UDMA_4) - t |= FIT(ENOUGH(via_timing[i].udma, T >> 1) - 2, 0, 7); - else - t |= FIT(ENOUGH(via_timing[i].udma, T ) - 2, 0, 3); - } else t = 0x0b; + switch(via_isa_bridges[via_config].speed) { + case XFER_UDMA_2: t = via_timing[i].udma ? (0x60 | +(FIT(via_timing[i].udma, 2, 5) - 2)) : 0x03; break; + case XFER_UDMA_4: t = via_timing[i].udma ? (0xe8 | +(FIT(via_timing[i].udma, 2, 9) - 2)) : 0x0f; break; + } - via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); + if (via_isa_bridges[via_config].speed != XFER_MW_DMA_2) + via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); /* * Drive init @@ -511,6 +505,11 @@ if (t < 0x20) via_config++; /* vt82c586 */ } + if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + if (t < 0x10) via_config++; /* vt82c596a */ + } + /* * Check UDMA66 mode set by BIOS. */ @@ -530,13 +529,8 @@ /* * 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 */ + if (via_isa_bridges[via_config].speed == XFER_UDMA_4) + pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); /* * Set up FIFO, flush, prefetch and post-writes.