cmd64x: fix PIO mode setup (take 3)

The driver's tuneproc() method fails to set the drive's own speed -- fix this
by renaming the function to cmd64x_tune_pio(), making it return the mode set,
and "wrapping" the new tuneproc() method around it; while at it, also get rid
of the non-working prefetch control code (filtering out related argument values
in the "wrapper"), remove redundant PIO5 mode limitation, make cmdprintk() give
more sensible mode info, and remove mention about the obsolete /proc/ interface.
Get rid of the broken config_chipset_for_pio() which always tried to set PIO4,
switch to always auto-tuning PIO instead.
Oh, and add the missing PIO5 support to the speedproc() method while at it. :-)

Warning: compile tested only -- getting to the real hardware isn't that easy...

On Tuesday 06 February 2007 22:11, Mikael Pettersson <mikpe@it.uu.se> wrote:
> 
> Worked fine on my SPARC Ultra5 with a CMD646 IDE controller.

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
Sergei Shtylyov 2007-03-03 17:48:53 +01:00 committed by Bartlomiej Zolnierkiewicz
parent 21b8247713
commit f92d50e6fd
1 changed files with 43 additions and 65 deletions

View File

@ -1,6 +1,6 @@
/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
*
* linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
* linux/drivers/ide/pci/cmd64x.c Version 1.41 Feb 3, 2007
*
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
@ -12,6 +12,7 @@
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
*
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
*/
#include <linux/module.h>
@ -262,43 +263,25 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
}
/*
* Attempts to set the interface PIO mode.
* The preferred method of selecting PIO modes (e.g. mode 4) is
* "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are
* 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
* Called with 255 at boot time.
* This routine selects drive's best PIO mode, calculates setup/active/recovery
* counts, and then writes them into the chipset registers.
*/
static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
{
int setup_time, active_time, recovery_time;
int clock_time, pio_mode, cycle_time;
u8 recovery_count2, cycle_count;
int setup_count, active_count, recovery_count;
int bus_speed = system_bus_clock();
/*byte b;*/
ide_pio_data_t d;
switch (mode_wanted) {
case 8: /* set prefetch off */
case 9: /* set prefetch on */
mode_wanted &= 1;
/*set_prefetch_mode(index, mode_wanted);*/
cmdprintk("%s: %sabled cmd640 prefetch\n",
drive->name, mode_wanted ? "en" : "dis");
return;
}
mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
pio_mode = d.pio_mode;
pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &d);
cycle_time = d.cycle_time;
/*
* I copied all this complicated stuff from cmd640.c and made a few
* minor changes. For now I am just going to pray that it is correct.
*/
if (pio_mode > 5)
pio_mode = 5;
setup_time = ide_pio_timings[pio_mode].setup_time;
active_time = ide_pio_timings[pio_mode].active_time;
recovery_time = cycle_time - (setup_time + active_time);
@ -320,22 +303,33 @@ static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
if (active_count > 16)
active_count = 16; /* maximum allowed by cmd646 */
/*
* In a perfect world, we might set the drive pio mode here
* (using WIN_SETFEATURE) before continuing.
*
* But we do not, because:
* 1) this is the wrong place to do it
* (proper is do_special() in ide.c)
* 2) in practice this is rarely, if ever, necessary
*/
program_drive_counts (drive, setup_count, active_count, recovery_count);
cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, "
"clocks=%d/%d/%d\n",
drive->name, pio_mode, mode_wanted, cycle_time,
drive->name, mode_wanted, pio_mode, cycle_time,
d.overridden ? " (overriding vendor mode)" : "",
setup_count, active_count, recovery_count);
return pio_mode;
}
/*
* Attempts to set drive's PIO mode.
* Special cases are 8: prefetch off, 9: prefetch on (both never worked),
* and 255: auto-select best mode (used at boot time).
*/
static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
{
/*
* Filter out the prefetch control values
* to prevent PIO5 from being programmed
*/
if (pio == 8 || pio == 9)
return;
pio = cmd64x_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static u8 cmd64x_ratemask (ide_drive_t *drive)
@ -387,22 +381,6 @@ static u8 cmd64x_ratemask (ide_drive_t *drive)
return mode;
}
static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
{
u8 speed = 0x00;
u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
cmd64x_tuneproc(drive, set_pio);
speed = XFER_PIO_0 + set_pio;
if (set_speed)
(void) ide_config_drive_speed(drive, speed);
}
static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
{
config_cmd64x_chipset_for_pio(drive, set_speed);
}
static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@ -414,7 +392,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
if (speed > XFER_PIO_4) {
if (speed >= XFER_SW_DMA_0) {
(void) pci_read_config_byte(dev, pciD, &regD);
(void) pci_read_config_byte(dev, pciU, &regU);
regD &= ~(unit ? 0x40 : 0x20);
@ -438,17 +416,20 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break;
case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break;
case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break;
case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break;
case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break;
case XFER_PIO_5:
case XFER_PIO_4:
case XFER_PIO_3:
case XFER_PIO_2:
case XFER_PIO_1:
case XFER_PIO_0:
(void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
break;
default:
return 1;
}
if (speed > XFER_PIO_4) {
if (speed >= XFER_SW_DMA_0) {
(void) pci_write_config_byte(dev, pciU, regU);
regD |= (unit ? 0x40 : 0x20);
(void) pci_write_config_byte(dev, pciD, regD);
@ -461,8 +442,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive));
config_chipset_for_pio(drive, !speed);
if (!speed)
return 0;
@ -478,7 +457,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
config_chipset_for_pio(drive, 1);
cmd64x_tune_drive(drive, 255);
return -1;
}
@ -679,14 +658,13 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
hwif->tuneproc = &cmd64x_tuneproc;
hwif->tuneproc = &cmd64x_tune_drive;
hwif->speedproc = &cmd64x_tune_chipset;
if (!hwif->dma_base) {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
if (!hwif->dma_base)
return;
}
hwif->atapi_dma = 1;