diff options
Diffstat (limited to 'drivers/ide/ide-lib.c')
-rw-r--r-- | drivers/ide/ide-lib.c | 157 |
1 files changed, 98 insertions, 59 deletions
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 074bb32..d97390c 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -76,41 +76,26 @@ EXPORT_SYMBOL(ide_xfer_verbose); * Given the available transfer modes this function returns * the best available speed at or below the speed requested. * - * FIXME: filter also PIO/SWDMA/MWDMA modes + * TODO: check device PIO capabilities */ -u8 ide_rate_filter(ide_drive_t *drive, u8 speed) +static u8 ide_rate_filter(ide_drive_t *drive, u8 speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = drive->hwif; - u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2; + u8 mode = ide_find_dma_mode(drive, speed); - if (hwif->udma_filter) - mask = hwif->udma_filter(drive); - - /* - * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false - * cable warning from eighty_ninty_three(), moving ide_rate_filter() - * calls from ->speedproc to core code will make this hack go away - */ - if (speed > XFER_UDMA_2) { - if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) - mask &= 0x07; + if (mode == 0) { + if (hwif->pio_mask) + mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; + else + mode = XFER_PIO_4; } - if (mask) - mode = fls(mask) - 1 + XFER_UDMA_0; - // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); return min(speed, mode); -#else /* !CONFIG_BLK_DEV_IDEDMA */ - return min(speed, (u8)XFER_PIO_4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } -EXPORT_SYMBOL(ide_rate_filter); - int ide_use_fast_pio(ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -249,12 +234,34 @@ static int ide_scan_pio_blacklist (char *model) return -1; } +unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio) +{ + struct hd_driveid *id = drive->id; + int cycle_time = 0; + + if (id->field_valid & 2) { + if (id->capability & 8) + cycle_time = id->eide_pio_iordy; + else + cycle_time = id->eide_pio; + } + + /* conservative "downgrade" for all pre-ATA2 drives */ + if (pio < 3) { + if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time) + cycle_time = 0; /* use standard timing */ + } + + return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time; +} + +EXPORT_SYMBOL_GPL(ide_pio_cycle_time); + /** * ide_get_best_pio_mode - get PIO mode from drive * @drive: drive to consider * @mode_wanted: preferred mode * @max_mode: highest allowed mode - * @d: PIO data * * This routine returns the recommended PIO settings for a given drive, * based on the drive->id information and the ide_pio_blacklist[]. @@ -263,22 +270,18 @@ static int ide_scan_pio_blacklist (char *model) * This is used by most chipset support modules when "auto-tuning". */ -u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d) +u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode) { int pio_mode; - int cycle_time = 0; - int use_iordy = 0; struct hd_driveid* id = drive->id; int overridden = 0; - if (mode_wanted != 255) { - pio_mode = mode_wanted; - use_iordy = (pio_mode > 2); - } else if (!drive->id) { - pio_mode = 0; - } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { - overridden = 1; - use_iordy = (pio_mode > 2); + if (mode_wanted != 255) + return min_t(u8, mode_wanted, max_mode); + + if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 && + (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { + printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name); } else { pio_mode = id->tPIO; if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ @@ -286,9 +289,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p overridden = 1; } if (id->field_valid & 2) { /* drive implements ATA2? */ - if (id->capability & 8) { /* drive supports use_iordy? */ - use_iordy = 1; - cycle_time = id->eide_pio_iordy; + if (id->capability & 8) { /* IORDY supported? */ if (id->eide_pio_modes & 7) { overridden = 0; if (id->eide_pio_modes & 4) @@ -298,36 +299,61 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p else pio_mode = 3; } - } else { - cycle_time = id->eide_pio; } } + if (overridden) + printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n", + drive->name); + /* * Conservative "downgrade" for all pre-ATA2 drives */ - if (pio_mode && pio_mode < 4) { + if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 && + pio_mode && pio_mode < 4) { pio_mode--; - overridden = 1; - if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time) - cycle_time = 0; /* use standard timing */ + printk(KERN_INFO "%s: applying conservative " + "PIO \"downgrade\"\n", drive->name); } } - if (pio_mode > max_mode) { + + if (pio_mode > max_mode) pio_mode = max_mode; - cycle_time = 0; - } - if (d) { - d->pio_mode = pio_mode; - d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; - d->use_iordy = use_iordy; - d->overridden = overridden; - } + return pio_mode; } EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +/* req_pio == "255" for auto-tune */ +void ide_set_pio(ide_drive_t *drive, u8 req_pio) +{ + ide_hwif_t *hwif = drive->hwif; + u8 host_pio, pio; + + if (hwif->set_pio_mode == NULL) + return; + + BUG_ON(hwif->pio_mask == 0x00); + + host_pio = fls(hwif->pio_mask) - 1; + + pio = ide_get_best_pio_mode(drive, req_pio, host_pio); + + /* + * TODO: + * - report device max PIO mode + * - check req_pio != 255 against device max PIO mode + */ + printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n", + drive->name, host_pio, req_pio, + req_pio == 255 ? "(auto-tune)" : "", pio); + + hwif->set_pio_mode(drive, pio); +} + +EXPORT_SYMBOL_GPL(ide_set_pio); + /** * ide_toggle_bounce - handle bounce buffering * @drive: drive to update @@ -365,13 +391,26 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) { -#ifndef CONFIG_BLK_DEV_IDEDMA - rate = min(rate, (u8) XFER_PIO_4); -#endif - if(HWIF(drive)->speedproc) - return HWIF(drive)->speedproc(drive, rate); - else + ide_hwif_t *hwif = drive->hwif; + + if (hwif->speedproc == NULL) return -1; + + rate = ide_rate_filter(drive, rate); + + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) { + if (hwif->set_pio_mode) + hwif->set_pio_mode(drive, rate - XFER_PIO_0); + + /* + * FIXME: this is incorrect to return zero here but + * since all users of ide_set_xfer_rate() ignore + * the return value it is not a problem currently + */ + return 0; + } + + return hwif->speedproc(drive, rate); } static void ide_dump_opcode(ide_drive_t *drive) |