it821x: PIO mode setup fixes

* 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: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 247b03f8
/* /*
* 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) 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 * May be copied or modified under the terms of the GNU General Public License
* Based in part on the ITE vendor provided SCSI driver. * Based in part on the ITE vendor provided SCSI driver.
...@@ -104,6 +105,7 @@ static int it8212_noraid; ...@@ -104,6 +105,7 @@ static int it8212_noraid;
/** /**
* it821x_program - program the PIO/MWDMA registers * it821x_program - program the PIO/MWDMA registers
* @drive: drive to tune * @drive: drive to tune
* @timing: timing info
* *
* Program the PIO/MWDMA timing for this channel according to the * Program the PIO/MWDMA timing for this channel according to the
* current clock. * current clock.
...@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing) ...@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
/** /**
* it821x_program_udma - program the UDMA registers * it821x_program_udma - program the UDMA registers
* @drive: drive to tune * @drive: drive to tune
* @timing: timing info
* *
* Program the UDMA timing for this drive according to the * Program the UDMA timing for this drive according to the
* current clock. * current clock.
...@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing) ...@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
} }
} }
/** /**
* it821x_clock_strategy * it821x_clock_strategy
* @hwif: hardware interface * @drive: drive to set up
* *
* Select between the 50 and 66Mhz base clocks to get the best * Select between the 50 and 66Mhz base clocks to get the best
* results for this interface. * results for this interface.
...@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive) ...@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
altclock = itdev->want[0][1]; 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; clock = altclock;
/* Nobody cares - keep the same clock */ /* Nobody cares - keep the same clock */
...@@ -240,37 +245,56 @@ static u8 it821x_ratemask (ide_drive_t *drive) ...@@ -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 * @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 * Try to tune the drive/host to the desired PIO mode taking into
* controller. By the time we are called the mode has been * the consideration the maximum PIO mode supported by the other
* modified as neccessary to handle the absence of seperate * device on the cable.
* master/slave timers for MWDMA/PIO.
*
* This code is only used in pass through mode.
*/ */
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; ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif); struct it821x_dev *itdev = ide_get_hwifdata(hwif);
int unit = drive->select.b.unit; int unit = drive->select.b.unit;
ide_drive_t *pair = &hwif->drives[1 - unit];
/* Spec says 89 ref driver uses 88 */ /* Spec says 89 ref driver uses 88 */
static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; 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 */ /* 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->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_clock_strategy(drive);
it821x_program(drive, itdev->pio[unit]); 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) ...@@ -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 * it821x_dma_read - DMA hook
* @drive: drive for DMA * @drive: drive for DMA
...@@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) ...@@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
struct it821x_dev *itdev = ide_get_hwifdata(hwif); struct it821x_dev *itdev = ide_get_hwifdata(hwif);
u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
if(!itdev->smart) { switch (speed) {
switch(speed) {
case XFER_PIO_4: case XFER_PIO_4:
case XFER_PIO_3: case XFER_PIO_3:
case XFER_PIO_2: case XFER_PIO_2:
case XFER_PIO_1: case XFER_PIO_1:
case XFER_PIO_0: case XFER_PIO_0:
it821x_tuneproc(drive, (speed - XFER_PIO_0)); return it821x_tunepio(drive, speed - XFER_PIO_0);
break; }
if (itdev->smart == 0) {
switch (speed) {
/* MWDMA tuning is really hard because our MWDMA and PIO /* MWDMA tuning is really hard because our MWDMA and PIO
timings are kept in the same place. We can switch in the timings are kept in the same place. We can switch in the
host dma on/off callbacks */ host dma on/off callbacks */
...@@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_drive_t *drive) ...@@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{ {
u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
if (speed) { if (speed == 0)
config_it821x_chipset_for_pio(drive, 0); return 0;
it821x_tune_chipset(drive, speed); it821x_tune_chipset(drive, speed);
return ide_dma_enable(drive); return ide_dma_enable(drive);
}
return 0;
} }
/** /**
...@@ -523,7 +513,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *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)) if (ide_use_dma(drive) && config_chipset_for_dma(drive))
return 0; return 0;
config_it821x_chipset_for_pio(drive, 1); it821x_tuneproc(drive, 255);
return -1; return -1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment