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: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
@ -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) 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;
|
|||||||
/**
|
/**
|
||||||
* 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)
|
|||||||
/**
|
/**
|
||||||
* 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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|||||||
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:
|
return it821x_tunepio(drive, speed - XFER_PIO_0);
|
||||||
it821x_tuneproc(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)
|
|||||||
{
|
{
|
||||||
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);
|
|
||||||
|
|
||||||
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))
|
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user