sis5513: PIO mode setup fixes

* limit max PIO mode to PIO4, this driver doesn't support PIO5 and attempt
  to program PIO5 by config_art_rwp_pio() could result in incorrect PIO
  timings being programmed and possibly the data corruption (for < ATA100
  family chipsets PIO0 timings were used, for ATA100 and ATA100a - the random
  content of test1 variable was used, for ATA133 - MWDMA0 timings were used)

* BUG() in sis5513_tune_chipset() if somebody tries to force unsupported PIO5,
  also cleanup this function a bit while at it

* add comment about PIO0 timings for < ATA100 family chipsets

* remove open-coded best PIO mode selection from config_art_rwp_pio(),
  it contained numerous bugs:

  - it didn't check for validity of id->eide_pio_modes and id->eide_pio_iordy
    before using them

  - it tried to found out maximum PIO mode basing on minimum IORDY cycle time
    (moreover wrong cycle times were used for PIO1/5)

  - it was overriding PIO blacklist and conservative PIO "downgrade" done
    by ide_get_best_pio_mode()

* use sis5513_tune_drive() instead of config_art_rwp_pio()
  in sis5513_config_xfer_rate() so the correct PIO mode is also set
  on drive even if the device is not IORDY/DMA capable

* config_art_rwp_pio() was always setting the best possible mode and not
  the wanted one - fix it and move ide_get_best_pio_mode() call to
  config_chipset_for_pio()

* don't use ide_find_best_mode() in config_chipset_for_pio(), it was being
  overriden by config_art_rwp_pio() for the host timings anyway + we need to
  set the same PIO mode on the device and the host

* pass correct "pio" argument (255 instead of 5) to sis5513_tune_drive() call
  in sis5513_config_xfer_rate() so the best PIO mode is set on the drive
  and not PIO4

* rename sis5513_tune_drive() to sis5513_tuneproc()
  and config_chipset_for_pio() to sis5513_tune_driver()

* bump driver version
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 9445de76
/* /*
* linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 * linux/drivers/ide/pci/sis5513.c Version 0.20 Mar 4, 2007
* *
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
* Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
* 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
* *
* *
...@@ -448,36 +450,15 @@ static void config_drive_art_rwp (ide_drive_t *drive) ...@@ -448,36 +450,15 @@ static void config_drive_art_rwp (ide_drive_t *drive)
pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
} }
/* Set per-drive active and recovery time */ /* Set per-drive active and recovery time */
static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev; struct pci_dev *dev = hwif->pci_dev;
u8 timing, drive_pci, test1, test2; u8 drive_pci, test1, test2;
u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
u16 xfer_pio = drive->id->eide_pio_modes;
config_drive_art_rwp(drive); config_drive_art_rwp(drive);
pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
if (xfer_pio> 4)
xfer_pio = 0;
if (drive->id->eide_pio_iordy > 0) {
for (xfer_pio = 5;
(xfer_pio > 0) &&
(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
xfer_pio--);
} else {
xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
(drive->id->eide_pio_modes & 2) ? 0x04 :
(drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
}
timing = (xfer_pio >= pio) ? xfer_pio : pio;
/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
drive_pci = 0x40; drive_pci = 0x40;
...@@ -500,17 +481,18 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) ...@@ -500,17 +481,18 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
test1 &= ~0x0F; test1 &= ~0x0F;
test2 &= ~0x07; test2 &= ~0x07;
switch(timing) { switch(pio) {
case 4: test1 |= 0x01; test2 |= 0x03; break; case 4: test1 |= 0x01; test2 |= 0x03; break;
case 3: test1 |= 0x03; test2 |= 0x03; break; case 3: test1 |= 0x03; test2 |= 0x03; break;
case 2: test1 |= 0x04; test2 |= 0x04; break; case 2: test1 |= 0x04; test2 |= 0x04; break;
case 1: test1 |= 0x07; test2 |= 0x06; break; case 1: test1 |= 0x07; test2 |= 0x06; break;
case 0: /* PIO0: register setting == X000 */
default: break; default: break;
} }
pci_write_config_byte(dev, drive_pci, test1); pci_write_config_byte(dev, drive_pci, test1);
pci_write_config_byte(dev, drive_pci+1, test2); pci_write_config_byte(dev, drive_pci+1, test2);
} else if (chipset_family < ATA_133) { } else if (chipset_family < ATA_133) {
switch(timing) { /* active recovery switch(pio) { /* active recovery
v v */ v v */
case 4: test1 = 0x30|0x01; break; case 4: test1 = 0x30|0x01; break;
case 3: test1 = 0x30|0x03; break; case 3: test1 = 0x30|0x03; break;
...@@ -525,24 +507,28 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) ...@@ -525,24 +507,28 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
pci_read_config_dword(dev, drive_pci, &test3); pci_read_config_dword(dev, drive_pci, &test3);
test3 &= 0xc0c00fff; test3 &= 0xc0c00fff;
if (test3 & 0x08) { if (test3 & 0x08) {
test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; test3 |= ini_time_value[ATA_133][pio] << 12;
test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; test3 |= act_time_value[ATA_133][pio] << 16;
test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; test3 |= rco_time_value[ATA_133][pio] << 24;
} else { } else {
test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; test3 |= ini_time_value[ATA_100][pio] << 12;
test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; test3 |= act_time_value[ATA_100][pio] << 16;
test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; test3 |= rco_time_value[ATA_100][pio] << 24;
} }
pci_write_config_dword(dev, drive_pci, test3); pci_write_config_dword(dev, drive_pci, test3);
} }
} }
static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
{ {
if (pio == 255) pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
config_art_rwp_pio(drive, pio); config_art_rwp_pio(drive, pio);
return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static void sis5513_tuneproc(ide_drive_t *drive, u8 pio)
{
(void)sis5513_tune_drive(drive, pio);
} }
static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
...@@ -622,25 +608,26 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) ...@@ -622,25 +608,26 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_SW_DMA_1: case XFER_SW_DMA_1:
case XFER_SW_DMA_0: case XFER_SW_DMA_0:
break; break;
case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); case XFER_PIO_4:
case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); case XFER_PIO_3:
case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); case XFER_PIO_2:
case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1)); case XFER_PIO_1:
case XFER_PIO_0: case XFER_PIO_0:
default: return((int) config_chipset_for_pio(drive, 0)); return sis5513_tune_drive(drive, speed - XFER_PIO_0);
default:
BUG();
break;
} }
return ((int) ide_config_drive_speed(drive, speed)); return ide_config_drive_speed(drive, speed);
}
static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
{
(void) config_chipset_for_pio(drive, pio);
} }
static int sis5513_config_xfer_rate(ide_drive_t *drive) static int sis5513_config_xfer_rate(ide_drive_t *drive)
{ {
config_art_rwp_pio(drive, 5); /*
* TODO: always set PIO mode and remove this
*/
sis5513_tuneproc(drive, 255);
drive->init_speed = 0; drive->init_speed = 0;
...@@ -648,7 +635,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) ...@@ -648,7 +635,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive)
return 0; return 0;
if (ide_use_fast_pio(drive)) if (ide_use_fast_pio(drive))
sis5513_tune_drive(drive, 5); sis5513_tuneproc(drive, 255);
return -1; return -1;
} }
...@@ -836,7 +823,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) ...@@ -836,7 +823,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
if (!hwif->irq) if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14; hwif->irq = hwif->channel ? 15 : 14;
hwif->tuneproc = &sis5513_tune_drive; hwif->tuneproc = &sis5513_tuneproc;
hwif->speedproc = &sis5513_tune_chipset; hwif->speedproc = &sis5513_tune_chipset;
if (!(hwif->dma_base)) { if (!(hwif->dma_base)) {
......
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