* limit max PIO mode to PIO4, this driver doesn't support PIO5 and attempt
  to setup PIO5 by it821x_tuneproc() could result in incorrect PIO timings
  + incorrect base clock being set for controller in the passthrough mode

* move code limiting max PIO according to the pair device capabilities from
  config_it821x_chipset_for_pio() to it821x_tuneproc() so the check is also
  applied for mode change requests coming through ->tuneproc and ->speedproc
  interfaces

* set device speed in it821x_tuneproc()

* in it821x_tune_chipset() call it821x_tuneproc() also if the controller is
  in the smart mode (so the check for pair device max PIO is done)

* rename it821x_tuneproc() to it821x_tune_pio(), then add it821x_tuneproc()
  wrapper which does the max PIO mode check;  it worked by the pure luck
  previously, pio[4] and pio_want[4] arrays were used with index == 255
  so random PIO timings and base clock were set for the controller in the
  passthrough mode, thankfully PIO timings and base clock were corrected
  later by config_it821x_chipset_for_pio() call (but it was not called for
  PIO-only devices during resume and for user requested PIO autotuning)

* remove config_it821x_chipset_for_pio() call from config_chipset_for_dma()
  as the driver sets ->autotune to 1 and ->tuneproc does the proper job now

* convert the last user of config_it821x_chipset_for_pio() to use
  it821x_tuneproc(drive, 255) and remove no longer needed function

While at it:

* fix few comments

* bump driver version

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
Bartlomiej Zolnierkiewicz 2007-05-05 22:03:50 +02:00
Родитель 247b03f8dc
Коммит 0e9b4e535f
1 изменённых файлов: 58 добавлений и 68 удалений

Просмотреть файл

@ -1,8 +1,9 @@
/*
* linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
* linux/drivers/ide/pci/it821x.c Version 0.10 Mar 10 2007
*
* Copyright (C) 2004 Red Hat <alan@redhat.com>
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
* Based in part on the ITE vendor provided SCSI driver.
@ -104,6 +105,7 @@ static int it8212_noraid;
/**
* it821x_program - program the PIO/MWDMA registers
* @drive: drive to tune
* @timing: timing info
*
* Program the PIO/MWDMA timing for this channel according to the
* current clock.
@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
/**
* it821x_program_udma - program the UDMA registers
* @drive: drive to tune
* @timing: timing info
*
* Program the UDMA timing for this drive according to the
* current clock.
@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
}
}
/**
* it821x_clock_strategy
* @hwif: hardware interface
* @drive: drive to set up
*
* Select between the 50 and 66Mhz base clocks to get the best
* results for this interface.
@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
altclock = itdev->want[0][1];
}
/* Master doesn't care does the slave ? */
if(clock == ATA_ANY)
/*
* if both clocks can be used for the mode with the higher priority
* use the clock needed by the mode with the lower priority
*/
if (clock == ATA_ANY)
clock = altclock;
/* Nobody cares - keep the same clock */
@ -240,37 +245,56 @@ static u8 it821x_ratemask (ide_drive_t *drive)
}
/**
* it821x_tuneproc - tune a drive
* it821x_tunepio - tune a drive
* @drive: drive to tune
* @mode_wanted: the target operating mode
* @pio: the desired PIO mode
*
* Load the timing settings for this device mode into the
* controller. By the time we are called the mode has been
* modified as neccessary to handle the absence of seperate
* master/slave timers for MWDMA/PIO.
*
* This code is only used in pass through mode.
* Try to tune the drive/host to the desired PIO mode taking into
* the consideration the maximum PIO mode supported by the other
* device on the cable.
*/
static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
{
ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
int unit = drive->select.b.unit;
ide_drive_t *pair = &hwif->drives[1 - unit];
/* Spec says 89 ref driver uses 88 */
static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
if(itdev->smart)
return;
/*
* Compute the best PIO mode we can for a given device. We must
* pick a speed that does not cause problems with the other device
* on the cable.
*/
if (pair) {
u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
/* trim PIO to the slowest of the master/slave */
if (pair_pio < set_pio)
set_pio = pair_pio;
}
if (itdev->smart)
goto set_drive_speed;
/* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
itdev->want[unit][1] = pio_want[mode_wanted];
itdev->want[unit][1] = pio_want[set_pio];
itdev->want[unit][0] = 1; /* PIO is lowest priority */
itdev->pio[unit] = pio[mode_wanted];
itdev->pio[unit] = pio[set_pio];
it821x_clock_strategy(drive);
it821x_program(drive, itdev->pio[unit]);
set_drive_speed:
return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
}
static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
{
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
(void)it821x_tunepio(drive, pio);
}
/**
@ -353,40 +377,6 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
}
/**
* config_it821x_chipset_for_pio - set drive timings
* @drive: drive to tune
* @speed we want
*
* Compute the best pio mode we can for a given device. We must
* pick a speed that does not cause problems with the other device
* on the cable.
*/
static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
u8 unit = drive->select.b.unit;
ide_hwif_t *hwif = drive->hwif;
ide_drive_t *pair = &hwif->drives[1-unit];
u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
u8 pair_pio;
/* We have to deal with this mess in pairs */
if(pair != NULL) {
pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
/* Trim PIO to the slowest of the master/slave */
if(pair_pio < set_pio)
set_pio = pair_pio;
}
it821x_tuneproc(drive, set_pio);
speed = XFER_PIO_0 + set_pio;
/* XXX - We trim to the lowest of the pair so the other drive
will always be fine at this point until we do hotplug passthru */
if (set_speed)
(void) ide_config_drive_speed(drive, speed);
}
/**
* it821x_dma_read - DMA hook
* @drive: drive for DMA
@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
if(!itdev->smart) {
switch(speed) {
case XFER_PIO_4:
case XFER_PIO_3:
case XFER_PIO_2:
case XFER_PIO_1:
case XFER_PIO_0:
it821x_tuneproc(drive, (speed - XFER_PIO_0));
break;
switch (speed) {
case XFER_PIO_4:
case XFER_PIO_3:
case XFER_PIO_2:
case XFER_PIO_1:
case XFER_PIO_0:
return it821x_tunepio(drive, speed - XFER_PIO_0);
}
if (itdev->smart == 0) {
switch (speed) {
/* MWDMA tuning is really hard because our MWDMA and PIO
timings are kept in the same place. We can switch in the
host dma on/off callbacks */
@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
if (speed) {
config_it821x_chipset_for_pio(drive, 0);
it821x_tune_chipset(drive, speed);
if (speed == 0)
return 0;
return ide_dma_enable(drive);
}
it821x_tune_chipset(drive, speed);
return 0;
return ide_dma_enable(drive);
}
/**
@ -523,7 +513,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive)
if (ide_use_dma(drive) && config_chipset_for_dma(drive))
return 0;
config_it821x_chipset_for_pio(drive, 1);
it821x_tuneproc(drive, 255);
return -1;
}