diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-15 18:51:42 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-15 18:51:42 -0400 |
commit | 6b8cf7724bd0f8ae1f61937c5f40f4dbbda40960 (patch) | |
tree | 61102c2ba75447441d54d0cb035e51416a7dc6ce /drivers/ide | |
parent | 9445de76c124e90176b5116cf82f6cd1413f5230 (diff) |
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: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide')
-rw-r--r-- | drivers/ide/pci/sis5513.c | 85 |
1 files changed, 36 insertions, 49 deletions
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 2bde1b92784a..bb6cc4aedd63 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c | |||
@@ -1,9 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 | 2 | * linux/drivers/ide/pci/sis5513.c Version 0.20 Mar 4, 2007 |
3 | * | 3 | * |
4 | * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> | 4 | * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> |
5 | * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer | 5 | * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer |
6 | * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> | 6 | * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> |
7 | * Copyright (C) 2007 Bartlomiej Zolnierkiewicz | ||
8 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public License | 9 | * May be copied or modified under the terms of the GNU General Public License |
8 | * | 10 | * |
9 | * | 11 | * |
@@ -448,36 +450,15 @@ static void config_drive_art_rwp (ide_drive_t *drive) | |||
448 | pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); | 450 | pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); |
449 | } | 451 | } |
450 | 452 | ||
451 | |||
452 | /* Set per-drive active and recovery time */ | 453 | /* Set per-drive active and recovery time */ |
453 | static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) | 454 | static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) |
454 | { | 455 | { |
455 | ide_hwif_t *hwif = HWIF(drive); | 456 | ide_hwif_t *hwif = HWIF(drive); |
456 | struct pci_dev *dev = hwif->pci_dev; | 457 | struct pci_dev *dev = hwif->pci_dev; |
457 | 458 | ||
458 | u8 timing, drive_pci, test1, test2; | 459 | u8 drive_pci, test1, test2; |
459 | |||
460 | u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; | ||
461 | u16 xfer_pio = drive->id->eide_pio_modes; | ||
462 | 460 | ||
463 | config_drive_art_rwp(drive); | 461 | config_drive_art_rwp(drive); |
464 | pio = ide_get_best_pio_mode(drive, 255, pio, NULL); | ||
465 | |||
466 | if (xfer_pio> 4) | ||
467 | xfer_pio = 0; | ||
468 | |||
469 | if (drive->id->eide_pio_iordy > 0) { | ||
470 | for (xfer_pio = 5; | ||
471 | (xfer_pio > 0) && | ||
472 | (drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]); | ||
473 | xfer_pio--); | ||
474 | } else { | ||
475 | xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : | ||
476 | (drive->id->eide_pio_modes & 2) ? 0x04 : | ||
477 | (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; | ||
478 | } | ||
479 | |||
480 | timing = (xfer_pio >= pio) ? xfer_pio : pio; | ||
481 | 462 | ||
482 | /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ | 463 | /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ |
483 | drive_pci = 0x40; | 464 | drive_pci = 0x40; |
@@ -500,17 +481,18 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) | |||
500 | test1 &= ~0x0F; | 481 | test1 &= ~0x0F; |
501 | test2 &= ~0x07; | 482 | test2 &= ~0x07; |
502 | 483 | ||
503 | switch(timing) { | 484 | switch(pio) { |
504 | case 4: test1 |= 0x01; test2 |= 0x03; break; | 485 | case 4: test1 |= 0x01; test2 |= 0x03; break; |
505 | case 3: test1 |= 0x03; test2 |= 0x03; break; | 486 | case 3: test1 |= 0x03; test2 |= 0x03; break; |
506 | case 2: test1 |= 0x04; test2 |= 0x04; break; | 487 | case 2: test1 |= 0x04; test2 |= 0x04; break; |
507 | case 1: test1 |= 0x07; test2 |= 0x06; break; | 488 | case 1: test1 |= 0x07; test2 |= 0x06; break; |
489 | case 0: /* PIO0: register setting == X000 */ | ||
508 | default: break; | 490 | default: break; |
509 | } | 491 | } |
510 | pci_write_config_byte(dev, drive_pci, test1); | 492 | pci_write_config_byte(dev, drive_pci, test1); |
511 | pci_write_config_byte(dev, drive_pci+1, test2); | 493 | pci_write_config_byte(dev, drive_pci+1, test2); |
512 | } else if (chipset_family < ATA_133) { | 494 | } else if (chipset_family < ATA_133) { |
513 | switch(timing) { /* active recovery | 495 | switch(pio) { /* active recovery |
514 | v v */ | 496 | v v */ |
515 | case 4: test1 = 0x30|0x01; break; | 497 | case 4: test1 = 0x30|0x01; break; |
516 | case 3: test1 = 0x30|0x03; break; | 498 | case 3: test1 = 0x30|0x03; break; |
@@ -525,24 +507,28 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) | |||
525 | pci_read_config_dword(dev, drive_pci, &test3); | 507 | pci_read_config_dword(dev, drive_pci, &test3); |
526 | test3 &= 0xc0c00fff; | 508 | test3 &= 0xc0c00fff; |
527 | if (test3 & 0x08) { | 509 | if (test3 & 0x08) { |
528 | test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; | 510 | test3 |= ini_time_value[ATA_133][pio] << 12; |
529 | test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; | 511 | test3 |= act_time_value[ATA_133][pio] << 16; |
530 | test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; | 512 | test3 |= rco_time_value[ATA_133][pio] << 24; |
531 | } else { | 513 | } else { |
532 | test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; | 514 | test3 |= ini_time_value[ATA_100][pio] << 12; |
533 | test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; | 515 | test3 |= act_time_value[ATA_100][pio] << 16; |
534 | test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; | 516 | test3 |= rco_time_value[ATA_100][pio] << 24; |
535 | } | 517 | } |
536 | pci_write_config_dword(dev, drive_pci, test3); | 518 | pci_write_config_dword(dev, drive_pci, test3); |
537 | } | 519 | } |
538 | } | 520 | } |
539 | 521 | ||
540 | static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) | 522 | static int sis5513_tune_drive(ide_drive_t *drive, u8 pio) |
541 | { | 523 | { |
542 | if (pio == 255) | 524 | pio = ide_get_best_pio_mode(drive, pio, 4, NULL); |
543 | pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; | ||
544 | config_art_rwp_pio(drive, pio); | 525 | config_art_rwp_pio(drive, pio); |
545 | return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); | 526 | return ide_config_drive_speed(drive, XFER_PIO_0 + pio); |
527 | } | ||
528 | |||
529 | static void sis5513_tuneproc(ide_drive_t *drive, u8 pio) | ||
530 | { | ||
531 | (void)sis5513_tune_drive(drive, pio); | ||
546 | } | 532 | } |
547 | 533 | ||
548 | static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) | 534 | 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 | case XFER_SW_DMA_1: | 608 | case XFER_SW_DMA_1: |
623 | case XFER_SW_DMA_0: | 609 | case XFER_SW_DMA_0: |
624 | break; | 610 | break; |
625 | case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); | 611 | case XFER_PIO_4: |
626 | case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); | 612 | case XFER_PIO_3: |
627 | case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); | 613 | case XFER_PIO_2: |
628 | case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1)); | 614 | case XFER_PIO_1: |
629 | case XFER_PIO_0: | 615 | case XFER_PIO_0: |
630 | default: return((int) config_chipset_for_pio(drive, 0)); | 616 | return sis5513_tune_drive(drive, speed - XFER_PIO_0); |
617 | default: | ||
618 | BUG(); | ||
619 | break; | ||
631 | } | 620 | } |
632 | 621 | ||
633 | return ((int) ide_config_drive_speed(drive, speed)); | 622 | return ide_config_drive_speed(drive, speed); |
634 | } | ||
635 | |||
636 | static void sis5513_tune_drive (ide_drive_t *drive, u8 pio) | ||
637 | { | ||
638 | (void) config_chipset_for_pio(drive, pio); | ||
639 | } | 623 | } |
640 | 624 | ||
641 | static int sis5513_config_xfer_rate(ide_drive_t *drive) | 625 | static int sis5513_config_xfer_rate(ide_drive_t *drive) |
642 | { | 626 | { |
643 | config_art_rwp_pio(drive, 5); | 627 | /* |
628 | * TODO: always set PIO mode and remove this | ||
629 | */ | ||
630 | sis5513_tuneproc(drive, 255); | ||
644 | 631 | ||
645 | drive->init_speed = 0; | 632 | drive->init_speed = 0; |
646 | 633 | ||
@@ -648,7 +635,7 @@ static int sis5513_config_xfer_rate(ide_drive_t *drive) | |||
648 | return 0; | 635 | return 0; |
649 | 636 | ||
650 | if (ide_use_fast_pio(drive)) | 637 | if (ide_use_fast_pio(drive)) |
651 | sis5513_tune_drive(drive, 5); | 638 | sis5513_tuneproc(drive, 255); |
652 | 639 | ||
653 | return -1; | 640 | return -1; |
654 | } | 641 | } |
@@ -836,7 +823,7 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) | |||
836 | if (!hwif->irq) | 823 | if (!hwif->irq) |
837 | hwif->irq = hwif->channel ? 15 : 14; | 824 | hwif->irq = hwif->channel ? 15 : 14; |
838 | 825 | ||
839 | hwif->tuneproc = &sis5513_tune_drive; | 826 | hwif->tuneproc = &sis5513_tuneproc; |
840 | hwif->speedproc = &sis5513_tune_chipset; | 827 | hwif->speedproc = &sis5513_tune_chipset; |
841 | 828 | ||
842 | if (!(hwif->dma_base)) { | 829 | if (!(hwif->dma_base)) { |