diff options
Diffstat (limited to 'drivers/ide/pci/serverworks.c')
-rw-r--r-- | drivers/ide/pci/serverworks.c | 159 |
1 files changed, 68 insertions, 91 deletions
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index dbcd37a0c652..d9c4fd1ae996 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -1,9 +1,10 @@ /* - * linux/drivers/ide/pci/serverworks.c Version 0.8 25 Ebr 2003 + * linux/drivers/ide/pci/serverworks.c Version 0.11 Jun 2 2007 * * Copyright (C) 1998-2000 Michel Aubry * Copyright (C) 1998-2000 Andrzej Krzysztofowicz * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * Portions copyright (c) 2001 Sun Microsystems * * @@ -65,16 +66,16 @@ static int check_in_drive_lists (ide_drive_t *drive, const char **list) return 0; } -static u8 svwks_ratemask (ide_drive_t *drive) +static u8 svwks_udma_filter(ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode = 0; + u8 mask = 0; if (!svwks_revision) pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) - return 2; + return 0x1f; if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { u32 reg = 0; if (isa_dev) @@ -86,25 +87,31 @@ static u8 svwks_ratemask (ide_drive_t *drive) if(drive->media == ide_disk) return 0; /* Check the OSB4 DMA33 enable bit */ - return ((reg & 0x00004000) == 0x00004000) ? 1 : 0; + return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0; } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) { - return 1; + return 0x07; } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) { - u8 btr = 0; + u8 btr = 0, mode; pci_read_config_byte(dev, 0x5A, &btr); mode = btr & 0x3; - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); + /* If someone decides to do UDMA133 on CSB5 the same issue will bite so be inclusive */ if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100)) mode = 2; + + switch(mode) { + case 2: mask = 0x1f; break; + case 1: mask = 0x07; break; + default: mask = 0x00; break; + } } if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && (!(PCI_FUNC(dev->devfn) & 1))) - mode = 2; - return mode; + mask = 0x1f; + + return mask; } static u8 svwks_csb_check (struct pci_dev *dev) @@ -130,19 +137,14 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed; - u8 pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + u8 speed = ide_rate_filter(drive, xferspeed); + u8 pio = ide_get_best_pio_mode(drive, 255, 4, NULL); u8 unit = (drive->select.b.unit & 0x01); u8 csb5 = svwks_csb_check(dev); u8 ultra_enable = 0, ultra_timing = 0; u8 dma_timing = 0, pio_timing = 0; u16 csb5_pio = 0; - if (xferspeed == 255) /* PIO auto-tuning */ - speed = XFER_PIO_0 + pio; - else - speed = ide_rate_filter(svwks_ratemask(drive), xferspeed); - /* If we are about to put a disk into UDMA mode we screwed up. Our code assumes we never _ever_ do this on an OSB4 */ @@ -156,48 +158,67 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_read_config_word(dev, 0x4A, &csb5_pio); pci_read_config_byte(dev, 0x54, &ultra_enable); + /* If we are in RAID mode (eg AMI MegaIDE) then we can't it + turns out trust the firmware configuration */ + + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + goto oem_setup_failed; + /* Per Specified Design by OEM, and ASIC Architect */ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { if (!drive->init_speed) { u8 dma_stat = inb(hwif->dma_status); -dma_pio: if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) && ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) { drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)]; return 0; } else if ((dma_timing) && ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) { - u8 dmaspeed = dma_timing; + u8 dmaspeed; - dma_timing &= ~0xFF; - if ((dmaspeed & 0x20) == 0x20) + switch (dma_timing & 0x77) { + case 0x20: dmaspeed = XFER_MW_DMA_2; - else if ((dmaspeed & 0x21) == 0x21) + break; + case 0x21: dmaspeed = XFER_MW_DMA_1; - else if ((dmaspeed & 0x77) == 0x77) + break; + case 0x77: dmaspeed = XFER_MW_DMA_0; - else + break; + default: goto dma_pio; + } + drive->current_speed = drive->init_speed = dmaspeed; return 0; - } else if (pio_timing) { - u8 piospeed = pio_timing; + } +dma_pio: + if (pio_timing) { + u8 piospeed; - pio_timing &= ~0xFF; - if ((piospeed & 0x20) == 0x20) + switch (pio_timing & 0x7f) { + case 0x20: piospeed = XFER_PIO_4; - else if ((piospeed & 0x22) == 0x22) + break; + case 0x22: piospeed = XFER_PIO_3; - else if ((piospeed & 0x34) == 0x34) + break; + case 0x34: piospeed = XFER_PIO_2; - else if ((piospeed & 0x47) == 0x47) + break; + case 0x47: piospeed = XFER_PIO_1; - else if ((piospeed & 0x5d) == 0x5d) + break; + case 0x5d: piospeed = XFER_PIO_0; - else + break; + default: goto oem_setup_failed; + } + drive->current_speed = drive->init_speed = piospeed; return 0; } @@ -206,8 +227,8 @@ dma_pio: oem_setup_failed: - pio_timing &= ~0xFF; - dma_timing &= ~0xFF; + pio_timing = 0; + dma_timing = 0; ultra_timing &= ~(0x0F << (4*unit)); ultra_enable &= ~(0x01 << drive->dn); csb5_pio &= ~(0x0F << (4*drive->dn)); @@ -225,6 +246,9 @@ oem_setup_failed: case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: + /* + * TODO: always setup PIO mode so this won't be needed + */ pio_timing |= pio_modes[pio]; csb5_pio |= (pio << (4*drive->dn)); dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; @@ -236,6 +260,9 @@ oem_setup_failed: case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: + /* + * TODO: always setup PIO mode so this won't be needed + */ pio_timing |= pio_modes[pio]; csb5_pio |= (pio << (4*drive->dn)); dma_timing |= dma_modes[2]; @@ -256,72 +283,21 @@ oem_setup_failed: return (ide_config_drive_speed(drive, speed)); } -static void config_chipset_for_pio (ide_drive_t *drive) -{ - u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - u16 xfer_pio = drive->id->eide_pio_modes; - u8 timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio > 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - else - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - (void) svwks_tune_chipset(drive, speed); - drive->current_speed = speed; -} - static void svwks_tune_drive (ide_drive_t *drive, u8 pio) { - if(pio == 255) - (void) svwks_tune_chipset(drive, 255); - else - (void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio)); -} - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, svwks_ratemask(drive)); - - if (!(speed)) - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); - - (void) svwks_tune_chipset(drive, speed); - return ide_dma_enable(drive); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + (void)svwks_tune_chipset(drive, XFER_PIO_0 + pio); } static int svwks_config_drive_xfer_rate (ide_drive_t *drive) { drive->init_speed = 0; - if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + if (ide_tune_dma(drive)) return 0; if (ide_use_fast_pio(drive)) - config_chipset_for_pio(drive); + svwks_tune_drive(drive, 255); return -1; } @@ -500,6 +476,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) hwif->tuneproc = &svwks_tune_drive; hwif->speedproc = &svwks_tune_chipset; + hwif->udma_filter = &svwks_udma_filter; hwif->atapi_dma = 1; |